> For the complete documentation index, see [llms.txt](https://gdplabs.gitbook.io/sdk/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/agents.md).

# Agents

Master agent lifecycle operations, orchestration patterns, and runtime controls with the Python SDK. Use CLI pages for low-code operations. Use REST as reference-only for internal integrations (for example GLChat).

{% hint style="info" %}
For current coverage, see the [AIP capability matrix](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/introduction-to-gl-aip#platform-capabilities-at-a-glance). Key callouts for agents: CLI still leans on export/import for `tool_configs`, memory toggles, and runtime overrides. Run history and scheduling are available via the SDK; REST remains reference-only.
{% endhint %}

{% hint style="info" %}
CLI examples accept either an agent ID or a unique name for `AGENT_REF`. Partial matches trigger fuzzy search; add `--select` to disambiguate or pass the full ID when you need a deterministic lookup.
{% endhint %}

### Execution Modes: Local vs Remote

See [Local vs Remote Mode](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/getting-started/local-vs-remote) for detailed comparison and decision checklist.

For deployed agents, see [Execution Engines](/sdk/gl-aip-ai-agent-package/guides/execution-engines.md) to select AIP Runner or GL Runner, configure the saved engine, and optionally override one remote run. Local execution uses the SDK's local runner.

### Pattern Decision Guide

Choose the right pattern for your agent operations:

#### Agent-First Pattern (Recommended)

Use for creating and deploying single agents with simple configuration.

```python
from glaip_sdk import Agent
from tools import CalculatorTool  # Your LangChain BaseTool class

agent = Agent(
    name="math-tutor",
    instruction="You are a patient tutor. Show working for every step.",
    tools=[CalculatorTool],  # Use LangChain BaseTool classes for local execution
    agent_config={"memory": "mem0"}
)

# Run the agent
result = agent.run("What is 15 * 23?")
```

**Use this pattern for:**

* Creating and running single agents
* Simple agent configuration
* Quick prototypes
* Self-contained agent operations

#### Client Pattern (Legacy/Advanced)

Use for listing, searching, and batch operations across multiple agents. This is a legacy/advanced pattern kept for backward compatibility and cross-agent governance workflows; prefer the Agent-first pattern for creating, updating, and running individual agents.

```python
from glaip_sdk import Client

client = Client()

# Listing operations
agents = client.agents.list_agents(name="tutor")

# Batch operations
for agent in agents:
    print(f"Agent: {agent.name}")

# Advanced lifecycle management
agent = client.agents.get_agent_by_id("agent-123")
```

**Use this pattern for:**

* Listing and searching agents
* Batch operations across multiple agents
* Complex resource management workflows
* Multi-agent coordination

{% hint style="warning" %}
**Client-only operations (legacy/advanced admin path):**

* Creating agents from JSON/YAML files (`create_agent_from_file`)
* Bulk listing and filtering agents
* LangFlow sync operations
* Run history retrieval via `client.agents.runs`

Use the Client pattern only for these administrative and batch workflows.
{% endhint %}

***

### Create Agents

**Python SDK**

**Recommended: Agent Pattern**

```python
from glaip_sdk import Agent

agent = Agent(
    name="math-tutor",
    instruction="You are a patient tutor. Show working for every step.",
    tools=["time_tool"],  # String references require deploy() for remote execution
    agent_config={"memory": "mem0"}
)
agent.deploy()  # Required when using string tool references
```

| Parameter      | Type                                 | Default       | Description                                                                                                                                                                                                                                   |
| -------------- | ------------------------------------ | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`         | `str`                                | (required)    | Unique agent identifier on the AIP platform.                                                                                                                                                                                                  |
| `instruction`  | `str`                                | (required)    | Core directive / system prompt for the agent.                                                                                                                                                                                                 |
| `description`  | `str`                                | `""`          | Human-readable description of the agent's purpose.                                                                                                                                                                                            |
| `tools`        | `list`                               | `[]`          | Tool classes, SDK `Tool` objects, or native tool name strings.                                                                                                                                                                                |
| `agents`       | `list`                               | `[]`          | Sub-agents for delegation/coordinator workflows.                                                                                                                                                                                              |
| `mcps`         | `list`                               | `[]`          | MCP references for external system connections.                                                                                                                                                                                               |
| `skills`       | `SkillsInput`                        | `None`        | Skill inputs for local execution (e.g., skill names or paths).                                                                                                                                                                                |
| `model`        | `str \| Model \| list[str \| Model]` | `None`        | Model selector. A list uses its first entry as primary and later entries as ordered fallbacks; symbolic `provider/model` values resolve seeded AIP models on remote deployment and UUID-shaped values bind exactly to remote language models. |
| `filesystem`   | `bool \| FilesystemConfig`           | `True`        | Enable filesystem middleware. Use [`SandboxConfig`](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/agent-filesystem/sandbox) to select an isolated sandbox and its E2B or OpenSandbox provider.                                |
| `guardrail`    | `GuardrailManager`                   | `None`        | Content safety guardrail manager.                                                                                                                                                                                                             |
| `ptc`          | `PTC`                                | `None`        | Programmatic tool calling (sandbox code execution) config.                                                                                                                                                                                    |
| `timeout`      | `int`                                | `300`         | SDK direct-`Agent(...)` default for the execution timeout (5 min); this is not the platform runner fallback.                                                                                                                                  |
| `metadata`     | `dict`                               | `None`        | Optional metadata dictionary attached to the agent.                                                                                                                                                                                           |
| `framework`    | `str`                                | `"langchain"` | Agent framework identifier.                                                                                                                                                                                                                   |
| `version`      | `str`                                | `"1.0.0"`     | Agent version string.                                                                                                                                                                                                                         |
| `agent_type`   | `str`                                | `"config"`    | Agent type identifier.                                                                                                                                                                                                                        |
| `agent_config` | `dict`                               | `None`        | Agent execution configuration (e.g., `{"memory": "mem0"}`).                                                                                                                                                                                   |
| `tool_configs` | `dict`                               | `None`        | Per-tool configuration overrides.                                                                                                                                                                                                             |
| `mcp_configs`  | `dict`                               | `None`        | Per-MCP configuration overrides.                                                                                                                                                                                                              |
| `a2a_profile`  | `dict`                               | `None`        | A2A profile configuration.                                                                                                                                                                                                                    |

**LM Retry Configuration**

For a model chain, set retry\_config on the primary model only; it configures retries for the chain's language-model invocation. A non-empty retry\_config on a fallback Model is rejected because retry configuration is not per-fallback. An empty retry\_config dictionary is treated as unset, preserving the runtime default.

For model configuration, put `retry_config` on `Model`.

```python
from glaip_sdk import Agent
from glaip_sdk.models import Model

agent = Agent(
    name="retry-aware-agent",
    instruction="Answer clearly and concisely.",
    model=Model(
        id="openai/gpt-4o-mini",
        retry_config={"max_retries": 2, "timeout": 30.0},
    ),
)
```

**Hosted Mem0 and Local SDK Memory**

`agent_config={"memory": "mem0"}` keeps the existing hosted Mem0 mode. For local SDK runs, `MemoryConfig` provides a validated nested form for Elasticsearch and its embedding model:

```python
from glaip_sdk import Agent, MemoryConfig

agent = Agent(
    name="memory-agent",
    instruction="You are a helpful assistant with long-term memory.",
    agent_config={
        "memory": MemoryConfig(
            backend="es",
            elasticsearch={
                "url": "https://elasticsearch.example:9243",
                "collection_name": "agent-memories",
                "username": "runtime-user",
                "password": "<elasticsearch-secret>",
            },
            embedding={
                "model": "openai/text-embedding-3-small",
                "dimensions": 1536,
                "credentials": "<embedding-secret>",
            },
        ),
    },
)
```

This structured form is additive; existing agents do not need to migrate. The legacy flat Elasticsearch form remains supported:

```python
from glaip_sdk import Agent

agent = Agent(
    name="memory-agent",
    instruction="You are a helpful assistant with long-term memory.",
    agent_config={
        "memory": "es",
        "memory_mode": "sdk",
        "memory_elasticsearch_url": "https://elasticsearch.example:9243",
        "memory_collection_name": "agent-memories",
        "memory_embedding_model": "openai/text-embedding-3-small",
        "memory_embedding_dimensions": 1536,
        "memory_elasticsearch_verify_certs": True,
        "memory_elasticsearch_user": "runtime-user",
        "memory_elasticsearch_password": "<elasticsearch-secret>",
    },
)
```

The equivalent mapping form is accepted under `agent_config["memory"]`. `MemoryConfig(backend="mem0")` is also available when a typed selector is preferred. Structured Elasticsearch memory selects local SDK mode; it does not enable remote AIP support.

The structured connection fields `username`, `password`, and `api_key`, and `embedding.credentials`, stay on the local Agent. `Agent.model_dump()` preserves them so `Agent(**agent.model_dump())` retains the memory connection; treat that dump as sensitive. `Agent.sanitized_model_dump()`, API payloads, and `MemoryConfig.model_dump()` omit them. If `embedding.credentials` is omitted, local execution retains the `MEMORY_EMBEDDING_API_KEY` fallback. Elasticsearch credentials can likewise be omitted and supplied through `MEMORY_ELASTICSEARCH_USER`, `MEMORY_ELASTICSEARCH_PASSWORD`, or `MEMORY_ELASTICSEARCH_API_KEY`. SDK mode requires the `memory` extra and does not enable Knowledge Graph or reranker extras. Existing hosted mode continues to use `MEM0_HOST`/`MEM0_API_KEY` or the `GLLM_MEMORY_*` aliases.

> The current `gllm-memory` 0.3.x dependency line supports the memory extra on Python 3.11 and 3.12. The base SDK remains compatible with Python 3.13; use the memory extra there after `gllm-retrieval` publishes Python 3.13 support.

> **Deprecated client pattern (still supported)**
>
> The older `client.agents.create_agent` API is kept for backward compatibility but new code should prefer the `Agent` pattern above for a simpler, low-code workflow and future improvements.

```python
# Deprecated: prefer the Agent(...) pattern above
from glaip_sdk import Client

client = Client()

agent = client.agents.create_agent(
    name="math-tutor",
    instruction="You are a patient tutor. Show working for every step.",
    tools=["time_tool"],
    agent_config={"memory": "mem0"},
)

# `agent` is a glaip_sdk.agents.Agent instance, so you can call the same
# lifecycle methods as with the Agent(...) pattern
agent.run("What is 15 * 23?")
```

**CLI**

```bash
aip agents create \
  --name math-tutor \
  --instruction "You are a patient tutor. Show working for every step." \
  --tools time_tool
```

```bash
curl \
  -X POST "$AIP_API_URL/agents" -H "Content-Type: application/json" -H \
  "X-API-Key: $AIP_API_KEY" -d '{
        "name": "math-tutor",
        "instruction": "You are a patient tutor. Show working for every step.",
        "tools": ["time_tool"],
        "agent_config": {"memory": "mem0"}
      }'
```

#### Specifying the Model

Agents use a default model (`openai/gpt-5-nano`) unless you specify otherwise. Use the `model` parameter with the standardized `provider/model` format:

{% hint style="info" %}
**Remote model resolution:** When deploying to AIP, each symbolic model entry (e.g., `"openai/gpt-5.2"`, `OpenAI.GPT_5_2`) resolves against **seeded AIP models only** (`account_id = null`). UUID-shaped entries (e.g., `"fc945f0a-595e-471f-807c-47334c0eba9f"`) bind exactly to that language model. In a list, the first entry is primary and later entries are attempted in order when eligible. See [Language models](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/language-models#sdk-model-selection) for full resolution semantics.
{% endhint %}

{% tabs %}
{% tab title="Python SDK" %}
**Using Model Constants (Recommended):**

```python
from glaip_sdk import Agent
from glaip_sdk.models import OpenAI, DeepInfra, Anthropic

# OpenAI model
agent = Agent(
    name="analysis",
    instruction="You are a data analyst.",
    model=OpenAI.GPT_5_NANO,  # "openai/gpt-5-nano"
)

# DeepInfra model
agent = Agent(
    name="research",
    instruction="You are a research assistant.",
    model=DeepInfra.QWEN3_30B_A3B,  # "deepinfra/Qwen/Qwen3-30B-A3B"
)

# Anthropic model
agent = Agent(
    name="creative",
    instruction="You are a creative writer.",
    model=Anthropic.CLAUDE_SONNET_4_0,  # "anthropic/claude-sonnet-4-0"
)
```

**Using String Format:**

```python
# OpenAI model
agent = Agent(
    name="analysis",
    instruction="You are a data analyst.",
    model="openai/gpt-5",
)

# DeepInfra model (includes organization in path)
agent = Agent(
    name="research",
    instruction="You are a research assistant.",
    model="deepinfra/Qwen/Qwen3-30B-A3B",
)

# Anthropic model
agent = Agent(
    name="creative",
    instruction="You are a creative writer.",
    model="anthropic/claude-sonnet-4-0",
)

# Exact binding to a specific language model (remote deployment only; for local
# use symbolic provider/model or Model(...))
agent = Agent(
    name="tenant-model",
    instruction="You are helpful.",
    model="fc945f0a-595e-471f-807c-47334c0eba9f",
)
```

**Using Model Class (Custom Configuration):**

```python
import os

from glaip_sdk import Agent
from glaip_sdk.models import Model

# Custom model with credentials and hyperparameters
agent = Agent(
    name="custom-model",
    instruction="You are helpful.",
    model=Model(
        id="custom/kimi-k2.5",
        base_url="https://api.moonshot.ai/v1",
        credentials=os.environ["MOONSHOT_API_KEY"],
        hyperparameters={
            "temperature": 1.0,
            "max_tokens": 32768,
        },
    ),
)
```

**Using ordered model fallbacks:**

```python
from glaip_sdk import Agent

agent = Agent(
    name="reliable-agent",
    instruction="Answer helpfully.",
    model=[
        "openai/gpt-5.6-luna",
        "openai/gpt-5.6-terra",
    ],
)
```

The first entry is the primary model. Later entries are tried in declaration order only when the previous model fails before side effects begin. Fallbacks are not replayed after cancellation, validation/configuration errors, pending tool-call requests, custom-code failures, or partial streamed output. Credentials and custom endpoints are isolated per model entry. Each entry accepts any supported `model=` format (constant, symbolic string, UUID, or `Model(...)`); see [Language models](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/language-models#attach-models-to-agents) for the acceptable formats.
{% endtab %}

{% tab title="CLI" %}

```bash
# Create agent with specific model
aip agents create \
  --name analysis \
  --instruction "You are a data analyst." \
  --model openai/gpt-5

# Or using DeepInfra
aip agents create \
  --name research \
  --instruction "You are a research assistant." \
  --model deepinfra/Qwen/Qwen3-30B-A3B
```

{% endtab %}

{% tab title="REST" %}

```bash
curl \
  -X POST "$AIP_API_URL/agents" -H "Content-Type: application/json" -H \
  "X-API-Key: $AIP_API_KEY" -d '{
        "name": "analysis",
        "instruction": "You are a data analyst.",
        "model": "openai/gpt-5"
      }'
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
**Model Constants:** Import typed constants from `glaip_sdk.models` for better IDE support and validation:

