NEWpromptev for Android and Chrome: your agents on your phone and in your browser. Get the apps→

Context Engine: Python SDK reference

The knowledge parts of the promptev package: upload documents and search your knowledge base. For a guided walk through, start with the guide.

Overview

The Context Engine is hosted by promptev. The Python SDK reaches it with a project API key: ingestion with upload_document and retrieval with search_knowledge_base. Every method has an async form.

MethodWhat it doesReturns
upload_document(file, *, mode=None)Put one document into the key’s project.DocumentResult
upload_documents(files, *, mode=None)Put up to 20 documents into the key’s project.List[DocumentResult]
search_knowledge_base(action, **fields)Read the key’s project knowledge base.dict
aupload_document(...)Async form of upload_document.DocumentResult
aupload_documents(...)Async form of upload_documents.List[DocumentResult]
asearch_knowledge_base(...)Async form of search_knowledge_base.dict

Install

Package promptev, version 1.3.0, Python 3.8 or later.

Shell
pip install promptev

PromptevClient

The key belongs to one project, so no call names a project. Create the key under the project’s API keys in the promptev console. Keep it on your server.

Python
from promptev import PromptevClient

client = PromptevClient(api_key="fk_...")

# or close it for you
with PromptevClient(api_key="fk_...", timeout=120) as client:
    ...
ArgumentTypeDefaultMeaning
api_keystrrequiredThe project API key (fk_...), from the project’s API keys in the console.
base_urlstrhttps://api.promptev.aiWhere the API is.
headersdict | NoneNoneExtra HTTP headers on every request.
timeoutfloat30.0Seconds to wait. An upload returns when its files are ready, so raise it for large files.
max_retriesint2Retries on a 502, 503 or 504.

upload_document and upload_documents

Put files into the key’s project knowledge base, in the same Uploads source the console writes to. The project’s agents can use them on their next turn.

Python
result = client.upload_document("handbook.pdf")
print(result.ok, result.status, result.document_id, result.chunks)

results = client.upload_documents([
    "policies/refunds.pdf",                 # a path
    ("release-notes.md", b"# 1.0\n..."),     # (filename, bytes)
    open("handbook.docx", "rb"),            # an open binary file
])
for r in results:
    print(r.filename, r.status, r.error or "")

client.upload_document("org-chart.pdf", mode="graph")   # build the Context Graph too
  • A file is a path, a (filename, bytes) pair, or an open binary file. The name matters: its extension decides how the file is read.
  • Limits: up to 20 files per call, 25 MB each. Larger sets belong in a connector source (Google Drive, SharePoint, Dropbox and more).
  • mode: leave it out for the workspace’s default, or pass "graph" to also extract entities and relationships into the Context Graph.
  • One result per file, in order. A file that fails is reported in its own row and never fails the batch.
  • Same bytes, same document: uploading an identical file again updates it instead of adding a copy.

DocumentResult

FieldTypeMeaning
filenamestrThe file’s name.
statusstrWhat became of it. "failed" when it did not land.
document_idstr | NoneThe document’s id, or None when it did not land.
chunksintHow many passages it was split into.
unitsintThe ingestion units counted for this file.
errorstr | NoneWhy this file failed, or None.
okbool (property)True when the file landed.
rawdictThe server’s row for this file, as sent.

Actions

The graph actions (get_neighbors, traverse, find_related, community_summary) need documents uploaded in graph mode. discover says which actions the project can run.

ActionWhat you getFields
discoverEach document and what is inside it (a sheet’s columns, a document’s sections), the extracted fields, and which actions the project can run. Call it first.source_ids, document_ids, limit, cursor
searchPassages by meaning or keywords, as hits. For an ID, code or invoice number, search the bare identifier.query, top_k, mode, source_ids, document_ids
get_docOne whole document by id.document_id
get_docsSeveral whole documents at once.document_ids, max_chars
get_chunksOne long document in order, up to 25 passages at a time.document_id, start, end
listBrowse the documents without searching.source_ids, document_ids, limit, cursor
query_metaThe structured fields a question names (dates, amounts, parties) and each document’s value. Compare the values yourself.query, source_ids, limit
computeA figure from the spreadsheets (total, average, count, ranking, margin) or the exact row for one value, over every row. Ask in plain words.query, source_ids, document_ids
map_reduceThe same question asked of every document in scope, one answer per document.query, source_ids, document_ids
get_neighborsWhat is one step from a named thing in the Context Graph.entity, limit
traverseEverything within a few steps of a named thing. For how two things connect, traverse from one.entity, depth, category, limit
find_relatedConnections of one kind across the knowledge base, with no starting thing.category, label, entity_type, limit
community_summaryThe main themes and groups the knowledge base falls into.query, limit

