create-agent
Create an agent in the project's agent registry and get back its agent_id, which get-agent, update-agent, delete-agent and run-agent accept unchanged. For a multi-agent process flow use create-process-flow. Needs the fabric:orchestrate.write grant.
curl -sS -X POST https://fabric.wexa.ai/mcp/$FABRIC_PROJECT_ID \
-H "authorization: Bearer $FABRIC_API_KEY" \
-H "Mcp-Session-Id: $MCP_SESSION_ID" \
-H "content-type: application/json" -H "accept: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"create-agent","arguments":{"name":"Support assistant","role":"Conversational","has_knowledge_base":true,"context":["support_faq"]}}}'{
"content": [
{
"type": "text",
"text": "{\"lifecycle_id\":\"qlc_000207\",\"result\":{\"agent_id\":\"6ab196817566f41b5c28e335.6ab19681c73ec18cad7c9c48\"}}"
}
],
"isError": false
}Parameters
| Parameter | Type | Required | Notes |
|---|---|---|---|
context | array | Optional | Knowledge-base context tags. |
description | string | Optional | What the agent is for. |
has_knowledge_base | boolean | Optional | Set true with at least one tag in context so a Conversational or Voice agent can run without a skill. |
model | string | Optional | Model id from list-models settable, or "auto", which picks a model per call (see More details). Omitted, the agent is stored with the organization's default model from the AI Models registry, or the first registry model when none is marked default. system_model is refused, and so is an id not in the organization's AI Models registry. |
name | string | Required | Agent name. Non-empty. |
prompt | string | Optional | System prompt template. |
role | string | Optional | The agent type: Conversational (default), Task, Voice, Proxy or Interop. |
skill_ids | array | Optional | Skill ids from list-skills. Skills in this project. |
type | string | Optional | Node kind. create-agent makes a skilled_agent (the default); the other kinds are declared in a create-process-flow manifest; a node kind other than skilled_agent is refused. |
Errors
ValidationError(400): the organization agent limit is full. The message isCustomer has exceeded number of coworkers. See the organization agent limit.ValidationError(422): nomodelwas named and the AI Models registry is empty. Calllist-modelsand pass an id fromsettable.
Show full response
A real response, captured from a live call to create-agent:
{
"content": [
{
"type": "text",
"text": "{\"lifecycle_id\":\"qlc_000207\",\"result\":{\"agent_id\":\"6ab196817566f41b5c28e335.6ab19681c73ec18cad7c9c48\"}}"
}
],
"isError": false
}More details
"auto" has Wexa pick, on every call, the cheapest permitted model that is good enough for the step; routing rules still apply.
What an agent is made of
An agent is one LLM worker definition: a single set of instructions, tools and model configuration. It is not a container for other agents and not a small process flow. Three parts change at different rates, which is why an agent stays reviewable.
| Part | It says | Where it lives |
|---|---|---|
| Instructions | What the agent is for and how it behaves | A prompt template |
| Tools | What it may do: the Wexa tools it can call and the skills it holds | A skills list of real skill ids |
| Model | Which LLM it runs on, one the platform provides or one you bring | An llm block whose model names it |
Two more settings belong to the definition, not to a single run. An agent that does work can pause and wait for a person before it proceeds. Any agent can receive a summary of the agents that ran before it, and be told which ones. Both are off unless you turn them on.
In the console, open Orchestrate, then Agents, and choose New agent. The wizard offers the types listed under agent types. The old system_model value is refused for a new agent. See list-models for how a model is chosen.
Choose an agent or a process flow
Choose by the shape of the work, not its size. Use one agent when the work is one worker's job: one set of instructions, one role, one model, however many steps it takes inside. Use a process flow when the work needs more than one worker, that is, two parts want different instructions or skills, or a decision routes between them. A long single-role task is still one agent. Two short tasks that need different instructions are already a process flow.
To give the agent something to reach and a way to start without a person, see Skills, actions and triggers.
Agent fields
An agent has the same fields whether you create it alone or as a node in a create-process-flow manifest. type is the node kind and role is the badge the console shows, on both.
| What it is | create-agent argument | Manifest agent field |
|---|---|---|
| Name | name | title |
| Node kind | type (only skilled_agent) | type: skilled_agent, decider_agent or interop_agent |
| Role badge | role | role |
| What the agent is for | description | role_description |
| Task prompt | prompt (string) | prompt.template |
| Skills | skill_ids | skills |
| Knowledge base | has_knowledge_base, context | has_knowledge_base, context |
| Model | model | llm.model |
A manifest node also takes wiring and access fields that only make sense inside a process flow, such as ref, next and context_access.
Running without a skill
An agent with no skill runs only when it can answer without one.
| Type | Runs with no skill when |
|---|---|
| Conversational | it has has_knowledge_base: true and at least one tag in context |
| Voice | the same as Conversational |
| Task | never: give it a skill |
| Proxy | never: give it a skill |
Interop (made with create-agent) | never: give it a skill |
The rule reads the stored role. If you send a role that is not Conversational or Voice, the agent needs a skill whatever its type is.
Two more things let an agent with no skill run. Long-term memory does it for a Conversational or Voice agent, and only the console can turn long-term memory on. Files given to the run with files do it for any type, but read the known limitation on files first.
An agent that cannot run is not refused when you create it. Its run fails, and the execution says the agent has no action or tool attached. A plain create-agent call with only a name makes a Conversational agent with no knowledge base, so give it a skill or knowledge base tags before you run it.
Agent types
role takes one of the five agent types the console offers. A type is a role label: every type is stored as the same kind of agent, and the console shows the role as a badge. decider_agent and interop_agent are node kinds declared in a create-process-flow manifest. It defaults to "Conversational".
Older calls sent the role in type. That still works, but the result carries a warning, because type is the node kind (skilled_agent) everywhere else. If you send both, role is stored and type is ignored, with the same warning.
The label does not give an agent a different runtime. A Task agent and a Conversational agent run on the same engine. The label changes two things only: whether the agent can run without a skill (see running without a skill, above), and which console features apply to it, such as voice calls for a Voice agent and the OpenAI-compatible endpoint for a Proxy agent.
Conversational
A chat agent. It answers messages, and keeps a conversation over several turns when you reuse one session_id on run-agent. It is the default type. It can run without a skill when it has knowledge base tags: set has_knowledge_base to true and give at least one tag in context.
curl -sS -X POST https://fabric.wexa.ai/mcp/$FABRIC_PROJECT_ID \
-H "authorization: Bearer $FABRIC_API_KEY" \
-H "Mcp-Session-Id: $MCP_SESSION_ID" \
-H "content-type: application/json" -H "accept: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"create-agent","arguments":{"name":"Support assistant","role":"Conversational","has_knowledge_base":true,"context":["support_faq"]}}}'Task
An agent that does a defined job from start to end, with no person in the conversation. A schedule or a trigger usually starts it. A Task agent always needs a skill. Find a real skill id with list-skills and pass it in skill_ids.
curl -sS -X POST https://fabric.wexa.ai/mcp/$FABRIC_PROJECT_ID \
-H "authorization: Bearer $FABRIC_API_KEY" \
-H "Mcp-Session-Id: $MCP_SESSION_ID" \
-H "content-type: application/json" -H "accept: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"create-agent","arguments":{"name":"Nightly invoice check","role":"Task","skill_ids":["<skill id from list-skills>"]}}}'Voice
An agent that takes phone and browser calls. Speech is turned into text, the agent answers in the same way as a Conversational agent, and the answer is spoken back.
Voice calls are console-only. A call needs a Bland connection and voice settings, and only the console can set them. From the SDKs and the REST API you can create an agent with role: "Voice" and run it on text with run-agent. It follows the Conversational rule for running without a skill.
curl -sS -X POST https://fabric.wexa.ai/mcp/$FABRIC_PROJECT_ID \
-H "authorization: Bearer $FABRIC_API_KEY" \
-H "Mcp-Session-Id: $MCP_SESSION_ID" \
-H "content-type: application/json" -H "accept: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"create-agent","arguments":{"name":"Front desk","role":"Voice","has_knowledge_base":true,"context":["clinic_hours"]}}}'Proxy
Your agent behind an OpenAI-compatible endpoint, so that a framework that speaks the OpenAI API can call it. The endpoint is POST /v1/agents/{agentflowId}/chat/completions. A Proxy agent always needs a skill.
The endpoint answers only after a version is promoted. Until then it returns 409 with the code not_ready. A new agent has no versions, and the first version is promoted in the console (Agent Simulation). After that, rollback-agent-version can make any promoted version live. run-agent needs no promoted version, so you can test the agent before you promote it.
curl -sS -X POST https://fabric.wexa.ai/mcp/$FABRIC_PROJECT_ID \
-H "authorization: Bearer $FABRIC_API_KEY" \
-H "Mcp-Session-Id: $MCP_SESSION_ID" \
-H "content-type: application/json" -H "accept: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"create-agent","arguments":{"name":"Revenue answers","role":"Proxy","skill_ids":["<skill id from list-skills>"]}}}'Interop
A connection to an agent that runs on another platform, over MCP or A2A. In the console, Interop has two directions. Outbound brings an external agent in: you register a connection to it, and then a process flow can hand a step to it through an external agent node. Inbound publishes one of your own agents so that external callers can reach it. Inbound publishing is console-only. No tool does it.
From the SDKs, Interop means register-peer-agent, not create-agent with role: "Interop". That create-agent call makes an ordinary Wexa agent with an Interop label: it runs on Wexa's own model and skills, and it always needs a skill.
Check the endpoint with handshake-peer-agent first. An MCP external agent must expose exactly one tool, and the console's other outbound option, attaching an external agent's tools as skills, is console-only.
curl -sS -X POST https://fabric.wexa.ai/mcp/$FABRIC_PROJECT_ID \
-H "authorization: Bearer $FABRIC_API_KEY" \
-H "Mcp-Session-Id: $MCP_SESSION_ID" \
-H "content-type: application/json" -H "accept: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"register-peer-agent","arguments":{"name":"invoice-reconciler","endpoint":"https://agents.example.com/a2a/invoice-reconciler","protocol":"a2a","secret":"<the external agent'"'"'s token>"}}}'The result carries a connection_id. Put it on an external agent node as registration_id; see an external agent node, end to end.
Every tool call works the same way: How every tool call works.