/agents): a list,
a builder (/agents/new, /agents/:agentId/edit), the chat (/agents/:agentId/chat)
and a detail shell with the tabs overview, access, instructions, knowledge,
memory, tools, mcp-servers, skills, slack and versions. Company tools have
their own pages under Tools (/tools). This page covers the in-server chat agent;
long-lived sandboxed agents (sandbox_type set) are in Sandboxes, one-shot
task execution in Cloud tasks and executors.
What it does
Defines the agent.createAgent takes a name (slug derived or given, unique per
company), description, avatar, personaConfig, systemPrompt, defaultProvider,
defaultModel, defaultIntegrationId and optional default executor and environment for
tasks. The persona is rendered into the prompt from four keys: tone, verbosity
(terse, balanced, detailed), expertise (list) and approach (react,
plan-and-execute, reflection). A new agent starts active with version 1 published
to production, and every active built-in tool is bound to it automatically.
Runs on the company’s LLM key. Each turn resolves credentials from the integration
named by defaultIntegrationId, else the first active integration whose provider slug
equals defaultProvider (anthropic, openai, google, mistral, cohere,
deepseek, bedrock; see Generic and provider integrations).
Optional temperature (0.0 to 2.0) is passed through. The billing gate runs before each
model call. Every interaction is stamped llm_key_source = byo; no Olyros-provided key
path exists yet.
Keeps a version history. Every updateAgent save writes a new AgentVersion
(published_env = draft) with optional changeNotes. publishAgentVersion(targetEnv)
sets the latest version to draft, staging or production; publishing to
production moves a draft or paused agent to active, demoting to draft moves an
active agent back to draft. archiveAgent hides the agent; restoreAgent returns
it to active when a production version exists, else draft. Status values:
draft, active, paused, archived; only active and draft agents can chat.
Tools in three types (Tool.tool_type): built_in (platform-wide, company_id
null, seeded on startup), http_api (a company-defined outbound HTTP call) and
custom_code (a company script run in the skill sandbox). A tool is offered to the
model only through an active AgentTool binding, filtered by environment: the binding’s
environmentOverrides, else the tool’s allowedEnvironments, else everywhere (web_chat,
slack, api, github_action, container). Tool names starting with mcp__ are
reserved for MCP servers. Built-ins today:
An
http_api tool stores execution_config with a URL, method, headers and body
templates; {{argument}} placeholders are filled from the model’s arguments, the URL and
headers are validated against the safe-HTTP rules on save, responses are truncated to
4000 characters and the default timeout is 10 s. Auth can come from an integration
(resolve_integration_auth). A custom_code tool holds runtime (python3.12 or
node22), entrypoint and files; arguments arrive as /work/in/arguments.json and
stdout is the result. requiresApproval is stored on every tool; see Known gaps for
what it does today.
Knowledge documents. Items (title, contentType in markdown, json, yaml,
code, qa_pair, pdf; inline content up to 500 KB) are chunked (500 tokens, 100
overlap) and embedded with the company’s embedding integration (Settings -> Memory,
/settings/memory). Each item carries indexingStatus pending, indexing, indexed
or failed, chunkCount and indexingError; reindexKnowledgeItem retries. At chat
time, if any chunk is indexed, semantic plus keyword search (reciprocal rank fusion,
15 candidates) is reranked to 5 chunks and injected with [Source: title, section n]
citations; with nothing indexed, items are injected whole in sortOrder. The done
event lists the knowledge_sources used.
Memories. Types: learned_preference, episodic, user_specific, team,
procedural; each has importance (0.0 to 1.0), isPinned, expiresAt, accessCount
and provenance (sourceEnv, sourceUserId, sourceInteractionId). Three writers: the
olyros_store_memory tool, the Memory tab (createMemory, source manual), and
automatic post-turn extraction, a second LLM call that runs after the done event and
is on only when both the agent’s memoryExtractionEnabled and the company-wide switch
are on. A new memory whose embedding is at least memoryDedupThreshold (default 0.95)
similar to an existing one overwrites that memory instead of adding a row. Retrieval
(memoryRetrievalEnabled) injects every pinned memory plus the top 10 unexpired
memories scored 0.4 similarity + 0.3 recency (30-day decay) + 0.2 importance + 0.1
access frequency.
Access control. An agent’s Access tab lists who may chat with it: Olyros users, Slack
users and Slack groups (access.olyrosUserIds, slackUserIds, slackGroupIds). No
grants at all means everyone; any grant means only the listed people and groups, in web
chat and on Slack alike. A Slack user is also admitted when linked to a listed Olyros
user who is still an active member, and a member is admitted on the web when their linked
Slack identity is listed or in a listed group. System actors (workflow, schedule, webhook)
are never checked and there is no admin bypass. AgentType.myAbilities (["agent.chat"]
or []) tells the caller; a denied caller gets the same error event as an agent that
cannot chat. Slack user and group management is on the Slack page.
Agent access is the one-ability case (agent.chat, shown as Chat) of the access
model that workflows use for Run and View: the same subjects and the
same rule. Slack users in a grant are keyed by workspace and user id, so the same Slack id
in another workspace does not match. Editors and admins hold the class-scoped
agent.manage ability (me.abilities) that gates the Access tab; the roles table is on
Company settings.
Web chat. GET /api/agents/{agent_id}/chat/stream?session_id&message streams
Server-Sent Events: thinking, token, tool_start, tool_progress, tool_result,
hitl_request, error and done (interaction id, tokens, cost, memories and knowledge
used, tool calls, hitl_request_id, skills used). The session id is chosen by the
client; history is the last interaction of that session, trimmed to its budget. Each
turn is an AgentInteraction row written at start and finalised at the end with
messages, tool calls, tokens, cost, actor attribution and cost tags.
agentConversations / agentConversation list past sessions; submitFeedback stores a
thumbs up or down with a comment on an interaction. Slack turns run the same executor
with environment_type = slack.
Structured questions to the person (HITL). With olyros_ask_user bound, the agent
asks one single_choice (2 to 10 options, optional free text), confirm or free_text
question; the turn suspends, later tool calls in the same batch are skipped, and the
question is rendered as a card in the web chat (hitl_request event, re-mounted on
reload via hitlRequests) or as a Slack Block Kit message. The answer comes back on the
same SSE endpoint, either as a card click (hitl_request_id, hitl_value) or as typed
text parsed against the options; typed text that is not an answer cancels the question
(not_an_answer). Only the person asked may answer; one pending question per session
(a newer one supersedes). Statuses: pending, answered, expired, cancelled,
delivery_failed. Requester kinds written today: server_agent (this page),
sandbox_agent (see Sandboxes, answered with answerHitlRequest).
Default repositories for tasks. setAgentDefaultRepositories attaches GitHub
repositories (access level, branch, /workspace/<name> mount path, one working
directory) that tasks created for the agent inherit (Cloud tasks and executors).
Who can use it
- Create, edit, archive, restore, publish versions, manage knowledge and memories, bind or unbind tools, chat, read conversations, submit feedback, answer questions: any company member (membership only).
- Edit the access lists (
setAgentAccess): editor or admin (agent.manage); each change writes anagent.access_updatedaudit event. - Create a tool: editor or admin for
built_inandcustom_code, company admin forhttp_api;updateToolanddeleteToolare editor or admin, and admin again when the tool ishttp_api.testToolis editor or admin. - Agent creation runs a per-tenant
max_agentsentitlement check; today it only logs when over the cap and still creates the agent. No other plan or tier gate exists.
How to configure it
- Prerequisite: an active LLM integration for the provider (Integrations), and for
knowledge or memories an embedding integration under Settings -> Memory
(
updateCompanySettings), which also holds the company-wide extraction switch, extraction model andragRerankingEnabled. - Create the agent (Agents -> New):
createAgent(name, systemPrompt, personaConfig, defaultProvider, defaultModel, defaultIntegrationId, ...). The slug must be non-empty and unique; a default executor or environment must belong to the company. - Tune in the builder:
updateAgent(... temperature, maxToolIterations, skillCallTimeoutS, skillTurnBudgetS, memoryDedupThreshold, memoryExtractionEnabled, memoryRetrievalEnabled, changeNotes). Values above the platform ceilings are clamped, not rejected;agentRuntimeLimitsreturns the ceilings for the form. - Tools tab:
bindToolToAgent,unbindToolFromAgent,updateToolBindingEnvironments. Company tools are made under Tools (createTool,updateTool,deleteTool,testTool);testToolon anhttp_apitool is limited to 60 calls per company per hour. - Knowledge tab:
createKnowledgeItem,updateKnowledgeItem(a content change bumpsversionand re-indexes),reorderKnowledgeItems,deleteKnowledgeItem,reindexKnowledgeItem. - Memory tab:
createMemory,updateMemory,pinMemory,unpinMemory,expireMemory,deleteMemory,deleteMemories;setAgentMemorySettingsflips the two switches without creating a version. - Access tab:
setAgentAccess(userIds, slackUserIds, slackGroupIds);nullleaves a list unchanged, users must be company members, Slack ids must matchU…/W…, groups must exist. Ids not yet in the Slack cache are saved with a warning. - Versions tab:
publishAgentVersion(agentId, targetEnv); Overview toggles status throughupdateAgent(status). - Chat at
/agents/:agentId/chat; connect Slack from the Slack tab (Slack).
Limits and defaults
What it emits
AgentInteractionrows per turn (messages, tool calls, tokens,cost_usd, provider and model,agent_version_id, actor, tags,environment_type): the basis of usage and cost reporting and of the conversations list.AgentMemoryrows from tools, manual entry and extraction;AgentKnowledgeChunkrows from indexing;HitlRequestrows for every structured question with answer and answerer.- Audit events
agent.access_updated(before and after lists) andtool.skill_code_enabled.updated; HTTP tool calls are recorded by the tool bridge audit. - SSE events to the chat client, including
mcp_auth_requiredwhen an MCP server needs the user’s connection.
Known gaps
requiresApprovalhas no approval step: anhttp_apitool flagged this way runs immediately (the flag only classifies the call as a write for audit), and acustom_codetool flagged this way is refused at run time.- Versions are history, not what runs: the executor always uses the live agent row,
publishAgentVersionacts only on the latest version, there is no rollback to an earlier version, andstaginghas no runtime effect. - Memories are shared across everyone who talks to the agent, including
user_specificones; retrieval never filters by user. Dedup overwrites the matched memory regardless of its type or pinned state.maxMemoriesPerAgentis stored but never enforced, and extraction leaves no cost row. - A knowledge item with only a
storageUrlis never indexed; indexing works on inlinecontentonly, andpdfis treated as markdown text. AgentTool.configOverridesis stored but not read anywhere.olyros_web_searchsilently disappears from the tool list on non-Google providers.custom_codetools have no authoring UI;execution_configis validated at run time.- Object access has no access requests and no admin bypass; HITL offers no multi-field forms and only one pending question per session.
- A router agent fronting many agents behind one Slack app exists (
kind = router) and has its own page, Routers; routing by channel, group or content is not built.