Skip to main content

Dewey

dewey

CI

Python client for the Dewey API. No third-party dependencies — uses only the Python standard library. See the full API reference for details on all endpoints and types.

Installation

pip install dewey

Quick start

from dewey import DeweyClient

client = DeweyClient(api_key="dwy_live_...")

# Create a collection (project_id from your Dewey dashboard → Project Settings)
col = client.collections.create("My Docs", project_id="proj_...")

# Upload a document
from pathlib import Path
doc = client.documents.upload(col.id, Path("report.pdf"))

# Query
results = client.retrieval.query(col.id, "What is the refund policy?")
for r in results:
    print(r.score, r.chunk.content[:100])

# Research (SSE streaming)
for event in client.research.stream(col.id, "Summarise key findings"):
    if event.type == "chunk":
        print(event.content, end="", flush=True)
    elif event.type == "done":
        print("\nSources:", event.sources)

Constructor

DeweyClient(api_key: str, base_url: str = "https://api.meetdewey.com/v1")

Resources

client.collections

Method Description
create(name, *, visibility, chunk_size, chunk_overlap, embedding_model) Create a collection
list() List collections
get(collection_id) Get by ID
update(collection_id, *, name, visibility, ...) Update
delete(collection_id) Delete
stats(collection_id) Document count, storage, section/chunk/claim counts
recompute_summaries(collection_id) Re-run AI section summarization
recompute_captions(collection_id) Re-run AI captioning for images and tables
recompute_claims(collection_id) Re-extract factual claims (clears existing)

update() accepts: name, visibility, chunk_size, chunk_overlap, description, enable_summarization, enable_captioning, enable_reranking, enable_deduplication, llm_model, instructions. llm_model and instructions accept None to clear the field; omit them entirely to leave unchanged.

# Set research instructions for a collection
client.collections.update(
    collection_id,
    instructions="All figures are in USD unless stated otherwise.",
)

# Clear instructions
client.collections.update(collection_id, instructions=None)

# Get collection statistics
stats = client.collections.stats(collection_id)
print(f"{stats.docCount} docs, {stats.totalClaimsCount} claims")

client.documents

Method Description
upload(collection_id, file, *, filename, content_type, ...) Multipart upload
upload_many(collection_id, files, *, concurrency, on_progress) Bulk upload via presigned S3 URLs
request_upload_url(collection_id, filename, content_type, file_size_bytes, content_hash) Presigned URL
confirm(collection_id, document_id) Confirm presigned upload
list(collection_id) List documents
get(collection_id, document_id) Get document
get_markdown(collection_id, document_id) Get Markdown string
retry(collection_id, document_id) Retry failed document
delete(collection_id, document_id) Delete document

upload() accepts a pathlib.Path, bytes, or any binary file-like object.

upload_many() is the recommended approach for large datasets. Each file is uploaded directly to S3 (bypassing the API server), so there are no payload-size limits. Files that match an existing document's hash are deduplicated automatically.

from pathlib import Path

docs = client.documents.upload_many(
    collection_id,
    list(Path("./reports").glob("**/*.pdf")),
    concurrency=10,
    on_progress=lambda doc, n, total: print(f"{n}/{total} {doc.filename}"),
)

Pass UploadManyItem instances when you need a custom filename or content type:

from dewey.resources.documents import UploadManyItem
from io import BytesIO

items = [
    UploadManyItem(file=BytesIO(data), filename="custom-name.pdf", content_type="application/pdf"),
]
docs = client.documents.upload_many(collection_id, items)

client.sections

Method Description
list(collection_id, document_id) List sections
get(section_id) Get section with content
get_chunks(section_id) Get chunks
scan(collection_id, query, *, top_k) Full-text section scan

client.retrieval

Method Description
query(collection_id, q, *, limit) Hybrid search

client.research

Method Description
stream(collection_id, q, *, depth, model) SSE research → Generator[ResearchEvent]

depth options: "quick", "balanced" (default), "deep", "exhaustive".

client.agents

Invoke saved agents defined in the dashboard. org_id and project_id are UUIDs (not slugs); agent_slug is the human-readable slug shown in dashboard URLs (e.g. "qa-test").

Method Description
invoke_sync(org_id, project_id, agent_slug, *, query) Buffered run → AgentInvokeResult
stream(org_id, project_id, agent_slug, *, query) SSE run → Generator[AgentRunEvent]
# Buffered — returns once the run terminates
result = client.agents.invoke_sync(
    org_id, project_id, "qa-test",
    query="What changed in 2023?",
)
print(result.response)
for s in result.sources:
    print(f"- {s.filename} § {s.sectionTitle}")

# Streaming — yields tool calls, tokens, and the final done event
for event in client.agents.stream(
    org_id, project_id, "qa-test",
    query="What changed in 2023?",
):
    if event.type == "chunk":
        print(event.content, end="", flush=True)
    elif event.type == "done":
        print(f"\n{len(event.sources)} sources")

AgentRunEvent is a tagged union: AgentRunEventStarted, AgentRunEventToolCall, AgentRunEventToolResult, AgentRunEventChunk, AgentRunEventDone, AgentRunEventError, AgentRunEventWarning. Match on event.type to discriminate.

