Curiosity

AI Agents

An agent in Curiosity Workspace is a saved configuration that pairs a system prompt with a list of tools and a chat model. You give it a goal in natural language, the model picks tools, the runtime executes them under the user's permissions, and you get a structured result back — or another agent's output, if you're chaining.

Agents are first-class objects: stored as graph nodes, manageable from Management → Agents, callable from any endpoint or AI tool, and exportable as code for promotion across environments.

Unknown component: alert If you've already shipped AI Tools, agents are the next layer up: a way to package a prompt + a curated tool set + a model into a single re-usable unit you can invoke programmatically. [!/alert]

How an agent runs

flowchart LR Caller[Endpoint / AI Tool / REST] --> AgentAI[AgentAI.RunAgentAsync] AgentAI --> Prompt[System prompt<br/>+ user message<br/>+ ${variables}] Prompt --> LLM[Chat model<br/>ChatTaskUID] LLM -->|tool call| ToolLoop[ChatAITool runtime] ToolLoop -->|result| LLM LLM -->|done| Run[(_AgentRun node:<br/>result + status)] Run --> Caller

The runtime is single-shot, non-streaming, and persists every invocation as an _AgentRun node — so you can audit, replay, or inspect what the model decided. Each run has a Running, Completed, Canceled, or Failed status and a default 5-minute timeout.

When to use an agent vs. an AI tool vs. an endpoint

Need Use
A deterministic, permission-aware piece of business logic over HTTP Custom endpoint
A function the chat assistant can call mid-conversation AI tool
A reusable LLM workflow with a fixed prompt + tools + model Agent (this section)
A complex task that needs another agent to do part of the work Sub-agent pattern — see Sub-agent workflows

A good rule of thumb: an agent is what you'd ship if a non-engineer asked for "a button that summarises this customer's open tickets and writes a draft reply." The behaviour is fixed; only the input changes.

In this section

Creating Agents

Define an agent: system prompt with ${variables}, attached tools, chat model, and optional structured output schema.

Calling from an Endpoint

Invoke AgentAI.RunAgentAsync from a custom endpoint, pass variables, await the result, and return a typed response to the caller.

Calling from an AI Tool

Wrap an agent as a [Tool] so the main chat assistant can delegate to it — the foundation for the sub-agent pattern.

Sub-agent Workflows

Chain specialised agents through an InvokeAgent tool to build research, summarisation, and aggregation pipelines.

Anatomy of an agent

Property Type Meaning
Name string Display name. Surfaced in the management UI and _AgentRun audit log.
Description string One-liner describing the agent's purpose. Used as the tool description when the agent is exposed as an InvokeAgent sub-agent.
SystemPrompt string The instruction prompt for the model. Supports ${VAR} placeholders bound at call time.
ChatTaskUID UID128 The scheduled task that supplies the chat model (provider + parameters). default falls back to the caller's default provider.
OutputSchema string (optional) Name of a C# type marked with [AgentOutputSchema] — the runtime forces the model to return JSON conforming to it.
Attached tools edges Any subset of the workspace's _ChatAITool nodes. Tools are filtered per-call by the caller's ACL.

Agents are persisted as _Agent graph nodes; the wire DTO is Mosaik.Shared.Agent. The runtime entry point on the server side is the static Mosaik.AI.AgentAI class.

Quick example

A "ticket triage" agent that searches the knowledge base, picks a category, and proposes a next action:

[agent: Curiosity.Agents.Name("Ticket Triage")]
[agent: Curiosity.Agents.Description("Categorise a support ticket and propose the next action.")]
[agent: Curiosity.Agents.Icon("ticket")]
[agent: Curiosity.Agents.ChatTask("01HQ…")]   // model/provider task UID
[agent: Curiosity.Agents.OutputSchema("TriageDecision")]
[agent: Curiosity.Agents.Tool("01HZ…")]      // SearchTickets
[agent: Curiosity.Agents.Tool("01J0…")]      // SearchKB

You triage incoming support tickets for ${PRODUCT}.

Given the ticket body, call SearchTickets to find similar past cases
and SearchKB to find resolution articles. Then return a TriageDecision.

Never invent resolutions — only suggest articles you have cited.

Invocation from an endpoint:

var runUID = await AgentAI.RunAgentAsync(
    graph:        Graph.Underlying,
    agentUID:     AI_Agents.Ticket_Triage,
    userMessage:  Body,                                  // ticket body
    userUID:      CurrentUser,
    variables:    new Dictionary<string, string> { ["PRODUCT"] = "MacBook Air" },
    cancellationToken: CancellationToken);

var run = Graph.GetReadOnlyContent<_AgentRun>(runUID);
return Ok(run.Result, "application/json");

The next pages walk through each piece in detail.

See also

© 2026 Curiosity. All rights reserved.