Fields

FieldTypeMeaning
querystrWhat you are looking for, in words, or a bare identifier you are looking up.
top_kintHow many passages a search returns. Default 10.
mode"hybrid" | "graph"How a search ranks. Leave it out and the right one is chosen. "graph" also uses how things connect.
document_idstrOne document’s id, from discover, list or a search hit. Not a number written inside a document.
document_idslist[str]Narrow to these documents.
source_idslist[str]Narrow to these sources (an upload folder, a connector).
limitintHow many rows: documents for discover and list (default 50), candidates for query_meta (20), links for the graph actions (50), groups for community_summary (3).
cursorstrThe next_cursor a previous page returned.
entitystrWhere a graph action starts: an entity id from an earlier graph answer (best), or a name as written in the documents.
depthintHow many steps traverse walks, 1 to 5. Default 2.
categorystrThe kind of connection to follow or find. discover lists the ones in your knowledge base.
labelstrThe exact relationship wording, for example reports_to. Narrower than category.
entity_typestrKeep only connections with this type of entity on one end.
startintFirst passage to read, from 0. A search hit’s chunk_idx reads around that passage.
endintLast passage to read, inclusive.
max_charsintHow much text get_docs returns before it stops and hands back the ids it did not reach.

What comes back

A dict, the knowledge base’s answer as sent. A search returns hits, best first:

JSON
{
  "hits": [
    {
      "document_id": "…",
      "document_name": "refund-policy.pdf",
      "chunk_text": "Refunds are accepted within 30 days …",
      "score": 0.82,
      "source_id": "…",
      "chunk_idx": 4
    }
  ]
}

discover and list return documents (each with id, name, source_id and kind), count and has_more. When there is more, send next_cursor back as cursor:

Python
page = client.search_knowledge_base("list", limit=50)
while True:
    for d in page["documents"]:
        print(d["name"])
    if not page.get("has_more"):
        break
    page = client.search_knowledge_base("list", limit=50, cursor=page["next_cursor"])

Follow the answer. An answer may carry a next_action or next_page: the next call, already filled in. Cite document_name when you show a passage.

Async

aupload_document, aupload_documents and asearch_knowledge_base take the same arguments and return the same things.

Python
import asyncio
from promptev import PromptevClient

async def main():
    async with PromptevClient(api_key="fk_...") as client:
        result = await client.aupload_document("handbook.pdf")
        found = await client.asearch_knowledge_base("search", query="how many days do customers have to ask for a refund")
        print(result.status, len(found["hits"]))

asyncio.run(main())

Errors

Every error is a PromptevError with message, status_code, response_text and, when known, field. A 502, 503 or 504 is retried (max_retries) before ServerError is raised.

ErrorStatusWhen
ValidationError422 (or 400)An unknown action or a field it does not take; no files, more than 20, a file over 25 MB, a type that is not accepted, or a mode that cannot be served. Some are caught before the request is sent. e.field names the field.
AuthenticationError401 (or 403)The key is missing, malformed, revoked or expired.
InsufficientCreditsError402The workspace has no credits left. A top-up fixes it, a retry does not.
NotFoundError404The key reaches no project.
RateLimitError429Too many requests. e.retry_after says how many seconds to wait.
ServerError5xxThe server failed, after the retries.
NetworkErrornoneNo answer: connection, DNS or timeout.
Python
from promptev import (
    PromptevClient, ValidationError, AuthenticationError,
    InsufficientCreditsError, NotFoundError, RateLimitError,
)

try:
    found = client.search_knowledge_base("search", query="how many days do customers have to ask for a refund")
except ValidationError as e:
    print("Fix the request:", e.message, e.field)
except InsufficientCreditsError:
    print("Out of credits: top up the workspace")
except RateLimitError as e:
    print("Slow down, retry in", e.retry_after, "seconds")

Credits and costs are on the guide.

1,000 free credits for a 30-day trial · No card required · No subscription1,000 free credits · 30-day trial · No card