Skip to Content
Polyant is open source under AGPL-3.0 — star us on GitHub.
ConceptsAgents

Agents

In Polyant, an agent is the same thing as an instance: a fully configured AI assistant that lives in PostgreSQL and is brought to life by the Supervisor, a single reasoning loop that orchestrates every turn. There are no per-instance code branches and no specialized sub-agent classes — every instance, regardless of domain, is driven by the same supervisor wired against per-instance prompts, tools, and skills.

This page covers what the supervisor actually does on each turn, how the eight-section system prompt is assembled, how tools are presented to the LLM, and the two distinct delegation pathsspawnTask (ad-hoc sub-agent inside the same instance) versus agent-to-agent calls through the in-process agent channel adapter.

Instance equals agent

An instance is the unit of multi-tenancy and the unit of personality. A single engine process can host many instances side-by-side:

  • Each has its own slug, name, provider (OpenAI, Anthropic, Bedrock), and model overrides.
  • Each has its own row set in instance_prompts, instance_tools, instance_skills, instance_secrets, and instance_channels.
  • Each has its own memory partition (memories.instance_id) and its own conversations.
  • Toggles like memoryEnabled, langsmithEnabled, and authEnabled are per-instance.

There is no shared global personality. The supervisor reads the active instance’s configuration on every turn (with a 30-second cache) and runs against that — so changes made in the admin panel take effect on the very next message.

The supervisor loop

The supervisor is a single agent, not a tree of specialised sub-agents. It runs in the standard tier with maxSteps = 15, meaning the LLM may chain up to fifteen reasoning/tool-call cycles before having to deliver a final response. The supervisor is invoked from the pipeline for every inbound user message, regardless of channel.

Each invocation receives:

  • The instance’s system prompt (eight sections, see below).
  • The last fifteen messages of conversation history.
  • The current conversation summary (a rolling 2–3 sentence digest).
  • The set of tools enabled for this instance (filtered via instance_tools).
  • Optional sub-agent delegation via the built-in spawnTask tool.

The tier hides the underlying model: components ask for fast, standard, or heavy — never gpt-4o or claude-sonnet-4-5. The supervisor always asks for standard; the instance’s chosen provider (and optionally a pinned model) decides what that resolves to. See AI Gateway for the tier-to-model tables and the per-instance override rules.

The eight prompt sections

An instance’s identity is composed of eight modular sections stored in instance_prompts (01-identity08-datetime). They are concatenated in order to build the system prompt, and they are the only runtime-editable surface for an agent’s behavior. The section keys are stable contract — they appear in the admin UI, the management API, and seed data — and new instances are seeded from packages/engine/src/instances/defaults.ts.

For the full table of section keys and roles, plus the optional contextual blocks appended at runtime (channel identity, conversation context, summary), see Prompt.

Delegation: two distinct mechanisms

Polyant ships two unrelated delegation paths — don’t conflate them:

  1. spawnTask — ad-hoc sub-agent in the same instance. The supervisor’s built-in spawnTask tool creates an isolated sub-agent that runs against the same instance’s prompts/tools (minus spawnTask itself, to prevent recursion). Useful for chunking a complex task in the current instance’s context.
  2. Agent-to-agent via the agent channel. A separate, in-process channel adapter (packages/engine/src/channels/adapters/agent.adapter.ts) that lets instance A invoke instance B synchronously, with no HTTP/Slack/Telegram round-trip. The callee runs its own full pipeline (history, summary, supervisor, tools) and the reply is returned as a tool result on A’s side. This is wired through dedicated supervisor tooling, not through spawnTask.

Agent-to-agent calls carry metadata (callerSlug, callerConversationId, depth, parentTraceId) so analytics and LangSmith traces stitch the child invocation back to its parent. Each call is gated by AGENT_CALL_TIMEOUT_MS (default 60000 ms, see packages/engine/src/config.ts) — a callee that does not return in time is aborted and the caller receives a timeout error.

See Channels for the channel-side perspective and Tools for how delegation tools are wired.

How it works

+----------------------------+ user message ->| Channel Adapter | +--------------+-------------+ | v +----------------------------+ | Pipeline (handleMessage) | | history + summary + ctx | +--------------+-------------+ | v +----------------------------+ | Supervisor (tier=standard, | maxSteps=15) | | | | system = sections | | 01-identity | | 02-soul | | 03-tooling | | 04-safety | | 05-skills + {{list}} | | 06-memory | | 07-user-identity | | 08-datetime | | | | +----------------------+ | | | tool loop (<=15) | | | | plan -> call -> ack| | | | ... -> final text | | | +----------------------+ | +--------------+-------------+ | v +----------------------------+ | Outbound + fire-and-forget| | (save msg, summary, mem) | +----------------------------+

Code reference

  • packages/engine/src/agents/supervisor/index.tssupervise() / superviseStream(); tier standard, maxSteps: 15.
  • packages/engine/src/agents/supervisor/prompt.ts — System prompt builder that assembles the eight sections and renders the {{skillsList}} placeholder.
  • packages/engine/src/instances/defaults.ts — Default content for every section, seeded on instance creation.
  • packages/engine/src/instances/prompts.store.ts — Read/write API for instance_prompts rows (60-second TTL cache).
  • packages/engine/src/ai-gateway/config.ts — Tier-to-model mapping for OpenAI, Anthropic, and Bedrock.
  • packages/engine/src/ai-gateway/index.tschat() / chatStream() entry points used by the supervisor.
  • packages/engine/src/instances/config-resolver.ts — Resolves the active provider/model/secrets/channels for an instance at runtime.
  • packages/engine/src/channels/adapters/agent.adapter.ts — In-process channel that powers agent-to-agent invocation.

See also

Last updated on