Skip to main content

Agents and knowledge

Ask an agent​

agent = client.get_agent(42) # a published agent's id
reply = agent.ask("How many orders were cancelled last month?")
print(reply["answer"])

follow_up = agent.ask("And the month before?", session_id=reply["session_id"])

Agent.ask(message, *, session_id=None, model=None, webapp_key=None, page_key=None) sends one message and returns the platform's chat response (answer, session_id, and, depending on the agent, sql, rows, follow_ups, …). Pass the returned session_id to continue the conversation. webapp_key (with an optional page_key) grounds a SQL agent in that webapp's dashboard cards, the way the webapp's built-in assistant is grounded.

client.list_agents() returns the agent library ({pinned, enterprise, project, recent_conversations}). client.chat(message, *, agent_id=None, ...) is the same call without a handle. See Agents for building agents.

Stream a reply​

for ev in agent.ask_stream("Top 5 stores by revenue this quarter?"):
if ev["event"] == "token":
print(ev["data"]["text"], end="", flush=True)
elif ev["event"] == "tool_start":
print(f"\n[{ev['data'].get('tool')}]")
elif ev["event"] == "error":
raise RuntimeError(ev["data"])

client.stream_chat(message, *, agent_id=None, session_id=None, model=None, persona=None, system=None, webapp_key=None, page_key=None, history=None, images=None, max_tokens=None, project_id=None, org_id=None) streams from the platform's chat stream endpoint; Agent.ask_stream is the agent-bound form. Both are generators: iterate them to receive the reply as it is produced.

Frames​

Every item is a dict with two keys:

{"event": "token", "data": {"text": "Store 12 leads with"}}
eventdata
token{"text": ...} — the next piece of the answer.
thinking{"text": ...} — reasoning text, when the model emits it.
tool_start{"tool", "label", …} — a tool call began.
tool_result{"tool", "summary", …} — that tool call finished.
citationA citation, collected into citations by collect_stream.
artifactAn artifact attached to the answer.
usageUsage figures for the turn.
errorThe stream failed; the payload describes why.
doneThe turn is complete; carries stop_reason.

The platform also sends session (first), guardrail and paused (the agent stopped for an approval or a question). Any event is passed through unchanged; heartbeat comments and frames whose data is not JSON are skipped. A frame larger than 8 MiB without an end aborts the stream with HoneyframeError (0.1.8+).

Fold a stream into one result​

from honeyframeapi import collect_stream

result = collect_stream(agent.ask_stream("Summarize last week's orders"))
print(result["text"])
print(result["tool_calls"]) # [{"tool", "label", "summary"}, …]
print(result["stop_reason"], result["error"])

collect_stream(events) returns {text, thinking, tool_calls, citations, artifact, usage, stop_reason, error}. parse_sse_frames(buffer) is the low-level parser it builds on: it splits a text buffer into complete events and returns (events, rest).

Personas, history and images​

  • persona= selects a capability persona; the platform intersects it with your own permissions, so it can only narrow what the agent may do.
  • history= passes earlier turns as [{"role": "user" | "assistant", "content": ...}, …].
  • images= attaches pictures for a vision-capable model, as content parts:
import base64

png = base64.b64encode(open("chart.png", "rb").read()).decode()
for ev in client.stream_chat("What does this chart show?", agent_id=42, images=[
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{png}"}},
]):
pass

Images are ignored when the selected model has no vision support.

Knowledge banks​

A knowledge bank is a document corpus an agent searches. Create one, add documents, embed them, then expose it to agents as a search tool. See Knowledge Banks.

client.kb_connector_options() # {vector_stores: [...], embedding_providers: [...]}

kb = client.create_knowledge_base(
"Support procedures",
vector_connector_id=7, # where embeddings are stored
embedding_connector_id=3, # which provider computes them
chunk_size=800, chunk_overlap=100,
)
kb.upload_doc("returns-policy.pdf")
kb.embed() # embed chunks stored before a provider was wired
hits = kb.search("How long is the return window?", top_k=5)
for h in hits["results"]:
print(round(h["score"], 3), h["source"])

tool = kb.create_tool() # a vector_search agent tool bound to this bank
kb.link_agent(agent_asset_id) # an agent's or webapp's asset id

Knowledge banks belong to the client's current project (organization-level banks are visible too). Other calls:

MethodDoes
kb.docs() / kb.remove_doc(doc_id)List or remove documents (and their chunks).
kb.sync()Re-ingest from the bank's source folder.
kb.clear()Drop every document, chunk and vector; keep the bank and its links.
kb.check_vector_store()Check the vector store can hold this bank's embedding size.
kb.usage()Which tools and agents use the bank.
kb.update(**fields) / kb.delete()Change settings; delete (refused with 409 while something still uses it).

LLM connections and spend​

Organization admins govern which models each LLM connection may use and what it may spend.

overview = client.llm_mesh_overview() # connections, policies, month-to-date spend
client.get_llm_policy(connector_id)
client.set_llm_policy(connector_id,
allowed_models=["model-a", "model-b"],
monthly_budget_usd=500, budget_blocking=True)
client.llm_mesh_usage(days=30) # spend by connection, model and day

set_llm_policy replaces the whole policy: allowed_models=None allows every model, monthly_budget_usd=None sets no budget, budget_blocking=True stops calls once the budget is spent (otherwise it only warns), and usable_by is all or admins. A request the platform refuses because the organization's metered budget is spent raises HoneyframeBudgetExceededError (0.1.8+); see Errors and retries.

Push notifications​

client.send_push("Daily briefing ready", "Revenue is up 4% on last week.",
role="manager") # or user_ids=[...]; admin only

Sends to the registered mobile devices of the given users or role and returns {sent, pruned, total, users}.

Comments on project objects​

Any project member can comment on datasets, dashboards, recipes, scenarios and models; editing and deleting are limited to the author (an admin may delete any comment).

c = project.add_comment("dataset", "fact_orders", "Store 12 looks low for March.")
project.add_comment("dataset", "fact_orders", "Source extract was late.",
parent_id=c["comment_id"])
project.list_comments("dataset", "fact_orders") # root comments, each with its replies
project.comment_count("dataset", "fact_orders")
project.edit_comment(c["comment_id"], "Store 12 looks low for March (checked).")
project.delete_comment(c["comment_id"]) # leaves a tombstone so replies stay

Verified against honeyframeapi 0.1.8.