lastsearch 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.
- lastsearch-1.0.0/.gitignore +90 -0
- lastsearch-1.0.0/PKG-INFO +290 -0
- lastsearch-1.0.0/README.md +261 -0
- lastsearch-1.0.0/lastsearch/__init__.py +63 -0
- lastsearch-1.0.0/lastsearch/cli.py +128 -0
- lastsearch-1.0.0/lastsearch/client.py +665 -0
- lastsearch-1.0.0/lastsearch/exceptions.py +29 -0
- lastsearch-1.0.0/lastsearch/integrations/__init__.py +0 -0
- lastsearch-1.0.0/lastsearch/integrations/crewai.py +47 -0
- lastsearch-1.0.0/lastsearch/integrations/langchain.py +93 -0
- lastsearch-1.0.0/lastsearch/models.py +228 -0
- lastsearch-1.0.0/pyproject.toml +41 -0
- lastsearch-1.0.0/tests/__init__.py +0 -0
- lastsearch-1.0.0/tests/test_client.py +54 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# MCP config (contains API keys)
|
|
2
|
+
.mcp.json
|
|
3
|
+
|
|
4
|
+
# Logs
|
|
5
|
+
logs
|
|
6
|
+
*.log
|
|
7
|
+
npm-debug.log*
|
|
8
|
+
yarn-debug.log*
|
|
9
|
+
yarn-error.log*
|
|
10
|
+
pnpm-debug.log*
|
|
11
|
+
lerna-debug.log*
|
|
12
|
+
|
|
13
|
+
node_modules
|
|
14
|
+
dist-ssr
|
|
15
|
+
*.local
|
|
16
|
+
|
|
17
|
+
# Build output
|
|
18
|
+
dist
|
|
19
|
+
.vercel/output
|
|
20
|
+
apps/*/dist
|
|
21
|
+
packages/*/dist
|
|
22
|
+
|
|
23
|
+
# Stale lockfiles (project uses pnpm)
|
|
24
|
+
package-lock.json
|
|
25
|
+
bun.lockb
|
|
26
|
+
|
|
27
|
+
# TypeScript build info
|
|
28
|
+
*.tsbuildinfo
|
|
29
|
+
|
|
30
|
+
# Supabase — lives in lastsearch-engine private repo
|
|
31
|
+
supabase/
|
|
32
|
+
|
|
33
|
+
# Claude Code local settings
|
|
34
|
+
.claude/settings.local.json
|
|
35
|
+
|
|
36
|
+
# Environment
|
|
37
|
+
.env
|
|
38
|
+
.env.local
|
|
39
|
+
.env.*.local
|
|
40
|
+
|
|
41
|
+
# Python
|
|
42
|
+
__pycache__/
|
|
43
|
+
*.pyc
|
|
44
|
+
*.egg-info/
|
|
45
|
+
|
|
46
|
+
# Editor directories and files
|
|
47
|
+
.vscode/*
|
|
48
|
+
!.vscode/extensions.json
|
|
49
|
+
.idea
|
|
50
|
+
.DS_Store
|
|
51
|
+
*.suo
|
|
52
|
+
*.ntvs*
|
|
53
|
+
*.njsproj
|
|
54
|
+
*.sln
|
|
55
|
+
*.sw?
|
|
56
|
+
.vercel
|
|
57
|
+
packages/python-sdk/lastsearch/__pycache__/
|
|
58
|
+
.env*.local
|
|
59
|
+
scripts/benchmark-results.json
|
|
60
|
+
scripts/seed-benchmark.ts
|
|
61
|
+
|
|
62
|
+
# Agent Skills (local install)
|
|
63
|
+
.agents/
|
|
64
|
+
skills-lock.json
|
|
65
|
+
|
|
66
|
+
# Swag designs (local only)
|
|
67
|
+
swag-designs/
|
|
68
|
+
apps/mcp/.smithery/
|
|
69
|
+
|
|
70
|
+
# MCP Registry tokens
|
|
71
|
+
.mcpregistry*
|
|
72
|
+
apps/mcp/.mcpregistry*
|
|
73
|
+
|
|
74
|
+
# Benchmark data and results (large, regenerated)
|
|
75
|
+
benchmarks/data/
|
|
76
|
+
benchmarks/results/
|
|
77
|
+
|
|
78
|
+
# Training — lives in lastsearch-engine private repo
|
|
79
|
+
training/
|
|
80
|
+
|
|
81
|
+
# Internal planning & strategy (not for public repo)
|
|
82
|
+
.planning/
|
|
83
|
+
docs/launch-video-script.md
|
|
84
|
+
|
|
85
|
+
# Pitch deck (local only)
|
|
86
|
+
deck/
|
|
87
|
+
|
|
88
|
+
# Security
|
|
89
|
+
*.pem
|
|
90
|
+
*.key
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: lastsearch
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python SDK for LastSearch — Grounded Intelligence research infrastructure for AI agents
|
|
5
|
+
Project-URL: Homepage, https://lastsearch.ai
|
|
6
|
+
Project-URL: Documentation, https://lastsearch.ai/developers
|
|
7
|
+
Project-URL: Repository, https://github.com/lastsearch-hq/lastsearch
|
|
8
|
+
Project-URL: Discord, https://discord.gg/ubAuT4YQsT
|
|
9
|
+
Author: LastSearch
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
Keywords: agent-tools,agents,ai,ai-search,autogpt,citations,confidence-scoring,crewai,deep-search,evidence,fact-checking,grounded-intelligence,hallucination-prevention,langchain,lastsearch,llamaindex,llm,mcp,rag,research,search,verified-research,web-search
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: httpx>=0.25.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Provides-Extra: crewai
|
|
25
|
+
Requires-Dist: crewai>=0.41.0; extra == 'crewai'
|
|
26
|
+
Provides-Extra: langchain
|
|
27
|
+
Requires-Dist: langchain-core>=0.2.0; extra == 'langchain'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# lastsearch
|
|
31
|
+
|
|
32
|
+
**Reliable research infrastructure for AI agents.** Python SDK for [LastSearch](https://lastsearch.ai) — the research layer for LangChain, CrewAI, and custom agent pipelines.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install lastsearch
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from lastsearch import LastSearch
|
|
44
|
+
|
|
45
|
+
client = LastSearch(api_key="ls_xxx")
|
|
46
|
+
|
|
47
|
+
# Research with citations
|
|
48
|
+
result = client.ask("What is quantum computing?")
|
|
49
|
+
print(result.answer)
|
|
50
|
+
print(f"Confidence: {result.confidence:.0%}")
|
|
51
|
+
for source in result.sources:
|
|
52
|
+
print(f" - {source.title}: {source.url}")
|
|
53
|
+
|
|
54
|
+
# Thorough mode — auto-retries if confidence < 60%
|
|
55
|
+
thorough = client.ask("What is quantum computing?", depth="thorough")
|
|
56
|
+
|
|
57
|
+
# Deep mode — multi-step agentic research with iterative gap analysis (requires BAI key + sign-in)
|
|
58
|
+
# Runs think→search→extract→evaluate cycles (up to 4 steps), 3x quota cost
|
|
59
|
+
deep = client.ask("Compare CRISPR approaches", depth="deep")
|
|
60
|
+
for step in deep.reasoning_steps or []:
|
|
61
|
+
print(f" Step {step.step}: {step.query} ({step.confidence:.0%})")
|
|
62
|
+
|
|
63
|
+
# Web search
|
|
64
|
+
results = client.search("latest AI news", limit=5)
|
|
65
|
+
|
|
66
|
+
# Page extraction
|
|
67
|
+
page = client.open("https://example.com")
|
|
68
|
+
|
|
69
|
+
# Structured extraction from a URL
|
|
70
|
+
extract = client.extract("https://example.com", query="pricing info")
|
|
71
|
+
|
|
72
|
+
# Compare raw LLM vs evidence-backed
|
|
73
|
+
compare = client.compare("Is Python faster than Rust?")
|
|
74
|
+
|
|
75
|
+
# Clarity — prompt mode (get enhanced prompts for your own LLM)
|
|
76
|
+
prompts = client.clarity("Write a blog post about quantum computing", mode="prompt")
|
|
77
|
+
print(prompts.system_prompt) # Anti-hallucination system prompt
|
|
78
|
+
print(prompts.user_prompt) # Rewritten user prompt with grounding cues
|
|
79
|
+
print(prompts.techniques) # Which techniques were selected
|
|
80
|
+
|
|
81
|
+
# Clarity — answer mode (LLM answers with reduced hallucinations, no internet)
|
|
82
|
+
clarity = client.clarity("Write a blog post about quantum computing", mode="answer")
|
|
83
|
+
print(clarity.answer) # LLM answer with reduced hallucinations
|
|
84
|
+
print(clarity.claims) # Extracted claims (origin: "llm")
|
|
85
|
+
print(clarity.confidence) # Confidence score
|
|
86
|
+
|
|
87
|
+
# Clarity — verified mode (LLM + web fusion for maximum accuracy)
|
|
88
|
+
verified = client.clarity("Explain CRISPR gene editing", mode="verified")
|
|
89
|
+
print(verified.answer) # Fused answer (best of LLM + web sources)
|
|
90
|
+
print(verified.claims) # Claims with origin: "confirmed", "llm", or "source"
|
|
91
|
+
print(verified.sources) # Web sources used for verification
|
|
92
|
+
|
|
93
|
+
# Submit feedback to improve accuracy
|
|
94
|
+
client.feedback(result_id=result.share_id, rating="good")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Async
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from lastsearch import AsyncLastSearch
|
|
101
|
+
|
|
102
|
+
async with AsyncLastSearch(api_key="ls_xxx") as client:
|
|
103
|
+
result = await client.ask("What is quantum computing?")
|
|
104
|
+
# Thorough mode works with async too
|
|
105
|
+
thorough = await client.ask("What is quantum computing?", depth="thorough")
|
|
106
|
+
# Deep mode — multi-step agentic research (requires BAI key + sign-in, 3x quota cost)
|
|
107
|
+
deep = await client.ask("Complex research question", depth="deep")
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Streaming (REST API)
|
|
111
|
+
|
|
112
|
+
For real-time progress events, use the streaming endpoint directly:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
import httpx
|
|
116
|
+
|
|
117
|
+
with httpx.stream("POST", "https://lastsearch.ai/api/browse/answer/stream",
|
|
118
|
+
json={"query": "What is quantum computing?"},
|
|
119
|
+
headers={"X-API-Key": "ls_xxx"}
|
|
120
|
+
) as response:
|
|
121
|
+
for line in response.iter_lines():
|
|
122
|
+
if line.startswith("data: "):
|
|
123
|
+
print(line[6:])
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Events: `trace` (progress), `sources` (discovered early), `token` (streamed answer text), `result` (final answer), `done`.
|
|
127
|
+
|
|
128
|
+
## Research Memory (Sessions)
|
|
129
|
+
|
|
130
|
+
Persistent research sessions that accumulate knowledge across multiple queries. Later queries recall prior knowledge — faster, cheaper, more coherent.
|
|
131
|
+
|
|
132
|
+
> **Sessions require a LastSearch API key** (`api_key="ls_xxx"`) for identity and ownership. Get a free API key at [lastsearch.ai/dashboard](https://lastsearch.ai/dashboard).
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from lastsearch import LastSearch
|
|
136
|
+
|
|
137
|
+
client = LastSearch(api_key="ls_xxx")
|
|
138
|
+
|
|
139
|
+
# Create a session
|
|
140
|
+
session = client.session("wasm-research")
|
|
141
|
+
|
|
142
|
+
# Each query builds on previous knowledge
|
|
143
|
+
r1 = session.ask("What is WebAssembly?")
|
|
144
|
+
r2 = session.ask("How does WASM compare to JavaScript performance?")
|
|
145
|
+
# ^ r2 recalls WASM knowledge from r1, only searches for JS perf
|
|
146
|
+
|
|
147
|
+
# Query accumulated knowledge without new searches
|
|
148
|
+
recalled = session.recall("WASM")
|
|
149
|
+
for entry in recalled.entries:
|
|
150
|
+
print(f" {entry.claim} (from: {entry.origin_query})")
|
|
151
|
+
|
|
152
|
+
# Export all knowledge
|
|
153
|
+
knowledge = session.knowledge()
|
|
154
|
+
|
|
155
|
+
# Delete a session
|
|
156
|
+
session.delete()
|
|
157
|
+
|
|
158
|
+
# List all your sessions
|
|
159
|
+
sessions = client.list_sessions()
|
|
160
|
+
|
|
161
|
+
# Resume an existing session by ID
|
|
162
|
+
session = client.get_session("session-id-here")
|
|
163
|
+
|
|
164
|
+
# Share with other agents
|
|
165
|
+
share = session.share()
|
|
166
|
+
print(share.url) # https://lastsearch.ai/session/share/abc123def456
|
|
167
|
+
|
|
168
|
+
# Another agent forks and continues the research
|
|
169
|
+
forked = client.fork_session(share.share_id)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Async sessions work the same way:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
async with AsyncLastSearch(api_key="ls_xxx") as client:
|
|
176
|
+
session = await client.session("my-project")
|
|
177
|
+
r1 = await session.ask("What is WASM?")
|
|
178
|
+
r2 = await session.ask("WASM vs JS?")
|
|
179
|
+
|
|
180
|
+
# Share and fork work async too
|
|
181
|
+
share = await session.share()
|
|
182
|
+
forked = await client.fork_session(share.share_id)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Premium Features (with API Key)
|
|
186
|
+
|
|
187
|
+
Users with a LastSearch API key (`ls_xxx`) get enhanced verification:
|
|
188
|
+
- **Semantic re-ranking** — search results re-scored by semantic query-document relevance
|
|
189
|
+
- **Semantic reranking** — evidence matched by meaning, not just keywords
|
|
190
|
+
- **Multi-provider search** — parallel search across multiple sources for broader coverage
|
|
191
|
+
- **Multi-pass consistency** — claims cross-checked across independent extraction passes (in thorough mode)
|
|
192
|
+
- **Deep reasoning mode** — premium multi-step agentic research with iterative think-search-extract-evaluate cycles, gap analysis, and cross-step claim merging (up to 4 steps, targets 0.85 confidence, 3x quota cost, 100 deep queries/day). Falls back to thorough when quota is exhausted
|
|
193
|
+
- **Token streaming** — per-token answer delivery via SSE for real-time UI
|
|
194
|
+
- **Research Sessions** — persistent memory across queries
|
|
195
|
+
|
|
196
|
+
Free BAI key users get a generous daily quota (100 premium queries/day, or ~33 deep queries/day at 3x cost each). When exceeded, queries gracefully fall back to keyword verification (deep falls back to thorough) — still works, just basic matching. Quota resets every 24 hours. Check `client.last_quota` after any API call for current usage.
|
|
197
|
+
|
|
198
|
+
Sign in at [lastsearch.ai](https://lastsearch.ai) for a free BAI key to unlock premium features.
|
|
199
|
+
|
|
200
|
+
## Contradictions
|
|
201
|
+
|
|
202
|
+
Detect conflicts across sources on controversial topics:
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
result = client.ask("Is coffee good for your health?", depth="thorough")
|
|
206
|
+
if result.contradictions:
|
|
207
|
+
for c in result.contradictions:
|
|
208
|
+
print(f"Conflict on '{c.topic}':")
|
|
209
|
+
print(f" A: {c.claim_a}")
|
|
210
|
+
print(f" B: {c.claim_b}")
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Enterprise Search Providers
|
|
214
|
+
|
|
215
|
+
Use your own data sources instead of — or alongside — public web search. Supports `elasticsearch`, `confluence`, and `custom` endpoints with optional `data_retention="none"` for compliance.
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
from lastsearch.models import SearchProviderConfig
|
|
219
|
+
|
|
220
|
+
# Using the typed model (snake_case fields)
|
|
221
|
+
provider = SearchProviderConfig(
|
|
222
|
+
type="elasticsearch",
|
|
223
|
+
endpoint="https://es.company.com/kb/_search",
|
|
224
|
+
auth_header="Bearer token",
|
|
225
|
+
index="docs",
|
|
226
|
+
)
|
|
227
|
+
result = client.ask("What is our refund policy?", search_provider=provider)
|
|
228
|
+
|
|
229
|
+
# Or pass a plain dict (camelCase keys, sent directly to API)
|
|
230
|
+
result = client.ask("What is our refund policy?", search_provider={
|
|
231
|
+
"type": "elasticsearch",
|
|
232
|
+
"endpoint": "https://es.company.com/kb/_search",
|
|
233
|
+
"authHeader": "Bearer token",
|
|
234
|
+
"index": "docs",
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
# Confluence
|
|
238
|
+
result = client.ask("PCI compliance?", search_provider={
|
|
239
|
+
"type": "confluence",
|
|
240
|
+
"endpoint": "https://company.atlassian.net/wiki/rest/api",
|
|
241
|
+
"authHeader": "Basic base64-creds",
|
|
242
|
+
"spaceKey": "ENG",
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
# Zero data retention (compliance mode — nothing stored, cached, or logged)
|
|
246
|
+
result = client.ask("Patient protocols", search_provider=SearchProviderConfig(
|
|
247
|
+
type="elasticsearch",
|
|
248
|
+
endpoint="https://es.hipaa.company.com/medical/_search",
|
|
249
|
+
auth_header="Bearer token",
|
|
250
|
+
data_retention="none",
|
|
251
|
+
))
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Framework Integrations
|
|
255
|
+
|
|
256
|
+
### LangChain
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
pip install langchain-lastsearch
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
from langchain_lastsearch import LastSearchAnswerTool, LastSearchSearchTool
|
|
264
|
+
|
|
265
|
+
tools = [LastSearchAnswerTool(api_key="ls_xxx")]
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### CrewAI
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
pip install crewai-lastsearch
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
from crewai_lastsearch import LastSearchAnswerTool
|
|
276
|
+
|
|
277
|
+
researcher = Agent(tools=[LastSearchAnswerTool(api_key="ls_xxx")])
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### LlamaIndex
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
pip install llamaindex-lastsearch
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
```python
|
|
287
|
+
from llamaindex_lastsearch import LastSearchAnswerTool
|
|
288
|
+
|
|
289
|
+
answer_tool = LastSearchAnswerTool(api_key="ls_xxx")
|
|
290
|
+
```
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# lastsearch
|
|
2
|
+
|
|
3
|
+
**Reliable research infrastructure for AI agents.** Python SDK for [LastSearch](https://lastsearch.ai) — the research layer for LangChain, CrewAI, and custom agent pipelines.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install lastsearch
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from lastsearch import LastSearch
|
|
15
|
+
|
|
16
|
+
client = LastSearch(api_key="ls_xxx")
|
|
17
|
+
|
|
18
|
+
# Research with citations
|
|
19
|
+
result = client.ask("What is quantum computing?")
|
|
20
|
+
print(result.answer)
|
|
21
|
+
print(f"Confidence: {result.confidence:.0%}")
|
|
22
|
+
for source in result.sources:
|
|
23
|
+
print(f" - {source.title}: {source.url}")
|
|
24
|
+
|
|
25
|
+
# Thorough mode — auto-retries if confidence < 60%
|
|
26
|
+
thorough = client.ask("What is quantum computing?", depth="thorough")
|
|
27
|
+
|
|
28
|
+
# Deep mode — multi-step agentic research with iterative gap analysis (requires BAI key + sign-in)
|
|
29
|
+
# Runs think→search→extract→evaluate cycles (up to 4 steps), 3x quota cost
|
|
30
|
+
deep = client.ask("Compare CRISPR approaches", depth="deep")
|
|
31
|
+
for step in deep.reasoning_steps or []:
|
|
32
|
+
print(f" Step {step.step}: {step.query} ({step.confidence:.0%})")
|
|
33
|
+
|
|
34
|
+
# Web search
|
|
35
|
+
results = client.search("latest AI news", limit=5)
|
|
36
|
+
|
|
37
|
+
# Page extraction
|
|
38
|
+
page = client.open("https://example.com")
|
|
39
|
+
|
|
40
|
+
# Structured extraction from a URL
|
|
41
|
+
extract = client.extract("https://example.com", query="pricing info")
|
|
42
|
+
|
|
43
|
+
# Compare raw LLM vs evidence-backed
|
|
44
|
+
compare = client.compare("Is Python faster than Rust?")
|
|
45
|
+
|
|
46
|
+
# Clarity — prompt mode (get enhanced prompts for your own LLM)
|
|
47
|
+
prompts = client.clarity("Write a blog post about quantum computing", mode="prompt")
|
|
48
|
+
print(prompts.system_prompt) # Anti-hallucination system prompt
|
|
49
|
+
print(prompts.user_prompt) # Rewritten user prompt with grounding cues
|
|
50
|
+
print(prompts.techniques) # Which techniques were selected
|
|
51
|
+
|
|
52
|
+
# Clarity — answer mode (LLM answers with reduced hallucinations, no internet)
|
|
53
|
+
clarity = client.clarity("Write a blog post about quantum computing", mode="answer")
|
|
54
|
+
print(clarity.answer) # LLM answer with reduced hallucinations
|
|
55
|
+
print(clarity.claims) # Extracted claims (origin: "llm")
|
|
56
|
+
print(clarity.confidence) # Confidence score
|
|
57
|
+
|
|
58
|
+
# Clarity — verified mode (LLM + web fusion for maximum accuracy)
|
|
59
|
+
verified = client.clarity("Explain CRISPR gene editing", mode="verified")
|
|
60
|
+
print(verified.answer) # Fused answer (best of LLM + web sources)
|
|
61
|
+
print(verified.claims) # Claims with origin: "confirmed", "llm", or "source"
|
|
62
|
+
print(verified.sources) # Web sources used for verification
|
|
63
|
+
|
|
64
|
+
# Submit feedback to improve accuracy
|
|
65
|
+
client.feedback(result_id=result.share_id, rating="good")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Async
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from lastsearch import AsyncLastSearch
|
|
72
|
+
|
|
73
|
+
async with AsyncLastSearch(api_key="ls_xxx") as client:
|
|
74
|
+
result = await client.ask("What is quantum computing?")
|
|
75
|
+
# Thorough mode works with async too
|
|
76
|
+
thorough = await client.ask("What is quantum computing?", depth="thorough")
|
|
77
|
+
# Deep mode — multi-step agentic research (requires BAI key + sign-in, 3x quota cost)
|
|
78
|
+
deep = await client.ask("Complex research question", depth="deep")
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Streaming (REST API)
|
|
82
|
+
|
|
83
|
+
For real-time progress events, use the streaming endpoint directly:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import httpx
|
|
87
|
+
|
|
88
|
+
with httpx.stream("POST", "https://lastsearch.ai/api/browse/answer/stream",
|
|
89
|
+
json={"query": "What is quantum computing?"},
|
|
90
|
+
headers={"X-API-Key": "ls_xxx"}
|
|
91
|
+
) as response:
|
|
92
|
+
for line in response.iter_lines():
|
|
93
|
+
if line.startswith("data: "):
|
|
94
|
+
print(line[6:])
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Events: `trace` (progress), `sources` (discovered early), `token` (streamed answer text), `result` (final answer), `done`.
|
|
98
|
+
|
|
99
|
+
## Research Memory (Sessions)
|
|
100
|
+
|
|
101
|
+
Persistent research sessions that accumulate knowledge across multiple queries. Later queries recall prior knowledge — faster, cheaper, more coherent.
|
|
102
|
+
|
|
103
|
+
> **Sessions require a LastSearch API key** (`api_key="ls_xxx"`) for identity and ownership. Get a free API key at [lastsearch.ai/dashboard](https://lastsearch.ai/dashboard).
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from lastsearch import LastSearch
|
|
107
|
+
|
|
108
|
+
client = LastSearch(api_key="ls_xxx")
|
|
109
|
+
|
|
110
|
+
# Create a session
|
|
111
|
+
session = client.session("wasm-research")
|
|
112
|
+
|
|
113
|
+
# Each query builds on previous knowledge
|
|
114
|
+
r1 = session.ask("What is WebAssembly?")
|
|
115
|
+
r2 = session.ask("How does WASM compare to JavaScript performance?")
|
|
116
|
+
# ^ r2 recalls WASM knowledge from r1, only searches for JS perf
|
|
117
|
+
|
|
118
|
+
# Query accumulated knowledge without new searches
|
|
119
|
+
recalled = session.recall("WASM")
|
|
120
|
+
for entry in recalled.entries:
|
|
121
|
+
print(f" {entry.claim} (from: {entry.origin_query})")
|
|
122
|
+
|
|
123
|
+
# Export all knowledge
|
|
124
|
+
knowledge = session.knowledge()
|
|
125
|
+
|
|
126
|
+
# Delete a session
|
|
127
|
+
session.delete()
|
|
128
|
+
|
|
129
|
+
# List all your sessions
|
|
130
|
+
sessions = client.list_sessions()
|
|
131
|
+
|
|
132
|
+
# Resume an existing session by ID
|
|
133
|
+
session = client.get_session("session-id-here")
|
|
134
|
+
|
|
135
|
+
# Share with other agents
|
|
136
|
+
share = session.share()
|
|
137
|
+
print(share.url) # https://lastsearch.ai/session/share/abc123def456
|
|
138
|
+
|
|
139
|
+
# Another agent forks and continues the research
|
|
140
|
+
forked = client.fork_session(share.share_id)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Async sessions work the same way:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
async with AsyncLastSearch(api_key="ls_xxx") as client:
|
|
147
|
+
session = await client.session("my-project")
|
|
148
|
+
r1 = await session.ask("What is WASM?")
|
|
149
|
+
r2 = await session.ask("WASM vs JS?")
|
|
150
|
+
|
|
151
|
+
# Share and fork work async too
|
|
152
|
+
share = await session.share()
|
|
153
|
+
forked = await client.fork_session(share.share_id)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Premium Features (with API Key)
|
|
157
|
+
|
|
158
|
+
Users with a LastSearch API key (`ls_xxx`) get enhanced verification:
|
|
159
|
+
- **Semantic re-ranking** — search results re-scored by semantic query-document relevance
|
|
160
|
+
- **Semantic reranking** — evidence matched by meaning, not just keywords
|
|
161
|
+
- **Multi-provider search** — parallel search across multiple sources for broader coverage
|
|
162
|
+
- **Multi-pass consistency** — claims cross-checked across independent extraction passes (in thorough mode)
|
|
163
|
+
- **Deep reasoning mode** — premium multi-step agentic research with iterative think-search-extract-evaluate cycles, gap analysis, and cross-step claim merging (up to 4 steps, targets 0.85 confidence, 3x quota cost, 100 deep queries/day). Falls back to thorough when quota is exhausted
|
|
164
|
+
- **Token streaming** — per-token answer delivery via SSE for real-time UI
|
|
165
|
+
- **Research Sessions** — persistent memory across queries
|
|
166
|
+
|
|
167
|
+
Free BAI key users get a generous daily quota (100 premium queries/day, or ~33 deep queries/day at 3x cost each). When exceeded, queries gracefully fall back to keyword verification (deep falls back to thorough) — still works, just basic matching. Quota resets every 24 hours. Check `client.last_quota` after any API call for current usage.
|
|
168
|
+
|
|
169
|
+
Sign in at [lastsearch.ai](https://lastsearch.ai) for a free BAI key to unlock premium features.
|
|
170
|
+
|
|
171
|
+
## Contradictions
|
|
172
|
+
|
|
173
|
+
Detect conflicts across sources on controversial topics:
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
result = client.ask("Is coffee good for your health?", depth="thorough")
|
|
177
|
+
if result.contradictions:
|
|
178
|
+
for c in result.contradictions:
|
|
179
|
+
print(f"Conflict on '{c.topic}':")
|
|
180
|
+
print(f" A: {c.claim_a}")
|
|
181
|
+
print(f" B: {c.claim_b}")
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Enterprise Search Providers
|
|
185
|
+
|
|
186
|
+
Use your own data sources instead of — or alongside — public web search. Supports `elasticsearch`, `confluence`, and `custom` endpoints with optional `data_retention="none"` for compliance.
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from lastsearch.models import SearchProviderConfig
|
|
190
|
+
|
|
191
|
+
# Using the typed model (snake_case fields)
|
|
192
|
+
provider = SearchProviderConfig(
|
|
193
|
+
type="elasticsearch",
|
|
194
|
+
endpoint="https://es.company.com/kb/_search",
|
|
195
|
+
auth_header="Bearer token",
|
|
196
|
+
index="docs",
|
|
197
|
+
)
|
|
198
|
+
result = client.ask("What is our refund policy?", search_provider=provider)
|
|
199
|
+
|
|
200
|
+
# Or pass a plain dict (camelCase keys, sent directly to API)
|
|
201
|
+
result = client.ask("What is our refund policy?", search_provider={
|
|
202
|
+
"type": "elasticsearch",
|
|
203
|
+
"endpoint": "https://es.company.com/kb/_search",
|
|
204
|
+
"authHeader": "Bearer token",
|
|
205
|
+
"index": "docs",
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
# Confluence
|
|
209
|
+
result = client.ask("PCI compliance?", search_provider={
|
|
210
|
+
"type": "confluence",
|
|
211
|
+
"endpoint": "https://company.atlassian.net/wiki/rest/api",
|
|
212
|
+
"authHeader": "Basic base64-creds",
|
|
213
|
+
"spaceKey": "ENG",
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
# Zero data retention (compliance mode — nothing stored, cached, or logged)
|
|
217
|
+
result = client.ask("Patient protocols", search_provider=SearchProviderConfig(
|
|
218
|
+
type="elasticsearch",
|
|
219
|
+
endpoint="https://es.hipaa.company.com/medical/_search",
|
|
220
|
+
auth_header="Bearer token",
|
|
221
|
+
data_retention="none",
|
|
222
|
+
))
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Framework Integrations
|
|
226
|
+
|
|
227
|
+
### LangChain
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
pip install langchain-lastsearch
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
from langchain_lastsearch import LastSearchAnswerTool, LastSearchSearchTool
|
|
235
|
+
|
|
236
|
+
tools = [LastSearchAnswerTool(api_key="ls_xxx")]
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### CrewAI
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
pip install crewai-lastsearch
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
from crewai_lastsearch import LastSearchAnswerTool
|
|
247
|
+
|
|
248
|
+
researcher = Agent(tools=[LastSearchAnswerTool(api_key="ls_xxx")])
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### LlamaIndex
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
pip install llamaindex-lastsearch
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from llamaindex_lastsearch import LastSearchAnswerTool
|
|
259
|
+
|
|
260
|
+
answer_tool = LastSearchAnswerTool(api_key="ls_xxx")
|
|
261
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""LastSearch — Reliable research infrastructure for AI agents."""
|
|
2
|
+
|
|
3
|
+
from .client import DISCLAIMER, AsyncLastSearch, LastSearch
|
|
4
|
+
from .exceptions import (
|
|
5
|
+
AuthenticationError,
|
|
6
|
+
LastSearchError,
|
|
7
|
+
InsufficientCreditsError,
|
|
8
|
+
RateLimitError,
|
|
9
|
+
ServerError,
|
|
10
|
+
ValidationError,
|
|
11
|
+
)
|
|
12
|
+
from .models import (
|
|
13
|
+
BrowseClaim,
|
|
14
|
+
BrowseResult,
|
|
15
|
+
BrowseSource,
|
|
16
|
+
ClarityClaim,
|
|
17
|
+
ClarityResult,
|
|
18
|
+
CompareResult,
|
|
19
|
+
Contradiction,
|
|
20
|
+
KnowledgeEntry,
|
|
21
|
+
NLIScore,
|
|
22
|
+
PageResult,
|
|
23
|
+
PremiumQuota,
|
|
24
|
+
ReasoningStep,
|
|
25
|
+
RecallResult,
|
|
26
|
+
SearchProviderConfig,
|
|
27
|
+
SearchResult,
|
|
28
|
+
Session,
|
|
29
|
+
SessionAskResult,
|
|
30
|
+
TraceStep,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"LastSearch",
|
|
35
|
+
"AsyncLastSearch",
|
|
36
|
+
"LastSearchError",
|
|
37
|
+
"AuthenticationError",
|
|
38
|
+
"RateLimitError",
|
|
39
|
+
"InsufficientCreditsError",
|
|
40
|
+
"ValidationError",
|
|
41
|
+
"ServerError",
|
|
42
|
+
"BrowseResult",
|
|
43
|
+
"BrowseSource",
|
|
44
|
+
"BrowseClaim",
|
|
45
|
+
"Contradiction",
|
|
46
|
+
"ReasoningStep",
|
|
47
|
+
"TraceStep",
|
|
48
|
+
"SearchResult",
|
|
49
|
+
"PageResult",
|
|
50
|
+
"CompareResult",
|
|
51
|
+
"Session",
|
|
52
|
+
"KnowledgeEntry",
|
|
53
|
+
"SessionAskResult",
|
|
54
|
+
"RecallResult",
|
|
55
|
+
"PremiumQuota",
|
|
56
|
+
"SearchProviderConfig",
|
|
57
|
+
"NLIScore",
|
|
58
|
+
"ClarityClaim",
|
|
59
|
+
"ClarityResult",
|
|
60
|
+
"DISCLAIMER",
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
__version__ = "1.0.0"
|