Skip to main content

AI assistants and agents

Applies to: SimpleTwo 0.9.x · Checked: 24.09.2026

AI in SimpleTwo is not a separate application beside the messaging. It is a bot with a second lane: the first leads into the conversation, the second to the model. The lanes are independent, and that is the main property of the design.

1. The model provider​

Settings → AI. Two dialects are supported:

KindWho fits
anthropicthe Anthropic API
openaianything speaking an OpenAI-compatible API: ITG AIaaS, vLLM, Ollama and the like

The tenant has one key, and it lives on the messaging host — the coordinator puts it there the way it does push keys, and never hands it back. The console card answers only two questions: is access configured, and where does it point.

A local model is the same openai

If data must not leave the perimeter, run vLLM or Ollama inside it and point the setting at them. Nothing changes on the SimpleTwo side — what changes is where the text goes.

The console pulls the model catalogue through the messaging service rather than asking you to type a name. The reason is practical: with some providers a model's capability is part of its name (opr.claude-sonnet5.chat_completions, itg.qwen3-embedding-4b.embeddings), and the "obvious" name like claude-sonnet-5 exists nowhere. A field offering a list cannot be filled with a value that does not exist.

1a. Personal quotas: one token per person​

The tenant key above answers "can a service bot think". An assistant asks a different question: it spends its owner's quota and never the tenant key. With no personal quota it is created without a brain — it reads and writes and does not reach the model at all.

Settings → AI → Personal quotas. Two fields:

FieldWhat to enter
Token API addressthe installation address itself, without /v1 — e.g. https://ai.example.com
Admin tokena token with the Admin role on that same installation

The management routes live outside /v1 while the consumer API is that address plus /v1; the console refuses an address that still carries the /v1 tail. A User-role token is not admitted to token management — the gateway itself refuses that.

The rest happens on its own: when somebody creates their assistant, the coordinator issues them a token (POST /token/create, role User, owner = their login, value prefix simpletwo), hands it to the messaging service, which stores it sealed and injects it into model calls. The gateway returns a token's value once, so it cannot be read back — here or in the gateway's own interface. A lost value means issuing a new token.

Quota and validity are set on the gateway side, in the token's record: we neither ask for them nor override them. Our per-agent daily budget (section 2) is a second belt on top.

An assistant thinks on its owner's devices, not on a server: the client core answers the person in their chat with the assistant and reads their invitations against their calendar while the app is open on one of their devices. The model call still goes through the assistant's lane — on the owner's personal token, within the model list and the daily budget, logged as the assistant. An assistant whose lane was never opened (the AI button under Bots) does not think, and its owner is told why in the chat.

When an account is deleted the coordinator revokes the token (REMOVED, irreversible) and the messaging service drops its copy. A gateway that is unreachable does not block the offboarding; the log records that the token was left live at the provider.

2. A bot's model lane​

Every bot is issued its own model credential (ai_…), and issuing it sets:

  • the allowed models — the bot cannot reach another;
  • a daily token budget — the ceiling on what this bot may spend.

Requests go through SimpleTwo to the provider with the tenant's key; the audit records the request's metadata, not its contents.

Why two credentials rather than one

The model credential does not authenticate against the messaging API, and the chat token does not open the model: a leaked chat token spends nothing at the provider, and a leaked ai_ key reads no messages. They rotate independently. Disabling the bot closes both lanes — one switch stops the agent entirely.

3. Assistants and delegation​

An assistant is an agent that acts in a specific person's name: it sees what its owner sees. Technically it is a delegated session, not a separate participant.

  • The organisation has a single switch: may agents act in people's names at all. It is checked on every request rather than only at creation, so turning it off takes effect immediately — live delegates are refused at once. Nothing is deleted by it.
  • With delegation off you still have ordinary bots working under their own names.
  • An owner sees their agents in the client and stops them there. That is deliberate: somebody who has to file a ticket to stop their own agent will not stop it. The same list appears on the sessions screen beside their devices — "who can act as me" is answered in one place.

4. The support bot​

A special case is a help desk with its own knowledge base. One button in the console stands the whole case up: the @librarian bot with the organisation badge, its model credential and the support channel. Everything it creates stays an ordinary object, visible and editable in the console. The bot answers from its knowledge base first; when the problem is new, it registers a report.

The same button switches the greeting on: the bot writes to every new person in a direct chat about how to report a bug or a wish. For the text, the switch and greeting the people who came earlier, see The first day: the welcome and the support bot.

There may be several such instances: different jobs, different knowledge bases, different bots, each with its own provider key. A support host is bound to one instance when it is enrolled and never receives another's credentials.

The support server itself sits in the DMZ, faces nothing outward and accepts only signed webhooks from the messaging service.

What the reporter hears​

Every report — «Report a problem», the complaint after a call, a bug or a wish the bot registered in a chat — is stored on the support server at once as a ticket, and the reporter is told its number: «Дефект зарегистрирован: обращение T-…». When it could not be stored, the bot says so and asks to send it again. The vendor's support collects the tickets — see Vendor support, section "Feedback tickets". Replies from the vendor to the reporter come as the next step.

The bot used to post a draft into the dev room, where the person on duty approved it with ✅; a GitLab issue was filed and the bot told the reporter how it went. That path is gone. GitLab is now only an optional source for the bot's knowledge base: the server's address, a project and a read token (read_api).

The bot and the support role​

They are different things. The bot @librarian is a chat participant: it reads nothing inside the platform. The support role is the platform service behind the bot, and its job is diagnosis. So the role has standing read access: the hosts' logs, metrics and traces from the monitoring host, client telemetry, the state of the roles and hosts.

The access is a read token like the vendor support one, of a second kind:

  • it is issued by itself when the support case is deployed, and rotated when it is redeployed;
  • it is delivered only to that case's support host;
  • it has no term while the role is deployed;
  • list it, revoke it and issue a new one in Settings → Support case → "Diagnostics access of the support role"; a revocation takes effect on the next request;
  • secrets are removed from what it reads; logins and error texts stay;
  • every use is in the audit trail as support:<case>.

What the role reads goes into the report's ticket; it leaves only with the ticket the vendor collects.

The reporter's client version​

Somebody who simply writes to the bot does not send their app version. The support server finds it itself — a telemetry query by the author's login for the day before the message (or before a moment the person described) — and adds a source: logs block to the report with the time the version refers to. Code writes the block, not the model. When no version is found, the bot asks the person. The in-app "Report a problem" form is unchanged: it shows its details to the person before sending.

Who takes the form's reports​

The "Report a problem" form offers the bots marked "takes reports". Standing a support case up marks its bot. To take the mark off (for example, from the bot of a retired case) or put it on by hand, use the Bots page: the row's menu → Stop taking reports / Take reports, or POST /admin/api/bots/{username}/accepts-reports with {"accepts_reports": false}. Bots only; the change is audited and reaches the clients with their next directory update.

5. What to decide before enabling​

  1. Where the text goes. An external provider means handing conversation content to a third party. For a closed perimeter, choose a model inside it.
  2. Budgets. Give every bot a daily ceiling immediately: a budget granted "without a limit for now" does not stay without a limit — it stays without attention.
  3. Who creates agents. Creating bots is a console permission; delegation is a separate organisation switch. Two different decisions, better taken separately.

Next​