Прескокни до содржината

Agents & assistants

Оваа содржина сè уште не е достапна на вашиот јазик.

An agent is configuration, not code. The platform runs a single general-purpose agent runtime; an agent is a record telling that runtime which model to use, what it is allowed to do, and what it already knows. Creating or changing one deploys nothing and restarts nothing — the next run picks it up.

That is worth pausing on, because it decides how you work with the API. There is no build step between editing an agent and calling it, no image to push, and no per-agent process to keep alive. It also means the interesting questions about an agent are all questions about its configuration, which is what the rest of this page is about.

“Agent” and “assistant” are the same thing under two names. The management surface calls it an agent; the runtime API calls it an assistant, and every run you start names one by its assistant_id.

A definition is YAML frontmatter plus a Markdown body. The body is the system prompt — the standing instructions the model gets on every run. The frontmatter is the configuration:

  • description — required. What the agent is for.
  • model — a registry alias (anthropic-haiku) or a provider-prefixed id (anthropic:claude-haiku-4-5). Omit it to take the platform default.
  • tools — the shared tools this agent may call, by name. An unknown name is rejected when you save, not silently ignored at run time.
  • require_approval — tools from tools that ask first. A call to one pauses the run until the person in the chat allows or denies it; a denial reaches the agent as the tool’s result, with the reason if one was given.
  • skills — procedural knowledge the agent can pull in on demand. See Skills.
  • collections — the knowledge collections it may search. See Collections & knowledge.
  • collection_filters — optional. Limits a collection to part of it, such as a folder. See Limit an agent to part of a collection.
  • visibility — tenant (the default) or platform.
  • memory — enabled (the default) or disabled. See Memory.
  • reasoning_effort — low, medium or high, on models that support it; leave it unset otherwise.
  • max_steps — how many model calls one run may make before it stops.
  • guardrails — per-agent overrides of your tenant’s content policy.
  • follow_ups — suggest a few next questions with each answer: enabled, count (1–5), explore (how many point to other topics) and an optional model. See Suggested next questions.
---
description: Answers support questions, citing sources when it searches.
model: anthropic-haiku
tools: [search]
skills: [web-research]
collections: [handbook]
visibility: tenant
---

Everything is optional except description. An agent with nothing but a description and a system prompt is a valid agent — it just has no tools and no knowledge, so it can only answer from the model’s own training.

Configuration is a ceiling, not a suggestion

Section titled “Configuration is a ceiling, not a suggestion”

Two of those fields are enforced rather than merely honoured, and the distinction matters if you are calling the API directly.

collections bounds retrieval. An agent’s search tool can only ever touch the collections named there. A run request that tries to add a collection does not get one: the platform overwrites collections, trust_tier, guardrails, max_steps and require_approval on every run with the agent’s own stored values, server-side, before the run starts. Naming a collection in a search narrows within the configured set; it never widens it.

tools is a request, and the agent’s trust tier is the ceiling above it. The effective tool set is the intersection of the two, so an agent asking for a tool its tier does not permit simply does not get it. It is told so explicitly, and told not to substitute something else — which is why you will see such an agent say plainly that it cannot search rather than quietly reaching for a lesser tool and answering as if it had. See Trust tiers.

An agent can search only part of a collection, for example one folder. Add collection_filters beside collections: a map from a collection name to a filter, using the same filter shape as a search.

---
description: Answers HR questions.
collections: [handbook]
collection_filters:
handbook:
folders:
any: ["Policies/HR"]
---

Through the API, send the same map as collection_filters when you create or update the agent. A filter can use any field the collection declares, and the folders field. Quote dates (gte: "2025-01-01"): an unquoted YAML date is not accepted.

