Skip to content

Conversations ​

Besides running workflows, an agent can hold a conversation: a person chats with an assistant, and the assistant answers with the same model loop a workflow step uses. It calls tools as that person and can start workflow runs for them. The assistant is defined by an assistant profile. Each conversation is a thread (a chat in the console).

Assistant profiles ​

A workflow step holds the instruction, tools and limits its model runs with, and an agent holds none of these. An assistant profile holds them for a conversation:

FieldMeaning
Name, descriptionName must be unique in the tenant (up to 128 characters).
AgentThe agent the assistant acts as. It must be Delegated or Orchestrator. An Autonomous agent acts without a user, so it is refused.
Model overrideOptional provider and model. Without one, the agent's model is used.
InstructionThe system instruction (up to 20,000 characters).
ToolsUp to 50 tenant tools. Each one is Requires confirmation (the default) or Auto.
SkillsUp to 20 skills, as on a step: the latest or a pinned version, loaded Always or On demand.
Max rounds per turnModel↔tool rounds one turn may run, 1–50 (default 10).
Token budget per turn1,000–1,000,000 tokens, or none (default 32,000).
History windowHow many earlier turns are replayed to the model, 0–50 (default 20).
Requires purposeWhether a chat must state its purpose before it starts.

Profile tools default to Requires confirmation, while step tools default to Auto. This is deliberate: a chat replays earlier turns, so a tool runs without asking only if the author chose Auto for it. An Orchestrator agent's workflow tools come from the agent and are not listed on the profile.

Lifecycle. A new profile is a Draft at version 1. Activate it (this checks the agent type again) so that chats can use it. Deactivate it to stop new turns, or delete it (soft delete, which frees the name). Every save that changes the content adds a new version. Earlier versions never change and are listed on the profile's page. Manage profiles on the Assistant profiles page (/assistant-profiles).

Threads and turns ​

A thread is one person's conversation with an active profile. A turn is one user message and the assistant's reply.

  • Pinned version. A thread uses the profile version that was current when it started. Every turn requires the profile to still be Active and, if the profile requires a purpose, the thread to have one.
  • Runs as the user. A turn runs inside the request, under the caller's own token. Tools receive tokens delegated from that user, exactly as a step does for the user who started a run. Nothing is stored for later, and the delegated grants are revoked when the turn ends.
  • People only. A thread belongs to a signed-in person and runs as that person. A service or agent token, or a request with no token, is refused with 403 Thread.HumanSubjectRequired.
  • Private. Every endpoint sees only the caller's own threads. Another user's thread answers 404, even in the same tenant.
  • One turn at a time. A message sent while a turn is running answers 409 Thread.TurnInProgress.
  • Text-only history. The model gets the user message and final reply of the last history window completed turns. Earlier tool calls and tool output are not replayed.
  • Streaming. Send the message with Accept: text/event-stream to receive the turn as server-sent events: turn_started, text_delta, tool_call_started / tool_call_completed, workflow_run_started, and finally turn_completed, confirmation_required or error. The deltas are a preview; the reply in turn_completed is the final text. Tool arguments and results are never streamed. Proxies in front of the API must not buffer text/event-stream.
  • Lifecycle. Threads can be renamed, archived (read-only) or deleted. A thread's title defaults to the first 80 characters of its first message.

Because a turn runs inside the request, keep the profile's rounds and token budget low enough to finish within your gateway's request timeout.

Host context ​

An embedding host can send a few string key/value pairs with the thread and with each message, saying what the chat is about, for example { "fundId": "F-9" }. For each turn the message's pairs are applied over the thread's. The model reads them as its context, like a run's inputs, and read_context returns a value in full. The limits are 20 entries, keys of 1–64 characters from [A-Za-z0-9_.-], and values up to 2,000 characters (otherwise 400 Thread.HostContextInvalid). Host context is never used for authorization: treat it like a user message.

Workflows as tools ​

When the profile's agent is an Orchestrator, its workflow tools are offered in each turn, but only those whose workflow is active and that the user may run (run-workflow-instance). Calling one launches an ordinary run for the user, and the turn does not wait for it:

  • The usual launch rules apply: launch policy, purpose, default agent, and version.
  • The run's initial context is the tool inputs plus thread_id, purpose and task_id (the turn).
  • A repeated call with the same tool call id does not queue a second run.
  • The model gets the run id straight away. The run's page links back to the thread.

