> Source: https://wexa.ai/docs/agents/update-agent

# update-agent

[Can be held for approval](/docs/sdks-and-apis/how-every-tool-call-works#lifecycle-and-governance)

Change an agent. A partial update: only the fields present in `agent` change, every omitted field is left as it was. Needs the `fabric:orchestrate.write` grant.

**Change an agent's prompt**

**Wexa MCP server**

```bash
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":"update-agent","arguments":{"agent_id":"6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc","agent":{"prompt":{"template":"Reply with READY.","display_template":"Reply with READY."},"role_description":"probe role"}}}}'
```

```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"lifecycle_id\":\"qlc_000178\",\"result\":{\"agent_id\":\"6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc\",\"updated\":[\"prompt\",\"role_description\"]}}"
    }
  ],
  "isError": false
}
```

**REST API**

```bash
curl -sS https://fabric.wexa.ai/v1/update-agent \
  -H "authorization: Bearer $FABRIC_API_KEY" \
  -H "content-type: application/json" \
  -d '{"agent_id":"6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc","agent":{"prompt":{"template":"Reply with READY.","display_template":"Reply with READY."},"role_description":"probe role"}}'
```

```json
{
  "lifecycle_id": "qlc_000178",
  "result": {
    "agent_id": "6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc",
    "updated": [
      "prompt",
      "role_description"
    ]
  }
}
```

**TypeScript SDK**

```ts
import { Fabric } from '@wexa-fabric/sdk'

const fabric = new Fabric()
const result = await fabric.updateAgent({
  agent_id: '6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc',
  agent: {
    prompt: {
      template: 'Reply with READY.',
      display_template: 'Reply with READY.'
    },
    role_description: 'probe role'
  }
})
```

```ts
// result is the payload itself, with no `.result` to read
{
  agent_id: '6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc',
  updated: ['prompt', 'role_description']
}
```

**Python SDK**

```python
from wexa import Fabric

fabric = Fabric()
out = fabric.update_agent(
    agent_id="6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc",
    agent={
        "prompt": {
            "template": "Reply with READY.",
            "display_template": "Reply with READY."
        },
        "role_description": "probe role"
    },
)
```

```python
# out is the result, already unwrapped
{
    "agent_id": "6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc",
    "updated": ["prompt", "role_description"]
}
```

## Parameters

| Parameter | Type | Required | Notes |
| --- | --- | --- | --- |
| `agent` | object | Required | The fields to change. Must hold at least one editable key; an empty object is refused with `'agent' must include at least one field to update`. Any key outside the editable set, including `description`, `name` or `type`, is refused before the call runs, and the refusal lists the set. The keys are listed under [Editable keys of `agent`](#editable-keys-of-agent). |
| `agent_id` | string | Required | Agent id from `list-agents` or `create-agent`, in full, including the part before the dot. An agent in this project. |

**Errors**

- `UpstreamError` (5xx): a `prompt` passed as a string surfaces here rather than as a `ValidationError`, because the gateway does not check the shape of that argument.

**Show full response**

A real response, captured from a live call to `update-agent`:

**Result of update-agent**

**REST API**

```json
{
  "lifecycle_id": "qlc_000178",
  "result": {
    "agent_id": "6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc",
    "updated": [
      "prompt",
      "role_description"
    ]
  }
}
```

**Wexa MCP server**

```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"lifecycle_id\":\"qlc_000178\",\"result\":{\"agent_id\":\"6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc\",\"updated\":[\"prompt\",\"role_description\"]}}"
    }
  ],
  "isError": false
}
```

**TypeScript SDK**

```ts
// the object you get back IS the result — there is no `.result` to read
{
  agent_id: '6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc',
  updated: [ 'prompt', 'role_description' ]
}

// The TS SDK names these camelCase — lifecycleId, traceId — where Python uses
// lifecycle_id and trace_id. Both are non-enumerable: readable, but omitted by
// Object.keys() and JSON.stringify(). `result.lifecycleId` here is undefined.
result.lifecycleId // 'qlc_000178'
```

**Python SDK**

```python
# a dict subclass; `result` is already unwrapped
{
 "agent_id": "6ab1945e7566f41b5c28e303.6ab1945e83ff5845d7db96bc",
 "updated": [
  "prompt",
  "role_description"
 ]
}

out.lifecycle_id  # 'qlc_000178' — an attribute, not a key
```

**More details**

The model is changed through `llm`, as `{"llm": {"model": "mdl_..."}}`: `create-agent`'s flat `model` argument has no update-side equivalent. Identity and wiring fields are not editable here.

### Editable keys of `agent`

Only these keys are accepted.

| Key | Type | Notes |
| --- | --- | --- |
| `title` | string | The agent's display name. This is `create-agent`'s `name`, renamed on the update side. |
| `role` | string |  |
| `role_description` | string |  |
| `prompt` | object | **Not a string.** `template` is enough: `display_template` is derived from it when you leave it out. Passing a string is refused by the agent tools, not by validation. |
| `llm` | object | `{"model": "mdl_..."}`. This is `create-agent`'s flat `model`, renamed and nested. |
| `skills` | array | This is `create-agent`'s `skill_ids`, renamed. |
| `context` | array |  |
| `has_knowledge_base` | boolean |  |
| `is_preview_mode_enabled` | boolean |  |
| `context_required` | boolean |  |
| `context_target_agent_ids` | array |  |
| `triggers` | array |  |
| `conditions` | array |  |
| `context_access` | object | The console's Context from Graph control. `{"mode": "off" \| "brief_only" \| "full"}`. `mode` is required whenever you send `context_access` at all, because the whole setting is replaced: an object without one would reset the mode to `full` rather than leave it alone. Omit `context_access` entirely to leave the stored setting untouched. |
| `agent_base_prompt` | string | The console's Agent Base Prompt box, the reasoning prompt the agent runs on. Omit it to leave a stored prompt untouched; send an empty string to ask for the platform default. |
| `is_terminal_agent` | boolean | `skilled_agent` only. The console's Terminal Agent switch. Recorded and read back, but nothing in the run engine acts on it yet. |
| `is_user_specific_task` | boolean | `skilled_agent` only. The console's "Restrict to active user's data only" checkbox. |
| `registration_id` | string | `interop_agent` only: the peer agent connection an [external agent node](/docs/automation/update-process-flow) delegates to. It belongs to a node inside a process flow rather than to an agent in this registry; repoint one with `update-process-flow`. |

Every tool call works the same way: [How every tool call works](/docs/sdks-and-apis/how-every-tool-call-works).