In the console, open the agent’s definition and look under Knowledge collections. Each collection has a Limit to folder picker listing its folders with their counts; No limit removes the limit. A filter of any other shape, such as one set in the YAML, shows as “Custom filter — set in the agent file or API”. The console leaves it as it is when you save.

  • The limit is applied on every run, inside retrieval. A run request cannot change it, and neither can the model: its own filters, the filters the platform infers from a question and the retry after a weak result can only narrow the search further.
  • Each filter is checked when you save, against the collection’s current fields. If a filter stops matching the collection’s fields later (a field changes type, say), the search fails with an error naming collection_filters rather than running unfiltered. A field that was removed is still matched literally, so the limit holds.
  • Leave collection_filters out of an update and the stored filters stay. Send {} to remove them all. A map you send replaces the stored one.
  • A filter for a collection the agent no longer lists is kept but never used; it applies again if you add the collection back. You may send such an entry back unchanged. Exporting the agent leaves it out.
  • The limit also holds for text returned around a match: neighbouring chunks (expand) and the sections built from them include only chunks that satisfy the filter. A filter on a chunk-level field such as language can therefore leave gaps in a window or section.

Give an agent the ask_user tool and it can ask a question the person answers with a tap: confirm (yes or no), choice (one of 2–10 options), multi (several options, then Submit) or scale (a row of numbers, with optional labels at each end). A title, a progress count (such as “Exercise 1/5”) and a preface (a short note shown above the question, such as feedback on the previous answer) are optional.

The question ends the agent’s turn. The person’s answer arrives as their next message, and they can type something else instead. Questions appear in the chat and the website widget as a card, in English or Macedonian depending on the question’s language. Elsewhere — an API client, an older widget — the question shows as text with its options numbered.

ask_user never asks in a scheduled or webhook run, since nobody is there to answer, and an agent working for another agent in a workflow is not given it. It cannot require approval. A question carries no answer key: grading, if you need it, is up to your own tools.

An agent can suggest a few questions the person might ask next, attached to its latest answer. Turn it on in the agent editor’s Follow-up questions section, or in the definition:

follow_ups:
enabled: true
count: 3 # at most this many, 1–5
explore: 1 # how many open a different topic, 0 up to count
model: fast-chat # optional: a chat model you may use; default is the platform's

The answer itself is unchanged. The suggestions come from one extra model call after the answer, so they add a few seconds before the run ends; if that call fails or takes too long, the answer is delivered without suggestions. With explore above 0, some suggestions point to other topics in the knowledge the agent can read, never to anything the person could not open. Setting enabled: false keeps your count and explore for later.

In the console’s chat and the website widget they appear under the latest answer; click or tap one to send it. They are hidden while an answer is being written or an approval or question is waiting.

API clients find the suggestions in the reply’s response_metadata.kovac_follow_ups, a list of strings that is absent when there are none.

Every write produces a new version, identified by a hash of the definition’s content. Two consequences follow.

A run pins the versions that were active when it started, so editing an agent never changes a run already in flight. And because the identity of a version is its content, re-saving an agent with no actual change does not manufacture a new version — the version history tracks real edits.

GET /api/manage/agents returns each agent’s version and content_hash, which is what to record if you need to say later which configuration produced a given answer.

Two endpoints list them, for two different purposes.

Terminal window
# The tenant catalog: name, description, trust tier, version, content hash.
curl -s "$KOVAC_BASE/api/manage/agents" \
-H "Authorization: Bearer $KOVAC_API_KEY"
# The runtime's own view, in Agent Protocol shape.
curl -s "$KOVAC_BASE/api/agent/assistants" \
-H "Authorization: Bearer $KOVAC_API_KEY"

Use the first to find an agent and read its metadata; use the second if your client already speaks the Agent Protocol and expects that shape. Both give you the assistant_id a run needs. The catalog also reports a bundle field — the name of the plugin an agent was imported from, or null for one authored in the platform.

Author one on the Agents screen, or ship a set of them in a plugin. Both paths run the same validation and produce the same kind of record; there is no second-class agent, and an imported one can be edited afterwards like any other.

Next: Threads & runs.