* `from glaip_sdk.models import OpenAI, Anthropic, Google, AzureOpenAI, DeepInfra, DeepSeek, Bedrock`
* Current SDK default model: `openai/gpt-5-nano`

See the [Language models](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/language-models) for the complete list of available models.
{% endhint %}

In JSON definitions, disable planning by setting `"planning": false` in `agent_config` when you want a standard single-pass agent instead of a planning-enabled one.

{% hint style="info" %}
`Agent.deploy()` will create a new agent when it does not exist yet, and update the existing definition when called again with the same reference. Use `agent.update()` when you already have a deployed `Agent` instance and want to change fields incrementally.
{% endhint %}

{% hint style="info" %}
By default, redeploying an existing agent uses a full-replacement `PUT` that can overwrite unrelated server-side edits. To redeploy only selected resolved fields, opt in with `update_strategy="patch"` — see [Sparse PATCH deploys](#sparse-patch-deploys-for-config-only-redeploys) below for the full semantics.
{% endhint %}

#### Sparse PATCH deploys for config-only redeploys

Use `Agent.deploy(update_strategy="patch")` to redeploy only a subset of top-level fields — the SDK resolves the latest local definition, sends only the selected fields, and preserves everything else on the server. This is useful when a deployment script owns `tool_configs` or `mcp_configs` while operators may still edit unrelated fields in AIP.

```python
from glaip_sdk import Agent
from aip_agents.tools.gl_connector import GLConnectorTool

agent = Agent(
    name="document-agent",
    instruction="Search records and summarize highlights.",
    tools=[GLConnectorTool("google_drive_search_files_tool")],
    tool_configs={
        "google_drive_search_files_tool": {
            "user_authentication": True,
            "timeout_seconds": 30,
        }
    },
)

# Existing agent: PATCHes the resolved tool_configs (and mcp_configs if set).
# Missing agent: creates the agent with the full resolved payload.
agent.deploy(update_strategy="patch")
```

Pass `patch_fields` when you need to patch a different subset:

```python
agent.deploy(
    update_strategy="patch",
    patch_fields={"instruction", "tool_configs", "agent_config"},
)
```

| Behavior             | Details                                                                                                                                                     |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Default deploy       | `agent.deploy()` still uses full-replacement `PUT` for existing agents.                                                                                     |
| Default PATCH fields | `agent.deploy(update_strategy="patch")` selects `tool_configs` and `mcp_configs`, but only includes a field if it is present in the resolved config.        |
| Missing remote agent | Still creates with the full resolved payload; `update_strategy="patch"` only changes the update branch.                                                     |
| Network calls        | PATCH deploy uses name discovery and does not call detail `GET /agents/{id}` before patching.                                                               |
| Validation           | Unsupported `patch_fields`, a single string `patch_fields`, or `patch_fields` without `update_strategy="patch"` raise `ValueError` before any network call. |

Allowed `patch_fields` values are `instruction`, `description`, `model`, `metadata`, `agent_config`, `tool_configs`, `mcp_configs`, `skills`, `tools`, `agents`, `mcps`, and `a2a_profile`. Identity and platform-managed fields such as `name`, `framework`, `version`, and `agent_type` are intentionally rejected.

{% hint style="warning" %}
If the selection resolves to no fields — for example the bare default `agent.deploy(update_strategy="patch")` on an agent with neither `tool_configs` nor `mcp_configs` — the SDK raises `ValueError` before any network call. Pass an explicit `patch_fields` containing at least one resolvable field (for example `patch_fields={"instruction"}`).
{% endhint %}

{% hint style="warning" %}
Relationship fields (`tools`, `agents`, `mcps`) are omitted from the PATCH when they were not provided to `Agent(...)`, which preserves the remote value. Select a relationship field only when this deployment should own it; passing an explicit empty list, for example `tools=[]` plus `patch_fields={"tools"}`, clears that relationship remotely.
{% endhint %}

#### PATCH deploys for nested agent hierarchies

Select `agents` when the deployment owns a local coordinator's sub-agent relationships. The same `update_strategy="patch"` and `patch_fields` are applied to local `Agent` references at every nested level, resolving descendants before their parents. Existing descendants receive sparse PATCH requests; missing descendants are created with their full resolved payload.

```python
from glaip_sdk import Agent

writer = Agent(name="writer", instruction="Draft the response.")
research_lead = Agent(
    name="research-lead",
    instruction="Delegate research, then synthesize it.",
    agents=[writer],
)
coordinator = Agent(
    name="coordinator",
    instruction="Coordinate the workflow.",
    agents=[research_lead],
)

# Applies the selected relationship update through every local nested Agent.
coordinator.deploy(update_strategy="patch", patch_fields={"agents"})
```

For an existing coordinator, omitting `agents` from `patch_fields` does not resolve or deploy local sub-agents and leaves the remote relationship unchanged. A shared local descendant is deployed once per top-level deploy call; separate top-level deploy calls keep their traversal state independent.

Use `agent.patch(...)` instead when you already have a deployed agent and want to send explicit fields directly to its backend PATCH endpoint. It does not resolve a local agent hierarchy.

{% hint style="warning" %}
`description` and `metadata` resolve to empty defaults when not provided. Do not include them in `patch_fields` unless this deployment should overwrite those remote values.
{% endhint %}

{% hint style="info" %}
Need `tool_configs`, runtime overrides, or memory toggles from the CLI today? Export with `aip agents get --export`, edit the JSON, then re-import with `aip agents create --import` or `aip agents update --import`.
{% endhint %}

### List and Inspect Agents

**Python SDK**

```python
for agent in client.agents.list_agents(name="tutor"):
    print(agent.id, agent.name)

detail = client.agents.get_agent_by_id("agent-123")
print(detail.agent_config.get("lm_name"))
```

Note: `client.agents.list_agents()` and `client.agents.get_agent_by_id()` already return `Agent` instances, so you can call methods like `agent.run()`, `agent.update()`, or `agent.delete()` on the returned objects.

**CLI**

```bash
aip agents list

aip agents get agent-123 --view json
```

### Update Agents

**Python SDK**

```python
# Assuming `agent` is an Agent instance
# (created with Agent(...) or loaded via client.agents.get_agent_by_id)
agent.update(
    instruction="Provide thorough financial analysis.",
    tools=["balance-sheet-parser", "chart-generator"],
    agent_config={"memory": "mem0", "tool_output_sharing": False},
    model="fc945f0a-595e-471f-807c-47334c0eba9f",
)
```

For remote agents:

* symbolic `model="openai/gpt-5-nano"` resolves seeded AIP language models only
* UUID-shaped `model="<language-model-uuid>"` binds exactly to that remote language model

**CLI**

```bash
cat > agent-update.json <<'JSON'
{
  "instruction": "Provide thorough financial analysis.",
  "agent_config": {
    "memory": "mem0",
    "tool_output_sharing": false
  },
  "language_model_id": "managed-finance-lm"
}
JSON

aip agents update agent-123 --import agent-update.json
```

### Delete and Restore Agents

**Python SDK**

```python
# Assuming `agent` is an Agent instance
agent.delete()  # Only needed if agent was deployed
```

**CLI**

```bash
aip agents delete agent-123
```

### Run Agents

#### Basic Execution

**Python SDK**

**Synchronous:**

```python
# Assuming `agent` is an Agent instance
response = agent.run("Summarise the latest updates.")
print(response)
```

**Asynchronous (streaming):**

```python
import asyncio

async def main():
    async for chunk in agent.arun("Summarise the latest updates."):
        print(chunk, end="", flush=True)

asyncio.run(main())
```

**Local event streaming:**

```python
import asyncio

async def main():
    async for event in agent.arun("Summarise", local=True):
        print(event)

asyncio.run(main())
```

Use `agent.arun()` for streaming text chunks from deployed agents. Use `agent.arun(local=True)` when you want the live local SSE/activity events printed as-is.

**Parameters for `agent.run()`**

| Parameter             | Type           | Default    | Description                                                        |
| --------------------- | -------------- | ---------- | ------------------------------------------------------------------ |
| `message`             | `str`          | (required) | The input message/query for the agent.                             |
| `verbose`             | `bool`         | `False`    | Print streaming output to the console.                             |
| `local`               | `bool`         | `False`    | Force local execution even if the agent is deployed.               |
| `runtime_config`      | `dict`         | `None`     | Runtime overrides for tools, MCPs, and agents.                     |
| `gl_connectors_token` | `str`          | `None`     | Token for GL Connectors user authentication.                       |
| `chat_history`        | `list[dict]`   | `None`     | Prior conversation messages (`{"role": "...", "content": "..."}`). |
| `trace`               | `bool`         | `False`    | Return `AgentRunResult` with detailed execution info.              |
| `export`              | `bool`         | `False`    | Write a transcript JSONL file to disk.                             |
| `export_dir`          | `str \| Path`  | `None`     | Directory for the export file (requires `export=True`).            |
| `enable_pii`          | `bool \| None` | `None`     | Override PII masking for this run.                                 |
| `files`               | `list[str]`    | `None`     | File paths to attach to the run (passed via \*\*kwargs).           |

**Parameters for `agent.arun()`**

| Parameter             | Type           | Default    | Description                                                        |
| --------------------- | -------------- | ---------- | ------------------------------------------------------------------ |
| `message`             | `str`          | (required) | The input message/query for the agent.                             |
| `verbose`             | `bool`         | `False`    | Print streaming output to the console.                             |
| `local`               | `bool`         | `False`    | Force local execution even if the agent is deployed.               |
| `runtime_config`      | `dict`         | `None`     | Runtime overrides for tools, MCPs, and agents.                     |
| `gl_connectors_token` | `str`          | `None`     | Token for GL Connectors user authentication.                       |
| `chat_history`        | `list[dict]`   | `None`     | Prior conversation messages (`{"role": "...", "content": "..."}`). |
| `enable_pii`          | `bool \| None` | `None`     | Override PII masking for this run.                                 |
| `files`               | `list[str]`    | `None`     | File paths to attach to the run (passed via \*\*kwargs).           |

> **Note:** `trace`, `export`, and `export_dir` are not supported in `arun`; use `run()` for those options.

**CLI**

```bash
aip agents run agent-123 --input "Summarise the latest updates."
```

#### With Files

**Python SDK**

```python
response = agent.run(
    "Review the attached report and highlight top risks.",
    files=["/tmp/report.pdf"],
)
```

**CLI**

```bash
aip \
  agents run agent-123 --input "Review the attached report and highlight \
  top risks." --file /tmp/report.pdf
```

#### Runtime Overrides and PII

To override the engine for one remote run, see [Optional: Override for One Run](/sdk/gl-aip-ai-agent-package/guides/execution-engines.md#optional-override-for-one-run).

**Python SDK**

```python
agent.run(
    "Produce a weekly revenue summary",
    pii_mapping={"<EMAIL_1>": "alice@example.com"},
    runtime_config={
        "agent_config": {
            "planning": False,
        },
        "tool_configs": {
            "revenue-sql": {"max_rows": 500, "group_by": "region"}
        },
        "mcp_configs": {
            "finance-data": {
                "authentication": {
                    "type": "api-key",
                    "value": "temporary-key"
                }
            }
        },
    },
)
```

Behind the scenes, `Agent` resolves `tool_configs` and `mcp_configs` using the global registries. This means you can define these configs against class-based `Tool` and MCP definitions, tool names, or IDs, and the SDK will map them to the correct resource IDs at deploy or run time.

**Config key resolution:** In `runtime_config`, you can reference tools and MCPs by:

* **Custom LangChain tool class**: `{GreetingTool: {"param": "value"}}` — your `BaseTool` subclass
* **Native aip-agents tool class**: `{TimeTool: {"param": "value"}}` — a class imported from `aip_agents.tools`
* **MCP helper instance**: `{MCP.from_native("weather"): {"auth": {...}}}` — an `MCP` reference
* **Name string**: `{"greeting_tool": {"param": "value"}}` — tool/MCP name on the remote server
* **UUID**: `{"550e8400-e29b-...": {"param": "value"}}` — direct ID registered in the server

**Configuration priority order (lowest to highest):**

Agent configurations are resolved in the following priority order, with higher priority overriding lower:

1. **Agent definition configs** (lowest priority) — `agent_config`, `tool_configs`, `mcp_configs` passed to `Agent()` constructor
2. **Runtime config global** — Top-level keys in `runtime_config` (e.g., `runtime_config["tool_configs"]`)
3. **Runtime config agent-specific** (highest priority) — Agent-specific overrides in `runtime_config[agent]`

Example showing all three layers:

```python
from glaip_sdk import Agent

# Layer 1: Agent definition configs (lowest priority)
agent = Agent(
    name="research-agent",
    instruction="...",
    tools=[ResearchTool],
    agent_config={"planning": False},  # Default: no planning
    tool_configs={
        ResearchTool: {"style": "brief", "max_results": 5}  # Defaults
    },
)

# Layer 2 & 3: Runtime overrides (higher priority)
agent.run(
    "Research AI trends",
    runtime_config={
        # Layer 2: Global runtime config
        "agent_config": {"planning": True},  # Override: enable planning
        "tool_configs": {
            ResearchTool: {"style": "detailed"}  # Override: detailed style
        },
        # Layer 3: Agent-specific runtime config (highest priority)
        agent: {
            "tool_configs": {
                ResearchTool: {"max_results": 10}  # Override: 10 results
            }
        }
    }
)

# Final resolved config for this run:
# - planning: True (from runtime global)
# - style: "detailed" (from runtime global)
# - max_results: 10 (from runtime agent-specific, highest priority)
```

This layered approach allows you to:

* Set sensible defaults at agent definition time
* Apply global overrides for all agents in a workflow
* Fine-tune specific agents with agent-specific overrides

**CLI**

`pii_mapping` and `runtime_config` flags are in development. Use the SDK or REST API for sensitive workflows until dedicated options land.

#### Chat History

**Python SDK**

```python
history = [
    {"role": "user", "content": "We are drafting a security brief."},
    {"role": "assistant", "content": "Acknowledged. What scope should we cover?"},
]
agent.run(
    "Include external threat intel sources.",
    chat_history=history,
)
```

**CLI**

```bash
HISTORY='[{"role":"user","content":"We are drafting a security brief."}]'
aip \
  agents run agent-123 --input "Include external threat intel sources." \
  --chat-history "$HISTORY"
```

Persist long-term context with `agent_config.memory="mem0"`; edit exports or use SDK kwargs until CLI flags arrive.

### Planning Mode

Enable planning mode to have agents create a structured plan before executing complex tasks. This improves reasoning quality and task decomposition for multi-step queries.

**Python SDK**

```python
from glaip_sdk import Agent
from tools import CalendarTool, TaskManagerTool  # Your LangChain BaseTool classes

agent = Agent(
    name="project-planner",
    instruction="You are a project manager. Break down tasks systematically.",
    tools=[CalendarTool, TaskManagerTool],
    agent_config={"planning": True},
)

# The agent will first create a plan, then execute each step
response = agent.run(
    "Create a launch plan for our new product release next month."
)
```

**CLI**

```bash
cat > planner-agent.json <<'JSON'
{
  "name": "project-planner",
  "instruction": "You are a project manager. Break down tasks systematically.",
  "agent_config": {
    "planning": true
  }
}
JSON

aip agents create --import planner-agent.json
```

{% hint style="info" %}
Planning mode is especially useful for:

* Complex multi-step tasks that benefit from upfront reasoning
* Tasks requiring coordination across multiple tools
* Scenarios where transparency in the agent's approach is valuable
  {% endhint %}

{% hint style="danger" %}
**The agent timeout governs the total run budget for both local and deployed execution.** The enclosing agent (or sub-agent) run timeout always governs the total execution budget. A per-tool resilience timeout can only stop a tool earlier — it cannot extend the agent run. If your tool needs 1200s to complete, the deployed agent timeout must also be at least 1200s. See [Tool Resilience → Timeout](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/tools#tool-resilience) for the per-tool timeout budget relationship and configuration.
{% endhint %}

### Timeouts and Limits

#### Canonical agent deadline

The agent timeout is the outer wall-clock budget for one agent execution. There are several supported ways to set it; they all target the same canonical stored field, `agent_config["timeout_seconds"]`:

```python
from glaip_sdk import Agent

# 1. SDK convenience argument on an Agent definition.
agent = Agent(
    name="long-running-agent",
    instruction="Complete the workflow.",
    timeout=600,
)

# 2. The canonical config field directly.
configured_agent = Agent(
    name="long-running-agent",
    instruction="Complete the workflow.",
    agent_config={"timeout_seconds": 600},
)

agent.deploy()
configured_agent.deploy()
# Both deployments persist agent_config["timeout_seconds"] == 600.
```

For JSON/YAML imports or hand-edited payloads, set the nested canonical field:

```yaml
agent_config:
  timeout_seconds: 600
```

When constructing an `Agent`, the definition-time precedence is:

1. Existing `agent_config["timeout_seconds"]`
2. `Agent(timeout=N)`
3. SDK direct-`Agent(...)` default (`300` seconds)

The SDK uses this precedence for the `Agent.timeout` property and deploy serialization. Canonical values must be positive integers; invalid values are rejected before serialization. Avoid supplying conflicting values; set one canonical value.

#### Which default applies?

The value `300` is an SDK default for the direct `Agent(...)` model and its deployment serialization; it is not the platform runner fallback. If a deployed payload arrives without a valid canonical `timeout_seconds`, the AIP runner currently applies its fallback of 3600 seconds. That fallback is only a missing/invalid-value fallback and is not a cap on an explicit timeout.

For local execution, `agent_config["timeout_seconds"]` or constructor `Agent(timeout=N)` is enforced as a whole-agent wall-clock deadline from the same canonical value used for deployed runs. When the value is set, `arun()` and `arun_stream()` raise `AgentTimeoutError` if the total execution exceeds the configured seconds. The synchronous `run()` path delegates to `arun()` and surfaces the same timeout. When no explicit `timeout_seconds` is set, local execution proceeds without a whole-run deadline and relies on tool-level resilience timeouts and runtime defaults. The top-level `Agent.run(timeout=N)` keyword is an SDK HTTP/SSE wait guard only for server-backed runs; for local mode, use `agent_config["timeout_seconds"]` or `Agent(timeout=N)`.

{% hint style="warning" %}
**Best-effort cancellation.** When `AgentTimeoutError` is raised, the SDK cancels the async execution and runs bounded cleanup. Synchronous side effects that are already running in a blocking default-executor tool (such as `time.sleep()` or a synchronous HTTP call) are not forcibly terminated and may continue until they complete or the process exits. Use per-tool `resilience.timeout_seconds` to limit individual tool calls independently of the whole-agent deadline.
{% endhint %}

#### Legacy `agent_config["timeout"]` is unsupported

`agent_config["timeout"]` does not configure the deployed AIP agent deadline. It is forwarded as an unknown configuration key, while the SDK adds the canonical default when no `timeout_seconds` is present:

```python
agent = Agent(
    name="incorrect-timeout-agent",
    instruction="Complete the workflow.",
    agent_config={"timeout": 600},
)
agent.deploy()
# Stored config includes:
# {"timeout": 600, "timeout_seconds": 300}
# The AIP deadline is 300 seconds, not 600 seconds.
```

Migrate manual configuration from `timeout` to `timeout_seconds`:

```yaml
# Before: unsupported for the deployed agent deadline
agent_config:
  timeout: 600

# After: canonical
agent_config:
  timeout_seconds: 600
```

There is currently no deprecation warning or compatibility translation for the legacy key. Treat it as unsupported/ignored for the AIP agent-deadline path, not as a supported alias.

#### Deployed agent and tool timeout hierarchy

For deployed platform runs, agent and tool timeouts operate at different scopes:

| Level                | Setting                                                  | Scope and outcome                                                                                                        |
| -------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Agent definition     | `agent_config["timeout_seconds"]` or `timeout=N`         | Outer wall-clock budget for that agent's complete run, including reasoning, delegation, and all tool calls               |
| Sub-agent definition | Its own `agent_config["timeout_seconds"]` or `timeout=N` | Budget for that child agent's own work; it cannot extend the coordinator's remaining budget                              |
| Tool invocation      | `tool_configs[Tool].resilience.timeout_seconds`          | Inner budget for one tool call, including its retries; it can stop that call early but cannot extend the enclosing agent |
| Platform fallback    | AIP runner fallback                                      | Used only when the deployed canonical agent deadline is absent or invalid; currently 3600 seconds                        |

For one tool call, the effective budget is bounded by both clocks:

```
effective tool budget = min(per-tool resilience timeout, remaining agent budget)
```

For example, with an agent timeout of 60 seconds and a tool timeout of 300 seconds, the remaining agent budget wins; the tool cannot run for 300 seconds.

The earliest applicable deadline wins. PTC execution, HITL approval, sandbox commands, and infrastructure idle timeouts are additional lower-level clocks; none can extend the outer agent deadline. See the dedicated [Tool Resilience → Timeout](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/tools#tool-resilience), [Programmatic Tool Calling](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/programmatic-tool-calling), and [Human-in-the-loop approvals](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/human-in-the-loop-approvals) for their independent clocks.

#### Deployed multi-agent timeout coordination

In a deployed multi-agent workflow, set a sufficient timeout on the coordinator and every child that may call long-running tools. Each child keeps its own budget, but a child cannot extend the coordinator's remaining outer budget.

#### Definition, run, and transport timeout scopes

These settings have different owners and should not be substituted for one another:

| Setting                                                              | Scope                         | What it controls                                                                                                                                                      |
| -------------------------------------------------------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Agent(timeout=N)` or `agent_config["timeout_seconds"]`              | Definition/deployment + local | The canonical outer deadline for both deployed and local agent runs; maps to `agent_config["timeout_seconds"]` internally                                             |
| `runtime_config={"agent_config": {"timeout_seconds": N}}`            | One deployed run              | A per-run platform deadline override when the selected runtime supports it; do not rely on it for multipart/file runs until the backend parser limitation is resolved |
| Server-backed `agent.run(timeout=N)` or `aip agents run --timeout N` | SDK/CLI                       | HTTP/SSE waiting and client-side stream guarding; the top-level value is not the authoritative deployed runner deadline                                               |
| Local `agent.run(timeout=N)`                                         | Local SDK/runtime             | HTTP/SSE wait guard for server-backed runs; for local mode, set `agent_config["timeout_seconds"]` to enforce a whole-run deadline                                     |
| Local `agent_config["timeout_seconds"]`                              | Local SDK/runtime             | Enforced whole-agent wall-clock deadline for `arun()`, `arun_stream()`, and `run()`; raises `AgentTimeoutError` when exceeded                                         |
| Local execution without explicit timeout                             | Local SDK/runtime             | No whole-run deadline; relies on tool-level resilience timeouts and runtime defaults                                                                                  |
| `Client(timeout=N)` or top-level `aip --timeout N`                   | SDK/CLI transport             | HTTP request transport timeout, separate from the agent runtime deadline                                                                                              |

For a deployed run, use `runtime_config["agent_config"]["timeout_seconds"]` for a one-off platform override. Use `Agent(timeout=N)` or the canonical `agent_config` field when the deadline should be part of the deployed agent definition.

For non-timeout `agent_config` keys, follow the target runtime's own reference; the SDK's canonical compatibility promise here is limited to `timeout_seconds`.

#### Remote stream and infrastructure idle timeouts

When running agents on the AIP server, intermediate infrastructure components (load balancers, proxies, API gateways) may impose their own idle timeouts on long-running streams. If the agent stops producing output for an extended period, the connection may drop before the agent timeout fires.

**Mitigations:**

* **Stream keepalives:** Intermediate infrastructure (load balancers, proxies, API gateways) may drop idle connections. Consider emitting progress updates or chunked responses from long-running custom tools to keep the stream alive. Some deployment runtimes also provide configurable keepalive intervals.
* **Async / background execution:** For workflows that exceed typical stream timeout windows (e.g., >30 minutes), use the platform's async run or schedule APIs instead of synchronous streaming.

#### Settings reference

| Setting          | Recommended Default | Maximum           | How to Change                                               |
| ---------------- | ------------------- | ----------------- | ----------------------------------------------------------- |
| Agent Runtime    | Set explicitly      | No SDK hard limit | `timeout=N` or `agent_config["timeout_seconds"]`            |
| Step Limit       | 100 steps           | 1000 steps        | `agent_config["step_limit_config"]["max_steps"]`            |
| Sub-Agent Levels | 5 levels            | 10 levels         | `agent_config["step_limit_config"]["max_delegation_depth"]` |

### Context Compaction

Use context compaction for **deployed LangChain agents on an AIP server** and for local `Agent.run(..., local=True)` runs through `LangGraphRunner` when a tool-heavy or long-running conversation may approach the model context limit. It is opt-in: add a `context_compaction` object to every agent that calls a model.

{% hint style="warning" %}
Context compaction is not a global setting and is not inherited by sub-agents. Configuring a coordinator does not configure the agents it delegates to. It is available for deployed AIP server agents and local `Agent.run(..., local=True)` runs through `LangGraphRunner`.
{% endhint %}

The AIP server runtime requires `aip-agents-binary >=0.6.121`; local runs require `aip-agents-binary >=0.6.158`. The `context_compaction` object itself enables the feature; do not add an unsupported `enabled` field.

#### Minimal configuration

An empty object enables compaction with the default settings:

```python
from glaip_sdk import Agent

agent = Agent(
    name="research-agent",
    instruction="Research the topic and return concise, cited findings.",
    agent_config={"context_compaction": {}},
)

agent.deploy()
```

To compact earlier, set `threshold_ratio` explicitly:

```python
agent_config = {"context_compaction": {"threshold_ratio": 0.80}}
```

#### Parameter reference

If `context_compaction` is omitted or `null`, compaction is disabled. An empty object enables it with the default settings. Only these five keys are currently read from `agent_config["context_compaction"]`. Omit a key to use its default.

| Parameter                   |   Default | Purpose                                                           |
| --------------------------- | --------: | ----------------------------------------------------------------- |
| `threshold_ratio`           |    `0.85` | Compact at this fraction of a known model context window.         |
| `fallback_threshold_tokens` | `170_000` | Compact at this token count when the context window is unknown.   |
| `min_tail_tokens`           |   `6_000` | Preserve at least this much recent context after compaction.      |
| `target_tail_ratio`         |    `0.10` | Preserve this fraction of the estimated prompt as recent context. |
| `min_head_messages`         |       `2` | Always preserve this many initial messages.                       |

Lower `threshold_ratio` or `fallback_threshold_tokens` when your prompt, tool schemas, or tool results are unusually large.

#### Configure sub-agents separately

The coordinator and each sub-agent that calls a model need their own setting:

```python
researcher = Agent(
    name="researcher",
    instruction="Research the topic.",
    agent_config={"context_compaction": {}},
)

coordinator = Agent(
    name="coordinator",
    instruction="Delegate research and compose the response.",
    agents=[researcher],
    agent_config={"context_compaction": {}},
)
```

The coordinator setting does not propagate to `researcher`. If the coordinator only routes work and never calls a model, it does not need this setting.

#### Keep tool results bounded

Compaction is a safeguard, not a substitute for disciplined tool output. Return small receipts, summaries, IDs, and artifact links to the agent; keep verbose logs and large reports out of stdout. This prevents a single tool result from consuming the available context before the next compaction pass can run.

### PII Masking (`enable_pii`)

NER-based PII masking redacts entities such as names, email addresses, and phone numbers from tool inputs and outputs, then restores the real values in the final response. You can control masking at three levels of granularity:

| Level                             | How to set                                                           | Priority |
| --------------------------------- | -------------------------------------------------------------------- | -------- |
| Per-agent definition (stored)     | `Agent(agent_config={"enable_pii": True})`                           | Lowest   |
| Per-run override                  | `agent.run(..., enable_pii=True)`                                    | Middle   |
| Per-run, top-level runtime config | `runtime_config={"agent_config": {"enable_pii": True}}`              | High     |
| Per-subagent runtime config       | `runtime_config={subagent: {"agent_config": {"enable_pii": False}}}` | Highest  |

When `enable_pii` is `None` (the default), no override is injected and existing stored config or the runner default (`False`) is used — fully backward-compatible.

{% hint style="info" %}
PII masking requires `NER_API_KEY` and `NER_API_URL` environment variables to be configured in the local runtime. For remote runs the SDK forwards `enable_pii` to the backend, which handles NER infrastructure.
{% endhint %}

#### Set PII masking at agent definition time

Use `agent_config={"enable_pii": True}` to enable masking for every run of the agent by default:

```python
from glaip_sdk import Agent

agent = Agent(
    name="customer-support",
    instruction="Help customers with their enquiries.",
    agent_config={"enable_pii": True},  # PII masking on by default for all runs
)
```

#### Override PII masking at run time

Pass `enable_pii` directly to `agent.run()` or `agent.arun()` to toggle masking for a single call without changing the stored agent definition:

```python
# Enable masking for this run even though stored config has enable_pii=False
result = agent.run("Look up Alice Johnson at alice.johnson@example.com", enable_pii=True)

# Disable masking for this run even though stored config has enable_pii=True
result = agent.run("Process this request", enable_pii=False)

# Omit the parameter to use whatever is stored in agent_config (default behavior)
result = agent.run("Process this request")
```

`agent.arun()` accepts the same parameter:

```python
import asyncio

async def main():
    async for chunk in agent.arun("Look up Alice Johnson", enable_pii=True):
        print(chunk, end="", flush=True)

asyncio.run(main())
```

#### Override PII masking via `runtime_config`

Use `runtime_config["agent_config"]["enable_pii"]` when you want the top-level runtime config to control masking. This takes priority over the per-run `enable_pii` parameter:

```python
result = remote_agent.run(
    "Process this request",
    runtime_config={"agent_config": {"enable_pii": True}},
)
```

#### Multi-agent propagation

When you pass `enable_pii` at run time for a **local** multi-agent setup, the value propagates automatically to all subagents in the tree — unless a subagent has its own explicit `runtime_config` override.

```python
from glaip_sdk import Agent

sub_agent = Agent(name="data-agent", instruction="Retrieve customer data.")
root_agent = Agent(
    name="coordinator",
    instruction="Coordinate customer queries.",
    agents=[sub_agent],
)

# enable_pii=True is applied to root AND sub_agent (no per-agent override)
result = root_agent.run("Get details for Alice Johnson", enable_pii=True, local=True)
```

To give a specific subagent a different setting while keeping the run-level default for others, use `runtime_config` with the subagent as the key:

```python
# root runs with enable_pii=True; sub_agent runs with enable_pii=False
result = root_agent.run(
    "Get details for Alice Johnson",
    enable_pii=True,
    local=True,
    runtime_config={
        sub_agent: {"agent_config": {"enable_pii": False}},
    },
)
```

Propagation is recursive — it applies to every level of nesting, not just direct children. A subagent with its own `runtime_config` override keeps that setting, while its own children continue to inherit the run-level value.

#### Priority resolution summary

Effective `enable_pii` for each agent is resolved from highest to lowest:

1. `runtime_config[<agent>]["agent_config"]["enable_pii"]` — per-agent escape hatch (local) or `runtime_config[<uuid>]["agent_config"]["enable_pii"]` (remote)
2. `runtime_config["agent_config"]["enable_pii"]` — top-level runtime config (root agent only)
3. `enable_pii` passed to `agent.run()` / `agent.arun()` — per-run caller override
4. `agent.agent_config["enable_pii"]` — stored definition-time value
5. Runner default: `False`

{% hint style="warning" %}
`enable_pii` in `runtime_config["agent_config"]` (priority 2) wins over the per-run `enable_pii` parameter (priority 3). If both are set, the `runtime_config` value is used.
{% endhint %}

### GL Connectors Token

Use the `gl_connectors_token` parameter when your run can invoke tools or MCPs that require end-user auth via GL Connectors.

* **When required:** at least one reachable integration (tool or MCP) has `user_authentication=true` in its `tool_configs` or `mcp_configs`.
* **Execution scope:** per-run only; it is not stored in the deployed agent definition.
* **Local tool support:** in local mode, any named tool with `tool_configs[tool_name]["user_authentication"] = True` can receive the propagated token, including custom tools, not only `GLConnectorTool`.

**Python SDK**

```python
# Remote JSON run (agent must be deployed first)
remote_agent.deploy()

result = remote_agent.run(
    "Summarise my recent CRM activities",
    gl_connectors_token="<user-token>",
)

# Multipart run (with files)
result = client.agents.run_agent(
    remote_agent.id,
    "Review the attached report and sync notes",
    files=["/tmp/report.pdf"],
    gl_connectors_token="<user-token>",
)

# Local run
result = local_agent.run(
    "Summarise my recent CRM activities",
    local=True,
    gl_connectors_token="<user-token>",
)
```

**With a native tool (GL Connectors Tool):** use the concrete `aip_agents.tools` implementation in both modes; remote runs also require `deploy()`.

```python
# Remote execution
from glaip_sdk import Agent
from aip_agents.tools.gl_connector import GLConnectorTool

remote_agent = Agent(
    name="remote-agent",
    instruction="Search records and summarize highlights.",
    tools=[GLConnectorTool("google_drive_search_files_tool")],
    tool_configs={
        "google_drive_search_files_tool": {
            "user_authentication": True,
        }
    },
)
remote_agent.deploy()

result = remote_agent.run(
    "Search my records and summarize highlights",
    gl_connectors_token="<user-token>",
)
```

```python
# Local execution
from glaip_sdk import Agent
from aip_agents.tools.gl_connector import GLConnectorTool

local_agent = Agent(
    name="agent-local",
    instruction="Search records and summarize highlights.",
    tools=[GLConnectorTool("google_drive_search_files_tool")],
    tool_configs={
        "google_drive_search_files_tool": {
            "user_authentication": True,
        }
    },
)

local_result = local_agent.run(
    "Search my records and summarize highlights",
    local=True,
    gl_connectors_token="<user-token>",
)
```

**With a custom local tool:** local propagation also works for non-native tools as long as the tool has a stable name and its config enables `user_authentication`.

```python
from langchain_core.tools import BaseTool
from glaip_sdk import Agent


class CRMSearchTool(BaseTool):
    name: str = "crm_search_tool"
    description: str = "Search CRM records"

    def _run(self, query: str) -> str:
        return f"Searching CRM for: {query}"


local_agent = Agent(
    name="custom-tool-local",
    instruction="Search CRM records and summarize highlights.",
    tools=[CRMSearchTool()],
    tool_configs={
        "crm_search_tool": {
            "user_authentication": True,
        }
    },
)

local_result = local_agent.run(
    "Search my CRM records and summarize highlights",
    local=True,
    gl_connectors_token="<user-token>",
)
```

**With an MCP:** remote and local runs use different MCP construction patterns.

```python
# Remote execution
from glaip_sdk import Agent, MCP

remote_agent = Agent(
    name="crm-agent",
    instruction="Summarise CRM activities.",
    mcps=[MCP.from_native("crm_mcp")],
    mcp_configs={
        "crm_mcp": {
            "user_authentication": True,
        }
    },
)
remote_agent.deploy()

result = remote_agent.run(
    "Summarise my recent CRM activities",
    gl_connectors_token="<user-token>",
)
```

```python
# Local execution
from glaip_sdk import Agent, MCP

local_agent = Agent(
    name="crm-agent-local",
    instruction="Summarise CRM activities.",
    mcps=[
        MCP(
            name="crm_mcp",
            description="CRM MCP",
            transport="http",
            config={
                "url": "https://your-connector-host/crm/mcp",
                "authentication": {
                    "type": "bearer-token",
                    "token": "<stale-or-placeholder-token>",
                },
            },
        )
    ],
    mcp_configs={
        "crm_mcp": {
            "user_authentication": True,
        }
    },
)

local_result = local_agent.run(
    "Summarise my recent CRM activities",
    local=True,
    gl_connectors_token="<user-token>",
)
```

If the token is missing or invalid for required integrations:

* **Remote runs** can fail early with backend auth or precheck errors (for example `403` or `409`).
* **Local runs** raise an SDK error when an eligible `user_authentication: true` tool or MCP is missing both an explicit resource credential and the top-level token. Explicit resource credentials take precedence; otherwise invalid tokens fail naturally at the tool or MCP request boundary.

### Multi-Agent Patterns

Need a refresher? The [Multi-Agent System Patterns overview](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/tutorials/multi-agent-system-patterns) dives deep into hierarchies, routers, aggregators, and more. Use the snippet below as a quick starter.

**Python SDK**

```python
from glaip_sdk import Agent

coordinator = Agent(
    name="research-coordinator",
    instruction="Delegate research and compile final briefs.",
    agents=[researcher, analyst],
    agent_config={"tool_output_sharing": True},
)
```

**CLI**

```bash
aip \
  agents create --name research-coordinator --instruction "Delegate \
  research and compile final briefs." \
  --agents researcher \
  --agents analyst
```

See the [Multi-Agent System Patterns overview](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/tutorials/multi-agent-system-patterns) for topology-specific examples (hierarchical, router, aggregator, sequential, parallel).

### Iterate Quickly with Export and Import

**CLI**

```bash
aip agents get agent-123 --export agent.json
aip agents get agent-123 --export agent.yaml

aip agents create --import agent.json
```

**Python SDK**

```python
import json

agent = client.agents.get_agent_by_id("agent-123")
with open("agent-123.json", "w") as fh:
    fh.write(json.dumps(agent.sanitized_model_dump(exclude_none=True), indent=2, default=str))
```

Use `sanitized_model_dump()` for exports: it never includes model credentials or filesystem secret values. See [Serializing agents with models](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/language-models#serializing-agents-with-models) for the difference between `model_dump()` and `sanitized_model_dump()`.

### Iterate on Instructions Quickly

The CLI merges imports with flag overrides, so keep your definition in source control and loop quickly:

1. **Export the agent** — `aip agents get prod-research --export prod-research.json` captures the full payload (instruction, `tool_configs`, runtime defaults).
2. **Edit locally** — adjust instructions, swap `model` (symbolic for seeded, UUID for exact remote binding), or tighten tool settings. Commit the file so teammates can review changes.
3. **Re-import** — `aip agents update prod-research --import prod-research.json` applies the update immediately; any CLI flags you pass override the JSON.
4. **Validate** — run `aip agents run prod-research --view md` or `--view json` to confirm behaviour before moving to the next tweak.

Prefer IDs in scripts to avoid fuzzy matches, and branch your JSON when testing alternative prompts so you can compare diffs later. When you are ready to move between environments, follow the [Configuration management](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/configuration-management) for a full promotion checklist.

### Observability

#### Run History

Python SDK:

```python
from glaip_sdk import Client

client = Client()
runs = client.agents.runs.list_runs(agent_id="agent-123", limit=20, page=1)

successful = [r for r in runs.data if r.status == "success"]
for run in successful:
    print(run.id, run.status, run.created_at)
```

CLI (local transcript cache):

```bash
/transcripts
```

`/transcripts` opens the local transcript history; select a run in the browser to inspect details.

#### Debug Remote Runs (Interactive `/runs` + SDK Run Detail)

Use this when a deployed agent behaves unexpectedly (tool failures, timeouts, inconsistent outputs) and you need an audit trail you can share.

1. Trigger a remote run with a reproducible input.
2. Capture the run ID (it appears in the streaming metadata and in run history).
3. Inspect tool calls, errors, and final output from the run record.

CLI (interactive remote runs browser):

```bash
# Open the slash palette
aip
```

Inside the palette:

1. Run `/agents` and select the agent you want to debug.
2. Run `/runs` to browse that agent's remote run history.
3. Open a run to view the full transcript and export it if needed.

{% hint style="info" %}
Screenshot placeholder: `/runs` table view with a selected run, plus the run detail panel showing tool calls and final output.
{% endhint %}

Python SDK (fetch run output events):

```python
from glaip_sdk import Client

client = Client()
agent_id = "agent-123"

# Pick the most recent run (page 1 is typically newest-first).
runs = client.agents.runs.list_runs(agent_id=agent_id, limit=1, page=1)
run_id = str(runs.data[0].id)

run = client.agents.runs.get_run(agent_id=agent_id, run_id=run_id)
print("status:", run.status)

# Print tool calls captured in agent_step events (best-effort; payloads vary by tool/framework).
for ev in run.output:
    meta = ev.get("metadata") or {}
    if meta.get("kind") not in ("agent_step", "agent_thinking_step"):
        continue
    for call in meta.get("tool_calls") or []:
        print(call.get("name"), call.get("args"))
```

Common debugging patterns:

* If the run ends early, search `run.output` for `metadata.kind == "error"` or terminal events (`final_response`, `error`, `step_limit_exceeded`).
* If a tool is misbehaving, compare the tool call args from the run transcript against your expected schema and defaults (`tool_configs`).
* If a run is inconsistent, export the agent definition and diff it across environments, then re-run with identical inputs and runtime overrides.

#### Scheduling

Schedules run the same agent input on a recurring timetable in Asia/Jakarta (WIB). Create schedules with the SDK; CLI commands are on the roadmap. REST documentation exists as reference only in Resources.

In the SDK, you can provide a cron string (`minute hour day_of_month month day_of_week`) or a `ScheduleConfig` object. Unspecified fields default to `*` (every).

Example (Python SDK):

```python
from glaip_sdk import Client
from glaip_sdk.models.schedule import ScheduleConfig

client = Client()
agent = client.agents.get_agent_by_id("agent-123")

# Create a schedule via the agent facade
schedule = agent.schedule.create(
    input="Generate daily summary report",
    schedule=ScheduleConfig(
        minute="0",
        hour="9",
        day_of_week="0-4",  # Weekdays at 9am WIB (Mon-Fri)
    ),
)
print(f"Next run: {schedule.next_run_time}")

# List runs for this schedule
runs = agent.schedule.list_runs(schedule.id)
for run in runs:
    if run.status == "success":
        result = run.get_result()
        print(f"Run {run.id} completed in {run.duration}")
```

See the [Automation & scripting guide](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/automation-and-scripting#schedule-runs) for cron formats, full CRUD, and run history retrieval.

### Troubleshooting

| Issue                 | Symptoms                        | Resolution                                                                                                               |
| --------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Authentication errors | 401 responses                   | Re-run `aip accounts add <name>` + `aip accounts use <name>`, or update `Client(api_key=...)`.                           |
| Validation errors     | 422 responses                   | Check required fields with `aip agents create --help` or inspect error payloads.                                         |
| Resource not found    | 404 responses                   | Confirm IDs with `aip agents list` or `client.agents.list_agents()`.                                                     |
| Timeouts              | `AgentTimeoutError` or HTTP 504 | Check the deployed `agent_config.timeout_seconds` deadline and the separate SDK/CLI request guard; review schedule load. |

### Best Practices

1. **Scope instructions** — concise prompts improve output quality.
2. **Attach only necessary tools** — reduces attack surface and execution time.
3. **Reuse memory intentionally** — enable `mem0` when cross-run context adds value.
4. **Audit run history** — review recent runs via `client.agents.runs.list_runs(...)` and CLI transcripts for failure patterns.
5. **Sanitise secrets** — leverage `pii_mapping` and runtime MCP overrides to avoid persisting credentials.

### Related Documentation

* [Tools](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/tools) — manage native and custom tooling.
* [MCPs](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/mcps) — connect external systems and rotate credentials.
* [Language models](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/language-models) — configure models using provider/model format or Model class.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/automation-and-scripting) — orchestrate agents programmatically.
* [Multi-Agent System Patterns overview](https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/tutorials/multi-agent-system-patterns) — explore multi-agent coordination strategies.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://gdplabs.gitbook.io/sdk/gl-aip-ai-agent-package/guides/agents.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
