Metadata-Version: 2.5
Name: lastsearch
Version: 1.0.1
Summary: Python SDK for LastSearch — Grounded Intelligence research infrastructure for AI agents
Project-URL: Homepage, https://lastsearch.ai
Project-URL: Documentation, https://lastsearch.ai/developers
Project-URL: Repository, https://github.com/lastsearch-hq/lastsearch
Project-URL: Discord, https://discord.gg/ubAuT4YQsT
Author: LastSearch
License-Expression: Apache-2.0
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
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: httpx>=0.25.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: crewai
Requires-Dist: crewai>=0.41.0; extra == 'crewai'
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.2.0; extra == 'langchain'
Description-Content-Type: text/markdown

# lastsearch

**Reliable research infrastructure for AI agents.** Python SDK for [LastSearch](https://lastsearch.ai) — the research layer for LangChain, CrewAI, and custom agent pipelines.

## Install

```bash
pip install lastsearch
```

## Quick Start

```python
from lastsearch import LastSearch

client = LastSearch(api_key="ls_xxx")

# Research with citations
result = client.ask("What is quantum computing?")
print(result.answer)
print(f"Confidence: {result.confidence:.0%}")
for source in result.sources:
    print(f"  - {source.title}: {source.url}")

# Thorough mode — auto-retries if confidence < 60%
thorough = client.ask("What is quantum computing?", depth="thorough")

# Deep mode — multi-step agentic research with iterative gap analysis (requires LastSearch key + sign-in)
# Runs think→search→extract→evaluate cycles (up to 4 steps), 3x quota cost
deep = client.ask("Compare CRISPR approaches", depth="deep")
for step in deep.reasoning_steps or []:
    print(f"  Step {step.step}: {step.query} ({step.confidence:.0%})")

# Web search
results = client.search("latest AI news", limit=5)

# Page extraction
page = client.open("https://example.com")

# Structured extraction from a URL
extract = client.extract("https://example.com", query="pricing info")

# Compare raw LLM vs evidence-backed
compare = client.compare("Is Python faster than Rust?")

# Clarity — prompt mode (get enhanced prompts for your own LLM)
prompts = client.clarity("Write a blog post about quantum computing", mode="prompt")
print(prompts.system_prompt)  # Anti-hallucination system prompt
print(prompts.user_prompt)    # Rewritten user prompt with grounding cues
print(prompts.techniques)     # Which techniques were selected

# Clarity — answer mode (LLM answers with reduced hallucinations, no internet)
clarity = client.clarity("Write a blog post about quantum computing", mode="answer")
print(clarity.answer)         # LLM answer with reduced hallucinations
print(clarity.claims)         # Extracted claims (origin: "llm")
print(clarity.confidence)     # Confidence score

# Clarity — verified mode (LLM + web fusion for maximum accuracy)
verified = client.clarity("Explain CRISPR gene editing", mode="verified")
print(verified.answer)        # Fused answer (best of LLM + web sources)
print(verified.claims)        # Claims with origin: "confirmed", "llm", or "source"
print(verified.sources)       # Web sources used for verification

# Submit feedback to improve accuracy
client.feedback(result_id=result.share_id, rating="good")
```

## Async

```python
from lastsearch import AsyncLastSearch

async with AsyncLastSearch(api_key="ls_xxx") as client:
    result = await client.ask("What is quantum computing?")
    # Thorough mode works with async too
    thorough = await client.ask("What is quantum computing?", depth="thorough")
    # Deep mode — multi-step agentic research (requires LastSearch key + sign-in, 3x quota cost)
    deep = await client.ask("Complex research question", depth="deep")
```

## Streaming (REST API)

For real-time progress events, use the streaming endpoint directly:

```python
import httpx

with httpx.stream("POST", "https://lastsearch.ai/api/browse/answer/stream",
    json={"query": "What is quantum computing?"},
    headers={"X-API-Key": "ls_xxx"}
) as response:
    for line in response.iter_lines():
        if line.startswith("data: "):
            print(line[6:])
```

Events: `trace` (progress), `sources` (discovered early), `token` (streamed answer text), `result` (final answer), `done`.

## Research Memory (Sessions)

Persistent research sessions that accumulate knowledge across multiple queries. Later queries recall prior knowledge — faster, cheaper, more coherent.

> **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).