The built-in read_run tool, offered only in chats, lets the model check one of the user's own runs: its state, its failure reason and, once it is done, its output. It never waits for a run to finish.

Tool confirmations in a chat ​

A call to a Requires confirmation tool pauses the turn (state AwaitingConfirmation) with the proposed arguments. The thread's owner decides it in the chat, not on the Confirmations page:

  • Approve, optionally with edited arguments. The call runs and the same turn continues.
  • Reject, with an optional reason. The model is told why and carries on without the call.
  • Send a new message to decline the call. The paused turn ends Cancelled.

A pending call expires after ToolConfirmation:TimeoutHours (72 hours by default). Clarifying questions (request_clarification) are never offered in a chat.

Cancelling a turn ​

Cancel a running or paused turn with POST /api/threads/{id}/turns/{turnId}/cancel (or Cancel in the chat). Closing the connection also cancels a running turn. The turn ends Cancelled, and anything it already recorded stays.

Cost ​

Every model and tool call a turn makes is recorded with the thread and turn. A turn reports its tokens and estimated cost, and the thread reports the totals over all its turns. The cost of a run that a chat launched stays on that run and is never added to the thread. Chats count towards usage limits, and a spent budget refuses a message with 403UsageLimit.BudgetExhausted. See Usage & Data Governance.

Turning it on and permissions ​

Threads ship off. While Threads:Enabled is false, every api/threads endpoint answers 404. The setting is read on every request.

PermissionAllows
start-threadStarting a thread.
view-threads, view-threadListing your threads, and reading one with its turns and conversation.
send-thread-messageSending messages, deciding confirmations, cancelling turns, renaming.
archive-thread, delete-threadArchiving and deleting your threads.

The six thread keys belong to the agentfleet:thread-user role (and admin), not to viewer, because a turn calls tools as the user. The profile keys (view-assistant-profiles, view-assistant-profile, and create- / update- / activate- / deactivate- / delete-assistant-profile) are in viewer (the view keys), workflow-author and assistant-profile-admin.

In the console ​

  • Chats (/threads) lists your threads, with search and a status filter.
  • New chat (/threads/new) asks for an active profile and, when needed, a purpose.
  • A chat (/threads/{id}) streams replies, shows tool calls and launched runs, has inline Approve / Edit / Reject cards, and a Cancel button.
  • Conversation (/threads/{id}/conversation) is a read-only view of every model round, showing the exact input the provider received.

From .NET ​

Agentfleet.Client.Http registers IAgentfleetThreadClient alongside the workflow client. SendMessageAsync returns the turn's events as an IAsyncEnumerable of typed events (ThreadTextDeltaEvent, ThreadWorkflowRunStartedEvent, ThreadConfirmationRequiredEvent, ThreadTurnCompletedEvent, …). SendMessageAndWaitAsync returns the finished turn instead. There are also approve, reject, cancel, rename, archive and delete methods. The client never retries a message, because a retry would start a second turn. It needs a person's token, for example an RFC 8693 token exchanged for the signed-in user.

Embedding in a portal ​

The API serves a framework-agnostic web component at /widget/agentfleet-chat.js. It renders in its own shadow root:

html
<script type="module" src="https://agentfleet.example.com/widget/agentfleet-chat.js"></script>
<agentfleet-chat api-base-url="https://agentfleet.example.com/api"
  assistant-profile-id="6f1c…" host-context='{"fundId":"F-42"}'></agentfleet-chat>
<script type="module">
  document.querySelector("agentfleet-chat").getToken =
    ({ forceRefresh }) => portal.getAgentfleetToken({ forceRefresh });
</script>
  • Attributes: api-base-url, assistant-profile-id or thread-id (to resume a chat), purpose, host-context (sent with every message), run-url-template, heading, placeholder.
  • getToken (required) returns the user's exchanged Agentfleet token. On a 401 the widget calls it once more with forceRefresh: true. It never sends cookies.
  • Events: agentfleet-thread-started, agentfleet-turn-completed, agentfleet-run-started, agentfleet-confirmation-required, agentfleet-error.

The portal's origin must be listed in Cors:AllowedOrigins. For the full setup, see the embedding guide.

Agentfleet — agent workflow orchestration.