client.claims

Method Description
map_stream(collection_id) SSE stream of all claims with UMAP coordinates
list_by_document(document_id, *, min_importance) Claims extracted from a specific document

map_stream() yields raw event dicts. Check event["type"]: "progress", "done" (with claims list), or "error".

from dewey.types import ClaimMapItem

for event in client.claims.map_stream(collection_id):
    if event["type"] == "done":
        claims = [ClaimMapItem.from_dict(c) for c in event["claims"]]
        for claim in claims:
            print(f"[{claim.importance}] {claim.text}")

# Per-document claims (fast, no SSE)
result = client.claims.list_by_document(document_id, min_importance=3)
for claim in result.claims:
    print(claim.text)

client.contradictions

Method Description
list(collection_id, *, severity, status, limit) List detected contradictions
detect(collection_id) Trigger async contradiction detection run
get_latest_run(collection_id) Poll status of the latest detection run
dismiss(collection_id, contradiction_id) Mark a contradiction as ignored
apply_instruction(collection_id, contradiction_id, instruction) Apply resolution; appends to collection instructions
# Trigger detection
run = client.contradictions.detect(collection_id)
print("Run ID:", run.runId)

# Later: poll status
status = client.contradictions.get_latest_run(collection_id)
print(status.status, status.contradictionsFound)

# List active contradictions and apply resolutions
result = client.contradictions.list(collection_id, status="active")
for c in result.items:
    print(c.severity, c.explanation)
    # Apply the suggested resolution
    client.contradictions.apply_instruction(collection_id, c.id)

client.duplicates

Fuzzy document deduplication. Identifies near-duplicate documents by measuring how much content they share, marks one member of each cluster as canonical, and excludes near-duplicates from retrieval and contradiction detection. Must be enabled per-collection with client.collections.update(id, enable_deduplication=True).

Method Description
detect(collection_id) Trigger async dedup run across all ready documents
get_latest_run(collection_id) Poll status of the latest dedup run
list(collection_id, *, limit, offset) List duplicate groups with members and coverage percentages
promote_canonical(collection_id, group_id, canonical_document_id) Promote a different member to canonical; old canonical becomes near_duplicate
disband(collection_id, group_id) Disband a group; all former members rejoin retrieval as distinct
# Enable on a collection (one-time)
client.collections.update(collection_id, enable_deduplication=True)

# Trigger detection, then poll
run = client.duplicates.detect(collection_id)
status = client.duplicates.get_latest_run(collection_id)
print(status.status, status.duplicateGroupsCreated)

# Review groups
result = client.duplicates.list(collection_id)
for group in result.items:
    for m in group.members:
        if m.relationship == "near_duplicate":
            pct = round((m.coverageToCanonical or 0) * 100)
            print(f"{m.filename} covers {pct}% of canonical")

client.provider_keys

Method Description
create(project_id, provider, key, name) Add provider key
list(project_id) List keys
delete(project_id, key_id) Delete key

Error handling

from dewey import DeweyClient, DeweyError

client = DeweyClient(api_key="dwy_live_...")

try:
    client.collections.get("unknown-id")
except DeweyError as e:
    print(e.status, e.message)  # e.g. 404 "Collection not found"

Presigned upload flow

For single files or when you need manual control, use the low-level presigned URL flow. For bulk ingestion, prefer upload_many() which handles this automatically with concurrency.

import hashlib
import urllib.request
from pathlib import Path

data = Path("file.pdf").read_bytes()
content_hash = hashlib.sha256(data).hexdigest()

# 1. Request a presigned URL
resp = client.documents.request_upload_url(
    collection_id,
    filename="file.pdf",
    content_type="application/pdf",
    file_size_bytes=len(data),
    content_hash=content_hash,
)

# 2. PUT bytes directly to S3 (no auth header needed)
req = urllib.request.Request(resp.uploadUrl, data=data, method="PUT")
req.add_header("Content-Type", "application/pdf")
urllib.request.urlopen(req)

# 3. Confirm to trigger ingestion
doc = client.documents.confirm(collection_id, resp.documentId)

Metadata

Release files for meetdewey 2.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for meetdewey 2.5.0
File Size Uploaded Provenance
meetdewey-2.5.0.tar.gz 32.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for meetdewey 2.5.0
File Interpreter ABI Platform
meetdewey-2.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 59.4 kB

Release files / meetdewey-2.5.0.tar.gz

Download URL meetdewey-2.5.0.tar.gz
Size 32.4 kB
Tags Source
SHA-256 checksum
How to use checksums
605a1b72b7dd7c200a217df877201e2d838adbfa915fbb766912e16c5c6dc307
BLAKE2b-256 checksum
How to use checksums
aa248b6db5eaae2fcd54228fa73729afe367aaffae46eea84793ca4f18cc6e98
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / meetdewey-2.5.0-py3-none-any.whl

Download URL meetdewey-2.5.0-py3-none-any.whl
Size 26.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f38300576e436f181c41894269e7cc76522708f3517370e21ef8913e2d2ca597
BLAKE2b-256 checksum
How to use checksums
83e241940c1a6b74e3ecf20159fffd5acfd341b338438677de64d940a689e936
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Security for meetdewey 2.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page