```python
from lastsearch import LastSearch

client = LastSearch(api_key="ls_xxx")

# Create a session
session = client.session("wasm-research")

# Each query builds on previous knowledge
r1 = session.ask("What is WebAssembly?")
r2 = session.ask("How does WASM compare to JavaScript performance?")
# ^ r2 recalls WASM knowledge from r1, only searches for JS perf

# Query accumulated knowledge without new searches
recalled = session.recall("WASM")
for entry in recalled.entries:
    print(f"  {entry.claim} (from: {entry.origin_query})")

# Export all knowledge
knowledge = session.knowledge()

# Delete a session
session.delete()

# List all your sessions
sessions = client.list_sessions()

# Resume an existing session by ID
session = client.get_session("session-id-here")

# Share with other agents
share = session.share()
print(share.url)  # https://lastsearch.ai/session/share/abc123def456

# Another agent forks and continues the research
forked = client.fork_session(share.share_id)
```

Async sessions work the same way:

```python
async with AsyncLastSearch(api_key="ls_xxx") as client:
    session = await client.session("my-project")
    r1 = await session.ask("What is WASM?")
    r2 = await session.ask("WASM vs JS?")

    # Share and fork work async too
    share = await session.share()
    forked = await client.fork_session(share.share_id)
```

## Premium Features (with API Key)

Users with a LastSearch API key (`ls_xxx`) get enhanced verification:
- **Semantic re-ranking** — search results re-scored by semantic query-document relevance
- **Semantic reranking** — evidence matched by meaning, not just keywords
- **Multi-provider search** — parallel search across multiple sources for broader coverage
- **Multi-pass consistency** — claims cross-checked across independent extraction passes (in thorough mode)
- **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
- **Token streaming** — per-token answer delivery via SSE for real-time UI
- **Research Sessions** — persistent memory across queries

Free LastSearch 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.

Sign in at [lastsearch.ai](https://lastsearch.ai) for a free LastSearch key to unlock premium features.

## Contradictions

Detect conflicts across sources on controversial topics:

```python
result = client.ask("Is coffee good for your health?", depth="thorough")
if result.contradictions:
    for c in result.contradictions:
        print(f"Conflict on '{c.topic}':")
        print(f"  A: {c.claim_a}")
        print(f"  B: {c.claim_b}")
```

## Enterprise Search Providers

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.

```python
from lastsearch.models import SearchProviderConfig

# Using the typed model (snake_case fields)
provider = SearchProviderConfig(
    type="elasticsearch",
    endpoint="https://es.company.com/kb/_search",
    auth_header="Bearer token",
    index="docs",
)
result = client.ask("What is our refund policy?", search_provider=provider)

# Or pass a plain dict (camelCase keys, sent directly to API)
result = client.ask("What is our refund policy?", search_provider={
    "type": "elasticsearch",
    "endpoint": "https://es.company.com/kb/_search",
    "authHeader": "Bearer token",
    "index": "docs",
})

# Confluence
result = client.ask("PCI compliance?", search_provider={
    "type": "confluence",
    "endpoint": "https://company.atlassian.net/wiki/rest/api",
    "authHeader": "Basic base64-creds",
    "spaceKey": "ENG",
})

# Zero data retention (compliance mode — nothing stored, cached, or logged)
result = client.ask("Patient protocols", search_provider=SearchProviderConfig(
    type="elasticsearch",
    endpoint="https://es.hipaa.company.com/medical/_search",
    auth_header="Bearer token",
    data_retention="none",
))
```

## Framework Integrations

### LangChain

```bash
pip install langchain-lastsearch
```

```python
from langchain_lastsearch import LastSearchAnswerTool, LastSearchSearchTool

tools = [LastSearchAnswerTool(api_key="ls_xxx")]
```

### CrewAI

```bash
pip install crewai-lastsearch
```

```python
from crewai_lastsearch import LastSearchAnswerTool

researcher = Agent(tools=[LastSearchAnswerTool(api_key="ls_xxx")])
```

### LlamaIndex

```bash
pip install llamaindex-lastsearch
```

```python
from llamaindex_lastsearch import LastSearchAnswerTool

answer_tool = LastSearchAnswerTool(api_key="ls_xxx")
```
