App agent
Chat with the AI agent of BPMS.ai, read your conversations, and see how an installation sets up the AI provider it uses.
The app agent is the AI assistant inside BPMS.ai. You write to it in a conversation, and it answers and works in BPMS for you through the same tools the MCP server offers. It acts only as you: in your tenant, with your authorities, checked by each operation exactly as over this API. A tool your roles do not allow is refused, the refusal is recorded in the audit log, and the agent tells you it could not do it.
| Operation | Call | Authority |
|---|---|---|
| Send a message and stream the answer | POST /api/v1/agent/conversations/{conversationId}/messages | Any signed-in user; each tool the agent calls requires its own authority |
| Read a conversation | GET /api/v1/agent/conversations/{conversationId}/messages | Any signed-in user |
Both are called with the session token of your sign-in, described in Authentication; an MCP access token is not accepted. Both answers carry Cache-Control: no-store.
Send a message
A conversation is identified by a UUID that the client chooses, for example 3f6c1a52-8e0b-4c7e-9a43-2d5b7f1e6a90. Use a new one to start a conversation, and the same one to continue it.
curl -sS -N -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
"$BPMS_URL/api/v1/agent/conversations/3f6c1a52-8e0b-4c7e-9a43-2d5b7f1e6a90/messages" \
-d '{"text": "Which roles does my tenant have?"}'text is required, not blank, and at most 10000 characters. -N shows the answer as it arrives. It answers 200 as text/event-stream (server-sent events):
event:message
data:{"text":"Your tenant has one role."}
event:done
data:{}| Event | Data |
|---|---|
message | {"text": "<chunk>"}, one per piece of the answer, in order. |
done | {}, the last event of a turn that completed. |
error | A problem with status, code, and detail, the last event of a turn that failed while streaming. |
What is refused before the stream starts answers a normal application/problem+json error with its status, listed under Errors below.
Read a conversation
curl -sS -H "Authorization: Bearer $TOKEN" \
"$BPMS_URL/api/v1/agent/conversations/3f6c1a52-8e0b-4c7e-9a43-2d5b7f1e6a90/messages"It answers 200 with your messages and the agent's answers, in order:
{"items": [{"role": "user", "text": "Which roles does my tenant have?"},
{"role": "assistant", "text": "Your tenant has one role."}]}The history belongs to its user in its tenant. A conversation of another user, or one that does not exist, answers an empty list, so its existence is never revealed. Only the text of the messages and answers is kept: never the agent's tool calls or their results, so the next turn asks the tools again with the authorities you hold at that moment. The history is append-only: messages are not edited or deleted.
Rules of a turn
- Before each tool call, the agent checks that your session is still valid. If you sign out, are disabled, or lose access to the tenant during a turn, no further tool runs.
- A turn runs at most
BPMS_AGENT_MAX_TOOL_CALLStool calls; past that, it ends with a message saying so. - A turn streams for at most
BPMS_AGENT_STREAM_TIMEOUT. - Your message and the answer join the history when the turn completes. A turn that fails or times out keeps nothing.
The installation's AI provider
The operator configures the installation's own model with environment variables:
| Variable | Default | Meaning |
|---|---|---|
BPMS_AGENT_PROVIDER | None | The provider: anthropic, openai (also any OpenAI-compatible API, with a base URL), gemini, or ollama. Without it, the installation has no model. |
BPMS_AGENT_MODEL | None | The provider's model name. |
BPMS_AGENT_API_KEY | None | The provider key. Set it only in the environment. |
BPMS_AGENT_BASE_URL | None | Optional: the provider's URL, for example an OpenAI-compatible API or an Ollama server. |
BPMS_AGENT_MAX_TOOL_CALLS | 10 | The tool calls of one turn. |
BPMS_AGENT_STREAM_TIMEOUT | 5m | How long one answer may stream. |
BPMS_AGENT_ENCRYPTION_KEY | None | The master key that seals the tenants' provider keys: base64 of exactly 32 random bytes, for example from openssl rand -base64 32. Set it only in the environment and keep it safe: a key sealed with a lost master key cannot be opened. |
Neither key is ever logged or returned by the API.
The provider catalog
The operator also lists, in the installation's configuration file, the providers that tenants may choose from, under bpms.agent.providers.<id>. The catalog has no environment-variable form. Each entry has a type (anthropic, openai, gemini, or ollama), a base-url, enabled (true by default), and allow-private (false by default).
anthropic,openai, andgeminiare built in, with their official URLs.enabled: falsewithdraws one.- An Ollama server or another OpenAI-compatible API is offered only when the operator adds it, for example an entry
localwithtype: ollama,base-url: http://ollama:11434, andallow-private: true. - An entry's URL must use
httpsand may not point to a loopback, private, or link-local address.allow-private: truelifts both rules, for a server on the operator's own network. The check runs again before every turn. A refused entry is not offered.
A tenant's own provider
A tenant can use its own choice instead of the installation's model: one entry of the catalog, a model, and a key of its own, never a URL. The tenant's key is sealed with BPMS_AGENT_ENCRYPTION_KEY and bound to that tenant, so it never opens for another one, and it is never returned. The API does not yet offer the operation through which a tenant sets its choice.
The agent fails closed: a tenant's prompts and data go to the provider it chose, or nowhere. A tenant with its own choice never falls back to the installation's model or key, and the agent answers 503 agent.not-configured, sending nothing to any provider, when:
- the tenant's entry is unknown, disabled, or refused by the address check;
- the tenant has no key and its provider is not Ollama, the only one that needs none;
- the tenant's key cannot be opened, for example because the master key is missing or changed;
- the tenant has no choice of its own and the installation has no model.
Errors
| Status | code | When |
|---|---|---|
400 | core.validation-failed | text is blank or longer than 10000 characters, or conversationId is not a UUID. |
401 | core.authentication-required | The call has no valid sign-in session token; an MCP access token is not accepted. |
403 | core.password-change-required | The session may only change its password. |
503 | agent.not-configured | No model can be used for your tenant. |
A tool refused during a turn does not fail the call: the agent receives the refusal, such as core.authority-required, and the answer goes on.
In the OpenAPI document, the operations are sendAgentMessage and listAgentMessages, under the agent tag.