# Welcome to the GL SDK User's Guide!

**GL SDK (GDP Labs Software Development Kit)** is a modular platform for building and operating AI-driven applications made by GDP Labs.

It provides modular components, each focused on specific capabilities—from intelligent agents and natural language processing to computer vision, secure authentication, and advanced search.

Whether you are:

* building AI-powered products,
* integrating internal or external APIs, or
* experimenting with new AI capabilities,

We offer a unified, **production-ready foundation** to accelerate development while keeping systems maintainable and scalable.


# Introduction

GL SDK (GDP Labs Software Development Kit).

## About GL SDK

Welcome to the GL SDK (GDP Labs Software Development Kit)!

The **GL SDK (GDP Labs Software Development Kit)** is a comprehensive collection of tools, frameworks, and services designed to accelerate AI-driven application development at GDP Labs. It provides modular components, each focused on specific capabilities—from intelligent agents and natural language processing to computer vision, secure authentication, and advanced search.

Whether you’re building AI-powered applications, integrating specialized APIs, or exploring experimental platforms, the GL SDK brings everything into a unified ecosystem.


# Feature Overview

**Last update**: April 23, 2026.

The GL SDK is ✨ **ever-growing**, with ✨ **100+ features** available at your disposal. Find the highlights below, or consult the [detailed feature list](#detailed-features).

<figure><img src="/files/HZjoQibQv9lbCAMhqEUF" alt=""><figcaption></figcaption></figure>

## Highlights :book:

### ✨ [Anonymized Logging](/sdk/gl-observability/guides/logs)

Automatically **detect and mask personally identifiable information (PII)** across operations. This intelligent logging system ensures that **sensitive data such as names, email addresses, phone numbers, and other personal identifiers are automatically redacted** or tokenized before being stored in logs, significantly reducing the risk of data exposure if logging systems are compromised. Maintain detailed **operational visibility** for debugging, monitoring, and analytics while ensuring **compliance with privacy regulations and protecting user data integrity**.

### ✨ [GL AI Agents Package (AIP)](broken://pages/FHWJhfjGs2w6fEuqwYv9)

Build **tailored agent systems that adapt to your tools, models, execution patterns, and governance requirements**. Configure every part of an agent—from **instructions, memory, and model selection to tool/MCP integrations**, runtime overrides, streaming outputs, and artifact handling—within a unified orchestration layer powered by the REST API, Python SDK, and CLI. This flexibility delivers optimal performance and compliance while keeping development and operations simple and consistent.

### ✨ [Build End-to-End RAG Pipeline](/sdk/gen-ai-sdk/guides/build-end-to-end-rag-pipeline)

Craft **customized RAG (Retrieval-Augmented Generation) pipelines** that **adapt to their specific data sources, retrieval strategies, and generation requirements**. Rather than being locked into rigid, one-size-fits-all solutions, you can configure every component of the pipeline—from document chunking and embedding models to retrieval algorithms and LLM integrations. This flexibility ensures optimal performance for your unique use case while maintaining the simplicity of a unified orchestration framework.

### ✨ [GL Deep Researcher](/sdk/gl-deep-researcher/introduction)

**Go beyond quick answers**. Instead of relying on a single search, **explore a question from multiple angles, gather the most relevant information, and bring everything together into a clear, well-supported report**. The reports are designed to be comprehensive, detailed, and grounded in evidence—giving users not just an answer, but a full understanding of their topic.

### ✨ [Knowledge Graph](/sdk/gen-ai-sdk/tutorials/knowledge-graph)

Build intelligent **graph-based RAG systems that understand relationships between entities rather than treating documents as isolated chunks**. Instead of simple keyword matching, the Knowledge Graph SDK extracts entities, relationships, and hierarchical structures from content, creating interconnected knowledge representations that preserve semantic context and enable sophisticated reasoning across connected information. This approach transforms retrieval from basic similarity search into relationship-aware discovery that follows conceptual pathways through your data.

### ✨ [Realtime Session](/sdk/gen-ai-sdk/tutorials/inference/realtime-session)

Experience **seamless, natural conversations**, designed to deliver instant, **human-like spoken responses**. Perfect for voice agents and interactive applications, this low-latency solution transforms how users engage with AI by processing continuous audio streams for a truly dynamic and responsive interaction.

### ✨ [GL Smart Search](/sdk/gl-smart-search/getting-started)

Experience **a unified search** that connects results from the web and third-party applications such as Google Drive, Gmail, Google Calendar, and GitHub..

***

## Detailed Features :mag:

The ✨ **100+ features** has been organized into categories for easier viewing.

### ✨ [GL Connectors](/sdk/gl-connectors/gl-connectors)

1. [Skills](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/connectors-skills)
2. [Tools](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/tools)

Refer to [Model Context Protocol](/sdk/gl-connectors/sdk/agentic-tools-and-model-context-protocol-mcp) for a comprehensive documentation and list!

1. Github
2. Twitter / X
3. Google Docs
4. Gmail
5. Google Calendar
6. Google Meet\*
7. Google Sheets
8. Slack
9. SQL
10. Hackernews
11. Microsoft Calendar
12. Microsoft OneDrive
13. Microsoft Outlook
14. Microsoft Teams
15. Microsoft Sharepoint
16. ...and more!

### ✨[GL Deep Researcher](/sdk/gl-deep-researcher/introduction)

1. ✨ [Deep Research](/sdk/gl-deep-researcher/introduction)

### ✨[GL Identity and Access Management](/sdk/gl-identity-and-access-management/introduction-to-gl-iam)

1. [Pluggable Auth Providers](/sdk/gl-identity-and-access-management/tutorials/traditional-iam/enterprise-protocols/ldap-authentication)
2. ✨ [Agent IAM & Delegation](/sdk/gl-identity-and-access-management/tutorials/agent-iam)
3. [Access Control](/sdk/gl-identity-and-access-management/tutorials/traditional-iam/dpop)

### ✨[GL Observability](/sdk/gl-observability/observability)

1. ✨ [Anonymized Logging](/sdk/gl-observability/guides/logs)
2. [Open Telemetry](/sdk/gl-observability/observability)

### ✨[GL Smart Crawl](/sdk/gl-smart-crawl/introduction)

1. [Crawler Article from Multiple Sources](https://gdplabs.gitbook.io/sdk/gl-smart-crawl/resources/developer-reference/smart-scrape/scrapers/article-scrapers)
2. [Crawler Property from Multiple Sources](https://gdplabs.gitbook.io/sdk/gl-smart-crawl/resources/developer-reference/smart-scrape/scrapers/property-scrapers)

### ✨[GL Smart Search](/sdk/gl-smart-search/introduction)

1. [Connector Search](/sdk/gl-smart-search/guides/sdk/connector-search)
2. [Site Discovery](https://gdplabs.gitbook.io/sdk/gl-smart-search/guides/sdk/web-search#id-4.-map-a-website)
3. [Structured Data Web Content Extraction](https://gdplabs.gitbook.io/sdk/gl-smart-search/guides/sdk/web-search#id-6.1-extract-snippets-with-json-schema)
4. [Web Search](/sdk/gl-smart-search/guides/sdk/web-search)

### ✨[Multimodal](/sdk/gen-ai-sdk/tutorials/multimodality)

1. [Image-to-text Modality Converter](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/multimodality/modality-converter/image-to-text-converter)
2. [Audio-to-text Modality Converter](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/multimodality/modality-converter/audio-to-text-converter)
3. [Video-to-text Modality Converter](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/multimodality/modality-converter/video-to-caption)
4. [Image Modality Transformer](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/multimodality/modality-transformer/image-modality-transformer)

### ✨[GL AI Agents Package (AIP)](broken://pages/FHWJhfjGs2w6fEuqwYv9)

1. [Audio Interface](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/audio-interface)
2. [Filesystem](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agent-filesystem)
3. [Human-in-the-loop (HITL)](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/human-in-the-loop-approvals)
4. ✨ [Multi-Agent Execution](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns)
5. [Programmatic Tool Calling (PTC)](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/programmatic-tool-calling)
6. [Skills](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/skills)

### ✨[Knowledge Graph](/sdk/gen-ai-sdk/tutorials/knowledge-graph)

1. ✨ [Text-to-Graph](/sdk/gen-ai-sdk/tutorials/knowledge-graph/text-to-graph)
2. [Graph Data Store](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/knowledge-graph/graph-data-store)
3. [GraphRAG Indexer](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/document-processing-orchestrator/indexer/graph-rag)
4. [GraphRAG Retriever](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/knowledge-graph/graph-retriever)

### ✨[GL Meemo](/sdk/gl-meemo/introduction-to-meemo)

1. [Meeting Bot](/sdk/gl-meemo/tutorials/meetings)
2. [Transcription](https://gdplabs.gitbook.io/sdk/gl-meemo/introduction-to-meemo)
3. [Summarization](https://gdplabs.gitbook.io/sdk/gl-meemo/introduction-to-meemo)
4. [Calendar Integration](https://gdplabs.gitbook.io/sdk/gl-meemo/introduction-to-meemo)

### ✨[GL Speech](/sdk/gl-speech/introduction-to-gl-speech)

1. [Speech-to-Text](/sdk/gl-speech/rest-api-reference/speech-to-text)
2. [Text-to-Speech](/sdk/gl-speech/rest-api-reference/text-to-speech)

### ✨[Computer Vision](/sdk/computer-vision/introduction)

#### OCR

1. [e-KYC](https://docs.glair.ai/vision#e-kyc)
2. [Paperless/Document Intelligence](https://docs.glair.ai/vision/general-document)

#### Retail Execution & Planogram

1. [Retail Execution & Planogram](https://docs.glair.ai/vision/retail/kpi/osa)

#### Identity Verification & Face Verification

1. [Identity Verification & Face Verification](https://gdplabs.gitbook.io/sdk/computer-vision/introduction-to-computer-vision)

#### Face Biometric

1. [Passive Liveness Detection](https://docs.glair.ai/vision/passive-liveness)
2. [Active Liveness Detection](https://docs.glair.ai/vision/active-liveness)
3. [Deepfake Detection](https://docs.glair.ai/vision/deepfake)
4. [Face Verification](https://docs.glair.ai/vision/identity-face-verification)

### ✨[NLP](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/security-and-privacy/pii-masking)

1. [Named-Entity Recognition (NER)-based Privacy](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/security-and-privacy/pii-masking)

### ✨Security

1. Data at Rest
2. Data in Transit / Data in Motion
3. Key Management
4. Data Classification

### ✨[Common Modules](/sdk/common-modules/introduction-to-common-modules)

1. [Plugin](https://gdplabs.gitbook.io/sdk/common-modules/tutorials/plugin)
2. [Internationalization](https://gdplabs.gitbook.io/sdk/common-modules/tutorials/internationalization)
3. [Code Interpreter](https://gdplabs.gitbook.io/sdk/common-modules/guides/code-interpreter-usage-guide)

### ✨[Generative AI](/sdk/gen-ai-sdk/introduction-to-gen-ai-sdk)

1. [Core (Component, Event Emitter, Tool, etc.)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/core)
2. [Inference (LLM/SLM, Embedding, & Realtime: OpenAI, Anthropic, Google, xAI, etc.)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/inference)
3. [Data Store (ES, OS, Chroma, Redis, SQL, etc.)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/data-store)
4. [Retrieval (Vector, Hybrid, Hierarchical, etc.)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/retrieval)
5. [Generation (Synthesizer, Citations, Context Enricher, etc.)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/generation)
6. [Orchestration (Routing & Pipeline Orchestration)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/orchestration)
7. [Document Processing (Chunker, Indexer, DPO Router, etc.)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/document-processing-orchestrator)
8. [Evaluation (GEval, RAGAS, DeepEval)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/evaluation)
9. [Security & Privacy (Guardrails, PII Masking)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/security-and-privacy)
10. [Memory (Chat history, memory management)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/memory)
11. [Fine-tuning (SFT, DPO, GRPO)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/fine-tuning)
12. [Cache (Eviction Manager, Eviction Strategy)](https://gdplabs.gitbook.io/sdk/gen-ai-sdk/tutorials/data-store/cache)

## Why GL SDK? :question:

Unlock your full potential in the AI era. The GL SDK provides the foundation you need to build groundbreaking applications without compromise.

1. **Low Code:** Achieve complex AI tasks in as few as five lines of code, drastically accelerating development and reducing errors.
2. **Simple, But Flexible:** Offers straightforward solutions without sacrificing the granular control needed for advanced use cases.
3. **Low Maintenance:** We handle all the underlying open-source dependency management, updates, and compatibility, so your applications simply "just work."
4. **One-Stop Shop:** The GL SDK provides a comprehensive, integrated solution for building production-ready AI applications.
5. **Designed with Developer Experience in Mind:** Meticulously crafted for intuitive use, quickly making beginners productive.

{% hint style="success" %}
**Learn more about GL SDK's advantages** [**here**](/sdk/overview/why-gl-sdk)**.**
{% endhint %}


# Detailed Features

**Last update**: October 29, 2025.

The GL SDK is ever-growing, with✨ **100+ features** available at your disposal. We have organized them into categories for your easier viewing.

## [GL Plugins](/sdk/common-modules/tutorials/plugin)

1. [Plugin](/sdk/common-modules/tutorials/plugin)

## [Broken mention](broken://pages/A2YFoQ4N2x1TWWoyHz4e)

1. ✨ [Connectors](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector)
   1. [Github](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   2. [Twitter / X](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   3. [Google Docs](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   4. [Gmail](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   5. [Google Calendar](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   6. Google Meet\*
   7. [Google Sheets](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   8. [Slack](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   9. [SQL](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   10. [Hackernews](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   11. [Microsoft Calendar](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   12. [Microsoft OneDrive](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   13. [Microsoft Outlook](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   14. [Microsoft Teams](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)
   15. [Microsoft Sharepoint](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp#available-connectors)

## [GL Observability](/sdk/gl-observability/observability)

1. ✨ [Anonymized Logging](https://gl-docs.gitbook.io/bosa/bosa-sdk/bosa-core-sdk/logger)
2. [Sentry](https://gl-docs.gitbook.io/bosa/bosa-sdk/bosa-core-sdk/telemetry#sentry-integration)
3. [Langfuse](https://gl-docs.gitbook.io/bosa/bosa-sdk/bosa-core-sdk/telemetry#choose-your-telemetry-setup)
4. [Prometheus](https://gl-docs.gitbook.io/bosa/bosa-sdk/bosa-core-sdk/telemetry#choose-your-telemetry-setup)
5. [ELK](https://gl-docs.gitbook.io/bosa/bosa-sdk/bosa-core-sdk/telemetry#choose-your-telemetry-setup)
6. [Open Telemetry](https://gl-docs.gitbook.io/bosa/bosa-sdk/bosa-core-sdk/telemetry#opentelemetry-integration)

## [MCP](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp)

1. ✨ [Server Templates](https://github.com/GDP-ADMIN/gl-mcp)
2. [Curated Servers List](https://github.com/GDP-ADMIN/gl-mcp)
3. [STDIO-Streamable HTTP Proxy](https://github.com/GDP-ADMIN/gl-mcp?tab=readme-ov-file#stdio)
4. ✨ [MCP Client](https://gl-docs.gitbook.io/bosa/bosa-platform/bosa-connector/mcp?q=Server+Temp#programmatic-usage)
5. STDIO MCP Manager\*

## [Smart Search](/sdk/gl-smart-search/introduction)

1. [Web Search](/sdk/gl-smart-search/guides/sdk/web-search)
2. [Search with Connectors](/sdk/gl-smart-search/guides/sdk/connector-search)

## [Deep Research](https://gl-docs.gitbook.io/smartsearch/smart-search-sdk/deep-research)

1. ✨ [Deep Research](https://gl-docs.gitbook.io/smartsearch/smart-search-sdk/deep-research)

## [NLP](broken://pages/urNHRxKVQ89EYWiuDdny)

1. [Named-Entity Recognition (NER)](broken://pages/uiBmEuCvoCd0So69k83V)

## [Speech](broken://pages/9lNi0DEUIGsvqwY6sB3z)

1. [Speech-to-Text](broken://pages/9lNi0DEUIGsvqwY6sB3z)
2. [Text-to-Speech](broken://pages/9lNi0DEUIGsvqwY6sB3z)

## [Computer Vision](https://docs.glair.ai/vision)

### OCR

1. [e-KYC](https://docs.glair.ai/vision#e-kyc)
2. [Paperless/Document Intelligence](https://docs.glair.ai/vision/general-document)
3. [Image Quality Detector](https://docs.glair.ai/vision/qualities)

### Face Detection

1. [Passive Liveness Detection](https://docs.glair.ai/vision/passive-liveness)
2. [Active Liveness Detection](https://docs.glair.ai/vision/active-liveness)
3. [Deepfake Detection](https://docs.glair.ai/vision/deepfake)
4. [Face Verification](https://docs.glair.ai/vision/identity-face-verification)

### Retail Execution

1. [Retail Execution](https://docs.glair.ai/vision/retail/kpi/osa)

## [Machine Learning](https://github.com/GDP-ADMIN/glance/wiki)

1. [Data Ingestion (ETL)](https://github.com/GDP-ADMIN/glance/wiki/Transform-Pandas)
2. Auto Feature Engineering \*
3. ✨ [Anomaly Detection](https://github.com/GDP-ADMIN/glance/wiki/Glance-PyOD)
4. [Forecasting](https://github.com/GDP-ADMIN/glance/wiki/Glance-Nixtla)
5. Evaluation\*
6. Data Quality Validation\*
7. [Model Explainability](https://github.com/GDP-ADMIN/glance/wiki/Glance-SHAP)

## [Zero-Knowledge Proof](https://gl-docs.gitbook.io/zkpass/)

1. [zkPass - Data Verification Request](https://gl-docs.gitbook.io/zkpass/zkpass-developers-guide/zkpass-modules/dvr/dvr-query)

## [Generative AI](https://gdplabs.gitbook.io/sdk/gen-ai-sdk-overview/getting-started)

### [Data Ingestion](/sdk/gen-ai-sdk/tutorials/document-processing-orchestrator) and [Storage](/sdk/gen-ai-sdk/tutorials/data-store)

1. [Document Processing](/sdk/gen-ai-sdk/tutorials/document-processing-orchestrator)
   1. ✨ [Documents (DOCX, PDF, PPTX, XLSX)](/sdk/gen-ai-sdk/resources/supported-documents#document)
   2. [Plain text (TXT, HTML, Python, JS, etc.)](/sdk/gen-ai-sdk/resources/supported-documents#plain-text)
   3. [Audio](/sdk/gen-ai-sdk/resources/supported-documents#audio)
   4. [Images](/sdk/gen-ai-sdk/resources/supported-documents#image)
   5. [YouTube Videos](/sdk/gen-ai-sdk/resources/supported-documents#url)
2. [Embedding](/sdk/gen-ai-sdk/tutorials/inference/em-invoker)
   1. [Azure](/sdk/gen-ai-sdk/resources/supported-models#azure-openai-1)
   2. [Google](/sdk/gen-ai-sdk/resources/supported-models#google-vertex-ai-1)
   3. Jina\*
   4. [OpenAI](/sdk/gen-ai-sdk/resources/supported-models#openai-1)
   5. [TwelveLabs](/sdk/gen-ai-sdk/resources/supported-models#twelvelabs)
   6. [Voyage](/sdk/gen-ai-sdk/resources/supported-models#voyage)
3. [Vector Store](/sdk/gen-ai-sdk/tutorials/data-store/legacy/vector-data-store)
   1. [Chroma](/sdk/gen-ai-sdk/resources/supported-vector-data-store)
   2. [Elasticsearch](/sdk/gen-ai-sdk/resources/supported-vector-data-store)

### [LLM/SLM Inference](/sdk/gen-ai-sdk/tutorials/inference/lm-invoker)

1. [Anthropic](/sdk/gen-ai-sdk/resources/supported-models#anthropic)
2. [Azure](/sdk/gen-ai-sdk/resources/supported-models#azure-openai)
3. [Bedrock](/sdk/gen-ai-sdk/resources/supported-models#bedrock)
4. [Google](/sdk/gen-ai-sdk/resources/supported-models#google-vertex-ai)
5. [HuggingFace](/sdk/gen-ai-sdk/resources/supported-models#langchain)
6. [Langchain](/sdk/gen-ai-sdk/resources/supported-models#langchain)
7. [LiteLLM](/sdk/gen-ai-sdk/resources/supported-models#litellm)
8. [OpenAI](/sdk/gen-ai-sdk/resources/supported-models#openai)
9. [xAI (Grok)](/sdk/gen-ai-sdk/resources/supported-models#xai)
10. [Open Models](/sdk/gen-ai-sdk/resources/supported-models#openai-chat-completions)
    1. [Deepseek](/sdk/gen-ai-sdk/resources/supported-models#openai-chat-completions)
    2. [GLM](/sdk/gen-ai-sdk/resources/supported-models#openai-chat-completions)
    3. [GPT-OSS](/sdk/gen-ai-sdk/resources/supported-models#openai-chat-completions)
    4. [Kimi](/sdk/gen-ai-sdk/resources/supported-models#openai-chat-completions)
    5. [Llama](/sdk/gen-ai-sdk/resources/supported-models#openai-chat-completions)
    6. [Mistral](/sdk/gen-ai-sdk/resources/supported-models#openai-chat-completions)
    7. [Qwen](/sdk/gen-ai-sdk/resources/supported-models#openai-chat-completions)
11. ✨ [Live/Realtime Chat](/sdk/gen-ai-sdk/tutorials/inference/realtime-session)

### [RAG](/sdk/gen-ai-sdk/guides/introduction-to-rag)

1. [Semantic Routing](/sdk/gen-ai-sdk/tutorials/orchestration/routing)
2. [Query Transformation](/sdk/gen-ai-sdk/tutorials/retrieval/query-transformer)
3. [Retrieval](/sdk/gen-ai-sdk/tutorials/retrieval/retriever)
4. [Reranking](/sdk/gen-ai-sdk/tutorials/retrieval/reranker)
5. [Context Enrichment](/sdk/gen-ai-sdk/tutorials/generation/context-enricher)
6. [Compression](/sdk/gen-ai-sdk/tutorials/generation/compressor)
7. [Reference Formatting](/sdk/gen-ai-sdk/tutorials/generation/reference-formatter)
8. [Response Synthesis/Generation](/sdk/gen-ai-sdk/tutorials/generation/response-synthesizer)
9. [Caching](/sdk/gen-ai-sdk/guides/build-end-to-end-rag-pipeline/caching)
10. [Orchestration (Pipeline)](/sdk/gen-ai-sdk/tutorials/orchestration/pipeline)

### [Memory](/sdk/gen-ai-sdk/tutorials/memory)

1. [Conversation History](/sdk/gen-ai-sdk/tutorials/memory/chat-history-manager)
2. ✨ [Long-Term Memory](/sdk/gen-ai-sdk/tutorials/memory/long-term-memory)

### [Evaluation](/sdk/gen-ai-sdk/tutorials/evaluation) & [Fine-tuning](/sdk/gen-ai-sdk/tutorials/fine-tuning)

1. [Evaluation](/sdk/gen-ai-sdk/tutorials/evaluation)
   1. ✨ [Evaluators](/sdk/gen-ai-sdk/tutorials/evaluation/evaluator)
      1. [GEval](/sdk/gen-ai-sdk/tutorials/evaluation/evaluator#gevalgenerationevaluator)
      2. [Retrieval](/sdk/gen-ai-sdk/tutorials/evaluation/evaluator#classicalretrievalevaluator)
      3. [Agent Trajectory](/sdk/gen-ai-sdk/tutorials/evaluation/evaluator#agentevaluator)
      4. [LLM-as-a-judge](/sdk/gen-ai-sdk/tutorials/evaluation/evaluator)
   2. [Metrics](/sdk/gen-ai-sdk/tutorials/evaluation/metric)
      1. [DeepEval](/sdk/gen-ai-sdk/tutorials/evaluation/metric#available-metrics)
      2. [RAGAS](/sdk/gen-ai-sdk/tutorials/evaluation/metric#available-metrics)
      3. [LangChain](/sdk/gen-ai-sdk/tutorials/evaluation/metric#available-metrics)
2. [Fine-tuning](/sdk/gen-ai-sdk/tutorials/fine-tuning/supervised-fine-tuning-sft)

### [Security & Privacy](/sdk/gen-ai-sdk/tutorials/security-and-privacy)

1. ✨ [Guardrail](/sdk/gen-ai-sdk/tutorials/security-and-privacy/guardrail)
2. ✨ [PII Masking](/sdk/gen-ai-sdk/tutorials/security-and-privacy/pii-masking)

### [Multimodality](/sdk/gen-ai-sdk/tutorials/multimodality)

1. [Audio to Text](/sdk/gen-ai-sdk/tutorials/multimodality/modality-converter/audio-to-text-converter)
2. [Image to Text](/sdk/gen-ai-sdk/tutorials/multimodality/modality-converter/image-to-text-converter)
3. [Video to Text](broken://pages/ixA7KX4FzH4tc6Ko2YcR)

## [Knowledge Graph](/sdk/gen-ai-sdk/tutorials/knowledge-graph)

1. ✨ [Graph DB](/sdk/gen-ai-sdk/tutorials/knowledge-graph/graph-data-store)
   1. [Neo4j](/sdk/gen-ai-sdk/tutorials/knowledge-graph/graph-data-store#available-implementations)
   2. [Nebula](/sdk/gen-ai-sdk/tutorials/knowledge-graph/graph-data-store#available-implementations)
2. ✨ [Graph RAG](/sdk/gen-ai-sdk/tutorials/knowledge-graph/graph-retriever)
3. ✨ [Text-to-Graph](/sdk/gen-ai-sdk/tutorials/knowledge-graph/text-to-graph)
4. [Subgraph Traversal](/sdk/gen-ai-sdk/tutorials/knowledge-graph/graph-data-store#graph-traversal)

## [AI Agents Package (AIP)](https://gdplabs.gitbook.io/sdk/gl-aip/)

1. [Agent Management](https://gdplabs.gitbook.io/sdk/gl-aip/guides/agents-guide)
2. [A2A](https://gdplabs.gitbook.io/sdk/gl-aip/resources/reference/schemas/agents#a2a-profile-structure)
3. ✨ [Multi-Agent Execution](https://gdplabs.gitbook.io/sdk/gl-aip/tutorials/multi-agent-system-patterns)
4. ✨ [Multi-framework support](https://gdplabs.gitbook.io/sdk/gl-aip/resources/reference/schemas/agents#agent-frameworks)
   1. [LangGraph/LangChain](https://gdplabs.gitbook.io/sdk/gl-aip/resources/reference/schemas/agents#agent-frameworks)
   2. [Google ADK](https://gdplabs.gitbook.io/sdk/gl-aip/resources/reference/schemas/agents#agent-frameworks)
   3. [Langflow](https://gdplabs.gitbook.io/sdk/gl-aip/resources/reference/schemas/agents#agent-frameworks)
5. [Tools Registry](https://gdplabs.gitbook.io/sdk/gl-aip/guides/tools-guide)
6. [Custom Tools](https://gdplabs.gitbook.io/sdk/gl-aip/guides/tools-guide)
7. [MCP Support](https://gdplabs.gitbook.io/sdk/gl-aip/guides/mcps-guide)
8. [Scheduling](https://gdplabs.gitbook.io/sdk/gl-aip/guides/automation-and-scripting#schedule-runs)

## [Cryptography](/sdk/common-modules/tutorials/cryptography)

1. [AES-256](/sdk/common-modules/tutorials/cryptography)
2. [AES-GCM](/sdk/common-modules/tutorials/cryptography)
3. [AES-256-GCM](/sdk/common-modules/tutorials/cryptography)
4. [Ed25519](/sdk/common-modules/tutorials/cryptography)
5. Post-quantum cryptography\*

## [Internationalization (i18n/l10n)](/sdk/common-modules/tutorials/internationalization)

1. [Language Detection](/sdk/common-modules/tutorials/internationalization/language-detection)
2. [Text Normalization](/sdk/common-modules/tutorials/internationalization/text-normalization)
3. [Transliteration](/sdk/common-modules/tutorials/internationalization/transliteration)
4. [Translation](/sdk/common-modules/tutorials/internationalization/translation)

*\*Coming soon*


# Component List

**Last update**: November 17, 2025.

The GL SDK is ✨ **ever-growing**, with ✨ **50+ types of components** available at your disposal. Please find the complete list below:

## AI Agents Package

Useful for building dynamic agents.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://gdplabs.gitbook.io/sdk/gl-aip/resources/reference/python-sdk">Python SDK</a></td><td>Python client library for building and managing AI agents, tools, and connections with session-aware support aligned to the FastAPI backend.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/gl-aip/resources/reference/cli-commands">CLI Commands</a></td><td>Command-line interface that enables users to manage agents, tools, and MCP connections without writing code.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/gl-aip/resources/reference/rest-api">REST API</a></td><td>Backend interface for managing agents, tools, MCP connections, language models, accounts, and utilities.</td></tr></tbody></table>

## Document Processing

Useful for processing raw documents into a useable knowledge.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/document-processing-orchestrator/downloader">Downloader</a></td><td>Downloads data from a designated source.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/document-processing-orchestrator/loader">Loader</a></td><td>Loads data content.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/document-processing-orchestrator/parser">Parser</a></td><td>Parses data into a structured format.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/document-processing-orchestrator/chunker">Chunker</a></td><td>Chunks data with certain strategy.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/document-processing-orchestrator/data-generator">Data Generator</a></td><td>Generates additional information for the data.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/document-processing-orchestrator/indexer">Indexer</a></td><td>Indexes data into data stores.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/document-processing-orchestrator/dpo-router">DPO Router</a></td><td>Routes data to determines processing paths.</td></tr></tbody></table>

## Evaluator

Useful for performing evaluation of certain modules.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="/pages/Jg3TMWIR8um3ZInRY9MK">End-to-End Evaluation</a></td><td>Orchestrates the entire evaluation process, from data loading to result tracking, in a single function call.</td></tr><tr><td><a href="/pages/rsGxveQ1gKU4KpNimevZ">Evaluator / Scorer</a></td><td>Evaluates modules using certain metrics.</td></tr><tr><td><a href="/pages/PlXbJdtNAaq67oseSjwK">Metric</a></td><td>Measures and assesses the performance of language models.</td></tr><tr><td><a href="/pages/3kL86rcc2mUKTLRDAGdq">Dataset</a></td><td>It provides a standardized interface to load data, iterate through them, and expose them in a consistent format.</td></tr><tr><td><a href="/pages/7el4jr1Am9Wfr5eCmh9j">Experiment Tracker</a></td><td>It logs model inputs/outputs, evaluation scores, configuration parameters, timestamps, and aggregated results to compare runs, reproduce them, and monitor performance changes over time.</td></tr></tbody></table>

## Fine-Tuning

Useful for fine-tuning models.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/fine-tuning/supervised-fine-tuning-sft">SFT Trainer</a></td><td>Manages Supervised Fine-Tuning (SFT) life-cycle.</td></tr><tr><td><a href="/pages/xOipibfNiifFsq3yJS4e">GRPO Trainer</a></td><td>Manages Group Relative Policy Optimization (GRPO) life-cycle.</td></tr></tbody></table>

## i18n/l10n

Useful for implementing i18n (internationalization) & l10n (localization).

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/internationalization/language-detection">Language Detector</a></td><td>Detects the language of a text.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/internationalization/text-normalization">Text Normalizer</a></td><td>Normalizes text into a standard, canonical form.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/internationalization/transliteration">Transliterator</a></td><td>Converts text between writing systems.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/internationalization/translation">Translator</a></td><td>Translates text between languages.</td></tr></tbody></table>

## Model Context Protocol

Useful for working with MCP (Model Context Protocol)s.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="/pages/VjJis4uyaH3URa6bDnxX">MCP Client</a></td><td>GDP Labs' in-house MCP Client, framework-agnostic and adaptable to other agentic frameworks.</td></tr><tr><td><a href="/pages/A2YFoQ4N2x1TWWoyHz4e">GL Connector</a></td><td>GDP Labs' maintained Connectors for third party applications.</td></tr></tbody></table>

## Multimodality

Useful for working with multimodal data.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="/pages/f2XmG3X1UcZ3ubqWxpsb">Modality Converter</a></td><td>Transform data from one modality to another (e.g., audio → text, image → text, video → text).</td></tr><tr><td><a href="/pages/ixA7KX4FzH4tc6Ko2YcR">Video to Caption Converter</a></td><td>Converts video files into natural language captions using multimodal language models, suitable for search, RAG, or analytics workflows.</td></tr><tr><td><a href="/pages/558fggmJn7PfmaVykmf0">Modality Transformer</a></td><td>Wrapper <code>Component</code> that transform an input modality into other modalities using one or more modality converters.</td></tr></tbody></table>

## Retrieval-Augmented Generation

Useful for building dynamic Retrieval-Augmented Generation (RAG) pipelines.

### Core

Useful for managing shared functionality across the RAG components.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="/pages/xS5r5RV7eoeeged3Btau">Component</a></td><td>Basic executable unit; foundation of all Gen AI components.</td></tr><tr><td><a href="/pages/aaK2Bo8j2W6kxPktA1yO">Tool</a></td><td>MCP-style schema to provide functionalities to an AI agent.</td></tr><tr><td><a href="/pages/guVqO5CGpNwf99T9zKin">Logger Manager</a></td><td>Manages logging across Gen AI apps.</td></tr><tr><td><a href="/pages/Tf9l3fQNrBpudaMMDJzW">Event Emitter</a></td><td>Manages event emitting (including streaming) across Gen AI apps.</td></tr></tbody></table>

### Inference

Useful for managing model inferences.

<table><thead><tr><th width="205.4019775390625">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/inference/em-invoker">EM Invoker</a></td><td>Invokes embedding models.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/inference/lm-invoker">LM Invoker</a></td><td>Invokes language models.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/inference/prompt-builder">Prompt Builder</a></td><td>Manages prompts as language models inputs.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/inference/output-parser">Output Parser</a></td><td>Parses language model outputs.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/inference/lm-request-processor">LM Request Processor</a></td><td>Orchestrates language model invocation end-to-end process, which includes prompt building, invocation, and output parsing.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/inference/realtime-chat">[BETA] Realtime Chat</a></td><td>Interacts with language models in realtime.</td></tr></tbody></table>

### Data Store

Useful for managing data stores.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/data-store">Data Store</a></td><td>Stores data for knowledge management.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/data-store/cache-manager">Cache</a></td><td>Enables caching management using data stores.</td></tr></tbody></table>

### Retrieval

Useful for managing knowledge retrieval.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/retrieval/query-transformer">Query Transformer</a></td><td>Transforms query to improve retrieval.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/retrieval/retrieval-parameter-extractor">Retrieval Parameter Extractor</a></td><td>Extracts retrieval parameters from query.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/retrieval/retriever">Retriever</a></td><td>Retrieves knowledge from a designated source.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/retrieval/chunk-processor">Chunk Processor</a></td><td>Transforms retrieved chunks.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/retrieval/reranker">Reranker</a></td><td>Reranks retrieved chunks.</td></tr></tbody></table>

### Generation

Useful for managing response generation.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/generation/context-enricher">Context Enricher</a></td><td>Enriches chunks with additional information.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/generation/relevance-filter">Relevance Filter</a></td><td>Filters chunks based on relevance.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/generation/repacker">Repacker</a></td><td>Repacks chunks as a context.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/generation/compressor">Compressor</a></td><td>Compresses context for compacity.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/generation/response-synthesizer">Response Synthesizer</a></td><td>Synthesizes response based on provided inputs.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/generation/reference-formatter">Reference Formatter</a></td><td>Manages reference formatting based on the response.</td></tr></tbody></table>

### Memory

Useful for managing memory.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/memory/chat-history-manager">Chat History Manager</a></td><td>Manages chat history.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/memory/long-term-memory">Memory Manager</a></td><td>Manages memory.</td></tr></tbody></table>

### Pipeline

Useful for managing pipeline building process.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/orchestration/pipeline">Pipeline</a></td><td>Orchestrates RAG components as pipelines.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/orchestration/steps">Step</a></td><td>Manages various step behavior in a pipeline.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/orchestration/routing">Router</a></td><td>Routes inputs into the most appropriate output.</td></tr><tr><td><a href="https://gdplabs.gitbook.io/sdk/tutorials/orchestration/composer">[BETA] Composer</a></td><td>Builds pipeline with builder patterns.</td></tr></tbody></table>

## Security & Privacy

Useful for managing security & privacy.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="/pages/KvSFiikDatimpCsjfbUQ">Guardrail</a></td><td>Manages content filtering and safety checks.</td></tr><tr><td><a href="/pages/m2vkD0WGIYoeX6RWUc56">PII Anonymizer</a></td><td>Anonymizes PII (Personal Identifiable Information) data.</td></tr></tbody></table>

## Smart Search

Useful for performing smart knowledge retrievals.

<table><thead><tr><th width="209.3819580078125">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="/pages/PImsyobdxO9Wq11a97lc">Web Search</a></td><td>The <strong>Web Search</strong> module enables you to perform searches across the web, retrieve URLs, fetch page content, and extract structured insights such as snippets or keypoints.</td></tr><tr><td><a href="/pages/FqVkzmQAD91AtfoGLaRz">Connector Search</a></td><td>The <strong>Connector</strong> capability lets Smart Search access third-party data sources such as <strong>Google Drive</strong>, <strong>Google Mail</strong>, <strong>Google Calendar</strong>, and <strong>GitHub</strong>.</td></tr></tbody></table>

## Why GL SDK? :question:

Unlock your full potential in the AI era. The GL SDK provides the foundation you need to build groundbreaking applications without compromise.

1. **Low Code:** Achieve complex AI tasks in as few as five lines of code, drastically accelerating development and reducing errors.
2. **Simple, But Flexible:** Offers straightforward solutions without sacrificing the granular control needed for advanced use cases.
3. **Low Maintenance:** We handle all the underlying open-source dependency management, updates, and compatibility, so your applications simply "just work."
4. **One-Stop Shop:** The GL SDK provides a comprehensive, integrated solution for building production-ready AI applications.
5. **Designed with Developer Experience in Mind:** Meticulously crafted for intuitive use, quickly making beginners productive.

{% hint style="success" %}
**Learn more about GL SDK's advantages** [**here**](/sdk/overview/why-gl-sdk)**.**
{% endhint %}


# Why GL SDK?

In the rapidly evolving landscape of AI development, choosing the right tools can make all the difference between rapid innovation and getting bogged down in complexity. The GL SDK stands out by offering a unique blend of power, simplicity, and unparalleled developer experience, especially when compared to traditional open-source alternatives.

1. **Low Code:** Achieve complex AI tasks in as few as **five lines of code**, drastically **accelerating development and reducing errors**. This principle ensures rapid iteration and a focus on innovation over boilerplate.
2. **Simple, But Flexible:** The SDK offers **straightforward solutions for common tasks** without sacrificing the **granular control** needed for **advanced use cases or customization**. You get both ease of use and the power to adapt to any requirement.
3. **Low Maintenance:** We handle all the **underlying open-source dependency management, updates, and compatibility,** so you gain stability, security, and the latest advancements without the usual headaches. **Your applications simply "just work."**
4. **One-Stop Shop:** The GL SDK provides a **comprehensive, integrated solution for building production-ready** AI applications across the entire development lifecycle. This **eliminates the need to stitch together disparate tools**, streamlining your workflow significantly.
5. **Designed with Developer Experience in Mind:** Meticulously crafted for intuitive use, the SDK combines **clear documentation and tutorials with its low-code approach**, quickly making beginners productive. It’s powerful, yet a joy to use.

## Low Code

The GL SDK adheres to the '**five lines of code'** principle, enabling complex tasks to be achieved with remarkable brevity, often in **five statements or less**. This significantly accelerates development cycles and reduces the potential for errors, allowing you to focus on innovation rather than boilerplate.

Here are some examples across the GL SDK ecosystem.

{% tabs %}
{% tab title="AI Agents Package (AIP)" %}
Learn more about creating AI Agents [here](https://gdplabs.gitbook.io/sdk/gl-aip/tutorials/hands-on-examples).

```python
from glaip_sdk import Client

client = Client()

agent = client.create_agent(
    name="hello-world-agent",
    instruction="You are a friendly AI assistant."
)
agent.run("Hello! How are you today?")

agent.delete()
```

{% endtab %}

{% tab title="GL Connectors" %}
Learn more about authenticating and using connectors here in [Broken mention](broken://pages/A2YFoQ4N2x1TWWoyHz4e)

```python
from gl_connectors_sdk.connector import GLConnectors

connector = GLConnectors(api_key="GL_CONNECTORS_API_KEY")

response = (connector.connect('google_drive')
    .action('search_files')
    .params({"query": "name contains 'wfo'"})
    .token('GL_CONNECTORS_USER_TOKEN')
    .run())

print(response.get_data())
```

{% endtab %}

{% tab title="GLLM" %}
Learn more about calling language models [here](/sdk/gen-ai-sdk/tutorials/inference/lm-invoker).

```python
import asyncio
from gllm_inference.lm_invoker import OpenAILMInvoker
from gllm_inference.model import OpenAILM

lm_invoker = OpenAILMInvoker(OpenAILM.GPT_5_NANO)
print(asyncio.run(lm_invoker.invoke("What is the capital city of Indonesia?")))
```

{% endtab %}
{% endtabs %}

## Simple, But Flexible

The GL SDK strives to be **as simple as possible** without sacrificing flexibility.

For instance, compare the following code to create a simple custom RAG pipeline using LangGraph vs. using [GLLM Pipeline](/sdk/gen-ai-sdk/guides/build-end-to-end-rag-pipeline).

{% tabs %}
{% tab title="With LangGraph" %}

```python
import asyncio
from typing import TypedDict

from langgraph.graph import END, START, StateGraph
from langgraph.runtime import Runtime

from prebuilt.response_synthesizer import response_synthesizer
from prebuilt.retriever import retriever


class State(TypedDict):
    user_query: str
    chunks: list
    response: str


class Context(TypedDict):
    top_k: int


def execute_retrieve(state: State, runtime: Runtime[Context]) -> State:
    top_k = runtime.context["top_k"]
    state_update = {"chunks": asyncio.run(retriever.retrieve(state["user_query"], top_k=top_k))}
    return state_update


def execute_synthesize(state: State) -> State:
    state_update = {"response": asyncio.run(response_synthesizer.synthesize(state["user_query"], state["chunks"]))}
    return state_update


graph = StateGraph(State, context_schema=Context)

graph.add_node("retrieve", execute_retrieve)
graph.add_node("synthesize", execute_synthesize)

graph.add_edge(START, "retrieve")
graph.add_edge("retrieve", "synthesize")
graph.add_edge("synthesize", END)

pipeline = graph.compile()
```

{% endtab %}

{% tab title="With GLLM Pipeline" %}

```python
from gllm_pipeline.steps import step

from prebuilt.response_synthesizer import response_synthesizer
from prebuilt.retriever import retriever

retriever_step = step(
    component=retriever,
    input_map={"query": "user_query", "top_k": "top_k"},
    output_state="chunks",
)

response_synthesizer_step = step(
    component=response_synthesizer,
    input_map={
        "query": "user_query",
        "chunks": "chunks",
    },
    output_state="response",
)

pipeline = retriever_step | response_synthesizer_step
```

{% endtab %}
{% endtabs %}

At GL SDK, **flexibility does not have to come at the expense of simplicity**.

## Low Maintenance

The GL SDK acts as a robust wrapper around **100+ open-source frameworks, packages, and libraries.** This means you gain all the power and flexibility of the open-source ecosystem without the burden of constant maintenance, dependency management, or version conflicts. We handle the upkeep, updates, and compatibility, ensuring your applications remain stable, secure, and performant with the latest advancements.

## One-Stop Shop

The GL SDK is your comprehensive, one-stop solution for building production-ready AI applications, from computer vision to agentic workflows. Explore our extensive [features list](/sdk/overview/feature-overview/detailed-features), containing **100+ features** to unlock the full potential of your projects.

## Designed with Developer Experience in Mind

We believe that a powerful SDK must also be a joy to use. The GL SDK is meticulously designed with developer experience at its core, ensuring it's not just complete but also intuitively easy to navigate. This commitment to usability, combined with our 'Low Code' philosophy, means you'll find comprehensive user guides, practical tutorials, and helpful how-tos that quickly transform beginners into productive developers.

Check out some of our tutorials and how-to guides:

1. [Language Model (LM) Invoker](/sdk/gen-ai-sdk/tutorials/inference/lm-invoker)
2. [Evaluation](/sdk/gen-ai-sdk/tutorials/evaluation)
3. [Build End-to-End RAG Pipeline](/sdk/gen-ai-sdk/guides/build-end-to-end-rag-pipeline)
4. [Build Ingestion Pipeline](/sdk/gen-ai-sdk/guides/build-document-processing-pipeline)

<br>


# GL Connectors

The definition of Tools, APIs, MCPs, Connectors, and everything surrounding agentic capabilities.

The term "tools" often mean too many things that the meaning tends to get lost. We're going to clarify what "tools" mean, especially when we talk about AI Agents, and what kind of terms we will use in the future.

We split the terminologies into two different sections:

1. [General Hierarchy Overview](/sdk/overview/gl-connectors/general-hierarchy-overview)\
   This highlights the hierarchy between general clients until it receives data that it needs from external sources.
2. [AI Agent Hierarchy Overview](/sdk/overview/gl-connectors/ai-agent-hierarchy-overview)\
   This specifically highlights the hierarchy between APIs and how AI Agents can utilize them in order to achieve their goals.

Alongside the terminology, we will also provide how many tools we currently have in our systems that fit this category.

* [Connectors Count](/sdk/overview/gl-connectors/connectors-count)

## Terminology Quick-Terms

For more details, please check the respective pages to see how they correlate. In this page, we will only give a brief explanation of what terms **we will use moving forward for clarity and consistency**.

* **AI Agents:** LLM-driven agents that perform reasoning and invoke Connectors / Agent Tools to interact with the outside world.
* **Connectors**: Blanket term for anything that an AI Agent can interact with directly. It can also be called Agent Tools (interchangeable terms), but for consistency, we shall call it Connectors. This includes both MCP and simply Tools.
* **REST API**: Remote API standards for communication between two systems. The target can be external services, data storage (e.g., databases, caches), external file storage (e.g., S3), etc.
* **Local API**: API standards that allow for communication with the internal system. Includes filesystem (i.e., file access, file write, etc.), system time, system level randomizer, code executions, etc.


# General Hierarchy Overview

Hierarchy for highlighting the flow from various clients until it receives data that it needs from external sources.

{% hint style="success" %}
This diagram is adapted from [GLChat, AIP, GL SDK - Architecture Block Diagram Slide 6: GL SDK: GDP Labs Software Development Kit](https://docs.google.com/presentation/d/1vV6xMvKZxclBunhFatk__gC2t0xvlDqsYG6x531LSf0/edit?slide=id.g39aef97b903_0_1158#slide=id.g39aef97b903_0_1158)
{% endhint %}

## Block Diagram

<div align="center"><figure><img src="/files/QTYMyfrT5kJjVXTRUBAH" alt=""><figcaption></figcaption></figure></div>

## Term Definitions

1. **GLChat**: Our in-house LLM Chat Client complete with pipeline and inference implementations.
2. **Clients**: The front-end interfaces or autonomous entities that initiate requests to access data or perform actions. This layer aggregates traditional user interfaces (Web, Mobile, Desktop Apps) alongside AI Agents, acting as the consumers of the underlying API layers.
3. **GL Connectors:** Our in-house connectors against third party APIs to provide a synchronized layer for authentication. It can be served over REST API or over MCP for agentic access.
4. **Privacy-First API:** The traditional, standard communication interface used primarily by the Web, Mobile, and Desktop apps. Here, we prioritize API Endpoints that fulfill privacy standards (such as ISO, FIPS, HIPAA, etc.)
5. **Remote Environment:** The backend infrastructure and external systems that serve as the "source of truth" and execution logic. This includes **External Databases, Third-Party Services,** and **External Storage** which are abstracted away from the Clients and accessed strictly through the MCP or REST API layers.


# AI Agent Hierarchy Overview

Hierarchy that highlights connections between APIs and how AI Agents can utilize them in order to achieve their goals.

## Block Diagram

<figure><img src="/files/XHzZ67VL2YGkQMHwtA7Z" alt=""><figcaption></figcaption></figure>

## Term Definitions

1. **AI Agent / Digital Employee:** LLM-driven agents that perform reasoning and invoke Connectors / Agent Tools to interact with the outside world.
2. **GL Connectors**: Anything that an AI Agent can interact with directly. They are created by GDP Labs and are hosted and maintained within our infrastructure. Can be one of the following:
   1. **MCP (Model Context Protocol)**
   2. **Tools**: Interface that can be consumed by AI Agents to execute certain tasks.
3. **REST API / Local API**: Anything that can interact with the Environment such as external databases, storage, internal filesystems, etc. Cannot be used by AI Agents directly.


# Connectors Count

## Term Definitions

1. **GL Connector:** Connectors that are written by and maintained by GDP Labs. This can be one of:
   1. **GL Connector Tools and MCP**: The tools and MCP Servers hosted within GDP Labs’ infrastructure.
   2. **GL Connector Tool SDK**: Agentic tools that are provided via code and can be implemented and extended further for AI Agents.
      1. **Predefined Tools**: Tools that are preincluded in the SDK and can be used as-is.
      2. **User-defined Tools:** Tools that are custom-made by people creating their own implementations. Done by extending from the SDK’s Core Tool
2. **Curated External MCP Servers**: External MCP Servers from official sources that can directly be used by a compatible MCP Client. **They are not hosted&#x20;*****nor*****&#x20;maintained by GDP Labs.**
3. **Provider**: Denotes the application for which certain tools or functionality are created (for example, Github, Google, etc).

## Connector Counts

For the most up to date information, you can click the following endpoint:

{% embed url="<https://connector.gdplabs.id/mcps/list>" %}

The following are the general statistics of our current toolsets based on the above terms (only production data is taken into consideration):

| Type                                                                     | Count                               |
| ------------------------------------------------------------------------ | ----------------------------------- |
| [GL Connector Tools and MCP](#gl-connector-tools-and-mcp)                | 28 Providers (376 Tools)            |
| [Predefined Tools](#gl-connector-tools-sdk)                              | 66 Tools                            |
| [User-Defined Tools](#gl-connector-tools-sdk)                            | 31 Tools                            |
| [Curated External MCP Servers (MCP Only)](#curated-external-mcp-servers) | 97 Providers (968 Tools)            |
| (Total)                                                                  | **125 Providers** (**1000+ Tools**) |

## [GL Connector Tools and MCP](#user-content-fn-1)[^1]

**GL Connector** is designed so that every integration **automatically exposes both**:

* a **REST API** (system-to-system interface), and
* an **MCP Server** (LLM-to-system interface),

**with no additional development work required.**

Because of this architectural design, **any API Endpoint that exists in the REST API will typically also exist as an MCP Tool** exposed by the connector’s MCP Server. This makes the connector’s capabilities consistently available to both traditional systems and LLM-based agents.

Currently, we have **26 providers**, and a total of **347 exposed as Tools and MCP**.

The complete list of GL Connector Tools can be accessed by opening these links:

* [Broken mention](broken://pages/uwTaBgSFKYEUe0Ykv0ci)
* [Model Context Protocol](/sdk/gl-connectors/sdk/agentic-tools-and-model-context-protocol-mcp)
* [Connector MCP Cookbook](/sdk/gl-connectors/sdk/agentic-tools-and-model-context-protocol-mcp/connector-mcp-cookbook)

## [GL Connector Tools SDK](#user-content-fn-2)[^2]

{% hint style="warning" %}
We currently do not have **1.b. (GL Connector Tool SDK)** provisioned yet, and are currently known as **AIP Tools**. We are in the process of creating the SDK and migrating the tools fully to **GL Connector** once the SDK has been fully created.
{% endhint %}

Our Connector SDK allows for tool provisioning via both predefined tools and user-defined tools. Our latest data based on production is as follows:

| Source                                       | Total  |
| -------------------------------------------- | ------ |
| [Predefined Tools](#user-content-fn-3)[^3]   | 66     |
| [User-Defined Tools](#user-content-fn-4)[^4] | 31     |
| **(Total)**                                  | **97** |

## [Curated External MCP Servers](#user-content-fn-5)[^5]

We have also curated MCP Servers (**Providers**) from various official places as listed in this document: [100+ MCP Servers](https://docs.google.com/spreadsheets/d/1n7ZAzwgA9cMNg7PJozaxA4seX6n3LBq3ZbEjgt_pAHw/edit?gid=805864834#gid=805864834). Currently, there are **106** external MCP Servers that we have curated, and this number is expected to continuously increase.

In general, we have categorized the MCP Servers (excluding the ones we host in GL Connector) as such:

| Read or Write  | Total   |
| -------------- | ------- |
| Readonly       | 48      |
| Read and Write | 58      |
| **(Total)**    | **106** |

Note that on the **Readonly** MCP Servers, a lot of them are from the same services, but for different dataset (such as various Gitbook MCP Servers for our documentation, each having their own MCP Servers, or Cloudflare and OpenZeppelin having multiple MCP Servers catered to specific details).

[^1]: The tools and MCP Servers hosted within GDP Labs’ infrastructure.

[^2]: Agentic tools that are provided via code and can be implemented and extended further for AI Agents.

[^3]: Tools that are preincluded in the SDK and can be used as-is.

[^4]: Tools that are custom-made by people creating their own implementations. Done by extending from the SDK’s Core Tool

[^5]: External MCP Servers from official sources that can directly be used by a compatible MCP Client. **They are not hosted&#x20;*****nor*****&#x20;maintained by GDP Labs.**


# GL SDK Package Installation

## What is the GL SDK Package?

The GL SDK package is a meta package for GenAI, GL Connectors, GL Observability and many more. It acts as a centralized installer for the entire GL SDK family.

## **Installation**

{% tabs %}
{% tab title="Linux, macOS, or Windows WSL" %}

```bash
# you can use a Conda environment
pip install --extra-index-url https://oauth2accesstoken:$(gcloud auth print-access-token)@glsdk.gdplabs.id/gen-ai-internal/simple/ "gl-sdk"
```

{% endtab %}

{% tab title="Windows Powershell" %}

```powershell
# you can use a Conda environment
$token = (gcloud auth print-access-token)
pip install --extra-index-url "https://oauth2accesstoken:$token@glsdk.gdplabs.id/gen-ai-internal/simple/" "gl-sdk"
```

{% endtab %}

{% tab title="Windows Command Prompt" %}

```bash
# you can use a Conda environment
FOR /F "tokens=*" %T IN ('gcloud auth print-access-token') DO SET TOKEN=%T
pip install --extra-index-url "https://oauth2accesstoken:%TOKEN%@glsdk.gdplabs.id/gen-ai-internal/simple/" "gl-sdk"
```

{% endtab %}
{% endtabs %}

<details>

<summary>Prerequisites</summary>

If you want to try the snippet code in this page:

* Completion of all setup steps listed on the [Prerequisites](/sdk/gen-ai-sdk/prerequisites) page.

</details>

## Using a Library in GL SDK

{% stepper %}
{% step %}
Create a script called `main.py`:

```python
import asyncio
from gllm_inference.lm_invoker import OpenAILMInvoker
from gllm_inference.model import OpenAILM

lm_invoker = OpenAILMInvoker(OpenAILM.GPT_5_NANO)
response = asyncio.run(lm_invoker.invoke("What is the capital city of Indonesia?"))
print(f"Response: {response}")
```

{% endstep %}

{% step %}
Run the script:

```bash
python main.py
```

{% endstep %}

{% step %}
The script will generate the following output (more or less):

```
[2025-09-17T15:12:36+0700.389 OpenAILMInvoker INFO] Invoking 'OpenAILMInvoker'
[2025-09-17T15:12:42+0700.907 httpx INFO] HTTP Request: POST https://api.openai.com/v1/responses "HTTP/1.1 200 OK"
Response: Jakarta. (Note: Indonesia has been planning to move its administrative capital to Nusantara in East Kalimantan, but Jakarta remains the capital for now.)
```

{% endstep %}
{% endstepper %}

## Extras

By default, if you install GL SDK you will get `gllm-core` and `gllm-inference`.

To keep the installation lean, GL SDK provides several extras. So you don't have to install libraries you don't need:

1. `genai` = `gllm-privacy`, `gllm-datastore`, `gllm-misc`, `gllm-docproc`, `gllm-retrieval`, `gllm-generation`, `gllm-pipeline`, `gllm-rag`
2. `agent` = `gllm-agent`, `gllm-agents`
3. `gl-connectors` = `gl-connectors`
4. `gl-observability` = `gl-observability`
5. `eval` = `gllm-evals`

You can install the extras as follows:

{% tabs %}
{% tab title="Linux, macOS, or Windows WSL" %}

```bash
# you can use a Conda environment
pip install --extra-index-url https://oauth2accesstoken:$(gcloud auth print-access-token)@glsdk.gdplabs.id/gen-ai-internal/simple/ "gl-sdk[genai, agent]"
```

{% endtab %}

{% tab title="Windows Powershell" %}

```powershell
# you can use a Conda environment
$token = (gcloud auth print-access-token)
pip install --extra-index-url "https://oauth2accesstoken:$token@glsdk.gdplabs.id/gen-ai-internal/simple/" "gl-sdk[genai, agent]"
```

{% endtab %}

{% tab title="Windows Command Prompt" %}

```bash
# you can use a Conda environment
FOR /F "tokens=*" %T IN ('gcloud auth print-access-token') DO SET TOKEN=%T
pip install --extra-index-url "https://oauth2accesstoken:%TOKEN%@glsdk.gdplabs.id/gen-ai-internal/simple/" "gl-sdk[genai, agent]"
```

{% endtab %}
{% endtabs %}


# Documentation Guide


# Introduction to GL AI Agent Package

GL AIP is an agent package with an SDK-first developer experience. The primary interface is the Python `Agent` object from `glaip-sdk`. You can run agents locally for fast iteration, then deploy and run remotely when you need centralized execution.

## Start Here (Python SDK, Agent-First)

The fastest path is a minimal `Agent`:

```python
from glaip_sdk import Agent

agent = Agent(
    name="hello",
    instruction="You are a helpful assistant.",
)

# Undeployed agents run locally (requires `glaip-sdk[local]`).
print(agent.run("Hello!"))
```

When you deploy an agent, `Agent.run()` uses server-backed execution by default. You can still force local execution for a deployed agent with `local=True`.

## Recommended Reading Path

* Getting started: install, configure, and quick start.
* Guides: build (agents, tools, MCPs), run (files, HITL), operate (security, config, automation).
* CLI: interactive ops workflows (accounts, runs/transcripts, export/import).
* Resources: Python SDK reference first; REST API is reference-only for internal integrators.

### Documentation Map

Use these sections in order when exploring the SDK and CLI:

* [**Get Started**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started) — Install, configure, complete the quick start, and run curated examples.
* [**Guides**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides) — Deep dives on lifecycle management, automation, integrations, and governance.
* [**Multi-Agent System Patterns**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns) — Runnable orchestration templates for complex workflows.
* [**CLI**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli) — Interactive ops workflows (accounts, runs/transcripts, export/import).
* [**Reference**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference) — Definitive API, SDK, and CLI commands for implementation details.
* [**Resources**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources) — Glossary, upgrade checklists, and cookbook pointers.

### Role-Based Entry Points

Choose the track that matches how you work today.

<details>

<summary>Engineers — Ship agents in applications and automation</summary>

**Why it matters:** You need reliable APIs, typed clients, and testable workflows that fit existing services.

**Start here:**

* [Quick Start Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide) for first-run success.
* [Python SDK Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk) for signatures and streaming behaviour.
* [Automation & Scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) for CI, cron, and deployment patterns.

</details>

<details>

<summary>Product Managers — Validate agents via GLChat</summary>

**Why it matters:** You review agent behaviour for stakeholders. GLChat gives you fast access, but the CLI helps you list available agents and capture verbose output when needed.

**Start here:**

* [CLI quick start](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide/cli) — run an agent end-to-end and see detailed logs.
* [CLI landing](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli) — task-focused pages (status, agents, runs/transcripts).
* [Agents guide › List & run](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents#list-and-inspect-agents) — discover agent IDs/names before launching them in GLChat.
* [Automation & Scripting › Choose the right output](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting#choose-the-right-output-format) — switch between rich and plain responses when sharing findings.

</details>

<details>

<summary>Data Developers — Curate prompts, evaluations, and linguistic QA</summary>

**Why it matters:** You iterate on prompts, run guided evaluations, and need to inspect agent transcripts without writing code.

**Start here:**

* [CLI quick start](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide/cli) — validate access and run agents.
* [Runs & transcripts](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/runs-and-transcripts) — capture and review outputs.
* [Configuration management guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) — master CLI export/import loops for prompt iteration.
* [CLI Commands Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands) — look up flags for runs, exports, and transcript capture.

</details>

### Choose Your Interface

Pick the surface that matches your environment. Default path is Python SDK first.

| Interface                 | When to use it                                                         | Start here                                                                                                                                                                                                            |
| ------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Python SDK (recommended)  | Application code, notebooks, CI, local iteration, type-safe workflows. | [Quick Start (SDK)](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide) · [Python SDK reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk) |
| CLI                       | Interactive ops, demos, export/import promotion loops, transcripts.    | [CLI](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli) · [CLI commands reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands)                               |
| REST API (reference-only) | Internal integrations (for example GLChat) or non-Python environments. | [REST API reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api)                                                                                                                 |

### Platform Capabilities at a Glance

Symbols: `✅` fully supported · `🛠️` partial via customization/workarounds · `🚧` roadmap

{% hint style="info" %}
REST exists as a reference-only surface for internal integrations. SDK and CLI are the supported day-to-day surfaces for most users.
{% endhint %}

| Capability                      | What it covers                                                    | REST API (ref) | Python SDK | CLI |
| ------------------------------- | ----------------------------------------------------------------- | -------------- | ---------- | --- |
| Agent lifecycle & metadata      | Create/list/update/delete agents with tools, MCPs, and sub-agents | ✅              | ✅          | ✅   |
| Streaming execution & artifacts | Runs, SSE output, file attachments, artifact links                | ✅              | ✅          | ✅   |
| Tools (native + custom)         | Attach catalog tools, upload tools, tool configs                  | ✅              | ✅          | ✅   |
| MCP connectors                  | MCP CRUD, connect/test, tool discovery                            | ✅              | ✅          | ✅   |
| HITL approvals                  | Pause, approve/reject, resume                                     | ✅              | ✅          | 🛠️ |
| Run history                     | List runs, statuses, transcripts                                  | ✅              | ✅          | ✅   |
| Scheduling                      | Cron schedules and run history                                    | ✅              | ✅          | 🚧  |
| Memory & persistence            | Memory config and chat history                                    | ✅              | ✅          | 🛠️ |
| Security & privacy              | `pii_mapping`, tool output sharing, secrets hygiene               | ✅              | ✅          | 🛠️ |

## Architecture (Reference)

<details>

<summary>How the SDK, CLI, and platform fit together</summary>

<figure><img src="/files/jDyoC3QZ3i2xfpdPTCfD" alt="Architecture reference: how glaip-sdk, aip-agents, and ai-agent-platform fit together."><figcaption><p>Architecture reference — SDK, CLI, local engine, and platform relationships.</p></figcaption></figure>

Components:

* `glaip-sdk`: user-facing SDK and CLI.
* `aip-agents`: local execution engine used by both local runs and the platform.
* `ai-agent-platform`: remote execution and management.

Setup:

* Local mode: configure LLM provider credentials (for example `OPENAI_API_KEY`).
* Remote mode: configure platform credentials (CLI: `aip accounts add/use`; Python SDK: `AIP_API_URL` and `AIP_API_KEY`).

</details>

### Notes on Execution Modes

* Local mode: runs in your Python process (fast iteration).
* Remote mode: runs on the platform (centralized execution, shared agents).
* The CLI uses the Python SDK under the hood for most operations.
* REST API documentation is kept as reference for internal integrations.

### Start Building

Ready to go from prototype to production? Follow this path to ship quickly:

1. **Install & configure** — Set up credentials and the CLI with [Install & Configure](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/prerequisites).
2. **Run the quick start** — Use the Agent-first pattern (recommended). Treat `Client` workflows as legacy/advanced admin paths in the [Quick Start Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide).
3. **Explore patterns** — Use the [Hands-on Examples](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/hands-on-examples) to pick the right pattern (single agent, multi-agent, class pattern, runtime config, local execution, report automation).
4. **Iterate on prompts** — Use the CLI export/import loop in [Configuration management](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) to refine instructions safely.
5. **Add real workflows** — Explore [Tools](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools), [File processing](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/file-processing), or [Multi-agent patterns](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns) as you expand capabilities.

The GL AIP package, SDK, and CLI give you a single, consistent toolkit to build, test, and operate AI agents anywhere.


# Prerequisites

Comprehensive setup guide for the AIP SDK with advanced configuration options, security best practices, and troubleshooting tips.

{% hint style="info" %}
Need the fastest path to a working agent? Jump to the [**Quick Start**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide) first, then return here when you need deeper configuration.
{% endhint %}

### Requirements

* **Python** 3.11 or 3.12 (3.10 and earlier are not supported)
  * Verify with: `python3 --version` or `python --version`
* **Operating System**: Windows, macOS, or Linux
* **Network**: Internet access for package installation

{% hint style="info" %}
**Corporate networks** may require outbound proxy variables (e.g. `HTTP_PROXY`/`HTTPS_PROXY`). Set those before installing or running the CLI if your organisation routes traffic through a proxy.
{% endhint %}

#### Install SDK and CLI Together

Installing `glaip-sdk` provides both the Python SDK and the `aip` CLI. Pick the install command that matches how you manage dependencies.

{% hint style="info" %}
**Local Execution Mode:** To run agents locally using the `aip-agents` library, install the `[local]` extra:

```bash
pip install --upgrade "glaip-sdk[local]"
```

This includes `aip-agents` for local LLM execution. See [Local vs Remote Mode](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/local-vs-remote) for when to use each mode.
{% endhint %}

{% hint style="warning" %}
**Privacy Features:** If you plan to use PII masking and privacy features, install `glaip-sdk[privacy]`:

```bash
pip install --upgrade "glaip-sdk[privacy]"
```

**Note:** Privacy features work in both remote and local modes. For local execution with privacy, use `glaip-sdk[local,privacy]`. See the [Security and Privacy guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) for more details.
{% endhint %}

**pip (Linux/macOS)**

```bash
# Standard installation
pip install --upgrade glaip-sdk

# With local execution support
pip install --upgrade "glaip-sdk[local]"
```

Use when you manage environments with `venv` or system Python. Activate the environment before running the command.

**pip (Windows PowerShell)**

```powershell
# Standard installation
pip install --upgrade glaip-sdk

# With local execution support
pip install --upgrade "glaip-sdk[local]"
```

Run inside an elevated PowerShell session if your organisation restricts installs. Use `py -m pip install --upgrade glaip-sdk` when `pip` is not on `PATH`.

**Poetry (project managed)**

```bash
# Standard installation
poetry add glaip-sdk

# With local execution support
poetry add "glaip-sdk[local]"

poetry run aip --version
```

Ideal when the SDK ships with your application code. `poetry run` ensures the CLI uses the project virtual environment.

**uv tool**

```bash
uv tool install glaip-sdk
```

Great for users who prefer reproducible global installs while keeping Python projects isolated.

**pipx (CLI only)**

```bash
pipx install glaip-sdk
pipx ensurepath
```

Deploys the CLI in an isolated environment and keeps your global Python clean. Ideal for operations or QA stations. Recommended for data developers who only need the CLI.

* `--upgrade` (or the equivalent) ensures you pick up the latest release or refresh an existing installation.
* Using a virtual environment? Activate it first, then run the same command.
* Verify the CLI once installed:

```bash
aip --version
```

{% hint style="info" %}
If `pip` is not available as a command, fall back to `python3 -m pip` (Linux/ macOS) or `py -m pip` (Windows). After installing, ensure `~/.local/bin` (Linux/macOS) or `%APPDATA%\Python\Python311\Scripts` (Windows) is on your `PATH` so `aip` resolves.
{% endhint %}

#### Configure Access Options

You only need these settings when pointing the SDK or CLI to the **AIP server**. Local runs (using `aip-agents` directly) use the built-in defaults. Choose the option that matches your workflow; each method sets the same API URL and API key, so pick one.

**.env file (project scoped)**

1. Create a `.env` file alongside your project code:

   ```bash
   AIP_API_URL=https://your-aip-instance.com
   AIP_API_KEY=your-api-key-here
   ```
2. Load it with `python-dotenv`, your framework of choice, or a task runner.
3. Ideal when you check environment files into a secure secrets store per project.

**Shell profile (persistent)**

Use when you want the **Python SDK** (scripts/notebooks/CI) available in every terminal.

The `aip` CLI uses account profiles stored in `~/.aip/config.yaml` and does **not** read `AIP_API_URL` / `AIP_API_KEY` from the environment.

* **Linux / macOS:**

  ```bash
  export AIP_API_URL="https://your-aip-instance.com"
  export AIP_API_KEY="your-api-key-here"
  ```

  Add the lines to `~/.bashrc`, `~/.zshrc`, or your shell profile to persist them.
* **Windows PowerShell:**

  ```powershell
  setx AIP_API_URL "https://your-aip-instance.com"
  setx AIP_API_KEY "your-api-key-here"
  ```

  Restart the terminal after running `setx` so the variables are picked up.

**Interactive CLI (per machine)**

Add a profile to store credentials in the CLI config file:

```bash
aip accounts add dev
aip accounts use dev
```

You will be prompted for:

* API URL
* API Key

This is convenient on developer laptops or CI agents that already store the values securely.

{% hint style="info" %}
Configuration precedence:

* CLI: account profiles (`aip accounts ...`) > (deprecated) `--api-url/--api-key` flags.
* Python SDK: `AIP_API_URL`/`AIP_API_KEY` env vars (or `.env`) > library defaults.
  {% endhint %}

{% hint style="info" %}
CLI configuration is stored in `~/.aip/config.yaml` (Linux/macOS) or `%USERPROFILE%\\.aip\\config.yaml` (Windows).
{% endhint %}

#### Verify Installation

Confirm both the CLI and SDK can reach your AIP instance.

**CLI**

```bash
aip status
```

Expected output includes `✅ Connected to AIP server`.

{% hint style="warning" %}
`aip status` may also report:
{% endhint %}

| Indicator               | Meaning                                                                | Common fix                                                                                                           |
| ----------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `⚠️ Partial Connection` | DNS/SSL failure or blocked outbound request after the client connects. | Check VPN/proxy settings, verify the API URL in your active account profile (`aip accounts show <name>`), and retry. |
| `❌ Connection failed`   | Credentials missing or rejected before any data flows.                 | Re-run `aip accounts add <name>` and `aip accounts use <name>`, then rerun the command.                              |
| `Timed out`             | CLI could not reach the API within the configured timeout.             | Confirm the service is up and adjust `--timeout` if your environment requires longer waits.                          |

{% hint style="warning" %}
If the error mentions `Temporary failure in name resolution`, your DNS cannot resolve the host—double-check the URL or try again once network connectivity is restored.
{% endhint %}

**Python SDK**

Preferred validation is the Agent-first quick start (`Agent(...)` + `agent.run(...)`). Use the `Client().ping()` check below for low-level connectivity diagnostics.

```python
from glaip_sdk import Client

client = Client()  # Reads AIP_API_URL and AIP_API_KEY from environment

if client.ping():
    print("✅ Connected to AIP server")
else:
    print("❌ Connection failed")
```

#### Security Best Practices

These apply to anyone handling API keys for the platform—whether you are a developer, DevOps engineer, or administrator.

* Use different API keys per environment (development, staging, production).
* Never commit keys to source control—prefer secret managers or CI variables.
* Rotate keys regularly and revoke unused ones promptly.

#### Optional CLI Configuration Helpers

Use these after installation when you need to inspect or adjust saved values.

```bash
# List saved accounts
aip accounts list

# Show a specific account
aip accounts show dev

# Add or update accounts interactively
aip accounts add dev
aip accounts use dev

# Update a specific account non-interactively
aip accounts edit dev --url "https://your-aip-instance.com" --key "$AIP_API_KEY"

# Remove an account
aip accounts remove dev
```

#### Continue

Ready to run your first agent? Head to the [Quick Start](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide) and follow the Python or CLI track.


# Getting Started

Move from installation to production-ready workflows with the three pages in this section. Each topic builds on the previous one so you can set up, validate, and extend the SDK or CLI without guesswork.

### Quick Path

| Step                                                                                                      | What you do                                                                                 | Why it matters                                                      |
| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| [Install & Configure](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/prerequisites)                   | Set up Python, manage dependencies (pip, Poetry, uv, pipx), and store credentials securely. | Establish a reliable runtime before touching agents or tools.       |
| [Quick Start Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide) | Use the Python SDK to run an agent locally, then optionally deploy and run remotely.        | Validate connectivity and build confidence with the core workflow.  |
| [Hands-On Examples](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/hands-on-examples)       | Run curated scenarios that mix tools, files, and multi-agent coordination.                  | Practice common follow-up tasks before moving into advanced guides. |

### Where to Go Next

* Jump to the [Guides topics](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/topics) for lifecycle, automation, and security deep dives.
* Browse the [platform overview](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/introduction-to-gl-aip) for personas, capability matrices, and navigation tips.


# Local vs Remote

Choose between local execution and remote deployment based on your development stage and infrastructure requirements.

{% hint style="info" %}
**When to use this guide:** Reference this when deciding how to run agents during development, testing, or production deployment. Use the decision checklist to pick the right mode for your use case.
{% endhint %}

### Overview

The SDK supports two execution modes:

* **Local Mode** — Agents run directly on your machine using the `aip-agents` library
* **Remote Mode** — Agents run on the **remote server** (via the `ai-agent-platform` platform, which uses `aip-agents` internally)

Both modes use the same `Agent` API, making it easy to switch between them. The SDK (`glaip-sdk`) can connect to either the platform's remote server or run agents locally using `aip-agents` directly.

### Quick Comparison

| Feature                    | Local Mode                                                    | Remote Mode                                  |
| -------------------------- | ------------------------------------------------------------- | -------------------------------------------- |
| **⚙️ Setup**               | Install local extra and configure LLM provider key            | Install SDK and configure remote API URL/key |
| **🔐 Credentials**         | LLM provider key + optional feature keys (memory, NER, tools) | AIP API URL + API key                        |
| **🚀 Deploy Step**         | No deploy step; run immediately                               | Deploy first to register agent               |
| **🖥️ Execution Location** | Runs on your machine                                          | Runs on remote server                        |
| **🧠 LLM Provider**        | Local (via `aip-agents`)                                      | Platform-managed or custom                   |

### Capability Checklist

| Capability                                               | Local Mode       | Remote Mode                                                       |
| -------------------------------------------------------- | ---------------- | ----------------------------------------------------------------- |
| **🛠️ Tool calling (custom tools)**                      | ✅                | ✅                                                                 |
| **🔗 MCP support**                                       | ✅                | ✅                                                                 |
| **🧠 Model selection**                                   | ✅                | ✅                                                                 |
| **🧵 Token streaming**                                   | ✅                | ✅                                                                 |
| **🧾 Tool output sharing**                               | ✅                | ✅                                                                 |
| **🤝 Sub-agent delegation**                              | ✅                | ✅                                                                 |
| **🧍 HITL**                                              | ✅                | ✅ (audit trail)                                                   |
| **💾 Persistent memory (`mem0`)**                        | ✅                | ✅                                                                 |
| **🧰 Built-in tool: Code Interpreter**                   | ✅                | ✅                                                                 |
| **🧰 Built-in tool: Browser Use**                        | ✅                | ✅                                                                 |
| **🧰 Built-in tool: Document Loader (PDF, DOCX, Excel)** | ✅                | ✅                                                                 |
| **🔧 Runtime config overrides**                          | ✅                | ✅                                                                 |
| **🕵️ PII**                                              | ✅                | ✅                                                                 |
| **📁 Run with file attachments**                         | ✅                | ✅                                                                 |
| **🗄️ Agent filesystem (read/write/edit/ls/grep tools)** | ✅                | ✅                                                                 |
| **💿 Agent filesystem: `LocalDiskConfig`**               | ✅                | ✅ (`base_directory` ignored; `allow_execute` and `env` supported) |
| **🔌 GL Connectors support**                             | ✅                | ✅                                                                 |
| **🧩 Built-in agents (e.g., Data Analyst)**              | ❌                | ✅                                                                 |
| **🌐 CRUD + Run REST API**                               | ❌                | ✅                                                                 |
| **🗂️ Agent registry (persistent storage)**              | ❌                | ✅                                                                 |
| **📜 Run history/logs/metrics**                          | ❌ (console only) | ✅                                                                 |
| **⏰ Scheduling**                                         | ❌                | ✅                                                                 |
| **📡 Offline execution**                                 | ✅                | ❌                                                                 |

### Local Mode

#### Setup

```bash
# Install with local execution support
pip install "glaip-sdk[local]"

# Configure LLM provider (required)
export OPENAI_API_KEY="your-openai-key"
```

The `[local]` extra includes `aip-agents` for local LLM execution.

#### Usage Pattern

```python
from glaip_sdk.agents import Agent

# Create and run locally (no deploy needed)
agent = Agent(
    name="local-agent",
    instruction="You are a helpful assistant.",
)

# Runs immediately on your machine
response = agent.run("Hello!")
```

#### Local Run Examples

All local features assume a configured LLM provider key (for example `OPENAI_API_KEY`). Additional required environment variables are listed per feature below.

Example `.env` (include only what you use):

```bash
OPENAI_API_KEY=your-openai-key
MEM0_API_KEY=your-mem0-key
NER_API_URL=https://ner.example.com
NER_API_KEY=your-ner-key
SERPER_API_KEY=your-serper-key
E2B_API_KEY=your-e2b-key
# GL Connectors settings
GL_CONNECTORS_BASE_URL=https://gl-connector.example.com
GL_CONNECTORS_API_KEY=your-api-key
GL_CONNECTORS_USERNAME=your-username
GL_CONNECTORS_PASSWORD=your-password
GL_CONNECTORS_IDENTIFIER=optional-identifier
# (Backward compatible with BOSA_BASE_URL, etc.)
ARXIV_MCP_API_KEY=your-arxiv-key
ARXIV_MCP_AUTH_TOKEN=your-arxiv-token
```

| Feature                                                                         | Required env vars                                                                                                                          | Example                                                                                                                                                                |
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Basic run                                                                       | None beyond LLM provider key                                                                                                               | [main.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main.py)                                                                 |
| Files (`files=[...]`)                                                           | None beyond LLM provider key                                                                                                               | [main\_with\_local\_files.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_local_files.py)                            |
| Built-in tool: Document Loader (PDFReaderTool, DocxReaderTool, ExcelReaderTool) | None beyond LLM provider key                                                                                                               | [main\_with\_docproc\_pdf.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_docproc_pdf.py)                            |
| Native aip-agents tools (web search, code sandbox, browser use)                 | `SERPER_API_KEY` (GoogleSerperTool), `E2B_API_KEY` (E2BCodeSandboxTool); other tools may require their own env                             | [main\_with\_native\_tool.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_native_tool.py)                            |
| mem0 memory                                                                     | `MEM0_API_KEY` or `GLLM_MEMORY_API_KEY`                                                                                                    | [main\_with\_memory.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_memory.py)                                       |
| PII toggle (`enable_pii`)                                                       | Optional `NER_API_URL` and `NER_API_KEY` for NER-backed masking                                                                            | [main\_with\_pii\_toggle.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_pii_toggle.py)                              |
| Tool output sharing (`agent_config.tool_output_sharing`)                        | None beyond LLM provider key                                                                                                               | [main\_with\_tool\_output\_sharing.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_tool_output_sharing.py)           |
| Runtime config overrides                                                        | `ARXIV_MCP_API_KEY` and `ARXIV_MCP_AUTH_TOKEN` (optional, for Arxiv MCP)                                                                   | [main\_with\_runtime\_config.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_runtime_config.py)                      |
| Definition-time configs (`tool_configs`, `mcp_configs`, `agent_config`)         | `ARXIV_MCP_API_KEY` and `ARXIV_MCP_AUTH_TOKEN` (optional, for Arxiv MCP)                                                                   | [main\_with\_agent\_definition\_configs.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_agent_definition_configs.py) |
| HITL (`hitl_enabled`)                                                           | None beyond LLM provider key                                                                                                               | [main\_with\_hitl.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_hitl.py)                                           |
| Chat history input                                                              | None beyond LLM provider key                                                                                                               | [main\_with\_chat\_history.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_chat_history.py)                          |
| Sub-agents                                                                      | None beyond LLM provider key                                                                                                               | [main\_with\_subagents.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_subagents.py)                                 |
| MCPs with local transport                                                       | `ARXIV_MCP_API_KEY` and `ARXIV_MCP_AUTH_TOKEN` (optional, for Arxiv MCP)                                                                   | [main\_with\_mcp.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_mcp.py)                                             |
| GL Connectors                                                                   | `GL_CONNECTORS_BASE_URL`, `GL_CONNECTORS_API_KEY`, `GL_CONNECTORS_USERNAME`, `GL_CONNECTORS_PASSWORD`; optional `GL_CONNECTORS_IDENTIFIER` | [main\_with\_gl\_connectors\_tool.py](https://github.com/gdplabs/gl-aip-sdk-cookbook/blob/main/examples/hello-world-local/main_with_gl_connectors_tool.py)             |

#### Tool Output Sharing Quickstart (Local)

The `hello-world-local` project ships with `main_with_tool_output_sharing.py`, which wires two LangChain-compatible tools together and enables `$tool_output.<call_id>` references through `agent_config={"tool_output_sharing": True}`. Use this path when you want to stage multi-step tool workflows locally before promoting them to the remote platform.

{% hint style="info" %}
Monitor the console output when running locally. Each tool call prints a `call_id` so you can trace which stored output is being replayed.
{% endhint %}

1. Install dependencies: `pip install "glaip-sdk[local]"` (includes `aip-agents`).
2. Copy `.env.example` from `examples/hello-world-local` in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main) and set `OPENAI_API_KEY`.
3. Run `python main_with_tool_output_sharing.py` to watch the agent perform a two-step greeting workflow with shared tool responses.

```python
from glaip_sdk.agents import Agent
from tools import GreetingFormatterTool, GreetingGeneratorTool

INSTRUCTION = """Use greeting_generator first, then pass the stored output
into greeting_formatter via $tool_output.<call_id> before responding."""

greeting_agent = Agent(
    name="hello_local_tool_output_sharing",
    instruction=INSTRUCTION,
    description="Local agent that demonstrates tool output sharing",
    tools=[GreetingGeneratorTool, GreetingFormatterTool],
    agent_config={"tool_output_sharing": True},
)

response = greeting_agent.run("Create a greeting for Alice, then format it nicely.", verbose=True)
print(response)
```

The script prints both the intermediate explanation (including the `call_id` reference) and the final formatted greeting, mirroring the same workflow you would deploy remotely once satisfied with the run.

### Remote Mode

Remote mode connects to the **platform's remote server**, which uses `aip-agents` internally to execute agents.

#### Setup

```bash
# Install SDK
pip install glaip-sdk

# Configure connection to AIP server
export AIP_API_URL="https://your-aip-instance.com"
export AIP_API_KEY="your-api-key-here"
```

#### Usage Pattern

```python
from glaip_sdk.agents import Agent

# Create agent definition
agent = Agent(
    name="remote-agent",
    instruction="You are a helpful assistant.",
    agent_config={"memory": "mem0"},  # Persistent memory
)

# Deploy to AIP server (creates/updates agent)
agent.deploy()

# Remote run
response = agent.run("Hello!")
```

### Switching Between Modes

**Best practice:** Use instances instead of strings for seamless migration between modes.

#### Local Override for Deployed Agents

You can force local execution for an agent that has already been deployed to the remote server by passing `local=True` to `run()` or `arun()`.

```python
# Agent is deployed (has an ID and routes to server by default)
agent.deploy()

# Standard run: routes to remote server
agent.run("Hello server")

# Override: forces local execution using local tools and code
agent.run("Hello local", local=True)
```

{% hint style="info" %}
When `local=True` is used, the SDK behaves exactly as if the agent was not deployed, requiring the `[local]` extra and local LLM credentials.
{% endhint %}

#### Seamless Migration Example

```python
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field


class EchoInput(BaseModel):
    text: str = Field(..., description="Text to echo")


class EchoTool(BaseTool):
    name: str = "echo_tool"
    description: str = "Echo back text."
    args_schema: type[BaseModel] = EchoInput

    def _run(self, text: str) -> str:
        return f"Echo: {text}"
```

```python
from glaip_sdk.agents import Agent

# Use LangChain-compatible tools for seamless local/remote compatibility
agent = Agent(
    name="my-agent",
    instruction="You are helpful.",
    tools=[EchoTool],
)

# Local mode: just run
response = agent.run("What time is it?")

# Remote mode: add deploy() call
agent.deploy()
response = agent.run("What time is it?")
```

{% hint style="warning" %}
**Local mode does not support string references or platform-only helpers** (`Tool.from_native()`, `MCP.from_native()`). Use LangChain BaseTool classes/instances or `Tool.from_langchain()` for tools, and MCP instances with local transport configs (`http`, `sse`, `stdio`). Add native tools or MCPs only when deploying to the platform.
{% endhint %}

#### Migration Path: Local → Remote

1. **Test locally** with `agent.run()` (uses `aip-agents` directly)
2. **Configure AIP server credentials** (`AIP_API_URL`, `AIP_API_KEY`)
3. **Add `deploy()` call** before first remote run
4. **Verify remote run** with same inputs

#### Migration Path: Remote → Local

1. **Install local extra**: `pip install "glaip-sdk[local]"` (includes `aip-agents`)
2. **Set `OPENAI_API_KEY`** environment variable
3. **Remove `deploy()` calls** from code (not needed for local execution)
4. **Replace string/native references** with instances if any exist

### Decision Checklist

Use **Remote Mode** (AIP server) if you need any capability that is remote-only (✅ on Remote, ❌ on Local). Otherwise, use **Local Mode** (aip-agents directly).

### Common Patterns

#### Pattern 1: Local Development, Remote Production

```python
import os
from glaip_sdk import Agent, Tool

# EchoTool defined in the example above.

# Use LangChain tools for local runs; add native tools only when deploying to the platform
tools = [EchoTool]
if os.getenv("AIP_API_KEY"):
    tools.append(Tool.from_native("time_tool"))

agent = Agent(
    name="my-agent",
    instruction="...",
    tools=tools,
)

# Deploy only if AIP server credentials exist - MUST succeed for native tools to work
# If deploy() fails, agent.run() will attempt local execution and fail with Tool.from_native()
if os.getenv("AIP_API_KEY"):
    agent.deploy()

# Run works in both modes:
# - Local: uses aip-agents directly (requires LangChain BaseTool classes/instances, not Tool.from_native())
# - Remote: runs on remote server (platform uses aip-agents internally)
response = agent.run("query")
```

#### Pattern 2: Conditional Mem0 Usage

```python
import os
from glaip_sdk import Agent

agent = Agent(
    name="my-agent",
    instruction="...",
)

# Enable persistent memory when Mem0 is configured locally or via AIP server
if os.getenv("AIP_API_KEY") or os.getenv("MEM0_API_KEY") or os.getenv("AIP_MEMORY_API_KEY"):
    agent.agent_config = {"memory": "mem0"}

# Deploy only if AIP server credentials exist
if os.getenv("AIP_API_KEY"):
    agent.deploy()

response = agent.run("query")
```

#### Pattern 3: Testing Locally, Running on Remote

```python
from glaip_sdk import Agent, Tool

# EchoTool defined in the example above.

# test_agent.py - runs locally
def test_agent_logic():
    agent = Agent(
        name="test-agent",
        instruction="...",
        tools=[EchoTool],
    )
    response = agent.run("test query")
    assert "expected" in response

# main.py - remote run on platform
def main():
    agent = Agent(
        name="prod-agent",
        instruction="...",
        tools=[EchoTool],
    )
    agent.deploy()  # Deploys to AIP server
    response = agent.run("production query")  # Remote run
```

### Troubleshooting

| Issue                 | Local Mode                                         | Remote Mode                                           |
| --------------------- | -------------------------------------------------- | ----------------------------------------------------- |
| Agent not found       | N/A (ephemeral)                                    | Check `aip agents list`                               |
| Missing dependencies  | Install `glaip-sdk[local]` (includes `aip-agents`) | Upload tools to AIP server                            |
| Authentication error  | N/A                                                | Verify `AIP_API_KEY` for AIP server                   |
| Memory not persisting | Check `MEM0_API_KEY` and `agent_config.memory`     | Check `agent_config.memory` and AIP server mem0 setup |
| Slow execution        | Check local LLM config                             | Check network latency to remote server                |

### Related Documentation

* [Install & Configure](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/prerequisites) — Setup for both modes
* [Quick Start Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide) — First agent in each mode
* [Agents Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Full agent lifecycle
* [Configuration Management](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) — Promote agents between environments


# Quick Start Guide

Go from zero to your first successful agent run.

If you have not installed and configured the SDK yet, start with [Install & Configure](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/prerequisites).

> **Success**
>
> **When to use this guide:** Choose it when you need a reproducible walkthrough to prove connectivity, create an agent, and observe responses without diving into advanced configuration.
>
> **Audience:** Developers, PMs running acceptance demos, and data developers validating prompt baselines.

{% hint style="info" %}
If you need a deeper comparison before choosing, read [Local vs Remote](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/local-vs-remote).
{% endhint %}

## Default Path: Python SDK

Follow the [Python SDK](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide/python-sdk) page for step-by-step installation, a default local agent run, and optional setup when you want to target a remote AIP server with API credentials and deployment.

> **Info**
>
> If you prefer a low-code workflow (operators, demos, CI smoke tests), use the CLI section:
>
> * CLI entry: [CLI](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli)
> * Quick start (CLI): [CLI Quick Start](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide/cli)

## Troubleshooting

| Issue                | Solution                                                                                          |
| -------------------- | ------------------------------------------------------------------------------------------------- |
| `command not found`  | Ensure pip's script directory is on `PATH`, or reinstall with uv                                  |
| `401 Unauthorized`   | Run `aip accounts add <name>` and `aip accounts use <name>`, or update your environment variables |
| `404 Not Found`      | Check your API URL with `aip accounts show <name>`                                                |
| `Connection refused` | Confirm the remote AIP server is reachable                                                        |
| `uv not found`       | Install uv: `curl -LsSf https://astral.sh/uv/install.sh \| sh`                                    |

## Next Steps

## Suggested Sequence

1. Complete either the [Python SDK quick start](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide/python-sdk) or [CLI quick start](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide/cli).
2. Confirm at least one successful response from your agent.
3. Move to the corresponding guide track: [Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents), [Tools](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools), [MCPs](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/mcps).

## Troubleshooting Quick Checks

| Issue                       | Fast fix                                                                                     |
| --------------------------- | -------------------------------------------------------------------------------------------- |
| `command not found` (`aip`) | Ensure pip's script directory is on `PATH`, or reinstall using `uv tool install glaip-sdk`   |
| `401 Unauthorized`          | Run `aip accounts add <name>` and `aip accounts use <name>`, or update environment variables |
| `404 Not Found`             | Verify API URL with `aip accounts show <name>`                                               |
| `Connection refused`        | Confirm AIP server reachability and network/proxy settings                                   |
| `uv not found`              | Install uv: `curl -LsSf https://astral.sh/uv/install.sh \| sh`                               |

## What to Read Next

1. [Hands-on examples](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/hands-on-examples) for runnable patterns.
2. [Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) for lifecycle and runtime controls.
3. [Configuration management](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) for export/import promotion loops.
4. [CLI reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands) for flags and automation.


# Python SDK

*When to use:* You are coding in Python, iterating from notebooks or applications, and want typed helpers during development.

### Step 1: Install or Upgrade the Package

```bash
# Standard install (includes local execution)
pip install --upgrade "glaip-sdk[local]"

# Or install without local extra (remote execution only)
pip install --upgrade glaip-sdk
```

### Step 2: Create and Run Your First Agent Locally

Ensure you installed `glaip-sdk[local]` and set your LLM provider key (for example `OPENAI_API_KEY`) before running locally.

```python
from glaip_sdk import Agent

agent = Agent(
    name="hello-world-agent",
    instruction="You are a friendly AI assistant.",
)

response = agent.run("Hello! How are you today?")
print(response)
```

### Step 3: Specify a Model (Optional)

By default, agents use `openai/gpt-5-nano`. You can specify a different model using the standardized `provider/model` format:

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

# Using model constants (recommended)
agent = Agent(
    name="hello-world-agent",
    instruction="You are a friendly AI assistant.",
    model=OpenAI.GPT_5_MINI,  # "openai/gpt-5-mini"
)

# Or using string format
agent = Agent(
    name="hello-world-agent",
    instruction="You are a friendly AI assistant.",
    model="deepinfra/Qwen/Qwen3-30B-A3B",
)

response = agent.run("Hello! How are you today?")
print(response)
```

### Step 4: Optional: Connect to AIP Server

If you want to run against the remote AIP server instead of using `aip-agents` locally, add your API details to a `.env` file:

```bash
echo "AIP_API_URL=https://your-aip-instance.com" >> .env
echo "AIP_API_KEY=your-api-key-here" >> .env
```

When targeting the AIP server, call `agent.deploy()` once before running:

```python
agent.deploy()
response = agent.run("Hello! How are you today?")
```

The SDK reads `AIP_API_URL` and `AIP_API_KEY` from the environment when deploying and running agents.

**Optional Next Steps**

* Attach a tool (see the [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools)) and rerun the agent.
* Attach a file with `agent.run(..., files=["/path/to/file.pdf"])` and follow the [File processing guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/file-processing).
* Persist conversation context with `chat_history` or `agent_config.memory` (covered in the [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents)).


# CLI

*When to use:* You need zero-code validation, quick demos, or scripted runs that operate from any shell.

{% hint style="info" %}
Looking for CLI pages beyond this quick start (accounts, agents, tools, MCPs, transcripts)? Start at the [CLI section](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli).
{% endhint %}

### Step 1: Install or Upgrade the Package

```bash
pip install --upgrade glaip-sdk
```

Or use `uv tool install glaip-sdk` if you prefer uv.

### Step 2: Configure Credentials

```bash
aip accounts add prod
aip accounts use prod
```

### Step 3: Create and Run Your First Agent

```bash
# Create agent
aip agents create \
  --name "hello-world-agent-123" \
  --instruction "You are a friendly AI assistant."

# Run the agent (use the ID or name shown in the create output)
aip agents run 49874068-f2e7-42b4-878d-ef545db5a110 "Hello! How are you today?"
# or
aip agents run "hello-world-agent-123" "Hello! How are you today?"
```

This creates and runs your first agent using the CLI. The `create` output shows both the agent ID and name—use either in the run command.

#### Optional: Run from the Slash Command Palette

Launch the palette and select `/agents` to pick and run your new agent:

```bash
aip
```

Inside the palette, choose `/agents`, select your agent, and provide the prompt inline. See the [CLI Slash Palette](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-slash-palette) reference for screenshots and deeper guidance.

{% hint style="info" %}
Screenshot placeholder: palette home screen with `/` completions open.
{% endhint %}

{% hint style="info" %}
Replace the sample ID or name with the values shown in your `aip agents create` output. If you have multiple agents with similar names, use the full ID to avoid confusion.
{% endhint %}

#### Optional Next Steps

* Add a tool with `aip tools create` and `aip agents update --tools ...` (details in the [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools)).
* Attach files during runs with `aip agents run <AGENT_REF> --input "Review" --file report.pdf` and consult the [File processing guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/file-processing).
* Reuse context by passing `--chat-history` JSON; see the [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) for examples.
* For prompt/export iteration, jump to the [Configuration management guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) which walks through the full export → edit → import loop.


# Guides

Use guides when you are building real workflows and need focused implementation guidance.

### Start With Topics

* [Topics](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/topics) gives the fastest map across build, run, operate, and integrate tasks.

### Guide Clusters

* Build agents and capabilities: [Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents), [A2UI](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/a2ui), [Tools](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools), [MCPs](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/mcps), [Language models](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/language-models), [Agent evaluations](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agent-evaluations), [GL Connectors best practices](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/gl-connectors-best-practices)
* Runtime operations: [File processing](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/file-processing), [HITL approvals](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/human-in-the-loop-approvals), [Automation and scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting)
* Governance and security: [Security and privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy), [Agent content guardrails](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agent-content-guardrails), [Multi-account management](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/multi-account-management)

Need exact command and payload details? Jump to [Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference).

After guides, move to [CLI](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli) for use-case command workflows that support agent development.


# Topics

Dive deeper into AIP capabilities with focused guides. The default path is Python SDK first. REST is reference-only for integrators.

> **Success**
>
> **Latest DX defaults (2026):**
>
> * Build and run with `Agent(...)` first.
> * Use CLI for low-code operational workflows.
> * Treat `Client` snippets as legacy/advanced admin paths (bulk listing, migration, workspace governance).

### Build

* [**Agents guide**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Define agents with `Agent(...)`, deploy, and run.
* [**A2UI guide**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/a2ui) — Build interactive UI flows for remote agents.
* [**Tools guide**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) — Attach tools (native and custom) and manage tool configs.
* [**MCPs guide**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/mcps) — Configure MCPs and attach them to agents.
* [**Skills guide**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/skills) — Package skills and activate them on agents or runs.
* [**Language models guide**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/language-models) — Choose models and apply overrides.
* [**GL Connectors best practices**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/gl-connectors-best-practices) — Choose between APIs, tools, MCP servers, and Skills.

### Run

* [**File processing**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/file-processing) — Attach files, reuse chunks, and capture artifacts.
* [**Agent filesystem**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agent-filesystem) — Enable `read_file`/`write_file`/`edit_file`/`ls`/`grep` workflows in runtime.
* [**Programmatic tool calling**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/programmatic-tool-calling) — Run PTC workflows with sandboxing.
* [**Human-in-the-loop approvals**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/human-in-the-loop-approvals) — Pause and resume runs with manual decisions.
* [**Audio interface**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/audio-interface) — Speak to local agents while keeping tool calls visible (optional).

### Operate

* [**Security & privacy**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — PII masking, secrets, data handling.
* [**Agent content guardrails**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agent-content-guardrails) — Filter and block harmful content.
* [**Configuration management**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) — Export/import resources and promote changes.
* [**Automation & scripting**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — CI scripting and schedules.
* [**Multi-account management**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/multi-account-management) — Current account boundaries and roadmap.

### Integrate

* [**LangFlow integration**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/langflow) — Sync boards and run flows as agents.

### Patterns

* [**Multi-agent system patterns**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns) — Sequential, parallel, router, hierarchical, loop, aggregator.

### Interfaces (Links Only)

* [**Python SDK reference**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk) — signatures and models.
* [**CLI**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli) — low-code ops workflows.
* [**REST API reference**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api) — integration surface for internal apps like GLChat.

### Keep Exploring

* Revisit [Introduction to GL AIP](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/introduction-to-gl-aip) for personas, capability matrices, and navigation tips.
* Jump to the [Reference section](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference) for API, SDK, and CLI command listings.


# 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-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-ai-agent-package/getting-started/local-vs-remote) for detailed comparison and decision checklist.

### 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`             | `None`        | Model selector (e.g., `"openai/gpt-5-nano"`): symbolic `provider/model` resolves seeded AIP models on remote deployment; UUID-shaped values bind exactly to a remote language model. |
| `filesystem`   | `bool \| FilesystemConfig` | `True`        | Enable filesystem middleware for local runs.                                                                                                                                         |
| `guardrail`    | `GuardrailManager`         | `None`        | Content safety guardrail manager.                                                                                                                                                    |
| `ptc`          | `PTC`                      | `None`        | Programmatic tool calling (sandbox code execution) config.                                                                                                                           |
| `timeout`      | `int`                      | `300`         | Execution timeout in seconds (5 min).                                                                                                                                                |
| `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.                                                                                                                                                           |

> **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, symbolic `model=` values (e.g., `"openai/gpt-5.2"`, `OpenAI.GPT_5_2`) resolve against **seeded AIP models only** (`account_id = null`). UUID-shaped values (e.g., `"fc945f0a-595e-471f-807c-47334c0eba9f"`) bind exactly to that language model. See [Language models](https://gdplabs.gitbook.io/sdk/gl-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
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="sk-xxxx",
        hyperparameters={
            "temperature": 1.0,
            "max_tokens": 32768,
        },
    ),
)
```

{% 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-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, Tool

agent = Agent(
    name="invoice-agent",
    instruction="Extract invoice totals and payment terms.",
    tools=[Tool.from_native("invoice_reader")],
    tool_configs={
        "invoice_reader": {
            "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 %}

{% 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

**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
* **Tool helper instance**: `{Tool.from_native("time_tool"): {"param": "value"}}` — a `Tool` reference
* **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, Tool

# 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" %}
**Agent timeout vs tool resilience timeout — the key relationship**

The enclosing agent (or sub-agent) run timeout always governs the total execution budget. Setting `tool_configs[*].resilience.timeout_seconds` to a value larger than `agent_config["timeout_seconds"]` will **not** extend the agent run. If your tool needs 1200s to complete, the agent timeout must also be at least 1200s. This applies to every agent in a multi-agent workflow — each one must have sufficient timeout individually.
{% endhint %}

### Timeouts and Limits

#### Timeout layers

| Layer                                                     | Setting                                         | Default                                                                                                                                  | Description                                                                                                                                                                 |
| --------------------------------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Agent default (`Agent(...)`)                              | `Agent.timeout` property                        | `300` (5 min)                                                                                                                            | Returned by `Agent.timeout` when no `timeout=` or agent\_config timeout keys are provided                                                                                   |
| CLI command default (`agent run`/normal `agent create`)   | `DEFAULT_AGENT_RUN_TIMEOUT` (constant)          | `86400` (24h)                                                                                                                            | CLI fallback when no `--timeout` flag is given; normal `agent create` omits this default from the stored config unless the user provides a non-default value or imports one |
| Client create default (`client.agents.create_agent(...)`) | `DEFAULT_AGENT_RUN_TIMEOUT` (constant)          | `86400` (24h)                                                                                                                            | SDK client fallback when no `timeout=` argument is given; persisted as `agent_config["timeout_seconds"]` in the create request                                              |
| Persisted agent config                                    | `agent_config["timeout_seconds"]`               | `300` (when set via `Agent(...)`); `86400` (when omitted via `client.agents.create_agent(...)`); explicit CLI/import value when provided | Injected by the SDK at construction/request time; when absent the platform runner applies its own fallback                                                                  |
| Runner fallback hard cap                                  | Platform-specific                               | `3600` (1h) on AIP                                                                                                                       | Hard cap applied by the AI Agent Platform when `timeout_seconds` is absent from the stored agent config                                                                     |
| Tool resilience                                           | `tool_configs[*].resilience.timeout_seconds`    | Per-tool default                                                                                                                         | Inner budget for a single tool execution (including retries); does **not** extend the enclosing agent run timeout                                                           |
| Per-agent (multi-agent)                                   | `agent_config["timeout_seconds"]` on each agent | Per-agent config                                                                                                                         | Each agent (coordinator and sub-agents) must have sufficient timeout individually                                                                                           |

{% hint style="info" %}
**Default persistence:** When you set `timeout=N` on `Agent(...)`, the value is persisted as `agent_config["timeout_seconds"]` in the stored agent definition. If you omit `timeout`, the `Agent` property defaults to `300` (5 min) and that default is persisted as `agent_config["timeout_seconds"]` in the stored agent definition. When `timeout_seconds` is absent from the stored agent config, the platform runner applies its own fallback hard cap (3600s on AIP).

The SDK constant `DEFAULT_AGENT_RUN_TIMEOUT` (86400) is used by CLI run/create commands and by the lower-level `client.agents.create_agent(...)` path, not by the `Agent(...)` constructor. For normal CLI `agent create` flows, the CLI strips the unchanged 86400 default before creating the agent, so the stored agent config omits `timeout_seconds` unless you explicitly provide a non-default `--timeout` value or import a config that already carries a timeout. The lower-level `client.agents.create_agent(...)` path does not perform that CLI stripping; when `timeout` is omitted it uses `DEFAULT_AGENT_RUN_TIMEOUT` and persists `agent_config["timeout_seconds"] = 86400` in the create request.
{% endhint %}

#### Tool resilience timeout does not extend agent run timeout

Setting `tool_configs[*].resilience.timeout_seconds` configures the maximum execution budget for a single tool call (including retries). It does **not** extend the enclosing agent's run timeout. If the agent run timeout fires before the tool completes, the agent is terminated regardless of the tool's remaining resilience budget.

**Rule:** Always ensure `agent_config["timeout_seconds"]` >= the longest expected `tool_configs[*].resilience.timeout_seconds` across all tools the agent (or its sub-agents) may call.

#### Multi-agent timeout coordination

In a multi-agent workflow, each agent has its own independent timeout — there is no shared budget between coordinator and sub-agents. Every agent definition must carry sufficient timeout for the tools it may call.

```python
from glaip_sdk import Agent

researcher = Agent(
    name="researcher",
    instruction="Research the topic in depth.",
    timeout=3600,  # Must cover its longest potential tool execution
)
analyst = Agent(
    name="analyst",
    instruction="Analyse findings and produce a summary.",
    timeout=3600,
)
coordinator = Agent(
    name="coordinator",
    instruction="Delegate research and compile final briefs.",
    agents=[researcher, analyst],
    timeout=3600,  # Must cover delegation + tool execution + compilation
)
```

#### Setting the timeout

{% hint style="info" %}
**Setting timeout:**

* **Recommended:** Use `timeout=N` on `Agent(...)`, `client.agents.create_agent(...)`, or `client.agents.update_agent(...)`.
* **Canonical config field:** The SDK normalizes this to `agent_config["timeout_seconds"]`.
* **Alternative:** Set `agent_config["timeout_seconds"]` directly when editing config by hand.
* **Alias normalization priority:** `timeout_seconds` (canonical) > `timeout` (alias) > `execution_timeout` (legacy alias). Only `timeout_seconds` is the canonical persisted field; the aliases are normalized at construction time.
  {% endhint %}

{% hint style="info" %}
Only `timeout_seconds` is explicitly normalized by the SDK. Other `agent_config` keys are mostly forwarded as provided to the local runtime or backend, so the exact shape can depend on the runtime contract you are targeting.

The SDK documentation only makes a hard compatibility promise for `timeout_seconds` here; treat the remaining non-timeout keys as runtime-specific settings you should verify against the target runtime before depending on them.
{% endhint %}

**Canonical timeout field:**

| Key Path                          | Type          | Default                                                                                         | Range                | Description                 |
| --------------------------------- | ------------- | ----------------------------------------------------------------------------------------------- | -------------------- | --------------------------- |
| `agent_config["timeout_seconds"]` | int (seconds) | `300` (Agent default); `86400` (client create default); explicit CLI/import value when provided | Any positive integer | Total runtime for the agent |

**Example non-timeout key hierarchy shown above:**

All of the following live under `agent_config`, and the table shows their full paths so the nesting is explicit:

| Full Key Path                                               | Parent Section      | Type    | Example Value | Notes                                                                           |
| ----------------------------------------------------------- | ------------------- | ------- | ------------- | ------------------------------------------------------------------------------- |
| `agent_config["step_limit_config"]["max_steps"]`            | `step_limit_config` | `int`   | `100`         | Example step-limit key for runtimes that support nested step limit config       |
| `agent_config["step_limit_config"]["max_delegation_depth"]` | `step_limit_config` | `int`   | `5`           | Example delegation-depth key for runtimes that support nested step limit config |
| `agent_config["lm_retry_config"]["max_retries"]`            | `lm_retry_config`   | `int`   | `3`           | Example retry key for runtimes that support nested retry config                 |
| `agent_config["lm_retry_config"]["initial_delay"]`          | `lm_retry_config`   | `float` | `1.0`         | Example retry-delay key for runtimes that support nested retry config           |
| `agent_config["lm_retry_config"]["max_delay"]`              | `lm_retry_config`   | `float` | `30.0`        | Example retry-delay cap key for runtimes that support nested retry config       |
| `agent_config["lm_retry_config"]["exponential_base"]`       | `lm_retry_config`   | `float` | `2.0`         | Example backoff multiplier key for runtimes that support nested retry config    |

Use those as documented examples of `agent_config` structure, not as SDK-normalized fields.

#### Long-running agents

For agents that run extended workflows, ensure the agent timeout covers the longest expected tool execution:

* **Data analysis workflows:** If a custom tool needs 3600s (1h), set `timeout=3600` or `"timeout_seconds": 3600` — and ensure any sub-agents involved have the same or higher timeout.
* **Multi-step research:** Increase step limits for complex research with multiple tools.
* **Document processing:** Adjust delegation limits for hierarchical parsing.
* **Automated pipelines:** Configure retry settings for network or API rate limits.

For long running agents, consider monitoring progress through logs or implementing checkpoint mechanisms if supported by your agent tools.

#### Remote stream and infrastructure idle timeouts

When running agents on the AI Agent Platform, 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"]` |

### 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):** remote and local runs use different tool construction patterns.

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

remote_agent = Agent(
    name="remote-agent",
    instruction="Search records and summarize highlights.",
    tools=[Tool.from_native("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 the top-level token, and 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-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-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
agent = client.agents.get_agent_by_id("agent-123")
with open("agent-123.json", "w") as fh:
    fh.write(agent.model_dump_json(indent=2))
```

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


# A2UI

Build interactive UI experiences for remote agents by enabling A2UI on the agent, reading `metadata.a2ui_content` from the final response, and sending follow-up user actions back through the normal `/run` contract.

> **Success**
>
> **When to use this guide:** You want an agent to return structured UI metadata that your application can render, then continue the interaction through the standard remote run flow.
>
> **Who benefits:** Product engineers, frontend teams, and backend teams wiring remote agents into forms, confirmations, and other guided user experiences.

{% hint style="warning" %}
`glaip-sdk` does not currently provide dedicated A2UI helper objects. A2UI is a platform-side capability today: configure the agent through `agent_config.a2ui`, run it remotely, and consume the response contract directly.
{% endhint %}

### Quick Flow

A2UI fits into the same lifecycle you already use for remote agents:

1. Enable A2UI on the agent with `agent_config.a2ui`
2. Start a normal `/run`
3. Read `metadata.a2ui_content` from the final response
4. Render that UI in your client
5. When the user interacts with the UI, send the action back as a stringified JSON message through the normal `/run` contract

There is no separate follow-up transport to adopt.

### Enable A2UI On The Agent

Start with the SDK path below. If you are integrating directly at the HTTP layer, send the same `agent_config.a2ui` block in your normal agent create/update payload.

**Python SDK**

{% code lineNumbers="true" %}

```python
from glaip_sdk import Agent

agent = Agent(
    name="a2ui-restaurant-agent",
    instruction="Help the user and emit A2UI when useful.",
    model="openai/gpt-5.2",
    agent_config={
        "a2ui": {
            "enabled": True,
            "schema_version": "0.8",
        }
    },
)

agent.deploy()  # Required before remote runs
```

{% endcode %}

Core fields:

* `enabled`: turns A2UI on for the agent
* `schema_version`: currently `"0.8"`

REST clients send the same `agent_config.a2ui` block in the normal agent create or update payload.

### Run Contract

Use the normal remote run path. A2UI does not introduce a separate run API.

**Python SDK**

Use `trace=True` when you want the SDK to return an `AgentRunResult` so you can inspect `result.events` and read final-response metadata.

{% code lineNumbers="true" %}

```python
result = agent.run("Book me a dinner for two tomorrow night.", trace=True)

final_event = None
for event in reversed(result.events):
    metadata = event.get("metadata")
    if event.get("event_type") == "final_response":
        final_event = event
        break
    if isinstance(metadata, dict) and metadata.get("kind") == "final_response":
        final_event = event
        break

a2ui_content = (final_event or {}).get("metadata", {}).get("a2ui_content")
print(a2ui_content)
```

{% endcode %}

**Raw Contract Reference**

{% hint style="info" %}
For the curl examples below, set `AIP_API_URL` and `AIP_API_KEY` in your environment first. Use the deployed agent ID as `AGENT_ID`.
{% endhint %}

{% code lineNumbers="true" %}

```bash
curl \
  -N \
  -X POST "$AIP_API_URL/agents/$AGENT_ID/run" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $AIP_API_KEY" \
  -d '{"input":"Book me a dinner for two tomorrow night."}'
```

{% endcode %}

#### Final Response Metadata

When the agent emits A2UI, look for `metadata.a2ui_content` on the final response:

{% code lineNumbers="true" %}

```json
{
  "event_type": "final_response",
  "metadata": {
    "kind": "final_response",
    "a2ui_content": {
      "schema_version": "0.8",
      "messages": [
        {
          "beginRendering": {
            "surfaceId": "booking-form",
            "root": "root-column"
          }
        }
      ],
      "validation": {
        "status": "valid"
      }
    }
  }
}
```

{% endcode %}

The normal response shape stays the same. When A2UI is present, the UI payload appears in `metadata.a2ui_content`; when it is absent, the run behaves like a normal text interaction.

### Follow-Up User Actions

When a user interacts with rendered A2UI, serialize that action object and send it back through the normal `/run` contract.

Example action object:

{% code lineNumbers="true" %}

```json
{
  "name": "submit_booking",
  "surfaceId": "booking-form",
  "sourceComponentId": "submit-button",
  "timestamp": "2026-06-02T11:31:00Z",
  "context": {
    "to_email": "test@example.com"
  }
}
```

{% endcode %}

**Python SDK**

{% code lineNumbers="true" %}

```python
import json

action = {
    "name": "submit_booking",
    "surfaceId": "booking-form",
    "sourceComponentId": "submit-button",
    "timestamp": "2026-06-02T11:31:00Z",
    "context": {
        "to_email": "test@example.com",
    },
}

history = [
    {"role": "user", "content": "I want to send a hello world email."},
    {"role": "assistant", "content": "<actual stored assistant turn>"},
]

follow_up = agent.run(
    json.dumps(action),
    chat_history=history,
    trace=True,
)
```

{% endcode %}

**Raw Contract Reference**

REST clients should send the same stringified JSON action in `input` together with the normal `chat_history` field on `/agents/{agent_id}/run`.

Keep these rules in mind:

* Keep the conversation history on your side
* Preserve the assistant turn that produced the A2UI payload
* Send the next user interaction back as a plain JSON string in `input`

Replace the assistant placeholder above with the actual assistant turn your app stored from the response that produced the A2UI payload.

### Recommended Flow

1. Create or deploy an agent with `agent_config.a2ui`
2. Run the agent through the normal remote `/run` path
3. Read `metadata.a2ui_content` from the final response
4. Render the UI in your app
5. Store the real assistant turn and chat history in your app state
6. On the next user interaction, serialize the action object and send it as the next `/run` input

### Compatibility Notes

* Text-only agents still work normally
* A2UI is additive to the existing remote run contract
* `metadata.a2ui_content` is the product-facing output to consume
* The recommended follow-up pattern is stringified JSON user actions through the normal `/run` contract

### Related Documentation

* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — create, deploy, and run agents with the SDK and CLI.
* [REST API: Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/agents) — inspect the underlying remote run contract.
* [Guide topics](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/topics) — jump to neighboring setup, runtime, and integration guides.


# Language Models

AIP language models are catalog entries stored in `language_models`. They can be seeded (`account_id = null`) or owned by a tenant. This page reflects the current SDK behavior including the single model selector for remote agents.

{% hint style="info" %}
At a glance:

* Catalog CRUD is REST-based.
* `client.list_language_models()` and `aip models list` are read-only.
* `language_model_id` is the canonical REST API reference for shared catalog entries. SDK users should use `model="<uuid>"` instead.
* Legacy aliases (`provider`, `lm_name`, `lm_display_name`, and `agent_config.lm_provider/lm_name`) still work.
* API responses intentionally omit `base_url` and `credentials`.
* See the platform capability matrix for interface coverage and feature support.
  {% endhint %}

## SDK vs API Vocabulary

The page uses two related but different surfaces:

* **SDK local execution** uses `Agent(model=...)` and `Model(...)` for direct runtime config.
* **SDK remote deployment** uses a single `model=` selector: symbolic strings resolve seeded models only; UUID-shaped strings bind exactly to a `language_model_id`.
* **AIP API / server execution** uses `language_model_id` or `provider` + `model_name` to resolve a shared catalog entry.
* **Catalog records** use `lm_invoker_type`, `name`, and display/provider labels.

## Discover Language Models

Use this when you want to inspect what the current API key can see.

```python
from glaip_sdk import Client

client = Client()
for model in client.list_language_models(force_refresh=True):
    print(model["id"], model["provider_name"], model["display_name"])
```

```bash
aip models list
```

{% hint style="info" %}
Visibility depends on the API key:

* master key: seeded models by default, or any account with `account_id=<uuid>`
* tenant key: seeded models plus models owned by that tenant
  {% endhint %}

The list response includes the model UUID, provider labels, model name, display name, and hyperparameters. It does not include `base_url` or `credentials`.

`force_refresh=True` bypasses the SDK's short-lived list cache, which is useful immediately after you create or update a language model.

## Language Model Record Shape

### Canonical fields

| Field                   | Meaning                                                                             |
| ----------------------- | ----------------------------------------------------------------------------------- |
| `lm_invoker_type`       | Canonical runtime invoker. Examples: `openai`, `azure-openai`, `openai-compatible`. |
| `name`                  | Canonical model slug used by the invoker. Example: `gpt-4.1`, `Qwen/Qwen3-30B-A3B`. |
| `provider_name`         | Tenant-scoped unique key. Defaults to `<lm_invoker_type>-<name>`.                   |
| `provider_display_name` | Provider label shown in UI. Defaults to `provider_name`.                            |
| `display_name`          | Model label shown in UI. Defaults to `name`.                                        |
| `hyperparameters`       | Default model parameters like `temperature`, `top_p`, or reasoning config.          |
| `base_url`              | Optional provider endpoint.                                                         |
| `credentials`           | API key or other secret material. Hidden from API responses.                        |

### Accepted aliases

| Canonical field   | Accepted alias    |
| ----------------- | ----------------- |
| `lm_invoker_type` | `provider`        |
| `name`            | `lm_name`         |
| `display_name`    | `lm_display_name` |

{% hint style="warning" %}
For `openai-compatible`, slash-qualified names are accepted as-is. For other invokers, slash-qualified names must match the invoker prefix.
{% endhint %}

### Defaulting behavior

The service fills in values when they are omitted:

| Missing field           | Default                    |
| ----------------------- | -------------------------- |
| `provider_name`         | `<lm_invoker_type>-<name>` |
| `provider_display_name` | `provider_name`            |
| `display_name`          | `provider_name`            |
| `hyperparameters`       | `{}`                       |

## Create, Update, Delete

Use the REST API for catalog writes. The auth key decides whether the record is seeded or tenant-owned.

{% hint style="warning" %}
The examples below use placeholders only. Never place real credentials in docs, scripts, or shell history. Load them from environment variables or a secret store.
{% endhint %}

### Create

```bash
curl --location "$AIP_API_URL/language-models/" \
  --header "Content-Type: application/json" \
  --header "X-API-Key: $AIP_API_KEY" \
  --data '{
    "lm_invoker_type": "openai-compatible",
    "name": "google/gemma-4-31B-it",
    "display_name": "Gemma 4 31B IT",
    "base_url": "https://api.deepinfra.com/v1/openai",
    "credentials": "your-api-key-here",
    "hyperparameters": {
      "temperature": 0.5,
      "top_p": 0.95
    }
  }'
```

### Update

Use `PUT /language-models/{lm_id}`. The payload is optional-by-field, so omitted fields are preserved.

```bash
curl --location --request PUT "$AIP_API_URL/language-models/$LM_ID" \
  --header "Content-Type: application/json" \
  --header "X-API-Key: $AIP_API_KEY" \
  --data '{
    "display_name": "Gemma 4 31B IT (AIP)",
    "hyperparameters": {
      "temperature": 0.2
    }
  }'
```

### Delete

```bash
curl --location --request DELETE "$AIP_API_URL/language-models/$LM_ID" \
  --header "X-API-Key: $AIP_API_KEY"
```

{% hint style="info" %}
Creation is scoped by the API key used:

* tenant key creates a tenant-owned model
* master key creates a seeded model

Updates and deletes are limited to the caller's scope.
{% endhint %}

### Response example

```json
{
  "id": "8cfc2f58-1f1e-4f38-b7d8-4a4e8df8ad5d",
  "account_id": null,
  "lm_invoker_type": "openai-compatible",
  "provider": "openai-compatible",
  "provider_name": "openai-compatible-google-gemma-4-31B-it",
  "provider_display_name": "openai-compatible-google-gemma-4-31B-it",
  "name": "google/gemma-4-31B-it",
  "lm_name": "google/gemma-4-31B-it",
  "display_name": "Gemma 4 31B IT",
  "lm_display_name": "Gemma 4 31B IT",
  "hyperparameters": {
    "temperature": 0.5,
    "top_p": 0.95
  }
}
```

## Scope Rules

| Action        | Master key                                               | Tenant key          |
| ------------- | -------------------------------------------------------- | ------------------- |
| List          | Seeded only by default, or any account with `account_id` | Seeded + own models |
| Get by ID     | Any model                                                | Seeded + own models |
| Create        | Seeded model                                             | Tenant-owned model  |
| Update/Delete | Seeded models only                                       | Own models only     |

The list endpoint also supports `account_id`, `offset`, `limit`, and deprecated `skip`.

## Validation Rules

The current backend validates these rules on create/update:

1. `lm_invoker_type` or legacy `provider` must be present on create.
2. `name` or legacy `lm_name` must be present on create.
3. If both canonical and legacy aliases are provided, they must match.
4. `provider_name`, `provider_display_name`, and `display_name` must be unique within the current account scope.
5. Seeded models (`account_id = null`) also enforce unique `(lm_invoker_type, name)` pairs.
6. `openai-compatible` allows slash-qualified model names without matching the invoker prefix rule.
7. Other invokers require slash-qualified names to start with the invoker prefix.

### Common validation examples

```json
{
  "lm_invoker_type": "openai",
  "name": "gpt-4o",
  "provider_name": "my-openai-model",
  "display_name": "My OpenAI Model"
}
```

```json
{
  "lm_invoker_type": "anthropic",
  "provider": "anthropic",
  "name": "claude-sonnet-4-5"
}
```

```json
{
  "lm_invoker_type": "openai",
  "provider": "anthropic",
  "name": "claude-sonnet-4-5"
}
```

## Attach Models to Agents

### SDK (Python)

The SDK exposes a single `model=` selector on `Agent(...)` and `agent.update()`:

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

agent = Agent(
    name="support-agent",
    instruction="Help customers.",
    model=OpenAI.GPT_5_NANO,
)

agent = Agent(
    name="support-agent",
    instruction="Help customers.",
    model="fc945f0a-595e-471f-807c-47334c0eba9f",
)
```

See [SDK Model Selection](#sdk-model-selection) for the full resolution semantics.

### REST API

For config agents, the API accepts exactly one language-model mechanism:

1. `language_model_id`
2. `provider` + `model_name`
3. legacy `agent_config.lm_provider` + `agent_config.lm_name`

`language_model_id` is the canonical choice for shared catalog entries.

```json
{
  "name": "support-agent",
  "type": "config",
  "framework": "langchain",
  "language_model_id": "<uuid>"
}
```

```json
{
  "name": "support-agent",
  "type": "config",
  "framework": "langchain",
  "provider": "openai",
  "model_name": "gpt-4.1"
}
```

```json
{
  "name": "support-agent",
  "type": "config",
  "framework": "langchain",
  "agent_config": {
    "lm_provider": "openai",
    "lm_name": "gpt-4.1"
  }
}
```

{% hint style="info" %}
`a2a` and `langflow` agents may omit language-model fields. `config` agents must specify one mechanism only.
{% endhint %}

## Agent Workflows

### Direct ID

Use this when the catalog entry already exists.

```json
{
  "name": "analysis-agent",
  "type": "config",
  "framework": "langchain",
  "language_model_id": "fc945f0a-595e-471f-807c-47334c0eba9f"
}
```

### Provider and model name

Use this when the server-side catalog has a seeded master entry.

```json
{
  "name": "analysis-agent",
  "type": "config",
  "framework": "langchain",
  "provider": "openai",
  "model_name": "gpt-4.1"
}
```

### Legacy agent\_config

Use this only if you are still migrating old payloads.

```json
{
  "name": "analysis-agent",
  "type": "config",
  "framework": "langchain",
  "agent_config": {
    "lm_provider": "openai",
    "lm_name": "gpt-4.1"
  }
}
```

## SDK Model Selection

The SDK exposes a single `model=` parameter on `Agent(...)` and `agent.update()`. How it behaves depends on the execution mode and the value shape:

### Local execution

For local runs, `model=` is used directly by the `aip-agents` runtime — no catalog lookup involved.

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

agent = Agent(name="analysis", instruction="You are a precise analyst.", model=OpenAI.GPT_5_2)
result = agent.run("Analyze this data")
```

Accepted formats: model constants (shown above), string (`"openai/gpt-5.2"`), or `Model(...)` for custom endpoints. See [String Format](#string-format) and [Custom Model Objects](#custom-model-objects) for details.

### Remote deployment

When deploying to AIP, `model=` has two modes:

| `model=` shape                                  | Resolution                                                        | Scope                                      |
| ----------------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------ |
| Symbolic (`"openai/gpt-5.2"`, `OpenAI.GPT_5_2`) | Resolves against **seeded AIP models only** (`account_id = null`) | Platform-provided models                   |
| UUID (`"fc945f0a-595e-471f-807c-47334c0eba9f"`) | Exact binding to `language_model_id`                              | Any visible model (seeded or tenant-owned) |

**Symbolic (seeded-only):**

```python
agent = Agent(
    name="analysis-agent",
    instruction="You are a precise analyst.",
    model="openai/gpt-5.2",
)
agent.deploy()
```

If no seeded model matches, the SDK raises `ValueError: Seeded language model '...' not found`.

**UUID (exact binding):**

```python
# UUID is for remote deployment only — local runs have no catalog to resolve against
agent = Agent(
    name="analysis-agent",
    instruction="You are a precise analyst.",
    model="fc945f0a-595e-471f-807c-47334c0eba9f",
)
agent.deploy()
```

The UUID is sent directly as `language_model_id` with no symbolic resolution or fallback.

### Updating an agent

The same rules apply on update:

```python
agent.update(model="openai/gpt-5.2")

agent.update(model="fc945f0a-595e-471f-807c-47334c0eba9f")
```

{% hint style="info" %}
Symbolic updates resolve against seeded AIP models only and fail fast when no seeded match exists. UUID-shaped values bind exactly, including tenant-owned rows.
{% endhint %}

## Model Constants in the SDK

Use typed constants when you want IDE support and stable names.

{% hint style="info" %}
These are plain Python classes with class attributes, not enums. The SDK currently ships constants through `GPT_5_2`; newer platform seed names may appear in the backend before SDK constants are added.
{% endhint %}

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

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

agent = Agent(
    name="research",
    instruction="You are a research assistant.",
    model=DeepInfra.KIMI_K2_INSTRUCT,  # resolves to "deepinfra/moonshotai/Kimi-K2-Instruct"
)

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

**Available constants:**

| Provider     | Import                                     | Examples                                                           |
| ------------ | ------------------------------------------ | ------------------------------------------------------------------ |
| OpenAI       | `from glaip_sdk.models import OpenAI`      | `GPT_5_NANO`, `GPT_5_2`, `GPT_4O`, `O4_MINI`                       |
| Anthropic    | `from glaip_sdk.models import Anthropic`   | `CLAUDE_3_7_SONNET_LATEST`, `CLAUDE_SONNET_4_5`, `CLAUDE_OPUS_4_1` |
| Google       | `from glaip_sdk.models import Google`      | `GEMINI_2_5_FLASH`, `GEMINI_3_FLASH_PREVIEW`, `GEMINI_2_5_PRO`     |
| Azure OpenAI | `from glaip_sdk.models import AzureOpenAI` | `GPT_4O`, `GPT_4O_MINI`, `GPT_4_1`                                 |
| DeepInfra    | `from glaip_sdk.models import DeepInfra`   | `KIMI_K2_INSTRUCT`, `QWEN3_30B_A3B`, `GLM_4_5`                     |
| DeepSeek     | `from glaip_sdk.models import DeepSeek`    | `DEEPSEEK_CHAT`, `DEEPSEEK_V3_1`                                   |
| AWS Bedrock  | `from glaip_sdk.models import Bedrock`     | `CLAUDE_SONNET_4_20250514_V1_0`, `CLAUDE_SONNET_4_5_20250929_V1_0` |

The current default model is `OpenAI.GPT_5_NANO`.

## String Format

Use the standardized `provider/model` format when you do not want to rely on constants. Bare model names like `gpt-4o` still work, but they emit a deprecation warning.

```python
from glaip_sdk import Agent

agent = Agent(
    name="analysis",
    instruction="You are a precise analyst.",
    model="openai/gpt-5.2",
)

agent = Agent(
    name="research",
    instruction="You are a research assistant.",
    model="deepinfra/moonshotai/Kimi-K2-Instruct",
)

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

```bash
aip agents create \
  --name analysis \
  --instruction "You are a precise analyst." \
  --model openai/gpt-5.2
```

{% hint style="info" %}
**Format patterns:**

* **OpenAI:** `openai/<model>` -> `openai/gpt-5.2`, `openai/gpt-5-nano`
* **DeepInfra:** `deepinfra/<org>/<model>` -> `deepinfra/moonshotai/Kimi-K2-Instruct`
* **DeepSeek:** `deepseek/<org>/<model>` -> `deepseek/deepseek-ai/DeepSeek-V3.1`
* **Anthropic:** `anthropic/<model>` -> `anthropic/claude-sonnet-4-5`
* **Google:** `google/<model>` -> `google/gemini-3-flash-preview`
* **Azure OpenAI:** `azure-openai/<model>` -> `azure-openai/gpt-4.1`

Some seeded catalog entries may use shorter names (e.g., `deepinfra/Qwen3-30B-A3B` without the org prefix) while the SDK constant resolves to the full path (`deepinfra/Qwen/Qwen3-30B-A3B`). Both forms exist in the catalog; use the constant or verify with `aip models list`.

Invalid formats (missing `/`) raise a `ValueError` with suggestions to use model constants.
{% endhint %}

## Custom Model Objects

When you need credentials, a base URL, or hyperparameters that do not belong in the shared catalog, use `Model`.

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

agent = Agent(
    name="kimi-agent",
    instruction="You are a helpful AI assistant.",
    model=Model(
        id="custom/kimi-k2.5",
        base_url="https://api.moonshot.ai/v1",
        credentials="sk-xxxx",
        hyperparameters={
            "temperature": 1.0,
            "max_tokens": 32768,
            "top_p": 0.95,
        },
    ),
)
```

{% hint style="info" %}
`Model.id` still uses the same `provider/model` style. Use `custom/<name>` for ad hoc or local-only endpoints.
{% endhint %}

### DeepInfra example

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

agent = Agent(
    name="custom-deepinfra",
    instruction="You are a helpful assistant.",
    model=Model(
        id="deepinfra/moonshotai/Kimi-K2-Instruct",
        credentials="your-deepinfra-api-key",
        hyperparameters={
            "temperature": 0.7,
            "max_tokens": 4096,
        },
    ),
)
```

{% hint style="warning" %}
Credential precedence:

1. `Model.credentials`
2. environment variables like `DEEPINFRA_API_KEY` or `OPENAI_API_KEY`
3. credential files or default locations
   {% endhint %}

## Local vs Remote Execution

*When to use:* understand how configuration behaves when switching between `agent.run()` and `agent.deploy()`.

| Execution mode            | Model config                                                     | Behavior                                                                                                                        |
| ------------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Local (`agent.run()`)     | `Model` object with `base_url`, `credentials`, `hyperparameters` | Full configuration is used directly by `aip_agents`                                                                             |
| Local                     | String like `deepinfra/moonshotai/Kimi-K2-Instruct`              | SDK resolves `base_url` from built-in provider mappings; credentials come from env vars or explicit fields                      |
| Remote (`agent.deploy()`) | Symbolic `model=` (e.g., `"openai/gpt-5.2"`)                     | SDK resolves against **seeded models only** and sends `language_model_id`; fails fast if no seeded match                        |
| Remote                    | UUID-shaped `model=`                                             | Exact binding to that `language_model_id`; no symbolic resolution                                                               |
| Remote                    | `Model` object or string                                         | Unwrapped to symbolic/UUID form and resolved as above; local-only fields (`credentials`, `base_url`) are ignored with a warning |

### Local execution with a known provider

```python
from glaip_sdk import Agent

agent = Agent(
    name="research",
    instruction="You are a research assistant.",
    model="deepinfra/moonshotai/Kimi-K2-Instruct",
)

result = agent.run("Research quantum computing")
```

### Switching to remote

```python
from glaip_sdk import Agent

agent = Agent(
    name="my-agent",
    instruction="You are helpful.",
    model="openai/gpt-5.2",
)

# Local: uses your env credentials
result = agent.run("Hello!")

# Deploy: SDK resolves "openai/gpt-5.2" against seeded models only
agent.deploy()

# Remote: uses server-side catalog credentials
result = agent.run("Hello!")
```

{% hint style="warning" %}
Local and remote execution are isolated:

* local config uses your environment
* remote config uses the AIP server catalog and its credentials
* changing local config does not change a deployed agent until you deploy again
* symbolic `model=` resolves seeded-only for remote — use a UUID for tenant-owned models
  {% endhint %}

## Hyperparameter Resolution for Remote Execution

When running agents remotely, the platform builds effective hyperparameters by **deep-merging** multiple sources in priority order:

| Priority    | Source                      | Description                                                     |
| ----------- | --------------------------- | --------------------------------------------------------------- |
| 1 (lowest)  | Language model row defaults | `hyperparameters` stored on the linked `language_models` record |
| 2           | Persisted agent overrides   | `agent_config.lm_hyperparameters` persisted on the agent        |
| 3 (highest) | Flat `lm_*` overrides       | Legacy `lm_temperature`, `lm_top_p`, etc. from `agent_config`   |

### Deep-merge semantics

Nested objects are merged recursively — sibling keys from the model row defaults are preserved when only a nested branch is overridden:

```json
// LM row defaults
{
  "temperature": 0.2,
  "top_p": 0.9,
  "reasoning": {"effort": "medium", "summary": "auto"}
}

// agent_config.lm_hyperparameters override
{
  "temperature": 0.7,
  "reasoning": {"effort": "high"}
}

// Effective result (deep-merged)
{
  "temperature": 0.7,
  "top_p": 0.9,
  "reasoning": {"effort": "high", "summary": "auto"}
}
```

Scalar override values replace the corresponding default. Empty override objects do not clear default sibling keys.

### Legacy resolution behavior

When legacy `agent_config.lm_provider` / `lm_name` is used to resolve the language model, the platform:

* Removes identity and connection fields only (`lm_provider`, `lm_name`, `lm_base_url`, `lm_credentials`, `lm_api_key`).
* Preserves `lm_hyperparameters` for the deep-merge step above.
* Preserves flat hyperparameter keys (e.g., `lm_temperature`) that contribute to the effective overrides.

This ensures persisted hyperparameter overrides are never silently dropped during legacy model resolution.

### Example

```json
{
  "name": "analysis-agent",
  "type": "config",
  "framework": "langchain",
  "language_model_id": "fc945f0a-595e-471f-807c-47334c0eba9f",
  "agent_config": {
    "lm_hyperparameters": {
      "temperature": 0.7,
      "reasoning": {"effort": "high"}
    }
  }
}
```

If the linked LM row has `{"temperature": 0.2, "top_p": 0.9, "reasoning": {"effort": "medium", "summary": "auto"}}`, the effective hyperparameters at execution time become:

```json
{
  "temperature": 0.7,
  "top_p": 0.9,
  "reasoning": {"effort": "high", "summary": "auto"}
}
```

## Using Catalog Models in AIP

If the model already exists in the AIP catalog, use the SDK's `model=` selector. Symbolic names resolve seeded models; UUIDs bind exactly.

```python
from glaip_sdk import Agent

agent = Agent(
    name="support-agent",
    instruction="Help customers.",
    model="fc945f0a-595e-471f-807c-47334c0eba9f",
)
agent.deploy()
```

Via REST, reference the `language_model_id` directly:

```json
{
  "name": "support-agent",
  "type": "config",
  "framework": "langchain",
  "language_model_id": "8cfc2f58-1f1e-4f38-b7d8-4a4e8df8ad5d"
}
```

If the model is not in the catalog yet, use the REST create endpoint and then re-list models before updating agents.

## Gemma and OpenAI-Compatible Providers

This is the path for Gemma-style usage when the provider exposes an OpenAI-compatible endpoint.

```bash
curl --location "$AIP_API_URL/language-models/" \
  --header "Content-Type: application/json" \
  --header "X-API-Key: $AIP_API_KEY" \
  --data '{
    "lm_invoker_type": "openai-compatible",
    "name": "google/gemma-4-31B-it",
    "display_name": "Gemma 4 31B IT",
    "base_url": "https://api.deepinfra.com/v1/openai",
    "credentials": "your-api-key-here",
    "hyperparameters": {
      "temperature": 0.2
    }
  }'
```

Seed data already includes DeepInfra-backed models such as `deepinfra/Kimi-K2-Instruct`, `deepinfra/Kimi-K2.5`, `deepinfra/Qwen3-30B-A3B`, `deepinfra/Qwen3-32B`, and `deepinfra/Qwen3-235B-A22B-Instruct-2507`.

## Seeded Model Examples

The current seed catalog includes these representative entries:

| Provider family | Examples                                                                                                                               |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| OpenAI          | `openai/gpt-5.4-mini`, `openai/gpt-5.4-nano`, `openai/gpt-5.2`, `openai/gpt-5.1`, `openai/gpt-5`                                       |
| Anthropic       | `anthropic/claude-3-5-sonnet-latest`, `anthropic/claude-3-7-sonnet-latest`, `anthropic/claude-sonnet-4-5`, `anthropic/claude-opus-4-1` |
| Google          | `google/gemini-2.5-flash`, `google/gemini-2.5-pro`, `google/gemini-3-flash-preview`, `google/gemini-3-pro-preview`                     |
| Azure OpenAI    | `azure-openai/gpt-4o`, `azure-openai/gpt-4o-mini`, `azure-openai/gpt-4.1`                                                              |
| DeepInfra       | `deepinfra/Kimi-K2-Instruct`, `deepinfra/Kimi-K2.5`, `deepinfra/Qwen3-30B-A3B`, `deepinfra/Qwen3-32B`, `deepinfra/GLM-4.5`             |
| DeepSeek        | `deepseek/deepseek-chat`, `deepseek/deepseek-ai/DeepSeek-V3.1`                                                                         |
| Bedrock         | `bedrock/us.anthropic.claude-sonnet-4-20250514-v1:0`, `bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0`                           |

## Troubleshooting

| Symptom                                             | Likely cause                                                                           | Fix                                                                                                           |
| --------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Agent still uses the old model                      | The deployed agent was not re-synced                                                   | Re-run `agent.deploy()` or update the agent payload and confirm the `language_model_id`                       |
| `400 Unknown model` errors                          | The model is not present in the target environment                                     | Use `client.list_language_models(force_refresh=True)` or `aip models list` and confirm the provider/name pair |
| `Seeded language model '...' not found`             | Symbolic `model=` has no seeded match in the current scope                             | Verify the model exists in `aip models list` with `account_id = null`, or use the UUID for exact binding      |
| `Provide exactly one exact language model selector` | Both `model=` and `language_model_id` were passed                                      | Use exactly one: symbolic/UUID `model=` or `language_model_id`, never both                                    |
| `Forbidden` on update/delete                        | You are mutating a model outside your scope                                            | Use the matching tenant key, or update a seeded model with a master key                                       |
| Missing `base_url` or `credentials` in the response | By design                                                                              | Fetch internal execution config through the service layer, not the public response                            |
| Duplicate model errors                              | Same scoped `provider_name`, `provider_display_name`, or `display_name` already exists | Rename the entry or update the existing record                                                                |
| Streaming stalls                                    | The chosen model or endpoint does not support it                                       | Disable streaming or choose a streaming-capable model                                                         |

## FAQ

### Should I use `language_model_id` or `provider` + `model_name`?

For the SDK, use the single `model=` selector:

* Symbolic (`"openai/gpt-5.2"` or `OpenAI.GPT_5_2`) for seeded models.
* UUID (`"fc945f0a-..."`) for exact binding to any visible model.

For REST payloads, use `language_model_id` for shared catalog entries. Use `provider` + `model_name` mainly when targeting a seeded master record by name.

### How do I bind a tenant-owned model?

Pass the language model UUID to `model=`:

```python
agent = Agent(name="my-agent", instruction="...", model="<language-model-uuid>")
agent.deploy()
```

Symbolic `model=` only resolves seeded models. If you need a tenant model by name, look up its UUID first with `client.list_language_models()`.

### What happens if a symbolic model has no seeded match?

The SDK raises `ValueError: Seeded language model '...' not found` before sending any request. This prevents silent binding to the wrong model.

### Can I create catalog entries from the CLI?

Not today. The CLI can list models, but catalog writes are REST-only.

### Can I keep using local custom endpoints?

Yes. Use `Model(...)` for local execution. If you need the same model in remote AIP execution, register it in the catalog first.

### What about `agent_config.lm_provider` and `agent_config.lm_name`?

They are legacy aliases that still resolve, but new payloads should prefer `language_model_id`.

## Related Documentation

* [Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) - attach `language_model_id` or legacy model selectors to agents
* [Python SDK reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk) - `client.list_language_models()`
* [REST API: Language Models](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/language-models) - catalog CRUD endpoints
* [CLI commands reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands) - list the catalog with `aip models list`
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) - script discovery and promotion across environments


# Tools

Extend agents with native catalog entries, custom uploads, and GL Connectors. This guide is SDK-first (Python). Use the CLI pages for operational registry workflows. Use the REST API reference only when integrating from internal apps (for example GLChat).

{% hint style="info" %}
Check tooling coverage in the [AIP capability matrix](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/introduction-to-gl-aip#platform-capabilities-at-a-glance). When you hit CLI gaps (metadata edits, tool configs, runtime overrides), use the Python SDK or export/import. REST details live in the reference section.
{% endhint %}

### When to Use Which Tool Pattern?

| Scenario                          | Recommended Pattern                                    | Remote deploy?                                      |
| --------------------------------- | ------------------------------------------------------ | --------------------------------------------------- |
| Rapid prototyping / Local testing | `Agent(..., tools=[ToolClass])`                        | No (Native tools require platform)                  |
| Platform development              | `Agent(..., tools=[ToolClass, Tool.from_native(...)])` | Yes (Custom tools bundled + uploaded automatically) |
| Manual registry management        | CLI (Client legacy admin API for automation)           | Yes (Direct code upload to registry)                |

{% hint style="info" %}
**Local Native Tool Parity**

When running agents locally, `Tool.from_native("tool_name")` automatically attempts to discover and use the corresponding local implementation from the `aip-agents` SDK. This allows you to test agents using platform tools without a remote connection, provided the `aip-agents` package is installed in your environment.
{% endhint %}

### Create and Attach Tools

Prefer the **Agent-First** pattern for development. It prioritizes **local execution** via `agent.run()` for rapid iteration, while `agent.deploy()` handles bundling and upload to the platform when you are ready.

#### Single-File Tool Integration

Assume your tool lives at `tool/calculator.py` within your project:

```python
# tool/calculator.py
import ast
import operator
from typing import Any
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field


ALLOWED_OPERATORS = {
    ast.Add: operator.add,
    ast.Sub: operator.sub,
    ast.Mult: operator.mul,
    ast.Div: operator.truediv,
    ast.Pow: operator.pow,
    ast.Mod: operator.mod,
    ast.USub: operator.neg,
}


def safe_arithmetic(expression: str) -> float:
    def _visit(node: ast.AST) -> float:
        if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
            return float(node.value)
        if isinstance(node, ast.BinOp) and type(node.op) in ALLOWED_OPERATORS:
            return ALLOWED_OPERATORS[type(node.op)](_visit(node.left), _visit(node.right))
        if isinstance(node, ast.UnaryOp) and type(node.op) in ALLOWED_OPERATORS:
            return ALLOWED_OPERATORS[type(node.op)](_visit(node.operand))
        raise ValueError("Unsupported expression")

    parsed = ast.parse(expression, mode="eval")
    return _visit(parsed.body)

class CalculatorArgs(BaseModel):
    expression: str = Field(..., description="Arithmetic expression to evaluate")

class CalculatorTool(BaseTool):
    name = "calculator"
    description = "Evaluates simple arithmetic expressions."
    args_schema = CalculatorArgs

    def _run(self, expression: str, **_: Any) -> str:
        try:
            return str(safe_arithmetic(expression))
        except ValueError:
            return "Only basic arithmetic expressions are supported."
```

You can then orchestrate it directly in your application. The SDK defaults to **local execution**, meaning `agent.run()` will execute the agent logic in your current environment using the `aip-agents` engine.

```python
# app.py
from glaip_sdk import Agent, Tool
from tool.calculator import CalculatorTool

agent = Agent(
    name="math-agent",
    instruction="You are a helpful math assistant",
    tools=[
        CalculatorTool,                # Custom tool (bundled automatically)
        Tool.from_native("time_tool"), # Native platform tool
    ],
)

agent.run("What is 2+2?")
```

#### Complex Tool Logic

When a tool requires complex logic, you can organize it across multiple files for better maintainability. During agent deployment (using the **`Agent(tools=[...])`** pattern), the SDK's automatic bundler detects and includes local imports—such as helper functions, services, or schemas—from your project into the uploaded tool source.

**Example structure:**

```
my_project/
  main.py
  tools/
    weather/
      __init__.py
      tool.py     # Exports WeatherTool
      service.py  # Contains helper logic
```

**Example `tools/weather/service.py`:**

```python
def get_mock_weather(city: str) -> str:
    return f"The weather in {city} is sunny."
```

**Example `tools/weather/tool.py`:**

```python
# Absolute import (recommended for portability)
from tools.weather.service import get_mock_weather
# OR Relative import (also supported)
# from .service import get_mock_weather

from langchain_core.tools import BaseTool

class WeatherTool(BaseTool):
    name = "weather_tool"
    description = "Gets weather info"

    def _run(self, city: str) -> str:
        # Bundler will include service.py automatically
        return get_mock_weather(city)
```

**Example `main.py`:**

```python
from glaip_sdk import Agent
from tools.weather.tool import WeatherTool

agent = Agent(
    name="weather-agent",
    instruction="Check the weather",
    tools=[WeatherTool],
)

agent.run("What's the weather in Tokyo?")
```

#### Modular Tools (Multiple Files)

For complex projects, you can organize multiple modular tools across your project. The SDK correctly resolves absolute imports and bundles the entire dependency tree.

```python
from glaip_sdk import Agent
from tools.flight_status import FlightStatusTool
from tools.stock_checker import StockCheckerTool
from tools.weather import WeatherTool

agent = Agent(
    name="travel-assistant",
    instruction="Help users with travel planning",
    tools=[WeatherTool, FlightStatusTool, StockCheckerTool],
)

agent.run("Check flight GA123 and weather in Bali.")
```

Refer to the [Modular Tool Integration](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/modular-tool-integration) example in the Cookbook for a full working implementation.

{% hint style="info" %}
**Absolute vs Relative Imports**

The SDK bundler supports both styles. For portable examples in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main), absolute imports (e.g., `from tools.weather.service import ...`) are used to ensure the tools work regardless of the user's local directory structure.
{% endhint %}

### Tool Implementation Expectations

When building custom tools for the AIP platform, ensure they meet the following technical requirements:

1. **BaseTool Inheritance**: All tools must inherit from LangChain's `BaseTool`.
2. **Metadata**: Tools must define `name` and `description` attributes.
3. **Schemas**: Tools must provide an `args_schema` (Pydantic model) for input validation.
4. **Standard I/O**: Runtime `stdout` and `stderr` are automatically captured and forwarded in the agent's event stream.

### Manage Tools

#### Registry Operations

For interactive, low-code tool registry workflows, use the CLI pages:

* CLI tools guide: [CLI: Tools](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/tools)
* CLI command reference: [CLI Commands Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands)

{% hint style="warning" %}
The `Client` examples in this section are legacy/advanced admin paths. For day-to-day product code, keep the Agent-first path as your default.
{% endhint %}

For automation and governance in Python, use the SDK client:

```python
from glaip_sdk import Client

client = Client()

tools = client.tools.list_tools()
for tool in tools:
    print(tool.id, tool.name, tool.type)
```

REST endpoints are documented in the reference section only:

* REST reference: [Tools](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/tools)

**Common errors and fixes**

| Symptom                               | Likely cause                                             | Fix                                                                                                                 |
| ------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `422 Unprocessable Entity` on upload  | Invalid metadata fields or missing BaseTool inheritance. | Validate the class inherits from LangChain BaseTool and includes required fields (name, description, args\_schema). |
| CLI upload hangs after progress bar   | Large dependency bundle or slow network upload.          | Remove unused dependencies/assets and retry. For internal integrations only, see the REST tools reference.          |
| Agent cannot run the tool at runtime  | Tool not attached, or config missing required keys.      | Re-run `aip agents update --tools` and verify `tool_configs` in the agent payload.                                  |
| `401 Unauthorized` when listing tools | API key scoped to viewer-only role.                      | Request a creator or runner key, or perform the action via an operator account.                                     |

#### GL Connectors and Managed Connectors

Remote-managed connectors (GL Connectors library) appear in the tool catalog with predefined IDs. Request enablement from the AIP operations team, then attach them like any other tool. Updates are handled centrally; monitor platform release notes and the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main) for refreshed implementation examples.

#### Tool Configuration (`tool_configs`)

Use `tool_configs` when a tool needs runtime configuration that shouldn't be hardcoded in its source — credentials, auth tokens, environment-specific settings, resilience policies, or HITL timeouts. This keeps tools reusable across agents and environments.

| Scenario                                                        | Configure via `tool_configs` |
| --------------------------------------------------------------- | ---------------------------- |
| Tool calls a database and needs a per-agent connection string   | `database_url`               |
| Tool needs a longer timeout because it processes large payloads | `resilience.timeout_seconds` |
| Tool should retry on transient upstream failures                | `resilience.retry`           |
| Tool should fast-fail when an upstream is down                  | `resilience.circuit_breaker` |
| Tool requires human approval before executing                   | `hitl.timeout_seconds`       |

`tool_configs` is an Agent-level dictionary that supplies per-tool configuration without modifying the tool's source code. Key each entry by the tool name or the tool class reference, and the SDK merges the config into every invocation of that tool.

```python
from glaip_sdk import Agent

agent = Agent(
    name="configurable-agent",
    instruction="Use configured tools.",
    tools=[MyTool, Tool.from_native("search_tool")],
    tool_configs={
        MyTool: {
            # Per-tool settings here
        },
        "search_tool": {
            # Config for the native tool by name
        },
    },
)
```

**What goes in a tool config:**

| Category                 | Example Keys                                                                   | Reference                                                                                                              |
| ------------------------ | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| Resilience policies      | `resilience.timeout_seconds`, `resilience.retry`, `resilience.circuit_breaker` | See below                                                                                                              |
| GL Connectors auth       | `GL_CONNECTORS_TOKEN`, `GL_CONNECTORS_API_KEY`                                 | [GL Connectors Best Practices](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/gl-connectors-best-practices) |
| HITL (Human-in-the-loop) | `hitl.timeout_seconds`                                                         | [HITL Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/human-in-the-loop-approvals)                    |
| User authentication      | `user_authentication: True`                                                    | [Agents Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents)                                       |
| Tool-specific parameters | `database_url`, `mode`, `timeout`                                              | Per-tool README                                                                                                        |

**Resolution order:**

1. **Definition config** — `tool_configs` passed to the `Agent()` constructor (base)
2. **Runtime config** — `runtime_config["tool_configs"]` in `agent.run()` (overrides definition)

```python
# Definition config (lowest priority)
agent = Agent(
    name="demo",
    instruction="...",
    tools=[MyTool],
    tool_configs={MyTool: {"mode": "default"}},
)

# Runtime config override (overrides definition)
agent.run(
    "Do something",
    runtime_config={
        "tool_configs": {
            "my_tool": {
                "tool_timeout_seconds": 5.0,
            }
        }
    },
)
```

See the [Agent Schema Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/agents#tool-configs-structure) for the full `tool_configs` schema. See the [Configuration Management Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) for managing configs across environments.

#### Tool Resilience

Protect agents from external service outages with per-tool timeout guardrails, bounded retry backoff, and circuit breakers. Use this section when tools call external endpoints such as GL Connectors, MCP servers, or custom APIs that can hang, fail transiently, or stay unavailable for extended periods.

{% hint style="info" %}
Tool resilience is configured entirely through `tool_configs` on the Agent. No changes to tool source code are required. Timeout, retry, and circuit breaker are independent layers, so you can enable them separately or combine all three.
{% endhint %}

**When to use tool resilience**

| Situation                                                                | Recommended layer                     |
| ------------------------------------------------------------------------ | ------------------------------------- |
| Tool calls hang for minutes (for example a slow upstream service)        | **Timeout**                           |
| Transient errors such as rate limits, short network blips, or 5xx spikes | **Retry**                             |
| A service stays down and you want fast-fail behavior until recovery      | **Circuit breaker**                   |
| Production workloads exposed to all of the above                         | **Timeout + Retry + Circuit breaker** |

**Timeout**

Every tool invocation runs under a deadline. If the tool exceeds its configured timeout, the agent receives a structured error instead of hanging indefinitely.

**Default behavior:** The default timeout is **60 seconds**. You get this protection automatically on every tool call.

**Override per tool:**

```python
from glaip_sdk import Agent
from tools.search import SearchTool

agent = Agent(
    name="search-agent",
    instruction="Search and summarise results.",
    tools=[SearchTool],
    tool_configs={
        SearchTool: {
            "resilience": {
                "timeout_seconds": 10.0,
            }
        }
    },
)

agent.run("Find the latest news on renewable energy.")
```

**Override at runtime:** Pass `tool_timeout_seconds` via `runtime_config` to override the configured value for a single invocation:

```python
agent.run(
    "Find recent papers on LLM alignment.",
    runtime_config={
        "tool_configs": {
            "search_tool": {
                "tool_timeout_seconds": 5.0,
            }
        }
    },
)
```

{% hint style="warning" %}
**Runtime override precedence:** `tool_timeout_seconds` in runtime config takes precedence over definition `tool_configs`. Invalid values (zero, negative, or non-numeric) are rejected and fail the call with a descriptive config error rather than silently falling back.
{% endhint %}

**Retry**

Enable retry to automatically re-attempt a failed tool call with exponential backoff. Retry is **disabled by default**.

**Basic retry setup:**

```python
from glaip_sdk import Agent
from tools.weather import WeatherTool

agent = Agent(
    name="weather-agent",
    instruction="Provide weather forecasts.",
    tools=[WeatherTool],
    tool_configs={
        WeatherTool: {
            "resilience": {
                "timeout_seconds": 15.0,
                "retry": {
                    "enabled": True,
                    "max_attempts": 3,
                    "backoff_min_seconds": 1.0,
                    "backoff_max_seconds": 8.0,
                },
            }
        }
    },
)
```

**Retryable error kinds:** By default, these error categories trigger a retry:

| Error kind             | Description                                 |
| ---------------------- | ------------------------------------------- |
| `timeout`              | Tool call exceeded its deadline             |
| `connection_error`     | TCP or socket connection failure            |
| `endpoint_unreachable` | DNS or routing failure                      |
| `upstream_5xx`         | HTTP 5xx response from the upstream service |
| `rate_limited`         | HTTP 429 response from the upstream service |

Authorization errors such as `unauthorized` and `forbidden` are **never retried** because they require operator action, not a retry loop.

{% hint style="info" %}
**Retry budget:** The total retry duration is capped by the tool's `timeout_seconds`. If starting another attempt would exceed the deadline, that attempt is skipped and the agent receives a `retry_exhausted` error.
{% endhint %}

**Circuit breaker**

The circuit breaker prevents repeated calls to a service that is already known to be down, returning fast-fail errors until the service recovers. Circuit breaking is **disabled by default**.

**How it works:**

| State                   | Behavior                                                                     |
| ----------------------- | ---------------------------------------------------------------------------- |
| **Closed** (normal)     | Calls are allowed through and failures are counted                           |
| **Open** (tripped)      | Calls fail immediately without contacting the service                        |
| **Half-open** (probing) | One probe call is allowed; success closes the circuit and failure reopens it |

**Basic circuit breaker setup:**

```python
from glaip_sdk import Agent
from tools.inventory import InventoryTool

agent = Agent(
    name="inventory-agent",
    instruction="Query product inventory.",
    tools=[InventoryTool],
    tool_configs={
        InventoryTool: {
            "resilience": {
                "timeout_seconds": 10.0,
                "circuit_breaker": {
                    "enabled": True,
                    "fail_max": 5,
                    "reset_timeout_seconds": 60.0,
                    "half_open_max_calls": 1,
                },
            }
        }
    },
)
```

**Configuration reference:**

| Key                     | Default | Description                                                        |
| ----------------------- | ------- | ------------------------------------------------------------------ |
| `fail_max`              | `5`     | Number of consecutive failures that trip the circuit open          |
| `reset_timeout_seconds` | `60.0`  | Seconds to wait in open state before probing with a half-open call |
| `half_open_max_calls`   | `1`     | Maximum concurrent probe calls allowed in half-open state          |

{% hint style="warning" %}
**Policy changes reset the breaker:** If you change `fail_max` or `reset_timeout_seconds` for a tool that already has an open circuit, the breaker resets to the closed state with the new policy. This is intentional because a policy change implies an explicit operator decision.
{% endhint %}

**Combining all three layers**

For production workloads that call external services, combine timeout, retry, and circuit breaker:

```python
from glaip_sdk import Agent
from tools.meemo import MeemoTool

agent = Agent(
    name="meemo-agent",
    instruction="Query the Meemo knowledge service.",
    tools=[MeemoTool],
    tool_configs={
        MeemoTool: {
            "resilience": {
                "timeout_seconds": 10.0,
                "retry": {
                    "enabled": True,
                    "max_attempts": 3,
                    "backoff_min_seconds": 1.0,
                    "backoff_max_seconds": 8.0,
                },
                "circuit_breaker": {
                    "enabled": True,
                    "fail_max": 5,
                    "reset_timeout_seconds": 60.0,
                    "half_open_max_calls": 1,
                },
            }
        }
    },
)

agent.run("Summarise the onboarding documentation.")
```

**Execution order per attempt:**

1. Circuit breaker checks whether the call is allowed and fast-fails if open.
2. The tool executes under the configured timeout deadline.
3. On failure, the SDK classifies the error kind.
4. If the error is retryable and budget remains, the next attempt starts from step 1.
5. On retry exhaustion or a non-retryable error, the circuit breaker records the failure.

**Observability**

Each tool response includes a `metadata.tool_execution` field with resilience diagnostics:

```json
{
  "result": "Tool call failed: circuit breaker is open",
  "metadata": {
    "tool_execution": {
      "category": "circuit_open",
      "circuit_state": "open",
      "last_error_kind": "endpoint_unreachable",
      "circuit_opened_at_unix_seconds": 1740654823.4,
      "circuit_reset_timeout_seconds": 60.0,
      "consecutive_failures": 5
    }
  }
}
```

#### MCP Tool Discovery

Use the SDK to inspect tools exposed by an MCP:

```python
from glaip_sdk import Client

client = Client()
tools = client.mcps.get_mcp_tools("mcp-id")
print([t.get("name") for t in tools])
```

Use the response to seed agent definitions or generate tool uploads where appropriate. The [MCP guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/mcps) covers credential rotation and live connection testing in detail.

#### Observability and Auditing

1. Use `aip tools get <TOOL_REF>` (or [CLI: Tools](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/tools)) to inspect tool metadata.
2. Use `aip agents list` to locate agents that reference a tool by name or by inspection.
3. Use the [Configuration management guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) to export/import tools alongside agents for promotion pipelines.

#### Best Practices

1. **Version your uploads** — keep source code in git and re-upload on change.
2. **Scope permissions** — custom tools run with the same rights as the agent execution environment; follow least-privilege principles.
3. **Validate inputs** — handle argument validation inside the tool to avoid unexpected failures mid-run.
4. **Set resilience policies for remote dependencies** — use timeout, retry, and circuit breaker for tools that call external services.
5. **Document configs** — record supported configuration keys in your README so teammates know how to set `tool_configs`.

### Production Readiness Checklist

Before deploying tools to production:

* [ ] All tools have required attributes: `name`, `description`, and `args_schema`
* [ ] Error handling is comprehensive in `_run()` methods
* [ ] Dependencies are minimal and well-documented
* [ ] Tool configs are documented in README
* [ ] External-facing tools have an explicit resilience policy
* [ ] Tools are tested with various input scenarios
* [ ] Source code is versioned in git
* [ ] Tool follows BaseTool inheritance pattern (no decorator needed)

#### Related Documentation

1. [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — attach tools, manage `tool_configs`, and run overrides.
2. [File processing](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/file-processing) — upload artifacts during agent runs and reuse chunk IDs.
3. [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — script tool creation and promotion in CI.


# MCPs

Model Context Protocol (MCP) connections let agents call external services while keeping credentials and transport details centralized. Use this guide when you need to create, manage, or validate MCP configurations with the Python SDK and the CLI. REST is reference-only and intended for internal integrations.

{% hint style="info" %}
Compare SDK and CLI support in the [AIP capability matrix](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/introduction-to-gl-aip#platform-capabilities-at-a-glance). REST details live in Resources as reference only.
{% endhint %}

{% hint style="info" %}
`aip mcps` commands accept either the MCP ID or a unique name. If multiple connections share similar names, prefer the explicit ID in scripts to avoid updating the wrong record.
{% endhint %}

### MCP Patterns

#### Recommended: MCP Object Pattern

Define MCPs directly using the `MCP` class and attach them to agents. This is the preferred pattern for day-to-day application code.

```python
from glaip_sdk import Agent, MCP

# Define MCP inline
weather_mcp = MCP(
    name="weather",
    transport="http",
    config={"url": "https://weather.example.com/mcp"},
    authentication={
        "type": "api-key",
        "key": "X-API-Key",
        "value": "secret-key",
    }
)

# Attach to agent
agent = Agent(
    name="weather-bot",
    instruction="You help users check the weather",
    mcps=[weather_mcp]
)

# Run locally - no deploy() needed for local execution
agent.run("What's the weather in Jakarta?", local=True)
```

**Reference existing MCPs by name or ID:**

```python
from glaip_sdk import Agent, MCP

# Reference by name (requires deploy() for remote)
agent = Agent(
    name="agent",
    instruction="...",
    mcps=[MCP.from_native("mcp-name")]
)
agent.deploy()

# Reference by ID (requires deploy() for remote)
agent = Agent(
    name="agent",
    instruction="...",
    mcps=[MCP.from_id("mcp_abc123")]
)
agent.deploy()
```

**Conditional MCP inclusion:**

```python
from glaip_sdk import Agent, MCP
import os

# Only include MCP if environment variable is set
weather_mcp = MCP(
    name="weather",
    transport="http",
    config={"url": os.getenv("WEATHER_MCP_URL")},
) if os.getenv("WEATHER_MCP_URL") else None

agent = Agent(
    name="weather-agent",
    instruction="You help with weather",
    mcps=[weather_mcp] if weather_mcp else []
)
```

#### HTTP/SSE Transport Examples

**HTTP transport:**

```python
from glaip_sdk import MCP

mcp = MCP(
    name="my-http-mcp",
    transport="http",
    config={"url": "https://api.example.com/mcp"},
    authentication={
        "type": "api-key",
        "key": "X-API-Key",
        "value": "your-api-key",
    }
)
```

**SSE transport:**

```python
from glaip_sdk import MCP

mcp = MCP(
    name="my-sse-mcp",
    transport="sse",
    config={"url": "https://mcp.example.com/sse"},
)
```

**Stdio transport:**

```python
from glaip_sdk import MCP

mcp = MCP(
    name="filesystem",
    transport="stdio",
    config={
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"],
    }
)
```

{% hint style="info" %}
Stdio transport only works in local mode. It is not supported for remote/deployed agents.
{% endhint %}

#### Legacy: Client Pattern

> The `Client` API is kept for backward compatibility but new code should prefer the `MCP` object pattern above for a simpler, low-code workflow.

```python
# Legacy: prefer the MCP(...) pattern above
from glaip_sdk import Client

client = Client()

# Create MCP in registry
mcp = client.mcps.create_mcp(
    name="weather-service",
    transport="http",
    config={"url": "https://weather.example.com/mcp"},
    authentication={...}
)

# Use for registry management, listing, and governance
mcps = client.mcps.list_mcps()
```

**Use Client pattern only for:**

* Managing the MCP registry
* Listing and searching MCPs
* Testing MCP connections
* MCP governance across environments

***

### Create an MCP Configuration

*When to use:* Establish a new integration endpoint or clone settings from staging to production.

**Python SDK (Recommended: MCP Object)**

```python
from glaip_sdk import MCP, Agent

# Define MCP with all configuration
weather_mcp = MCP(
    name="weather-service",
    description="HTTP weather API via MCP",
    transport="http",
    config={"url": "https://weather.example.com/mcp"},
    authentication={
        "type": "api-key",
        "key": "X-API-Key",
        "value": "secret-key",
    },
)

# Attach to agent and deploy for remote execution
agent = Agent(
    name="weather-agent",
    instruction="You provide weather information",
    mcps=[weather_mcp],
)
agent.deploy()
print(weather_mcp.id)  # Available after deploy()
```

**CLI**

```bash
aip mcps create \
  --name weather-service \
  --description "HTTP weather API via MCP" \
  --transport http \
  --config '{"url": "https://weather.example.com/mcp"}' \
  --authentication '{"type": "api-key", "key": "X-API-Key", "value": "secret-key"}'
```

Using file references:

```bash
aip mcps create \
  --name weather-service \
  --transport http \
  --config @weather-config.json \
  --auth @weather-auth.json
```

See [Using files with the CLI](#using-files-with-the-cli) for file-based workflows and import examples.

**CLI (Import file)**

```bash
aip mcps create --import weather-mcp.json
```

See [Using files with the CLI](#using-files-with-the-cli) for field details and override behaviour.

The CLI loads every supported field from the file, then applies any CLI flags you pass on top of that data. This lets you tweak a few values (for example a new name or transport) without editing the file:

```bash
aip mcps create \
  --import weather-mcp.json \
  --name weather-service-prod \
  --transport http
```

Merge rules:

* Values inside `weather-mcp.json` form the baseline request (name, transport, config, authentication, metadata, etc.).
* Flags you provide alongside `--import` override the file values one by one (e.g., `--transport http` replaces the file's transport).
* If the file already supplies required fields like `name` and `transport`, you can omit those flags entirely; the CLI falls back to the file contents.

Example `weather-mcp.json`:

```json
{
  "name": "weather-service",
  "transport": "http",
  "description": "HTTP weather API via MCP",
  "config": {
    "url": "https://weather.example.com/mcp"
  },
  "authentication": {
    "type": "api-key",
    "headers": {
      "X-API-Key": "secret-key"
    }
  },
  "mcp_metadata": {
    "environment": "staging",
    "owner": "platform-team"
  }
}
```

#### Using files with the CLI

* **Inline vs file inputs:** Any JSON flag (e.g., `--config`, `--auth`) accepts either inline JSON or a file reference using `@path/to/file.json`. File inputs are parsed with the same validation as inline payloads.
* **Importing full definitions:** Supply `--import <file>` to recreate an MCP from an export. The CLI loads every supported field from the file (name, transport, config, authentication, `mcp_metadata`, etc.).
* **Flag overrides:** CLI flags provided alongside `--import` override the matching keys in the file. Leaving a flag out keeps the file's value. When the file already contains required fields like `name` and `transport`, those flags become optional.

Example config file:

```json
{
  "url": "https://weather.example.com/mcp"
}
```

Example auth file:

```json
{
  "type": "api-key",
  "key": "X-API-Key",
  "value": "secret-key"
}
```

Example import file:

```json
{
  "name": "weather-service",
  "transport": "http",
  "description": "HTTP weather API via MCP",
  "config": {
    "url": "https://weather.example.com/mcp"
  },
  "authentication": {
    "type": "api-key",
    "headers": {
      "X-API-Key": "secret-key"
    }
  },
  "mcp_metadata": {
    "environment": "staging",
    "owner": "platform-team"
  }
}
```

Command examples:

```bash
# Use dedicated config/auth files with @file syntax
aip mcps create \
  --name weather-service \
  --transport http \
  --config @weather-config.json \
  --auth @weather-auth.json

# Import and override selected fields
aip mcps create \
  --import weather-mcp.json \
  --name weather-service-prod \
  --transport http
```

### Rotate Credentials or Update Configs

*When to use:* Refresh secrets before they expire or tweak transport parameters without downtime.

**Python SDK (MCP Object)**

After deploying an MCP, you can update it using the MCP object's methods:

```python
from glaip_sdk import Client, MCP

# First get the MCP from the platform
client = Client()
mcp = client.mcps.get_mcp_by_id("mcp-123")

# Update credentials - uses MCP object method
mcp.update(
    authentication={
        "type": "api-key",
        "key": "X-API-Key",
        "value": "new-secret",
    }
)
```

**CLI**

```bash
# Export current config, edit, then update
aip mcps get <MCP_REF> --export mcp-config.json
# Edit the JSON file to update credentials
aip mcps update <MCP_REF> --config @mcp-config.json
```

### Validate Connections Before Saving

*When to use:* Confirm the connector responds and auth works before exposing it to agents.

**Python SDK (MCP Object)**

```python
from glaip_sdk import MCP, Client

# Test MCP config before using
mcp = MCP(
    name="weather-service",
    transport="http",
    config={"url": "https://weather.example.com/mcp"},
    authentication={
        "type": "api-key",
        "key": "X-API-Key",
        "value": "secret-key",
    }
)

client = Client()
result = client.mcps.test_mcp_connection_from_config(mcp.model_dump(exclude_none=True))
print(result)
```

CLI:

```bash
aip mcps connect --from-file weather-mcp.json
```

REST reference only (internal integrations):

* [REST: MCPs](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/mcps)

#### Common errors and fixes

| Symptom                                         | Likely cause                                                       | Fix                                                                                      |
| ----------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| `401 Unauthorized` when validating              | API key lacks MCP permissions or connector secrets expired.        | Issue a runner/creator key or rotate the provider secret under **Rotate Credentials**.   |
| `404` or `connection refused` during validation | Base URL incorrect or firewall blocking outbound traffic.          | Confirm the URL, allowlist the host, or test from a network that can reach the provider. |
| Connector saves but tools list is empty         | Provider exposes no MCP tools or scope is limited.                 | Run discovery with elevated scopes or confirm the provider exports MCP metadata.         |
| Agents timeout when calling the MCP             | Runtime overrides missing, or concurrency exceeds provider limits. | Use per-run overrides for busy periods and tune agent `timeout` settings.                |

### Discover MCP Tools

*When to use:* Inspect which tool definitions become available once the connector is active.

**Python SDK (MCP Object)**

```python
from glaip_sdk import Client, MCP

# Get MCP from platform and discover tools
client = Client()
mcp = client.mcps.get_mcp_by_id("mcp-123")
tools = mcp.get_tools()

for tool in tools:
    print(f"{tool['name']}: {tool['description']}")
```

{% hint style="info" %}
`mcp.get_tools()` requires the MCP to be saved on the platform (has an ID). If you haven't saved the MCP yet or want to use an MCP directly without AIP, you can discover tools through the MCP provider directly (e.g., DeepWiki's API).
{% endhint %}

**CLI**

Get tools from a saved MCP:

```bash
aip mcps tools <MCP_ID>
```

Get tools from a config file (without saving to DB):

```bash
aip mcps tools --from-config mcp-config.json
```

Get just tool names for `allowed_tools` config:

```bash
# Simple list output - easy to copy-paste
aip mcps tools <MCP_ID> --names-only

# JSON array output - ready for config files
aip mcps tools <MCP_ID> --names-only --json
```

Example config file (`mcp-config.json`):

```json
{
  "transport": "sse",
  "config": {
    "url": "https://mcp.obrol.id/f/sse"
  }
}
```

**Python SDK (Legacy: Client Pattern)**

```python
# Legacy pattern
from glaip_sdk import Client

client = Client()

# From a saved MCP (stored in DB)
tools = client.mcps.get_mcp_tools(mcp_id)
for tool in tools:
    print(f"{tool['name']}: {tool['description']}")

# From a non-saved MCP config (not stored in DB)
config = {
    "transport": "sse",
    "config": {"url": "https://mcp.obrol.id/f/sse"},
}
tools = client.mcps.get_mcp_tools_from_config(config)
for tool in tools:
    print(f"{tool['name']}: {tool['description']}")
```

Attach discovered tool IDs to agents just like native or custom uploads.

### Restrict Agent Tool Access (Allow List)

*When to use:* Limit which MCP tools an agent can access instead of allowing all tools from the MCP.

{% hint style="warning" %}
Tool names in `allowed_tools` must match exactly. Use [Discover MCP Tools](#discover-mcp-tools) to find the correct tool names before configuring the allow list.
{% endhint %}

#### Configure Tool Filtering at Agent Level

**Python SDK (Recommended: Agent + MCP Pattern)**

```python
from glaip_sdk import Agent, MCP, Client

# First, get MCP from platform (client-connected)
client = Client()
mcp = client.mcps.get_mcp_by_id("mcp_abc123")

# Discover available tools using MCP object method
tools = mcp.get_tools()
print([t['name'] for t in tools])  # ['get_weather', 'get_forecast', 'get_alerts']

# Define MCP with tool restrictions
weather_mcp = MCP(
    name="weather-service",
    transport="http",
    config={"url": "https://weather.example.com/mcp"},
)

# Create agent with only specific tools allowed
agent = Agent(
    name="Weather Agent",
    instruction="Provide weather info",
    model_name="gpt-5",
    mcps=[weather_mcp],
    mcp_configs={
        weather_mcp: {
            "allowed_tools": ["get_weather", "get_forecast"]  # blocks get_alerts
        }
    }
)
```

**Configuration rules:**

* Omit `allowed_tools` or set to `null` or empty list `[]` — allows all MCP tools (default)
* Set to `["tool1", "tool2"]` — allows only listed tools

**Different ways to key `mcp_configs`:**

```python
# 1. MCP object (recommended)
mcp_configs={
    weather_mcp: {
        "allowed_tools": ["get_weather"]
    }
}

# 2. MCP name string
mcp_configs={
    "weather-service": {
        "allowed_tools": ["get_weather"]
    }
}

# 3. MCP ID string (remote only, requires saved MCP)
mcp_configs={
    "mcp_abc123": {
        "allowed_tools": ["get_weather"]
    }
}
```

**Combining with authentication:**

```python
agent = Agent(
    name="Weather Agent",
    instruction="Provide weather info",
    mcps=[weather_mcp],
    mcp_configs={
        weather_mcp: {
            "allowed_tools": ["read_data"],
            "authentication": {
                "type": "bearer-token",
                "token": "agent-specific-token"
            }
        }
    }
)
```

**Python SDK (Legacy: Client Pattern)**

```python
# Legacy pattern - prefer Agent + MCP pattern above
from glaip_sdk import Client

client = Client()

# First, discover available tools
tools = client.mcps.get_mcp_tools(mcp_id)
print([t['name'] for t in tools])  # ['get_weather', 'get_forecast', 'get_alerts']

# Create agent with only specific tools allowed
agent = client.agents.create_agent(
    name="Weather Agent",
    instruction="Provide weather info",
    model_name="gpt-5",
    mcps=[mcp_id],
    mcp_configs={
        mcp_id: {
            "allowed_tools": ["get_weather", "get_forecast"]  # blocks get_alerts
        }
    }
)
```

#### Update Existing Agent Tool Access

**Python SDK**

```python
# Update agent's MCP config
agent.mcp_configs = {
    weather_mcp: {
        "allowed_tools": ["get_weather", "get_forecast", "get_alerts"]  # add get_alerts
    }
}
agent.update()
```

### Runtime Overrides During Agent Runs

*When to use:* Supply per-run credentials, tool restrictions, or endpoints that differ from the stored defaults.

**Override authentication:**

```python
agent.run(
    "Summarise sales data",
    runtime_config={
        "mcp_configs": {
            weather_mcp: {
                "authentication": {
                    "type": "api-key",
                    "key": "X-API-Key",
                    "value": "temporary-override"
                }
            }
        }
    }
)
```

**Override allowed tools:**

```python
# Agent normally has access to ['get_weather', 'get_forecast']
# Restrict to only get_weather for this run
agent.run(
    "What's the current weather?",
    runtime_config={
        "mcp_configs": {
            weather_mcp: {
                "allowed_tools": ["get_weather"]  # temporary restriction
            }
        }
    }
)
```

**Configuration layers (resolution order):**

1. **Runtime config** (highest priority) — per-execution overrides
2. **Agent config** — stored in agent `mcp_configs`
3. **MCP config** (lowest priority) — base MCP settings

{% hint style="info" %}
Runtime overrides are processed in-memory for the run and do not modify stored MCP or agent records. CLI support is under development; use the SDK for now (REST is reference-only).
{% endhint %}

### MCP Maintenance

*When to use:* Audit or retire connectors after incidents, vendor changes, or environment migrations.

**Python SDK**

```python
from glaip_sdk import Client

client = Client()

# List MCPs
mcps = client.mcps.list_mcps()

# Get specific MCP and delete
mcp = client.mcps.get_mcp_by_id("mcp-123")
mcp.delete()
```

* List MCPs with `client.mcps.list_mcps()` or `aip mcps list` (see [CLI: MCPs](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/mcps)).
* Delete MCPs from the registry with `mcp.delete()` or CLI equivalent.
* Combine MCP tooling with the [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) when you want to import remote tools into agent definitions.

### Best Practices

*When to use:* Align your organisation on safe defaults that reduce downtime and credential leaks.

1. **Store secrets securely** — use environment variables when invoking CLI or export/import workflows; avoid committing secrets to JSON.
2. **Validate before saving** — run `aip mcps connect --from-file ...` or the SDK connection test helpers to catch network or auth issues early.
3. **Document tool discovery** — record which MCP tool IDs power each agent so teammates can maintain the integration.
4. **Monitor timeouts** — many services expose their own rate or timeout limits; set `config.timeout` accordingly and surface errors in run logs.

### Related Documentation

* [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) — attach native, custom, and MCP-discovered tools.
* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — manage agent lifecycle and runtime overrides.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — script MCP promotion in CI pipelines.


# Skills

Run prompt-only skills with local and remote agents in `glaip-sdk`. Use this guide to install/load skills, attach them to agents, and run them in the right execution mode.

{% hint style="info" %}
Use GitHub-backed skills or local `Skill.from_path(...)` folders for both local runs and remote deploy. Local path skills are uploaded during deploy, so remote runs do not need GitHub clone access for those skills.

`glaip-sdk` utilizes the **GL Connectors Skills** workflow and references the same skill model documented in GL Connectors.
{% endhint %}

### Local vs Remote Examples

For concrete local and remote skill examples, refer directly to the cookbook PR: [gdplabs/gl-aip-sdk-cookbook#3](https://github.com/gdplabs/gl-aip-sdk-cookbook/pull/3).

Use this guide for the skill loading and attachment patterns; use the cookbook as the runnable reference for local-vs-remote behavior.

### Skills Patterns

#### GitHub-Based Skills

The recommended way to use skills is via GitHub URLs. This works for both local and remote deployment.

**Public GitHub Skills**

For public repositories, pass the GitHub skill URL directly:

```python
from glaip_sdk import Agent

github_skill = "https://github.com/coreyhaines31/marketingskills/tree/main/skills/copywriting"

agent = Agent(
    name="skills-github-agent",
    instruction="You are a helpful assistant.",
    model="openai/gpt-5",
    skills=[github_skill],
)

result = agent.run("Write landing page copy for PulsePath.")
```

**Private GitHub Skills**

For private repositories, set one of these environment variables before running:

```bash
export GITHUB_PERSONAL_ACCESS_TOKEN="<your_token>"
# or
export GITHUB_TOKEN="<your_token>"
# or
export GH_TOKEN="<your_token>"
```

Then use the private URL the same way:

```python
from glaip_sdk import Agent

agent = Agent(
    name="skills-private-github-agent",
    instruction="You are a helpful assistant.",
    model="openai/gpt-5",
    skills=["https://github.com/<org>/<repo>/tree/<branch>/skills/<skill-name>"],
)
```

**Remote Deploy with GitHub Skills**

For remote runs, deploy the agent first. With GitHub-backed skills, the SDK normalizes the skills payload and enables filesystem support automatically.

```python
from glaip_sdk import Agent

agent = Agent(
    name="skills-remote-agent",
    instruction="You are a helpful assistant.",
    model="openai/gpt-5",
    skills=["https://github.com/<org>/<repo>/tree/<branch>/skills/<skill-name>"],
)

agent.deploy()
result = agent.run("Write landing page copy for PulsePath.")
```

Accepted GitHub-based inputs:

* single URL string:

```python
skills="https://github.com/<org>/<repo>/tree/<branch>/skills/<name>"
```

* list of URL strings: `skills=["<github-skill-url-1>", "<github-skill-url-2>"]`

Input behavior:

* string or list of strings in `skills` is treated as GitHub skill source URL(s)
* `Skill` object from `Skill.from_path(...)` is treated as a local skill folder and uploaded during remote deploy

#### Path-Based Skills (Local and Remote)

Use local skill folders under `.agents/skills/<skill-name>/` and load them with `Skill.from_path(...)`. The SDK reads the folder, validates safe text files, and uploads the skill payload before agent create/update when you deploy remotely.

```python
from glaip_sdk import Agent
from glaip_sdk.skills import Skill

skill = Skill.from_path(".agents/skills/copywriting")

agent = Agent(
    name="skills-local-agent",
    instruction="You are a helpful assistant.",
    model="openai/gpt-5",
    skills=[skill],
)

result = agent.run("Write landing page copy for PulsePath.")
```

For remote deploy, use the same `Skill.from_path(...)` object:

```python
from glaip_sdk import Agent
from glaip_sdk.skills import Skill

skill = Skill.from_path(".agents/skills/copywriting")

agent = Agent(
    name="skills-uploaded-agent",
    instruction="You are a helpful assistant.",
    model="openai/gpt-5",
    skills=[skill],
)

agent.deploy()
result = agent.run("Write landing page copy for PulsePath.")
```

Remote path-based deploy behavior:

* `SKILL.md` is required at the skill root.
* Hidden/cache files, symlinks, unsafe relative paths, non-UTF-8 files, and size limit violations are rejected before upload.
* Filesystem support is auto-enabled when unset.
* Explicit `filesystem=False` fails fast for uploaded local path skills.

**Use path-based skills for:**

* deterministic local development
* teams managing skill files inside the repository
* explicit skill versioning through Git history

***

### Skill Authoring (GL Connectors Skills)

For creating and structuring skills, follow the canonical GL Connectors docs:

* [GL Connectors Skills](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/connectors-skills)
* [Creating a Skill](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/connectors-skills/creating-a-skill)
* [Skills, MCP Servers, Pipelines and APIs](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/agentic-tools-and-model-context-protocol-mcp)

In this SDK guide:

* GitHub tree URLs work for local runs and remote deploy.
* Path-based custom skills (`Skill.from_path(...)`) work locally and can be remote-deployed through uploaded skill payloads.

### Troubleshooting

* **`ImportError: aip_agents is required for Skill`**
  * likely cause: local runtime extras are missing
  * fix: install `glaip-sdk[local]`
* **Filesystem override warning during deploy**
  * likely cause: filesystem is explicitly disabled in config while GitHub skills are set
  * fix: remove the override if unnecessary; SDK auto-enables filesystem for remote deploy
* **`filesystem=False` with an uploaded local skill fails**
  * likely cause: `Skill.from_path(...)` needs remote filesystem support to stage files
  * fix: remove `filesystem=False` or enable filesystem support
* **`Missing required SKILL.md`**
  * likely cause: invalid skill directory
  * fix: add `SKILL.md` at skill root
* **GitHub install failure**
  * likely cause: missing dependency or GitHub auth
  * fix: ensure `gl-connectors-tools` is installed and set `GITHUB_PERSONAL_ACCESS_TOKEN` (or `GITHUB_TOKEN` / `GH_TOKEN`) for private repos

### Current Limitations and Roadmap

* Skills are currently read/prompt-oriented (`SKILL.md`, references, examples).
* Agent execution of code inside skill folders is planned (TBD).

***

### How Skills Relate to Tools, MCP Servers, and APIs

Use these components together based on responsibility:

* **Skills**: teach the agent workflow, format, and domain rules.
* **Tools**: let the agent perform discrete actions.
* **MCP servers**: expose external tools/resources through a standard interface.
* **Pipelines/APIs**: run deterministic execution outside the model.

Decision matrix:

| If you need...                                         | Start with                 | Why                                              |
| ------------------------------------------------------ | -------------------------- | ------------------------------------------------ |
| The agent to **know how** to follow a workflow/format  | **Skill**                  | Encodes instructions, rules, and domain process  |
| The agent to **do** a discrete action                  | **Tool** or **MCP server** | Executes capabilities against external systems   |
| Deterministic, fixed execution with no model reasoning | **Pipelines/APIs**         | Keeps logic explicit and predictable             |
| Team-specific workflow using existing tools/MCP        | **Skill + Tool/MCP**       | Skill teaches process; Tool/MCP provides actions |

Use tools or MCP servers for executable actions in the current release.

#### Runtime Relationship (AIP + GL Connectors Skills)

Conceptual sequence for how `glaip-sdk` uses GL Connectors skill sources:

```mermaid
sequenceDiagram
    participant Dev as Developer
    participant SDK as AIP SDK Agent
    participant GC as GL Connectors Skills
    participant Src as Skill Source (GitHub or uploaded folder)
    participant RT as AIP Runtime

    Dev->>SDK: Configure Agent(skills=[github_url or Skill.from_path(...)])
    SDK->>GC: Resolve skill metadata and source/upload payload
    GC->>Src: Fetch or stage skill folder/SKILL.md
    GC-->>SDK: Return normalized skill payload
    SDK->>RT: deploy()/run() with skills attached
    RT-->>SDK: Agent response
```

### Related Documentation

* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents)
* [CLI agents commands](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/agents)
* [CLI slash palette](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-slash-palette)
* [CLI commands reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands)
* [MCPs guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/mcps)


# Agent Evaluations

Evaluate local or AIP-hosted agents with YAML testcases, configurable metrics, and canonical JSON reports using the Python SDK.

### Overview

Agent evaluation is the process of running an agent against predefined scenarios and checking whether the observed behavior satisfies explicit success criteria. In the SDK, each scenario is represented by one YAML testcase file. That single testcase can declare multiple evaluation metrics, so one agent run can be checked for response quality, tool calls, or custom business rules.

The goal is to make agent quality measurable and repeatable. Instead of manually inspecting every response after a prompt, tool, model, or deployment change, you can keep a suite of YAML testcases in your project and run them through `AgentEvaluator`. The output is a canonical JSON-compatible report that engineers can use for debugging and stakeholders can review through persisted JSON or a Google Sheets mirror.

Use evaluations as regression tests for high-value behaviors: what the agent should answer, which tools it should use, what it must not say, and which domain-specific rules it must satisfy.

### Core Concepts

| Concept   | Description                                                                                                                                                    |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Evaluator | The runner for an evaluation session. It takes an agent and a set of scenarios, then produces evidence of how well the agent performed.                        |
| Testcase  | A single business scenario to verify. It describes what the user asks, any relevant conversation context, and the success criteria for that scenario.          |
| Metrics   | The success criteria for a testcase. Metrics turn expectations like "mentions the right employee" or "uses the correct tool" into measurable pass/fail checks. |
| Report    | The evaluation outcome for review and decision-making. It summarizes which scenarios passed or failed and explains what needs attention.                       |

### Quick Start

Install the local and evals SDK extras, then configure an LLM provider key for the agent run.

```bash
pip install "glaip-sdk[local,evals]"
export OPENAI_API_KEY="..."
```

Create a local testcase directory in your project. The evaluator also accepts a single YAML file when you only want to run one testcase.

```bash
mkdir -p evals
cat > evals/employee_lookup.yaml <<'YAML'
id: tc-engineering-employees-deterministic
description: Verify the agent calls employee_lookup and mentions employees from the tool output.
input:
  message: Who are the employees in the Engineering department?
metrics:
  - name: tool_calls
    type: deterministic
    reference:
      tool_calls:
        - tool: employee_lookup
          params:
            department:
              match: exact
              value: Engineering
  - name: response_keywords
    type: deterministic
    reference:
      keywords: ["Alice", "Engineering"]
YAML
```

Then define the tool your agent should use, create an evaluator, and pass the local testcase directory.

```python
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field

from glaip_sdk.agents import Agent
from glaip_sdk.evals import AgentEvaluator
from glaip_sdk.models import OpenAI
from glaip_sdk.tools import Tool


class EmployeeLookupInput(BaseModel):
    department: str = Field(description="Department name to look up employees for")


class EmployeeLookupTool(BaseTool):
    name: str = "employee_lookup"
    description: str = "Look up employees in a given department."
    args_schema: type[BaseModel] = EmployeeLookupInput

    def _run(self, department: str) -> str:
        employees = {
            "Engineering": ["Alice Chen", "Bob Smith", "Carol Wu"],
            "Marketing": ["David Lee", "Eve Johnson"],
        }
        return ", ".join(employees.get(department, []))


agent = Agent(
    name="employee-lookup-agent",
    instruction="Call employee_lookup with the requested department and list the returned employees.",
    model=OpenAI.GPT_4O_MINI,
    tools=[Tool.from_langchain(EmployeeLookupTool)],
)

evaluator = AgentEvaluator(
    name="Employee Lookup Evaluation",
    version="1.0.0",
)

report = evaluator.evaluate(
    agent=agent,
    test_cases="evals",
)
```

`report` is the canonical JSON-compatible result object. You can print it, inspect it in tests, persist it, or mirror it to a review sink.

### Local and Hosted Targets

Evaluation target selection is run configuration, not testcase intent. Keep testcases focused on user input and success criteria, then choose the execution target when calling `evaluate()`.

| Mode     | Behavior                                                                                        |
| -------- | ----------------------------------------------------------------------------------------------- |
| `auto`   | Default. Uses hosted execution when the agent has a hosted identity, otherwise local execution. |
| `local`  | Forces local SDK execution, even when the agent also has a hosted identity.                     |
| `hosted` | Forces hosted AIP execution and requires a deployed agent identity.                             |

The YAML testcase contract does not change between local and hosted execution. Only the agent invocation target changes. Testcase loading, validation, metric execution, report generation, JSON persistence, and Sheets mirroring still run locally in the SDK process.

Use the default `auto` mode when you want the evaluator to infer the target from the agent object:

```python
report = evaluator.evaluate(
    agent=agent,
    test_cases="evals",
)
```

Use `local` when you want to validate the local implementation path explicitly:

```python
report = evaluator.evaluate(
    agent=agent,
    test_cases="evals",
    target_mode="local",
)
```

Use `agent.deploy()` when you want to evaluate the remote AIP-hosted path. After deployment, the agent has a hosted identity, so `auto` mode resolves to hosted execution. You can also set `target_mode="hosted"` explicitly when you want the run to fail if the agent is not deployed.

```python
agent.deploy()

report = evaluator.evaluate(
    agent=agent,
    test_cases="evals",
)
```

To force hosted execution explicitly:

```python
report = evaluator.evaluate(
    agent=agent,
    test_cases="evals",
    target_mode="hosted",
)
```

If `target_mode="hosted"` is selected for an agent without a hosted identity, the evaluator raises `EvalExecutionError` before running any testcase.

### Writing Testcases

Each testcase is a YAML file with an `id`, `input`, and `metrics` list. `description` and `input.chat_history` are optional.

```yaml
id: tc-engineering-employees-deterministic
description: Verify the agent calls employee_lookup and mentions employees from the tool output.
input:
  message: Who are the employees in the Engineering department?
metrics:
  - name: tool_calls
    type: deterministic
    reference:
      tool_calls:
        - tool: employee_lookup
          params:
            department:
              match: exact
              value: Engineering
          output:
            match: keyword
            value: ["Alice Chen", "Bob Smith"]
  - name: response_keywords
    type: deterministic
    reference:
      keywords: ["Alice", "Engineering"]
```

The evaluator validates all testcase files before execution. If any testcase is malformed, has unknown fields, or misses required fields, the run fails before the agent is called.

### Metric Types

The evaluator currently supports three metric categories: deterministic, model, and Python.

#### Deterministic Metrics

Use deterministic metrics for exact or keyword-based checks that should not require an LLM judge.

Supported deterministic metrics:

| Metric                        | Use for                                                    |
| ----------------------------- | ---------------------------------------------------------- |
| `response_keywords`           | Require specific keywords in the final response.           |
| `response_forbidden_keywords` | Fail when forbidden keywords appear in the final response. |
| `tool_calls`                  | Require expected tool calls, parameters, or tool outputs.  |
| `tool_calls_forbidden`        | Fail when forbidden tools are called.                      |

```yaml
metrics:
  - name: response_keywords
    type: deterministic
    reference:
      keywords: ["Alice", "Bob", "Engineering"]
  - name: tool_calls
    type: deterministic
    reference:
      tool_calls:
        - tool: employee_lookup
          params:
            department:
              match: exact
              value: Engineering
```

Use deterministic metrics first when the expected behavior is concrete. They are easier to debug and make good regression checks.

#### Model Metrics

Use model metrics when quality needs judgment rather than exact matching. Model metrics use an LLM as a judge, and the evaluator delegates model-metric execution to the `gllm-evals` SDK. These metrics require provider credentials unless your environment already provides credentials through the upstream model configuration.

Supported model metrics:

| Metric             | Use for                                                     |
| ------------------ | ----------------------------------------------------------- |
| `completeness`     | Check whether the response covers the expected answer.      |
| `groundedness`     | Check whether the response is grounded in supplied context. |
| `redundancy`       | Check whether the response contains unnecessary repetition. |
| `tool_correctness` | Check whether tool usage matches expected tools.            |

```yaml
metrics:
  - name: completeness
    type: model
    threshold: 0.5
    model:
      name: openai/gpt-4o-mini
      credentials: env:OPENAI_API_KEY
    reference: The Engineering department employees are Alice Chen, Bob Smith, and Carol Wu.
  - name: tool_correctness
    type: model
    threshold: 0.5
    model:
      name: openai/gpt-4o-mini
      credentials: env:OPENAI_API_KEY
    reference:
      expected_tools:
        - name: employee_lookup
          input_parameters:
            department: Engineering
```

If `threshold` is omitted, the evaluator uses the metric default. Use explicit thresholds when you want stable review criteria across runs.

#### Python Metrics

Use Python metrics for domain-specific rules that are easier to express in code than in YAML.

```yaml
metrics:
  - name: employee_response_alignment
    type: python
    source: examples/evaluations/metrics/employee_response_alignment.py
    class: EmployeeResponseAlignmentMetric
```

The metric class must inherit from `gllm_evals.metrics.metric.BaseMetric`.

The `_evaluate()` method receives `MetricInput`, a dictionary-like row normalized from the testcase plus the agent run artifact. Common fields include:

| Field               | Description                                                                                       |
| ------------------- | ------------------------------------------------------------------------------------------------- |
| `input`             | The full testcase input dict (access the message via `input.message`).                            |
| `actual_output`     | The agent's final response text.                                                                  |
| `expected_output`   | The expected output string when a metric, such as `completeness`, declares one.                   |
| `retrieved_context` | Runtime context captured from tool outputs when available.                                        |
| `tools_called`      | Observed tool calls from the agent run, normalized to `ToolCall` objects.                         |
| `expected_tools`    | Expected tool calls from `tool_correctness.reference.expected_tools`.                             |
| `glaip_metadata`    | SDK metadata such as `test_case_id`, `source_file`, `agent_run_id`, `token_usage`, and `latency`. |
| `glaip_assertions`  | Deterministic metric reference payloads keyed by metric name.                                     |

The method must return `MetricOutput`, represented as a dictionary. At minimum, return `score` and `explanation`. The inherited `BaseMetric` contract derives pass/fail from `score`, `threshold`, and `higher_is_better`, then the SDK maps that result into the canonical report.

```python
from gllm_evals.metrics.metric import BaseMetric
from gllm_evals.types import MetricInput, MetricOutput


class EmployeeResponseAlignmentMetric(BaseMetric):
    name = "employee_response_alignment"
    type = "python"
    higher_is_better = True
    threshold = 1.0

    async def _evaluate(self, data: MetricInput) -> MetricOutput:
        output = data.get("actual_output") or ""
        tools_called = data.get("tools_called") or []

        if not tools_called:
            return {
                "score": 0.0,
                "explanation": "The agent did not call any tools.",
            }

        if "Engineering" not in output:
            return {
                "score": 0.0,
                "explanation": "The final answer did not mention the requested department.",
            }

        return {
            "score": 1.0,
            "explanation": "The response stayed aligned with the expected department context.",
        }
```

Python metric `source` paths must resolve inside the evaluation workspace and point to a `.py` file. Use the `class` field to select the metric class when a file contains more than one class.

### Reading Reports

Every run returns a canonical report object with `summary` and `results`.

```json
{
  "summary": {
    "evaluation_run_id": "...",
    "run_timestamp": "...",
    "evaluation_name": "Employee Lookup Evaluation",
    "evaluation_description": null,
    "evaluation_version": "1.0.0",
    "agent_ref": "agent-...",
    "agent_version": "1.2.3",
    "total_cases": 1,
    "passed_cases": 1,
    "failed_cases": 0,
    "pass_rate": 1.0,
    "metric_failure_counts": {}
  },
  "results": [
    {
      "test_case_id": "tc-engineering-employees-deterministic",
      "source_file": "examples/evaluations/data/employee_lookup_deterministic.yaml",
      "agent_run_id": "run-...",
      "response": "...",
      "status": "PASS",
      "explanation": "...",
      "metric_results": [
        {
          "name": "response_keywords",
          "type": "deterministic",
          "status": "PASS",
          "score": 1.0,
          "threshold": 1.0,
          "explanation": "..."
        }
      ],
      "token_usage": {
        "input_tokens": 0,
        "output_tokens": 0,
        "total_tokens": 0
      },
      "latency": {
        "total_ms": 0,
        "first_token_ms": null
      }
    }
  ]
}
```

Use the top-level summary for run status and dashboards. For hosted targets, `agent_ref` and `agent_version` identify the evaluated hosted agent when those fields are available. For local targets, they remain `null` to preserve the local-only report behavior.

Use each result's `metric_results` array when debugging why a testcase passed or failed. For hosted targets, `agent_run_id` is populated when the hosted runtime returns or exposes a stable run reference.

### Persisting JSON Output

By default, the report is returned in memory only. Set `report_output_dir` to write a JSON artifact while preserving the same returned report object.

```python
evaluator = AgentEvaluator(
    name="Employee Lookup Evaluation",
    version="1.0.0",
    report_output_dir="examples/evaluations/output",
)

report = evaluator.evaluate(
    agent=agent,
    test_cases="examples/evaluations/data/employee_lookup_json_sink.yaml",
)
```

Use persisted JSON when you need an artifact for local review, CI logs, or historical comparison.

### Mirroring to Google Sheets

Google Sheets output is an optional mirror for stakeholder visibility. The canonical JSON report remains the source of truth. If Sheets writing fails, the evaluator still returns the canonical report and emits a warning.

```python
import json
import os

service_account_credentials = json.loads(os.environ["GOOGLE_SERVICE_ACCOUNT_JSON"])

evaluator = AgentEvaluator(
    name="Employee Lookup Evaluation",
    version="1.0.0",
    sheets_report={
        "enabled": True,
        "sheet_url": "https://docs.google.com/spreadsheets/d/...",
        "auth_mode": "service_account",
        "service_account_credentials": service_account_credentials,
        "summary_worksheet_title": "Evaluation Results",
    },
)

report = evaluator.evaluate(
    agent=agent,
    test_cases="examples/evaluations/data/employee_lookup_sheets_sink.yaml",
)
```

The Sheets sink supports service account credentials as a dictionary or file path, plus OAuth credentials. Prefer environment variables for credentials so secrets do not live in source control.

### Recommended Workflow

1. Start with deterministic metrics for exact response and tool-use checks.
2. Add model metrics for qualitative behavior that cannot be represented with simple matching.
3. Add Python metrics for project-specific rules and business logic.
4. Persist JSON when you need durable artifacts for CI or review.
5. Mirror to Sheets when non-engineering stakeholders need an easy review surface.

### Current Limitations

* Evaluations are launched from Python SDK code; CLI evaluation commands are not supported for now.
* Hosted target execution requires a deployed agent identity and valid hosted runtime credentials.
* Metric execution, report generation, JSON persistence, and Sheets mirroring remain local; there is no hosted evaluator service.
* Testcases are YAML files in the local workspace.
* Ordered or causal tool-call assertions are not currently supported.
* Google Sheets is a non-canonical mirror; JSON is the authoritative report shape.

### Advanced Usage

Use advanced configuration when basic deterministic or model checks are not enough for your evaluation suite.

#### Custom Model Judge

Each model metric can override the LLM judge model and credentials through the `model` block. `credentials: env:NAME` resolves the named environment variable at runtime.

```yaml
metrics:
  - name: completeness
    type: model
    threshold: 0.7
    model:
      name: openai/gpt-4o-mini
      credentials: env:OPENAI_API_KEY
    reference: The Engineering department employees are Alice Chen, Bob Smith, and Carol Wu.
```

If the `model` block is omitted, the evaluator uses the default model behavior from `gllm-evals`.

#### Model Invocation Config

Use `model.config` for model invocation settings such as temperature or max tokens. This is separate from metric `options`, which are metric-specific constructor options.

```yaml
metrics:
  - name: completeness
    type: model
    threshold: 0.7
    model:
      name: openai/gpt-4o-mini
      credentials: env:OPENAI_API_KEY
      config:
        temperature: 0
        max_tokens: 512
    reference: The Engineering department employees are Alice Chen, Bob Smith, and Carol Wu.
```

#### Custom Prompts for Model Metrics

Use `model.prompt.evaluation_steps` and `model.prompt.additional_context` to customize model-judge instructions. Each value is a path to a markdown file resolved relative to the evaluation workspace root.

```yaml
metrics:
  - name: completeness
    type: model
    model:
      name: openai/gpt-4o-mini
      credentials: env:OPENAI_API_KEY
      prompt:
        evaluation_steps: prompt-samples/completeness/evaluation_steps.md
        additional_context: prompt-samples/completeness/additional_context.md
    reference: The Engineering department employees are Alice Chen, Bob Smith, and Carol Wu.
```

When `model.prompt` is set, at least one of `evaluation_steps` or `additional_context` must be provided. Providing a single custom prompt file that replaces both `evaluation_steps` and `additional_context` simultaneously is not supported.

#### Multi-Turn Input

Use `chat_history` when the current message depends on previous conversation context. Each entry must contain `role` and `content`; supported roles are `user` and `assistant`.

```yaml
id: tc-follow-up-question
input:
  chat_history:
    - role: user
      content: I need help with the Engineering department.
    - role: assistant
      content: I can look up employees by department.
  message: Who works there?
metrics:
  - name: response_keywords
    type: deterministic
    reference:
      keywords: ["Engineering"]
```

#### Metric Options

Some metrics accept additional `options`. Options are passed to the metric constructor and should configure how the metric runs; they should not contain testcase input data.

```yaml
metrics:
  - name: tool_correctness
    type: model
    options:
      should_exact_match: true
      should_consider_ordering: false
      evaluation_params: ["input_parameters"]
    reference:
      expected_tools:
        - name: employee_lookup
          input_parameters:
            department: Engineering
```


# Programmatic Tool Calling

Enable AI agents to orchestrate multiple tool calls through code execution, reducing context pollution and improving efficiency for complex multi-step workflows. This guide shows how to use Programmatic Tool Calling (PTC) to let agents chain tool calls programmatically in a sandboxed environment.

> **Success**
>
> **When to use this guide:** You need agents to process large datasets with minimal context overhead, orchestrate complex multi-step tool workflows, or perform parallel operations across multiple tools without polluting the agent's context window.
>
> **Who benefits:** Developers building data-intensive agents, teams optimizing token usage and latency, and engineers implementing complex tool orchestration workflows.

{% hint style="info" %}
PTC supports both local runs (`agent.run(local=True)`) and remote deployments (`agent.deploy()` + remote `agent.run(...)`) using the same `ptc=PTC(...)` configuration model. The SDK automatically handles sandbox lifecycle management and cleanup after each run.
{% endhint %}

### Overview

Programmatic Tool Calling (PTC) enables agents to orchestrate tools through Python code rather than through individual API round-trips. Instead of requesting tools one at a time with each result entering the agent's context, the agent writes code that calls multiple tools, processes their outputs programmatically, and controls what information enters its context window.

Traditional tool calling creates two fundamental problems as workflows become more complex:

* **Context pollution from intermediate results**: When processing large datasets (10MB log files, database queries, API responses), all intermediate data enters the agent's context window, consuming massive token budgets and potentially pushing important information out of context.
* **Inference overhead and manual synthesis**: Sequential tool orchestration requires multiple model inference passes. The agent must parse results, compare values, and synthesize conclusions through natural language processing—both slow and error-prone.

PTC solves these problems by letting agents express orchestration logic in Python code. Loops, conditionals, data transformations, and error handling become explicit in code rather than implicit in the agent's reasoning.

### Key Features

* **Code-Based Orchestration**: Agents write Python code to chain multiple tool calls
* **Context Window Protection**: Intermediate results stay in the sandbox, only final outputs reach the agent
* **Parallel Execution**: Run multiple tool calls concurrently using `asyncio.gather`
* **Tool Integration**: Works seamlessly with MCP tools
* **Automatic Cleanup**: Sandbox resources are released after each run
* **Sandboxed Execution**: Code runs in a secure E2B environment

### Installation

PTC uses one SDK configuration model (`ptc=PTC(...)`) for both local and remote execution, but prerequisites differ by mode.

{% hint style="warning" %}
**Prerequisites (Local runs):** Install local runner support and configure E2B:

```bash
# Install with local runner support
pip install glaip-sdk[local]

# Set E2B API key for sandbox execution
export E2B_API_KEY="your-e2b-api-key"
```

Get your E2B API key from [e2b.dev](https://e2b.dev).
{% endhint %}

{% hint style="info" %}
**Prerequisites (Remote runs):** Configure platform credentials before `deploy()` and remote `run()`:

```bash
export AIP_API_URL="https://your-aip-instance.com"
export AIP_API_KEY="your-aip-api-key"
```

{% endhint %}

### Quick Start

#### Basic PTC Setup

```python
from glaip_sdk.agents import Agent
from glaip_sdk.ptc import PTC

# Create agent with PTC enabled
agent = Agent(
    name="ptc_demo",
    instruction="Use execute_ptc_code for multi-tool workflows.",
    mcps=[my_mcp],  # Your MCP tools
    ptc=PTC(enabled=True)
)

# Run locally with PTC
result = agent.run("Analyze the data and summarize findings", local=True)
print(result)
```

#### Example: Processing Team Expenses

Consider a common task: "Which team members exceeded their Q3 travel budget?"

With three MCP tools:

* `get_team_members(department)` - Returns team member list with IDs
* `get_expenses(user_id, quarter)` - Returns expense line items
* `get_budget_by_level(level)` - Returns budget limits

**Without PTC** (traditional approach):

* Fetch 20 team members → 20 tool calls for expenses
* Each returns 50-100 line items (2,000+ expenses total)
* All data enters agent context (200KB+)
* Agent manually sums expenses, compares against budgets
* Multiple inference passes required

**With PTC**:

The agent writes orchestration code that runs in the sandbox:

```python
# Agent-generated code (runs in sandbox)
import asyncio
import json
from tools.hr_mcp import get_team_members, get_expenses, get_budget_by_level

team = await get_team_members("engineering")

# Fetch budgets for unique levels in parallel
levels = list(set(m["level"] for m in team))
budget_results = await asyncio.gather(*[
    get_budget_by_level(level) for level in levels
])
budgets = {level: budget for level, budget in zip(levels, budget_results)}

# Fetch all expenses in parallel
expenses = await asyncio.gather(*[
    get_expenses(m["id"], "Q3") for m in team
])

# Process data and filter results
exceeded = []
for member, exp in zip(team, expenses):
    budget = budgets[member["level"]]
    total = sum(e["amount"] for e in exp)
    if total > budget["travel_limit"]:
        exceeded.append({
            "name": member["name"],
            "spent": total,
            "limit": budget["travel_limit"]
        })

print(json.dumps(exceeded))
```

**Results**:

* Agent context receives only the final result (2-3 people who exceeded budgets)
* Token consumption drops from \~200KB to \~1KB
* Multiple inference passes reduced to code execution
* Parallel execution reduces latency

### How PTC Works

#### 1. Agent Writes Orchestration Code

When PTC is enabled and the agent needs to orchestrate multiple tools, it uses the `execute_ptc_code` tool (automatically available) to generate Python code:

```python
# Agent calls execute_ptc_code with orchestration logic
import asyncio
from tools.hr_mcp import get_team_members, get_expenses

team = await get_team_members("engineering")
expenses = await asyncio.gather(*[get_expenses(m["id"], "Q3") for m in team])
# ... processing logic
print(result)
```

#### 2. Code Executes in E2B Sandbox

The code runs in a secure E2B sandbox environment. When the code calls tools, the sandbox pauses and requests tool execution from the API.

#### 3. Tool Results Stay in Sandbox

Tool results are returned to the sandbox environment and processed by the Python code—they do not enter the agent's context window.

#### 4. Final Output Returns to Agent

Only the code's final output (via `print()` or return value) is sent back to the agent's context:

```json
{
  "stdout": "[{\"name\": \"Alice\", \"spent\": 12500, \"limit\": 10000}]"
}
```

The agent sees only the summary, not the thousands of intermediate expense records.

### Configuration

#### PTC Class

```python
from glaip_sdk.ptc import PTC

# Minimal configuration (recommended)
ptc = PTC(enabled=True)

# Custom configuration
ptc = PTC(
    enabled=True,
    sandbox_timeout=180.0,       # Global sandbox execution timeout in seconds
    default_tool_timeout=45.0,   # Per-MCP tool call timeout inside sandbox wrappers
    sandbox_template="aip-agents-v2-2",  # Optional override; omit to use aip-agents default
    auto_build_template=True,    # Optional passthrough to aip-agents runtime config
    package_install_timeout=600.0,  # Optional pip install timeout inside sandbox runtime
    prompt={
        "mode": "full",           # Prompt mode: "auto", "minimal", "index", or "full"
        "auto_threshold": 10,     # Tool count threshold for auto mode
        "include_example": False  # Include example code in prompt
    }
)
```

**Configuration Options:**

* `enabled` (bool, required): Must be `True` to activate PTC. When `False`, all other fields are ignored.
* `sandbox_timeout` (float, optional): Maximum execution time for the full sandbox run (global cap). Default: 120.0.
* `default_tool_timeout` (float, optional): Per-MCP-call timeout used by sandbox MCP wrappers. Default: 60.0.
* `sandbox_template` (str, optional): Sandbox runtime template to use. Default: omitted by SDK so `aip-agents` selects the canonical default.
* `auto_build_template` (bool, optional): Explicit template auto-build toggle forwarded by SDK to `aip-agents`.
* `package_install_timeout` (float, optional): Explicit package-install timeout forwarded by SDK to `aip-agents`.
* `prompt` (dict, optional): Customize the PTC prompt configuration
  * `mode`: `"auto"` (default), `"minimal"`, `"index"`, or `"full"`
  * `auto_threshold`: Tool count threshold for auto mode (default: 10)
  * `include_example`: Whether to include example code in the prompt

`auto_build_template` and `package_install_timeout` are SDK payload/config passthrough fields. Runtime behavior still depends on downstream `aip-agents` and environment support.

**Prompt Modes:**

* `"auto"` (default): Automatically selects "minimal" if tools > auto\_threshold (10), otherwise "full"
* `"minimal"`: Shows only package list with discovery helper (`tools.ptc_helper`)
* `"index"`: Shows tool names grouped by package with discovery helper
* `"full"`: Shows complete tool signatures with descriptions

#### Agent Integration

PTC is configured via the `ptc` parameter on the Agent:

```python
from glaip_sdk.agents import Agent
from glaip_sdk.ptc import PTC

agent = Agent(
    name="data_processor",
    instruction="Process data efficiently using PTC.",
    mcps=[mcp1, mcp2],
    ptc=PTC(enabled=True)
)

# Local run
local_result = agent.run("Process the dataset", local=True)

# Remote run with the same PTC config
agent.deploy()
remote_result = agent.run("Process the dataset")
```

#### Constraints and Limitations

{% hint style="warning" %}
**Current PTC Constraints:**

* **No local runtime override**: local runner still rejects `runtime_config.ptc` and local `agent_config.ptc` overrides.
* **Remote field restrictions**: when `ptc.enabled=True`, remote deployment rejects `ptc_packages` and `custom_tools`.
* **E2B dependency (local only)**: local sandbox execution requires valid `E2B_API_KEY`.
  {% endhint %}

### When to Use PTC vs Other Techniques

#### Use PTC When:

**Processing large datasets with minimal relevant output:**

* Example: Processing 10MB log file to extract 3 error patterns
* Without PTC: 10MB enters agent context
* With PTC: Only error summary (\~1KB) enters context

**Running multi-step workflows with 3+ dependent tool calls:**

* Example: Fetch data → Filter → Aggregate → Compare → Report
* Benefit: Reduces round-trips and keeps intermediate data out of context

**Parallel operations across many items:**

* Example: Check health of 50 endpoints, aggregate results
* Benefit: Runs checks concurrently, only returns summary

**Data transformation before agent sees results:**

* Example: Fetch raw DB records → Normalize → Deduplicate → Format
* Benefit: Agent sees clean final output, not raw records

**Filtering or aggregating tool outputs:**

* Example: Fetch 1000 records → Filter by criteria → Return 10 matches
* Without PTC: All 1000 records enter context
* With PTC: Only 10 filtered results enter context

#### Use Traditional Tool Calling When:

**Making simple single-tool invocations:**

* Example: Get current weather for a city
* Reason: PTC overhead not justified for single lookup

**Agent needs to reason about intermediate results:**

* Example: "Analyze this error message and decide next debugging step"
* Reason: Agent should see the error to make informed decisions

**Working with small, relevant datasets:**

* Example: Fetch user profile (\~100 bytes)
* Reason: All data is relevant, no filtering needed

**Quick lookups with small responses:**

* Example: Dictionary lookup, simple API call
* Reason: PTC adds unnecessary execution overhead

**Exploratory workflows where agent needs full context:**

* Example: "Review these 3 documents and compare themes"
* Reason: Agent needs to see all content to reason effectively

### Real-World Performance: Tested Demo Scenario

To demonstrate PTC's real-world impact, we tested a common multi-tool workflow: fetching content from Google Drive and sending it via email. This scenario represents a typical use case where an agent needs to chain multiple tool calls together.

#### Demo Scenario

**Task**: Get markdown content from a Google Drive file and send it via email.

**Tools Used**:

* `google_drive_get_markdown_content` - Retrieves file content from Google Drive
* `google_mail_send_email` - Sends email with the content

**Test Setup**:

* Same task executed with PTC enabled and disabled
* Measured: execution time, token usage, tool calls
* Model: GPT-5.2
* Environment: Local execution with MCP tools

#### Execution Flow Comparison

```mermaid
sequenceDiagram
    participant User
    participant Agent
    participant LLM
    participant GoogleDrive as Google Drive MCP
    participant GoogleMail as Gmail MCP

    Note over User,GoogleMail: WITHOUT PTC (Traditional Approach)

    User->>Agent: Get Drive content and email it
    Agent->>LLM: Inference #1: Analyze task
    LLM->>Agent: Use google_drive_get_markdown_content
    Agent->>GoogleDrive: Call tool with file ID
    GoogleDrive->>Agent: Return content (large payload)
    Note right of Agent: Content enters context<br/>(~10-20KB)
    Agent->>LLM: Inference #2: Process result + next step
    LLM->>Agent: Use google_mail_send_email
    Agent->>GoogleMail: Call tool with email data
    GoogleMail->>Agent: Success response
    Agent->>LLM: Inference #3: Synthesize final response
    LLM->>Agent: Task completed
    Agent->>User: Done (148.85s, 47K tokens, 2 tool calls)

    Note over User,GoogleMail: WITH PTC (Code Orchestration)

    User->>Agent: Get Drive content and email it
    Agent->>LLM: Inference #1: Analyze task
    LLM->>Agent: Use execute_ptc_code
    Agent->>Agent: Execute in E2B sandbox:<br/>1. Call GoogleDrive<br/>2. Call Gmail<br/>3. Return result
    Note right of Agent: Intermediate results<br/>stay in sandbox
    Agent->>LLM: Return only final status
    LLM->>Agent: Task completed
    Agent->>User: Done (30.22s, 5.8K tokens, 1 tool call)
```

#### Detailed Metrics

| Metric            | Without PTC | With PTC | Improvement |
| ----------------- | ----------- | -------- | ----------- |
| **Total Time**    | 148.85s     | 30.22s   | **79.7% ↓** |
| **Input Tokens**  | 36,780      | 5,461    | **85.1% ↓** |
| **Output Tokens** | 10,250      | 396      | **96.1% ↓** |
| **Total Tokens**  | 47,030      | 5,857    | **87.5% ↓** |
| **Tool Calls**    | 2           | 1        | **50% ↓**   |

#### Why PTC Made a Difference

**Without PTC**:

1. Agent makes first inference to understand task
2. Calls `google_drive_get_markdown_content` → Large content enters context
3. Second inference with full content in context (high token cost)
4. Calls `google_mail_send_email` with content
5. Third inference to synthesize response
6. Multiple round-trips and context pollution

**With PTC**:

1. Agent generates orchestration code via `execute_ptc_code`
2. Code executes in sandbox:
   * Fetches Drive content (stays in sandbox)
   * Sends email with content (stays in sandbox)
   * Returns only status/confirmation
3. Agent processes minimal output for final response
4. Reduced context pollution, no intermediate data

#### Key Takeaways

* **5x faster execution**: PTC reduced total time from 149s to 30s
* **8x fewer tokens**: Token usage dropped from 47K to 5.8K tokens
* **Eliminated context pollution**: Large Drive content never entered agent context
* **Reduced API costs**: 87.5% reduction in tokens = proportional cost savings
* **Simpler orchestration**: Single code execution handles the entire workflow

> **Success**
>
> This demo represents a realistic multi-tool workflow. The improvements scale with workflow complexity—more tool calls and larger intermediate data lead to greater PTC benefits.

### Usage Patterns

{% hint style="info" %}
The code examples below show what the agent might generate when using PTC. You configure the agent and give it a task—the agent writes the orchestration code automatically.
{% endhint %}

#### Pattern 1: Parallel Data Collection

Fetch data from multiple sources concurrently:

```python
from glaip_sdk.agents import Agent
from glaip_sdk.ptc import PTC

agent = Agent(
    name="parallel_fetcher",
    instruction="Fetch data from multiple sources in parallel using execute_ptc_code.",
    mcps=[data_mcp],
    ptc=PTC(enabled=True)
)
```

Example agent-generated code:

```python
import asyncio
from tools.data_mcp import get_sales_data

results = await asyncio.gather(
    get_sales_data("Q1"),
    get_sales_data("Q2"),
    get_sales_data("Q3"),
    get_sales_data("Q4")
)

total_sales = sum(r["total"] for r in results)
print(f"Annual sales: ${total_sales}")
```

#### Pattern 2: Filter and Aggregate

Process large datasets and return only relevant summaries:

```python
agent = Agent(
    name="log_analyzer",
    instruction="Analyze logs for errors using execute_ptc_code.",
    mcps=[log_mcp],
    ptc=PTC(enabled=True)
)
```

Example agent-generated code:

```python
import json
from tools.log_mcp import fetch_logs

logs = await fetch_logs("app.log", lines=10000)

errors = [log for log in logs if log["level"] == "ERROR"]
error_counts = {}
for error in errors:
    error_counts[error["message"]] = error_counts.get(error["message"], 0) + 1

# Return only top 5 error types
top_errors = sorted(error_counts.items(), key=lambda x: x[1], reverse=True)[:5]
print(json.dumps(dict(top_errors)))
```

#### Pattern 3: Multi-Step Data Pipeline

Chain multiple operations without context pollution:

```python
agent = Agent(
    name="pipeline_processor",
    instruction="Process customer data pipeline using execute_ptc_code.",
    mcps=[db_mcp, api_mcp],
    ptc=PTC(enabled=True)
)
```

Example agent-generated code:

```python
import asyncio
import json
from tools.db_mcp import get_customers
from tools.api_mcp import get_purchase_history

# Step 1: Fetch raw customer data
customers = await get_customers(status="active")

# Step 2: Enrich with purchase history
enriched = await asyncio.gather(*[
    get_purchase_history(c["id"]) for c in customers
])

# Step 3: Calculate lifetime value
for customer, purchases in zip(customers, enriched):
    customer["ltv"] = sum(p["amount"] for p in purchases)

# Step 4: Filter high-value customers
high_value = [c for c in customers if c["ltv"] > 10000]

# Return summary only
print(f"High-value customers: {len(high_value)}")
print(json.dumps([{"name": c["name"], "ltv": c["ltv"]} for c in high_value[:10]]))
```

### Error Handling

#### Missing E2B API Key

```python
# If E2B_API_KEY is not set
result = agent.run("Process data", local=True)
# Error: E2B_API_KEY environment variable is required for PTC execution
```

**Solution**: Set your E2B API key before running:

```bash
export E2B_API_KEY="your-key-here"
```

#### Sandbox Timeout

```python
# If code execution exceeds sandbox_timeout
ptc = PTC(enabled=True, sandbox_timeout=60.0)
# Error: Sandbox execution timed out after 60 seconds
```

**Solution**: Increase `sandbox_timeout` for long-running operations:

```python
ptc = PTC(enabled=True, sandbox_timeout=300.0)  # 5 minutes
```

#### Runtime Override Attempts

```python
# Attempting to override PTC via runtime_config
agent.run("task", local=True, runtime_config={"ptc": {...}})
# ValidationError: ptc cannot be overridden via runtime_config
```

**Solution**: Configure PTC only via `Agent.ptc` parameter.

### Best Practices

#### Specifying Tool Response Formats

For tools with nested or complex response structures, include the format in your agent instruction to help the agent generate correct code:

```python
agent = Agent(
    name="my_agent",
    instruction="""You are a helpful assistant.

When calling via code, tool_name returns:
{"data": {"field": value}, "meta": {...}}

Access data using result["data"]["field"].""",
    mcps=[my_mcp],
    ptc=PTC(enabled=True)
)
```

#### Performance Optimization

1. **Use parallel execution for independent operations:**

   ```python
   import asyncio
   from tools.data_mcp import fetch_data

   # Good: Parallel fetching
   results = await asyncio.gather(*[fetch_data(id) for id in ids])

   # Avoid: Sequential fetching
   results = [await fetch_data(id) for id in ids]
   ```
2. **Filter data early to minimize processing:**

   ```python
   import asyncio
   from tools.user_mcp import get_details

   # Good: Filter before expensive operations
   active_users = [u for u in users if u["status"] == "active"]
   details = await asyncio.gather(*[get_details(u["id"]) for u in active_users])

   # Avoid: Fetch all, then filter
   all_details = await asyncio.gather(*[get_details(u["id"]) for u in users])
   active_details = [d for d in all_details if d["status"] == "active"]
   ```
3. **Return only essential data:**

   ```python
   import json

   # Good: Return summary
   print(json.dumps({"total": sum(amounts), "count": len(amounts)}))

   # Avoid: Return all raw data
   print(json.dumps(all_records))
   ```

#### Code Quality in PTC

1. **Handle errors gracefully:**

   ```python
   from tools.data_mcp import fetch_data

   try:
       data = await fetch_data(id)
   except Exception as e:
       print(f"Error fetching data: {e}")
       data = None
   ```
2. **Use structured output formats:**

   ```python
   import json

   # Good: JSON output
   print(json.dumps({"results": results, "count": len(results)}))

   # Avoid: Unstructured strings
   print(f"Found {len(results)} results: {results}")
   ```
3. **Set reasonable timeouts:**

   ```python
   # For quick operations
   ptc = PTC(enabled=True, sandbox_timeout=30.0)

   # For complex workflows
   ptc = PTC(enabled=True, sandbox_timeout=300.0)
   ```

#### Security Considerations

1. **Validate tool outputs before processing:**

   ```python
   from tools.data_mcp import get_data

   data = await get_data()
   if not isinstance(data, list):
       print("Error: Invalid data format")
       return
   ```
2. **Avoid exposing sensitive data in outputs:**

   ```python
   import json

   # Good: Sanitize output
   print(json.dumps([{"id": u["id"], "name": u["name"]} for u in users]))

   # Avoid: Including sensitive fields
   print(json.dumps(users))  # May contain passwords, tokens, etc.
   ```
3. **Use sandbox timeout to prevent runaway code:**

   ```python
   ptc = PTC(enabled=True, sandbox_timeout=120.0)  # Always set a timeout
   ```

### Troubleshooting

#### Common Issues

**"PTC module not found"**

* Install local dependencies: `pip install glaip-sdk[local]`

**"E2B\_API\_KEY not set"**

* Local runs require this variable. Set it with: `export E2B_API_KEY="your-key"`
* Get key from [e2b.dev](https://e2b.dev)

**"execute\_ptc\_code tool not available"**

* Ensure PTC is enabled: `ptc=PTC(enabled=True)`
* Verify execution mode is configured correctly:
  * Local run: `agent.run(local=True)` with local dependencies and `E2B_API_KEY`
  * Remote run: call `agent.deploy()` first, then `agent.run(...)`
* Check that tools are configured

**"Sandbox execution failed"**

* Check E2B service status
* Verify network connectivity
* Review code for syntax errors in agent-generated code

**"Code timeout exceeded"**

* Increase `sandbox_timeout` in PTC config
* Optimize code for faster execution
* Consider splitting into smaller operations

#### Debugging PTC Execution

Enable detailed logging:

```python
import logging
logging.basicConfig(level=logging.DEBUG)

# Run agent with verbose output
result = agent.run("task", local=True)
```

Check sandbox output in logs:

```
DEBUG:aip_agents.runtime.ptc:Sandbox code execution started
DEBUG:aip_agents.runtime.ptc:Tool call: get_team_members
DEBUG:aip_agents.runtime.ptc:Tool call: get_expenses
DEBUG:aip_agents.runtime.ptc:Sandbox stdout: {"results": [...]}
```

### API Reference

#### Core Classes

**`PTC`** - Configuration object for Programmatic Tool Calling:

```python
PTC(
    enabled: bool,                           # Required: Must be True to activate
    sandbox_timeout: float = 120.0,          # Optional: Global sandbox timeout (seconds)
    default_tool_timeout: float = 60.0,      # Optional: Per-MCP-call timeout (seconds)
    sandbox_template: str | None = None,     # Optional: Sandbox runtime template override
    auto_build_template: bool | None = None,  # Optional: Forward template auto-build toggle
    package_install_timeout: float | None = None,  # Optional: Forward package-install timeout
    prompt: dict = None                      # Optional: Prompt configuration
)
```

**Properties:**

* `enabled`: Boolean flag to activate/deactivate PTC
* `sandbox_timeout`: Maximum execution time for full sandbox execution
* `default_tool_timeout`: Timeout applied per MCP tool call within sandbox wrappers
* `sandbox_template`: Sandbox runtime template identifier
* `auto_build_template`: Optional template auto-build toggle passthrough
* `package_install_timeout`: Optional package-install timeout passthrough
* `prompt`: Dictionary with `mode` ("auto" | "minimal" | "index" | "full"), `auto_threshold` (int), and `include_example` (bool)

#### Automatic Tool Registration

When PTC is enabled, the `execute_ptc_code` tool is automatically registered and available to the agent. This tool allows the agent to execute Python code in the E2B sandbox with access to all configured tools.

### Related Documentation

* [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) — Configure and use tools with agents
* [MCPs guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/mcps) — Set up Model Context Protocol tools
* [Local vs Remote](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/local-vs-remote) — Understand local and remote execution modes

### Additional Resources

* [GL SDK Documentation](https://gdplabs.gitbook.io/sdk) — Core SDK reference
* [E2B Sandbox Documentation](https://e2b.dev/docs) — E2B sandbox configuration and API
* [Anthropic Tool Use Guide](https://docs.anthropic.com/en/docs/build-with-claude/tool-use) — Advanced tool calling patterns
* Contact enterprise support for advanced PTC configuration assistance


# Human in the Loop Approvals

Enable manual checkpoints for high-risk actions by routing agent decisions through an operator before execution. This guide outlines the end-to-end flow, where it fits in existing automation, and how to combine it with the SDK and CLI.

{% hint style="warning" %}
HITL runtime examples should stay Agent-first where possible. `Client` examples in this page are advanced integrations for remote handler customization and workspace-level approval orchestration.
{% endhint %}

### When to Use HITL

* You need an audit trail for outbound actions (email, ticketing, CRM updates).
* Teams want live visibility into agent decisions without disabling automation.
* Regulatory or compliance policies require operator approval on sensitive steps.

### Quick Start

#### Auto-Approval (Local Testing/CI)

```python
import os
os.environ["GLAIP_HITL_AUTO_APPROVE"] = "true"

from glaip_sdk.agents import Agent
from tools import CalculatorTool  # Any LangChain BaseTool subclass.

# Local auto-approval uses LocalPromptHandler, injected when hitl_enabled is True.
agent = Agent(
    name="hitl_local_agent",
    instruction="Use the calculator tool when needed.",
    tools=[CalculatorTool],
    tool_configs={CalculatorTool: {"hitl": {"timeout_seconds": 30}}},
    agent_config={"hitl_enabled": True},
)

response = agent.run("Calculate 2 + 2", local=True)
# All HITL requests auto-approved.
```

**Note:** Local HITL prompts do not enforce timeouts; approval waits indefinitely.

#### Auto-Approval (Remote Testing/CI)

For remote runs, the env var is only read by `RemoteHITLHandler`. Make sure you pass one so HITL requests are actually resolved.

```python
import os
os.environ["GLAIP_HITL_AUTO_APPROVE"] = "true"

from glaip_sdk import Client
from glaip_sdk.hitl.remote import RemoteHITLHandler

client = Client(api_url="...", api_key="...")
handler = RemoteHITLHandler(client=client)  # Reads env var.
response = client.agents.run_agent(
    agent_id,
    "Run with auto-approval",
    hitl_handler=handler,
)
```

#### Custom Approval Logic

```python
from glaip_sdk import Client
from glaip_sdk.hitl.remote import RemoteHITLHandler
from glaip_sdk.hitl.base import HITLRequest, HITLResponse, HITLDecision

def approver(request: HITLRequest) -> HITLResponse:
    # Auto-approve safe tools
    if request.tool_name in ["read_file", "search"]:
        return HITLResponse(decision=HITLDecision.APPROVED)

    # Auto-reject dangerous tools
    if "delete" in request.tool_name.lower():
        return HITLResponse(
            decision=HITLDecision.REJECTED,
            operator_input="Dangerous operation blocked"
        )

    # Interactive prompt for others
    choice = input(f"Approve {request.tool_name}? (y/n/s): ")
    if choice == 'y':
        return HITLResponse(decision=HITLDecision.APPROVED)
    elif choice == 'n':
        return HITLResponse(decision=HITLDecision.REJECTED)
    else:
        return HITLResponse(decision=HITLDecision.SKIPPED)

client = Client(api_url="...", api_key="...")
handler = RemoteHITLHandler(callback=approver, client=client)

response = client.agents.run_agent(
    agent_id,
    "Perform actions requiring approval",
    hitl_handler=handler,
)
```

**Note:** Keep callbacks short and handle timeouts; for longer approvals, use the manual approval flow (`hitl.list_pending` + approve/reject) from another process. Log errors for operational visibility.

#### Manual Approval (Separate Process)

```python
from glaip_sdk import Client

client = Client(api_url="...", api_key="...")

# In monitoring dashboard/script
pending = client.hitl.list_pending()
for req in pending:
    print(f"Tool: {req['tool']}, Args: {req['arguments']}")
    decision = input("Approve? (y/n): ")

    if decision == 'y':
        client.hitl.approve(req['request_id'], operator_input="Approved")
    else:
        client.hitl.reject(req['request_id'], operator_input="Rejected")
```

### Components

* **Approval-aware tool** — Exposes a tool that records pending actions instead of executing them immediately.
* **HITL-enabled agent** — Flags tools that require approval and pauses run execution until a decision arrives.
* **Operator console** — Any surface (custom UI, CLI, or scripts) that calls the HITL APIs (prefer the Python SDK; REST is reference-only for internal integrations).

### Detecting Pauses in a Run

* Remote runs stream Server-Sent Events. When an approval is required the chunk includes `metadata.hitl`.
* Capture the `metadata.hitl.request_id` and `metadata.tool_info` fields to populate the operator UI. `metadata.hitl.decision` moves from `pending` to `approved`, `rejected`, or `timeout_skip` once resolved.
* Keep the stream open so follow-up tokens deliver the agent's response after the decision lands.

### Typical Workflow

1. Upload or register a tool that surfaces actions for approval.
2. Create an agent with `hitl_enabled` set and map the tool to HITL settings and timeouts.
3. Start a run and watch the SSE stream for `metadata.hitl.decision == "pending"` to know when to open an approval card.
4. Let operators approve in your console using the SDK (`client.hitl.approve(...)` / `client.hitl.reject(...)`) with the streamed `request_id`.
5. Optionally monitor pending approvals via `client.hitl.list_pending()` for inbox-style dashboards or recovery from client restarts.
6. Remove temporary agents, tools, or runs when tests finish.

### Implementation Paths

#### Python SDK - Remote HITL Handler (Recommended)

Use `RemoteHITLHandler` for programmatic approval workflows:

**Features:**

* Thread-based callback execution (non-blocking)
* Timeout enforcement (80% of backend timeout)
* Automatic retry on network/server errors
* Error recovery (callback exceptions handled gracefully)

**Patterns:**

1. **Auto-approval**: Set `GLAIP_HITL_AUTO_APPROVE=true` or `auto_approve=True`
2. **Conditional approval**: Callback with business logic (safe/dangerous tools)
3. **Interactive approval**: User prompts with timeout handling
4. **Logging-only**: Auto-approve but log all requests for audit
5. **Manual approval**: Separate process polling `client.hitl.list_pending()`

#### REST API

Follow the detailed payloads in the [HITL REST Workflow Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/hitl) for cURL-ready examples and sample SSE payloads.

#### CLI

Combine `aip agents run` with small scripts that invoke the HITL endpoints for approvals. Perfect for demos or manual QA.

### Best Practices

* **Separate duties** — Store approval history outside the agent payload so you can report on reviewer actions.
* **Define timeouts** — Use `tool_configs[tool_id].hitl.timeout_seconds` to align with your SLA. Callbacks get 80% of this time (20% reserved for network).
* **Alerting** — Hook pending requests into chat or incident systems to avoid stalled workflows. Use `on_unrecoverable_error` callback for critical alerts.
* **Testing** — Include HITL runs in integration tests to ensure endpoints stay in sync across releases. Use auto-approval for CI/CD pipelines.
* **Error handling** — Callbacks should complete quickly and handle exceptions internally. Callback exceptions are logged and treated as REJECTED.
* **Thread safety** — If using custom `BaseClient`, ensure it's thread-safe or pass a dedicated client instance to `RemoteHITLHandler`.

### Testing & Examples

With these pieces in place you can ship agents that stay fast for low-risk scenarios while keeping an operator in the loop for everything else.

***

### API Reference

#### Decision Types

| Decision | Code                    | Behavior      |
| -------- | ----------------------- | ------------- |
| Approve  | `HITLDecision.APPROVED` | Tool executes |
| Reject   | `HITLDecision.REJECTED` | Tool blocked  |
| Skip     | `HITLDecision.SKIPPED`  | Tool skipped  |

#### HITLRequest Fields

```python
@dataclass
class HITLRequest:
    request_id: str          # Unique ID for this request
    tool_name: str           # Name of tool requiring approval
    tool_args: dict          # Arguments being passed to tool
    timeout_at: str          # ISO 8601 deadline (authoritative)
    timeout_seconds: int     # Timeout in seconds (informational)
    hitl_metadata: dict      # Raw HITL metadata
    tool_metadata: dict      # Raw tool metadata
```

**Example:**

```python
request.request_id        # "bc4d0a77-7800-470e-a91c-7fd663a66b4d"
request.tool_name         # "send_email"
request.tool_args         # {"to": "user@example.com", "subject": "..."}
request.timeout_at        # "2026-01-05T10:30:00Z"
request.timeout_seconds   # 180
```

#### HITLResponse Fields

```python
@dataclass
class HITLResponse:
    decision: HITLDecision            # APPROVED, REJECTED, or SKIPPED
    operator_input: str | None = None # Optional reason/notes
```

**Examples:**

```python
# Approve
HITLResponse(decision=HITLDecision.APPROVED)

# Reject with reason
HITLResponse(
    decision=HITLDecision.REJECTED,
    operator_input="Production writes not allowed"
)

# Skip with note
HITLResponse(
    decision=HITLDecision.SKIPPED,
    operator_input="Tool temporarily unavailable"
)
```

#### RemoteHITLHandler Configuration

```python
RemoteHITLHandler(
    callback=your_callback,           # Approval function (optional)
    client=client,                     # BaseClient instance (required)
    auto_approve=None,                 # Override env var (optional)
    max_retries=3,                     # POST retries (default: 3)
    on_unrecoverable_error=handler,    # Error callback (optional)
)
```

**Parameters:**

* `callback`: Function `(HITLRequest) -> HITLResponse`
  * If `None` and `auto_approve=False`, requests will be rejected
* `client`: `BaseClient` instance for posting decisions
* `auto_approve`: Override `GLAIP_HITL_AUTO_APPROVE` env var
* `max_retries`: Max retries for POST errors (default: 3)
* `on_unrecoverable_error`: Called when both callback and POST fail

#### Manual Approval API

**List Pending Requests:**

```python
pending = client.hitl.list_pending()
# Returns: [{"request_id": "...", "tool": "...", "arguments": {...}, ...}, ...]
```

**Approve a Request:**

```python
client.hitl.approve(
    request_id="bc4d0a77-...",
    operator_input="Verified and approved",  # Optional
    run_id="run-123",                        # Optional
)
```

**Reject a Request:**

```python
client.hitl.reject(
    request_id="bc4d0a77-...",
    operator_input="Policy violation",       # Optional
    run_id="run-123",                        # Optional
)
```

**Skip a Request:**

```python
client.hitl.skip(
    request_id="bc4d0a77-...",
    operator_input="Tool unavailable",       # Optional
    run_id="run-123",                        # Optional
)
```

### Common Patterns

#### Conditional Approval

```python
def smart_approver(request: HITLRequest) -> HITLResponse:
    # Whitelist safe tools
    if request.tool_name in ["read_file", "search", "list"]:
        return HITLResponse(decision=HITLDecision.APPROVED)

    # Blacklist dangerous tools
    if "delete" in request.tool_name.lower():
        return HITLResponse(
            decision=HITLDecision.REJECTED,
            operator_input="Dangerous operation blocked"
        )

    # Check arguments
    if "production" in str(request.tool_args).lower():
        return HITLResponse(
            decision=HITLDecision.REJECTED,
            operator_input="No production modifications"
        )

    # Default: approve
    return HITLResponse(decision=HITLDecision.APPROVED)
```

#### Interactive Approval

```python
def interactive_approver(request: HITLRequest) -> HITLResponse:
    print(f"Tool: {request.tool_name}")
    print(f"Args: {request.tool_args}")

    choice = input("Approve? [y/n/s]: ").lower()

    if choice == 'y':
        return HITLResponse(decision=HITLDecision.APPROVED)
    elif choice == 'n':
        reason = input("Reason: ")
        return HITLResponse(
            decision=HITLDecision.REJECTED,
            operator_input=reason
        )
    else:
        return HITLResponse(decision=HITLDecision.SKIPPED)
```

#### Logging + Auto-Approve

```python
import json
from datetime import datetime

def logging_approver(request: HITLRequest) -> HITLResponse:
    # Log to audit trail
    log_entry = {
        "timestamp": datetime.now().isoformat(),
        "request_id": request.request_id,
        "tool_name": request.tool_name,
        "tool_args": request.tool_args,
        "decision": "approved",
    }

    with open("hitl_audit.jsonl", "a") as f:
        f.write(json.dumps(log_entry) + "\n")

    # Auto-approve
    return HITLResponse(decision=HITLDecision.APPROVED)
```

#### Error Handling

```python
def robust_approver(request: HITLRequest) -> HITLResponse:
    try:
        # Your approval logic
        return HITLResponse(decision=HITLDecision.APPROVED)

    except Exception as e:
        # Fallback: reject on error
        return HITLResponse(
            decision=HITLDecision.REJECTED,
            operator_input=f"Error: {str(e)[:100]}"
        )

def error_handler(request_id: str, error: Exception) -> None:
    # Handle unrecoverable errors (callback + POST both failed)
    print(f"CRITICAL: HITL request {request_id} failed: {error}")
    # Send alert to monitoring system

handler = RemoteHITLHandler(
    callback=robust_approver,
    client=client,
    on_unrecoverable_error=error_handler,
)
```

### Error Handling Details

#### Callback Errors

| Error            | Behavior                    |
| ---------------- | --------------------------- |
| Callback raises  | Log error, reject request   |
| Callback timeout | Log timeout, reject request |
| Invalid response | Log error, reject request   |

#### POST Errors

| Error                  | Behavior                          |
| ---------------------- | --------------------------------- |
| Network error          | Retry 3x with delays (1s, 2s, 3s) |
| 5xx server error       | Retry 3x with delays              |
| 4xx client error       | Fail immediately, no retry        |
| 404 (not found)        | Treated as resolved, no retry     |
| 409 (already resolved) | Treated as resolved, no retry     |

#### Unrecoverable Errors

When both callback execution **and** fallback rejection POST fail:

1. Error is logged
2. `on_unrecoverable_error` callback is invoked (if provided)
3. Backend will eventually timeout the request

### Timeout Details

**Callback Timeout:**

* Callbacks get 80% of backend timeout
* 20% reserved for network/POST operations

**Example:**

* Backend timeout: 60 seconds
* Callback timeout: 48 seconds (80%)
* Network buffer: 12 seconds (20%)

**Source of truth:** `timeout_at` field (ISO 8601 deadline) **Fallback:** `timeout_seconds` field (only if `timeout_at` parsing fails)

### Environment Variables

```bash
# Auto-approve all HITL requests
export GLAIP_HITL_AUTO_APPROVE=true

# Backend URL
export AIP_API_URL=http://localhost:8000

# API Key
export AIP_API_KEY=your-api-key
```

### Complete Example

```python
import os
from glaip_sdk import Client
from glaip_sdk.hitl.remote import RemoteHITLHandler
from glaip_sdk.hitl.base import HITLRequest, HITLResponse, HITLDecision

# Approval callback
def smart_approver(request: HITLRequest) -> HITLResponse:
    # Safe tools
    if request.tool_name in ["read_file", "search"]:
        return HITLResponse(decision=HITLDecision.APPROVED)

    # Dangerous tools
    if "delete" in request.tool_name.lower():
        return HITLResponse(
            decision=HITLDecision.REJECTED,
            operator_input="Dangerous operation blocked"
        )

    # Default
    return HITLResponse(decision=HITLDecision.APPROVED)

# Error handler
def on_error(request_id: str, error: Exception) -> None:
    print(f"CRITICAL ERROR: {request_id} - {error}")

# Setup
client = Client(
    api_url=os.getenv("AIP_API_URL"),
    api_key=os.getenv("AIP_API_KEY"),
)

handler = RemoteHITLHandler(
    callback=smart_approver,
    client=client,
    max_retries=3,
    on_unrecoverable_error=on_error,
)

# Run agent with HITL handler
response = client.agents.run_agent(
    agent_id="your-agent-id",
    message="Perform actions requiring approval",
    hitl_handler=handler,
)

print(f"Response: {response}")
```


# File Processing

Attach files to agent runs, reuse artifacts from prior attachments, and manage chunk IDs for long-form analysis. Reach for this guide when agents need to consume documents, transcripts, or datasets with the Python SDK. CLI support exists for common flows. REST is reference-only.

{% hint style="info" %}
File-handling support is summarised in the [AIP capability matrix](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/introduction-to-gl-aip#platform-capabilities-at-a-glance). The main limitation today is regenerating presigned URLs. Use the REST reference endpoint when a URL expires.
{% endhint %}

{% hint style="info" %}
`aip agents run` accepts either an agent ID or a unique name. Use `--select` to pick from partial name matches or provide the ID directly when scripting.
{% endhint %}

### Attach Files to an Agent Run

*When to use:* Collect fresh documents from users or pipelines and supply them during execution.

{% hint style="info" %}
**Local Document Processing:** For local execution, you can use document loader tools like `PDFReaderTool`, `DocxReaderTool`, and `ExcelReaderTool` from `aip-agents` to read files directly from disk without uploading to the server. Attach the file in the same run so the tool has access to it. See the [Local vs Remote guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/local-vs-remote) for the document loader tools quickstart and example (`main_with_docproc_pdf.py`).
{% endhint %}

**Python SDK**

```python
from glaip_sdk import Agent

agent = Agent(name="analysis-agent", instruction="You analyze documents.")

response = agent.run(
    "Summarise the document and extract key metrics",
    files=["./reports/q1.pdf", "./reports/q2.pdf"],
)
print(response)
```

**CLI**

```bash
aip agents run analysis-agent \
  --input "Summarise these reports" \
  --file reports/q1.pdf \
  --file reports/q2.pdf \
  --view json > summary.json
```

#### Common attachment errors

| Symptom                         | Likely cause                                      | Fix                                                                                     |
| ------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `413 Payload Too Large`         | File exceeds backend attachment/upload limits.    | Compress the file or split it into smaller chunks.                                      |
| Missing file in run logs        | File path incorrect or permissions denied.        | Double-check the path, ensure the process can read the file, or use absolute paths.     |
| Duplicate chunks created        | Run attaches files without reusing `artifact_id`. | Pass the stored chunk IDs using the reuse workflows in the next section.                |
| `Unsupported media type` errors | File type not allowed for ingestion.              | Convert to a supported format (PDF, TXT, DOCX) or register a custom ingestion pipeline. |

### Reuse Chunk IDs from Prior Attachments

*When to use:* Avoid re-ingesting the same files while keeping chunk IDs stable across runs.

When the backend returns `chunk_ids`, store them for later runs:

```python
chunk_ids = ["chunk-abc", "chunk-def"]
agent.run(
    "Compare the latest reports with previous attachments",
    chunk_ids=chunk_ids,
)
```

{% hint style="info" %}
CLI support for passing `chunk_ids` is coming soon. Use the SDK today to avoid re-attaching large files (REST is reference-only).
{% endhint %}

### Retrieve Artifacts and Output

*When to use:* Capture the processed results, enriched files, or generated reports after execution.

1. Capture the run ID from the streaming response (`X-Run-ID`).
2. List run history with the SDK:

   ```python
   from glaip_sdk import Client

   client = Client()
   runs = client.agents.runs.list_runs(agent_id="agent-id", limit=20, page=1)
   print([r.id for r in runs.data])
   ```
3. Download artifacts directly from the presigned URLs in the response. If a URL has expired, regenerate it using the REST reference utilities (internal integrations only): [Utilities](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/utilities).

### Best Practices

*When to use:* Create organisation-wide guardrails for storage, retention, and compliance.

* **Compress large files** — keep attachments efficient and within allowable limits.
* **Track chunk IDs** — store them alongside run metadata so you can reference prior attachments without retransmitting data.
* **Sanitise inputs** — redaction or PII masking should occur before attaching sensitive documents; see the [Security & privacy guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy).
* **Automate clean-up** — if you are storing artifacts locally for auditing, ensure rotation policies are in place.

### Related Documentation

* [Local vs Remote](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/local-vs-remote) — local vs remote file processing comparison and built-in tools overview.
* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — streaming behaviour and runtime overrides.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — capture outputs in CI pipelines.
* [Configuration management](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) — export/import agents that rely on file workflows.


# Agent Filesystem

Give agents a managed filesystem during execution so they can read, write, edit, and search files as part of a run.

Use this guide when you need stateful file operations across a run, large tool output capture, or multi-agent workflows that share artifacts.

{% hint style="info" %}
For document ingestion (attachments, chunk IDs, artifact retrieval), use the [File Processing Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/file-processing). This page focuses on runtime filesystem tooling.
{% endhint %}

## Quick Start

```python
from glaip_sdk import Agent

agent = Agent(
    name="file-agent",
    instruction="Use files to plan, draft, and revise outputs.",
    filesystem=True,  # Defaults to Local Disk
)

agent.run("Create /reports/summary.txt and then read it back.")
```

## Backend Options

| Backend                               | Best For                  | Execute Default | Persistence |
| ------------------------------------- | ------------------------- | --------------- | ----------- |
| `filesystem=True` / `LocalDiskConfig` | Local development         | **Disabled** ⚠️ | Yes         |
| `LocalDiskConfig(allow_execute=True)` | Local + remote execution  | **Enabled** ✅   | Yes         |
| `InMemoryConfig`                      | Testing, ephemeral work   | N/A             | No          |
| `SandboxConfig`                       | Untrusted code, isolation | **Enabled** ✅   | No          |

{% hint style="danger" %}
**Critical:** `filesystem=True` uses Local Disk with **execute disabled by default** (security).

* To run commands safely: Use `SandboxConfig()` (isolated environment)
* Or explicitly enable: `LocalDiskConfig(base_directory="/tmp/agent_files", allow_execute=True)`

**Warning:** `LocalDiskConfig(allow_execute=True)` runs commands directly on the runner host without sandbox isolation. Use only for trusted workloads. For untrusted code execution, always use `SandboxConfig`.
{% endhint %}

## Usage Examples

### Local Disk (Default)

```python
from glaip_sdk import Agent

# Simple default - file operations only, no execute
agent = Agent(name="docs", instruction="...", filesystem=True)

# Or explicit with custom path
from glaip_sdk.models.filesystem import LocalDiskConfig

agent = Agent(
    name="docs",
    instruction="...",
    filesystem=LocalDiskConfig(
        base_directory="/tmp/agent_files",
        env={"GH_TOKEN": "***"},
    ),
)
```

### In-Memory (Testing)

```python
from glaip_sdk import Agent
from glaip_sdk.models.filesystem import InMemoryConfig

agent = Agent(
    name="test",
    instruction="...",
    filesystem=InMemoryConfig(),  # Ephemeral, no persistence
)
```

### Sandbox (Isolated Execution)

```python
from glaip_sdk import Agent
from glaip_sdk.models.filesystem import SandboxConfig

# Execute enabled by default - safe for running code
agent = Agent(
    name="secure-runner",
    instruction="Run code safely in isolation.",
    filesystem=SandboxConfig(
        env={"MYCELIUM_MODE": "prod"},
    ),
)

agent.run("""
Create a Python script that calculates factorial,
run it with execute, and save the result.
""")
```

## Image Inputs And `read_image`

Use this when a run includes image files and the agent needs to inspect visual details. Enable vision for image inspection (filesystem is not required — add it only when the agent also needs runtime file tools):

```python
from glaip_sdk import Agent

agent = Agent(
    name="image-reader",
    instruction="Use read_image when visual details in provided images matter.",
    agent_config={"vision": True},
)

response = agent.run(
    "Inspect the provided image and describe the important details.",
    files=["./images/example.png"],
)
```

Images passed through `Agent.run(..., files=[...])` are registered as image attachments for the run. They are not automatically injected into every model prompt. When visual details are needed, the agent calls `read_image` to turn the selected image into text context. By default, `read_image` uses the same model configured for the agent.

Path semantics:

* `files=["./images/example.png"]` is a host path supplied by the SDK caller.
* Filesystem tool paths such as `/images/example.png` are virtual paths relative to the configured filesystem root.
* `read_file` is for text/code files. Use `read_image` for PNG, JPEG/JPG, or WebP images.

When a tool creates a supported image artifact during a run, the agent can inspect it later with `read_image("chart.png", "What trend does this chart show?")`.

## Available File Tools

When filesystem is enabled, agents receive these file operation tools. Vision-enabled agents can also receive `read_image` for registered image attachments and generated image artifacts.

### `read_file` - Read File Contents

**Purpose:** Read all or part of a file.

**When to use:** Inspecting file contents, reading configuration, examining logs, accessing evicted tool outputs.

**Examples:**

```python
# Read entire file (small files only)
read_file(path="/config/app.yaml")

# Read specific lines
read_file(path="/logs/server.log", line_offset=100, limit=50)

# Read by character offset (for large files)
read_file(path="/data/large.json", char_offset=0, max_chars=20000)
```

**Key parameters:**

* `path` - Absolute file path (required)
* `line_offset` + `limit` - Line-based pagination
* `char_offset` + `max_chars` - Character-based pagination

See [Reading Large Files](#reading-large-files--outputs) for pagination details.

### `read_image` - Inspect Images

**Purpose:** Analyze a registered image attachment or generated image artifact and return text context.

**When to use:** A user provides an image file (via `files=[]`) or a tool creates an image artifact, and the agent needs to describe its visual content.

**Examples:**

```python
# Inspect an image by its registered filename
read_image(image="example.png", query="What does this image show?")

# Inspect by artifact filename (from a tool output)
read_image(image="chart.png", query="What trend does this chart show?")
```

**Key parameters:**

* `image` - Registered filename, artifact name, or image attachment ID (required)
* `query` - Optional targeted question about the image

**Behavior:**

* `read_image` is only available when `agent_config={"vision": True}` is set
* It does not have access to raw file bytes — it receives a safe data URL resolved from the attachment registry
* By default it uses the same model configured for the agent

### `write_file` - Create New Files

**Purpose:** Create a new file. Errors if the destination already exists.

**When to use:** Creating new files, writing initial content, saving outputs that don't exist yet.

**Examples:**

```python
# Create a new file
write_file(
    path="/workspace/output.txt",
    content="Hello, this is the result of my analysis."
)

# Write JSON data
write_file(
    path="/data/results.json",
    content='{"status": "success", "count": 42}'
)
```

**Important:** This tool creates new files only. It will error if the file already exists. Use `edit_file` to modify existing files.

### `edit_file` - Modify Existing Files

**Purpose:** Make targeted changes to specific parts of a file using exact string replacement.

**When to use:** Fixing bugs, updating values, refactoring code, making surgical edits without rewriting the whole file.

**Examples:**

```python
# Replace a specific line
edit_file(
    path="/config/app.yaml",
    old_string="debug: false",
    new_string="debug: true"
)

# Update a function
edit_file(
    path="/src/main.py",
    old_string="def calculate(x):\n    return x * 2",
    new_string="def calculate(x):\n    return x * 3"
)
```

**Key points:**

* Uses exact string matching
* Errors if multiple matches found unless `replace_all=True` is provided
* Must match exactly (including whitespace)

### `ls` - List Directory Contents

**Purpose:** List files and directories at a given path.

**When to use:** Exploring directory structure, finding files, checking what exists, understanding the workspace layout.

**Examples:**

```python
# List current directory
ls(path="/workspace")

# List specific directory
ls(path="/workspace/src")

# Check if directory exists (and see its contents)
ls(path="/data/processed")
```

**Output:** Returns a Python list-style string of absolute file paths (e.g., `['/workspace/file1.txt', '/workspace/file2.txt']`).

### `grep` - Search File Contents

**Purpose:** Search for text patterns within files.

**When to use:** Finding specific text across multiple files, searching logs for errors, locating code patterns, filtering large files.

**Examples:**

```python
# Search for "error" in log files
grep(pattern="ERROR", path="/logs")

# Search for a function definition
grep(pattern="def calculate", path="/workspace/src")

# Search in a specific file
grep(pattern="TODO", path="/workspace/notes.txt")
```

**Key points:**

* `pattern` supports basic text matching
* `path` can be a directory (searches recursively) or specific file
* Filesystem tools (`ls`, `grep`, `read_file`, `write_file`, `edit_file`) are excluded from auto-eviction and always return inline

***

All paths must be **absolute** (start with `/`).

## Reading Large Files & Outputs

### Pagination Strategy

When reading files, agents can use **line-based** or **character-based** pagination. Choose one mode per file and never mix them.

#### Line-Based (Default)

Best for normal code/text files with reasonable line lengths:

```
# Read first 100 lines
read_file(path="/src/main.py", line_offset=0, limit=100)

# Read next 100 lines
read_file(path="/src/main.py", line_offset=100, limit=100)
```

**Use case:** Reading source code, logs, configuration files.

#### Character-Based

Best for large/long-line files (JSON, minified JS, CSV, database query results):

```
# Read first 20,000 characters
read_file(path="/data/large.json", char_offset=0, max_chars=20000)

# Read next 20,000 characters
read_file(path="/data/large.json", char_offset=20000, max_chars=20000)
```

**Use case:** GL Connectors SQL MCP results that return as single-line JSON blobs, minified JavaScript bundles, or large CSV files where lines exceed typical limits.

{% hint style="danger" %}
**Never mix modes:** Once you pick a mode for a file, continue with that mode until done.
{% endhint %}

### Tool Output Auto-Eviction

When tool outputs exceed **\~80,000 characters**, they're automatically saved to `/tool_outputs/<tool_call_id>.txt`.

**Applies to:** Non-filesystem tools (e.g., `execute` tool output, large API responses)

**Excluded from eviction:** Filesystem tools (`read_file`, `write_file`, `edit_file`, `ls`, `grep`) always return inline

**Why this matters:**

* Large command outputs from `execute` tool
* Big API responses that would overflow context window
* Long-running command results

**What the agent receives:**

* File path where content was saved
* Preview (first 500 chars + last 500 chars)
* Instructions to use `read_file` for full access

**Example scenario:**

```
# Agent runs: execute("find /var -name '*.log' | head -1000")
# Returns 100K characters of output
# Automatically saved to: /tool_outputs/call_abc123.txt
# Agent gets preview + instruction to use read_file with pagination
```

### File Watching After Execute

When the agent runs a command via the `execute` tool, the SDK automatically monitors the filesystem for files created or modified by that command. The agent can then discover and use those files without needing to know their paths in advance.

**How it works:**

1. The agent runs a command (e.g., `execute("python script.py")`)
2. After the command finishes, the SDK watches the configured output directories for new or changed files
3. Created files are surfaced to the agent with their paths and content previews
4. The agent can then use `read_file` to inspect these outputs

The watcher timeout is internally managed — commands that produce outputs asynchronously or in batches may need slightly longer for all files to appear.

**Local vs Sandbox strategies:**

| Backend           | Watcher Strategy                    | Notes                                                                      |
| ----------------- | ----------------------------------- | -------------------------------------------------------------------------- |
| `LocalDiskConfig` | `LsDiffWatcher` / `WatchdogWatcher` | Compares directory state before/after, or uses OS-level file notifications |
| `SandboxConfig`   | `E2BFileWatcher`                    | Uses E2B's directory watch API; polls for create/write events              |

**Example flow:**

```mermaid
sequenceDiagram
    participant Agent
    participant SDK
    participant Sandbox

    Agent->>SDK: execute("python analysis.py --out /workspace/output")
    SDK->>Sandbox: run command
    Sandbox-->>SDK: command completes
    SDK->>SDK: file watcher polls /workspace/output
    SDK->>Agent: results.json, chart.png discovered
    Agent->>SDK: read_file("/workspace/output/results.json")
    Agent->>SDK: read_image("chart.png") [if vision enabled]
```

See [Sandbox Filesystem](https://github.com/GDP-ADMIN/gl-sdk/blob/docs/gitbook-sync/gitbook/gl-ai-agent-package/guides/agent-filesystem/sandbox/README.md) for detailed sandbox configuration and use cases.

## When to Use Each Backend

### Local Disk

* ✅ Local development and debugging
* ✅ Need persistence across runs
* ✅ Working with existing files
* ⚠️ Execute disabled by default
* ❌ **Not recommended for remote execute** — runs commands on the runner host without isolation; use `SandboxConfig` for untrusted code

### In-Memory

* ✅ Unit testing
* ✅ Ephemeral operations
* ❌ No execute capability
* ❌ Files lost after run

### Sandbox

* ✅ Running untrusted code
* ✅ CI/CD automation
* ✅ Security-critical workflows
* ✅ Execute enabled by default

{% hint style="warning" %}
**Remote Mode Note:** In remote execution, `LocalDiskConfig.base_directory` is platform-managed. Use explicit paths only for local expectations.
{% endhint %}

## Environment Variables

Inject environment variables into the filesystem execution context. Available on all backends for both local and remote agents.

### Configure at Agent Creation

Set `env` on the filesystem config model when building your agent. This applies to local runs (LocalDisk and Sandbox) and remote runs with `allow_execute=True`.

```python
from glaip_sdk import Agent
from glaip_sdk.models.filesystem import LocalDiskConfig, SandboxConfig

# Local Disk: env merged over ambient, config values take precedence
agent = Agent(
    name="local-worker",
    instruction="...",
    filesystem=LocalDiskConfig(
        base_directory="/tmp/workspace",
        allow_execute=True,
        env={"GH_TOKEN": "***"},
    ),
)

# Sandbox: env forwarded to command execution inside the sandbox
agent = Agent(
    name="sandbox-worker",
    instruction="...",
    filesystem=SandboxConfig(
        env={"MYCELIUM_MODE": "prod"},
    ),
)
```

{% hint style="info" %}
**Validation:** Non-string keys or values are rejected at the SDK boundary with a clear error. Omit `env` entirely for existing behavior — no change required.
{% endhint %}

## Troubleshooting

### "Why can't I run commands with `filesystem=True`?"

**Cause:** Local Disk defaults to `allow_execute=False`.

**Fix:**

```python
# Option 1: Use Sandbox (recommended for untrusted code)
filesystem=SandboxConfig()

# Option 2: Explicitly enable on Local Disk (works locally and remotely)
filesystem=LocalDiskConfig(
    base_directory="/tmp/agent_files",
    allow_execute=True
)
```

{% hint style="warning" %}
**Security:** `LocalDiskConfig(allow_execute=True)` runs commands on the runner host without sandbox isolation. Prefer `SandboxConfig` for any workload that processes untrusted input or executes user-supplied code.
{% endhint %}

### Sandbox Not Available

**Cause:** Missing E2B API key or `glaip-sdk[local]` extras.

**Fix:**

```bash
export E2B_API_KEY="your-key"
pip install "glaip-sdk[local]"
```

## Cookbook

See the [Filesystem Middleware Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/filesystem-middleware) for runnable examples of common patterns including file discovery, lifecycle management, data pipelines, codebase analysis, and security auditing.

## Related Documentation

* [Sandbox Filesystem Deep Dive](https://github.com/GDP-ADMIN/gl-sdk/blob/docs/gitbook-sync/gitbook/gl-ai-agent-package/guides/agent-filesystem/sandbox/README.md) - Detailed sandbox guide
* [File Processing Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/file-processing) - Document ingestion
* [Agents Guide](/sdk/gl-aip-ai-agent-package/guides/agents) - Agent configuration


# Sandbox Filesystem

Run agents in an isolated, ephemeral environment. Perfect for executing untrusted code, CI/CD pipelines, and security-critical workflows.

{% hint style="success" %}
**Key Benefits:**

* ✅ Isolated execution environment
* ✅ Execute enabled by default (safe in isolation)
* ✅ Automatic cleanup after run
* ✅ Works identically in local and remote execution
  {% endhint %}

## Quick Start

```python
from glaip_sdk import Agent
from glaip_sdk.models.filesystem import SandboxConfig

agent = Agent(
    name="secure-runner",
    instruction="Execute code safely in an isolated environment.",
    filesystem=SandboxConfig(),  # Uses defaults
)

result = agent.run("""
Create a Python script that calculates factorial,
run it with the execute tool, and save the result to /workspace/output.txt
""")
```

## When to Use Sandbox

| Use Case             | Why Sandbox?                          |
| -------------------- | ------------------------------------- |
| **Untrusted Code**   | Run arbitrary code without host risk  |
| **CI/CD Automation** | Clean environment for each run        |
| **Data Processing**  | Isolated workspace for sensitive data |
| **Remote Execution** | Same isolation as local               |

## Configuration

```python
SandboxConfig(
    base_dir="/workspace",      # Working directory inside sandbox
    timeout_seconds=300,          # Session timeout (default: 300)
    allow_execute=True,          # Enable/disable execute tool
    env={"MYCELIUM_MODE": "prod"},  # Environment variables (optional)
)
```

### Parameters

* **`base_dir`** - Absolute path (e.g., `/workspace`). Auto-created.
* **`timeout_seconds`** - Must be > 0. Session expires after this duration.
* **`allow_execute`** - `True` (default): Agent can run commands. `False`: File operations only.
* **`env`** - `dict[str, str] | None` (optional): Environment variables injected into sandbox command execution. Omit for existing behavior.

## Prerequisites

### Local Execution

```bash
# Install with local extras
pip install "glaip-sdk[local]"

# Set sandbox provider API key
export E2B_API_KEY="your-api-key"
```

Get your key from the provider dashboard (e.g., [e2b.dev](https://e2b.dev)).

### Remote Execution

* Platform must support sandbox filesystem backend
* No additional setup needed (platform manages the sandbox)

## Examples

### Run Code Safely

```python
agent = Agent(
    name="code-runner",
    instruction="Execute Python code safely.",
    filesystem=SandboxConfig(base_dir="/workspace"),
)

result = agent.run("""
1. Create a Python script at /workspace/script.py
2. Run it with execute
3. Save output to /workspace/result.txt
""")
```

### File Operations Only

```python
# When you only need file operations, disable execute
agent = Agent(
    name="editor",
    instruction="Edit files.",
    filesystem=SandboxConfig(
        base_dir="/workspace",
        allow_execute=False,  # Extra safety
    ),
)
```

### Long-Running Tasks

```python
# Increase timeout for longer processing
agent = Agent(
    name="processor",
    instruction="Process large dataset.",
    filesystem=SandboxConfig(timeout_seconds=600),  # 10 minutes
)
```

### Environment Variables

```python
# Inject env vars into sandbox execution
agent = Agent(
    name="deploy",
    instruction="Deploy using configured credentials.",
    filesystem=SandboxConfig(
        env={
            "DEPLOY_KEY": "sk-...",
            "TARGET_ENV": "staging",
        },
    ),
)
```

The `env` dict is forwarded to command execution inside the sandbox. For local sandbox runs, these are the only environment variables available (no ambient host env is passed through). Omit `env` entirely for existing behavior.

## How It Works

1. **Provisioning** - Isolated environment is provisioned (may take a few seconds on first use)
2. **Execution** - Commands run inside the isolated environment
3. **Cleanup** - Environment is destroyed after run or timeout

{% hint style="warning" %}
**Cold Start:** First sandbox creation may take a few seconds. Subsequent runs in the same session reuse the environment.
{% endhint %}

## Limitations

* **Ephemeral** - Files lost after run ends
* **Resource Limits** - Subject to provider quotas
* **No Persistence** - Cannot save state between runs

## Troubleshooting

### "ModuleNotFoundError: Sandbox filesystem backend requires..."

**Fix:**

```bash
pip install "glaip-sdk[local]"
```

### "E2B\_API\_KEY not set" or tests skipped

**Cause:** Sandbox provider API key not configured

**Fix:**

```bash
export E2B_API_KEY="your-api-key"
```

### "base\_dir must not contain parent directory traversal"

**Fix:** Use absolute path without `..`:

```python
SandboxConfig(base_dir="/workspace")  # ✅
SandboxConfig(base_dir="/../workspace")  # ❌
```

## Comparison with Local Disk

| Aspect          | Local Disk                                            | Sandbox            |
| --------------- | ----------------------------------------------------- | ------------------ |
| **Execute**     | Disabled by default; enable with `allow_execute=True` | Enabled by default |
| **Persistence** | Yes                                                   | No (ephemeral)     |
| **Isolation**   | None                                                  | Full container     |
| **Cleanup**     | Manual                                                | Automatic          |
| **Best For**    | Trusted dev                                           | Untrusted code     |

## Related Documentation

* [Agent Filesystem Overview](/sdk/gl-aip-ai-agent-package/guides/agent-filesystem) - All filesystem backends, file tools, and handling large files
* [Sandbox Execution Example](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/filesystem-middleware/07_sandbox_execute.py) - Runnable cookbook example
* [File Processing Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/file-processing) - Document ingestion
* [Agents Guide](/sdk/gl-aip-ai-agent-package/guides/agents) - Agent configuration


# Security and Privacy

Protect sensitive data while using the AIP SDK and CLI. This guide covers PII masking, tool-output controls, memory scoping, and API key hygiene.

> **Success**
>
> **When to use this guide:** You handle regulated data, govern tooling access, or perform privacy reviews on agent configurations.
>
> **Who benefits:** Security engineers, PMs overseeing compliance, and data developers stewarding user content.

{% hint style="info" %}
Security features by surface are tracked in the [AIP capability matrix](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/introduction-to-gl-aip#platform-capabilities-at-a-glance). Key gaps today: CLI still relies on export/import for `pii_mapping`, memory, and tool-output toggles. Presigned URL regeneration and some auditing workflows use REST reference endpoints.
{% endhint %}

### Mask PII During Runs

*When to use:* Redact sensitive inputs or outputs before sharing transcripts or artifacts.

{% hint style="warning" %}
**Prerequisites:** To use PII masking features, install the privacy extra:

```bash
pip install --upgrade "glaip-sdk[privacy]"
```

**Installation options:**

* **Remote mode only:** `glaip-sdk[privacy]` - Privacy features work with remote API calls
* **Local mode only:** `glaip-sdk[local]` - For local agent execution without privacy
* **Local mode with privacy:** `glaip-sdk[local,privacy]` - For local execution with PII masking
* **All features:** `glaip-sdk[local,privacy,memory]` - Local execution with privacy and memory features
  {% endhint %}

```python
from glaip_sdk import Agent

agent = Agent(name="secure-processor", instruction="Process sensitive inputs.")
response = agent.run(
    "Process <EMAIL_1> order",
    pii_mapping={
        "<EMAIL_1>": "customer@example.com",
        "<NAME_1>": "Alex Taylor",
    },
)
print(response)
```

{% hint style="info" %}
Until CLI flags ship, export the agent JSON, add a `pii_mapping` example, and re-import for automation scenarios.
{% endhint %}

#### Common security gaps

| Symptom                                      | Likely cause                                                    | Fix                                                                       |
| -------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------- |
| PII still appears in outputs                 | Redaction rules incomplete or mismatch between SDK and backend. | Expand `pii_mapping` entries and test with sample payloads.               |
| Shared artifacts visible to unintended teams | `agent_config.tool_output_sharing` left enabled.                | Disable sharing or scope agents per team.                                 |
| Keys leaked in repos                         | Credentials stored in `.env` committed accidentally.            | Add `.env` to `.gitignore`, rotate keys, and use secrets managers.        |
| Expired presigned URLs break workflows       | Long-running jobs using stale download links.                   | Regenerate URLs via the REST Utilities reference (internal integrations). |

### Control Tool Output Sharing

*When to use:* Limit which agents or collaborators can see tool artifacts.

```python
agent.update(agent_config={"tool_output_sharing": False})
```

* `True` — downstream agents can reuse artifacts and tables produced by the agent.
* `False` — artifacts stay isolated to the producing agent.

Configure the field through agent payloads; the CLI will expose a dedicated flag in a future release.

### Manage Memory Scope

*When to use:* Keep conversation history compliant while preserving useful context.

Use `agent_config["memory"] = "mem0"` to persist conversation state between runs. Share memory only when agents belong to the same account and should retain context; otherwise leave memory unset for stateless behaviour.

### API Key Hygiene

*When to use:* Rotate, scope, and store credentials safely across teams.

1. Issue separate keys per environment (dev/staging/production).
2. Store keys in environment variables or secure stores (`aip accounts add` saves them locally under `~/.aip/config.yaml`).
3. Rotate keys regularly and revoke unused values after testing.

### Presigned Artifact Management

*When to use:* Secure file downloads and prevent stale links from leaking data.

* Each run response may include presigned URLs for attached artifacts.
* If a URL expires and you need to regenerate it from an internal integration, use the REST reference only:
* REST reference: [Utilities](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/utilities)
* Keep regenerated URLs short-lived and avoid sharing them broadly.

### Audit Trails

*When to use:* Document who changed what and when for compliance or incident response.

Use run history to trace PII usage, artifact creation, and tool activity.

Python SDK:

```python
from glaip_sdk import Client

client = Client()
runs = client.agents.runs.list_runs(agent_id="<AGENT_ID>", limit=20, page=1)
for run in runs.data:
    print(run.id, run.created_at)
```

CLI (saved locally):

```bash
/transcripts
```

### Related Documentation

* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — configure `pii_mapping`, `tool_configs`, and memory alongside other agent features.
* [File processing](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/file-processing) — handle attached artifacts and chunk reuse securely.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — integrate security checks into CI pipelines.


# Configuration Management

Promote and back up AIP resources across environments. Use this guide when you move configurations between sandboxes, staging, and production or need repeatable backups for version control and peer review.

{% hint style="info" %}
Review export/import support in the [AIP capability matrix](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/introduction-to-gl-aip#platform-capabilities-at-a-glance). Notable constraints: CLI edits to environment-specific overrides still require manual JSON tweaks, and automated backup tooling is driven through REST or custom scripts.
{% endhint %}

{% hint style="info" %}
In CLI snippets, resource arguments accept either the ID or a unique name. If a name matches multiple records, use `--select` to choose the right one or provide the full ID for deterministic promotion scripts.
{% endhint %}

{% hint style="info" %}
Data developers can focus on the CLI examples in this guide. Python samples are included for engineering teams that automate the same workflows in code.

**Example Configuration**: Start from an exported file generated with `aip agents get <agent_id> --export agent-config.yaml` or adapt the sample below.

```yaml
# agent-config.example.yaml
name: prod-research
instruction: >
  You are the production research agent. Act as a senior analyst and cite sources.
model: gpt-4o-mini
timeout: 450
mcps:
  - id: ${MCP_ID}
    description: Weather insights
tools:
  - id: ${TOOL_ID}
    config:
      region: us-east-1
metadata:
  team: insights
  environment: production
```

{% endhint %}

{% hint style="warning" %}
Configuration promotion should default to CLI export/import flows. Use `Client` only for legacy/advanced automation where you need custom orchestration across multiple resources.
{% endhint %}

### Export Resources

*When to use:* Capture the current state before changes or to seed a new environment.

{% hint style="info" %}
**YAML Format Recommendation**: For better readability and version control compatibility, we recommend using YAML format (`.yaml` or `.yml` extension) for configuration files. YAML is more human-readable and handles complex nested structures better than JSON.

JSON exports/imports remain fully supported—simply switch the extension (for example, `aip agents get prod-research --export prod-research.json`). Choose JSON when you need strict tooling compatibility, and YAML when you want easier diffing of multiline prompts.
{% endhint %}

**Agents**

```bash
aip agents get prod-research --export prod-research.yaml
```

**Tools**

```bash
aip tools get query-runner --export query-runner.yaml
```

**MCPs**

```bash
aip mcps get weather-service --export weather-service.yaml
```

Add `--view md` if you need a human-readable snapshot alongside the JSON file.

### Import or Update from Files

*When to use:* Apply reviewed configurations or roll back to a known-good version.

**Create**

```bash
aip agents create --import prod-research.yaml
```

**Update**

```bash
aip agents update prod-research --import prod-research.yaml
```

**Python SDK**

```python
from glaip_sdk import Client

client = Client()

# Create a new agent from an exported / hand-authored file
agent = client.agents.create_agent_from_file("agent-config.yaml")
print(f"Created agent {agent.name} ({agent.id}) from YAML definition.")

# Update an existing agent with the same file (supply the target agent ID)
updated = client.agents.update_agent_from_file(agent.id, "agent-config.yaml")
print(f"Updated agent {updated.name} ({updated.id}) from YAML definition.")
```

{% hint style="info" %}
File-based operations use the Client pattern since they require bulk operations. For simple agent creation, prefer the [Agent pattern](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents#agent-first-pattern-recommended).
{% endhint %}

Ensure referenced tools or MCPs exist in the target environment before creating the agent. Export and import them in the same batch when promoting.

#### Common import/export issues

| Symptom                                     | Likely cause                                             | Fix                                                                                      |
| ------------------------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| JSON import fails with `schema mismatch`    | Outdated export or manual edits removed required fields. | Re-export from the latest environment and limit manual edits to sections you understand. |
| CLI prompts for confirmation mid-automation | `--force` flag omitted on destructive updates.           | Add `--force` when running non-interactive scripts.                                      |
| Tool import missing code bundle             | Referenced file path invalid or not checked into repo.   | Store zip packages alongside configs and double-check relative paths before import.      |
| Differences lost between environments       | Imports overwrite without diffing.                       | Run `git diff` or compare exports before applying and track changes in version control.  |

### Rapid Iteration Loop (CLI)

*When to use:* Share quick adjustments with teammates or iterate during workshops.

1. **Export the current definition**

   ```bash
   aip agents get <agent_id> --export prod-research.yaml
   ```
2. **Edit the file locally** — tweak `instruction`, `language_model_id`, or nested `tool_configs` as needed. Keep the file under version control so you can diff changes between runs.
3. **Re-import immediately**

   ```bash
   aip agents update prod-research --import prod-research.yaml
   ```
4. **Validate the result** — use `aip agents run prod-research --view md` (or `--view json` for automation) to confirm the change behaved as expected.

Repeat the cycle until the prompt or configuration meets your needs, then commit the JSON to your repository for peer review or promotion.

### Promotion Checklist

*When to use:* Gate deployments with an explicit review and testing routine.

1. **Export from source environment** — pull agents, tools, MCPs, and schedules if applicable.
2. **Commit to version control** — store JSON files in Git for peer review.
3. **Apply environment overrides** — adjust API keys, dataset names, or tool configs before import.
4. **Import into target environment** — start with tools/MCPs, then agents.
5. **Smoke test** — run quick scenarios to verify connectivity and credentials.

### Validation Tips

*When to use:* Confirm imported resources behave as expected before promoting.

* Use `aip agents run … --view json` after import to confirm the agent behaves as expected.
* For MCPs, run `aip mcps test-connection --from-file` prior to saving new credentials.
* Watch for `language_model_id` differences between environments—exported files retain the original ID, so adjust if the target closes over a different label.

### Automating Backups

*When to use:* Schedule recurring exports for compliance or DR planning.

* Cron job / CI step: `aip agents list --view json | jq '.[].id'` then loop over IDs and export each agent nightly.
* Store artifacts in object storage with versioning (S3, GCS) for quick rollback.
* Use the [Automation & scripting guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) for shell and Python templates.

### Related Documentation

* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — understand payload structure and runtime overrides.
* [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) — capture custom tool source alongside exports.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — run exports in CI or scheduled jobs.


# Automation and Scripting

Automate AIP workflows from Python scripts, shell pipelines, or CI jobs. Use this guide when you need repeatable patterns for consistent output formats, resource promotion, and scheduling hooks that teammates can reuse across environments.

{% hint style="info" %}
For a full capability breakdown, refer to the [AIP matrix](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/introduction-to-gl-aip#platform-capabilities-at-a-glance). Scheduling is available via the Python SDK. CLI scheduling commands are under development.
{% endhint %}

{% hint style="info" %}
CLI automations can target resources by ID or unique name. When scripting loops, prefer IDs or add `--select` handling so partial name matches do not prompt for input mid-run.
{% endhint %}

{% hint style="info" %}
This guide is SDK-first (Python). CLI equivalents are included when they add unique low-code value.
{% endhint %}

{% hint style="warning" %}
`Client` snippets in this guide are legacy/advanced automation paths. Prefer Agent-first execution (`Agent(...)`, `agent.run(...)`, `agent.deploy()`) for new scripts unless you need workspace-wide admin operations.
{% endhint %}

### Choose the Right Output Format

*When to use:* Tailor CLI output for downstream systems, docs, or logs before integrating into scripts.

**Python SDK**

```python
from glaip_sdk import Client

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

# Rich text (default renderer)
print(agent.run("Provide a concise summary"))

# Plain output for scripting
print(agent.run("List KPIs", renderer="plain"))
```

**CLI**

```bash
# JSON for automation
aip agents get analytics-agent --view json > agent.json

# Markdown for docs
aip agents run analytics-agent --input "Create summary" --view md > REPORT.md

# Plain text for logs
aip agents run analytics-agent --input "Quick check" --view plain
```

### Script Resource Promotion

*When to use:* Promote agents and tools between sandboxes, staging, and production with audit trails.

Use the export/import workflows from the [Configuration management guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) as the source of truth. When you automate them, wrap the commands so your CI job can back up or promote resources in one run:

```bash
#!/usr/bin/env bash
set -euo pipefail

mkdir -p exports

agents=(prod-research ops-analyst)
tools=(query-runner mcp-sync)

for agent in "${agents[@]}"; do
  aip agents get "$agent" --export "exports/agent-${agent}.json"
done

for tool in "${tools[@]}"; do
  aip tools get "$tool" --export "exports/tool-${tool}.json"
done

# Promote the JSON with the create/update commands from the configuration guide
# after your change review passes.
```

The script centralises resource selection for CI but defers ordering, validation, and import strategy to the configuration guide’s checklist.

### Automate Prompt Iteration

*When to use:* Batch-run prompts for evaluation, regression testing, or manual review.

Extend the configuration guide’s rapid-iteration loop with automation steps that enforce reproducibility. Example nightly job:

```bash
#!/usr/bin/env bash
set -euo pipefail

AGENT_ID="prod-research"
EXPORT="exports/${AGENT_ID}.json"

aip agents get "${AGENT_ID}" --export "$EXPORT"

tmp=$(mktemp)
jq '.instruction = "Summarise latest earnings with KPIs"' "$EXPORT" > "$tmp"
mv "$tmp" "$EXPORT"

aip agents update "${AGENT_ID}" --import "$EXPORT"
aip agents run "${AGENT_ID}" --input "Smoke test" --view md > artifacts/${AGENT_ID}-smoke.md

git add "$EXPORT" artifacts/${AGENT_ID}-smoke.md
```

This focuses on the scripting concerns—file paths, idempotent edits, and artifact capture—while the linked configuration guide covers the manual review and promotion steps.

### Run Agents in CI

*When to use:* Block deployments until sanity checks pass or surface usage metrics in pipelines.

```bash
#!/usr/bin/env bash
set -euo pipefail

: "${AIP_API_URL:?Missing AIP_API_URL}"
: "${AIP_API_KEY:?Missing AIP_API_KEY}"

aip agents run prod-research \
  --input "Generate daily summary" \
  --view json > artifacts/daily_summary.json
```

Store credentials in your CI secret manager and inject them as environment variables before executing.

### Python Automation Pattern

*When to use:* Embed agent calls inside existing Python services, notebooks, or ETL jobs.

```python
from glaip_sdk import Client

client = Client()

agent = client.agents.get_agent_by_id("prod-research")
result = agent.run(
    "Generate daily summary",
    runtime_config={
        "tool_configs": {
            "query-runner": {"dataset": "daily_metrics"}
        }
    },
    renderer="silent",
)
print(result)
```

The `renderer="silent"` option suppresses streaming UI output so your script can capture the final text response directly.

### Schedule Runs

*When to use:* Run the same agent input on a recurring timetable. Schedules execute automatically in the Asia/Jakarta (WIB) timezone.

Schedules require an `agent_id`, `input`, and a schedule. In the SDK you can pass either a cron string or a structured config. Cron strings use five fields: `minute hour day_of_month month day_of_week`. Each field supports `*`, ranges (e.g., `2-4`), lists (`0,6`), and steps (`*/N`).

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

client = Client()

# Create a schedule for an agent
schedule = client.schedules.create(
    agent_id="agent-123",
    input="Generate daily summary report",
    schedule=ScheduleConfig(
        minute="0",
        hour="9",
        day_of_month="*",
        month="*",
        day_of_week="0-4",  # Monday to Friday
    ),
)

# Or use a cron string directly
schedule = client.schedules.create(
    agent_id="agent-123",
    input="Weekly status update",
    schedule="0 10 * * 0",  # Every Monday at 10am
)

# List all schedules
schedules = client.schedules.list()
for s in schedules:
    print(f"{s.id}: next run at {s.next_run_time}")

# List schedules for a specific agent
agent_schedules = client.schedules.list(agent_id="agent-123")

# Update a schedule
# Note: Omit schedule to keep the existing timing. Any provided schedule fills missing fields with "*".
updated = client.schedules.update(
    schedule.id,
    input="Updated daily report",
    schedule=ScheduleConfig(minute="30", hour="9"),
)

# Delete a schedule
client.schedules.delete(schedule.id)
```

You can also use the agent facade for schedule operations; it infers `agent_id` from the `Agent` instance:

```python
agent = client.agents.get_agent_by_id("agent-123")

# Create schedule via agent
schedule = agent.schedule.create(
    input="Daily task",
    schedule="0 8 * * *",
)

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

CLI commands for scheduling are under development. Use the SDK for now.

#### Schedule Configuration

| Field          | Format                        | Examples          | Description                |
| -------------- | ----------------------------- | ----------------- | -------------------------- |
| `minute`       | 0-59, \*, \*/N, ranges, lists | `0`, `*/15`, `30` | Minute of the hour         |
| `hour`         | 0-23, \*, \*/N, ranges, lists | `9`, `*/2`, `0`   | Hour of the day (WIB)      |
| `day_of_month` | 1-31, \*, ranges, lists       | `1`, `15`, `*`    | Day of the month           |
| `month`        | 1-12, \*, \*/N, ranges, lists | `1`, `*/3`, `*`   | Month of the year          |
| `day_of_week`  | 0-6, \*, \*/N, ranges, lists  | `0-4`, `0,6`, `*` | Day of week (0=Mon, 6=Sun) |

{% hint style="info" %}
All schedules run in Asia/Jakarta (WIB) timezone. Plan your cron expressions accordingly.
{% endhint %}

#### Schedule Run History

Retrieve execution history for scheduled runs, including status, duration, and output. Run history is scoped to an agent; use `schedule_id` to narrow results, and a `run_id` to fetch output. These APIs return scheduled runs only.

List runs to filter by schedule, status, or paginate through history.

```python
# List all scheduled runs for an agent
runs = client.schedules.list_runs(agent_id="agent-123")

# Filter by specific schedule
runs = client.schedules.list_runs(
    agent_id="agent-123",
    schedule_id="schedule-abc",
    limit=10,
)

# Filter by status (started, success, failed, cancelled, aborted, unavailable)
successful_runs = client.schedules.list_runs(
    agent_id="agent-123",
    status="success",
)

# Via schedule instance
schedule = client.schedules.get("schedule-abc")
runs = schedule.list_runs(status="success", limit=20)
```

Get run results to fetch full output and metadata for a specific run.

```python
# From a ScheduleRun instance
for run in runs:
    print(f"Run ID: {run.id}")
    print(f"Status: {run.status}")
    print(f"Started: {run.started_at}")
    print(f"Duration: {run.duration}")

    # Get full output
    if run.status in ["success", "failed"]:
        result = run.get_result()
        # result.output contains the SSE output chunks
        # result.schedule_id links back to the schedule
```

Run status values:

| Status        | Description                |
| ------------- | -------------------------- |
| `started`     | Run has started execution  |
| `success`     | Run completed successfully |
| `failed`      | Run encountered an error   |
| `cancelled`   | Run was cancelled          |
| `aborted`     | Run was aborted            |
| `unavailable` | Run result is unavailable  |

#### Common automation failures

| Symptom                                 | Likely cause                                          | Fix                                                                                                                               |
| --------------------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Cron job exits with `command not found` | `aip` not on the scheduler PATH.                      | Prefix with the full path or source the profile before invoking the CLI.                                                          |
| CI run fails with `401 Unauthorized`    | Expired or missing API key in the runner environment. | Rotate credentials and inject them via secrets or environment variables per job.                                                  |
| Scripts hang on interactive prompts     | CLI fuzzy search triggered by unfiltered lists.       | Pass IDs, use `--select`, add a filter flag (`--name`, `--type`, etc.), or force `--simple` when you need non-interactive output. |
| SDK automation times out intermittently | Backend slow or default timeout too low.              | Increase `Client(timeout=...)` or add retry logic with exponential backoff.                                                       |

### Automation Tips

*When to use:* Sense-check your automation plan before scaling or handing it off to new team members.

1. **Use JSON everywhere** — it is the most resilient format for piping into tests or dashboards.
2. **Keep exports in Git** — treat agent/tool JSON like infrastructure-as-code and review changes via pull requests.
3. **Log run IDs** — responses include `X-Run-ID`; store it to trace streaming output later.
4. **Fail fast in CI** — run `set -euo pipefail` (Bash) or equivalent constructs to surface agent errors quickly.

### Related Documentation

* [Install & Configure](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/prerequisites) — bootstrap environments for automation servers.
* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — full lifecycle and runtime overrides.
* [Configuration management](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) — promote resources between environments.
* [CLI commands reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands) — explore automation flags in detail.


# LangFlow Integration

Operationalise LangFlow boards inside AIP so you can run and manage them alongside native agents. This guide is for teams prototyping visually who are ready to sync flows into the wider automation platform without rewriting them by hand.

### Overview

*When to use:* Understand the sync pipeline before wiring automation.

LangFlow lets you design complex agent workflows visually. The GL AIP package can sync those flows and expose them as agents of type `langflow`, ready to run via the Python SDK or CLI. Use LangFlow for rapid prototyping, then promote the result into your wider automation pipelines.

### Configure Access

*When to use:* Connect LangFlow to AIP with the right credentials and endpoints.

Set the LangFlow connection once via environment variables or CLI flags:

```bash
export LANGFLOW_BASE_URL="https://your-langflow.example.com"
export LANGFLOW_API_KEY="super-secret"
```

### Sync Flows from LangFlow

*When to use:* Promote a visual flow into an AIP agent for the first time or after edits.

**Python SDK**

```python
from glaip_sdk import Client

client = Client()

client.sync_langflow_agents()

# Inspect LangFlow-based agents
langflow_agents = client.agents.list_agents(agent_type="langflow")
for agent in langflow_agents:
    print(agent.name)
```

**CLI**

```bash
# Pull all flows and create/update matching AIP agents
aip agents sync-langflow

# Provide explicit connection details if you do not use env vars
aip agents sync-langflow \
  --base-url "https://your-langflow.example.com" \
  --api-key "super-secret"

# List the imported agents (type=langflow)
aip agents list --type langflow
```

{% hint style="info" %}
`aip agents sync-langflow` references agents by their underlying LangFlow IDs, but follow-up commands like `aip agents run` accept either the synced agent ID or its unique name. Use `--select` if multiple agents share a similar name.
{% endhint %}

The sync operation fetches every published flow, creating new agents or updating existing ones if the LangFlow ID already exists in AIP.

#### Common sync issues

| Symptom                            | Likely cause                                               | Fix                                                                                                 |
| ---------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Flow not listed in CLI after sync  | Sync command failed silently or wrong workspace connected. | Re-run the sync with verbose logging and confirm API keys reference the correct LangFlow workspace. |
| Tool references missing            | Tool IDs in the flow do not exist in the target account.   | Import or recreate the tools first, then resync the flow.                                           |
| Runtime errors about unknown nodes | Custom components unsupported in AIP runtime.              | Replace custom nodes with supported blocks before syncing.                                          |
| Flow changes not reflected         | Cached agent still running previous version.               | Use `--force` sync options or delete/recreate the agent before syncing.                             |

### Run LangFlow Agents

*When to use:* Execute, monitor, and validate converted flows inside AIP.

**Python SDK**

```python
from glaip_sdk import Client

client = Client()

agent = client.find_agents(name="marketing-flow")[0]
response = agent.run("Create a campaign brief for the autumn launch")
print(response)
```

**CLI**

```bash
aip agents list --type langflow
aip agents run <LANGFLOW_AGENT_REF> --input "Summarise the Q4 roadmap"
```

Replace `<LANGFLOW_AGENT_REF>` with the agent ID or name from the list output.

### Best Practices

*When to use:* Keep flows consistent between design and production environments.

* **Version in LangFlow**: Tag releases in LangFlow so you can track which build is currently synced. The sync output returns counts for created, updated, and skipped flows.
* **Modular boards**: Break large chains into reusable sub-flows to keep agent responses predictable and easier to debug.
* **Tool parity**: Ensure any tools referenced in the LangFlow board exist in the target AIP account; missing tools will surface as execution errors.
* **Scheduled syncs**: Use CI or scheduled jobs to call `aip agents sync-langflow` so your AIP account always mirrors the latest published boards.

### Troubleshooting

*When to use:* Resolve sync or runtime failures before filing an issue.

| Symptom                                | Likely Cause                                  | Fix                                                                  |
| -------------------------------------- | --------------------------------------------- | -------------------------------------------------------------------- |
| `Missing LangFlow configuration` error | No base URL/API key configured                | Set `LANGFLOW_BASE_URL` and `LANGFLOW_API_KEY` or pass flags         |
| Agents not appearing after sync        | Flow is disabled or missing required metadata | Publish/enable the flow in LangFlow and re-run sync                  |
| Execution errors at runtime            | Referenced tools/models unavailable in AIP    | Provision the same tools/models in the target account before running |

### Related Documentation

* [**Agents guide**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents): Operate LangFlow and native agents side by side.
* [**Automation & scripting**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting): Schedule sync jobs or integrate with CI pipelines.
* [**Configuration management**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management): Export agent configurations after syncing for review or promotion.
* [**REST API reference**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api): Reference-only endpoints for LangFlow sync.

***

*Design visually in LangFlow, sync into AIP, and run those flows anywhere you use the SDK or CLI.*


# Multi-account Management

Understand how resources are isolated by account today and what to expect from upcoming RBAC enhancements.

> **Success**
>
> **When to use this guide:** You manage multiple tenants or environments and need to enforce isolation while planning for future RBAC.
>
> **Who benefits:** Platform administrators, PMs handling customer onboarding, and compliance teams auditing access.

### Current Behavior

*When to use:* Review how isolation works today before making architectural decisions.

| Topic         | Details                                                                            |
| ------------- | ---------------------------------------------------------------------------------- |
| Account scope | Every agent, tool, MCP, and schedule is associated with a single account ID.       |
| API keys      | A regular API key only sees and manages resources for its account.                 |
| Master key    | Platform operators can list or modify any account using the master key.            |
| Soft delete   | Deleting a resource keeps it within the originating account.                       |
| Auditing      | Run history endpoints respect account scope; master key can audit across accounts. |

### Working Across Accounts

*When to use:* Share resources safely or perform admin tasks between tenants.

* **Standard usage**: one API key per tenant environment (development, staging, production) keeps resources separated automatically.
* **Promoting configurations**: export from one account and import into another using the [Configuration management guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management).
* **Operations access**: master key holders can create, list, or revoke accounts and keys via internal integrations. REST documentation is reference-only: [REST API reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api).

#### Common isolation issues

| Symptom                                       | Likely cause                                             | Fix                                                                                       |
| --------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| Resources appear across accounts unexpectedly | API key uses master scope.                               | Issue account-scoped keys and rotate credentials that should not have master permissions. |
| CLI refuses cross-account updates             | Selected account differs from resource owner.            | Switch API keys or use dedicated service accounts per tenant.                             |
| Audit trail incomplete                        | Manual updates performed via master key without logging. | Run exports before/after changes and store them centrally.                                |

### Preparing for RBAC

*When to use:* Plan migrations or communicate timelines to stakeholders.

Future releases introduce roles (Creator, Runner, Viewer) and delegated API keys with scoped permissions. Plan ahead by:

1. Tracking which teams need read vs. write access.
2. Storing owner metadata on agents/tools (`metadata` fields) to ease migration.
3. Auditing automation scripts to ensure they use least-privilege keys once available.

### Operational Tips

*When to use:* Keep daily account management predictable and auditable.

* Rotate account keys regularly and revoke unused keys promptly.
* Keep a secure record of master key usage; restrict it to platform operators.
* When troubleshooting cross-account issues, verify that the API key matches the expected tenant before escalating.

### Related Documentation

* [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — key hygiene and PII controls.
* [Configuration management](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) — promote resources between accounts safely.
* [REST API reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api) — account endpoints and master-key operations.


# Agent Content Guardrails

Implement modular content filtering and safety checks for AI agent interactions. This guide covers rule-based phrase matching and advanced LLM-based content safety engines, showing how to prevent harmful content in both user inputs and AI outputs.

> **Success**
>
> **When to use this guide:** You need content safety controls for AI agents, want to block harmful prompts or filter inappropriate AI responses, or require local content filtering options for security-conscious deployments.
>
> **Who benefits:** Security engineers, compliance teams, and developers building production AI applications that handle sensitive or regulated content.

{% hint style="info" %}
Guardrails integrate seamlessly with agent execution—configure once and they work locally (via `agent.run()`) or remotely (via `agent.deploy()` + `agent.run()`). The SDK automatically handles middleware injection and serialization.
{% endhint %}

### Overview

Agent Content Guardrails provide modular content filtering and safety checks for AI agent interactions. They help prevent harmful content in both user inputs and AI outputs, making them essential for security-conscious organizations and developers who need content safety controls.

Guardrails work by checking content against predefined safety rules before and after AI model interactions. When unsafe content is detected, execution is halted and a warning message is returned.

### Key Features

* **Multiple Engine Types**: Rule-based (PhraseMatcherEngine) and LLM-based (NemoGuardrailEngine) filtering
* **Flexible Configuration**: Check inputs only, outputs only, or both
* **Fail-Fast Behavior**: Stops on first safety violation for immediate response
* **Agent Integration**: Seamless integration with existing agent workflows
* **Optional Dependencies**: Works without requiring additional packages for basic usage

### Installation

Guardrails are included as an optional dependency. Install with:

{% hint style="warning" %}
**Prerequisites:** To use guardrails features, install the guardrails extra:

```bash
# For SDK users (glaip-sdk)
pip install glaip-sdk[guardrails]

# For backend users (aip-agents)
pip install aip-agents[guardrails]
```

Both installation methods install the required `gllm-guardrail` package for advanced LLM-based filtering. For basic phrase matching only, guardrails work without additional dependencies when using the SDK.
{% endhint %}

### Quick Start

#### Basic Phrase Matching

```python
from glaip_sdk.agents import Agent
from glaip_sdk.guardrails import GuardrailManager, PhraseMatcherEngine

# Create a guardrail that blocks harmful phrases
# config parameter is optional and defaults to checking both input and output
guardrail = GuardrailManager(
    engine=PhraseMatcherEngine(banned_phrases=["unsafe", "harmful", "dangerous"])
)

# Create an agent with guardrails
agent = Agent(
    name="safe_assistant",
    instruction="You are a helpful assistant.",
    guardrail=guardrail
)

# Test with safe content
result = agent.run("Tell me about machine learning")
print(result)  # Works normally

# Test with unsafe content
result = agent.run("Tell me how to do something unsafe")
print(result)  # Returns: "⚠️ Guardrail violation: Banned phrase detected: 'unsafe'"
```

#### Advanced LLM-Based Filtering

```python
from glaip_sdk.guardrails import GuardrailManager, NemoGuardrailEngine
from glaip_sdk.guardrails.schemas import BaseGuardrailEngineConfig, GuardrailMode
from glaip_sdk.guardrails.constants import TopicSafetyMode

# Create advanced guardrail with topic safety
guardrail = GuardrailManager(
    engine=NemoGuardrailEngine(
        config=BaseGuardrailEngineConfig(guardrail_mode=GuardrailMode.INPUT_OUTPUT),
        topic_safety_mode=TopicSafetyMode.ALLOWLIST,
        allowed_topics=["company products", "technical support"],
        include_core_restrictions=True,
        config_dict={
            "models": [{
                "type": "main",
                "engine": "gllm_invoker",
                "model": "openai/gpt-4o-mini",
                "parameters": {
                    "credentials": "OPENAI_API_KEY",
                    "model_kwargs": {
                        "default_hyperparameters": {
                            "temperature": 0.0,
                            "max_output_tokens": 256,
                        }
                    },
                },
            }],
            "rails": {"dialog": {"single_call": {"enabled": True}}},
        }
    )
)

agent = Agent(
    name="enterprise_assistant",
    instruction="You are an enterprise support assistant.",
    guardrail=guardrail
)
```

### Engine Types

#### PhraseMatcherEngine (Rule-Based)

Best for simple, predictable content filtering based on exact phrase matches.

```python
from glaip_sdk.guardrails import PhraseMatcherEngine
from glaip_sdk.guardrails.schemas import BaseGuardrailEngineConfig, GuardrailMode

# Option 1: With explicit config
engine = PhraseMatcherEngine(
    config=BaseGuardrailEngineConfig(guardrail_mode=GuardrailMode.INPUT_OUTPUT),
    banned_phrases=[
        "harmful content",
        "unsafe phrase",
        "inappropriate words"
    ]
)

# Option 2: Using defaults (config defaults to INPUT_OUTPUT mode)
engine = PhraseMatcherEngine(
    banned_phrases=["harmful content", "unsafe phrase", "inappropriate words"]
)
```

**Configuration Options:**

* `config`: Optional `BaseGuardrailEngineConfig` object. If not provided, defaults to `GuardrailMode.INPUT_OUTPUT`
* `guardrail_mode`: Enum value - `GuardrailMode.INPUT_ONLY`, `GuardrailMode.OUTPUT_ONLY`, or `GuardrailMode.INPUT_OUTPUT`
* `banned_phrases`: List of phrases to block (required)

#### NemoGuardrailEngine (LLM-Based)

Advanced filtering using AI models for context-aware content safety analysis.

```python
from glaip_sdk.guardrails import NemoGuardrailEngine
from glaip_sdk.guardrails.schemas import BaseGuardrailEngineConfig, GuardrailMode
from glaip_sdk.guardrails.constants import TopicSafetyMode

engine = NemoGuardrailEngine(
    config=BaseGuardrailEngineConfig(guardrail_mode=GuardrailMode.INPUT_OUTPUT),

    # Topic safety configuration (passed as kwargs)
    topic_safety_mode=TopicSafetyMode.ALLOWLIST,  # or DENYLIST
    allowed_topics=["company products", "technical support"],
    denied_topics=[],  # Only used with DENYLIST mode

    # Core safety restrictions
    include_core_restrictions=True,
    core_restriction_categories=[
        "privacy_personal_information",
        "system_manipulation_security",
        "harmful_activities"
    ],

    # Model configuration
    config_dict={
        "models": [{
            "type": "main",
            "engine": "gllm_invoker",
            "model": "openai/gpt-4o-mini",  # Any gllm-inference supported model
            "parameters": {
                "credentials": "OPENAI_API_KEY",
                "model_kwargs": {
                    "default_hyperparameters": {
                        "temperature": 0.0,  # Low temperature for consistent decisions
                        "max_output_tokens": 256,
                    }
                },
            },
        }],
        "rails": {"dialog": {"single_call": {"enabled": True}}},
    },

    # Custom denial phrases
    denial_phrases=[
        "DENIED TOPIC:",
        "DENIED ACTION:",
        "I cannot comply with that request."
    ]
)
```

### Direct Guardrail Usage

*When to use:* Validate content before sending it to agents or perform standalone content filtering outside of agent execution.

You can use guardrails independently of agents for content checking. This is useful for validating content before sending it to agents or for standalone content filtering.

```python
from glaip_sdk.guardrails import GuardrailManager, PhraseMatcherEngine
from glaip_sdk.guardrails.schemas import GuardrailInput

# Create guardrail
manager = GuardrailManager(
    engine=PhraseMatcherEngine(banned_phrases=["unsafe", "harmful"])
)

# Check single content string (async required)
result = await manager.check_content("user input here")
if not result.is_safe:
    print(f"Blocked: {result.reason}")
    print(f"Filtered content: {result.filtered_content}")

# Check both input and output together
result = await manager.check_content(
    GuardrailInput(input="user input", output="ai output")
)
if not result.is_safe:
    print(f"Content violation: {result.reason}")
```

**Important Notes:**

* When using guardrails with `agent.run()`, async handling is automatic
* For direct usage, you must use `await` since `check_content()` is an async method
* Use `GuardrailInput` when you want to check both user input and AI output in a single call
* The `filtered_content` field may contain sanitized content if the engine provides it

### Agent Integration

*When to use:* Integrate guardrails into agent workflows for automatic content filtering during agent execution.

#### Local Execution

When running agents locally, guardrails are enforced through middleware injection:

```python
agent = Agent(
    name="safe_agent",
    instruction="You are helpful.",
    guardrail=guardrail_manager
)

# Guardrails are automatically applied
result = agent.run("User input here")
```

#### Remote Execution

For deployed agents, guardrails are serialized and enforced by the backend:

```python
agent = Agent(
    name="safe_agent",
    instruction="You are helpful.",
    guardrail=guardrail_manager
)

# Deploy with guardrails
agent.deploy()

# Backend enforces guardrails automatically
result = agent.run("User input here")
```

### Configuration Patterns

*When to use:* Combine multiple engines, configure different checking modes, or customize guardrail behavior for specific use cases.

#### Multiple Engines

Combine multiple guardrail engines for comprehensive protection:

```python
from glaip_sdk.guardrails import GuardrailManager, PhraseMatcherEngine, NemoGuardrailEngine
from glaip_sdk.guardrails.schemas import BaseGuardrailEngineConfig, GuardrailMode
from glaip_sdk.guardrails.constants import TopicSafetyMode

# Create multiple engines
phrase_engine = PhraseMatcherEngine(banned_phrases=["unsafe", "harmful"])
nemo_engine = NemoGuardrailEngine(
    config=BaseGuardrailEngineConfig(guardrail_mode=GuardrailMode.INPUT_OUTPUT),
    topic_safety_mode=TopicSafetyMode.ALLOWLIST,
    allowed_topics=["allowed topics"],
    include_core_restrictions=True,
    config_dict={...}  # Model config
)

# Manager orchestrates multiple engines with fail-fast behavior
# Can use either 'engine' (single) or 'engines' (list) parameter
manager = GuardrailManager(engines=[phrase_engine, nemo_engine])
```

#### Input-Only vs Output-Only

Configure different checking modes:

```python
from glaip_sdk.guardrails.schemas import BaseGuardrailEngineConfig, GuardrailMode

# Check only user inputs
input_only = GuardrailManager(
    engine=PhraseMatcherEngine(
        config=BaseGuardrailEngineConfig(guardrail_mode=GuardrailMode.INPUT_ONLY),
        banned_phrases=["bad input"]
    )
)

# Check only AI outputs
output_only = GuardrailManager(
    engine=NemoGuardrailEngine(
        config=BaseGuardrailEngineConfig(guardrail_mode=GuardrailMode.OUTPUT_ONLY),
        # ... other config
    )
)
```

#### Checking Both Input and Output Together

Use `GuardrailInput` to check both user input and AI output in a single call:

```python
from glaip_sdk.guardrails import GuardrailManager, PhraseMatcherEngine
from glaip_sdk.guardrails.schemas import GuardrailInput

manager = GuardrailManager(
    engine=PhraseMatcherEngine(banned_phrases=["unsafe", "harmful"])
)

# Check both input and output together
result = await manager.check_content(
    GuardrailInput(
        input="Tell me about unsafe practices",
        output="Here's how to do unsafe things..."
    )
)

if not result.is_safe:
    print(f"Violation detected: {result.reason}")
```

#### Disabling Guardrails

You can disable guardrails for a specific engine:

```python
from glaip_sdk.guardrails.schemas import BaseGuardrailEngineConfig, GuardrailMode

# Disabled guardrail (won't check anything)
disabled_engine = PhraseMatcherEngine(
    config=BaseGuardrailEngineConfig(guardrail_mode=GuardrailMode.DISABLED),
    banned_phrases=["unsafe"]  # Won't be used when disabled
)
```

**Note**: Disabled mode is useful for temporarily disabling guardrails during development or testing.

### Error Handling

#### Guardrail Violations

When unsafe content is detected, execution halts and returns a warning message. Internally, a `GuardrailViolationError` exception is raised, which is caught and converted to a user-friendly warning message in the response.

**With Agent Integration:**

```python
result = agent.run("Tell me about harmful things")

if "Guardrail violation" in result:
    print("Content was blocked")
    print(f"Reason: {result}")
else:
    print("Content passed safety checks")
    print(f"Response: {result}")
```

**With Direct Usage:**

```python
from glaip_sdk.guardrails.exceptions import GuardrailViolationError

try:
    result = await manager.check_content("unsafe content")
    if not result.is_safe:
        print(f"Blocked: {result.reason}")
        print(f"Filtered: {result.filtered_content}")
except GuardrailViolationError as e:
    # This exception contains the GuardrailResult
    print(f"Violation: {e.result.reason}")
```

#### Handling Exceptions

When using agents, violations are automatically converted to warning messages:

```python
try:
    result = agent.run(user_input)
    if result.startswith("⚠️ Guardrail violation"):
        # Handle violation appropriately
        log_violation(user_input, result)
        return get_safe_response()
    else:
        return result
except Exception as e:
    # Handle other execution errors (not guardrail violations)
    print(f"Agent execution failed: {e}")
```

**Key Points:**

* Guardrail violations are caught internally and converted to warning strings
* Users typically see warning messages like `"⚠️ Guardrail violation: [reason]"` in responses
* The underlying `GuardrailViolationError` exception contains a `GuardrailResult` with details
* For direct usage, you can catch `GuardrailViolationError` explicitly if needed

### Best Practices

#### Performance Considerations

* **PhraseMatcherEngine**: Fast, low latency (<1ms) - ideal for high-throughput scenarios
* **NemoGuardrailEngine**: Higher latency (\~100-500ms depending on model) - use for advanced filtering when needed
* **Fail-fast behavior**: Multiple engines stop on first violation, reducing unnecessary processing
* **Async/await requirements**:
  * Direct usage (`manager.check_content()`) requires `await` since it's async
  * Agent integration (`agent.run()`) handles async automatically
* **Multiple engines**: Engines run sequentially until first violation, so total latency is sum of engines until violation
* **Performance tip**: Place faster engines (PhraseMatcherEngine) first in the list to catch violations quickly

#### Configuration Tips

1. **Start Simple**: Begin with PhraseMatcherEngine for basic filtering
2. **Layer Protection**: Use multiple engines for comprehensive coverage
3. **Test Thoroughly**: Validate configurations with various inputs
4. **Monitor Performance**: Measure latency impact on agent response times

#### Security Recommendations

```python
# Recommended enterprise configuration
from glaip_sdk.guardrails import GuardrailManager, PhraseMatcherEngine, NemoGuardrailEngine
from glaip_sdk.guardrails.schemas import BaseGuardrailEngineConfig, GuardrailMode
from glaip_sdk.guardrails.constants import TopicSafetyMode

enterprise_guardrail = GuardrailManager(engines=[
    # Fast rule-based filtering first
    PhraseMatcherEngine(
        config=BaseGuardrailEngineConfig(guardrail_mode=GuardrailMode.INPUT_OUTPUT),
        banned_phrases=get_enterprise_banned_phrases()
    ),

    # Advanced LLM-based filtering
    NemoGuardrailEngine(
        config=BaseGuardrailEngineConfig(guardrail_mode=GuardrailMode.INPUT_OUTPUT),
        topic_safety_mode=TopicSafetyMode.ALLOWLIST,
        allowed_topics=get_allowed_topics(),
        include_core_restrictions=True,
        core_restriction_categories=[
            "privacy_personal_information",
            "system_manipulation_security",
            "harmful_activities",
            "jailbreak_attacks"
        ],
        config_dict=get_enterprise_model_config()
    )
])
```

### Troubleshooting

#### Common Issues

**"Guardrails module not found"**

* Install optional dependencies: `pip install glaip-sdk[guardrails]`

**"NemoGuardrailEngine not available"**

* Ensure `gllm-guardrail` package is installed
* Check that `OPENAI_API_KEY` or required credentials are set

**"Agent execution hangs"**

* Check guardrail configuration for overly broad rules
* Verify model endpoints are accessible
* Review network connectivity for LLM-based engines

**"False positives in phrase matching"**

* Review banned phrases for overly generic terms
* Consider case sensitivity settings
* Test with various input variations

#### Debugging

Enable detailed logging to troubleshoot issues:

```python
import logging
logging.basicConfig(level=logging.DEBUG)

# Run agent with verbose output
result = agent.run("test input")
```

#### Remote vs Local Behavior

* **Local execution**: Immediate blocking with detailed error messages
* **Remote execution**: Backend-enforced with standardized warning format

### API Reference

#### Core Classes

* **`GuardrailManager`**: Orchestrates multiple guardrail engines
* **`PhraseMatcherEngine`**: Rule-based phrase filtering
* **`NemoGuardrailEngine`**: Advanced LLM-based content safety
* **`GuardrailMiddleware`**: Integrates guardrails into agent execution

#### Configuration Schemas

* **`GuardrailMode`**: Enum with values `INPUT_ONLY`, `OUTPUT_ONLY`, `INPUT_OUTPUT`, `DISABLED`
* **`TopicSafetyMode`**: Enum with values `ALLOWLIST`, `DENYLIST`
* **`BaseGuardrailEngineConfig`**: Common engine configuration class with `guardrail_mode` parameter
* **`GuardrailInput`**: Input schema for checking both input and output together (contains `input` and `output` fields)

#### Result Objects

* **`GuardrailResult`**: Contains:
  * `is_safe`: Boolean indicating if content passed all safety checks
  * `reason`: String explanation when content is blocked (None if safe)
  * `filtered_content`: Optional cleaned/sanitized content if the engine provides it (None if not available)

#### Input Schemas

* **`GuardrailInput`**: Schema for checking both input and output together:
  * `input`: Optional string containing user input content
  * `output`: Optional string containing AI output content

### Related Documentation

* [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — apply PII masking, secure memory, and manage credentials responsibly.
* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — design, update, and monitor agents with the SDK and CLI (REST is reference-only).

### Additional Resources

* [GL SDK Documentation](https://gdplabs.gitbook.io/sdk) — Core SDK reference
* [NeMo Engine Guide](https://gdplabs.gitbook.io/sdk/tutorials/security-and-privacy/guardrail/nemo-engine) — Advanced LLM-based guardrail configuration
* Contact enterprise support for advanced configuration assistance


# API Key Management

This guide covers how to integrate with GLAIR AIP Platform's multi-API key authentication system for remote server implementations.

### Overview

The AIP Platform supports multiple API keys per tenant account, enabling:

* Safe API key rotation without downtime
* Audit logging of all API key activities
* Key lifecycle management (create, list, update, revoke)
* 90-day expiration for newly created expiring keys

***

### Authentication

All protected endpoints require an API key in the `X-API-Key` header:

```
X-API-Key: <your-api-key>
```

#### API Key Types

| Type                           | Description                                                      | Expiration            |
| ------------------------------ | ---------------------------------------------------------------- | --------------------- |
| **Primary (Non-Expiring) Key** | Initial account key created at signup                            | Never expires         |
| **Expiring Key**               | Additional keys created via `POST /api-keys` for normal accounts | Expires after 90 days |

For account-creator accounts, `POST /api-keys` creates non-expiring primary keys used for self-rotation.

***

### Response Format

All API responses use a consistent envelope format:

#### Success Response

```json
{
  "success": true,
  "data": {},
  "message": "Operation completed successfully"
}
```

#### Error Response

```json
{
  "success": false,
  "error": "Unauthorized|NotFound|Conflict|ValidationError|...",
  "message": "Human-readable error description",
  "details": null
}
```

***

### API Key Lifecycle Endpoints

#### 1. Create Account

Creates a new account and returns its primary API key.

There are 2 account types:

* **normal**: can be created by the platform key or an account-creator key
* **account-creator**: can only be created by the platform key

**Endpoint:** `POST /accounts/`

**Headers:**

* `Content-Type: application/json`
* `X-API-Key: <platform key (master key) or account-creator key>` for normal accounts
* `X-API-Key: <platform key>` for account-creator accounts

**Request Body:**

```json
{
  "name": "my-organization"
}
```

**Examples:**

**Create a normal account**

```bash
curl -X POST "$AIP_BASE_URL/accounts/" \
  -H "X-API-Key: $AIP_MASTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-organization"
  }'
```

**Response (201):**

```json
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "api_key": "aip_xxxxxxxxxxxxxxxxx",
    "account_type": "normal"
  },
  "message": "Account created successfully"
}
```

**Create an account-creator account**

```bash
curl -X POST "$AIP_BASE_URL/accounts/" \
  -H "X-API-Key: $AIP_MASTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-creator",
    "account_type": "account_creator"
  }'
```

**Response (201):**

```json
{
  "success": true,
  "data": {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "api_key": "aip_yyyyyyyyyyyyyyyyy",
    "account_type": "account_creator"
  },
  "message": "Account created successfully"
}
```

**Error Codes:**

* `401` - Missing/invalid API key for account creation
* `403` - Caller is not allowed to create the requested account type
* `409` - Duplicate account name
* `422` - Validation error (missing/empty name)

> **Note:** Normal accounts can be created by the platform key (master key) or any account-creator key. Account-creator accounts can only be created by the platform key and can only create normal accounts. The `api_key` is returned only once at creation, so store it securely.

***

#### 2. List API Keys

List all API keys for your account.

**Endpoint:** `GET /api-keys`

**Headers:**

* `X-API-Key: <your-api-key>`

**Query Parameters:**

| Parameter          | Type     | Description                                                        |
| ------------------ | -------- | ------------------------------------------------------------------ |
| `status`           | string   | Comma-separated: `active,expired,revoked,deleted`                  |
| `created_at_start` | datetime | Filter by creation date (inclusive)                                |
| `created_at_end`   | datetime | Filter by creation date (inclusive)                                |
| `include_deleted`  | boolean  | Include soft-deleted keys (default: `false`)                       |
| `limit`            | integer  | Items per page (optional, `>=1`, currently no backend upper bound) |
| `page`             | integer  | Page number (optional, `>=1`)                                      |

**Success Response (200):**

```json
{
  "success": true,
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "prod-deployment-2026",
      "preview": "sk-1****COUA",
      "status": "active",
      "created_at": "2026-02-06T10:30:00Z",
      "expires_at": "2026-05-07T10:30:00Z",
      "last_used_at": "2026-02-07T09:12:00Z",
      "created_by_api_key_id": "<actor-key-id>",
      "created_by_name": "<actor-key-name>",
      "revoked_at": null,
      "revoked_by_api_key_id": null,
      "revoked_by_name": null
    }
  ],
  "message": "API keys retrieved successfully"
}
```

**Paginated Response (when `limit` and `page` provided):**

```json
{
  "success": true,
  "data": [...],
  "total": 5,
  "page": 1,
  "limit": 20,
  "has_next": true,
  "has_prev": false,
  "message": "API keys retrieved successfully"
}
```

**Error Codes:**

* `401` - Invalid or missing API key
* `422` - Invalid filter values

***

#### 3. Create API Key

Create a new API key. Normal accounts create expiring keys (90-day expiration); account-creator accounts create non-expiring primary keys for self-rotation.

**Endpoint:** `POST /api-keys`

**Headers:**

* `X-API-Key: <your-api-key>`
* `Content-Type: application/json`

**Request Body:**

```json
{
  "name": "prod-deployment-2026"
}
```

> **Note:** `name` is optional. Duplicate names are allowed within the same account. This example shows a normal account key. Account-creator accounts use the same endpoint but receive a non-expiring primary key.

**Success Response (201):**

```json
{
  "success": true,
  "data": {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "api_key": "aip_yyyyyyyyyyyyyyyyy",
    "name": "prod-deployment-2026",
    "preview": "sk-y****9XYZ",
    "status": "active",
    "created_at": "2026-02-06T10:30:00Z",
    "expires_at": "2026-05-07T10:30:00Z",
    "last_used_at": null,
    "created_by_api_key_id": "<actor-key-id>",
    "created_by_name": "<actor-key-name>"
  },
  "message": "API key created successfully"
}
```

> **Important:** The `api_key` secret is returned only once at creation. Store it immediately.

***

#### 4. Update API Key Name

Update the name of an existing API key.

**Endpoint:** `PATCH /api-keys/{key_id}`

**Headers:**

* `X-API-Key: <your-api-key>`
* `Content-Type: application/json`

**Request Body:**

```json
{
  "name": "updated-key-name"
}
```

**Success Response (200):**

```json
{
  "success": true,
  "data": {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "name": "updated-key-name",
    "preview": "sk-y****9XYZ",
    "status": "active",
    "created_at": "2026-02-06T10:30:00Z",
    "expires_at": "2026-05-07T10:30:00Z",
    "last_used_at": null,
    "created_by_api_key_id": "<actor-key-id>",
    "created_by_name": "<actor-key-name>",
    "revoked_at": null,
    "revoked_by_api_key_id": null,
    "revoked_by_name": null
  },
  "message": "API key updated successfully"
}
```

**Error Codes:**

* `401` - Invalid or missing API key
* `404` - Key not found
* `422` - Validation error

***

#### 5. Revoke API Key

Revoke an API key. Revocation is permanent and irreversible.

**Endpoint:** `POST /api-keys/{key_id}/revoke`

**Headers:**

* `X-API-Key: <your-api-key>`

**Success Response (200):**

```json
{
  "success": true,
  "data": {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "status": "revoked",
    "revoked_at": "2026-02-06T12:00:00Z",
    "revoked_by_api_key_id": "<actor-key-id>",
    "revoked_by_name": "<actor-key-name>"
  },
  "message": "API key revoked successfully"
}
```

**Error Codes:**

* `401` - Invalid or missing API key
* `404` - Key not found
* `409` - Cannot revoke the last active non-expiring key

> **Note:** Revocation is idempotent. Revoking an already-revoked key returns success.

***

### Key Rotation Workflow

Create the replacement key first, then revoke the old key with the replacement key.

Use the right path for the account type:

| Account type    | Create replacement key                                                         | Revoke old key                                                          |
| --------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------- |
| normal          | platform key via `POST /accounts/{account_id}/api-keys` with `"primary": true` | platform key via `POST /accounts/{account_id}/api-keys/{key_id}/revoke` |
| account-creator | current account-creator key via `POST /api-keys`                               | new account-creator key via `POST /api-keys/{key_id}/revoke`            |

> **Important:** Normal tenant keys create expiring replacement keys only. Use the master API key to rotate a normal account's non-expiring primary key. Account-creator accounts can self-rotate because tenant `POST /api-keys` creates another non-expiring primary key for that account.

#### Rotate a normal account key with the platform key

```bash
ACCOUNT_ID="<account-uuid>"
OLD_KEY_ID="<old-key-uuid>"

NEW_KEY_RESPONSE=$(curl -s -X POST "$AIP_BASE_URL/accounts/$ACCOUNT_ID/api-keys" \
  -H "X-API-Key: $AIP_MASTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "rotation-2026-02",
    "primary": true
  }')

NEW_KEY=$(echo "$NEW_KEY_RESPONSE" | jq -r '.data.api_key')

curl -X GET "$AIP_BASE_URL/accounts/$ACCOUNT_ID/api-keys" \
  -H "X-API-Key: $AIP_MASTER_API_KEY"

curl -X POST "$AIP_BASE_URL/accounts/$ACCOUNT_ID/api-keys/$OLD_KEY_ID/revoke" \
  -H "X-API-Key: $AIP_MASTER_API_KEY"
```

#### Rotate an account-creator key with the current key

```bash
OLD_KEY="<current-account-creator-key>"
OLD_KEY_ID="<old-key-uuid>"

NEW_KEY_RESPONSE=$(curl -s -X POST "$AIP_BASE_URL/api-keys" \
  -H "X-API-Key: $OLD_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "rotation-2026-02"
  }')

NEW_KEY=$(echo "$NEW_KEY_RESPONSE" | jq -r '.data.api_key')

curl -X GET "$AIP_BASE_URL/api-keys" \
  -H "X-API-Key: $NEW_KEY"

curl -X POST "$AIP_BASE_URL/api-keys/$OLD_KEY_ID/revoke" \
  -H "X-API-Key: $NEW_KEY"
```

***

### Activity Audit

#### List Activity (Tenant)

Query API key activity logs for your account. This is useful for security auditing and tracking who performed what actions.

**Endpoint:** `GET /api-keys/activity`

**Headers:**

* `X-API-Key: <your-api-key>`

**Query Parameters:**

| Parameter       | Type     | Description                                                                                    |
| --------------- | -------- | ---------------------------------------------------------------------------------------------- |
| `resource_type` | string   | Comma-separated: `api_key,account,agent,agent_run,hitl,mcp,tool,schedule,utils,language_model` |
| `action`        | string   | Comma-separated: `create,read,update,delete,revoke,run,decision,timeout`                       |
| `api_key_id`    | UUID     | Filter by specific API key                                                                     |
| `status_code`   | string   | Comma-separated HTTP status codes (e.g., `200,401,500`)                                        |
| `start_date`    | datetime | Filter by event date (inclusive, `>=`)                                                         |
| `end_date`      | datetime | Filter by event date (inclusive, `<=`)                                                         |
| `limit`         | integer  | Items per page (default: `20`, range: `1-100`)                                                 |
| `page`          | integer  | Page number (default: `1`, `>=1`)                                                              |

**Success Response (200):**

```json
{
  "success": true,
  "data": [
    {
      "id": "770e8400-e29b-41d4-a716-446655440002",
      "account_id": "550e8400-e29b-41d4-a716-446655440000",
      "api_key_id": "660e8400-e29b-41d4-a716-446655440001",
      "resource_type": "agent",
      "action": "run",
      "http_method": "POST",
      "path_template": "/agents/{agent_id}/run",
      "resource_id": "880e8400-e29b-41d4-a716-446655440003",
      "status_code": 200,
      "duration_ms": 150,
      "metadata": {
        "request_id": "req_1234567890",
        "actor_type": "api_key",
        "actor_name_at_event": "prod-deployment-2026"
      },
      "created_at": "2026-02-10T09:18:00Z"
    }
  ],
  "total": 150,
  "page": 1,
  "limit": 20,
  "has_next": true,
  "has_prev": false,
  "message": "API key activity logs retrieved successfully"
}
```

**Error Codes:**

* `401` - Invalid or missing API key
* `422` - Invalid filter values

> **Note:** Sort order is `created_at DESC, id DESC` (newest first).

***

### Error Reference

#### Common HTTP Status Codes

| Code  | Error Type        | Description                                            |
| ----- | ----------------- | ------------------------------------------------------ |
| `200` | -                 | Success (GET, PATCH, POST for revoke)                  |
| `201` | -                 | Created (POST for create)                              |
| `401` | `Unauthorized`    | Invalid, expired, or missing API key                   |
| `404` | `NotFound`        | Resource not found                                     |
| `409` | `Conflict`        | Business rule violation (e.g., cannot revoke last key) |
| `422` | `ValidationError` | Request validation failed                              |

#### Specific Error Messages

| Scenario                    | HTTP | Error Type        | Message                                                                                     |
| --------------------------- | ---- | ----------------- | ------------------------------------------------------------------------------------------- |
| Missing `X-API-Key` header  | 401  | `Unauthorized`    | `API key is required. Please provide X-API-Key header`                                      |
| Invalid/expired/revoked key | 401  | `Unauthorized`    | `Invalid API key`                                                                           |
| Key not found               | 404  | `NotFound`        | `API key {key_id} not found`                                                                |
| Revoke last active key      | 409  | `Conflict`        | `Cannot revoke: account must retain at least one active non-expiring key`                   |
| Invalid date range          | 422  | `ValidationError` | `start_date must be less than or equal to end_date`                                         |
| Invalid limit/page          | 422  | `ValidationError` | `GET /api-keys`: `limit >= 1`, `page >= 1`; activity endpoints: `limit 1..100`, `page >= 1` |

***


# GL Connectors Best Practices

Use this guide as the central AIP reference for choosing between GL Connectors APIs, native tools, MCP servers, and Skills.

{% hint style="info" %}
This is an SDK-first guide. The GL Connectors component docs, cookbook, and API reference live in the GL Connectors section of the same GitBook space.
{% endhint %}

## Quick Choice Guide

| Need                                                                                                            | Best fit                  | Why                                                                                               |
| --------------------------------------------------------------------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------- |
| Teach the agent a workflow, checklist, formatting rule, or operating procedure                                  | **Skill**                 | Skills add instructions and process knowledge without adding new runtime capability.              |
| Do a local runtime action such as file handling, date math, script execution, or deterministic local processing | **Function-calling tool** | These are narrow system primitives that the model cannot perform by itself.                       |
| Run one deterministic external operation or a fixed external flow                                               | **API**                   | A single call is simpler and cheaper than asking the agent to reason through deterministic steps. |
| Connect to an existing broad service such as GitHub, Google Drive, Slack, Jira, or a database                   | **MCP server**            | MCP gives the agent runtime-discovered service capabilities; restrict it with an allow-list.      |

Start with the smallest component that satisfies the requirement. Combine components only when each one owns a distinct responsibility.

## AIP Guidance

### Prerequisites Shared by APIs, Tools, and MCPs

GL Connectors is multi-tenant. Most surfaces need both client-level and user-level credentials:

* **Client API Key**: identifies the client; use the value issued by the GL Connectors team or Console.
* **User Token**: bearer token for the user whose integrations are being used.
* **Integration**: the user's connected third-party account, created outside MCP/tool execution.

Create integrations before attaching tools or MCPs. The GL Connectors docs are explicit that tools and MCP servers do not initialize integrations. Use the Connectors Console, CLI, or SDK quickstart first. Console setup commonly uses `https://connectors.glair.ai/console`; MCP/API runtime examples commonly use `https://connectors.gdplabs.id`, while the API quickstart shows `https://connectors.glair.ai`.

### GL Connectors Native Tools in AIP

AIP already seeds GL Connectors-backed native tools from the runner's BOSA/GL Connectors tool catalog. These tools are stored with the `bosa_` prefix, for example `bosa_github_*` or `bosa_google_drive_*`.

How the seeded tools work:

* The backend `ToolSeeder` loads normal manifest tools, then appends available GL Connectors/BOSA tools from `BOSA_AUTOMATED_TOOLS` and `get_bosa_modules()`.
* Each appended native tool is named with the `bosa_` prefix and seeded as a native tool.
* Tool seeding is controlled by `USE_GL_CONNECTORS_TOOLS`, with legacy `USE_BOSA_TOOLS` still supported.
* The runner loads the matching native tool implementation at execution time from the BOSA tool package.
* Prefer these seeded tools when the default GL Connectors function-call behavior is enough and you want the tool to appear as a normal AIP native tool.

For product/docs language, describe these as **seeded GL Connectors native tools**. The `bosa_` prefix is an internal compatibility name used by AIP and the runner.

These seeded tools are AIP's preferred path for GL Connectors function-calling tools. The GL Connectors docs also document the standalone Tools Generator, which dynamically fetches connector schemas and returns LangChain-compatible `BaseTool` instances. In AIP, do not create another generated tool layer unless the seeded `bosa_` tool catalog cannot satisfy the use case.

#### Tool Config Overrides

Seeded GL Connectors native tools can receive per-tool config from AIP `tool_configs`. Use this when one tool needs request-specific or agent-specific GL Connectors credentials instead of only the runner environment defaults.

Supported auth override keys:

* `gl_connectors_token` or `GL_CONNECTORS_TOKEN`
* `gl_connectors_api_key` or `GL_CONNECTORS_API_KEY`
* legacy/internal aliases `BOSA_TOKEN` and `BOSA_API_KEY`

Prefer the `gl_connectors_*` keys in new public examples. Use `BOSA_TOKEN` and `BOSA_API_KEY` when configuring existing AIP/BOSA-native tool paths that already expect those aliases.

Example per-tool config shape:

```python
from glaip_sdk import Agent

agent = Agent(
    name="connector-agent",
    instruction="Use a seeded GL Connectors tool.",
    tools=["bosa_<tool_name>"],
    tool_configs={
        "bosa_<tool_name>": {
            "GL_CONNECTORS_TOKEN": "read from secret manager at runtime",
            "GL_CONNECTORS_API_KEY": "read from secret manager at runtime",
        }
    },
)
```

For `bosa_sql_query_tool`, the required tool config is `database_url`. This lets the SQL handler identify which connected database to query.

Example SQL tool config:

```python
tool_configs={
    "bosa_sql_query_tool": {
        "database_url": "postgresql://readonly_user@db.example.internal:5432/analytics",
        "GL_CONNECTORS_TOKEN": "read from secret manager at runtime",
        "GL_CONNECTORS_API_KEY": "read from secret manager at runtime",
    }
}
```

Do not commit real tokens, API keys, or database passwords in stored tool configs. Resolve secret values from the platform secret store or request-time runtime config.

### APIs

Use a direct GL Connectors API when the job is one precise external operation, or when a deterministic sequence should be collapsed behind one server-side call. Good examples include file upload/download and fixed flows where the agent does not need to make decisions between steps.

Avoid wrapping every connector endpoint as a separate custom tool. If the agent needs broad access to a service, use MCP instead.

Typical SDK setup from the GitBook:

```bash
uv add gl-connectors-sdk
```

Typical direct/fluent execution:

```python
from gl_connectors_sdk.connector import GLConnectors

client_key = "read from environment or secret manager"
user_token = "read from environment or secret manager"

connector = GLConnectors(
    api_base_url="https://connectors.glair.ai",
    api_key=client_key,
)

response = (
    connector.connect("google_drive")
    .action("search_files")
    .params({"query": "name contains 'wfo'"})
    .token(user_token)
    .run()
)

print(response.get_data())
```

Use API directly for deterministic work such as `google_drive.search_files`, connector sanity checks, file creation/upload/download flows, or server-side workflows that do not need LLM judgment between steps.

### MCP Servers

Use a GL Connectors MCP server when the agent needs broad or uncertain access to a service. Keep the exposed surface small with an allow-list so the agent only sees the service actions needed for the use case.

MCP is preferred over many one-off tools when the service already has multiple related operations and the agent may need to choose between them.

Hosted MCP URL pattern:

```
https://connectors.gdplabs.id/<connector>/mcp
```

Some MCP clients require a trailing slash:

```
https://connectors.gdplabs.id/github/mcp/
```

Common hosted connectors from the GitBook:

| Connector        | Base MCP URL                                         | Connector name     | Capability examples                                                                           |
| ---------------- | ---------------------------------------------------- | ------------------ | --------------------------------------------------------------------------------------------- |
| GitHub           | `https://connectors.gdplabs.id/github/mcp`           | `github`           | issues, PRs, commits, contributors, releases, project items                                   |
| Google Drive     | `https://connectors.gdplabs.id/google_drive/mcp`     | `google_drive`     | search/get/create/update/copy/delete files, folders, permissions, downloads, markdown content |
| Google Docs      | `https://connectors.gdplabs.id/google_docs/mcp`      | `google_docs`      | get/list/create/update/copy documents, markdown updates, comments, comment summaries          |
| Google Mail      | `https://connectors.gdplabs.id/google_mail/mcp`      | `google_mail`      | drafts, send email, labels, list/get/modify/delete emails, threads, attachments, auto-reply   |
| Google Calendar  | `https://connectors.gdplabs.id/google_calendar/mcp`  | `google_calendar`  | calendars, free/busy, event get/list/insert/update/delete                                     |
| Google Sheets    | `https://connectors.gdplabs.id/google_sheets/mcp`    | `google_sheets`    | create spreadsheet, get/update/batch update/append values                                     |
| Slack            | `https://connectors.gdplabs.id/slack/mcp`            | `slack`            | channels, messages, users, search, bookmarks, pins, reactions, reminders                      |
| SQL              | `https://connectors.gdplabs.id/sql/mcp`              | `sql`              | SQL query execution against a configured database                                             |
| Code Interpreter | `https://connectors.gdplabs.id/code_interpreter/mcp` | `code_interpreter` | remote Python execution                                                                       |

Authentication options:

* **Token-based/headless**: send the client API key in the `X-Api-Key` header and the user token in the `Authorization` bearer header. Optionally pass `X-Integration` when selecting a specific integration.
* **OAuth 2.1/interactive clients**: supported clients can often configure only `serverUrl`, then complete the interactive OAuth flow.
* **Client compatibility**: clients must support Streamable HTTP MCP directly, or use a bridge such as `mcp-remote`/`mcp-proxy`.

Minimal MCP client shape from the GitBook:

```json
{
  "mcpServers": {
    "gmail": {
      "serverUrl": "https://connectors.gdplabs.id/google_mail/mcp"
    }
  }
}
```

AIP usage should restrict tools whenever possible. For example, a PR summary workflow should expose only the GitHub operation it needs:

```python
from glaip_sdk import Agent, MCP

agent = Agent(
    name="github-agent",
    instruction="Summarise PRs",
    mcps=[MCP.from_native("github")],
    mcp_configs={
        "github": {
            "allowed_tools": ["github_list_pull_requests"]
        }
    },
)
```

Use MCP when the agent should choose between multiple related service actions, such as finding GitHub PRs and then inspecting one, or searching Drive before retrieving a file. Use direct API instead when the action is a single deterministic call.

### Skills

Use Skills for the *how*: procedures, review checklists, report formats, house style, escalation rules, or multi-step workflows. Skills do not add live access by themselves, so pair them with seeded native tools, APIs, function-calling tools, or MCP servers when the workflow needs runtime capability.

The GL Connectors docs describe Skills as folders containing `SKILL.md` plus optional scripts and resources. They provide:

* **Procedural knowledge**: step-by-step task instructions.
* **Contextual awareness**: company, team, or user-specific information.
* **On-demand behavior**: instructions loaded dynamically when a compatible agent matches the task.

GL Connectors Skills currently act as an SDK path to install Agent Skills; the docs point to public skill sources rather than a GL Connectors-owned skill catalog. Examples of skill sources and what they provide:

| Source       | What the skills provide                                                                                              |
| ------------ | -------------------------------------------------------------------------------------------------------------------- |
| Anthropic    | document and creative workflows such as `docx`, `pdf`, `pptx`, `xlsx`, frontend design, and algorithmic art examples |
| OpenAI/Codex | coding skills grouped into auto-installed, curated, and experimental skill sets                                      |
| Microsoft    | Azure SDK and Microsoft AI Foundry workflows across Python, .NET, TypeScript, and Java                               |
| Vercel       | React/Next.js best practices, web design, React Native, and Vercel deployment guidance                               |
| GitHub       | community skills, custom agents, instructions, and prompts for GitHub Copilot workflows                              |
| Hugging Face | ML workflows such as dataset creation, training, evaluation, experiment tracking, and Hub CLI usage                  |
| Supabase     | PostgreSQL performance optimization guidance                                                                         |
| Google       | Gemini API/SDK and Stitch workflows such as design-to-code, Remotion video, and shadcn/ui components                 |

Typical installation flow from the GitBook:

```bash
uv init --bare
uv add gl-connectors-tools-binary
```

```python
import asyncio
from gl_connectors_tools.skill_factory import SkillFactory

async def install_skills():
    await SkillFactory.from_github(
        source="https://github.com/anthropics/skills/tree/main/skills/algorithmic-art",
        destination=[".agents/skills"],
    )

asyncio.run(install_skills())
```

For private repositories, pass a token. Common destinations include `.claude/skills`, `.github/skills`, `.cursor/skills`, `.windsurf/skills`, `.codex/skills`, `.kimi/skills`, or an AIP-managed skills directory.

Use a Skill when the agent needs to perform a repeatable workflow consistently: code review checklists, PR summary format, monthly reporting steps, presentation generation rules, spreadsheet analysis conventions, or team-specific escalation instructions. Pair it with MCP/API/tools for live capabilities.

### Combined Workflows

Use multiple components only when the responsibilities are different. A strong pattern is:

1. **Skill**: defines the workflow and output contract.
2. **MCP**: fetches or updates broad service data with an allow-list.
3. **API**: performs a precise deterministic operation such as upload/download.
4. **Function-calling tool**: handles local runtime work such as temporary files or date ranges.

The GL Connectors cookbook's PR summary pipeline demonstrates this pattern with all four surfaces attached to one AIP agent.

## Anti-patterns

* Building an MCP server only to enforce formatting. Use a Skill.
* Creating many one-endpoint tools for a broad service. Use MCP with an allow-list.
* Using a Skill for live data access. Use an API, native tool, or MCP for the data and keep the Skill for instructions.
* Duplicating seeded `bosa_` native tools as custom tools unless the default behavior is insufficient.
* Exposing a full MCP surface when the use case only needs one or two service actions.

## Implementation Checklist

* [ ] Pick one primary surface using the quick choice guide.
* [ ] Reuse seeded `bosa_` GL Connectors native tools before adding a new function-calling tool.
* [ ] Use direct API calls for deterministic external operations, especially file transfer.
* [ ] Use MCP with `allowed_tools` for broad service access.
* [ ] Add a Skill only when the agent needs procedure, workflow, or output guidance.
* [ ] Link back to the GL Connectors component guide and cookbook from feature docs or runbooks.

## Related Documentation

* [GL Connectors Components](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/gl-connectors-components)
* [GL Connectors Cookbook](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/gl-connectors-cookbook)
* [GL Connectors API](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/api)
* [GL Connectors MCP](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/agentic-tools-and-model-context-protocol-mcp)
* [GL Connectors Skills](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/connectors-skills)
* [GL Connectors Tools](https://gdplabs.gitbook.io/sdk/gl-connectors/sdk/tools)


# Audio Interface

Add audio input/output to AIP agents using one interface that supports multiple implementations.

* **One interface:** `create_audio_session(...)` in `glaip-sdk`
* **Many implementations:** provider-specific session backends under the same API
* **Current implementation:** `livekit` (available now)
* **Planned implementation:** `attendee` (TBD)

{% hint style="info" %}
Audio interface is beta and local-only. You must run the LiveKit server and client yourself. The CLI does not expose audio sessions yet. This page documents a design preview; APIs and behavior may change before release.
{% endhint %}

### Interface First (Provider-Agnostic)

The entrypoint stays the same across providers: `create_audio_session(...)`. Implementation selection is explicit: pass `implementation="..."` or set `config["provider"]`. If both are omitted, session creation raises `ValueError`.

#### Hypothetical provider example

This shows the interface shape before choosing a concrete transport:

```python
import asyncio
from glaip_sdk import Agent


async def main() -> None:
    agent = Agent(name="my-agent", instruction="You are a helpful assistant.")
    session = agent.create_audio_session(
        implementation="my-provider",
        config={
            "provider": "my-provider",
            "io": {"input_enabled": True, "output_enabled": True},
            "my_provider": {"endpoint": "...", "token": "..."},
        },
    )
    await session.run()


if __name__ == "__main__":
    asyncio.run(main())
```

#### SDK Usage (Minimum)

Use this as the smallest working snippet in `glaip-sdk`:

```python
import asyncio
from glaip_sdk import Agent

async def main():
    agent = Agent(name="my-agent", instruction="You are a helpful assistant.")
    session = agent.create_audio_session(implementation="livekit")
    await session.run()

if __name__ == "__main__":
    asyncio.run(main())
```

This call is intentionally explicit. The following fails because no implementation is provided:

```python
session = agent.create_audio_session()
# ValueError: Audio implementation must be specified
```

#### Custom implementation wiring (same interface)

```python
from glaip_sdk.audio_interface import register_audio_session_implementation


class CustomProviderSession:
    ...


register_audio_session_implementation("custom-provider", CustomProviderSession)

# Swap implementation without changing the high-level call shape.
session = agent.create_audio_session(implementation="custom-provider")
```

### Architecture Overview (Interface + Providers)

This is the high-level architecture behind the interface:

```mermaid
graph TD
    User[Human and mic audio<br/>Speech input and output]

    LiveKit[LiveKit<br/>WebRTC provider]
    Attendee[Attendee<br/>Meeting bot provider<br/>TBD for Meemo]
    Custom[Custom<br/>Any other provider]

    SDK[glaip-sdk<br/>Audio Interface<br/>create_audio_session]
    AIP[aip-agents<br/>Agent logic and tools]

    User <-->|voice transport| LiveKit
    LiveKit <-->|session API| SDK
    SDK <-->|agent runtime| AIP

    User <-->|voice transport| Attendee
    User <-->|voice transport| Custom
    Attendee <-->|session API| SDK
    Custom <-->|session API| SDK

    classDef current fill:#eef7ff,stroke:#4c7fb8,color:#163a5f,stroke-width:1.8px
    classDef planned fill:#f6f8fc,stroke:#77869b,color:#2d3b4e,stroke-width:1.6px

    class User,LiveKit,SDK,AIP current
    class Attendee,Custom planned
```

### Current Implementation: LiveKit (Available Now)

LiveKit is the implementation ready today. You still use the same interface and select `implementation="livekit"`.

To explicitly pass LiveKit config from code:

```python
session = agent.create_audio_session(
    implementation="livekit",
    config={
        "provider": "livekit",
        "io": {"input_enabled": True, "output_enabled": True},
        "livekit": {
            "url": "ws://localhost:7880",
            "api_key": "devkey",
            "api_secret": "devsecretdevsecretdevsecretdevsecret",
            "room_name": "aip-audio-demo",
        },
    }
)
```

LiveKit prerequisites, setup commands, and local test flow are currently captured in `python/glaip-sdk/examples/sdk/livekit-local-dev.md`.

#### Planned Implementation: Attendee / Meemo (TBD)

The audio interface is provider-agnostic, and we plan to add an Attendee-based transport for Google Meet/Meemo flows.

* **Attendee status**: TBD. This is the provider path planned for Meemo.
* **Core provider implementation** will be added in `aip-agents` audio interface (session implementation + factory mapping).
* **SDK DX** will remain low-code in `glaip-sdk` via `create_audio_session(...)` with provider selection.

This section will be updated with concrete setup once the Attendee provider is available.

### Provider Model

The audio interface is provider-agnostic. Use `implementation="..."` to pick the backend (for example `"livekit"` today). Provider-specific settings are passed via config.

Current AIP implementation support: LiveKit AgentSession-based local audio sessions.

### Turn Sequence (Audio -> STT -> AIP -> TTS)

The runtime turn flow is the same across providers; only the transport implementation changes.

```mermaid
sequenceDiagram
    autonumber
    participant U as User (voice)
    participant P as Audio Provider
    participant STT as STT
    participant A as AIP Agent
    participant X as External Action/Tool
    participant TTS as TTS

    rect rgb(235, 247, 255)
        U->>P: 1) Audio-in (speech)
        P->>STT: 2) Stream audio frames
        STT->>A: 3) Transcript text
    end

    rect rgb(237, 255, 241)
        A->>X: 4) Do something (tool/action, optional)
        X-->>A: 5) Action result
    end

    rect rgb(255, 246, 232)
        A->>TTS: 6) Response text
        TTS->>P: 7) Synthesized audio
        P-->>U: 8) Speak + chat response
    end
```

### Tool Call Visibility

Tool calls are handled by the underlying agent runtime (e.g. LangGraph) the same way they are for text-only runs.

For the demo workflow in this repo:

* run with `AIP_AUDIO_DEBUG=1` to print transcripts and final replies
* use the agent's standard streaming/logging to observe tool events

### Configuration Tips

* **Audio input/output**: Set `input_enabled` or `output_enabled` to `False` to run input-only or output-only sessions.
* **Devices**: Supply `input_device` or `output_device` when multiple audio devices are present.
* **STT/TTS**: Provider-specific. LiveKit handles audio transport; transcription and synthesis live in the LiveKit worker/agent. Providers that expose model selection use `AudioModelConfig` (see the GL SDK realtime session tutorial).
* **Provider config**: `LiveKitConfig` expects the server URL, `api_key`, and `api_secret`; `room_name` and `identity` are optional.

### Limitations

* Local-only; no AIP-hosted audio service yet.
* LiveKit is the only provider supported in this phase for AIP, but the API is provider-agnostic for future providers.
* CLI support is intentionally deferred.

### Troubleshooting

| Symptom                        | Likely cause               | Fix                                                                                                                                  |
| ------------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `AudioSessionUnavailableError` | LiveKit deps are missing   | Install published extras: `pip install "glaip-sdk[audio]"`. Monorepo contributors can run `make -C python/aip-agents install-audio`. |
| `AudioConfigError`             | URL/api key/secret missing | Check `LiveKitConfig` and env vars `LIVEKIT_API_KEY` / `LIVEKIT_API_SECRET`.                                                         |
| No audio / device error        | Device not available       | Disable audio output or set `input_device`/`output_device`.                                                                          |

### Related Documentation

* Local setup runbook (repo): `python/glaip-sdk/examples/sdk/livekit-local-dev.md`
* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — manage agent configs and runtime overrides.
* [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) — inspect tool definitions and outputs.
* [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — handle credentials and sensitive data.

### External References

* [GL SDK realtime session tutorial](https://gdplabs.gitbook.io/sdk/tutorials/inference/realtime-session)


# Tutorials

Use tutorials for end-to-end walkthroughs and pattern drills.

### Included Tutorials

* [CLI](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli) for command workflows, interactive operations, and lifecycle drills using only terminal commands.
* [Hands-on examples](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/hands-on-examples) for runnable, validated project blueprints.
* [Multi-agent system patterns](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns) for sequential, parallel, router, hierarchical, loop, and aggregator workflows.

If you prefer short copy-and-run recipes, start at the [Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns).


# CLI

Use AIP CLI as the utility layer for agent development after you finish conceptual design in Guides.

### When to Use CLI

* Validate access and environment health before coding: `aip status`.
* Operate resources without writing scripts: list, inspect, create, update.
* Run and debug agents interactively with rich streaming output.
* Export/import agents, tools, and MCPs for promotion workflows.

### Placeholder Legend

* `<ACCOUNT_NAME>`: Named CLI account profile (for example `prod`, `staging`).
* `<AGENT_REF>`: Agent ID or unique agent name.
* `<TOOL_REF>`: Tool ID or unique tool name.
* `<MCP_REF>`: MCP ID or unique MCP name.
* `<RUN_ID>`: Run ID from transcript or history views.
* `<EXPORT_FILE>`: Output file path, for example `agent.yaml`.

### CLI Learning Path

1. Start with the [Lifecycle tutorial](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/lifecycle).
2. Continue with [Use cases](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/use-cases).
3. Learn core commands in [Accounts](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/accounts), [Status](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/status), and [Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/agents).
4. Add capabilities with [Tools](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/tools), [MCPs](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/mcps), and [Models](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/models).
5. Capture output using [Runs and Transcripts](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/runs-and-transcripts).
6. Promote config safely with [MCP export/import workflow](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/workflows/mcp-export-import).

### Interactive UX

* Open the palette with `aip` and use `/accounts`, `/agents`, `/status`, and `/transcripts`.
* After selecting an agent via `/agents`, use `/runs` and `/schedules` for remote debugging and automation.
* Workflow guide: [Slash palette](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/interactive/slash-palette).

### Command Reference

* Detailed flags and options: [CLI Commands Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands).
* Legacy config format: [CLI Legacy Config](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-legacy-config).


# CLI Agent Lifecycle

Build, test, and promote one agent end-to-end using only the `aip` CLI.

*When to use:* You want a reproducible terminal workflow for demos, QA validation, or ops handoff without writing Python code.

{% hint style="info" %}
If you are brand new to the CLI, complete [Quick Start (CLI)](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide/cli) first, then return here.
{% endhint %}

### What You Will Do

1. Verify account and connectivity.
2. Create a production-style support triage agent.
3. Run prompts and save transcripts.
4. Iterate instructions with `update`.
5. Export and promote the agent config.
6. Validate the same flow in the slash palette.

### Step 1: Verify Account and Environment

```bash
aip accounts use <ACCOUNT_NAME>
aip status
```

Expected result: status shows valid auth, reachable API, and healthy resource checks.

### Step 2: Create the Agent

```bash
aip agents create \
  --name "support-triage-cli" \
  --instruction "You triage incoming support tickets. Return severity, likely owner, and next action in 3 bullets." \
  --model "openai/gpt-5-mini"
```

Expected result: CLI prints the new agent ID and name. Keep either value for run commands.

### Step 3: Run and Capture a Transcript

```bash
mkdir -p runs
aip agents run support-triage-cli \
  "Customer reports repeated 504 errors on checkout in the last 10 minutes." \
  --save runs/triage-checkout.md
```

Expected result: streamed output in terminal plus a saved transcript at `runs/triage-checkout.md`.

### Step 4: Tighten Behavior with Update

Update the instruction to return strict JSON for downstream automation:

```bash
aip agents update support-triage-cli \
  --instruction "Classify tickets into severity P1-P4 and output valid JSON with keys: severity, owner, next_action, rationale."
```

Re-run to confirm the new format:

```bash
aip agents run support-triage-cli "Payment webhook retries are spiking after deploy." --save runs/triage-webhook.md
```

Expected result: output shape follows the new JSON-oriented instruction.

### Step 5: Export and Promote Configuration

Export the current definition:

```bash
aip agents get support-triage-cli --export support-triage-cli.yaml
```

Create a second environment copy from that file:

```bash
aip agents create --import support-triage-cli.yaml --name support-triage-cli-staging
```

Validate both exist:

```bash
aip agents list
```

Expected result: both `support-triage-cli` and `support-triage-cli-staging` appear in the list.

### Step 6: Validate in Interactive Palette

```bash
aip
```

Then run:

* `/agents` to select `support-triage-cli` and execute a prompt.
* `/runs` to inspect recent executions.

Use the [Slash palette guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/interactive/slash-palette) if you want command discovery screenshots and key bindings.

### Optional Cleanup

```bash
aip agents delete support-triage-cli-staging --yes
```

Keep the main tutorial agent if you want to continue testing export/import and transcript workflows.

### Related Documentation

* [CLI Use Cases](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/use-cases) for compact, task-based command recipes.
* [Agents Commands](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/agents) for full command syntax and flags.
* [CLI Commands Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands) for complete option coverage.


# Use Cases

Use these workflows when you need CLI to support day-to-day agent development without writing custom scripts.

### 1) Validate Environment Before Coding

*Use when:* A teammate cannot run agents, or you just switched credentials.

```bash
aip accounts use <ACCOUNT_NAME>
aip status
```

Expected result: auth is valid, API is reachable, and resource checks return successfully.

### 2) Quickly Run an Existing Agent

*Use when:* You want to validate prompt behavior before changing SDK code.

```bash
aip agents list
aip agents run <AGENT_REF> "Summarize this requirement in 5 bullets"
```

Expected result: streamed output appears in terminal and final response is shown.

### 3) Capture a Transcript for Debugging

*Use when:* You need to share reproducible evidence with engineers or PMs.

```bash
aip agents run <AGENT_REF> "Investigate tool failure" --save run.md
/transcripts
```

Expected result: saved file path plus cached run history.

### 4) Promote MCP Configuration Across Environments

*Use when:* You move config from staging to production.

```bash
aip mcps get <MCP_REF> --export <EXPORT_FILE> --no-auth-prompt
# edit placeholders/secrets in <EXPORT_FILE>
aip mcps create --import <EXPORT_FILE>
```

Expected result: imported MCP appears in `aip mcps list` for target environment.

### 5) Update Agent Attachments (Tools/MCPs)

*Use when:* You need to test capability changes without redeploying app code.

```bash
aip agents update <AGENT_REF> --tools <TOOL_REF>
aip agents update <AGENT_REF> --mcps <MCP_REF>
```

Expected result: `aip agents get <AGENT_REF>` shows updated dependencies.

### 6) Run Interactive Ops from Palette

*Use when:* You prefer guided selection and quick discovery.

```bash
aip
```

Then use `/accounts`, `/agents`, or `/transcripts` (and inside an agent session: `/runs` and `/schedules`).

See [Slash palette guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-slash-palette) for details.


# Commands

CLI commands for managing accounts, agents, tools, MCPs, models, and runs.

### Commands

| Command                                                                                          | Purpose                                                     |
| ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- |
| [Accounts](/sdk/gl-aip-ai-agent-package/tutorials/cli/commands/accounts)                         | Manage credential profiles and switch between environments. |
| [Status](/sdk/gl-aip-ai-agent-package/tutorials/cli/commands/status)                             | Validate connectivity and environment health.               |
| [Agents](/sdk/gl-aip-ai-agent-package/tutorials/cli/commands/agents)                             | List, inspect, create, and run agents.                      |
| [Tools](/sdk/gl-aip-ai-agent-package/tutorials/cli/commands/tools)                               | Attach and manage tools for agents.                         |
| [MCPs](/sdk/gl-aip-ai-agent-package/tutorials/cli/commands/mcps)                                 | Configure and manage MCP servers.                           |
| [Models](/sdk/gl-aip-ai-agent-package/tutorials/cli/commands/models)                             | List and inspect language models.                           |
| [Runs and Transcripts](/sdk/gl-aip-ai-agent-package/tutorials/cli/commands/runs-and-transcripts) | Capture and view run output.                                |


# Accounts

Accounts are named credential profiles in `~/.aip/config.yaml`.

*Use when:* You switch between environments (dev, staging, prod) during agent development.

### Placeholders

* `<ACCOUNT_NAME>`: profile name, for example `prod`.

### Common Commands

```bash
aip accounts add <ACCOUNT_NAME>
aip accounts list
aip accounts use <ACCOUNT_NAME>
aip accounts show <ACCOUNT_NAME>
```

### Rotate Credentials

```bash
aip accounts edit <ACCOUNT_NAME>
```

Non-interactive update:

```bash
aip accounts edit <ACCOUNT_NAME> --url "https://your-aip-instance.com" --key "${AIP_API_KEY}"
```

### Rename and Remove

```bash
aip accounts rename <ACCOUNT_NAME> <NEW_ACCOUNT_NAME>
aip accounts remove <NEW_ACCOUNT_NAME>
```

### Expected Result

* `aip accounts use <ACCOUNT_NAME>` succeeds and `aip status` shows valid connectivity.


# Status

Use `aip status` as the first health check before agent runs.

*Use when:* You need to confirm auth/network issues quickly.

### Command

```bash
aip status
```

### Expected Result

* API URL is reachable.
* Auth is valid.
* Basic resource checks complete.

### Common Failures and Fixes

* `401 Unauthorized`: rotate key with `aip accounts edit <ACCOUNT_NAME>`.
* `timeout` or `connection refused`: update URL and check network/VPN.
* TLS errors: use proper CA/proxy settings for your environment.

### Next Commands

```bash
aip agents list
aip tools list
aip mcps list
```


# Agents

Use CLI agents commands to iterate and validate behavior without writing SDK scripts.

*Use when:* You want quick create/run/export loops during agent development.

### Placeholders

* `<AGENT_REF>`: agent ID or unique name.
* `<EXPORT_FILE>`: output file path, for example `agent.yaml`.

### List and Inspect

```bash
aip agents list
aip agents get <AGENT_REF>
```

### Create and Run

```bash
aip agents create --name "hello-cli" --instruction "You are a friendly assistant."
aip agents run <AGENT_REF> "Hello"
```

Attach remote GitHub-backed skills at create time:

```bash
aip agents create \
  --name "skills-cli" \
  --instruction "Use attached skills when helpful." \
  --skills https://github.com/org/repo/tree/main/skills/copywriting
```

Save transcript:

```bash
aip agents run <AGENT_REF> "Hello" --save run.md
```

### Export and Import (Promotion Loop)

```bash
aip agents get <AGENT_REF> --export <EXPORT_FILE>
aip agents create --import <EXPORT_FILE> --name "hello-cli-prod"
```

Update existing agent from file:

```bash
aip agents update <AGENT_REF> --import <EXPORT_FILE>
```

### Common Capability Updates

```bash
aip agents update <AGENT_REF> --tools <TOOL_REF>
aip agents update <AGENT_REF> --mcps <MCP_REF>
aip agents update <AGENT_REF> --skills https://github.com/org/repo/tree/main/skills/research
```

`--skills` replaces the full skill set. Repeat the flag or pass comma-separated URLs to attach more than one remote skill.


# Tools

Tools commands help you manage agent capabilities quickly from terminal.

*Use when:* You need to upload, inspect, or promote tools while iterating on agents.

### Placeholders

* `<TOOL_REF>`: tool ID or unique name.
* `<EXPORT_FILE>`: output file path, for example `tool.json`.

### List and Inspect

```bash
aip tools list
aip tools get <TOOL_REF>
```

### Create and Update

```bash
aip tools create tool.py --name "my-tool"
aip tools update <TOOL_REF> --file tool.py
```

View source script:

```bash
aip tools script <TOOL_REF>
```

### Promotion Workflow

```bash
aip tools get <TOOL_REF> --export <EXPORT_FILE>
aip tools create --import <EXPORT_FILE>
```

Related: [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools).


# MCPs

MCP commands connect agents to external tool servers and support promotion workflows.

*Use when:* You need to register, test, and move MCP configs across environments.

### Placeholders

* `<MCP_REF>`: MCP ID or unique MCP name.
* `<EXPORT_FILE>`: output file path, for example `mcp.yaml`.

### List and Create

```bash
aip mcps list
aip mcps create --name "my-mcp" --transport http --url "https://example.com/mcp"
```

### Test Connection

```bash
aip mcps connect --url "https://example.com/mcp"
```

### Export and Import

```bash
aip mcps get <MCP_REF> --export <EXPORT_FILE>
aip mcps create --import <EXPORT_FILE>
```

For full secret-handling workflow, use [MCP export/import guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/workflows/mcp-export-import).


# Models

Use models commands to discover available language models before assigning them to agents.

*Use when:* You are choosing or validating model IDs for agent updates.

### Commands

```bash
aip models list
aip models list --view json
```

### Expected Result

* Model IDs/providers are visible for the current account.

### Next Step

* Set model on agent config, then validate with `aip agents run <AGENT_REF> "..."`.
* Model selection guidance: [Language models guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/language-models).


# Runs and Transcripts

Use runs and transcripts to debug agent behavior and share reproducible outputs.

*Use when:* You need evidence for prompt quality, tool failures, or regression checks.

### Placeholders

* `<AGENT_REF>`: agent ID or unique name.
* `<RUN_ID>`: run ID from transcripts listing.

### Run and Save Output

```bash
aip agents run <AGENT_REF> "Hello" --save run.md
aip agents run <AGENT_REF> "Hello" --save run.json --view json
```

In `--view rich` mode, the CLI also captures a local transcript and may open the post-run transcript viewer automatically when running in a TTY.

### Transcript Commands

```bash
/transcripts
```

Inside the command palette (run `aip`), press `Ctrl+T` after a run to open the transcript viewer for the most recent execution.

Use `/transcripts` to browse and open local cached runs.

Cache location defaults to `~/.config/glaip-sdk/transcripts/`. Override with `AIP_TRANSCRIPT_CACHE_DIR` when you need a custom path (for example on CI machines).

There is currently no dedicated cleanup command; remove the cache directory manually if you need to clear transcript files.

### Interactive Remote Run Debugging

```bash
aip
```

Inside palette: `/agents` -> select agent -> `/runs` -> open run details.

To open a known remote run directly from the same agent context:

```
/runs <RUN_ID>
```

Run details now keep general metadata and usage in separate sections. The `Usage` section displays aggregate usage when the platform returns `total_usage`:

```
Total
Input   5,372
Output    671
Total   6,043
```

When the platform also returns `model_usage`, `/runs` uses each safe provider/model identity as its own section and nests token details underneath it:

```
Per Model
openai:gpt-5.2
Input      3,668
Cached     1,792
Uncached   1,876
Output       649
Reasoning      0
Response     649
Total      4,317

openai:gpt-5-mini
Input      1,704
Cached         0
Uncached   1,704
Output        22
Reasoning      0
Response      22
Total      1,726
```

Older runs may only include `total_usage` or no usage fields. When aggregate usage exists but `model_usage` is absent, `/runs` keeps the aggregate `Total` and shows a best-effort per-model section using the current selected agent model when it can be resolved, marked with `(estimated)`. If the model cannot be resolved, it falls back to `unknown model`.

The transcript pane remains a raw event JSON view. If the backend emits usage fields such as `step_usage`, `total_usage`, or `model_usage` inside transcript events, those fields appear there verbatim; the transcript does not currently reformat them into a separate usage table.

Remote JSONL exports include the normalized `total_usage` and `model_usage` summary fields when they are present, while preserving raw per-event metadata in the transcript records.

Related: [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents).


# Interactive

Interactive CLI workflows for guided operations with less typing.

### Topics

| Topic                                                                                 | Purpose                                                     |
| ------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| [Slash Palette](/sdk/gl-aip-ai-agent-package/tutorials/cli/interactive/slash-palette) | Use the palette for discoverable commands and guided flows. |


# Slash Palette

Use the slash palette for guided CLI operations with less typing.

*Use when:* You want discoverable commands while debugging or operating agents.

### Start Palette

```bash
aip
```

<figure><img src="/files/5Vsq30LrUKgNZHfTHSop" alt=""><figcaption><p>Agent workspace shell screenshot captured from the Textual TUI flow.</p></figcaption></figure>

<figure><img src="/files/auNLXbhqslSTIVqM3IZL" alt=""><figcaption><p>CLI command screenshot captured from `aip --help`.</p></figcaption></figure>

### Core Flows

From the palette home screen:

* `/accounts`: manage credential profiles (add/switch).
* `/agents`: pick an agent and enter a focused run prompt.
* `/transcripts`: browse cached local transcripts and open the viewer.

Inside an agent session (after `/agents`):

* `/runs`: browse remote run history for the active agent.
* `/schedules`: manage recurring schedules for the active agent.
* `/prompt`: edit the agent instruction in a TUI.
* `/details`: view the agent export/config.

### Suggested Debug Loop

1. `/agents` -> select target agent.
2. `/runs` -> open latest failed or suspicious run.
3. Inspect tool calls and final output.
4. `/transcripts` -> open the cached transcript viewer when you need detailed local evidence.

Tip: after an agent run, press `Ctrl+T` to open the transcript viewer for the most recent execution.

Reference details: [CLI Slash Palette Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-slash-palette).


# Workflows

Workflows for promoting and migrating configurations between environments.

### Topics

| Topic                                                                                           | Purpose                                                              |
| ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| [MCP Export and Import](/sdk/gl-aip-ai-agent-package/tutorials/cli/workflows/mcp-export-import) | Safely move MCP configurations between dev, staging, and production. |


# MCP Export and Import

Use this workflow to safely move MCP configurations between environments.

*Use when:* You promote MCP setup from dev/staging to production and need secret-safe exports.

### Placeholders

* `<MCP_REF>`: MCP ID or unique MCP name.
* `<EXPORT_FILE>`: export path, for example `mcp.yaml`.
* `<AUTH_PLACEHOLDER>`: placeholder text such as `${MCP_AUTH_TOKEN}`.
* `<TARGET_ACCOUNT_NAME>`: destination CLI account profile.

### Basic Export

```bash
aip mcps get <MCP_REF> --export <EXPORT_FILE>
```

Format is inferred from extension (`.json`, `.yaml`, `.yml`).

### Non-Interactive Export (CI/CD)

```bash
aip mcps get <MCP_REF> \
  --export <EXPORT_FILE> \
  --no-auth-prompt \
  --auth-placeholder "<AUTH_PLACEHOLDER>"
```

Use this mode for automation to avoid prompt hangs.

### Import to Target Environment

```bash
aip accounts use <TARGET_ACCOUNT_NAME>
aip mcps create --import <EXPORT_FILE>
```

### Security Rules

* Never commit real secrets to git.
* Prefer `--no-auth-prompt` for exported files destined for repositories.
* Inject secrets at deploy/runtime via secret manager or environment variables.

### Related Pages

* [CLI MCP commands](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli/commands/mcps)
* [MCP schema reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/mcps)
* [REST API MCPs](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/mcps)


# Multi-Agent System Patterns

Explore runnable templates for orchestrating multiple agents with GL AIP.

> **Success**
>
> **When to use this section:** You need proven coordination patterns before customising them for production.
>
> **Audience:** Engineers designing workflows and PMs creating workflows from requirements.

Use these examples to compare architectures (sequential, parallel, router, hierarchical, aggregator, loop) and understand when to apply each one.

### Prerequisites

* Python 3.11 or 3.12
* [uv](https://docs.astral.sh/uv/) package manager installed
* The public cookbook repository cloned locally:

  ```bash
  git clone https://github.com/gdplabs/gl-aip-sdk-cookbook.git
  ```
* Environment variables defined in `.env`:

  ```bash
  OPENAI_API_KEY=your-openai-key-here
  ```

### Getting Started

Ready-to-run implementations of these patterns are available in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns).

```bash
git clone https://github.com/gdplabs/gl-aip-sdk-cookbook.git
cd gl-aip-sdk-cookbook/examples/multi-agent-system-patterns
uv sync
cp .env.example .env  # then edit with your credentials
```

Run any pattern example with uv, for example the sequential workflow:

```bash
uv run sequential/main.py
```

### Orchestration Approaches

These patterns demonstrate two orchestration approaches, each suited for different workflow types:

#### gllm-pipeline (Linear Workflows)

Patterns with **linear, non-cyclic workflows** use `gllm-pipeline` for orchestration. gllm-pipeline provides a declarative API with features like:

* **Parallel execution** - Run multiple agents simultaneously
* **Sequential workflows** - Chain agents where output flows to the next
* **Conditional routing** - Direct queries to specialized agents based on logic
* **State management** - Track data flow through the pipeline using Pydantic models

**Patterns using gllm-pipeline:**

* Sequential, Parallel, Router, Aggregator

To use these patterns, install `gllm-pipeline-binary` version 0.4.13:

```bash
uv add gllm-pipeline-binary==0.4.13
```

#### Sub-Agent Delegation (Cyclic Workflows)

Patterns with **cyclic workflows or feedback loops** use sub-agent delegation instead. This approach allows parent agents to:

* Make autonomous decisions based on sub-agent responses
* Loop back to previous steps for refinement
* Implement quality checks and conditional branching
* Control iteration limits to prevent infinite loops

**Patterns using sub-agent delegation:**

* Hierarchical (coordinator decides based on sub-agent outputs)
* Loop (optimizer iterates based on executor feedback)

These patterns define sub-agents via the `agents` parameter when creating the coordinator/optimizer agent.

### AgentComponent Wrapper

Patterns using gllm-pipeline (Sequential, Parallel, Router, Aggregator) use the `AgentComponent` wrapper to integrate `glaip_sdk.Agent` with gllm-pipeline. This wrapper is now built into the SDK and can be accessed via the `.to_component()` method.

**Note:** Sub-agent delegation patterns (Hierarchical, Loop) do not use this wrapper - they use the native `agents` parameter instead.

#### Usage

```python
from glaip_sdk import Agent

# Create an agent
assistant_agent = Agent(
    name="assistant_agent",
    instruction="Be helpful",
    model="openai/gpt-5-mini"
)

# Convert it to a pipeline-compatible component
component = assistant_agent.to_component()
```

The `AgentComponent` handles:

* Converting agents to pipeline-compatible components
* Compiling structured pipeline state (context, history) into a cohesive prompt
* Executing agents asynchronously within the pipeline
* Managing runtime configuration overrides

For more details on advanced usage, see the [Agent as Component](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/agent-component) guide.

### Example Structure

Every pattern page shares the same layout so you can skim quickly:

1. Overview of when the pattern works best
2. Demo scenario you can run immediately
3. Diagram showing agent relationships
4. Implementation steps with code snippets
5. Run commands and required environment variables
6. Sample output for validation
7. Notes and related documentation

### Pattern Library

| Pattern                                                                                                                   | When to use                                                   | Orchestration | Cookbook Example                                                                                                           |
| ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------- |
| [**Aggregator**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/aggregator)     | Combine specialist insights into one briefing.                | gllm-pipeline | [aggregator](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/aggregator)     |
| [**Hierarchical**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/hierarchical) | Delegate tasks through supervisors for complex workflows.     | Sub-agent     | [hierarchical](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/hierarchical) |
| [**Loop**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/loop)                 | Iterative optimization with feedback loops.                   | Sub-agent     | [loop](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/loop)                 |
| [**Parallel**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/parallel)         | Execute independent tasks simultaneously or compare variants. | gllm-pipeline | [parallel](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/parallel)         |
| [**Router**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/router)             | Direct each request to the right specialist.                  | gllm-pipeline | [router](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/router)             |
| [**Sequential**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/sequential)     | Refine answers step-by-step with predictable stages.          | gllm-pipeline | [sequential](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/sequential)     |

### Related Documentation

* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Agent lifecycle, nesting, and runtime overrides.
* [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) — Upload Python tools and reuse catalog assets.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — Run pattern scripts inside CI pipelines or cron jobs.
* [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — Apply memory, PII, and artifact-sharing controls across agents.


# Sequential

A linear workflow where each agent processes the output from the previous agent, ideal for intent refinement, multi-step validation, or staged content creation.

### Overview

Sequential compositions shine when work must pass through clearly defined stages. Each agent can tighten the scope, enrich the data, or validate the previous step before passing the baton.

### Demo Scenario: Refine Then Answer

Two lightweight agents collaborate on a user question using **gllm-pipeline**:

1. **Intent refiner** – rewrites the user's short prompt into a clear question
2. **Answerer** – provides the final response using the refined question

The pipeline automatically passes the output from the refiner as input to the answerer, eliminating manual data passing.

### Diagram

<figure><img src="/files/oMIuo26cFOp3M7LVIKqS" alt="Sequential pattern: User Query flows through Refiner Agent then Answerer Agent to produce a Final Answer."><figcaption><p>Sequential pattern — linear pipeline where each agent refines the output of the previous one.</p></figcaption></figure>

### Implementation Steps

1. **Create agents**

   ```python
   from glaip_sdk import Agent

   refiner_agent = Agent(
       name="refiner_agent",
       instruction="Rewrite ambiguous input as clear question...",
       model="openai/gpt-5-mini"
   )

   answerer_agent = Agent(
       name="answerer_agent",
       instruction="Answer coding questions with code...",
       model="openai/gpt-5-mini"
   )
   ```
2. **Chain steps with pipe operator**

   ```python
   from gllm_pipeline.steps import step

   pipeline = refine_step | answer_step
   pipeline.state_type = State
   ```
3. **Run the pipeline**

   ```python
   result = await pipeline.invoke(state)
   print(result['final_answer'])
   ```

> **Full implementation:** See `sequential/main.py` for complete code with State definition and step configuration.
>
> **AgentComponent:** See the [Agent as Component](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/agent-component) guide for details on the `.to_component()` pattern.

### How to Run

From the `sequential` example directory in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/sequential):

```bash
uv run main.py
```

Set the usual environment variables in `.env`:

```bash
OPENAI_API_KEY=your-openai-key-here
```

### Output

````
Final answer: Short answer: use str.join() when you want a single concatenated string (requires elements
to be str), use map(str, ...) or a comprehension to convert non-strings first, use str(list) for a quick
Python-style representation, and use json.dumps() when you need a JSON-formatted string (for interoperability).

Examples

1) List of strings — use join()
```python
words = ["apple", "banana", "cherry"]
s1 = ",".join(words)        # "apple,banana,cherry"
s2 = ", ".join(words)       # "apple, banana, cherry"
s3 = "\n".join(words)       # each on its own line
````

2. List of non-strings (integers) — convert elements first

```python
nums = [1, 2, 3]
s4 = ",".join(map(str, nums))      # "1,2,3"
s5 = ", ".join(str(n) for n in nums)  # "1, 2, 3"
```

3. Quick Python-looking representation — use str()

```python
lst = [1, "two", 3]
s6 = str(lst)   # "[1, 'two', 3]"
```

4. JSON output — use json.dumps()

```python
import json
data = [1, "two", 3]
s7 = json.dumps(data)   # '[1, "two", 3]'
```

...

Demo completed

```

## Notes

- This example uses **gllm-pipeline** for orchestrating the sequential workflow.
- The pipe operator (`|`) provides a clean, readable syntax for chaining sequential steps.
- Add more stages by creating additional steps and chaining them with the pipe operator.
- All intermediate state (like `refined_query`) is automatically managed by the pipeline.
- To install gllm-pipeline: `uv add gllm-pipeline-binary==0.4.13` (compatible with aip_agents and langgraph <0.3.x)

## Related Documentation

- [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Configure instructions and streaming renderers.
- [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — Capture transcripts inside CI pipelines.
- [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — Apply memory and PII policies between stages.
```


# Parallel

A concurrent workflow where multiple agents process the same input simultaneously, ideal for comparative analysis, multi-model testing, or getting multiple perspectives.

Multiple agents tackle independent subtasks simultaneously to reduce overall latency, with each agent's output preserved separately.

### Overview

Use this pattern when subtasks do not depend on each other and you want faster responses by running them side by side. The outputs are displayed separately, preserving each agent's unique perspective without synthesis.

### Demo Scenario: Trip Planning with Specialized Agents

Two travel specialists work in parallel on the same user request using **gllm-pipeline**:

* **Logistics agent** – focuses on flights, hotels, and transportation
* **Activities agent** – curates attractions, food, and experiences

The pipeline runs both specialists simultaneously and returns their outputs separately, allowing you to see each specialist's perspective distinctly.

### Diagram

<figure><img src="/files/hek4GI6xJ1I5QEV2VhZb" alt="Parallel pattern: User Query fans out to Logistics Agent and Activities Agent simultaneously, merging into Combined Output."><figcaption><p>Parallel pattern — multiple agents process the same input concurrently.</p></figcaption></figure>

### Implementation Steps

1. **Create specialist agents**

   ```python
   from glaip_sdk import Agent

   logistics_agent = Agent(
       name="logistics_agent",
       instruction="Focus on flights, hotels, transport...",
       model="openai/gpt-5-mini"
   )

   activities_agent = Agent(
       name="activities_agent",
       instruction="Focus on attractions, food...",
       model="openai/gpt-5-mini"
   )
   ```
2. **Build pipeline: parallel → merge**

   ```python
   from gllm_pipeline.steps import parallel, step, transform

   pipeline = (
       parallel(branches=[logistics_step, activities_step])
       | transform(
           format_outputs,
           ["logistics_out", "activities_out"],
           "combined_output"
       )
   )
   pipeline.state_type = State
   ```
3. **Run the pipeline**

   ```python
   result = await pipeline.invoke(state)
   print(result['combined_output'])
   ```

> **Full implementation:** See `parallel/main.py` for complete code with State definition and step configuration.
>
> **AgentComponent:** See the [Agent as Component](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/agent-component) guide for details on the `.to_component()` pattern.

### How to Run

From the `parallel` example directory in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/parallel):

```bash
uv run main.py
```

Ensure your `.env` contains:

```bash
OPENAI_API_KEY=your-openai-key-here
```

### Output

```
Specialist Outputs:
[Logistics]
Assuming you're departing from Jakarta (CGK). Plan: 5 days (4 nights) — 2026-02-12 (Thu) to 2026-02-16 (Mon).
Below are concise logistics: flights, hotels, airport ⇄ city, local transport, and budget estimates.

Flights (roundtrip, economy)
- Recommended: nonstop CGK ⇄ Tokyo Haneda (HND) when available — carriers: Garuda Indonesia, ANA, JAL.
  Typical duration ~7.5–8.5 hrs.
- Flight timing: take overnight outbound (depart CGK evening, arrive HND morning) and evening or
  late-afternoon return to maximize time.
...

Hotels (4 nights) — pick by area
- Budget (Asakusa/Ueno): APA Hotel / Hotel MyStays Asakusa — ~USD 50–90/night.
- Mid-range (Shinjuku/Shibuya/Ginza): Hotel Sunroute Plaza Shinjuku, Tokyu Stay Ginza — ~USD 120–220/night.
...

[Activities]
5-day Tokyo itinerary — attractions & food (concise)

Day 1 — Shinjuku (arrival, lively night)
- Morning: Check in, stroll Shinjuku Gyoen (park/tea houses).
- Afternoon: Tokyo Metropolitan Government Building observatory (free city view), explore department stores.
- Evening: Omoide Yokocho for yakitori; Golden Gai for tiny themed bars.

Day 2 — Harajuku + Omotesando + Shibuya (youth culture & view)
- Morning: Meiji Jingu shrine and Yoyogi Park.
- Late morning: Takeshita Street (crepes, street fashion) → Omotesando for chic cafés.
...

Day 3 — Asakusa, Ueno, Akihabara (traditional + pop)
- Morning: Senso‑ji temple and Nakamise shopping (street snacks: ningyo‑yaki, melon pan).
- Afternoon: Ueno Park — museums and Ameya‑Yokocho market (takoyaki, grilled seafood).
...
```

### Notes

* This example uses **gllm-pipeline** for orchestrating parallel execution of specialist agents.
* The `parallel()` step automatically runs all branches concurrently for optimal performance.
* Add more specialists by adding more branches to the `parallel()` step.
* The `transform()` step provides a clean way to format and combine outputs while preserving each agent's perspective.
* Unlike the [Aggregator pattern](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/aggregator), this pattern does not synthesize outputs - each agent's response remains distinct.
* To install gllm-pipeline: `uv add gllm-pipeline-binary==0.4.13` (compatible with aip\_agents and langgraph <0.3.x)

### Related Documentation

* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Configure instructions and streaming renderers.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — Capture transcripts or usage metrics in CI workflows.
* [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — Apply tool-output and memory policies when sharing results downstream.


# Router

A central agent inspects each request and routes it to the most appropriate specialist agent based on content and context.

### Overview

Routers keep front-line interactions lightweight: they triage requests, choose which specialist should respond, and optionally provide fallbacks when no match is found. Common use cases include customer support triage and language translation hubs.

### Demo Scenario: Language Help Desk

Four agents collaborate using **gllm-pipeline** with conditional routing:

* **Router agent** – classifies the language query
* **Spanish expert** – handles Spanish translation and explanations
* **Japanese expert** – handles Japanese translation and explanations
* **General handler** – provides fallback for unsupported languages

The pipeline uses the `switch()` step to route queries based on the router's classification, automatically directing each query to the appropriate specialist.

### Diagram

<figure><img src="/files/7yJ9xBlImZCiWoxN4lGS" alt="Router pattern: Router Agent classifies queries and routes to Spanish, Japanese, or General Agent."><figcaption><p>Router pattern — central agent triages requests to the appropriate specialist.</p></figcaption></figure>

### Implementation Steps

1. **Create router and specialist agents**

   ```python
   from glaip_sdk import Agent

   router_agent = Agent(
       name="router_agent",
       instruction="Classify query: spanish | japanese | other",
       model="openai/gpt-5-mini"
   )

   spanish_agent = Agent(
       name="spanish_agent",
       instruction="Spanish language expert...",
       model="openai/gpt-5-mini"
   )

   japanese_agent = Agent(
       name="japanese_agent",
       instruction="Japanese language expert...",
       model="openai/gpt-5-mini"
   )

   general_agent = Agent(
       name="general_agent",
       instruction="Fallback handler...",
       model="openai/gpt-5-mini"
   )
   ```
2. **Build pipeline with switch for conditional routing**

   ```python
   from gllm_pipeline.steps import step, switch

   route_switch = switch(
       condition=lambda s: s["route_label"].strip().lower(),
       branches={
           "spanish": spanish_step,
           "japanese": japanese_step,
           "other": general_step
       },
       default=general_step,
   )

   pipeline = route_step | route_switch
   pipeline.state_type = State
   ```
3. **Process requests**

   ```python
   for query in queries:
       result = await pipeline.invoke(State(user_query=query, ...))
       print(result['final_answer'])
   ```

> **Full implementation:** See `router/main.py` for complete code with State definition and step configuration.
>
> **AgentComponent:** See the [Agent as Component](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/agent-component) guide for details on the `.to_component()` pattern.

### How to Run

From the `router` example directory in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/router):

```bash
uv run main.py
```

Set the usual environment variables in `.env`:

```bash
OPENAI_API_KEY=your-openai-key-here
```

### Output

```
--- Processing Query: How do you say 'hello' in German? ---
Answer: Lo siento — solo puedo ayudar con consultas en español o japonés. No puedo proporcionar
traducciones al alemán.

Si te sirve:
- En español: "hola" (pronunciación aproximada: OH-la).
- En japonés: "こんにちは" (konnichiwa).

¿Quieres más saludos o ayuda con pronunciación en español o japonés?

Demo completed
```

### Notes

* This example uses **gllm-pipeline** with the `switch()` step for conditional routing.
* The router agent outputs a classification label that determines which branch to execute.
* Add more language specialists by adding new agents and branches to the switch.
* The `default` parameter in `switch()` provides a fallback when no branch matches.
* To install gllm-pipeline: `uv add gllm-pipeline-binary==0.4.13` (compatible with aip\_agents and langgraph <0.3.x)

### Related Documentation

* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Configure nested agents, memory, and streaming renderers.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — Log routing results or wire the router into scheduled jobs.
* [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — Apply memory and PII controls when routing sensitive requests.


# Hierarchical

Agents are organized in a tree-like structure, with higher-level agents (supervisors) coordinating specialist agents.

### Overview

Hierarchies shine when you need structured decision flows, explicit quality checks, and clear ownership of each step. Supervisors break work into pieces, delegate to the right specialists, and assemble the final answer.

### Demo Scenario: Multi-Level Research System

This runnable example builds a hierarchical research workflow using **sub-agent delegation**:

1. **Coordinator agent** – manages the research and compilation workflow
2. **Research agent** – performs web searches using the google\_serper tool
3. **Compiler agent** – formats raw findings into a polished summary

The coordinator delegates tasks to research and compiler agents, reviews their outputs, and can make decisions based on their responses. This cyclic decision-making capability is why we use sub-agent delegation instead of gllm-pipeline.

### Diagram

<figure><img src="/files/oBtGczHdtYhkjQG88H4J" alt="Hierarchical pattern: Coordinator Agent delegates to Research Agent and Compiler Agent in a tree structure."><figcaption><p>Hierarchical pattern — supervisor agent delegates tasks to specialist sub-agents.</p></figcaption></figure>

### Implementation Steps

1. **Create specialist agents**

   ```python
   from glaip_sdk import Agent
   from glaip_sdk.tools import Tool

   web_search_tool = Tool.from_native("google_serper")

   research_agent = Agent(
       name="research_agent",
       instruction="Perform web searches and provide comprehensive information...",
       tools=[web_search_tool],
       model="openai/gpt-5.2"
   )

   compiler_agent = Agent(
       name="compiler_agent",
       instruction="Transform raw research into summaries...",
       model="openai/gpt-5.2"
   )
   ```
2. **Create coordinator agent with sub-agents**

   ```python
   coordinator_agent = Agent(
       name="coordinator_agent",
       instruction="""Manage research and compilation tasks.
       Delegate to 'research_agent' to gather information,
       then delegate to 'compiler_agent' to create summaries...""",
       agents=[research_agent, compiler_agent],  # Sub-agent delegation
       model="openai/gpt-5.2"
   )
   ```
3. **Run the coordinator**

   ```python
   result = coordinator_agent.run(
       "Research this topic and provide a compiled summary: [topic]",
       verbose=False
   )
   ```

> **Full implementation:** See `hierarchical/main.py` for complete code with detailed instructions.
>
> **Why sub-agents?** This pattern uses sub-agent delegation (not gllm-pipeline) because the coordinator needs to make decisions based on sub-agent responses and potentially loop back if needed.

### How to Run

From the `hierarchical` example directory in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/hierarchical):

```bash
uv run main.py
```

Ensure your `.env` contains:

```bash
OPENAI_API_KEY=your-openai-key-here
SERPER_API_KEY=your-serper-api-key-here
```

Note: You'll need a [Serper API key](https://serper.dev/) for the google\_serper tool to work.

### Output

```
## 1) GenAI deployments / product & platform updates (found)

### Epic: ongoing EHR-integrated AI positioning and feature direction
- 2025-08-20 — Epic UGM coverage: "Epic touts new AI tools"
  Source: CNBC (Aug 20, 2025)

- 2025-12-12 — Epic blog: "How AI Is Shaping the Patient and Clinician Experience"
  Source: Epic (Dec 12, 2025)

### Microsoft: "agentic AI" + Copilot framing for healthcare innovation
- 2025-11-18 — Microsoft Industry blog: "Agentic AI: Shaping the future of healthcare innovation"
  Source: Microsoft (Nov 18, 2025)

- 2025-12-02 — Microsoft TechCommunity: Ignite 2025 highlights for healthcare
  Source: Microsoft TechCommunity (Dec 2, 2025)

## 2) Regulatory guidance / policy (found; mostly FDA)

### FDA guidance documents found
- 2025-01-06 — FDA: "Considerations for the Use of Artificial Intelligence to Support
  Regulatory Decision Making for Drug and Biological Products"

- 2025-01-07 — FDA Draft Guidance: "Artificial Intelligence-Enabled Device Software Functions:
  Lifecycle Management and Marketing Submission Recommendations"

- 2025-03-25 — FDA topic page: "Artificial Intelligence in Software as a Medical Device (SaMD)"

## 3) Clinical evidence and trials

- 2025-12-23 — TCTMD journalism: "Year in Review: Evidence Around AI in Cardiology Grows"
  Source: TCTMD (Dec 23, 2025)

- 2025-10-28 — Vendor blog: PMcardio "positive RCT results…"
  Source: Powerful Medical blog (Oct 28, 2025)
...

Demo completed
```

### Notes

* This example uses **sub-agent delegation** (not gllm-pipeline) because the coordinator needs to make autonomous decisions based on sub-agent responses.
* Add reviewers or domain specialists by including them in the coordinator's `agents` list.
* The coordinator agent can implement feedback loops, quality checks, and conditional delegation based on sub-agent outputs.
* For linear workflows without decision-making or loops, prefer patterns that use gllm-pipeline (Sequential, Parallel, Router, Aggregator) which leverage the [AgentComponent](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/agent-component) wrapper.
* For iterative optimization with feedback loops, see the [Loop pattern](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/loop).

### Related Documentation

* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Configure nested agents, memory, and runtime overrides.
* [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) — Manage catalog tools such as `web_search`.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — Run hierarchical workflows in CI pipelines.
* [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — Apply tool-output sharing and PII policies across supervisor chains.


# Loop

An iterative optimization pattern where an agent autonomously loops through testing and refinement cycles using sub-agent delegation.

### Overview

The loop pattern is ideal when you need iterative refinement with feedback loops. Unlike linear pipelines, this pattern allows agents to cycle back, test, and improve their output based on execution results. The optimizer agent makes autonomous decisions about when to iterate and when to stop.

### Demo Scenario: Code Optimizer with Feedback Loop

This example demonstrates an autonomous optimization loop using **sub-agent delegation**:

1. **Optimizer agent** – proposes code improvements and decides when to iterate
2. **Executor agent** – runs and benchmarks the code, providing feedback

The optimizer performs an internal loop (up to 3 iterations): it proposes code, delegates execution to the executor agent, analyzes the benchmark results, and refines the approach. This cyclic workflow is why we use sub-agent delegation instead of gllm-pipeline.

### Diagram

<figure><img src="/files/JjUJjCd74l1t5tgnzLSs" alt="Loop pattern: Optimizer Agent delegates to Executor Agent, receives feedback, and iterates."><figcaption><p>Loop pattern — iterative optimization with autonomous feedback cycles.</p></figcaption></figure>

### Implementation Steps

1. **Create executor agent with code execution tool**

   ```python
   from glaip_sdk import Agent
   from glaip_sdk.tools import Tool

   e2b_sandbox_tool = Tool.from_native("e2b_sandbox_tool")

   executor_agent = Agent(
       name="executor_agent",
       instruction="Run code, measure runtime, and return benchmark report...",
       tools=[e2b_sandbox_tool],
       model="openai/gpt-5-mini"
   )
   ```
2. **Create optimizer agent with executor as sub-agent**

   ```python
   optimizer_agent = Agent(
       name="optimizer_agent",
       instruction="""Perform internal loop (up to 3 iterations):
       propose code, delegate to 'executor_agent', analyze results, refine...""",
       agents=[executor_agent],  # Sub-agent delegation
       model="openai/gpt-5-mini"
   )
   ```
3. **Run the optimizer**

   ```python
   result = optimizer_agent.run(prompt, verbose=False)
   ```

> **Full implementation:** See `loop/main.py` for complete code with detailed instructions.
>
> **Why sub-agents?** This pattern uses sub-agent delegation (not gllm-pipeline) because the optimizer needs to make autonomous decisions about looping back based on execution feedback. gllm-pipeline is designed for linear workflows without cyclic control flow.

### How to Run

From the `loop` example directory in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/loop):

```bash
uv run main.py
```

Ensure your `.env` contains:

```bash
OPENAI_API_KEY=your-openai-key-here
E2B_API_KEY=your-e2b-api-key-here
```

Note: You'll need an [E2B API key](https://e2b.dev/) for the code sandbox functionality.

### Output

```
Summary
- Iterations performed: 2
  1) Basic trial-division: correct (78498) but slow (~11.025 s).
  2) Sieve of Eratosthenes: correct (78498) and fast (~0.004887 s).
- Final (selected) runtime: ~0.0049 s (measured in the sandbox).
- Final output: 78498
- Goal satisfied: runtime < 1 s and correct result.

Final minimal Python program (prints 78498 when run):

import math
N = 10**6
s = bytearray(b'\x01') * (N + 1)
s[0:2] = b'\x00\x00'
for p in range(2, math.isqrt(N) + 1):
    if s[p]:
        s[p*p:N+1:p] = b'\x00' * ((N - p*p)//p + 1)
print(s.count(1))

Total iterations in internal loop: 2.

Demo completed
```

### Notes

* This pattern uses **sub-agent delegation** (not gllm-pipeline) because of the cyclic nature of the workflow.
* The optimizer agent autonomously decides when to loop back and when to stop based on the executor's feedback.
* Use this pattern when you need iterative refinement with feedback loops - testing, optimization, validation cycles.
* The maximum iteration count is controlled via the optimizer's instructions, preventing infinite loops.
* For non-cyclic workflows, prefer patterns that use gllm-pipeline (Sequential, Parallel, Router, Aggregator) which leverage the [AgentComponent](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/agent-component) wrapper.

### Related Documentation

* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Configure nested agents and delegation patterns.
* [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) — Manage execution tools like e2b\_sandbox\_tool.
* [Hierarchical pattern](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/hierarchical) — Another pattern using sub-agent delegation for decision-based workflows.
* [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — Apply sandbox and execution policies for code running agents.


# Aggregator

Agents contribute specialized outputs that are collected and synthesized by an aggregator agent into a single, well-formatted result.

### Overview

Reach for this pattern when multiple agents (or tools) produce complementary information and you want a unified summary. Executive briefings, dashboards, and cross-team status reports are common fits.

### Demo Scenario: Daily Briefing Synthesizer

This runnable example assembles a morning briefing by combining three specialists using **gllm-pipeline** for orchestration:

* **Time & calendar agent** – pulls the current time and today's events
* **Weather agent** – reports the local forecast
* **Synthesizer agent** – stitches everything together into a friendly briefing

Specialists run in parallel for faster execution, and their outputs are merged and passed to the synthesizer. Each specialist uses a mock tool that returns static values so the demo works out of the box; swap the tools for real integrations to connect to live data.

### Diagram

<figure><img src="/files/uFBD5IMIWb3pP7BDD5xh" alt="Aggregator pattern: Time Calendar Agent and Weather Agent run in parallel, then Synth Agent synthesizes a unified briefing."><figcaption><p>Aggregator pattern — parallel specialists feed a synthesizer for a unified result.</p></figcaption></figure>

### Implementation Steps

1. **Create specialist agents with tools**

   ```python
   from glaip_sdk import Agent
   from tools.mock_time_tool import MockTimeTool, MockCalendarTool, MockWeatherTool

   time_calendar_agent = Agent(
       name="time_calendar_agent",
       tools=[MockTimeTool, MockCalendarTool],
       model="openai/gpt-5-mini"
   )

   weather_agent = Agent(
       name="weather_agent",
       tools=[MockWeatherTool],
       model="openai/gpt-5-mini"
   )

   synth_agent = Agent(
       name="synth_agent",
       instruction="Synthesize a brief morning briefing...",
       model="openai/gpt-5-mini"
   )
   ```
2. **Build pipeline: parallel specialists → merge → synthesize**

   ```python
   from gllm_pipeline.steps import parallel, step, transform

   pipeline = (
       parallel(branches=[time_calendar_step, weather_step])
       | transform(
           join_partials,
           ["time_text", "weather_text"],
           "partials_text"
       )
       | step(
           component=synth_agent.to_component(),
           input_state_map={"query": "partials_text"},
           output_state="final_answer"
       )
   )
   pipeline.state_type = State
   ```
3. **Run the pipeline**

   ```python
   result = await pipeline.invoke(state)
   print(result['final_answer'])
   ```

> **Full implementation:** See `aggregator/main.py` for complete code with State definition and helper functions.
>
> **AgentComponent:** See the [Agent as Component](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/multi-agent-system-patterns/agent-component) guide for details on the `.to_component()` pattern.

### How to Run

From the `aggregator` example directory in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns/aggregator):

```bash
uv run main.py
```

Ensure your `.env` contains:

```bash
OPENAI_API_KEY=your-openai-key-here
```

### Output

```
Daily Briefing:
Good morning — it's 10:00 AM WIB, 15 Jan 2026. Quick briefing:

Top time-sensitive items
- Development team meeting at 2:00 PM WIB (starts in ~4 hours).
  - Suggestions: finalize agenda and key updates now, send any pre-read by 1:00 PM,
    and set reminders at 30 and 10 minutes before start.
  - If you're presenting: confirm slides, test screen-sharing and audio 15–20 minutes
    before the meeting.

Weather & travel
- Partly cloudy, ~72°F (22°C). Rain expected at 3:00 PM WIB (during/just after the meeting).
  - Suggestions: bring an umbrella or light waterproof jacket; if you commute around that
    time, leave a bit earlier to avoid wet delays.
...

Quick action checklist (next few hours)
- 10:00–12:00: polish agenda, compile blockers/metrics, prepare slides.
- 12:00–13:00: send pre-read and confirm attendees.
- 1:40–1:50 PM: tech check (or arrive on site).
- 2:00 PM: meeting.
```

### Notes

* This example uses **gllm-pipeline** for orchestrating the multi-agent workflow with parallel execution.
* Replace the mock tool scripts under `aggregator/tools/` with real integrations to connect to live systems.
* Add more specialists (finance, news, incidents) by adding more branches to the `parallel()` step.
* Combine this pattern with a router or scheduler for automated briefings.
* To install gllm-pipeline: `uv add gllm-pipeline-binary==0.4.13` (compatible with aip\_agents and langgraph <0.3.x)

### Related Documentation

* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Configure agent instructions and manage lifecycles.
* [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) — Upload Python tools and reference their IDs.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — Schedule or orchestrate the aggregator run in CI.
* [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — Apply PII masking or output-sharing policies when aggregating data.


# Agent Component

In modular AI systems, the **Pipeline** serves as the core orchestration component, managing the execution of modular units called **Components**. While a Pipeline manages structured data flow (retrieval results, metadata, and state), an **Agent** typically operates on natural language instructions.

The `AgentComponent` standardizes this interaction by wrapping a GL Agent into a basic executable unit. It compiles structured pipeline state into a cohesive prompt, allowing Agents to be seamlessly orchestrated alongside other components.

***

### The `to_component()` Pattern

To simplify integration, any `Agent` instance can be converted into a reusable `Component` using the built-in `.to_component()` method. This abstraction ensures that the Pipeline can treat the Agent as a uniform executable unit, regardless of its underlying reasoning engine.

```python
from glaip_sdk import Agent

# 1. Initialize your agent
my_agent = Agent(
    name="Researcher",
    instruction="You are a research assistant."
)

# 2. Convert to a Component
# This returns an AgentComponent instance
agent_component = my_agent.to_component()
```

***

### Pipeline Integration

Once converted, the Agent becomes a standard building block that can be inserted into any `gllm-pipeline` step. The component automatically handles the mapping between the pipeline's **State** and the agent's **Prompt**.

#### Supported Input Mapping

The `AgentComponent` exposes a standardized interface for common orchestration needs:

| Argument         | Type                     | Description                                                                       |
| ---------------- | ------------------------ | --------------------------------------------------------------------------------- |
| `query`          | `str`                    | The primary user question or instruction.                                         |
| `context`        | `list[Chunk\|str\|dict]` | Background data (e.g., retrieval results). Automatically formats `Chunk` objects. |
| `chat_history`   | `list[Message\|dict]`    | Prior conversation turns. Supports `Message` objects and raw dictionaries.        |
| `runtime_config` | `dict`                   | Execution-time overrides (e.g., planning, tool settings).                         |
| `run_kwargs`     | `dict`                   | Payload for advanced agent execution parameters (e.g., `local: True`).            |

#### Advanced Execution Control

The `AgentComponent` supports fine-grained control over execution, allowing you to switch between local and remote runners or pass runtime-specific execution parameters dynamically through the pipeline state.

**Local Execution**

To force a pipeline step to run locally, pass `local: True` inside the `run_kwargs` payload:

```python
# state['params'] = {"local": True}
agent_step = step(
    component=my_agent.to_component(),
    input_state_map={
        "query": "user_query",
        "run_kwargs": "params"
    },
    output_state="answer"
)
```

**Robust Argument Passthrough**

Any key provided in the `run_kwargs` dictionary is passed directly to the underlying `agent.run()` call. This is useful for passing per-step configuration that should not be baked into the agent's static definition.

#### Example Workflow

```python
from gllm_pipeline.pipeline import Pipeline
from gllm_pipeline.steps import step

# Define the pipeline step
# mapping shared state keys ('user_query', 'docs') to component arguments
agent_step = step(
    component=my_agent.to_component(),
    input_state_map={
        "query": "user_query",
        "context": "retrieved_docs",
        "chat_history": "history"
    },
    output_state="agent_answer"
)

pipeline = Pipeline(steps=[agent_step], state_type=MyState)
```

***

### How Prompt Compilation Works

The `AgentComponent` follows the GLLM Core standard of encapsulating business logic. During execution, it automatically transforms heterogeneous inputs into a structured prompt:

1. **Conversation History**: Formats messages into a readable dialogue (e.g., "User: ... \n Assistant: ...").
2. **Relevant Context**: flattens background data into a clear reference list.
3. **User Query**: Positions the primary instruction at the end of the prompt for optimal model attention.

This ensures that the Agent receives all necessary state in a format optimized for reasoning, without bloating the Pipeline definition with string manipulation logic.

***

### Installation

The `AgentComponent` is enabled via the `pipeline` extra:

```bash
pip install glaip-sdk[pipeline]
```


# Hands-on Examples

Use these examples after [Quick Start](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/quick-start-guide) to explore real scenarios with runnable code and CLI commands.

> **Success**
>
> **When to use this page:** You are ready for richer workflows and want copy-and-run snippets instead of building from scratch.

{% hint style="info" %}
**Audience:** Engineers prototyping orchestration, PMs preparing demos, and data developers running evaluations without coding.
{% endhint %}

{% hint style="info" %}
**TUI Development**: Many examples below demonstrate Textual-based TUI patterns. For comprehensive TUI guidance, refer to the TUI foundation spec in the repository.
{% endhint %}

{% hint style="info" %}
**Note:** Validated example projects are now centralized in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main). This ensures all blueprints remain self-contained, runnable, and maintained with the latest SDK best practices.
{% endhint %}

Each row links to a runnable project. Follow the README for quick start instructions, then inspect code to understand the pattern.

### Validated Example Projects

These projects demonstrate foundational patterns and are maintained in the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main). Each project is self-contained and ready to run.

| Pattern                       | Description                                                                                                                                                            | Project Link                                                                                                           |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Basic Agent (Hello World)** | A minimal starter demonstrating how to create and run an agent using config-based instantiation.                                                                       | [hello-world](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/hello-world)                           |
| **Modular Tool Integration**  | Learn how to organize complex tools with separate helper files and modular structure.                                                                                  | [modular-tool-integration](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/modular-tool-integration) |
| **Multi-Agent Coordinator**   | Coordinator with specialized sub-agents (e.g., formal and casual greeting team).                                                                                       | [multi-agent](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent)                           |
| **Multi-Agent Patterns**      | Runnable blueprints for Sequential, Parallel, Router, Hierarchical, and Aggregator flows.                                                                              | [multi-agent-patterns](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/multi-agent-system-patterns)  |
| **Runtime Configuration**     | How to pass per-request overrides for agents, tools, and MCPs at runtime (e.g., database URLs or planning).                                                            | [runtime-config](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/runtime-config)                     |
| **Agent Export & Import**     | Demonstrates how to serialize and deserialize agent configurations for portability.                                                                                    | [export-import](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/agent-export-import)                 |
| **Local Execution**           | Run agents locally without deployment (see [Local vs Remote](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/getting-started/local-vs-remote) for feature mapping). | [hello-world-local](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main/examples/hello-world-local)               |

***

### Cookbook Examples

For quick copy-and-run recipes, use the dedicated [Cookbook repository](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main).


# Resources

Use these companion documents to track changes, clarify terminology, and plan upgrades across AIP deployments. The SDK is the default interface; REST pages are reference-only.

### Stay Current

| Resource                                                                                      | Purpose                                                         |
| --------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| [Upgrade Guides](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/upgrade-guides) | Step-by-step help when moving between platform or SDK versions. |
| [Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main)                          | Runnable examples and implementation-level recipes.             |

### Reference Material

| Resource                                                                          | Purpose                                                        |
| --------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| [Glossary](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/glossary) | Definitions for AIP-specific concepts, payloads, and acronyms. |

### Related Sections

* Consult the [Overview](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/introduction-to-gl-aip) for a full capability map and links to all guides.
* Use the [CLI section](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/cli) for interactive ops workflows and transcript capture.
* Visit the [Reference section](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference) for API and command details when you need exact request/response formats.


# Upgrade Guides

Use this checklist whenever you bump GL AIP or deploy a new version of the platform.

> **Success**
>
> **When to use this guide:** Plan upgrades, communicate timelines, or document migrations between AIP releases.
>
> **Who benefits:** Release managers, platform engineers, and PMs coordinating customer rollouts.

For the latest release notes and migration deltas, follow your GL AIP platform release channel. For runnable implementation examples during migrations, use the [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main).

***

### Quick Checklist

1. **Review release notes** – capture breaking changes or behavioural updates.
2. **Export state** – back up agents, tools, and MCP configs as JSON/YAML if you manage them manually.
3. **Update the SDK/CLI** – on each machine or runner execute `aip update` (use `--check-only` to verify availability or `--force` to reinstall).
4. **Smoke test**
   * `aip status`
   * representative `aip agents run` / `aip tools get` commands
   * `client.ping()` from a Python shell
5. **Deploy backend changes** (if applicable) – pull the corresponding AIP release and restart services.
6. **Verify MCP and tool integrations** – run one workflow that exercises each connector you depend on.
7. **Communicate** – note the versions installed and any follow-up tasks (e.g., feature flag toggles, configuration updates).

***

### Tips

* Keep a copy of exported agent/tool JSON in version control; it simplifies rollback and lets you diff changes across upgrades.
* Automate `aip update` via CI jobs so runners stay in sync with PyPI releases.
* When the REST API introduces new endpoints or payloads, the [REST API Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/README) is updated automatically and should be consulted for schema details.

Future breaking changes will re-use this page—add concise “Before / After” code snippets when they land so the checklist stays actionable.

### Related playbooks

* [Configuration management guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/configuration-management) — Export/import workflows for pre- and post-upgrade backups.
* [Automation & scripting](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/automation-and-scripting) — Schedule `aip update` checks and regression runs.
* [Agents guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Validate run history and streaming behaviour after upgrades.
* [Security & privacy](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/security-and-privacy) — Confirm PII mappings and token scopes did not regress.


# Glossary

Key concepts and terminology used throughout the GL AIP package and its Python SDK.

### A

**Agent** – A configured AI worker that executes instructions, invokes tools, processes attached files, and produces responses. Agents are stored per account and exposed via `/agents`.

**Agent Config** – Structured settings that tune an agent’s behaviour at rest and runtime (memory backend, tool-output sharing, temperature overrides, etc.). Persisted under `agent_config` in agent records and extended dynamically via `runtime_config` during runs.

**Agent Run** – A single execution of an agent triggered via the REST API, SDK, or CLI. Runs can stream Server-Sent Events (SSE) and optionally attach files.

### B

**GL Connectors** – A curated set of tools packaged by GDP Labs that connect agents to third-party services (e.g., GitHub, Google Workspace, HR systems). GL Connectors appear with `gl_connector_` prefixes in `/tools` listings.

### C

**CLI (`aip`)** – The command-line interface bundled with the SDK. Provides commands for managing agents, tools, MCPs, language models, and configuration. Supports Rich output (default), JSON (`--view json`), and Markdown.

### L

**LangFlow Sync** – A synchronisation endpoint (`POST /agents/langflow/sync`) that imports LangFlow flows into AIP agents. Exposed via `client.sync_langflow_agents` and `aip agents sync-langflow`.

### M

**Memory Scope** – Identifier used by the `mem0` backend to persist conversation state across runs. Controlled through `agent_config.memory` and `agent_config.agent_id`.

**MCP (Model Context Protocol)** – A protocol allowing agents to interact with external systems. MCP configurations live under `/mcps` and can be overridden at runtime via `runtime_config.mcp_configs`.

### P

**PII Mapping** – A dictionary mapping placeholders (e.g., `<EMAIL_1>`) to actual sensitive values. Passed during runs so secrets remain client-side while the backend receives fully resolved inputs.

### R

**Runtime Config** – A payload supplied with `POST /agents/{id}/run` that applies in-memory adjustments for a single execution (tool-specific overrides, MCP credentials, agent settings per delegate).

### T

**Tool** – A reusable capability (custom or native) that agents can invoke. Tools are uploaded via `/tools/upload`, and each stores metadata, optional configuration schemas, and versioning information.

**Tool Config** – Structured parameters stored alongside an agent to customise a tool’s behaviour (e.g., chart format, API mode). Not to be confused with `runtime_config.tool_configs`, which applies per run.

### W

**Workspace (Account)** – A logical tenant boundary. API keys, agents, tools, and schedules are scoped per account. Master keys bypass scoping for operator workflows.


# Agent Catalogue

Browse built-in specialist agents and planned agents.

### Available Agents

| Agent Name                     | Agent Description                                                                                                                 | Remarks / Notes                                                                   |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| Browser Use Agent              | Executes end-to-end web automation: navigate sites, fill forms, click actions, extract content, and summarize results.            | Requires Steel account/integration for browser sessions.                          |
| Code Interpreter Agent         | Processes natural-language analysis tasks and direct code snippets in a secure sandbox, including visualization and file outputs. | Requires E2B account/integration.                                                 |
| Data Analysis Agent            | Performs SQL-backed analysis, generates visualizations, and produces formatted insights.                                          | Requires database configuration.                                                  |
| SQL Query Agent                | Handles SQL query generation and related data retrieval flows.                                                                    | Requires database configuration.                                                  |
| Pandas Data Processing Agent   | Processes and transforms data with pandas for analysis/aggregation.                                                               | Internal availability can vary by environment.                                    |
| Table Generation Agent         | Generates formatted tables from analysis outputs.                                                                                 | Internal availability can vary by environment.                                    |
| Graph Generation Agent         | Produces visual charts from analysis outputs.                                                                                     | Can often be substituted by Code Interpreter Agent.                               |
| Research Agent                 | Coordinator agent for research and communication workflows.                                                                       | Internal availability can vary by environment.                                    |
| Research Compiler Agent        | Performs web research and document workflows (for example Google Docs), and can integrate with email delivery flows.              | Requires search + connector integrations (for example Serper, Google connectors). |
| Email Assistant Agent          | Reads and sends email via connector-backed integrations.                                                                          | Requires email connector configuration.                                           |
| GitHub Agent                   | Provides cross-repository insights across PRs, issues, commits, and metadata.                                                     | Requires GitHub integration for full access.                                      |
| GitHub Commits Agent           | Specialized analysis over repository commit histories.                                                                            | Requires GitHub integration/key setup.                                            |
| GitHub Contributions Agent     | Specialized contributor-activity analysis across repositories.                                                                    | Requires GitHub integration/key setup.                                            |
| GitHub Issues Agent            | Specialized issue analysis across repositories.                                                                                   | Requires GitHub integration/key setup.                                            |
| GitHub Projects Agent          | Specialized analysis for GitHub Projects and project items.                                                                       | Requires GitHub integration/key setup.                                            |
| GitHub PRs Agent               | Specialized pull-request analysis across repositories.                                                                            | Requires GitHub integration/key setup.                                            |
| Calendly Agent                 | Finds availability and assists meeting setup workflows.                                                                           | Requires calendar MCP/integration setup.                                          |
| Data Analysis RAG Agent        | Combines SQL analysis, charting, and vector retrieval in one flow.                                                                | Requires SQL and vector DB connector configuration.                               |
| Meemo Chat Agent               | Answers questions from meeting transcription context.                                                                             | Internal availability can vary by environment.                                    |
| GitBook Agent                  | Answers questions grounded on connected GitBook content.                                                                          | Requires MCP GitBook connection.                                                  |
| Report Automation Sync Agent   | Syncs report configuration from Google Sheets to deployed agents and schedules.                                                   | Internal availability can vary by environment.                                    |
| \[SS v2] GitHub Agent          | Smart Search connector for GitHub search workflows.                                                                               | Requires Smart Search integration.                                                |
| \[SS v2] Google Calendar Agent | Smart Search connector for Google Calendar search workflows.                                                                      | Requires Smart Search integration.                                                |
| \[SS v2] Google Drive Agent    | Smart Search connector for Google Drive search workflows.                                                                         | Requires Smart Search integration.                                                |
| \[SS v2] Google Mail Agent     | Smart Search connector for Google Mail search workflows.                                                                          | Requires Smart Search integration.                                                |
| Release Notes Beautifier Agent | Beautifies release-note draft content from GitHub title + "What's Changed" PR list.                                               | Internal availability can vary by environment.                                    |

### Upcoming Agents

| Agent Name                         | Agent Description                                                                                                      | Remarks / Notes   |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ----------------- |
| Observability Agent                | Correlates Sentry traces, ELK logs, and Prometheus metrics for unified root-cause analysis and action recommendations. | On-trial mode     |
| ELK Log Retrieval Agent            | Retrieves logs from ELK sources.                                                                                       | On-trial mode     |
| Sentry Traces Retriever Agent      | Retrieves traces from Sentry sources.                                                                                  | On-trial mode     |
| Prometheus Metrics Retrieval Agent | Retrieves metrics from Prometheus sources.                                                                             | On-trial mode     |
| Data Crawling Agent                | Crawls data from internet sources.                                                                                     | Planned (Q1 2026) |
| RegTech Agent                      | Extracts/summarizes regulation documents and supports compliance comparison workflows.                                 | Planned (Q1 2026) |
| PR Code Review Agent               | Analyzes PR quality/activity metrics (for example merge duration, comment volume, change size).                        | Planned (Q1 2026) |

### Related Pages

* [Browser Use Agent](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/agent-catalogue/browser-use-agent)
* [Code Interpreter Agent](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/agent-catalogue/code-interpreter-agent)
* [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools)


# Browser Use Agent

### Overview

The Browser Use Agent enables AI agents to interact with websites automatically. It can navigate pages, fill forms, extract data, and handle complex scenarios like CAPTCHAs and logins with human assistance when needed.

### Execution Flow & Architecture

#### Process Flow Diagram

```mermaid
sequenceDiagram
    participant User
    participant Agent
    participant BrowserUse Tool
    participant Live Browser
    participant LLM

    User->>Agent: Submit Web Task
    Agent->>BrowserUse Tool: Execute Task

    BrowserUse Tool->>Live Browser: Create Browser Session
    Live Browser-->>BrowserUse Tool: Live Browser URL
    BrowserUse Tool-->>User: Live Browser URL (for monitoring/intervention)

    loop Step-by-Step Execution
        BrowserUse Tool->>LLM: Plan Next Action
        LLM-->>BrowserUse Tool: Action Plan

        BrowserUse Tool->>Live Browser: Execute Action (click, type, navigate)
        Live Browser-->>BrowserUse Tool: Result + Page State

        BrowserUse Tool-->>User: Progress Update (if streaming enabled)

        alt Human Help Needed (CAPTCHA/Login)
            User->>Live Browser: Open Live URL & Complete Manually
            Note over BrowserUse Tool: Agent continues, may detect changes
            BrowserUse Tool->>Live Browser: Execute Next Step
            Live Browser-->>BrowserUse Tool: Updated Page State
        end
    end

    BrowserUse Tool-->>User: Final Result
```

#### Workflow Explanation

1. **Task Submission**: You provide a web automation task (e.g., "Search for jobs on LinkedIn")
2. **Browser Session Creation**: The agent creates an isolated browser session and provides you with a live browser URL
3. **Step-by-Step Execution**: The agent plans and executes actions one by one:
   1. Analyzes the current page
   2. Decides what to do next (click button, fill form, navigate)
   3. Executes the action
   4. Reports progress
4. **Human Assistance**: When the agent encounters challenges like CAPTCHAs or login prompts, you can help by opening the live browser URL and completing them manually
5. **Result Delivery**: The agent returns the final results (extracted data, completion status, etc.)

***

### Human-in-the-Loop Mechanisms

The Browser Use Agent handles challenging web scenarios through intelligent automation and optional human assistance.

#### How It Handles CAPTCHAs and Logins

**Automatic Attempts:** The agent tries to handle challenges automatically using its built-in instructions:

1. **CAPTCHAs**: Attempts to solve them when possible; uses alternative strategies if blocked
2. **Logins**: Only attempts login if credentials are provided or explicitly required
3. **Stuck Situations**: Re-evaluates the task and tries different approaches

**When You Need to Help:** Sometimes the agent needs human assistance for complex challenges:

1. **Agent encounters a challenge** (CAPTCHA, login prompt, etc.) during execution
2. **Live browser URL is available** - You receive a URL that shows the current browser session in real-time
3. **You open the URL** and manually complete the challenge (solve CAPTCHA, enter login credentials, etc.)
4. **Agent continues** - The agent proceeds with its next step independently (it doesn't wait for you)
5. **Task continues** - When the agent executes its next step, it may detect that you've completed the challenge and continue with the updated page state (this detection is automatic but not guaranteed)

**Important Points:**

1. The agent doesn't pause or wait for you - it continues executing steps independently
2. You can help at any time by opening the live browser URL
3. The agent may detect your changes when it executes its next step (this is automatic, not guaranteed)
4. There's no explicit pause/resume - you're helping in parallel with the agent's execution

#### Example Scenario: Job Board Search

**Task**: "Search for software engineer jobs on a job board and extract the first 5 listings"

**What Happens:**

1. Agent navigates to the job board website
2. Agent encounters a CAPTCHA during search
3. You receive a live browser URL
4. You open the URL and solve the CAPTCHA manually
5. Agent continues searching and extracts job listings
6. Agent returns the results

**If Login is Required:**

1. If no credentials are provided, the agent skips login (per its instructions)
2. If login is necessary, you can complete it via the live browser URL
3. The agent then continues with the task

#### Recovery Strategies

When the agent gets stuck or encounters errors:

1. **Automatic Retry**: The agent tries alternative approaches automatically
2. **Session Recovery**: If the browser connection is lost, the agent recreates the session and continues
3. **State Preservation**: Your manual changes (like completing a CAPTCHA) are typically preserved in the browser session, and the agent may detect them when it executes its next step

***

### How It Works

#### Browser Automation Process

**Step-by-Step Execution:**

1. The agent analyzes the current webpage
2. It plans the next action using AI reasoning
3. It executes the action (click, type, navigate, extract data)
4. It checks the result and plans the next step
5. This continues until the task is complete

**Real-Time Updates:**

1. You receive progress updates showing what the agent is doing
2. You can see the agent's "thinking" process
3. A live browser URL lets you watch or intervene if needed

**Session Recording:**

1. Optionally records a video of the entire browser session
2. Useful for debugging or reviewing what happened
3. Available after task completion

#### Error Handling

**Automatic Recovery:**

1. If the browser disconnects, the agent automatically recreates the session
2. If an action fails, the agent tries alternative approaches
3. Configurable retry limits prevent infinite loops

**Common Issues:**

1. **CAPTCHA/Login Blocks**: Use the live browser URL to complete manually
2. **Element Not Found**: Agent waits, refreshes, or tries alternative selectors
3. **Session Disconnects**: Automatic retry with session recreation

***

### Sample Usage

#### Basic Web Automation

**Using via SDK:**

```python
from glaip_sdk import Client

client = Client()
agent = client.agents.find_agents("browser_use_agent")[0]

# Simple task
result = agent.run("Go to example.com and extract the main heading")
print(result)
```

**Example Output:**

```
The agent navigated to example.com and extracted: "Example Domain"
```

#### Task Requiring Human Assistance

```python
from glaip_sdk import Client

client = Client()
agent = client.agents.find_agents("browser_use_agent")[0]

# Complex task that may require CAPTCHA/login handling
result = agent.run("""
    Navigate to a job board, search for 'software engineer' positions,
    filter by remote work, and extract the first 5 job listings with
    company names and salaries.
""")

# If CAPTCHA appears, you'll receive a live browser URL as a status update
# Open it, complete the CAPTCHA, and the agent may detect the change on its next step
```

**What to Expect:**

1. Agent starts executing the task
2. If a CAPTCHA appears, you receive a live browser URL as a status update
3. Open the URL, solve the CAPTCHA
4. Agent continues with its next step and might detect your changes when it executes the next action
5. Final results are returned with the job listings

#### Configuring Timeouts

You can configure timeout settings to match your task requirements:

```python
from glaip_sdk import Client

client = Client()
agent = client.agents.find_agents("browser_use_agent")[0]

# Configure timeouts for longer tasks via runtime_config
runtime_config = {
    "tool_configs": {
        "browser_use_tool": {
            "steel_timeout_in_ms": 900_000,  # 15 minutes (matches Steel Hobby plan max)
            "browser_use_llm_timeout_in_s": 120,  # 2 minutes for LLM responses
            "browser_use_step_timeout_in_s": 300,  # 5 minutes per step
        }
    }
}

# Use the configured agent with custom timeouts
result = agent.run("Your task here", runtime_config=runtime_config)
```

***

### Capabilities & Limitations

#### Known Capabilities

The Browser Use Agent excels at a wide range of web automation tasks:

1. **Web Navigation & Form Filling**
   1. **Use Case**: Automatically fill out contact forms, registration pages, or search forms
   2. **Example Task**: "Go to <https://duckduckgo.com>, search for 'Python web automation', and extract the titles of the first 5 search results"
2. **Data Extraction & Collection**
   1. **Use Case**: Gather information from multiple pages or websites
   2. **Example Task**: "Navigate to <https://en.wikipedia.org/wiki/Python\\_(programming\\_language)> and extract the first paragraph"
3. **Multi-Step Task Automation**
   1. **Use Case**: Complete complex workflows that require multiple sequential actions
   2. **Example Task**: "Go to <https://www.python.org>, navigate to the documentation section, find the 'Tutorial' page, and extract the main topics covered"
4. **Scrolling & Pagination**
   1. **Use Case**: Navigate through long pages or multiple pages of results
   2. **Example Task**: "Go to <https://en.wikipedia.org/wiki/Python\\_(programming\\_language)> and scroll down past the introduction section"
5. **Multi-Tab Operations**
   1. **Use Case**: Open multiple tabs for research or parallel information gathering
   2. **Example Task**: "Open <https://www.python.org>, open the documentation section in a new tab, then extract the main heading from each page"

#### Known Limitations

While powerful, the Browser Use Agent has some limitations:

1. **CAPTCHAs in Iframes**
   1. **Limitation**: CAPTCHAs embedded in iframes are difficult to solve automatically
   2. **Example Scenario**: A login page with a CAPTCHA widget loaded in an iframe may require manual intervention
   3. **Workaround**: Use the live browser URL to complete CAPTCHAs manually when needed
2. **Login Without Credentials**
   1. **Limitation**: The agent skips login attempts if no credentials are provided (by design for security)
   2. **Example Scenario**: Task requires accessing a protected area but no login credentials are available
   3. **Workaround**: Provide credentials in the task description or complete login manually via the live browser URL
3. **Timeouts & Limits**
   1. **Limitation**: Several timeout and limit constraints may affect task execution:
      1. **Task Length**: Tasks requiring more than 100 steps may face memory constraints. This is a practical limitation based on observed memory usage patterns, not a hard limit enforced by the tool. The browser-use framework roadmap includes plans to improve agent memory handling for longer tasks.
      2. **Timeout Settings**: Three configurable timeout settings limit task duration (all configurable via `BrowserUseToolConfig`):
         1. **Steel Session API Timeout**: Default 600 seconds (10 minutes) - controls how long the Steel session can remain active (`steel_timeout_in_ms`)
         2. **Browser Use Agent LLM Timeout**: Default 60 seconds - controls how long the LLM has to respond for each planning step (`browser_use_llm_timeout_in_s`)
         3. **Browser Use Agent Step Timeout**: Default 180 seconds (3 minutes) - controls how long each agent step can take (`browser_use_step_timeout_in_s`)
      3. **Network Latency**: Due to geographic distance between Browser Use deployment (South East Asia) and Steel servers (United States), network latency can cause timeout scenarios during rapid interactions
      4. **Steel Hobby Plan Limits**: Browser Use currently uses Steel's free Hobby plan with the following limits (note: these limits are subject to change if we upgrade to a paid Steel plan):
         1. **Max Session Time**: 15 minutes per browser session
         2. **Daily Requests**: 500 requests per day
         3. **Requests per Second**: 1 request per second rate limit
         4. **Concurrent Sessions**: Maximum 5 concurrent browser sessions
         5. **Data Retention**: Session data retained for 24 hours
   2. **Example Scenario**: Long-running tasks exceeding 15 minutes will be terminated, rapid interactions may timeout due to network latency, or hitting daily request limits will prevent new sessions
   3. **Workaround**: Break large tasks into smaller subtasks under 15 minutes, use the file system to track progress across multiple runs, configure timeout values if needed, or upgrade to a paid Steel plan for higher limits (see [Steel Pricing](https://docs.steel.dev/overview/pricinglimits))
4. **Cross-Origin Iframe Interactions**
   1. **Limitation**: Interacting with elements inside cross-origin iframes can be unreliable
   2. **Example Scenario**: A payment form embedded in an iframe from a different domain
   3. **Workaround**: Manual intervention via live browser URL for critical iframe interactions
5. **Sequential Execution**
   1. **Limitation**: Tasks execute sequentially, not in parallel
   2. **Example Scenario**: Applying to 50 different job postings must be done one at a time
   3. **Workaround**: For parallel tasks, run multiple agent instances or break into batches
6. **UI Element Detection**
   1. **Limitation**: Some dynamically loaded or custom UI elements may not be immediately detected
   2. **Example Scenario**: A custom dropdown menu that loads content via JavaScript after a delay
   3. **Workaround**: The agent will wait and retry, or you can use the live browser URL to verify element visibility
7. **Real-Time Interactive Elements**
   1. **Limitation**: Elements that require real-time human interaction (like drag-and-drop) may be challenging
   2. **Example Scenario**: A complex image editor with drag-and-drop functionality
   3. **Workaround**: Use manual intervention via live browser URL for complex interactions
8. **Elements with Mouse Events**
   1. **Limitation**: Elements that rely on mouse event handlers (such as `mousedown`, `mouseup`, `mouseover`, etc.) instead of standard `click` events may not respond correctly to agent interactions
   2. **Example Scenario**: A custom button or interactive element that only triggers actions on mouse events (common in some JavaScript frameworks or custom UI libraries)
   3. **Workaround**: Use manual intervention via live browser URL to interact with such elements, or contact support if this is a critical requirement
9. **Token Consumption**
   1. **Limitation**: Very large pages with extensive DOM content can consume significant tokens
   2. **Example Scenario**: A single-page application with thousands of interactive elements
   3. **Workaround**: Configure vision detail levels (auto/low/high) to optimize token usage

***

### Technical Details

#### Browser Sessions

The agent uses isolated browser sessions that:

1. Run in secure, isolated environments
2. Automatically clean up after task completion
3. Support real-time monitoring via live browser URLs

#### AI Models

The agent uses two AI models:

1. **Primary Model**: Plans actions and makes decisions
2. **Secondary Model**: Extracts structured data from web pages

Both models work together to understand pages and execute tasks effectively.

#### Streaming Events

The agent provides real-time updates through streaming events:

1. **Status Updates**: Progress notifications, session initialization
2. **Step Results**: Action execution results with thinking process
3. **Live Browser URL**: You'll receive the live browser URL as a status update early in execution, allowing you to monitor or intervene if needed

#### Security

**Isolation:**

1. Each browser session is isolated from others
2. No data persists between tasks
3. API keys are loaded from environment variables (never hardcoded)

**Safety:**

1. Actions are validated before execution (enforced by the browser-use framework)
2. Error messages are sanitized
3. Logging available for monitoring

***

### Performance & Troubleshooting

**Efficiency:**

1. Configurable vision detail levels (auto/low/high) for faster processing
2. Background video recording doesn't slow down execution
3. Automatic resource cleanup

**Common Issues:**

| Issue                | Solution                                            |
| -------------------- | --------------------------------------------------- |
| CAPTCHA/Login blocks | Use the live browser URL to complete manually       |
| Session disconnects  | Automatic retry - agent recreates session           |
| Element not found    | Agent waits and retries with alternative approaches |
| Task stuck           | Agent re-evaluates and tries different strategies   |

**Debug Resources:**

1. Live browser URLs for real-time monitoring
2. Video recordings (if enabled) for reviewing sessions
3. Action logs showing what the agent did
4. AI reasoning traces showing decision-making process


# Code Interpreter Agent

### Execution Flow & Architecture

#### Process Flow Diagram

```mermaid
sequenceDiagram
    participant User
    participant Agent
    participant Code Sandbox Tool

    User->>Agent: Submit Query (NL or Raw Code)
    Agent->>Agent: Input Detection
    Agent->>Agent: Code Preparation
    Agent->>Code Sandbox Tool: Execute Code (code, language, timeout, packages)
    Code Sandbox Tool->>Code Sandbox Tool: Initialize Sandbox & Install Packages
    Code Sandbox Tool->>Code Sandbox Tool: Execute Code
    Code Sandbox Tool-->>Agent: Return Result (stdout, stderr, status, artifacts)
    alt Error Detected
        Agent->>Agent: Analyze & Modify Code
        Agent->>Code Sandbox Tool: Re-execute (max 5 attempts)
    end
    Agent->>Agent: Format Results
    Agent->>User: Return Output
```

#### Workflow Explanation

1. **Input Detection**: Detects if input is natural language (generates code) or raw code (executes as-is). Identifies language (Python default, or JS/TS/R/Java)
2. **Code Preparation**: Adds imports, installs packages dynamically, includes error handling and save commands for artifacts
3. **Secure Execution**: Runs in sandbox. On error: analyzes -> modifies -> re-executes (max 5 attempts). Blocks dangerous operations
4. **Result Formatting**: Returns final code only (hides iterations), formatted results, and embedded artifacts

***

### Detailed Mechanisms

#### Code Execution Mechanism

**How Code is Executed:**

1. **Agent calls the E2B Sandbox Tool** with parameters:
   * `code`: The Python/JS/TS/R/Java code to execute
   * `language`: Target programming language (default: Python)
   * `timeout`: Maximum execution time in seconds (default: 30s, max: 300s)
   * `additional_packages`: Optional packages to install before execution
2. **Sandbox Initialization**: E2B Cloud Sandbox creates isolated environment with specified language runtime
3. **Package Installation**: Installs required packages dynamically within the sandbox
4. **Code Execution**: Runs code in isolated environment with resource monitoring
5. **Result Collection & Response**: Captures execution details and returns structured response:

   ```json
   {
     "status": "success/error",
     "code": "executed code",
     "stdout": "standard output",
     "stderr": "standard error",
     "error": "error message if any",
     "duration_ms": "execution time",
     "artifacts": ["generated files"]
   }
   ```

#### Language Support

1. **Supported Languages**: Python (default), JavaScript, TypeScript, R, Java
2. **Extensible**: Additional languages can be installed dynamically based on user requirements or query needs

#### Security Mechanisms

| Layer                | Protection                                                               |
| -------------------- | ------------------------------------------------------------------------ |
| Execution Boundaries | Isolated sandbox; no system commands; max 5 iterations; reject eval/exec |
| Resource Protection  | Memory monitoring; computation limits; output truncation                 |
| Code Validation      | Block harmful operations; sanitize errors; prevent system info exposure  |

#### Iterative Error Recovery

1. **Error Detection**: Captures exceptions, syntax errors, runtime failures
2. **Error Analysis**: Parses messages, identifies root causes
3. **Code Modification**: Adjusts imports, fixes syntax, installs packages
4. **Re-execution**: Runs modified code (max 5 attempts)
5. **Clean Presentation**: Only final successful code shown to users

**Example**: Missing matplotlib -> agent installs it automatically -> re-executes -> user sees only working result.

#### Artifacts

1. **Visualization Generation**: Charts, graphs, plots, heatmaps saved as PNG/JPG/SVG and embedded in markdown
2. **File Generation**: CSV exports, JSON data, reports, processed files

***

### Sample Code

#### Using Code Interpreter Agent via SDK

```python
from glaip_sdk import Client

client = Client()

agent = client.agents.find_agents("code_interpreter_agent")[0]
print(agent.run("Generate 5x5 chessboard"))
```

**Output:**

**Executed Code:**

```python
import matplotlib.pyplot as plt
import numpy as np

# Create a 5x5 chessboard pattern
chessboard = np.zeros((5, 5))
chessboard[1::2, ::2] = 1
chessboard[::2, 1::2] = 1

plt.figure(figsize=(5, 5))
plt.imshow(chessboard, cmap='gray', interpolation='nearest')
plt.xticks([])
plt.yticks([])
plt.title('5x5 Chessboard')
plt.savefig('/tmp/output/chessboard_5x5.png', bbox_inches='tight', dpi=300)
plt.close()
```

**Output:** Example execution returns a generated chessboard image artifact plus summary text.


# Reference

This directory collects the definitive reference material for GL AIP: low-level REST endpoints, the Python SDK surface, and the companion CLI. Each page is derived from the live sources in `aip_readme.md` and kept in lockstep with the SDK and CLI implementations, so you can rely on it when building or automating against the platform.

### What's Included

* [**Python SDK Reference**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk) — client architecture, method signatures, data models, streaming behaviour, and error handling patterns.
* [**CLI Commands Reference**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands) — every `aip` subcommand with flags, interactive behaviour, import/export flows, and workflow tips.
* [**CLI Slash Command Palette**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-slash-palette) — interactive palette shortcuts (`/help`, `/agents`, `/details`) with keyboard hints, completions, and agent-context actions.
* [**REST API Reference**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api) — endpoint catalogue aligned with AIP features (agents, tools, MCP, schedules, language models, accounts, utilities) plus sample payloads.
* [**HITL REST Workflow**](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/hitl) — end-to-end walkthrough of the Human-in-the-Loop approval flow with example payloads and cURL snippets.

### Source of Truth

* The Python reference mirrors the SDK client architecture, models, and utilities.
* CLI coverage reflects the Click command tree and the behaviours validated by the unit tests in the repository.
* REST endpoints, configuration subsystems, and security notes are summarised from `aip_readme.md` and the FastAPI routers that power the platform.

Whenever you ship new SDK features, CLI flags, or backend endpoints, update the corresponding reference page alongside the code change.

### How to Use This Section

* **Developers** — Jump into the Python SDK reference for method signatures and streaming examples, then the REST catalogue when you need to craft custom requests or runtime overrides.
* **Operators** — Lean on the CLI guide for day-to-day management (status checks, imports, scripted runs) and the REST guide for automation or monitoring hooks.
* **Integrators** — Start with the REST API page to understand available capabilities (memory, PII mapping, tool output sharing, MCP overrides), then pick the SDK or CLI depending on your execution environment.

### Keeping Docs Fresh

#### 1) When you add or change SDK methods

Update the Python SDK reference and include illustrative snippets so consumers can rely on accurate method signatures and examples.

#### 2) When you extend CLI commands

Keep the CLI commands reference in sync with new flags, default behaviours, and examples so operators and automation scripts behave as expected.

#### 3) When backend routers change

Refresh the REST API reference so it reflects the latest endpoints, payload shapes, and security guarantees.

Related sections worth bookmarking:

* [Guides](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides) — task-oriented walkthroughs
* [Resources overview](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources) — upgrade notes and release checklists

Keeping these three reference pages aligned with the codebase ensures SDK consumers, CLI users, and API integrators share a single, up-to-date source of truth.


# Python SDK

Official Python client for GL AIP (GDP Labs AI Agents Package). Typed, session-aware, and aligned with the live FastAPI backend.

This document is the authoritative guide to the `glaip-sdk` package. Every method, payload, and return type documented here is derived from the code in `python/glaip-sdk/glaip_sdk` and mirrors the behaviour used by the CLI and the end-to-end test suite.

The content is organised by resource category so you can quickly locate the operation you need—agents, tools, MCP connections, language models, and utility helpers.

> **Success**
>
> **Quickstart (SDK, Agent-first)** — `pip install glaip-sdk` (or `glaip-sdk[local]`) → create `Agent(...)` → `agent.run(...)` locally → optionally `agent.deploy()` for remote execution.

{% hint style="info" %}
`Client` remains available as a low-level/advanced API for workspace-wide admin operations (bulk list/filter, migration/import pipelines, and governance).
{% endhint %}

***

### Installation & SDK Basics

```bash
pip install glaip-sdk
```

```python
from glaip_sdk import Agent

agent = Agent(
    name="hello-agent",
    instruction="You are a helpful assistant.",
)

print(agent.run("Hello"))
```

Use the low-level `Client` API when you need workspace-wide administrative operations:

```python
from glaip_sdk import Client

# Read configuration from environment variables (AIP_API_URL, AIP_API_KEY)
client = Client()

# Explicit configuration
client = Client(
    api_url="https://aip.example.com",
    api_key="sk-your-api-key",
    timeout=60.0,
)
```

{% hint style="info" %}
**Environment variables:** The client reads `AIP_API_URL` and `AIP_API_KEY` by default when arguments are omitted.
{% endhint %}

#### Session lifecycle

| Action                     | Behaviour                                                                                    |
| -------------------------- | -------------------------------------------------------------------------------------------- |
| `with Client() as client:` | Opens and automatically closes the underlying `httpx.Client`.                                |
| `client.timeout = 90`      | Rebuilds the shared HTTP client and propagates the session to `agents`, `tools`, and `mcps`. |
| `client.close()`           | Manual teardown when not using a context manager.                                            |

```python
with Client(timeout=45) as client:
    client.timeout = 90  # propagates to sub-clients
    print(client.agents.list_agents())
```

***

### Client API Surface

The `Client` class exposes convenience methods that delegate to the specialised sub-clients under the hood. This section documents every public method grouped by resource.

Each signature is shown exactly as implemented. Optional parameters list their Python default values.

#### Agents

**`client.create_agent(...) -> Agent`**

```python
client.create_agent(
    name=None,
    instruction=None,
    model=None,
    tools=None,
    agents=None,
    timeout=None,
    *,
    file=None,
    **kwargs,
) -> Agent
```

Create an agent with the supplied configuration. When `file` is provided, the SDK loads the agent definition from a JSON or YAML document, merges any keyword overrides you pass, and submits the combined payload.

Parameters:

* `name` (`str`, required unless `file` is provided, default: none): human-readable agent name (must be unique per account). Loaded from file when omitted.
* `instruction` (`str`, required unless `file` is provided, default: none): system prompt / operating instructions. Pulled from file when omitted.
* `model` (`str`, optional, default: `openai/gpt-5-nano`): language model selector. Symbolic `provider/model` values resolve seeded AIP models (raises `ValueError` if no seeded match); UUID-shaped values bind exactly to a remote language model.
* `tools` (`list[str | Tool] | None`, optional, default: `None`): tool IDs or `Tool` objects to attach.
* `agents` (`list[str | Agent] | None`, optional, default: `None`): sub-agent IDs or `Agent` objects for delegation.
* `timeout` (`int`, optional): Execution timeout in seconds. Recommended way to set agent runtime timeout. Internally normalized to `agent_config["timeout_seconds"]`.
* `file` (`str | Path`, optional, default: `None`): load base configuration from JSON/YAML; merge overrides.
* `**kwargs` (optional): forwarded fields such as `agent_config`, `metadata`, and `mcps`. `language_model_id` is also accepted via kwargs for exact remote binding, but prefer `model="<uuid>"` for new code.

Common values:

* `name`: `"pipeline-runner"`
* `instruction`: `"Coordinate ETL tasks..."`
* `model`: `"openai/gpt-5-nano"`
* `tools`: `["tool-uuid"]`
* `agents`: `["delegate-id"]`
* `file`: `"configs/agent.yaml"`
* `model`: `"fc945f0a-595e-471f-807c-47334c0eba9f"`

When `file` is used you may specify tools/agents/MCPs by **name** instead of ID; the SDK resolves them against the current workspace before submitting the payload (mirroring the CLI’s `--import` behaviour).

Returns the created `Agent` with all persisted fields populated. Raises `ValueError` if neither runtime arguments nor the file payload provide `name` and `instruction`.

{% hint style="info" %}
**Complete field specifications:** See [Agents Schema Reference](https://github.com/GDP-ADMIN/gl-sdk/blob/docs/gitbook-sync/gitbook/gl-ai-agent-package/resources/reference/schemas/agents/README.md) for all available fields, validation rules, and constraints. Additional fields can be passed via `**kwargs`.
{% endhint %}

```python
agent = client.create_agent(
    name="pipeline-runner",
    instruction="Coordinate ETL tasks and report results",
    tools=["tool-uuid"],
    metadata={"team": "ml"},
    agent_config={"memory": "mem0", "tool_output_sharing": True},
)
```

```python
agent = client.create_agent(
    file="configs/sentiment.yaml",
    metadata={"environment": "prod"},
    tools=["tool-uuid-extra"],
)
```

**`client.list_agents(...) -> AgentListResult`**

```python
client.list_agents(
    agent_type=None,
    framework=None,
    name=None,
    version=None,
    sync_langflow_agents=False,
    *,
    limit=None,
    page=None,
    include_deleted=None,
    created_at_start=None,
    created_at_end=None,
    updated_at_start=None,
    updated_at_end=None,
    metadata=None,
    query=None,
) -> AgentListResult
```

Fetch agents with optional filtering and pagination metadata. The returned `AgentListResult` is iterable like a list of `Agent` models and also exposes `total`, `page`, `limit`, `has_next`, and `has_prev`.

Filters:

* `agent_type` (`str`, optional, default: `None`): `config`, `code`, `a2a`, or `langflow`.
* `framework` (`str`, optional, default: `None`): filter by orchestration framework.
* `name` (`str`, optional, default: `None`): case-insensitive substring match.
* `version` (`str`, optional, default: `None`): exact version.
* `sync_langflow_agents` (`bool`, optional, default: `False`): sync LangFlow before listing.
* `limit` (`int`, optional, default: `None`): page size (1-100).
* `page` (`int`, optional, default: `None`): 1-based page number.
* `include_deleted` (`bool`, optional, default: `None`): include soft-deleted agents.
* `created_at_start` / `created_at_end` (`str`, optional, default: `None`): creation timestamp range (ISO 8601).
* `updated_at_start` / `updated_at_end` (`str`, optional, default: `None`): update timestamp range (ISO 8601).
* `metadata` (`dict[str, str]`, optional, default: `None`): metadata filters (for example `metadata.environment=prod`).
* `query` (`AgentListParams`, optional, default: `None`): pass a pre-built parameter object.

Common values:

* `agent_type`: `"langflow"`
* `framework`: `"langgraph"`
* `name`: `"pipeline"`
* `version`: `"1.2.0"`
* `limit`: `20`
* `page`: `2`
* `created_at_start`: `"2024-01-01T00:00:00Z"`
* `metadata`: `{"environment": "prod"}`

Returns an empty result set if no agents match (`len(result) == 0`).

**`client.get_agent_by_id(agent_id) -> Agent`**

Retrieve an agent by UUID. Raises `NotFoundError` if the agent does not exist or belongs to another account.

`client.get_agent(agent_id)` is an alias.

**`client.find_agents(name=None) -> list[Agent]`**

List agents and apply a case-insensitive name filter client-side. Returns an empty list if nothing matches.

**`client.update_agent(agent_id, name=None, instruction=None, model=None, skills=None, timeout=None, *, file=None, tools=None, agents=None, mcps=None, **kwargs) -> Agent`**

Replace an agent's configuration.

* `name` (`str | None`): agent display name.
* `instruction` (`str | None`): system prompt/instructions.
* `model` (`str | None`): language model selector. Symbolic `provider/model` values resolve seeded AIP models; UUID-shaped values bind exactly to a remote language model.
* `skills` (`str | list | dict | None`): skills to attach.
* `timeout` (`int | None`): execution timeout in seconds.
* `file` (`str | Path`): load base configuration from JSON/YAML; merge overrides.
* `tools` (`list[str | Tool] | None`): tool IDs or objects to attach.
* `agents` (`list[str | Agent] | None`): sub-agent IDs or objects for delegation.
* `mcps` (`list[str | MCP] | None`): MCP configurations to attach.
* Unspecified parameters retain their stored values.
* Symbolic `model=` updates resolve against seeded AIP models only and fail fast when no seeded match exists.
* UUID-shaped `model=` values bind exactly to a remote language model, including tenant-owned rows.
* Do not pass symbolic `model=` together with `language_model_id`; use exactly one selector.
* Provide `tools=[]` / `agents=[]` to clear associations.
* Supply `file` to load a JSON/YAML definition and merge overrides, matching the CLI's `--import` behaviour.

When updating from a file, the SDK also resolves tool/agent/MCP names to the corresponding IDs in the current workspace so you can reuse CLI exports without manual edits.

{% hint style="info" %}
**Complete field specifications:** See [Agents Schema Reference](https://github.com/GDP-ADMIN/gl-sdk/blob/docs/gitbook-sync/gitbook/gl-ai-agent-package/resources/reference/schemas/agents/README.md) for all available fields, validation rules, and constraints. Additional fields can be passed via `**kwargs`.
{% endhint %}

```python
updated = client.update_agent(
    agent.id,
    instruction="Be precise and provide references",
    timeout=900,
    metadata={"environment": "prod"},
)
```

**`client.patch_agent(agent_id, **kwargs) -> Agent`**

Partially update an agent with sparse backend `PATCH /agents/{agent_id}` semantics.

* Only explicitly provided fields are sent.
* Omitted fields are preserved by the backend.
* `timeout=` patches `agent_config.timeout_seconds`.
* `model=` patches the language model — UUID values bind to `language_model_id`; symbolic names resolve against seeded models. Mutually exclusive with `language_model_id` and `provider`/`model_name` in the same call.
* `tools=[]`, `agents=[]`, `mcps=[]`, or `skills=[]` clear those relationships (all four **replace** the existing set when provided).
* `tool_configs`, `mcp_configs`, and `agent_config` are **deep merged** — nested objects are recursively merged, not replaced.
* `update_agent(...)` remains the full-replacement, prefetching PUT path.
* `patch_agent(...)` does **not** support `file=` import materialization.

```python
patched = client.patch_agent(
    agent.id,
    instruction="Be precise and provide references",
    timeout=900,
)
```

**`client.delete_agent(agent_id) -> None`**

Soft-delete the agent.

**`client.run_agent(agent_id, message, files=None, tty=False, *, renderer="auto", runtime_config=None, gl_connectors_token=None, trace=False, **kwargs) -> str | AgentRunResult`**

Execute an agent and stream results. Returns the final assistant response as a string.

Parameters:

* `message` (`str`): prompt for the agent.
* `files` (`list[str | BinaryIO] | None`): optional file attachments (file paths as strings).
* `tty` (`bool`): enables the Rich TTY renderer (`auto` by default on the CLI).
* `runtime_config` (`dict[str, Any] | None`): optional runtime overrides for tools, MCPs, and agent behavior.
* `gl_connectors_token` (`str | None`): optional end-user GL Connectors token forwarded to `/agents/{agent_id}/run`.
* `trace` (`bool`): when `True`, returns an `AgentRunResult` with response metadata/events.
* `**kwargs`: additional forwarded fields such as `chat_history`, `pii_mapping`, and `timeout`.

Use `gl_connectors_token` when a run may require GL Connectors user-auth checks for native tools/MCPs. The token is forwarded in both JSON and multipart (`files`) request modes.

The SDK automatically handles SSE streaming, rich rendering, and error handling. It mirrors [`POST /agents/{agent_id}/run`](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/agents).

```python
response = client.run_agent(
    agent.id,
    "Summarise ticket INC-42",
    chat_history=[{"role": "user", "content": "Please continue"}],
    gl_connectors_token="<user-token>",
)
```

**`client.sync_langflow_agents(base_url=None, api_key=None) -> dict`**

Trigger LangFlow synchronization. Returns the backend JSON response containing counts of created/updated flows. `base_url` and `api_key` override the environment variables `LANGFLOW_BASE_URL` / `LANGFLOW_API_KEY` when set. Pairs with [`POST /agents/langflow/sync`](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/agents).

**Async streaming – `client.agents.arun_agent(agent_id, message, files=None, *, request_timeout=None, runtime_config=None, gl_connectors_token=None, **kwargs)`**

Asynchronous generator that yields parsed SSE JSON fragments. Useful for server applications or custom renderers.

`gl_connectors_token` is also supported in async runs and is forwarded for both JSON and multipart requests.

```python
async for event in client.agents.arun_agent(agent.id, "Status update"):
    print(event)
```

Example SSE payload emitted by the backend:

```
event: token
data: {"text": "Working on it..."}

event: completed
data: {"output": "Final answer here"}
```

#### Agent model helpers

Agents returned by the SDK are Pydantic models that keep a reference to the originating client when fetched through the SDK.

| Method                                                  | Description                                                                              |
| ------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `agent.run(message, **kwargs) -> str`                   | Delegates to `client.run_agent`, injecting the agent name automatically.                 |
| `agent.arun(message, **kwargs) -> AsyncGenerator[dict]` | Async streaming: server-backed runs yield response chunks; local runs yield event dicts. |
| `agent.update(**kwargs) -> Agent`                       | Calls `client.update_agent` and refreshes model fields in-place.                         |
| `agent.patch(**kwargs) -> Agent`                        | Calls `client.patch_agent` with sparse PATCH semantics and refreshes in-place.           |
| `agent.delete() -> None`                                | Calls `client.delete_agent`.                                                             |
| `agent.to_component() -> Component`                     | Returns an `AgentComponent` for use in `gllm-pipeline`.                                  |

```python
agent = client.get_agent_by_id(agent_id)
result = agent.run("Summarise ticket INC-42", timeout=120)
print(result)
```

**`agent.arun(message, verbose=False, local=False, runtime_config=None, gl_connectors_token=None, chat_history=None, export=False, export_dir=None, enable_pii=None, **kwargs) -> AsyncGenerator[dict]`**

Async generator that streams output from the agent. Supports two modes:

* **Server-backed** (default when the agent is deployed): streams response chunks from the AIP backend.
* **Local** (`local=True` or undeployed agent): uses the local aip-agents runtime and yields each live SSE/activity event as a dict.

```python
async for event in agent.arun("What is the status?", local=True):
    print(event)
```

* `export=True` is not supported for async runs (raises `ValueError`).
* `enable_pii` enables NER-based PII masking per request (local only).

***

#### Tools

**`client.create_tool(file_path, name=None, description=None, framework="langchain", **kwargs) -> Tool`**

Upload a Python plugin packaged as a `.py` file.

| Parameter     | Type          | Description                                                               |
| ------------- | ------------- | ------------------------------------------------------------------------- |
| `file_path`   | `str`         | Path to the plugin file. Must exist locally.                              |
| `name`        | `str \| None` | Optional override; default is derived from the plugin’s `name` attribute. |
| `description` | `str \| None` | Stored description. Auto-generated if omitted.                            |
| `framework`   | `str`         | Tool framework identifier (`langchain` default).                          |
| `**kwargs`    | –             | Additional metadata (e.g. `tags`, `tool_type`).                           |

Returns the created `Tool` instance. Temporary files created during upload are cleaned up automatically.

{% hint style="info" %}
**Complete field specifications:** See [Tools Schema Reference](https://github.com/GDP-ADMIN/gl-sdk/blob/docs/gitbook-sync/gitbook/gl-ai-agent-package/resources/reference/schemas/tools/README.md) for all available fields, validation rules, and constraints.
{% endhint %}

```python
tool = client.create_tool(
    file_path="calculator_tool.py",
    tags=["math", "utility"],
)
```

**`client.list_tools(tool_type=None) -> list[Tool]`**

List tool metadata. Optional `tool_type` filters by backend type (`custom`, `native`).

**`client.get_tool_by_id(tool_id) -> Tool`**

Fetch a tool by UUID. Raises `NotFoundError` if missing.

`client.get_tool(tool_id)` is an alias.

**`client.find_tools(name) -> list[Tool]`**

Return tools whose names match the supplied string (case-insensitive, client-side filter).

**`client.update_tool(tool_id, **kwargs) -> Tool`**

Update tool metadata (e.g. `name`, `description`, `tags`). For custom tools that need a code refresh, use `client.update_tool_via_file`.

**`client.update_tool_via_file(tool_id, file_path, **kwargs) -> Tool`**

Upload a new plugin file for an existing custom tool. Any `kwargs` provided are forwarded as form fields (description, tags, etc.).

**`client.get_tool_script(tool_id) -> str`**

Return the stored plugin source. Useful for audits or version control.

**`client.delete_tool(tool_id) -> None`**

Soft-delete the tool.

#### Tool model helpers

| Method                          | Description                                                               |
| ------------------------------- | ------------------------------------------------------------------------- |
| `tool.get_script() -> str`      | Returns cached `tool_script` or a placeholder when not available.         |
| `tool.update(**kwargs) -> Tool` | Delegates to the appropriate SDK update method (metadata vs file upload). |
| `tool.delete() -> None`         | Delegates to `client.delete_tool`.                                        |

***

#### Model Context Protocol (MCP)

**`client.create_mcp(**kwargs) -> MCP`**

Create an MCP configuration. Accepts the same payload shape as the REST API (`/mcps` POST) including `name`, `description`, `transport`, `config`, and `authentication` dictionaries.

{% hint style="info" %}
**Complete field specifications:** See [MCP Schema Reference](https://github.com/GDP-ADMIN/gl-sdk/blob/docs/gitbook-sync/gitbook/gl-ai-agent-package/resources/reference/schemas/mcps/README.md) for all available fields, validation rules, and constraints.
{% endhint %}

```python
mcp = client.create_mcp(
    name="vector-db",
    transport="http",
    config={"url": "https://mcp.example.com"},
    authentication={"type": "api-key", "key": "X-API-Key", "value": "secret"},
)
```

**`client.list_mcps() -> list[MCP]`**

Return all stored MCP configurations for the account.

**`client.get_mcp_by_id(mcp_id) -> MCP`**

Retrieve an MCP by UUID. `client.get_mcp(mcp_id)` is an alias.

**`client.find_mcps(name) -> list[MCP]`**

Client-side name filtering across MCP configurations.

**`client.update_mcp(mcp_id, **kwargs) -> MCP`**

Update an MCP configuration. The SDK chooses between PUT or PATCH depending on whether you provide a full payload (`name`, `config`, `transport`).

{% hint style="info" %}
**Complete field specifications:** See [MCP Schema Reference](https://github.com/GDP-ADMIN/gl-sdk/blob/docs/gitbook-sync/gitbook/gl-ai-agent-package/resources/reference/schemas/mcps/README.md) for all available fields, validation rules, and constraints.
{% endhint %}

**`client.delete_mcp(mcp_id) -> None`**

Soft-delete an MCP.

**`client.test_mcp_connection(config: dict) -> dict`**

Call `/mcps/connect` to validate credentials or connectivity without persisting the configuration.

`client.test_mcp_connection_from_config(config)` is an alias.

**`client.get_mcp_tools_from_config(config: dict) -> list[dict]`**

Call `/mcps/connect/tools` to fetch tool metadata from an MCP without storing it. Useful for validating available actions before creation.

#### MCP model helpers

| Method                        | Description                       |
| ----------------------------- | --------------------------------- |
| `mcp.update(**kwargs) -> MCP` | Delegates to `client.update_mcp`. |
| `mcp.delete() -> None`        | Delegates to `client.delete_mcp`. |

***

#### Schedules

**`client.schedules.create(*, agent_id, input, schedule) -> Schedule`**

Create a schedule for recurring agent execution.

Parameters:

* `agent_id` (`str`, required): agent ID to schedule runs for.
* `input` (`str`, required): input text for each scheduled execution.
* `schedule` (`ScheduleConfig | dict | str`, required): cron config as object, dict, or string.

Common values:

* `agent_id`: `"agent-123"`
* `input`: `"Generate daily report"`
* `schedule`: `"0 9 * * 0-4"`

Cron strings use five fields: `minute hour day_of_month month day_of_week`. Fields accept `*`, ranges (e.g., `2-4`), lists (`0,6`), and steps (`*/N`). Day-of-week uses APScheduler numbering (`0` = Monday, `6` = Sunday). All schedules run in Asia/Jakarta (WIB).

Returns the created `Schedule` instance.

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

schedule = client.schedules.create(
    agent_id="agent-123",
    input="Generate daily summary",
    schedule=ScheduleConfig(
        minute="0",
        hour="9",
        day_of_week="0-4",  # Weekdays (Mon-Fri)
    ),
)

# Or use a cron string directly
schedule = client.schedules.create(
    agent_id="agent-123",
    input="Weekly update",
    schedule="0 10 * * 0",  # Every Monday at 10am
)
```

**`client.schedules.list(*, limit=None, page=None, agent_id=None) -> ScheduleListResult`**

List schedules with optional filtering and pagination.

| Parameter  | Type  | Required | Default | Description                   |
| ---------- | ----- | -------- | ------- | ----------------------------- |
| `limit`    | `int` | No       | `None`  | Page size (1-100).            |
| `page`     | `int` | No       | `None`  | Page number for pagination.   |
| `agent_id` | `str` | No       | `None`  | Filter schedules by agent ID. |

Returns `ScheduleListResult` with `items`, `total`, `page`, `limit`, `has_next`, `has_prev`.

```python
# List all schedules
schedules = client.schedules.list()

# Filter by agent
agent_schedules = client.schedules.list(agent_id="agent-123")

# Paginate
page1 = client.schedules.list(limit=10, page=1)
```

**`client.schedules.get(schedule_id) -> Schedule`**

Retrieve a schedule by UUID.

Raises `NotFoundError` if the schedule does not exist.

```python
from glaip_sdk.exceptions import NotFoundError

try:
    schedule = client.schedules.get("schedule-abc")
    print(schedule.next_run_time)
except NotFoundError:
    print("Schedule not found")
```

**`client.schedules.update(schedule_id, *, input=None, schedule=None) -> Schedule`**

Update an existing schedule. Unspecified parameters retain their values.

**Update Behavior (Explicit, Not Merge):**

* Omit `schedule` to keep the existing timing unchanged
* Providing a partial schedule dict (e.g., `{"hour": "10"}`) will fill missing fields with `"*"`
* This is intentional for predictability: what you provide is what you get, plus wildcard defaults
* To preserve existing values, fetch the current schedule first and modify only what you need

| Parameter     | Type                            | Required | Default | Description                             |
| ------------- | ------------------------------- | -------- | ------- | --------------------------------------- |
| `schedule_id` | `str`                           | Yes      | —       | Schedule ID to update.                  |
| `input`       | `str`                           | No       | `None`  | New input text for scheduled execution. |
| `schedule`    | `ScheduleConfig \| dict \| str` | No       | `None`  | New schedule configuration.             |

```python
updated = client.schedules.update(
    "schedule-abc",
    input="Updated daily report",
    schedule="0 8 * * *",  # Change to 8am
)
```

**`client.schedules.delete(schedule_id) -> None`**

Delete a schedule by ID.

```python
client.schedules.delete("schedule-abc")
```

**`client.schedules.list_runs(agent_id, *, schedule_id=None, status=None, limit=None, page=None) -> ScheduleRunListResult`**

List execution runs for an agent, optionally filtered by schedule and status. Only returns schedule runs (equivalent to `run_type=schedule`).

Parameters:

* `agent_id` (`str`, required): agent ID to list runs for.
* `schedule_id` (`str`, optional, default: `None`): filter by specific schedule ID.
* `status` (`RunStatus`, optional, default: `None`): `started`, `success`, `failed`, `cancelled`, `aborted`, or `unavailable`.
* `limit` (`int`, optional, default: `None`): page size (1-100).
* `page` (`int`, optional, default: `None`): page number.

```python
# List all scheduled runs for an agent
runs = client.schedules.list_runs("agent-123")

# Filter by schedule and status
successful_runs = client.schedules.list_runs(
    "agent-123",
    schedule_id="schedule-abc",
    status="success",
)
```

#### Schedule model helpers

| Method                                                  | Description                      |
| ------------------------------------------------------- | -------------------------------- |
| `schedule.update(**kwargs) -> Schedule`                 | Update schedule config or input. |
| `schedule.delete() -> None`                             | Delete the schedule.             |
| `schedule.list_runs(**params) -> ScheduleRunListResult` | List runs for this schedule.     |
| `run.get_result() -> ScheduleRunResult`                 | Fetch full output for a run.     |
| `schedule_run.duration -> str \| None`                  | Formatted duration (HH:MM:SS).   |

#### Schedule run fields

Schedule run list items (`ScheduleRun`) expose run metadata:

| Field          | Description                                                                                    |
| -------------- | ---------------------------------------------------------------------------------------------- |
| `id`           | Run ID.                                                                                        |
| `agent_id`     | Agent ID associated with the run.                                                              |
| `schedule_id`  | Schedule ID for scheduled runs.                                                                |
| `run_type`     | Run type, usually `schedule`.                                                                  |
| `status`       | Run status (lowercase): `started`, `success`, `failed`, `cancelled`, `aborted`, `unavailable`. |
| `started_at`   | Execution start timestamp.                                                                     |
| `completed_at` | Execution end timestamp.                                                                       |
| `input`        | Input used for the run, when provided by the backend.                                          |
| `config`       | Schedule config used for the run, when provided by the backend.                                |

#### Schedule run results

`run.get_result()` returns a `ScheduleRunResult` with the stored output payload. The `output` field is a list of backend-defined event dictionaries and is not guaranteed to match a fixed schema.

#### Agent schedule facade

Access `agent.schedule` for scoped operations:

```python
agent = client.get_agent_by_id("agent-123")

# Create schedule via agent
schedule = agent.schedule.create(
    input="Daily task",
    schedule="0 9 * * 0-4",
)

# List this agent's schedules
for s in agent.schedule.list():
    print(s.id)

# List runs for a schedule
runs = agent.schedule.list_runs(schedule.id)
```

***

#### Language Models & Utilities

**`client.list_language_models() -> list[dict]`**

Returns the language model catalogue visible to the current API key. Each entry contains provider metadata, model identifiers, and optional base URLs.

**`client.ping() -> bool`**

Calls `/health-check`. Returns `True` when the API responds successfully, otherwise `False`.

**`client.timeout`**

Property exposing the current timeout (seconds). Assigning a new value rebuilds the shared `httpx.Client` instance.

***

### Error Handling

All network operations raise typed exceptions from `glaip_sdk.exceptions` when the backend responds with an error status.

| Exception                            | Trigger                                                                 |
| ------------------------------------ | ----------------------------------------------------------------------- |
| `AuthenticationError`                | Missing/invalid `X-API-Key` (401).                                      |
| `ForbiddenError`                     | Attempt to access a master-key-only endpoint with an account key (403). |
| `NotFoundError`                      | Resource does not exist or is soft-deleted (404).                       |
| `ValidationError`                    | Payload failed validation (400/422).                                    |
| `ConflictError`                      | Duplicate names or incompatible state (409).                            |
| `RateLimitError`                     | Too many requests (429).                                                |
| `TimeoutError` / `AgentTimeoutError` | Request or streaming timeout.                                           |
| `ServerError`                        | Backend 5xx responses.                                                  |

Example pattern:

```python
from glaip_sdk import Client
from glaip_sdk.exceptions import AuthenticationError, ValidationError

client = Client()

try:
    agent = client.create_agent(name="demo", instruction="Be helpful")
except AuthenticationError:
    print("Invalid API key")
except ValidationError as exc:
    print("Payload rejected", exc.payload)
```

### Troubleshooting & FAQ

* **401 Invalid API key** — Refresh credentials from the AIP console and confirm `AIP_API_KEY` is set.
* **404 Not found** — Resources are soft-deleted; call `client.list_*` to confirm IDs before retrying.
* **409 Conflict** — Resolve duplicate names or finish outstanding runs before retrying the write.
* **429 Rate limited** — Catch `RateLimitError` and back off using the `Retry-After` header from the REST response.
* **Streaming stalls** — Increase `timeout`; SSE connections idle for 5 minutes are closed server-side.

***

### Related Documentation

* [CLI Commands Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-commands)
* [REST API Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api)
* [Hands-on examples](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/tutorials/hands-on-examples) for curated, runnable projects
* [GL SDK Cookbook](https://github.com/gdplabs/gl-aip-sdk-cookbook/tree/main) for advanced patterns and integrations

Keep this page in sync whenever you add new client methods, adjust signatures, or expand the backend payloads consumed by the SDK.


# CLI Commands

> This page provides reference for `aip` command-line interface that ships with Python SDK. The CLI exposes same resource coverage as SDK, adds rich terminal renderers and TUI components, and wraps import/export helpers for automation workflows.

{% hint style="info" %}
Need interactive slash palette cheat sheet? Head over to [CLI Slash Command Palette](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-slash-palette).
{% endhint %}

{% hint style="info" %}
**TUI Support**: This CLI includes comprehensive Textual-based TUI components for interactive agent management, configuration, and monitoring. Refer to the TUI foundation spec in the repository for patterns and best practices.
{% endhint %}

{% hint style="info" %}
Multi-account profiles ship in CLI v0.5.0+. Legacy `aip config ...` commands are deprecated and gated; see the [Legacy Config Commands](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-legacy-config) page for details and migration guidance.
{% endhint %}

### At a glance

* Manage **agents, tools, MCP connections, and language models** without writing code.
* Stream AI agent runs with a live TTY renderer, file attachments, and transcript capture.
* Import/export full resource definitions (JSON or YAML) and sync LangFlow flows into AIP.
* Store multiple credential profiles in `~/.aip/config.yaml` (default + named accounts) and switch output formats (`rich`, `plain`, `json`, `md`).

***

### Installation & Quick start

**Install & quick start**

```bash
pipx install glaip-sdk

aip accounts add prod   # interactive credential prompt

aip status              # smoke test connectivity
aip agents list         # browse resources (defaults to active account)
```

{% hint style="info" %}
**Configuration sources** Account selection order is `--account` flag > `active_account` in `~/.aip/config.yaml`. CLI/palette ignore raw credential env vars; Python SDK still honors `AIP_API_URL`/`AIP_API_KEY` for scripts. `AIP_ACCOUNT_FALLBACK` is ignored in the MVP.
{% endhint %}

***

### Global options

```bash
aip [GLOBAL OPTIONS] COMMAND [ARGS]...
```

**Global options** (also honored on subcommands)

| Flag              | Description                                                                         |
| ----------------- | ----------------------------------------------------------------------------------- |
| `--api-url TEXT`  | Deprecated: override API endpoint (profiles recommended)                            |
| `--api-key TEXT`  | Deprecated: override API key (profiles recommended)                                 |
| `--account TEXT`  | Target a named account profile for this command (hidden; shown with `--help --all`) |
| `--timeout FLOAT` | Request timeout in seconds (`30` default)                                           |
| `--view`          | Output mode: `rich` (default), `plain`, `json`, `md`                                |
| `--no-tty`        | Disable rich TTY renderer for agent runs                                            |
| `--version`       | Show CLI version                                                                    |
| `--help`          | Show command help                                                                   |

#### Output modes

* `--view rich` (default) renders tables/panels using Rich.
* `--view json` emits machine‑friendly JSON.
* `--view md` renders Markdown; `--view plain` prints plain text. All subcommands inherit `--view` from the top-level group.

***

### Command Map

| Command            | Description                                                                                                                                                      |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `aip status`       | Check connectivity and resource counts                                                                                                                           |
| `aip accounts ...` | Manage credential profiles (add/list/show/edit/use/rename/remove)                                                                                                |
| `aip configure`    | Legacy configuration wizard (deprecated; gated). Prefer `aip accounts add <name>`                                                                                |
| `aip agents ...`   | Agent CRUD, execution, import/export, LangFlow sync                                                                                                              |
| `aip tools ...`    | Tool upload/update, metadata, script retrieval                                                                                                                   |
| `aip mcps ...`     | MCP configuration management and connection tests                                                                                                                |
| `aip models list`  | View available language models                                                                                                                                   |
| `aip update`       | Upgrade the installed `glaip-sdk` package                                                                                                                        |
| `aip version`      | Show detailed version and environment info                                                                                                                       |
| `/transcripts`     | View cached run transcripts and manage local transcript cache                                                                                                    |
| `aip config ...`   | Deprecated legacy config helpers (gated); see [Legacy Config Commands](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-legacy-config) |

***

### Agents

#### List

```bash
aip agents list [OPTIONS]
```

Options:

* `--simple` — skip interactive fuzzy picker; always show a table
* `--type TEXT` — filter by agent type (`config`, `code`, `a2a`, `langflow`)
* `--framework TEXT` — filter by orchestration framework (`langchain`, `langgraph`, `google_adk`)
* `--name TEXT` — filter by partial name (case-insensitive)
* `--version TEXT` — filter by agent version
* `--sync-langflow` — pull latest flows from the configured LangFlow server before listing (honours `LANGFLOW_BASE_URL`/`LANGFLOW_API_KEY`)
* `--view` / `--json` — override output format

When you run the command on an interactive terminal in Rich mode it opens the picker **only** if no filters are supplied and `--simple` is omitted. Supplying any filter (`--name`, `--type`, `--framework`, `--version`) or switching to the simple/plain/JSON views skips the picker and prints the table immediately. Selecting an agent in the picker still shows complete metadata and suggested follow-up commands (`run`, `update`, `delete`).

#### Get

```bash
aip agents get AGENT_REF [OPTIONS]
```

Options:

* `--select INTEGER` — choose among ambiguous name matches (1-based)
* `--export PATH` — export the full agent definition to `.json` or `.yaml`
* `--view` / `--json`

`AGENT_REF` accepts either an ID or a name. The command resolves ambiguity using fuzzy search or the `--select` flag. Exported files include `agent_config`, tool associations, MCP references, and metadata.

#### Create

```bash
aip agents create [OPTIONS]
```

Required flags:

* `--name TEXT`
* `--instruction TEXT`

Optional flags:

* `--model TEXT` — override the base model (omit to use your workspace’s AIP default); pass `language_model_id` inside `--import` payload for catalogue models
* `--tools TOOL_REF` — attach tools by name or ID (multi-use option)
* `--agents AGENT_REF` — attach sub-agents by name or ID (multi-use)
* `--mcps MCP_REF` — attach MCP connections by name or ID (multi-use)
* `--skills SKILL_URL` — attach remote GitHub skill URLs (repeatable; comma-separated values are also accepted)
* `--timeout INTEGER` — execution timeout per run (seconds, default `300`)
* `--import PATH` — bootstrap from an exported agent JSON/YAML file (CLI merges CLI flags over imported data)
* `--view` / `--json`

References accept either UUIDs or human-friendly names; ambiguity raises unless unique. Import files can include `metadata`, `agent_config` (memory, tool sharing, PII tags), `skills`, and runtime defaults. Secret fields should be re-supplied manually post-import.

Skills must be remote URL references such as:

```bash
aip agents create \
  --name "skills-agent" \
  --instruction "Use attached skills when helpful." \
  --skills https://github.com/org/repo/tree/main/skills/copywriting
```

Repeat `--skills` or pass comma-separated URLs to attach multiple skills. Local path-only skills are local-runtime only and are not deployable through the remote API.

#### Run

```bash
aip agents run AGENT_REF [INPUT] [OPTIONS]
```

Parameters:

* Positional `INPUT` or `--input TEXT` — required prompt if not provided positionally
* `--select INTEGER` — disambiguate name matches
* `--chat-history JSON` — pass prior turns as JSON array (`[{"role": "user", "content": "..."}, ...]`)
* `--file PATH` — attach one or more files (repeatable)
* `--timeout INTEGER` — execution timeout for this run (defaults to agent timeout)
* `--save PATH` — persist transcript and full debug log (supports `.md` or `.json`)
* `--verbose` — deprecated; use the transcript viewer (Ctrl+T) for detailed events
* `--view` / `--json`

Note: top-level `aip --timeout` controls HTTP request timeout; `aip agents run --timeout` controls agent execution timeout. If you need both, pass the request timeout before the subcommand (for example: `aip --timeout 60 agents run <AGENT_REF> "Hello" --timeout 600`).

The command streams SSE responses using the Rich renderer (progress panels, tool call summaries, usage stats) and stores a structured transcript locally. In an interactive terminal with `--view rich` the CLI may open the post-run transcript viewer automatically; you can also press `Ctrl+T` during streaming to toggle transcript mode. Runtime overrides such as `pii_mapping`, `runtime_config`, or per-tool settings are currently only available via SDK/REST — the CLI forwards the fixed set above.

#### Update

```bash
aip agents update AGENT_REF [OPTIONS]
```

Options:

* `--name TEXT`
* `--instruction TEXT`
* `--tools TOOL_REF`
* `--agents AGENT_REF`
* `--skills SKILL_URL`
* `--timeout INTEGER`
* `--import PATH` — merge updates from exported definition (CLI sanitises language model fields automatically)
* `--view` / `--json`

Updating fetches the latest copy, merges defaults, and issues a full PUT. Passing `--skills` replaces all existing skills; omitting `--skills` preserves the current skill set. Passing empty lists (e.g. `--tools` omitted) keeps current associations; supplying an empty list in an import file clears them.

#### Delete

```bash
aip agents delete AGENT_REF [-y/--yes]
```

Soft-deletes the agent after confirmation (or immediately with `--yes`). Use the SDK/REST to restore soft-deleted agents if needed.

#### Sync LangFlow

```bash
aip agents sync-langflow [--base-url URL] [--api-key KEY]
```

Fetches all flows from the configured LangFlow instance and upserts matching agents. Credentials fall back to `LANGFLOW_BASE_URL` / `LANGFLOW_API_KEY` environment variables.

***

### Tools

#### List

```bash
aip tools list [--type TYPE]
```

* `--type TEXT` — filter by backend tool type (`custom`, `native`, etc.)
* `--view` / `--json`

#### Create

```bash
aip tools create [FILE] [OPTIONS]
```

Options:

* Positional `FILE` or `--file PATH` — path to the plugin Python file
* `--name TEXT` — override inferred plugin name (must match the class `name` attribute)
* `--description TEXT`
* `--tags TEXT` — comma-separated tags
* `--import PATH` — import metadata from exported tool definition (merges with CLI flags)
* `--view` / `--json`

If a file is provided, the CLI validates the plugin `name` attribute, checks for duplicates, and uploads via `/tools/upload`. Metadata-only creation is reserved for imports or native catalog entries.

#### Get

```bash
aip tools get TOOL_REF [OPTIONS]
```

Options:

* `--select INTEGER` — disambiguate by name
* `--export PATH` — export JSON/YAML definition
* `--view` / `--json`

#### Update

```bash
aip tools update TOOL_ID [OPTIONS]
```

Options:

* `--file PATH` — upload new plugin code (only valid for custom tools)
* `--description TEXT` — metadata update (only valid for native tools)
* `--tags TEXT` — comma-separated tags (native tools only)
* `--view` / `--json`

Custom tools support code updates via file upload; native tools support metadata updates. The command enforces these constraints before calling the backend.

#### Delete

```bash
aip tools delete TOOL_ID [-y/--yes]
```

Deletes the tool after confirmation. The underlying API performs a soft delete.

#### Script

```bash
aip tools script TOOL_ID [--view VIEW]
```

Fetches and prints the stored plugin source (`json` view wraps it under `{"script": ...}`).

***

### MCPs (Model Context Protocol)

#### List

```bash
aip mcps list
```

Shows stored MCP connections.

#### Create

```bash
aip mcps create --name NAME --transport TRANSPORT [OPTIONS]
```

Options:

* `--description TEXT`
* `--config JSON` — inline JSON payload (e.g. `'{"url": "https://..."}'`)
* `--view` / `--json`

#### Get

```bash
aip mcps get MCP_REF [--export PATH] [--view VIEW]
```

Resolves names/IDs, optionally exports the definition.

#### Tools

```bash
aip mcps tools MCP_REF
```

Lists tools discovered from a stored MCP connection.

#### Connect (ad-hoc test)

```bash
aip mcps connect --from-file CONFIG.json
```

Loads JSON config from disk, calls `/mcps/connect`, and prints the result. Uses Rich panels unless `--view json` is active.

#### Update

```bash
aip mcps update MCP_REF [OPTIONS]
```

Options:

* `--name TEXT`
* `--description TEXT`
* `--config JSON`
* `--view` / `--json`

The underlying SDK escalates to a full PUT when `name`, `transport`, and `config` are supplied together; the CLI currently exposes `name`, `description`, and `config`, so updates are submitted as partial PATCH requests.

#### Delete

```bash
aip mcps delete MCP_REF [-y/--yes]
```

Soft-delete after confirmation.

***

### Language Models

```bash
aip models list [--view VIEW]
```

Displays available language models for the current API key, including provider and optional base URL overrides. Use this list to locate `language_model_id` values for agent creation.

***

### Configuration & Status

#### Interactive setup

1. **Prompt for API URL and key**

The wizard prompts for API URL and key (with masked input).

2. **Persist to disk**

Persists values to `~/.aip/config.yaml` (0600 permissions).

3. **Test the connection**

Tests the connection by listing agents/tools/MCPs.

#### Legacy config commands (deprecated)

Use `aip accounts ...` for credentials. If you still need the legacy `aip config ...` commands (for example, global settings like `history_default_limit`), see [Legacy Config Commands](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/cli-legacy-config) for gated usage and migration guidance.

#### Status

```bash
aip status
```

Displays the resolved account + source (`flag`/`account:<name>`/`active_profile:<name>`), masks the key, pings the API, and counts agents/tools/MCPs. Useful for smoke tests in CI.

#### Accounts command group

```bash
aip accounts list [--json]
aip accounts show <name> [--json]
aip accounts add <name> [--url URL] [--key [KEY|-]] [--yes]
aip accounts edit <name> [--url URL] [--key [KEY|-]]
aip accounts use <name>
aip accounts rename <current_name> <new_name> [--yes]
aip accounts remove <name> [--yes]
```

* `aip accounts list` renders a table with an active badge; `--json` returns `[{name, api_url, has_key, active}]` (keys are never printed).
* `aip accounts show` prints one profile with masked key and config path; `--json` returns a single object and omits empty metadata fields.
* `aip accounts add` is interactive by default; `--url` + `--key <value>` accepts inline keys, and `--url` + `--key -` (or no value) reads from stdin for scripts. Use `--yes` to overwrite without prompting. Add does not validate connectivity; validation happens when you switch.
* `aip accounts edit` updates an existing profile, prompting for missing fields; `--url` or `--key` can be supplied non‑interactively.
* `aip accounts use` validates connectivity before switching and then sets `active_account` (no offline bypass).
* `aip accounts rename` renames a profile; pass `--yes` to overwrite an existing target name.
* `aip accounts remove` refuses to delete the last profile; if the active profile is removed, the CLI auto-selects `default` (or the next alphabetical) and prints a notice.
* The global `--account <name>` override is available on all commands (hidden; visible via `--help --all`) so you can target a profile without switching it.

***

### Transcripts

#### Transcripts command group

```bash
/transcripts
```

* `/transcripts` shows cached run history captured from `aip agents run` in the local transcript cache.
* In TTY environments, `/transcripts` opens the local transcript browser so you can pick and inspect a run.
* There is currently no dedicated transcript-cleanup command; remove `~/.config/glaip-sdk/transcripts/` manually when you need to clear local cache data.

***

### Import & Export Workflow Tips

* Use `aip agents get <ref> --export agent.yaml` or `aip tools get <ref> --export tool.json` to version configurations alongside code.
* Imported agent files can carry `agent_config` settings for **memory scopes**, **PII mappings**, and **tool output sharing** described in the AIP REST reference. The CLI sanitises language model fields so you can swap between named models and catalogue IDs safely.
* `aip agents run ... --save transcript.md` captures the Rich stream plus final answer; JSON saves include captured debug events for replaying pipelines.
* When scripting, prefer `--view json` to capture machine-friendly responses and avoid control characters from the Rich renderer.

***

### Examples

#### Run an agent with attachments and save the transcript

**Run an agent with attachments**

```bash
aip agents run agent-123 \
  "Summarise the incident and propose mitigation" \
  --file incident-report.pdf \
  --timeout 900 \
  --save incident-summary.md
```

Replace `agent-123` with the ID you captured from `aip agents list`.

#### Import agent configuration from Git

**Import agent from repo**

```bash
# Assuming agent.yaml lives in your repo
aip agents create --import agent.yaml --name "prod-coordinator"
```

#### Sync LangFlow and inspect

**Sync LangFlow and inspect (JSON view)**

```bash
export LANGFLOW_BASE_URL=https://flows.example.com
export LANGFLOW_API_KEY=lfk-123

aip agents list --type langflow --sync-langflow --view json | jq '.[] | {id, name, metadata}'
```

***

### Related documentation

* [Python SDK Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk) — low‑level control with code
* [REST API Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api) — authoritative endpoint catalogue

> The CLI shares the same backend guarantees as the Python SDK. Consult the REST reference for the full payload schema.


# CLI Legacy Config

`aip config ...` is deprecated and gated. Use `aip accounts ...` and `aip accounts add`/`aip accounts use` for credentials whenever possible.

{% hint style="warning" %}
Legacy config commands are disabled by default. Set `AIP_ENABLE_LEGACY_CONFIG=1` to run old scripts while you migrate.
{% endhint %}

### When to use legacy config

* Global settings stored in `~/.aip/config.yaml` (for example `timeout` or `history_default_limit`).
* Short-term compatibility for existing automation.

### Recommended replacements

* `aip config list` → `aip accounts list`
* `aip config configure` → `aip accounts add <name>`
* `aip config set api_url/api_key` → `aip accounts edit <name> --url ... --key ...`
* `aip config get` → `aip accounts show <name>` (or read `~/.aip/config.yaml`)
* `aip config reset` → `aip accounts remove <name>` for each profile

### Legacy commands (gated)

```bash
AIP_ENABLE_LEGACY_CONFIG=1 aip config list
AIP_ENABLE_LEGACY_CONFIG=1 aip config get api_url
AIP_ENABLE_LEGACY_CONFIG=1 aip config set api_url "https://your-aip-instance.com"
AIP_ENABLE_LEGACY_CONFIG=1 aip config set api_key "$AIP_API_KEY"
AIP_ENABLE_LEGACY_CONFIG=1 aip config set history_default_limit 25
AIP_ENABLE_LEGACY_CONFIG=1 aip config unset api_url
AIP_ENABLE_LEGACY_CONFIG=1 aip config reset --force
```

### Audit helper

Use the built-in audit tool to find deprecated config usage in scripts and CI:

```bash
AIP_ENABLE_LEGACY_CONFIG=1 aip config audit --path "**/*.sh" --path "**/*.yml"
```


# CLI Slash Palette

The AIP CLI ships with an interactive command palette that recognises a curated set of slash commands. Launching `aip` with no subcommand in an interactive terminal drops you straight into this palette so you can browse agents, run them, or reconfigure credentials without remembering full Click invocations.

<figure><img src="/files/5Vsq30LrUKgNZHfTHSop" alt=""><figcaption><p>Captured agent workspace shell (TUI) screenshot for visual reference.</p></figcaption></figure>

***

### Launch & Requirements

* Run `aip` without arguments in a TTY-enabled shell to open the palette.
* The palette honours existing CLI context: flags such as `--api-url`, `--api-key`, and `--view` become defaults for the slash commands you trigger.
* `prompt_toolkit` is optional but recommended. When installed, you get inline completions, coloured placeholders, and `/`-aware key bindings. Without it, the CLI falls back to a plain input prompt and prints placeholder hints before the first command.
* The palette checks your credentials up front. If API URL or API key are missing, it launches the `/login` wizard, which stores credentials via `aip accounts add` and revalidates before continuing.
* Slash mode is skipped automatically when STDIN/STDOUT are not TTYs or when you pass `--no-tty`; in those cases the CLI prints regular help output instead.

```bash
aip
```

***

### Global Slash Commands

These commands are always available from the palette home screen and inside agent sessions.

| Command        | Aliases | What it does                                                                                                                                                          | Context                         |
| -------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
| `/help`        | `/?`    | Renders a Rich table of palette commands, showing descriptions and any aliases.                                                                                       | Global & agent                  |
| `/status`      | -       | Runs `aip status` with live Rich output, then suggests quick follow-up actions (recent agents, `/agents`).                                                            | Global & agent                  |
| `/accounts`    | -       | Opens the accounts manager (add/switch profiles) and refreshes the session context so subsequent API calls use the new active profile.                                | Global & agent                  |
| `/transcripts` | -       | Opens the local transcript history browser (cached runs) and lets you inspect the most recent execution details.                                                      | Global & agent                  |
| `/agents`      | -       | Lists available agents using the API client; lets you pick interactively or jump straight to an agent via `/agents <ref>`. Enters the agent run session on selection. | Global (also callable in agent) |
| `/update`      | -       | Upgrades the installed `glaip-sdk` package (same effect as running `aip update` from your shell).                                                                     | Global & agent                  |
| `/exit`        | `/q`    | Leaves the command palette cleanly. When called from an agent session it returns you to the palette home screen.                                                      | Global & agent                  |

`/login` exists for internal onboarding (for example when credentials are missing) and routes to `/accounts`. It is intentionally hidden from the default `/help` inventory.

```
/help
```

<figure><img src="/files/auNLXbhqslSTIVqM3IZL" alt=""><figcaption><p>Captured CLI help snapshot generated from `aip --help`.</p></figcaption></figure>

#### Tips

* Type `/` to trigger inline completion; continue typing to filter commands. Backspace cancels completion when the current token is no longer a slash command.
* Rich quick-action cards appear after `/status`, `/login`, or when you exit an agent session, highlighting the next useful slash commands to try.
* The palette remembers up to five recent agents and shows the most recent one in the status banner so you can re-open it quickly (`/agents <agent-id>`).

***

### Agent Run Session Commands

Picking an agent with `/agents` drops you into a focused prompt tied to that agent. Any plain text you enter runs the agent once; slash commands provide shortcuts to inspect or exit without losing context.

```
/agents
```

<figure><img src="/files/5Vsq30LrUKgNZHfTHSop" alt=""><figcaption><p>Captured `/agents` workspace session view with metadata and composer panel.</p></figcaption></figure>

| Input        | Aliases       | Behaviour                                                                                                                       |
| ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `<message>`  | -             | Executes `aip agents run` for the active agent with the entered prompt. The last input is remembered and displayed in `/help`.  |
| `/details`   | -             | Shows the agent export/config (prompts to expand long instructions when needed).                                                |
| `/skills`    | -             | Shows attached skills. In the TUI workspace, rows show compact skill names plus URL context with sensitive URL portions masked. |
| `/prompt`    | -             | Opens a Textual editor to update the agent instruction (prompt).                                                                |
| `/status`    | -             | Surfaces the same Rich status view without leaving the agent session.                                                           |
| `/runs`      | -             | Opens the remote runs browser for the active agent.                                                                             |
| `/schedules` | -             | Opens the schedules manager for the active agent (create/edit/delete recurring runs).                                           |
| `/help`      | `/?`          | Prints the context-aware help table (agent controls first, reminder that global commands stay available).                       |
| `/exit`      | `/back`, `/q` | Returns to the palette home screen while keeping agent history for quick re-entry.                                              |

#### Agent Prompt UX

* The header highlights the agent name, type, ID, and readiness, followed by shortcut reminders (`/help`, `/details`, `/exit`).
* After each successful run the palette stores the prompt so the help sheet can show the latest input alongside guidance.
* With `prompt_toolkit` installed, `Alt+Enter` inserts a newline and `Ctrl+T` opens the transcript viewer for the most recent run.
* If you press `Ctrl+C`, the current input is cleared and you stay inside the agent session; `Ctrl+D` exits the palette immediately.

#### Skills Display

The workspace sidebar shows compact skill names so long URLs do not crowd the layout:

```
Skills (2)
  - copywriting
  - research
```

Run `/skills` inside an agent session to show the current skill names and URL context in the transcript:

```
Cmd: /skills
Skills (2):
  - copywriting - https://github.com/org/repo/tree/main/skills/copywriting
  - research - https://github.com/org/repo/tree/main/skills/research
```

Credential-bearing URL portions are masked before display. In the TUI workspace, `/skills <url>` is view-only and shows guidance to update skills with `aip agents update <agent-id> --skills <url>` instead.

***

### Non-interactive Execution

While the palette is primarily interactive, the session also supports feeding a list of slash commands programmatically. The CLI skips the palette automatically when STDIN/STDOUT are not TTYs, but you can force a run by calling `SlashSession` directly in scripts or tests.

**example.py**

```python
from glaip_sdk.cli.main import main
from glaip_sdk.cli.slash import SlashSession

ctx = click.Context(main, obj={"api_url": "https://api.example", "api_key": "..."})
session = SlashSession(ctx)
session.run(initial_commands=["/status", "/exit"])
```

> Warning - The public `aip` entry point does not expose a `--slash` flag. Use the Python entry point shown above when orchestrating tests or demos that exercise the palette in a non-interactive environment.

***

### Troubleshooting & FAQ

<details>

<summary>I only see the regular CLI help</summary>

Ensure you're running `aip` inside an interactive terminal (no redirected stdin/stdout) and without `--no-tty`.

</details>

<details>

<summary>Slash completions are missing</summary>

Install `prompt_toolkit>=3.0`. The CLI works without it, but you'll lose dropdown completions and themed placeholders.

</details>

<details>

<summary>API calls fail inside the palette</summary>

`/login` re-runs the credential wizard and refreshes cached config. The header shows API URL and credential status so you can confirm the setup before re-running commands.

</details>


# REST API

Backend API for the GL AIP (GDP Labs AI Agents Package) covering agents, tools, MCP connections, language models, accounts, and utilities. The canonical OpenAPI document is published at <https://aip.glair.ai/docs> and is updated alongside every GL AIP package release.

### Base URLs

| Environment       | Base URL                | Notes                 |
| ----------------- | ----------------------- | --------------------- |
| Production        | `https://aip.glair.ai`  | Use issued API key.   |
| Local development | `http://localhost:8000` | Default FastAPI port. |

All paths documented below are relative to the chosen base URL.

### Authentication

Unless noted, endpoints require an API key presented in the `X-API-Key` header. The specification defines the `APIKeyHeader` security scheme.

{% hint style="info" %}
Include your API key in requests using the `X-API-Key` header:

```http
X-API-Key: <your-api-key>
```

Endpoints marked with `Authentication: None` are publicly accessible (for example, `POST /accounts`).
{% endhint %}

### Response Envelope

Most JSON responses follow this envelope (streaming endpoints return SSE events instead):

```json
{
  "success": true,
  "data": { ... },
  "message": "Operation successful",
  "timestamp": "2024-01-01T00:00:00Z"
}
```

Error responses set `success` to `false` and include an `error` payload with diagnostic context.

### Endpoint Index

* [Health Checks](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/health-checks)
* [Accounts](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/accounts)
* [Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/agents)
* [Tools](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/tools)
* [Model Context Protocol (MCP)](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/mcps)
* [Language Models](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/language-models)
* [Utilities](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/utilities)
* [Schema Components](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/schemas)
* [Human-in-the-Loop Workflow](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/hitl)
* [HITL Audit Log](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/hitl-audit-log)
* [HITL REST Workflow Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/hitl-rest-workflow-guide)


# Agents

### GET /agents/

**Summary:** List all agents with optional filtering

Retrieve a filtered list of agents for display in cards/grids. Supports filtering by type, framework, name (partial match), version, and metadata fields.

Use metadata.{key} syntax for JSON metadata filtering (e.g., metadata.environment=production).

When sync\_langflow\_agents=true is specified, automatically fetches and syncs all available flows from the configured LangFlow server.

This uses the LANGFLOW\_BASE\_URL and LANGFLOW\_API\_KEY environment variables and creates new agents for any flows that don't already exist in the database.

**Authentication:** API key (`X-API-Key` header)

#### Query Parameters

| Name                   | Type    | Required | Description                                                                                                                                                                 |
| ---------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent_type`           | —       | No       | Filter by agent type (config, code, a2a, langflow)                                                                                                                          |
| `framework`            | —       | No       | Filter by framework (langchain, langgraph, google\_adk)                                                                                                                     |
| `name`                 | —       | No       | Filter by partial name match (case-insensitive)                                                                                                                             |
| `version`              | —       | No       | Filter by exact version match                                                                                                                                               |
| `sync_langflow_agents` | boolean | No       | If true, fetches and syncs all available flows from LangFlow server before returning the agent list. Uses LANGFLOW\_BASE\_URL and LANGFLOW\_API\_KEY environment variables. |
|                        |         |          | Creates new agents for any flows that don't exist in the database.                                                                                                          |

**Request Body:** None

#### Responses

| Status | Description                           | Schema                                                     |
| ------ | ------------------------------------- | ---------------------------------------------------------- |
| `200`  | List of agents retrieved successfully | `application/json` — BaseResponse\_list\_AgentListItem\_\_ |
| `422`  | Validation Error                      | `application/json` — HTTPValidationError                   |
| `500`  | Internal server error                 | `application/json` — ErrorResponse                         |

### POST /agents/

**Summary:** Create new agent

Create a new config-based agent with optional tools, sub-agents, and MCP configurations

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

#### Request Body

*Required.*

* `application/json` — [AgentCreate](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/agents#agentcreate)

For complete field specifications, constraints, and validation rules, see the [Agents Schema Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/agents).

#### Responses

| Status | Description                                  | Schema                                                  |
| ------ | -------------------------------------------- | ------------------------------------------------------- |
| `201`  | Agent created successfully                   | `application/json` — BaseResponse\_dict\_str\_\_str\_\_ |
| `400`  | Invalid input data                           | `application/json` — ErrorResponse                      |
| `409`  | Agent with name already exists               | `application/json` — ErrorResponse                      |
| `422`  | Validation error - missing or invalid fields | `application/json` — ErrorResponse                      |
| `500`  | Internal server error                        | `application/json` — ErrorResponse                      |

### POST /agents/langflow/sync

**Summary:** Sync LangFlow agents

Fetch available flows from LangFlow and create agents automatically.

Optionally accepts base\_url and api\_key in request body, with fallback to environment variables.

Can be called with no body to use environment variables only.

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

#### Request Body

* `application/json` — —

#### Responses

| Status | Description                                 | Schema                                    |
| ------ | ------------------------------------------- | ----------------------------------------- |
| `200`  | LangFlow agents synced successfully         | `application/json` — LangflowSyncResponse |
| `400`  | Invalid request data or missing credentials | —                                         |
| `422`  | Validation Error                            | `application/json` — HTTPValidationError  |
| `500`  | Internal server error                       | `application/json` — ErrorResponse        |

### GET /agents/schedules

**Summary:** Get schedules with optional filtering

Get paginated schedules with optional filtering

**Authentication:** API key (`X-API-Key` header)

#### Query Parameters

| Name       | Type    | Required | Description                           |
| ---------- | ------- | -------- | ------------------------------------- |
| `limit`    | integer | No       | Maximum number of schedules to return |
| `page`     | integer | No       | Page number (1-based)                 |
| `agent_id` | —       | No       | Filter by agent ID                    |

**Request Body:** None

#### Responses

| Status | Description                      | Schema                                                             |
| ------ | -------------------------------- | ------------------------------------------------------------------ |
| `200`  | Schedules retrieved successfully | `application/json` — PaginatedResponse\_list\_ScheduleResponse\_\_ |
| `404`  | Agent not found                  | `application/json` — ErrorResponse                                 |
| `422`  | Validation Error                 | `application/json` — HTTPValidationError                           |
| `500`  | Internal server error            | `application/json` — ErrorResponse                                 |

### GET /agents/schedules/{schedule\_id}

**Summary:** Get specific schedule

Get a specific schedule by its ID

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name          | Type          | Required | Description |
| ------------- | ------------- | -------- | ----------- |
| `schedule_id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description                     | Schema                                                |
| ------ | ------------------------------- | ----------------------------------------------------- |
| `200`  | Schedule retrieved successfully | `application/json` — BaseResponse\_ScheduleResponse\_ |
| `404`  | Schedule not found              | `application/json` — ErrorResponse                    |
| `422`  | Validation Error                | `application/json` — HTTPValidationError              |
| `500`  | Internal server error           | `application/json` — ErrorResponse                    |

### PUT /agents/schedules/{schedule\_id}

**Summary:** Update schedule

Update an existing schedule

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name          | Type          | Required | Description |
| ------------- | ------------- | -------- | ----------- |
| `schedule_id` | string (uuid) | Yes      | —           |

#### Request Body

*Required.*

* `application/json` — ScheduleUpdateRequest

#### Responses

| Status | Description                    | Schema                                                |
| ------ | ------------------------------ | ----------------------------------------------------- |
| `200`  | Schedule updated successfully  | `application/json` — BaseResponse\_ScheduleResponse\_ |
| `400`  | Invalid schedule configuration | `application/json` — ErrorResponse                    |
| `404`  | Schedule not found             | `application/json` — ErrorResponse                    |
| `422`  | Invalid schedule format        | `application/json` — ErrorResponse                    |
| `500`  | Internal server error          | `application/json` — ErrorResponse                    |

### DELETE /agents/schedules/{schedule\_id}

**Summary:** Delete schedule

Delete an existing schedule by its ID

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name          | Type          | Required | Description |
| ------------- | ------------- | -------- | ----------- |
| `schedule_id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description                   | Schema                                        |
| ------ | ----------------------------- | --------------------------------------------- |
| `200`  | Schedule deleted successfully | `application/json` — BaseResponse\_NoneType\_ |
| `404`  | Schedule not found            | `application/json` — ErrorResponse            |
| `422`  | Invalid schedule ID format    | `application/json` — ErrorResponse            |
| `500`  | Internal server error         | `application/json` — ErrorResponse            |

### GET /agents/{agent\_id}

**Summary:** Get agent details

Retrieve full agent configuration including tools, sub-agents, and MCP settings

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name       | Type          | Required | Description |
| ---------- | ------------- | -------- | ----------- |
| `agent_id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description                          | Schema                                             |
| ------ | ------------------------------------ | -------------------------------------------------- |
| `200`  | Agent details retrieved successfully | `application/json` — BaseResponse\_AgentResponse\_ |
| `404`  | Agent not found                      | `application/json` — ErrorResponse                 |
| `422`  | Invalid agent ID format              | `application/json` — ErrorResponse                 |
| `500`  | Internal server error                | `application/json` — ErrorResponse                 |

### PUT /agents/{agent\_id}

**Summary:** Update agent (full replacement)

Replace an existing agent's configuration completely, including all relationships

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name       | Type          | Required | Description |
| ---------- | ------------- | -------- | ----------- |
| `agent_id` | string (uuid) | Yes      | —           |

#### Request Body

*Required.*

* `application/json` — [AgentCreate](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/agents#agentcreate)

For complete field specifications, constraints, and validation rules, see the [Agents Schema Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/agents).

#### Responses

| Status | Description                                                          | Schema                                             |
| ------ | -------------------------------------------------------------------- | -------------------------------------------------- |
| `200`  | Agent updated successfully                                           | `application/json` — BaseResponse\_AgentResponse\_ |
| `400`  | Invalid input data                                                   | `application/json` — ErrorResponse                 |
| `404`  | Agent not found                                                      | `application/json` — ErrorResponse                 |
| `409`  | Agent name conflict                                                  | `application/json` — ErrorResponse                 |
| `422`  | Validation error - missing/invalid fields or invalid agent ID format | `application/json` — ErrorResponse                 |
| `500`  | Internal server error                                                | `application/json` — ErrorResponse                 |

### PATCH /agents/{agent\_id}

**Summary:** Partially update agent (sparse patch)

Apply a sparse update to an existing agent. Only explicitly provided fields are validated and changed; omitted fields are preserved.

Current backend PATCH semantics:

* `tools`, `agents`, `mcps`, and `skills` replace the relationship only when explicitly provided; pass `[]` to clear.
* `tool_configs`, `mcp_configs`, and `agent_config` are **deep merged** (recursively) server-side — nested objects are merged, not replaced.
* Deletion-style clears that depend on full replacement should use `PUT`.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name       | Type          | Required | Description |
| ---------- | ------------- | -------- | ----------- |
| `agent_id` | string (uuid) | Yes      | —           |

#### Request Body

*Required.*

* `application/json` — [AgentPatch](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/agents#agentpatch)

For complete field specifications, constraints, and validation rules, see the [Agents Schema Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/agents).

#### Responses

| Status | Description                                                          | Schema                                             |
| ------ | -------------------------------------------------------------------- | -------------------------------------------------- |
| `200`  | Agent patched successfully                                           | `application/json` — BaseResponse\_AgentResponse\_ |
| `400`  | Invalid input data                                                   | `application/json` — ErrorResponse                 |
| `404`  | Agent not found                                                      | `application/json` — ErrorResponse                 |
| `409`  | Agent name conflict                                                  | `application/json` — ErrorResponse                 |
| `422`  | Validation error - missing/invalid fields or invalid agent ID format | `application/json` — ErrorResponse                 |
| `500`  | Internal server error                                                | `application/json` — ErrorResponse                 |

### DELETE /agents/{agent\_id}

**Summary:** Soft delete agent

Soft delete an agent (marks as deleted but preserves data)

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name       | Type          | Required | Description |
| ---------- | ------------- | -------- | ----------- |
| `agent_id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description                | Schema                                                  |
| ------ | -------------------------- | ------------------------------------------------------- |
| `200`  | Agent deleted successfully | `application/json` — BaseResponse\_dict\_str\_\_str\_\_ |
| `404`  | Agent not found            | `application/json` — ErrorResponse                      |
| `422`  | Invalid agent ID format    | `application/json` — ErrorResponse                      |
| `500`  | Internal server error      | `application/json` — ErrorResponse                      |

### POST /agents/{agent\_id}/restore

**Summary:** Restore soft-deleted agent

Restore a soft-deleted agent to active state

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name       | Type          | Required | Description |
| ---------- | ------------- | -------- | ----------- |
| `agent_id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description                    | Schema                                                  |
| ------ | ------------------------------ | ------------------------------------------------------- |
| `200`  | Agent restored successfully    | `application/json` — BaseResponse\_dict\_str\_\_str\_\_ |
| `404`  | Agent not found or not deleted | `application/json` — ErrorResponse                      |
| `422`  | Invalid agent ID format        | `application/json` — ErrorResponse                      |
| `500`  | Internal server error          | `application/json` — ErrorResponse                      |

### POST /agents/{agent\_id}/run

**Summary:** Run agent and get streaming response

Execute an agent and stream the response back. Supports both JSON and form data with file attachments (multipart uploads). When native tools/MCPs require user authentication, the backend may use `gl_connectors_token` for GL Connectors prechecks and runtime propagation.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name       | Type          | Required | Description |
| ---------- | ------------- | -------- | ----------- |
| `agent_id` | string (uuid) | Yes      | —           |

#### Request Body

*Required.*

Supported content types:

* `application/json`
* `multipart/form-data`

Common fields:

| Field                 | Type     | Required | Notes                                                                                 |
| --------------------- | -------- | -------- | ------------------------------------------------------------------------------------- |
| `input`               | `string` | Yes      | User prompt sent to the agent.                                                        |
| `gl_connectors_token` | `string` | No       | Optional GL Connectors token for connector auth checks and runtime token propagation. |
| `chat_history`        | `array`  | No       | Prior conversation turns.                                                             |
| `pii_mapping`         | `object` | No       | Placeholder-to-PII mapping used by PII-aware workflows.                               |
| `runtime_config`      | `object` | No       | Runtime overrides (`tool_configs`, `mcp_configs`, `agent_config`).                    |
| `files`               | `array`  | No       | Multipart only: uploaded files attached to the run request.                           |

#### Responses

| Status | Description                                      | Schema                                                     |
| ------ | ------------------------------------------------ | ---------------------------------------------------------- |
| `200`  | Agent execution started, response is streaming.  | `text/event-stream` (SSE, each `data:` line contains JSON) |
| `400`  | Invalid request data or unsupported content type | `application/json` — ErrorResponse                         |
| `403`  | GL Connectors token is invalid or forbidden      | `application/json` — ErrorResponse                         |
| `404`  | Agent not found                                  | `application/json` — ErrorResponse                         |
| `409`  | Run blocked by GL Connectors precheck            | `application/json` — ErrorResponse                         |
| `422`  | Validation Error                                 | `application/json` — HTTPValidationError                   |
| `502`  | GL Connectors dependency failure                 | `application/json` — ErrorResponse                         |
| `500`  | Internal server error                            | `application/json` — ErrorResponse                         |

### GET /agents/{agent\_id}/runs

**Summary:** Get runs for agent with optional filtering

Get paginated runs for a specific agent with optional filtering

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name       | Type          | Required | Description |
| ---------- | ------------- | -------- | ----------- |
| `agent_id` | string (uuid) | Yes      | —           |

#### Query Parameters

| Name          | Type          | Required | Description                                           |
| ------------- | ------------- | -------- | ----------------------------------------------------- |
| `limit`       | integer       | No       | Maximum number of runs to return                      |
| `page`        | integer       | No       | Page number (1-based)                                 |
| `schedule_id` | string (uuid) | No       | Filter by schedule ID                                 |
| `run_type`    | string        | No       | Filter by run type (schedule)                         |
| `status`      | string        | No       | Filter by execution status (started, success, failed) |

**Request Body:** None

#### Responses

| Status | Description                       | Schema                                                             |
| ------ | --------------------------------- | ------------------------------------------------------------------ |
| `200`  | Agent runs retrieved successfully | `application/json` — PaginatedResponse\_list\_AgentRunResponse\_\_ |
| `404`  | Agent not found                   | `application/json` — ErrorResponse                                 |
| `422`  | Validation Error                  | `application/json` — HTTPValidationError                           |
| `500`  | Internal server error             | `application/json` — ErrorResponse                                 |

### POST /agents/{agent\_id}/schedule

**Summary:** Create schedule for agent

Create a new schedule for an agent with cron-like schedule configuration

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name       | Type          | Required | Description |
| ---------- | ------------- | -------- | ----------- |
| `agent_id` | string (uuid) | Yes      | —           |

#### Request Body

*Required.*

* `application/json` — ScheduleCreateRequest

#### Responses

| Status | Description                    | Schema                                                  |
| ------ | ------------------------------ | ------------------------------------------------------- |
| `201`  | Schedule created successfully  | `application/json` — BaseResponse\_ScheduleCreateData\_ |
| `400`  | Invalid schedule configuration | `application/json` — ErrorResponse                      |
| `404`  | Agent not found                | `application/json` — ErrorResponse                      |
| `422`  | Invalid schedule format        | `application/json` — ErrorResponse                      |
| `500`  | Internal server error          | `application/json` — ErrorResponse                      |


# Tools

### GET /tools/

**Summary:** Get list of tools

Retrieve a list of all tools available in the system. Returns an array of tool objects.

**Authentication:** API key (`X-API-Key` header)

#### Query Parameters

| Name   | Type | Required | Description                            |
| ------ | ---- | -------- | -------------------------------------- |
| `type` | —    | No       | Filter by tool type (native or custom) |

**Request Body:** None

#### Responses

| Status | Description                          | Schema                                                    |
| ------ | ------------------------------------ | --------------------------------------------------------- |
| `200`  | Successfully retrieved list of tools | `application/json` — BaseResponse\_list\_ToolListItem\_\_ |
| `422`  | Validation Error                     | `application/json` — HTTPValidationError                  |

### POST /tools/

**Summary:** Create a new tool

Create a new tool entry by providing tool metadata. Returns the created tool object.

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

#### Request Body

*Required.*

* `application/json` — [ToolBase](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/tools#schema-toolbase)

For complete field specifications, constraints, and validation rules, see the [Tools Schema Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/tools).

#### Responses

| Status | Description               | Schema                                                  |
| ------ | ------------------------- | ------------------------------------------------------- |
| `200`  | Tool created successfully | `application/json` — BaseResponse\_dict\_str\_\_Any\_\_ |
| `422`  | Validation Error          | —                                                       |

### POST /tools/upload

**Summary:** Upload and register a new tool plugin

This endpoint allows uploading a Python file containing a tool plugin class. The plugin will be validated, registered at runtime, and stored in the database.

This endpoint is for creating new tools only, not updating existing ones. For updates, use PUT /tools/{tool\_id}/upload instead.

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

#### Request Body

*Required.*

* `multipart/form-data` — Body\_upload\_and\_register\_plugin\_tools\_upload\_post

#### Responses

| Status | Description                                      | Schema                                                  |
| ------ | ------------------------------------------------ | ------------------------------------------------------- |
| `200`  | Tool plugin uploaded and registered successfully | `application/json` — BaseResponse\_dict\_str\_\_Any\_\_ |
| `400`  | Invalid plugin file                              | —                                                       |
| `409`  | Tool with the same name already exists           | —                                                       |
| `422`  | Validation Error                                 | `application/json` — HTTPValidationError                |
| `500`  | Failed to register plugin                        | —                                                       |

#### Example upload

```bash
curl -X POST "$AIP_API_URL/tools/upload" \
  -H "X-API-Key: $AIP_API_KEY" \
  -F name=calculator \
  -F description="Performs basic arithmetic" \
  -F file=@calculator.py
```

The file `calculator.py` must export a `tool_plugin` entry point. See the [Tools guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools#create-tools) for a full walkthrough of packaging and re-uploading custom tools.

### PUT /tools/{id}

**Summary:** Update tool metadata

Update metadata for an existing tool by its ID. Returns the updated tool object.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name | Type          | Required | Description |
| ---- | ------------- | -------- | ----------- |
| `id` | string (uuid) | Yes      | —           |

#### Request Body

*Required.*

* `application/json` — [ToolBase](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/tools#schema-toolbase)

For complete field specifications, constraints, and validation rules, see the [Tools Schema Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/tools).

#### Responses

| Status | Description               | Schema                                                  |
| ------ | ------------------------- | ------------------------------------------------------- |
| `200`  | Tool updated successfully | `application/json` — BaseResponse\_dict\_str\_\_Any\_\_ |
| `404`  | Tool not found            | —                                                       |
| `422`  | Validation Error          | —                                                       |

### GET /tools/{id}

**Summary:** Get tool details by ID

Retrieve detailed information about a specific tool by its ID.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name | Type          | Required | Description |
| ---- | ------------- | -------- | ----------- |
| `id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description                         | Schema                                                  |
| ------ | ----------------------------------- | ------------------------------------------------------- |
| `200`  | Tool details retrieved successfully | `application/json` — BaseResponse\_dict\_str\_\_Any\_\_ |
| `404`  | Tool not found                      | —                                                       |
| `422`  | Validation Error                    | `application/json` — HTTPValidationError                |

### DELETE /tools/{id}

**Summary:** Delete a tool

Delete a specific tool by its ID. Returns a confirmation message upon successful deletion.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name | Type          | Required | Description |
| ---- | ------------- | -------- | ----------- |
| `id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description               | Schema                                                  |
| ------ | ------------------------- | ------------------------------------------------------- |
| `200`  | Tool deleted successfully | `application/json` — BaseResponse\_dict\_str\_\_str\_\_ |
| `404`  | Tool not found            | —                                                       |
| `422`  | Validation Error          | `application/json` — HTTPValidationError                |

### POST /tools/{id}/restore

**Summary:** Restore a soft-deleted tool

Restore a soft-deleted tool to an active state.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name | Type          | Required | Description |
| ---- | ------------- | -------- | ----------- |
| `id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description                   | Schema                                                  |
| ------ | ----------------------------- | ------------------------------------------------------- |
| `200`  | Tool restored successfully    | `application/json` — BaseResponse\_dict\_str\_\_str\_\_ |
| `404`  | Tool not found or not deleted | —                                                       |
| `422`  | Validation Error              | `application/json` — HTTPValidationError                |

### GET /tools/{tool\_id}/script

**Summary:** Get the script content for a tool

Retrieve the Python script content for a specific tool by its ID.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name      | Type   | Required | Description |
| --------- | ------ | -------- | ----------- |
| `tool_id` | string | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description                        | Schema                                                  |
| ------ | ---------------------------------- | ------------------------------------------------------- |
| `200`  | Tool script retrieved successfully | `application/json` — BaseResponse\_dict\_str\_\_Any\_\_ |
| `404`  | Tool or script not found           | —                                                       |
| `422`  | Validation Error                   | `application/json` — HTTPValidationError                |

### PUT /tools/{tool\_id}/upload

**Summary:** Update a tool plugin via file upload

This endpoint allows updating an existing tool plugin by uploading a new Python file. The plugin will be validated, registered at runtime, and the database record will be updated.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name      | Type          | Required | Description                  |
| --------- | ------------- | -------- | ---------------------------- |
| `tool_id` | string (uuid) | Yes      | The ID of the tool to update |

#### Request Body

*Required.*

* `multipart/form-data` — Body\_update\_tool\_via\_upload\_tools\_\_tool\_id\_\_upload\_put

#### Responses

| Status | Description                      | Schema                                                  |
| ------ | -------------------------------- | ------------------------------------------------------- |
| `200`  | Tool plugin updated successfully | `application/json` — BaseResponse\_dict\_str\_\_Any\_\_ |
| `400`  | Invalid plugin file              | —                                                       |
| `404`  | Tool not found                   | —                                                       |
| `422`  | Validation Error                 | `application/json` — HTTPValidationError                |
| `500`  | Failed to update plugin          | —                                                       |


# MCPs

### GET /mcps/

**Summary:** List all MCPs

Retrieve a list of all MCP configurations, optionally including related resources (e.g., tools).

Args: mcp\_service: Injected MCP service dependency. account\_id: Account ID from API key (None for master API key) include: If set to 'tools', include tools for each MCP validate\_mcp\_params: Injected MCP query parameter validator dependency.

Returns: MCPWithToolsListResponse | MCPListResponse: Response containing a list of MCPs, each with an optional tools field.

Raises: StandardHTTPException: If a database error occurs.

**Authentication:** API key (`X-API-Key` header)

#### Query Parameters

| Name      | Type   | Required | Description                                                                                 |
| --------- | ------ | -------- | ------------------------------------------------------------------------------------------- |
| `include` | string | No       | Comma-separated list of related resources to include. Currently, only 'tools' is supported. |

**Request Body:** None

#### Responses

| Status | Description                         | Schema                                   |
| ------ | ----------------------------------- | ---------------------------------------- |
| `200`  | List of MCPs retrieved successfully | `application/json` — —                   |
| `422`  | Validation Error                    | `application/json` — HTTPValidationError |
| `500`  | Internal server error               | `application/json` — ErrorResponse       |

### POST /mcps/

**Summary:** Create a new MCP

Create a new MCP configuration.

Args: mcp: The MCP configuration data. mcp\_service: Injected MCP service dependency. account\_id: Account ID from API key (None for master API key)

Returns: MCPCreateResponse: Response containing the ID of the created MCP.

Raises: StandardHTTPException: If an MCP with the same name already exists (409) or if another database error occurs.

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

#### Request Body

*Required.*

* `application/json` — [MCPCreate](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/mcps#schema-mcpcreate)

For complete field specifications, constraints, and validation rules, see the [MCP Schema Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/mcps).

#### Responses

| Status | Description                                  | Schema                                                  |
| ------ | -------------------------------------------- | ------------------------------------------------------- |
| `201`  | MCP created successfully                     | `application/json` — BaseResponse\_dict\_str\_\_str\_\_ |
| `400`  | Invalid input data                           | `application/json` — ErrorResponse                      |
| `422`  | Validation error - missing or invalid fields | `application/json` — ErrorResponse                      |
| `500`  | Internal server error                        | `application/json` — ErrorResponse                      |

### POST /mcps/connect

**Summary:** Test MCP Connection

Tests the connection to an MCP server using the provided configuration without saving it.

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

#### Request Body

*Required.*

* `application/json` — [MCPConnectionTestRequest](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/mcps#connection-test-schemas)

#### Responses

| Status | Description                                    | Schema                                                  |
| ------ | ---------------------------------------------- | ------------------------------------------------------- |
| `200`  | Connection successful                          | `application/json` — BaseResponse\_dict\_str\_\_str\_\_ |
| `400`  | Invalid input data                             | `application/json` — ErrorResponse                      |
| `422`  | Validation Error                               | `application/json` — HTTPValidationError                |
| `500`  | Internal server error                          | `application/json` — ErrorResponse                      |
| `503`  | Service unavailable (e.g., connection refused) | `application/json` — ErrorResponse                      |

### POST /mcps/connect/tools

**Summary:** Fetch tools from an MCP configuration

Fetches the list of tools from an MCP server using the provided configuration without saving it.

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

#### Request Body

*Required.*

* `application/json` — [MCPConnectionTestRequest](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/mcps#connection-test-schemas)

#### Responses

| Status | Description                                    | Schema                                                   |
| ------ | ---------------------------------------------- | -------------------------------------------------------- |
| `200`  | Tools retrieved successfully                   | `application/json` — BaseResponse\_MCPToolListResponse\_ |
| `400`  | Invalid input data                             | `application/json` — ErrorResponse                       |
| `422`  | Validation Error                               | `application/json` — HTTPValidationError                 |
| `500`  | Internal server error                          | `application/json` — ErrorResponse                       |
| `503`  | Service unavailable (e.g., connection refused) | `application/json` — ErrorResponse                       |

### GET /mcps/{mcp\_id}

**Summary:** Get MCP by ID

Retrieve a single MCP configuration by its unique ID, optionally including related resources (e.g., tools).

Args: mcp\_id: The unique identifier of the MCP. mcp\_service: Injected MCP service dependency. account\_id: Account ID from API key (None for master API key) include: If set to 'tools', include tools for this MCP. validate\_mcp\_params: Injected MCP query parameter validator dependency.

Returns: MCPDetailResponse or MCPDetailWithToolsResponse: Response containing the MCP details.

Raises: StandardHTTPException: If the MCP is not found (404) or a database error occurs.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name     | Type          | Required | Description |
| -------- | ------------- | -------- | ----------- |
| `mcp_id` | string (uuid) | Yes      | —           |

#### Query Parameters

| Name      | Type   | Required | Description                                                                                 |
| --------- | ------ | -------- | ------------------------------------------------------------------------------------------- |
| `include` | string | No       | Comma-separated list of related resources to include. Currently, only 'tools' is supported. |

**Request Body:** None

#### Responses

| Status | Description                | Schema                             |
| ------ | -------------------------- | ---------------------------------- |
| `200`  | MCP retrieved successfully | `application/json` — —             |
| `404`  | MCP not found              | `application/json` — ErrorResponse |
| `422`  | Invalid MCP ID format      | `application/json` — ErrorResponse |
| `500`  | Internal server error      | `application/json` — ErrorResponse |

### PUT /mcps/{mcp\_id}

**Summary:** Update an MCP

Update an existing MCP configuration.

Args: mcp\_id: The unique identifier of the MCP to update. mcp: The updated MCP data. mcp\_service: Injected MCP service dependency. account\_id: Account ID from API key (None for master API key)

Returns: MCPDetailResponse: Response containing the updated MCP details.

Raises: StandardHTTPException: If the MCP is not found (404) or a database error (e.g., unique constraint) occurs.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name     | Type          | Required | Description |
| -------- | ------------- | -------- | ----------- |
| `mcp_id` | string (uuid) | Yes      | —           |

#### Request Body

*Required.*

* `application/json` — [MCPCreate](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/mcps#schema-mcpcreate)

#### Responses

| Status | Description                                                        | Schema                                           |
| ------ | ------------------------------------------------------------------ | ------------------------------------------------ |
| `200`  | MCP updated successfully                                           | `application/json` — BaseResponse\_MCPResponse\_ |
| `400`  | Invalid input data                                                 | `application/json` — ErrorResponse               |
| `404`  | MCP not found                                                      | `application/json` — ErrorResponse               |
| `422`  | Validation error - missing/invalid fields or invalid MCP ID format | `application/json` — ErrorResponse               |
| `500`  | Internal server error                                              | `application/json` — ErrorResponse               |

### PATCH /mcps/{mcp\_id}

**Summary:** Update an MCP Partially

Update an existing MCP configuration partially.

Args: mcp\_id: The unique identifier of the MCP to update. mcp: The updated MCP data (partial update). mcp\_service: Injected MCP service dependency. account\_id: Account ID from API key (None for master API key)

Returns: MCPDetailResponse: Response containing the updated MCP details.

Raises: StandardHTTPException: If the MCP is not found (404) or a database error (e.g., unique constraint) occurs.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name     | Type          | Required | Description |
| -------- | ------------- | -------- | ----------- |
| `mcp_id` | string (uuid) | Yes      | —           |

#### Request Body

*Required.*

* `application/json` — [MCPPatch](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/mcps#schema-mcppatch)

#### Responses

| Status | Description                                                        | Schema                                           |
| ------ | ------------------------------------------------------------------ | ------------------------------------------------ |
| `200`  | MCP updated successfully                                           | `application/json` — BaseResponse\_MCPResponse\_ |
| `400`  | Invalid input data                                                 | `application/json` — ErrorResponse               |
| `404`  | MCP not found                                                      | `application/json` — ErrorResponse               |
| `422`  | Validation error - missing/invalid fields or invalid MCP ID format | `application/json` — ErrorResponse               |
| `500`  | Internal server error                                              | `application/json` — ErrorResponse               |

### DELETE /mcps/{mcp\_id}

**Summary:** Delete an MCP

Soft delete an MCP configuration by its ID.

Args: mcp\_id: The unique identifier of the MCP to delete. mcp\_service: Injected MCP service dependency. account\_id: Account ID from API key (None for master API key)

Returns: MCPDeleteResponse: Response indicating successful deletion.

Raises: StandardHTTPException: If the MCP is not found (404) or a database error occurs.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name     | Type          | Required | Description |
| -------- | ------------- | -------- | ----------- |
| `mcp_id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description              | Schema                                                  |
| ------ | ------------------------ | ------------------------------------------------------- |
| `200`  | MCP deleted successfully | `application/json` — BaseResponse\_dict\_str\_\_str\_\_ |
| `404`  | MCP not found            | `application/json` — ErrorResponse                      |
| `422`  | Invalid MCP ID format    | `application/json` — ErrorResponse                      |
| `500`  | Internal server error    | `application/json` — ErrorResponse                      |

### POST /mcps/{mcp\_id}/restore

**Summary:** Restore soft-deleted MCP

Restore a soft-deleted MCP to active state

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name     | Type          | Required | Description |
| -------- | ------------- | -------- | ----------- |
| `mcp_id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description               | Schema                                                  |
| ------ | ------------------------- | ------------------------------------------------------- |
| `200`  | MCP restored successfully | `application/json` — BaseResponse\_dict\_str\_\_str\_\_ |
| `404`  | MCP not found             | `application/json` — ErrorResponse                      |
| `422`  | Invalid MCP ID format     | `application/json` — ErrorResponse                      |
| `500`  | Internal server error     | `application/json` — ErrorResponse                      |

### GET /mcps/{mcp\_id}/tools

**Summary:** List tools from MCP

Retrieve a list of tools from a specific MCP server with proper session management.

Args: mcp\_id: The ID of the MCP to fetch tools from mcp\_service\_factory: Factory for creating MCP service instances with proper session management account\_id: Account ID from API key (None for master API key)

Returns: MCPToolListStandardResponse containing the list of tools available from the MCP

Raises: HTTPException: If MCP is not found or tools cannot be fetched

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name     | Type          | Required | Description |
| -------- | ------------- | -------- | ----------- |
| `mcp_id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description                         | Schema                                                   |
| ------ | ----------------------------------- | -------------------------------------------------------- |
| `200`  | Tools retrieved successfully        | `application/json` — BaseResponse\_MCPToolListResponse\_ |
| `404`  | MCP not found or URL not configured | `application/json` — ErrorResponse                       |
| `422`  | Invalid MCP ID format               | `application/json` — ErrorResponse                       |
| `500`  | Failed to fetch tools from MCP      | `application/json` — ErrorResponse                       |


# Language Models

### GET /language-models/

**Summary:** Get All Language Models

Get all language models.

Args: lm\_service (LanguageModelService, optional): The service to handle language model operations. Defaults to Depends(get\_language\_model\_service). api\_key (str, optional): The API key for authentication. Defaults to Depends(verify\_api\_key).

Returns: LanguageModelListResponse: A response object containing a list of all language models.

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

**Request Body:** None

#### Responses

| Status | Description         | Schema                                                             |
| ------ | ------------------- | ------------------------------------------------------------------ |
| `200`  | Successful Response | `application/json` — BaseResponse\_list\_LanguageModelResponse\_\_ |

### POST /language-models/

**Summary:** Create Language Model

Create a new language model.

Args: lm\_data (LanguageModelCreate): The data for creating the new language model. lm\_service (LanguageModelService, optional): The service to handle language model operations. Defaults to Depends(get\_language\_model\_service). api\_key (str, optional): The API key for authentication. Defaults to Depends(verify\_master\_api\_key).

Returns: LanguageModelDetailResponse: A response object containing the newly created language model's details.

Raises: StandardHTTPException: If a language model with the same provider and name already exists.

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

#### Request Body

*Required.*

* `application/json` — LanguageModelCreate

#### Responses

| Status | Description         | Schema                                                     |
| ------ | ------------------- | ---------------------------------------------------------- |
| `201`  | Successful Response | `application/json` — BaseResponse\_LanguageModelResponse\_ |
| `422`  | Validation Error    | `application/json` — HTTPValidationError                   |

### GET /language-models/{lm\_id}

**Summary:** Get Language Model

Get a specific language model by its ID.

Args: lm\_id (UUID): The unique identifier of the language model to retrieve. lm\_service (LanguageModelService, optional): The service to handle language model operations. Defaults to Depends(get\_language\_model\_service). api\_key (str, optional): The API key for authentication. Defaults to Depends(verify\_api\_key).

Returns: LanguageModelDetailResponse: A response object containing the details of the requested language model.

Raises: StandardHTTPException: If no language model is found with the specified ID.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name    | Type          | Required | Description |
| ------- | ------------- | -------- | ----------- |
| `lm_id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description         | Schema                                                     |
| ------ | ------------------- | ---------------------------------------------------------- |
| `200`  | Successful Response | `application/json` — BaseResponse\_LanguageModelResponse\_ |
| `422`  | Validation Error    | `application/json` — HTTPValidationError                   |

### PUT /language-models/{lm\_id}

**Summary:** Update Language Model

Update a specific language model.

Args: lm\_id (UUID): The unique identifier of the language model to update. lm\_data (LanguageModelUpdate): The new data for updating the language model. lm\_service (LanguageModelService, optional): The service to handle language model operations. Defaults to Depends(get\_language\_model\_service). api\_key (str, optional): The API key for authentication. Defaults to Depends(verify\_master\_api\_key).

Returns: LanguageModelDetailResponse: A response object containing the updated language model's details.

Raises: StandardHTTPException: If no language model is found with the specified ID, or if the update would violate the unique constraint.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name    | Type          | Required | Description |
| ------- | ------------- | -------- | ----------- |
| `lm_id` | string (uuid) | Yes      | —           |

#### Request Body

*Required.*

* `application/json` — LanguageModelUpdate

#### Responses

| Status | Description         | Schema                                                     |
| ------ | ------------------- | ---------------------------------------------------------- |
| `200`  | Successful Response | `application/json` — BaseResponse\_LanguageModelResponse\_ |
| `422`  | Validation Error    | `application/json` — HTTPValidationError                   |

### DELETE /language-models/{lm\_id}

**Summary:** Delete Language Model

Delete a specific language model.

Args: lm\_id (UUID): The unique identifier of the language model to delete. lm\_service (LanguageModelService, optional): The service to handle language model operations. Defaults to Depends(get\_language\_model\_service). api\_key (str, optional): The API key for authentication. Defaults to Depends(verify\_master\_api\_key).

Returns: LanguageModelDeleteResponse: A response object confirming the deletion.

Raises: StandardHTTPException: If no language model is found with the specified ID.

**Authentication:** API key (`X-API-Key` header)

#### Path Parameters

| Name    | Type          | Required | Description |
| ------- | ------------- | -------- | ----------- |
| `lm_id` | string (uuid) | Yes      | —           |

**Request Body:** None

#### Responses

| Status | Description         | Schema                                                   |
| ------ | ------------------- | -------------------------------------------------------- |
| `200`  | Successful Response | `application/json` — BaseResponse\_dict\_str\_\_UUID\_\_ |
| `422`  | Validation Error    | `application/json` — HTTPValidationError                 |


# HITL

Use these endpoints to orchestrate Human-in-the-Loop (HITL) pauses from a client application: register a tool, create an agent, stream run updates, and resolve approval requests.

### Prerequisites

* Backend service reachable at `$BACKEND_URL` (default: `http://localhost:8000`).
* API key with access to the HITL endpoints (`X-API-Key` header).

Examples below assume the API key is stored in `$AIP_MASTER_API_KEY`.

### 1. Create an Agent with HITL Enabled

```bash
curl -X POST "$BACKEND_URL/agents/" \
  -H "X-API-Key: $AIP_MASTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d @agent_payload.json
```

Sample `agent_payload.json`:

```json
{
  "name": "hitl_approval_agent",
  "instruction": "Whenever an action needs approval, call the custom_tool first.",
  "type": "config",
  "framework": "langchain",
  "version": "1.0",
  "tools": ["<TOOL_ID_FROM_UPLOAD>"],
  "agent_config": {
    "hitl_enabled": true,
    "lm_provider": "openai",
    "lm_name": "gpt-4.1"
  },
  "tool_configs": {
    "<TOOL_ID_FROM_UPLOAD>": {
      "hitl": {
        "timeout_seconds": 180
      }
    }
  }
}
```

The response JSON returns a new `agent_id`.

### 2. Run the Agent and Watch for HITL Pauses

```bash
curl -N -X POST "$BACKEND_URL/agents/<AGENT_ID>/run" \
  -H "X-API-Key: $AIP_MASTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "input": "Please send an offer email to jane.doe@example.com and update her ATS record."
      }'
```

The call returns an SSE stream. When a tool requires human approval the chunks include a `metadata.hitl` object. Example payload captured from the integration test (`notes/hitl_e2e_run_raw.log`):

```json
{
  "status": "success",
  "task_state": "working",
  "content": "Awaiting human approval for request 'bc4d0a77-7800-470e-a91c-7fd663a66b4d'. Invoke ApprovalManager.resolve_pending_request using this identifier to continue execution.",
  "metadata": {
    "kind": "agent_thinking_step",
    "status": "finished",
    "hitl": {
      "required": true,
      "decision": "pending",
      "request_id": "bc4d0a77-7800-470e-a91c-7fd663a66b4d",
      "timeout_at": "2025-10-14T01:56:22.464367+00:00",
      "timeout_seconds": 10
    },
    "tool_info": {
      "id": "call_UHU9hq7rfikCrTLhImGmRx37",
      "name": "custom_tool",
      "args": {},
      "output": "Awaiting human approval for request 'bc4d0a77-7800-470e-a91c-7fd663a66b4d'. Invoke ApprovalManager.resolve_pending_request using this identifier to continue execution.",
      "execution_time": null
    }
  }
}
```

Key fields to capture:

* `metadata.hitl.request_id` — unique identifier for the pending approval (UUID).
* `metadata.hitl.decision` — current state. Expect at least `pending`, `approved`, `rejected`, or `timeout_skip`.
* `metadata.hitl.timeout_at` — ISO 8601 timestamp when the HITL request will timeout if no decision is made (UTC+0 timezone)
* `metadata.hitl.timeout_seconds` — static value of timeout duration in seconds for the HITL request (configured per tool with tool config)
* `metadata.tool_info` — context about the tool invocation (call id, tool name, arguments, output) for use in operator UIs.

Maintain the SSE connection while the operator decides so your client receives the resumed tokens once the request is resolved.

### 3. Resolve a HITL Request

Use the `request_id` from the stream (or from the pending inbox endpoint) when calling the decision API.

```bash
curl -X POST "$BACKEND_URL/agents/hitl/decision" \
  -H "X-API-Key: $AIP_MASTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "request_id": "bc4d0a77-7800-470e-a91c-7fd663a66b4d",
        "decision": "approved",
        "operator_input": "Looks good",
        "run_id": "optional-client-tracker"
      }'
```

Required fields:

* `request_id` — matches the identifier from the SSE chunk.
* `decision` — one of `approved`, `rejected`, or `skipped`.

Optional fields:

* `operator_input` — free-form notes for audit trails (defaults to `""`).
* `run_id` — client-side correlation identifier if you track sessions.

The endpoint returns `{"status": "ok", "message": "Request <id> <decision>"}` on success. The corresponding SSE stream delivers a new chunk reflecting the final decision so your client can update local state.

### 4. Optional: List Pending HITL Requests

```bash
curl -X GET "$BACKEND_URL/agents/hitl/pending" \
  -H "X-API-Key: $AIP_MASTER_API_KEY"
```

Sample response:

```json
[
  {
    "request_id": "bc4d0a77-7800-470e-a91c-7fd663a66b4d",
    "tool": "custom_tool",
    "arguments": {
      "action": "Finalize Jane Doe's hiring decision in the ATS for the Senior Backend Engineer role, including score and recommendation to move forward with offer."
    },
    "created_at": "2025-10-08T14:41:01.553063+00:00",
    "agent_id": "hitl_approval_agent-a44ac39b",
    "run_id": null,
    "hitl_metadata": {
      "required": true,
      "decision": "pending",
      "timeout_at": "2025-10-08T15:41:01.553063+00:00",
      "timeout_seconds": 180
    },
    "additional_context": {
      "tool_name": "custom_tool",
      "arguments": {
        "action": "Finalize Jane Doe's hiring decision in the ATS for the Senior Backend Engineer role, including score and recommendation to move forward with offer."
      },
      "agent_id": "hitl_approval_agent-a44ac39b"
    }
  }
]
```

The runner tracks these requests in-memory, so restarts clear the list. Treat this endpoint as a real-time inbox rather than an audit log.

### 5. Optional Cleanup

* Delete agent: `DELETE /agents/<AGENT_ID>`
* Delete tool: `DELETE /tools/<TOOL_ID>`

Keep cleanup scripts handy for integration tests so temporary resources do not accumulate in your tenant.


# HITL Audit Log

Reference notes for HITL audit visibility.

This page documents how to capture operator decisions and approval history when using Human-in-the-Loop (HITL) workflows.

### Scope

Use this page with the core HITL endpoints in:

* [HITL REST Workflow](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/hitl)

### Audit Data to Persist

For each HITL request, persist at least:

* `request_id`
* `agent_id`
* `run_id`
* `decision` (`approved`, `rejected`, `skipped`, `timeout_skip`)
* `operator_input`
* `created_at`
* `resolved_at`
* `timeout_at`
* tool context (`tool_name`, arguments snapshot)

### Recommended Pattern

1. Stream run events and capture `metadata.hitl.*` fields.
2. On operator action, submit decision via the HITL decision endpoint.
3. Store both pending snapshot and final decision record in your audit store.
4. Correlate with your own user/session identifiers for compliance reporting.

### Notes

* The pending HITL endpoint is an operational inbox, not a durable audit store.
* Persist audit records in your own system of record.


# HITL Workflow

Step-by-step reference for Human-in-the-Loop (HITL) REST orchestration.

### Primary Workflow

Use the canonical workflow page:

* [HITL](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/hitl)

That page covers:

1. Agent creation with HITL enabled.
2. Streaming execution and pause detection.
3. Decision submission (`approved`, `rejected`, `skipped`).
4. Pending request listing.

### Integration Checklist

* Keep SSE connection active while waiting for operator decisions.
* Surface `request_id` and timeout metadata in operator UI.
* Handle timeout paths explicitly (`timeout_skip`).
* Persist operator rationale for post-run audit and review.

### Related

* [HITL Audit Log](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/hitl-audit-log)
* [Agents REST Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/agents)


# Accounts

The accounts API supports 2 account types: normal and account-creator. Normal accounts can be created by the platform key or an account-creator key. Account-creator accounts can only be created by the platform key and can only create normal accounts. All other account lifecycle operations are reserved for platform operators and are intentionally omitted here.

### POST /accounts/

**Summary:** Create new account

Create a new account with a unique name and generate an API key. There are 2 account types: normal and account-creator. Normal account creation accepts a platform key (master key) or an account-creator key. Creating an account-creator account requires the platform key.

**Authentication:** `X-API-Key` required for account creation. Normal accounts accept a platform key or an account-creator key; account-creator accounts require the platform key.

Account-creator accounts can also manage their own keys through the tenant `/api-keys` endpoints for rotation and revocation within the same account.

**Parameters:** None

#### Request Body

*Required.*

* `application/json` — AccountCreateRequest

#### Examples

**Create a normal account**

```bash
curl -X POST "$AIP_BASE_URL/accounts/" \
  -H "X-API-Key: $AIP_MASTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-organization"
  }'
```

**Response (201):**

```json
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "api_key": "aip_xxxxxxxxxxxxxxxxx",
    "account_type": "normal"
  },
  "message": "Account created successfully"
}
```

**Create an account-creator account**

```bash
curl -X POST "$AIP_BASE_URL/accounts/" \
  -H "X-API-Key: $AIP_MASTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-creator",
    "account_type": "account_creator"
  }'
```

**Response (201):**

```json
{
  "success": true,
  "data": {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "api_key": "aip_yyyyyyyyyyyyyyyyy",
    "account_type": "account_creator"
  },
  "message": "Account created successfully"
}
```

#### Responses

| Status | Description                      | Schema                                     |
| ------ | -------------------------------- | ------------------------------------------ |
| `201`  | Account created successfully     | `application/json` — AccountCreateResponse |
| `400`  | Invalid input data               | —                                          |
| `409`  | Account with name already exists | —                                          |
| `422`  | Validation Error                 | `application/json` — HTTPValidationError   |
| `500`  | Internal server error            | —                                          |


# Schemas

| Name                                                     | Description                                                                                                                                                                                                         |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `A2AProfile`                                             | Schema for A2A (Agent-to-Agent) profile configuration.                                                                                                                                                              |
| `AccountCreateData`                                      | Response data for account creation.                                                                                                                                                                                 |
| `AccountCreateRequest`                                   | Request model for creating an account.                                                                                                                                                                              |
| `AccountCreateResponse`                                  | Response model for account creation.                                                                                                                                                                                |
| `AccountListResponse`                                    | Response model for account list.                                                                                                                                                                                    |
| `AccountResponse`                                        | Response model for account information.                                                                                                                                                                             |
| `AccountResponseData`                                    | Response data for account information.                                                                                                                                                                              |
| `AgentCreate`                                            | Schema for creating an agent.                                                                                                                                                                                       |
| `AgentFramework`                                         | Enumeration of supported agent frameworks.                                                                                                                                                                          |
| `AgentListItem`                                          | Schema for individual agent in list responses (simplified for cards/details).                                                                                                                                       |
| `AgentReference`                                         | Schema for agent references in agent responses.                                                                                                                                                                     |
| `AgentResponse`                                          | Schema for agent responses.                                                                                                                                                                                         |
| `AgentRunResponse`                                       | Response model for agent run history.                                                                                                                                                                               |
| `AgentRunStatus`                                         | Enum for agent run status values.                                                                                                                                                                                   |
| `AgentRunType`                                           | Enum for agent run type values.                                                                                                                                                                                     |
| `AgentType`                                              | Enumeration of agent types.                                                                                                                                                                                         |
| `BaseResponse_AgentResponse_`                            | —                                                                                                                                                                                                                   |
| `BaseResponse_LanguageModelResponse_`                    | —                                                                                                                                                                                                                   |
| `BaseResponse_MCPDetailWithTools_`                       | —                                                                                                                                                                                                                   |
| `BaseResponse_MCPResponse_`                              | —                                                                                                                                                                                                                   |
| `BaseResponse_MCPToolListResponse_`                      | —                                                                                                                                                                                                                   |
| `BaseResponse_NoneType_`                                 | —                                                                                                                                                                                                                   |
| `BaseResponse_ScheduleCreateData_`                       | —                                                                                                                                                                                                                   |
| `BaseResponse_ScheduleResponse_`                         | —                                                                                                                                                                                                                   |
| `BaseResponse_dict_`                                     | —                                                                                                                                                                                                                   |
| `BaseResponse_dict_str__Any__`                           | —                                                                                                                                                                                                                   |
| `BaseResponse_dict_str__UUID__`                          | —                                                                                                                                                                                                                   |
| `BaseResponse_dict_str__str__`                           | —                                                                                                                                                                                                                   |
| `BaseResponse_list_AgentListItem__`                      | —                                                                                                                                                                                                                   |
| `BaseResponse_list_LanguageModelResponse__`              | —                                                                                                                                                                                                                   |
| `BaseResponse_list_MCPListItem__`                        | —                                                                                                                                                                                                                   |
| `BaseResponse_list_MCPWithToolsItem__`                   | —                                                                                                                                                                                                                   |
| `BaseResponse_list_ToolListItem__`                       | —                                                                                                                                                                                                                   |
| `Body_update_tool_via_upload_tools__tool_id__upload_put` | —                                                                                                                                                                                                                   |
| `Body_upload_and_register_plugin_tools_upload_post`      | —                                                                                                                                                                                                                   |
| `ErrorResponse`                                          | Schema for error responses.                                                                                                                                                                                         |
| `HTTPValidationError`                                    | —                                                                                                                                                                                                                   |
| `HealthCheckResponse`                                    | Health check response model. Attributes: status: The status of the service. message: A descriptive message about the service state. details: Optional additional details about the service state.                   |
| `LangflowSyncRequest`                                    | Request model for LangFlow synchronization.                                                                                                                                                                         |
| `LangflowSyncResponse`                                   | Response model for LangFlow synchronization operations.                                                                                                                                                             |
| `LangflowSyncResponseData`                               | Data payload for LangFlow synchronization response.                                                                                                                                                                 |
| `LanguageModelCreate`                                    | Model for creating a new language model configuration.                                                                                                                                                              |
| `LanguageModelResponse`                                  | Model for the response of a language model configuration.                                                                                                                                                           |
| `LanguageModelUpdate`                                    | Model for updating a language model configuration. All fields are optional.                                                                                                                                         |
| `MCPConfig`                                              | Schema for MCP configuration including descriptive fields.                                                                                                                                                          |
| `MCPConnectionTestRequest`                               | Pydantic model for testing an MCP connection without saving it. This model is used as the request body for the connection test endpoints. It has the same structure as creating a new MCP, but it is not persisted. |
| `MCPCreate`                                              | Pydantic model for creating a new MCP. Inherits all fields from MCPBase. All non-optional fields in MCPBase are required.                                                                                           |
| `MCPDetailWithTools`                                     | —                                                                                                                                                                                                                   |
| `MCPListItem`                                            | —                                                                                                                                                                                                                   |
| `MCPPatch`                                               | Pydantic model for updating an existing MCP. User can update MCP partially.                                                                                                                                         |
| `MCPResponse`                                            | —                                                                                                                                                                                                                   |
| `MCPToolDefinition`                                      | Pydantic model representing a single tool provided by an MCP server.                                                                                                                                                |
| `MCPToolListResponse`                                    | Pydantic model for the response containing a list of MCP tools.                                                                                                                                                     |
| `MCPWithToolsItem`                                       | —                                                                                                                                                                                                                   |
| `PaginatedResponse_list_AgentRunResponse__`              | —                                                                                                                                                                                                                   |
| `PaginatedResponse_list_ScheduleResponse__`              | —                                                                                                                                                                                                                   |
| `PresignedUrlRequest`                                    | Request model for presigned URL regeneration.                                                                                                                                                                       |
| `PresignedUrlResponse`                                   | Response model for presigned URL regeneration.                                                                                                                                                                      |
| `PresignedUrlResponseData`                               | Response data for presigned URL regeneration.                                                                                                                                                                       |
| `ScheduleConfig`                                         | Schedule configuration for cron-like scheduling.                                                                                                                                                                    |
| `ScheduleCreateData`                                     | Response data for successful schedule creation.                                                                                                                                                                     |
| `ScheduleCreateRequest`                                  | Request model for creating a schedule.                                                                                                                                                                              |
| `ScheduleResponse`                                       | Detailed schedule information.                                                                                                                                                                                      |
| `ScheduleUpdateRequest`                                  | Request model for updating a schedule.                                                                                                                                                                              |
| `SentryResponse`                                         | Response model for Sentry test endpoints.                                                                                                                                                                           |
| `ToolBase`                                               | Base model for tool-related operations.                                                                                                                                                                             |
| `ToolFramework`                                          | Enum for tool frameworks.                                                                                                                                                                                           |
| `ToolListItem`                                           | Schema for individual tool in list responses (simplified for cards/details).                                                                                                                                        |
| `ToolReference`                                          | Schema for tool references in agent responses.                                                                                                                                                                      |
| `ToolType`                                               | Enum for tool types.                                                                                                                                                                                                |
| `TransportType`                                          | Enum for supported MCP transport types. Currently, only SSE is supported, but this allows for future expansion.                                                                                                     |
| `ValidationError`                                        | —                                                                                                                                                                                                                   |


# Utilities

**Summary:** Regenerate presigned URL for any storage object

Generate a new presigned URL for any object in storage by providing its path in request body

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

## Request Body

*Required.*

* `application/json` — PresignedUrlRequest

## Responses

| Status | Description                            | Schema                                    |
| ------ | -------------------------------------- | ----------------------------------------- |
| `200`  | Presigned URL regenerated successfully | `application/json` — PresignedUrlResponse |
| `400`  | Invalid object path                    | `application/json` — ErrorResponse        |
| `422`  | Validation Error                       | `application/json` — HTTPValidationError  |
| `500`  | Internal server error                  | `application/json` — ErrorResponse        |


# Health Checks

### GET /health-check

**Summary:** Health Check

Health check endpoint.

Returns: HealthCheckResponse: Status and message indicating service health.

**Authentication:** None

**Parameters:** None

**Request Body:** None

#### Responses

| Status | Description         | Schema                                   |
| ------ | ------------------- | ---------------------------------------- |
| `200`  | Successful Response | `application/json` — HealthCheckResponse |

### GET /health-check/auth-test

**Summary:** Test Authentication

Test authentication endpoint.

This endpoint requires a valid API key to access and can be used to test that authentication is working correctly.

Args: account\_id: The verified API key from the request header

Returns: HealthCheckResponse: Status confirming authentication works

**Authentication:** API key (`X-API-Key` header)

**Parameters:** None

**Request Body:** None

#### Responses

| Status | Description         | Schema                                   |
| ------ | ------------------- | ---------------------------------------- |
| `200`  | Successful Response | `application/json` — HealthCheckResponse |

### GET /health-check/database

**Summary:** Database Health Check

Database health check endpoint.

Returns: HealthCheckResponse: Status and message indicating database health.

Raises: HTTPException: If database health check fails.

**Authentication:** None

**Parameters:** None

**Request Body:** None

#### Responses

| Status | Description         | Schema                                   |
| ------ | ------------------- | ---------------------------------------- |
| `200`  | Successful Response | `application/json` — HealthCheckResponse |


# Schemas

Field-by-field specification for runtime configuration used in multi-agent execution, derived from the backend runtime models.

{% hint style="info" %}
**Looking for operational guidance?** This page is a technical reference focused on field specifications. For endpoint usage, see the [REST API: Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/agents) and SDK usage patterns in the [Python SDK Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk#agents).
{% endhint %}

### Schema: RuntimeConfig

Runtime configuration for multi-agent execution. Supports global configurations and agent-specific overrides keyed directly by agent UUID. Runtime merges are shallow: agent-level overrides replace entire sibling objects rather than deep-merging nested structures.

#### Supported Fields

| Field                           | Type                                                 | Constraints / Notes                                                  |
| ------------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------- |
| [`tool_configs`](#tool-configs) | `object`                                             | Optional. Keys must be tool UUIDs; values must be objects.           |
| [`mcp_configs`](#mcp-configs)   | `object`                                             | Optional. Keys must be MCP UUIDs; values must be objects.            |
| [`agent_config`](#agent-config) | `object`                                             | Optional. Top-level agent configuration.                             |
| `<agent_uuid>`                  | [`AgentSpecificConfig`](#schema-agentspecificconfig) | Optional. Each additional top-level key must be a valid UUID string. |

Unknown top-level keys that are not valid UUIDs raise a validation error. Agent IDs are validated for proper UUID format.

#### Global Configuration Structures

**MCP Configs**

```json
{
  "mcp_configs": {
    "mcp-uuid-1": {
      "authentication": {
        "type": "custom-header",
        "headers": {
          "Authorization": "Bearer <token>"
        }
      }
    }
  }
}
```

**Tool Configs**

```json
{
  "tool_configs": {
    "tool-uuid-1": {
      "mode": "dry_run"
    },
    "tool-uuid-2": {
      "timeout": 30
    }
  }
}
```

**Agent Config**

```json
{
  "agent_config": {
    "tool_output_sharing": true,
    "max_recursion_limit": 10,
    "memory": "mem0"
  }
}
```

### Schema: AgentSpecificConfig

Configuration specific to an individual agent. These objects have the same shape as the global fields in `RuntimeConfig`. When supplied, they override the corresponding global settings for that agent.

| Field                           | Type     | Constraints                   | Description                                                                  |
| ------------------------------- | -------- | ----------------------------- | ---------------------------------------------------------------------------- |
| [`tool_configs`](#tool-configs) | `object` | Keys must be valid UUIDs      | Tool configurations keyed by tool UUID                                       |
| [`mcp_configs`](#mcp-configs)   | `object` | Keys must be valid UUIDs      | MCP configurations keyed by MCP UUID                                         |
| [`agent_config`](#agent-config) | `object` | Additional properties allowed | Agent-specific configuration (e.g., `tool_output_sharing`, recursion limits) |

### Validation Rules

#### Structure Validation

* `tool_configs`, `mcp_configs`, and `agent_config` must be objects when provided.
* Additional top-level keys must be valid UUID strings. Their values must be objects conforming to `AgentSpecificConfig`.
* Unknown non-UUID keys raise `Unknown top-level key '<key>' in runtime_config`.
* Invalid UUID keys raise `Invalid UUID: <agent_id>`.

#### Configuration Precedence

1. Agent-specific overrides (top-level UUID keys) take precedence over global configuration.
2. When an override omits a field, the global configuration is used.
3. Merges are shallow: overriding an object replaces the global object for that agent.

#### Tool Config Filtering

Tool configuration dictionaries are validated so each value is an object. Additional filtering (e.g., matching `tool_configs` keys to stored agent tools) occurs during agent validation.

### Examples

#### Global Configuration Only

```json
{
  "tool_configs": {
    "tool-uuid-1": {
      "mode": "dry_run"
    }
  }
}
```

#### Global and Agent-Specific Overrides

```json
{
  "tool_configs": {
    "tool-uuid-1": {
      "mode": "production",
      "timeout": 30
    }
  },
  "mcp_configs": {
    "mcp-uuid-1": {
      "authentication": {
        "type": "bearer-token",
        "token": "global-token"
      }
    }
  },
  "agent_config": {
    "tool_output_sharing": true,
    "max_recursion_limit": 10
  },
  "agent-uuid-1": {
    "tool_configs": {
      "tool-uuid-1": {
        "mode": "dry_run"
      }
    },
    "agent_config": {
      "tool_output_sharing": false
    }
  },
  "agent-uuid-2": {
    "mcp_configs": {
      "mcp-uuid-1": {
        "authentication": {
          "type": "api-key",
          "key": "X-API-Key",
          "value": "agent-specific-key"
        }
      }
    }
  }
}
```

### Usage in AgentRunRequest

The `runtime_config` field in `AgentRunRequest` accepts this schema and automatically supplants legacy top-level `tool_configs` and `mcp_configs` fields.

```json
{
  "input": "Where is my order #123?",
  "chat_history": [
    {
      "role": "user",
      "content": "hi"
    },
    {
      "role": "assistant",
      "content": "Hello! How can I assist you today?"
    }
  ],
  "runtime_config": {
    "tool_configs": {
      "tool-uuid-1": {
        "mode": "dry_run"
      }
    },
    "mcp_configs": {
      "mcp-uuid-1": {
        "authentication": {
          "type": "bearer-token",
          "token": "<token>"
        }
      }
    }
  }
}
```

Legacy requests that still provide the deprecated top-level `tool_configs`/`mcp_configs` are automatically converted to `runtime_config` on ingest, but new integrations should send the new structure directly.

### Common Validation Errors

<details>

<summary>Common Validation Errors and Causes</summary>

| Error                                                  | Cause                                                          |
| ------------------------------------------------------ | -------------------------------------------------------------- |
| `Unknown top-level key '<key>' in runtime_config`      | Top-level key is neither a known global field nor a valid UUID |
| `Configuration must be a dictionary`                   | `tool_configs` or `mcp_configs` is not a dictionary            |
| `Configuration value for '<key>' must be a dictionary` | Value in `tool_configs` or `mcp_configs` is not a dictionary   |
| `Agent config for '<agent_id>' must be a dictionary`   | Agent-specific configuration is not a dictionary               |
| `Invalid UUID: <agent_id>`                             | Agent ID is not a valid UUID format                            |

</details>

### Migration from Legacy Format

{% hint style="warning" %}
The legacy `tool_configs` and `mcp_configs` fields at the top level of `AgentRunRequest` are deprecated. Use `runtime_config` instead.
{% endhint %}

#### Legacy Format (Deprecated)

```json
{
  "input": "Where is my order?",
  "tool_configs": {
    "tool-uuid-1": {
      "mode": "dry_run"
    }
  },
  "mcp_configs": {
    "mcp-uuid-1": {
      "authentication": {
        "type": "bearer-token",
        "token": "<token>"
      }
    }
  }
}
```

#### New Format (Recommended)

```json
{
  "input": "Where is my order?",
  "runtime_config": {
    "tool_configs": {
      "tool-uuid-1": {
        "mode": "dry_run"
      }
    },
    "mcp_configs": {
      "mcp-uuid-1": {
        "authentication": {
          "type": "bearer-token",
          "token": "<token>"
        }
      }
    }
  }
}
```

### Related Documentation

* [REST API: Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/agents) — Endpoint reference
* [Python SDK Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk#agents) — Method signatures and usage
* [Agents Schema](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/agents) — Agent configuration details
* [Tools Schema](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/tools) — Tool configuration details
* [MCPs Schema](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/schemas/mcps) — MCP configuration details


# Agents

Field-by-field specification for agent resources derived from the backend Pydantic models.

{% hint style="info" %}
**Looking for operational guidance?** This page is a technical reference focused on field specifications. For endpoint usage, see the [REST API: Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/agents) and SDK usage patterns in the [Python SDK Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk#agents).
{% endhint %}

### Schema: AgentCreate

Used when creating a new agent via `POST /agents`.

#### Core Requirements

| Field       | Type            | Constraints / Notes                                                                                                                           |
| ----------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`      | `string` (enum) | Required. One of \[`config`, `a2a`, `langflow`].                                                                                              |
| `name`      | `string`        | Required for all types except `a2a` when `a2a_profile` is provided. Max 255 chars.                                                            |
| `framework` | `string` (enum) | Required for `config` agents (`langchain`, `langgraph`, or `google_adk`). Optional for other types; `a2a` defaults to `langchain` if omitted. |

All other fields are optional, but `config` agents **must** specify a language model using exactly one of the mechanisms described in [Language Model Selection](#language-model-selection).

#### Optional Fields

| Field                                     | Type            | Constraints / Notes                                                             |
| ----------------------------------------- | --------------- | ------------------------------------------------------------------------------- |
| `account_id`                              | `string`        | Account UUID (auto-assigned when omitted).                                      |
| `instruction`                             | `string`        | Agent instruction prompt. Optional but recommended.                             |
| `version`                                 | `string`        | Max 255 chars.                                                                  |
| `description`                             | `string`        | Free-form description.                                                          |
| [`a2a_profile`](#a2a-profile-structure)   | `object`        | Required for `a2a` agents if `name` is omitted.                                 |
| [`agent_config`](#agent-config-structure) | `object`        | Framework-specific configuration. Additional properties allowed.                |
| `agents`                                  | `array<string>` | Optional list of sub-agent UUIDs.                                               |
| `tools`                                   | `array<string>` | Optional list of tool UUIDs.                                                    |
| `mcps`                                    | `array<string>` | Optional list of MCP configuration UUIDs.                                       |
| [`tool_configs`](#tool-configs-structure) | `object`        | Keys must match entries in `tools`. Extra configs are ignored.                  |
| `metadata`                                | `object`        | Application-defined metadata. Additional properties allowed.                    |
| `language_model_id`                       | `string`        | Mutually exclusive with `provider`/`model_name` and `agent_config.lm_provider`. |
| `provider`                                | `string`        | Legacy language model provider. Must be supplied together with `model_name`.    |
| `model_name`                              | `string`        | Legacy language model name. Must be supplied together with `provider`.          |

On create, supply UUID references in `tools`, `agents`, and `mcps`. Read responses expand those references into detailed objects.

#### Language Model Selection

`config` agents must specify a language model exactly once using one of the following options:

1. `language_model_id`
2. `provider` **and** `model_name`
3. `agent_config.lm_provider` (legacy) with accompanying `agent_config.lm_name`

If multiple mechanisms are provided, validation fails. `a2a` and `langflow` agents may omit language model information.

#### Agent Types

Defined by `AgentType` enum:

| Value      | Description                          |
| ---------- | ------------------------------------ |
| `config`   | Standard configuration-based agent   |
| `a2a`      | Agent-to-agent communication profile |
| `langflow` | Agent sourced from LangFlow flows    |

#### Agent Frameworks

Defined by `AgentFramework` enum:

| Value        | Description          |
| ------------ | -------------------- |
| `langchain`  | LangChain framework  |
| `langgraph`  | LangGraph framework  |
| `google_adk` | Google ADK framework |
| `langflow`   | LangFlow framework   |

#### Tool Configs Structure

The `tool_configs` field is a JSON object keyed by tool UUID. Each entry supplies configuration for the referenced tool. Keys that are not present in the `tools` list are ignored automatically.

```json
{
  "tool_configs": {
    "tool-uuid-1": {
      "parameter1": "value1",
      "parameter2": 42
    },
    "tool-uuid-2": {
      "custom_setting": true
    }
  }
}
```

#### Agent Config Structure

The `agent_config` field contains framework-specific settings. Common keys include recursion limits, memory bindings, or LangFlow metadata.

```json
{
  "agent_config": {
    "max_recursion_limit": 10,
    "memory": "mem0",
    "planning": true,
    "tool_output_sharing": true
  }
}
```

No default values are enforced by the API; populate only the settings your runtime understands.

**Available Configuration Options:**

| Field                 | Type      | Default | Description                                                                                                                                                                                                                |
| --------------------- | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `max_recursion_limit` | `integer` | 100     | Maximum number of recursive calls the agent can make. Prevents infinite loops in agent reasoning chains. This setting is especially important for complex agents that may call themselves or create circular dependencies. |
| `memory`              | `string`  | `null`  | Memory system identifier to use for persistent conversation context. Common values include `"mem0"` for Mem0 integration.                                                                                                  |
| `planning`            | `boolean` | `false` | Whether to enable planning mode for the agent. When enabled, the agent will first create a structured plan before executing tasks, improving reasoning and task decomposition for complex queries.                         |
| `tool_output_sharing` | `boolean` | `false` | Whether tool outputs are shared across different tool calls within the same agent execution session. When enabled, tools can access outputs from previous tool calls in the execution chain.                               |

#### Metadata Structure

The `metadata` field can be used by applications such as GLChat to store UI and behavior configuration. Common fields include:

```json
{
  "metadata": {
    "type": "custom",
    "timeout": 60,
    "is_shown": true,
    "agent_source": "form",
    "display_name": "Display agent name",
    "chat_history_limit": 20,
    "svg_icon": "<svg>...</svg>"
  }
}
```

**Common Fields:**

| Field                | Type      | Description                             |
| -------------------- | --------- | --------------------------------------- |
| `type`               | `string`  | Agent type: `native` or `custom`        |
| `display_name`       | `string`  | Display name shown in GLChat UI         |
| `is_shown`           | `boolean` | Whether agent is visible in UI          |
| `timeout`            | `number`  | Request timeout in seconds              |
| `chat_history_limit` | `number`  | Maximum chat history messages           |
| `agent_source`       | `string`  | Source of agent creation (e.g., `form`) |
| `svg_icon`           | `string`  | SVG markup for agent icon               |

#### A2A Profile Structure

The `a2a_profile` field configures agent-to-agent communication profiles. It is required for `a2a` agents unless a `name` is provided.

```json
{
  "a2a_profile": {
    "url": "https://remote-agent-server.com/api"
  }
}
```

`url` is required and validated for proper scheme and host.

### Schema: AgentResponse

Returned by `GET /agents/{agent_id}` and other read operations.

| Field                                     | Type                    | Description                                              |
| ----------------------------------------- | ----------------------- | -------------------------------------------------------- |
| `id`                                      | `string` (UUID)         | Unique agent identifier                                  |
| `name`                                    | `string`                | Agent name                                               |
| [`type`](#agent-types)                    | `string` (enum)         | Agent type classification                                |
| `description`                             | `string`                | Detailed description                                     |
| `instruction`                             | `string`                | Agent instructions                                       |
| [`framework`](#agent-frameworks)          | `string` (enum)         | Framework used by agent                                  |
| `version`                                 | `string`                | Agent version                                            |
| [`metadata`](#metadata-structure)         | `object`                | Agent metadata                                           |
| `tools`                                   | `array<ToolReference>`  | List of tool references with `id`, `name`, `description` |
| `agents`                                  | `array<AgentReference>` | List of sub-agent references                             |
| `mcps`                                    | `array<MCPConfig>`      | List of MCP configurations                               |
| [`tool_configs`](#tool-configs-structure) | `object`                | Tool configuration keyed by tool UUID                    |
| `language_model_id`                       | `string`                | Resolved language model configuration ID                 |
| `provider`                                | `string`                | Legacy language model provider (deprecated)              |
| `model_name`                              | `string`                | Legacy language model name (deprecated)                  |
| [`agent_config`](#agent-config-structure) | `object`                | Agent-specific config                                    |
| [`a2a_profile`](#a2a-profile-structure)   | `object`                | Agent-to-agent communication profile                     |
| `account_id`                              | `string`                | Account ID associated with the agent                     |
| `created_at`                              | `string` (datetime)     | Creation timestamp                                       |
| `updated_at`                              | `string` (datetime)     | Last update timestamp                                    |

### Schema: AgentListItem

Returned by `GET /agents` list operations.

| Field                            | Type                | Description                      |
| -------------------------------- | ------------------- | -------------------------------- |
| `id`                             | `string` (UUID)     | Unique agent identifier          |
| `name`                           | `string`            | Agent name                       |
| [`type`](#agent-types)           | `string` (enum)     | Agent type classification        |
| [`framework`](#agent-frameworks) | `string` (enum)     | Framework used by agent          |
| `version`                        | `string`            | Agent version                    |
| `description`                    | `string`            | Detailed description             |
| `metadata`                       | `object`            | Agent metadata                   |
| `created_at`                     | `string` (datetime) | Creation timestamp               |
| `updated_at`                     | `string` (datetime) | Last update timestamp            |
| `deleted_at`                     | `string` (datetime) | Soft-delete timestamp (nullable) |

### AgentPatch

Used for partial updates via `PATCH /agents/{agent_id}`. Unlike the full-replace `PUT` (`AgentUpdate`), the PATCH schema is **sparse**: only fields the caller explicitly provides are included in the request body.

#### Sparse Contract

| Caller intent           | How to express it                                                                                                                                 |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Leave a field unchanged | Omit it. Omitted fields are never sent and are preserved by the backend.                                                                          |
| Clear a field           | Pass an explicit `null` (scalars) or an empty collection (`[]`). Explicit `null`/empty values are always included so the backend can act on them. |

The SDK never prefetches the current agent — there is no `GET` round-trip and no fallback to existing values — so an edit touches exactly the fields the caller asked for. An empty body (no fields provided) is rejected client-side before any request is sent.

#### Fields

All fields are optional; provide only the ones you want to change. Additional keys (`extras`) are passed through to the body verbatim.

| Field                                     | Type            | PATCH behavior                                                                                        |
| ----------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------- |
| `name`                                    | `string`        | Must be non-empty; whitespace-only is rejected client-side.                                           |
| `instruction`                             | `string`        | Agent instruction prompt.                                                                             |
| `description`                             | `string`        | Pass `null` to clear.                                                                                 |
| `type`                                    | `string` (enum) | One of `config`, `a2a`, `langflow` ([Agent Types](#agent-types)).                                     |
| `framework`                               | `string` (enum) | One of `langchain`, `langgraph`, `google_adk`, `langflow` ([Agent Frameworks](#agent-frameworks)).    |
| `version`                                 | `string`        | Max 255 chars.                                                                                        |
| `account_id`                              | `string`        | Account UUID.                                                                                         |
| `language_model_id`                       | `string`        | Language model selector; mutually exclusive with `provider`/`model_name`.                             |
| `provider`                                | `string`        | Legacy selector; must be supplied together with `model_name`.                                         |
| `model_name`                              | `string`        | Legacy selector; must be supplied together with `provider`.                                           |
| [`metadata`](#metadata-structure)         | `object`        | Application-defined metadata. Pass `null` to clear.                                                   |
| `tools`                                   | `array<string>` | Tool UUIDs. **Replaces** the existing set when provided; pass `[]` to clear all.                      |
| `agents`                                  | `array<string>` | Sub-agent UUIDs. **Replaces** the existing set when provided; pass `[]` to clear.                     |
| `mcps`                                    | `array<string>` | MCP configuration UUIDs. **Replaces** the existing set when provided; pass `[]` to clear.             |
| [`tool_configs`](#tool-configs-structure) | `object`        | **Deep merged** into existing configs when provided — nested objects are recursively merged.          |
| `mcp_configs`                             | `object`        | **Deep merged** into existing configs when provided — nested objects are recursively merged.          |
| `skills`                                  | `array<object>` | Skill definitions. **Replaces** the existing set when provided; pass `[]` to clear all.               |
| [`agent_config`](#agent-config-structure) | `object`        | Framework-specific config. **Deep merged** when provided; pass `null` to clear.                       |
| [`a2a_profile`](#a2a-profile-structure)   | `object`        | Agent-to-agent communication profile.                                                                 |
| `timeout`                                 | `integer`       | SDK convenience written to `agent_config.timeout_seconds`. See [Timeout Handling](#timeout-handling). |

Server-side, collection fields are either replaced or deep merged: `tools`, `agents`, `mcps`, and `skills` **replace** the existing set when provided, while `tool_configs`, `mcp_configs`, and `agent_config` are **deep merged** (recursively) into the stored values.

**Deep merge example — `mcp_configs` and `tool_configs`**

Stored state before the PATCH:

```json
{
  "mcp_configs": {
    "<mcp-1-id>": { "auth": "token-abc", "timeout": 30, "nested": { "x": 1 } },
    "<mcp-2-id>": { "auth": "token-xyz" }
  }
}
```

PATCH body (updating only `auth` inside `<mcp-1-id>`):

```json
{ "mcp_configs": { "<mcp-1-id>": { "auth": "token-NEW" } } }
```

Result:

```json
{
  "mcp_configs": {
    "<mcp-1-id>": { "auth": "token-NEW", "timeout": 30, "nested": { "x": 1 } },
    "<mcp-2-id>": { "auth": "token-xyz" }
  }
}
```

`<mcp-2-id>` is preserved. Within `<mcp-1-id>`, `timeout` and `nested` survive — only `auth` is updated. `tool_configs` and `agent_config` follow the same deep merge behaviour.

#### Timeout Handling

`timeout` is not sent as a top-level field; it is written into `agent_config.timeout_seconds`. Because it overlaps with `agent_config`, the SDK rejects ambiguous combinations client-side before any request:

* `timeout=` together with an `agent_config` that already carries a timeout key (`timeout_seconds`, `timeout`, or `execution_timeout`) is rejected.
* `timeout=` together with an explicit `agent_config=null` is rejected (set the timeout *or* clear the config, not both).
* `timeout=null` is rejected — use `update(...)` (PUT) for deletion-style timeout changes.

Language model selectors remain mutually exclusive. Provide at most one of `language_model_id`, `provider`/`model_name`, or the legacy `agent_config.lm_provider`; see the [create rules](#language-model-selection) for details.

### Validation Rules

#### On Create (POST /agents)

* `type` must be one of `config`, `a2a`, `langflow`.
* `name` is required for all non-`a2a` agents. `a2a` agents must provide either `name` or a populated `a2a_profile`.
* `framework` is required for `config` agents. When omitted for `a2a` agents it defaults to `langchain`. `langflow` agents expect `agent_config.langflow.flow_id` instead.
* `config` agents must specify a language model using exactly one supported method.
* String fields respect their max length constraints.
* `tools`, `agents`, and `mcps` arrays must contain valid UUID strings when provided. Extra entries in `tool_configs` that do not correspond to the `tools` list are ignored.

#### On Update (PUT /agents/{agent\_id})

* Full replacement: all required fields must be present and follow create rules.
* Language model selectors remain mutually exclusive.

#### On Partial Update (PATCH /agents/{agent\_id})

* Only provided fields are validated and updated.
* Language model selectors remain mutually exclusive.

### Common Validation Errors

| Status | Error                          | Cause                                            |
| ------ | ------------------------------ | ------------------------------------------------ |
| `400`  | Invalid input data             | Malformed JSON or invalid field types            |
| `409`  | Agent with name already exists | Duplicate `name` in the same account             |
| `422`  | Validation error               | Missing required fields or constraint violations |

### Minimal Example

```json
{
  "name": "basic-agent",
  "type": "config",
  "framework": "langchain",
  "instruction": "You are a helpful assistant that provides clear and accurate responses.",
  "language_model_id": "model-uuid"
}
```

### Full Example

```json
{
  "name": "data-analyst",
  "type": "config",
  "framework": "langchain",
  "version": "1.0.0",
  "description": "Analyzes data and generates reports",
  "instruction": "You are a data analyst. Analyze the provided data and generate comprehensive reports with visualizations.",
  "metadata": {
    "team": "analytics",
    "environment": "production"
  },
  "tools": ["tool-uuid-1", "tool-uuid-2"],
  "agents": ["sub-agent-uuid"],
  "mcps": ["mcp-config-uuid"],
  "tool_configs": {
    "tool-uuid-1": {
      "api_key": "analytics-api-key",
      "timeout": 30
    }
  },
  "language_model_id": "model-uuid",
  "agent_config": {
    "max_recursion_limit": 10,
    "memory": "mem0",
    "planning": true,
    "tool_output_sharing": true
  }
}
```

### Related Documentation

* [REST API: Agents](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/agents) — Endpoint reference
* [Python SDK Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk#agents) — Method signatures and usage
* [Agents Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/agents) — Lifecycle operations


# Tools

{% hint style="info" %}
**Looking for operational guidance?** This page is a technical reference focused on field specifications. For endpoint usage, see the [REST API: Tools](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/tools) and SDK usage patterns in the [Python SDK Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk#tools).
{% endhint %}

### Schema: ToolBase

Used when creating or updating a tool via `POST /tools/` or `PUT /tools/{id}`.

#### Required Fields

| Field                           | Type            | Constraints                | Description                |
| ------------------------------- | --------------- | -------------------------- | -------------------------- |
| `name`                          | `string`        | Must be unique per account | Tool name                  |
| [`framework`](#framework-types) | `string` (enum) | Must be valid framework    | Framework used by the tool |
| [`tool_type`](#tool-types)      | `string` (enum) | Must be valid tool type    | Type of the tool           |

#### Optional Fields

| Field         | Type           | Constraints                  | Description                |
| ------------- | -------------- | ---------------------------- | -------------------------- |
| `account_id`  | `string`       | UUID format                  | Account ID (auto-assigned) |
| `description` | `string`       | Max length varies by backend | Tool description           |
| `tags`        | `list[string]` | Optional                     | Tags for search/filtering  |
| `version`     | `string`       | Default: `"1.0.0"`           | Tool version identifier    |

#### Framework Types

Defined by `ToolFramework` enum:

| Value        | Description          |
| ------------ | -------------------- |
| `langchain`  | LangChain framework  |
| `langgraph`  | LangGraph framework  |
| `google_adk` | Google ADK framework |

#### Tool Types

Defined by `ToolType` enum:

| Value    | Description                |
| -------- | -------------------------- |
| `native` | Pre-built native tools     |
| `custom` | User-uploaded custom tools |

### Schema: ToolListItem

Returned by `GET /tools/` and other list operations. Includes additional runtime fields.

| Field                           | Type            | Required | Description                                                                  |
| ------------------------------- | --------------- | -------- | ---------------------------------------------------------------------------- |
| `id`                            | `string` (UUID) | Yes      | Unique tool identifier                                                       |
| `name`                          | `string`        | Yes      | Tool name                                                                    |
| [`framework`](#framework-types) | `string` (enum) | Yes      | Framework type                                                               |
| [`tool_type`](#tool-types)      | `string` (enum) | Yes      | Tool type                                                                    |
| `description`                   | `string`        | No       | Tool description                                                             |
| `version`                       | `string`        | No       | Tool version                                                                 |
| `account_id`                    | `string`        | No       | Associated account ID                                                        |
| `plugin_class_name`             | `string`        | No       | Name of the plugin class (for custom tools)                                  |
| `module_name`                   | `string`        | No       | Python module name                                                           |
| `script_content`                | `string`        | No       | Source code (redacted by default; use `/tools/{id}/source` for full content) |

### File Upload Requirements

For custom tools uploaded via `POST /tools/upload` and `PUT /tools/{tool_id}/upload`:

#### File Format

* Format: Python source file (`.py`)
* Encoding: UTF-8
* Size limits: Varies by backend configuration

#### Plugin Requirements

On older servers (< v0.1.85), the Python file must export a `tool_plugin` entry point with the following structure:

```python
def tool_plugin():
    return YourToolClass()
```

On newer servers (v0.1.85+), this entry point is optional as long as the file defines a valid tool class. The Python SDK injects the entry point automatically when needed for compatibility.

#### Plugin Class Requirements

* Must inherit from the appropriate base class for the specified framework.
* Should implement the required interface methods for the framework.
* Include proper metadata and documentation.

### Validation Rules

#### On Create (POST /tools/ or POST /tools/upload)

* `name` must be unique within the account.
* `framework` must be one of `langchain`, `langgraph`, `google_adk`.
* `tool_type` must be one of `native`, `custom`.
* On older servers (< v0.1.85), custom tool uploads must include a valid `tool_plugin` function. On newer servers, a valid tool class is sufficient (the Python SDK injects the entry point when needed).

#### On Update (PUT /tools/{id})

* Full replacement: all required fields must be present.
* Same validation as create.
* For code updates, use `PUT /tools/{tool_id}/upload` instead.

#### On Metadata Update (PUT /tools/{id})

* Only metadata fields are updated (`name`, `description`, `version`, etc.).
* Plugin code remains unchanged.
* Validation applies only to provided fields.

### Common Validation Errors

| Status | Error                         | Cause                                                                   |
| ------ | ----------------------------- | ----------------------------------------------------------------------- |
| `400`  | Invalid plugin file           | Malformed Python code or missing `tool_plugin` function (older servers) |
| `404`  | Tool not found                | Tool ID does not exist or is soft-deleted                               |
| `409`  | Tool with name already exists | Duplicate `name` in the same account                                    |
| `422`  | Validation error              | Missing required fields or constraint violations                        |
| `500`  | Failed to register plugin     | Runtime error during plugin validation                                  |

### Minimal Example

**Minimal example (JSON)**

```json
{
  "name": "basic-calculator",
  "framework": "langchain",
  "tool_type": "custom"
}
```

### Full Example

**Full example (JSON)**

```json
{
  "name": "advanced-analytics-tool",
  "description": "Performs complex statistical analysis and data visualization",
  "framework": "langgraph",
  "tool_type": "custom",
  "version": "2.1.0"
}
```

### File Upload Example

**cURL file upload example**

```bash
curl -X POST "$AIP_API_URL/tools/upload" \
  -H "X-API-Key: $AIP_API_KEY" \
  -F name="analytics-tool" \
  -F description="Statistical analysis tool" \
  -F framework="langchain" \
  -F tool_type="custom" \
  -F file=@analytics_tool.py
```

### Security Considerations

* Keep credentials for custom tools in an external secret manager instead of embedding raw keys in tool metadata.
* Redacted fields (`script_content`, secrets) only surface in targeted endpoints; avoid logging them downstream.

### Related Documentation

* [REST API: Tools](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/tools) — Endpoint reference
* [Python SDK Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk#tools) — Method signatures and usage
* [Tools Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/tools) — Lifecycle operations and file upload workflows


# MCPs

Field-by-field specification for Model Context Protocol (MCP) configurations derived from the backend Pydantic models.

{% hint style="info" %}
**Looking for operational guidance?** This page is a technical reference focused on field specifications. For endpoint usage, see the [REST API: MCPs](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/mcps) and SDK usage patterns in the [Python SDK Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk#model-context-protocol-mcp).
{% endhint %}

### Schema: MCPCreate

Used when creating a new MCP configuration via `POST /mcps`.

#### Required Fields

| Field                                | Type            | Constraints                             | Description                                 |
| ------------------------------------ | --------------- | --------------------------------------- | ------------------------------------------- |
| `name`                               | `string`        | Max 255 chars, unique per account       | Name of the MCP configuration               |
| [`transport`](#transport-types)      | `string` (enum) | `http` or `sse`                         | Transport protocol for the MCP connection   |
| [`config`](#config-object-structure) | `object`        | Must include `url` for `http` and `sse` | Connection details (e.g., `command`, `url`) |

#### Optional Fields

| Field                                     | Type     | Constraints                                       | Description                                  |
| ----------------------------------------- | -------- | ------------------------------------------------- | -------------------------------------------- |
| [`authentication`](#authentication-types) | `object` | See [Authentication Types](#authentication-types) | Authentication credentials                   |
| `description`                             | `string` | Max 1000 chars                                    | Human-readable description                   |
| [`mcp_metadata`](#mcp-metadata-structure) | `object` | Additional properties allowed                     | Organizational metadata (informational only) |
| `account_id`                              | `string` | UUID format                                       | Account ID (auto-assigned)                   |

### Transport Types

Defined by `TransportType` enum:

| Value  | Description                                          |
| ------ | ---------------------------------------------------- |
| `http` | Streaming HTTP transport (requires `config.url`)     |
| `sse`  | Server-Sent Events transport (requires `config.url`) |

### Config Object Structure

The `config` field is a flexible JSON object that contains connection details for the MCP server. The only enforced requirement today is that `http` and `sse` transports must include a valid URL.

#### HTTP config

| Field | Type     | Description                                |
| ----- | -------- | ------------------------------------------ |
| `url` | `string` | HTTPS endpoint that exposes the MCP server |

```json
{
  "url": "https://api.example.com/mcp"
}
```

**Future Fields**

The following fields are planned to be supported in the future:

| Field            | Type            | Description                                   |
| ---------------- | --------------- | --------------------------------------------- |
| `disabled_tools` | `array<string>` | List of tools to disable access to for agents |
| `enabled_tools`  | `array<string>` | List of tools to enable access to for agents  |

#### SSE config

SSE transports reuse the same shape as HTTP and still require a `url`.

```json
{
  "url": "https://legacy.example.com/mcp-stream"
}
```

Additional fields are allowed and passed through to the MCP connector. Common optional keys include tool allow/deny lists and per-transport tuning parameters.

### MCP Metadata Structure

The `mcp_metadata` field is a flexible JSON object for storing organizational information about the MCP configuration. This metadata is informational only and does not affect runtime behavior.

```json
{
  "mcp_metadata": {
    "total_tools": 15,
    "environment": "production"
  }
}
```

### Authentication Types

The `authentication` object must include a `type` field with one of the following values. Responses redact sensitive values unless `return_full` serialization is requested internally.

#### `no-auth`

```json
{
  "type": "no-auth"
}
```

#### `bearer-token`

Provide a bearer token either directly or via headers.

```json
{
  "type": "bearer-token",
  "token": "your-bearer-token"
}
```

**Header format (mutually exclusive with `token`)**

```json
{
  "type": "bearer-token",
  "headers": {
    "Authorization": "Bearer your-bearer-token"
  }
}
```

#### `api-key`

Supply the API key name and value, or precomputed headers.

```json
{
  "type": "api-key",
  "key": "X-API-Key",
  "value": "your-secret"
}
```

**Header format (mutually exclusive with `value`)**

```json
{
  "type": "api-key",
  "headers": {
    "X-API-Key": "your-secret"
  }
}
```

#### `custom-header`

```json
{
  "type": "custom-header",
  "headers": {
    "X-API-Key": "secret",
    "X-Client-ID": "client123"
  }
}
```

### Schema: MCPPatch

Used for partial updates via `PATCH /mcps/{mcp_id}`. All fields are optional.

| Field                                     | Type            | Constraints                                   | Description              |
| ----------------------------------------- | --------------- | --------------------------------------------- | ------------------------ |
| `name`                                    | `string`        | Max 255 chars                                 | Update the MCP name      |
| `description`                             | `string`        | Max 1000 chars                                | Update description       |
| [`transport`](#transport-types)           | `string` (enum) | `http` or `sse`                               | Update transport type    |
| [`config`](#config-object-structure)      | `object`        | Must include `url` when transport is provided | Update connection config |
| [`authentication`](#authentication-types) | `object`        | See authentication rules                      | Update credentials       |
| [`mcp_metadata`](#mcp-metadata-structure) | `object`        | Additional properties allowed                 | Update metadata          |

### Schema: MCPResponse

Returned by `GET /mcps/{mcp_id}` and other read operations. Authentication fields are sanitized in responses (only non-sensitive keys are returned by default).

| Field            | Type                | Description                                        |
| ---------------- | ------------------- | -------------------------------------------------- |
| `id`             | `string` (UUID)     | Unique MCP identifier                              |
| `name`           | `string`            | MCP name                                           |
| `description`    | `string`            | Description                                        |
| `transport`      | `string`            | Transport type (`http` or `sse`)                   |
| `config`         | `object`            | Connection configuration                           |
| `authentication` | `object`            | Authentication details (sensitive values redacted) |
| `mcp_metadata`   | `object`            | Metadata                                           |
| `account_id`     | `string`            | Associated account ID                              |
| `created_at`     | `string` (datetime) | Creation timestamp                                 |
| `updated_at`     | `string` (datetime) | Last update timestamp                              |
| `deleted_at`     | `string` (datetime) | Soft-delete timestamp                              |

### Schema: MCPToolDefinition

Represents a tool exposed by an MCP server, returned by `GET /mcps/{mcp_id}/tools` and `POST /mcps/connect/tools`.

| Field         | Type     | Required | Description                          |
| ------------- | -------- | -------- | ------------------------------------ |
| `name`        | `string` | Yes      | Unique tool name                     |
| `description` | `string` | Yes      | What the tool does                   |
| `args_schema` | `object` | No       | JSON schema for tool input arguments |

### Validation Rules

#### On Create (POST /mcps)

* `name` must be unique within the account.
* `transport` must be `http` or `sse`.
* `config` must be a JSON object that includes a valid URL when the transport is `http` or `sse`.
* If `authentication` is provided, it must include a valid `type` and satisfy the per-type requirements.

#### On Update (PUT /mcps/{mcp\_id})

* Full replacement: all required fields must be present.
* Same validation as create.

#### On Partial Update (PATCH /mcps/{mcp\_id})

* Only provided fields are updated.
* Validation applies only to fields being changed.

### Common Validation Errors

| Status | Error                        | Cause                                            |
| ------ | ---------------------------- | ------------------------------------------------ |
| `400`  | Invalid input data           | Malformed JSON or invalid field types            |
| `400`  | Invalid URL format           | `config.url` missing or fails URL validation     |
| `409`  | MCP with name already exists | Duplicate `name` in the same account             |
| `422`  | Validation error             | Missing required fields or constraint violations |

### Connection Test Schemas

#### MCPConnectionTestRequest

Used by `POST /mcps/connect` and `POST /mcps/connect/tools` to test configurations without saving. Has the same structure as `MCPCreate` but does not persist the configuration.

### Minimal Example

```json
{
  "name": "minimal-mcp",
  "transport": "http",
  "config": {
    "url": "https://api.example.com/mcp"
  }
}
```

### Full Example

```json
{
  "name": "production-analytics",
  "description": "Analytics MCP for production environment",
  "transport": "http",
  "config": {
    "url": "https://analytics.example.com/mcp"
  },
  "authentication": {
    "type": "api-key",
    "key": "X-API-Key",
    "value": "analytics-secret"
  },
  "mcp_metadata": {
    "environment": "production",
    "team": "data-science",
    "cost_center": "analytics"
  }
}
```

### Related Documentation

* [REST API: MCPs](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/rest-api/mcps) — Endpoint reference
* [Python SDK Reference](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/resources/reference/python-sdk#model-context-protocol-mcp) — Method signatures and usage
* [MCPs Guide](https://gdplabs.gitbook.io/sdk/gl-ai-agent-package/guides/mcps) — Lifecycle operations


# Introduction to GL Browser Use

**GL Browser Use** is a typed Python SDK for running browser automation tasks through [`browser-use`](https://github.com/browser-use/browser-use). It gives application code a stable client facade, structured stream events, explicit run results, bounded retries for recoverable browser-session failures, and optional integrations for hosted browser infrastructure and session recordings.

Use GL Browser Use when you want an LLM-powered agent to operate a browser for tasks such as opening websites, gathering information from pages, filling forms, checking web workflows, or producing an auditable trace of a browser run.

## Key Features

**Typed client API**: Run browser tasks with `BrowserUseClient` using streaming, async one-shot, or synchronous methods.

**Structured events**: Consume progress, thinking/activity updates, tool-call summaries, streaming URLs, recording URLs, and terminal errors through `BrowserUseStreamEvent`.

**Explicit results**: Inspect status, final output, session IDs, browser streaming links, recording links, step counts, errors, and metadata through `BrowserUseRunResult`.

**Optional hosted browser sessions**: Use `SteelBrowserInfrastructure` or `OpenSandboxBrowserInfrastructure` when you want a remote browser session with CDP and streaming URLs.

**Optional recording storage**: Use `MinIOS3CompatibleStorage` to upload hosted session recordings to MinIO or an S3-compatible object store and return presigned URLs.

**Recoverable session retries**: Retry only classified browser-session failures, such as browser closure or websocket disconnects, with a bounded retry count.

## Get Started

1. [**Prerequisites**](/sdk/gl-browser-use/prerequisites): Prepare Python, model credentials, and optional provider credentials.
2. [**Getting Started**](/sdk/gl-browser-use/getting-started): Run your first browser automation task.
3. [**Guides**](/sdk/gl-browser-use/guides): Learn streaming, recordings, and production usage patterns.
4. [**Resources**](/sdk/gl-browser-use/resources): Review the SDK reference and runtime contracts.


# Prerequisites

Before you begin using GL Browser Use, make sure your environment and credentials are ready.

{% stepper %}
{% step %}
**Python 3.11 or 3.12**

GL Browser Use requires Python `>=3.11,<3.13`.

```bash
python --version

# Python 3.11.x or Python 3.12.x
```

{% endstep %}

{% step %}
**Install the SDK**

Install the core package when you only need local browser execution through `browser-use`:

```bash
pip install gl-browser-use
```

Install optional extras only when you use the matching provider:

| Extra            | Installs                       | When to use                                 |
| ---------------- | ------------------------------ | ------------------------------------------- |
| `steel`          | Steel SDK                      | Hosted browser sessions through Steel       |
| `opensandbox`    | OpenSandbox client, Playwright | Hosted browser sessions through OpenSandbox |
| `minio`          | MinIO SDK                      | MinIO or S3-compatible recording storage    |
| `infrastructure` | `steel` + `opensandbox`        | All hosted browser providers                |
| `storage`        | `minio`                        | All object storage providers                |
| `full`           | `infrastructure` + `storage`   | All currently available providers           |

```bash
pip install "gl-browser-use[steel]"
pip install "gl-browser-use[opensandbox]"
pip install "gl-browser-use[minio]"
pip install "gl-browser-use[infrastructure]"
pip install "gl-browser-use[storage]"
pip install "gl-browser-use[full]"
```

{% hint style="info" %}
Use concrete extras such as `steel`, `opensandbox`, and `minio` in application dependency files when you want to pin exactly which provider your application uses. The `infrastructure`, `storage`, and `full` extras are convenience aliases and may include more providers later.
{% endhint %}
{% endstep %}

{% step %}
**OpenSandbox Browser Setup (Optional, One-Time)**

If you install `gl-browser-use[opensandbox]`, also install Playwright's Chromium binary once in that environment:

```bash
pip install "gl-browser-use[opensandbox]"
playwright install chromium
```

OpenSandbox sessions use Playwright-backed recording helpers, so the browser binary must be available before you run hosted OpenSandbox flows.
{% endstep %}

{% step %}
**OpenAI API Key**

GL Browser Use uses OpenAI-compatible chat models through `browser-use`. Set `OPENAI_API_KEY`, or pass the keys directly through `BrowserUseClientConfig`.

```bash
export OPENAI_API_KEY="your-openai-api-key"
```

If you do not pass `llm_openai_api_key` or `page_extraction_llm_openai_api_key`, both values default to `OPENAI_API_KEY`.
{% endstep %}

{% step %}
**Optional Steel Credentials**

Steel is only required when you want hosted browser sessions, streaming URLs, CDP URLs, or Steel-backed recordings.

```bash
export STEEL_API_KEY="your-steel-api-key"
```

{% endstep %}

{% step %}
**Optional OpenSandbox Credentials**

OpenSandbox is only required when you want hosted browser sessions, streaming URLs, CDP URLs, or OpenSandbox-backed recordings.

```bash
export OPENSANDBOX_DOMAIN="localhost:8080"
export OPENSANDBOX_API_KEY="your-opensandbox-api-key"
```

`OPENSANDBOX_API_KEY` is optional when you run against a local insecure OpenSandbox server. When `OPENSANDBOX_DOMAIN` includes a scheme such as `https://`, the SDK uses that protocol automatically.
{% endstep %}

{% step %}
**Optional Object Storage Credentials**

Object storage is only required when you want GL Browser Use to upload browser session recordings and return recording URLs.

```bash
export OBJECT_STORAGE_URL="localhost:9001"
export OBJECT_STORAGE_USERNAME="your-access-key"
export OBJECT_STORAGE_PASSWORD="your-secret-key"
export OBJECT_STORAGE_BUCKET_NAME="browser-recordings"
export OBJECT_STORAGE_DIRECTORY_PREFIX="optional-prefix"
export OBJECT_STORAGE_SECURE="false"
```

`OBJECT_STORAGE_URL` may include an `http://` or `https://` scheme. When no scheme is provided, `OBJECT_STORAGE_SECURE` controls whether the client uses HTTPS.
{% endstep %}
{% endstepper %}


# Getting Started

This guide runs a browser automation task with GL Browser Use and shows how to consume the final result.

## Prerequisites

Before you begin, complete the [Prerequisites](/sdk/gl-browser-use/prerequisites) guide. At minimum, you need:

* Python 3.11 or 3.12
* `gl-browser-use` installed
* `OPENAI_API_KEY` configured, or API keys passed directly in code

## Run Your First Browser Task

Create a Python file, for example `browser_task.py`:

```python
from gl_browser_use import BrowserUseClient, BrowserUseClientConfig

client = BrowserUseClient(
    config=BrowserUseClientConfig(
        # Optional when OPENAI_API_KEY is already set.
        llm_openai_api_key="your-openai-api-key",
        page_extraction_llm_openai_api_key="your-openai-api-key",
    )
)

result = client.run_sync("Open Hacker News and list five article titles")

print(result.status)
print(result.final_output)
```

Run the script:

```bash
python browser_task.py
```

`run_sync()` returns a `BrowserUseRunResult` with the final output, status, step count, and any terminal error details.

{% hint style="warning" %}
Do not call `run_sync()` from inside an existing async event loop. Use `await client.run_once(...)` or `async for event in client.run(...)` in async applications.
{% endhint %}

## Stream Progress Events

Use `run()` when your application needs to display progress while the browser task is running:

```python
import asyncio

from gl_browser_use import BrowserUseClient, BrowserUseClientConfig


async def main() -> None:
    client = BrowserUseClient(config=BrowserUseClientConfig())

    async for event in client.run("Open Hacker News and list five article titles"):
        print(event.content)


asyncio.run(main())
```

The stream yields `BrowserUseStreamEvent` objects for progress updates, tool-call summaries, streaming URLs, recording URLs, retries, and final status.

## Use Hosted Browser Sessions

Install a hosted infrastructure provider when you want GL Browser Use to create a remote browser session:

{% tabs %}
{% tab title="Steel" %}

```bash
pip install "gl-browser-use[steel]"
export STEEL_API_KEY="your-steel-api-key"
```

```python
from gl_browser_use import BrowserUseClient, BrowserUseClientConfig
from gl_browser_use.infrastructure import SteelBrowserInfrastructure

client = BrowserUseClient(
    config=BrowserUseClientConfig(),
    infrastructure=SteelBrowserInfrastructure(),
)

result = client.run_sync("Open Hacker News and list five article titles")

print(result.session_id)
print(result.streaming_url)
```

{% endtab %}

{% tab title="OpenSandbox" %}

```bash
pip install "gl-browser-use[opensandbox]"
playwright install chromium  # one-time per environment
export OPENSANDBOX_DOMAIN="localhost:8080"
export OPENSANDBOX_API_KEY="your-opensandbox-api-key"
```

```python
from gl_browser_use import BrowserUseClient, BrowserUseClientConfig
from gl_browser_use.infrastructure import OpenSandboxBrowserInfrastructure

client = BrowserUseClient(
    config=BrowserUseClientConfig(),
    infrastructure=OpenSandboxBrowserInfrastructure(),
)

result = client.run_sync("Open Hacker News and list five article titles")

print(result.session_id)
print(result.streaming_url)
```

{% endtab %}
{% endtabs %}

With a hosted infrastructure configured, the result can include a `session_id` and `streaming_url`. Streaming mode also emits a `Receive streaming URL` activity event when a URL is available.

{% hint style="info" %}
OpenSandbox uses `OPENSANDBOX_DOMAIN` and optionally `OPENSANDBOX_API_KEY`. API keys are typically required for shared clusters but can be omitted for local insecure servers. See [Prerequisites](/sdk/gl-browser-use/prerequisites) for the one-time Chromium setup step.
{% endhint %}

## Next Steps

* [Run Browser Automation Tasks](/sdk/gl-browser-use/guides/run-browser-automation): Learn the streaming, async, and sync run methods.
* [Record Browser Sessions](/sdk/gl-browser-use/guides/record-browser-sessions): Configure hosted browser recordings with Steel or OpenSandbox plus MinIO or S3-compatible storage.
* [SDK Reference](/sdk/gl-browser-use/resources/reference): Review configuration, result, event, retry, and error contracts.


# Guides

This section provides task-oriented guides for integrating GL Browser Use into Python applications.

Choose a guide based on what you want to build:

* [**Run Browser Automation Tasks**](/sdk/gl-browser-use/guides/run-browser-automation): Use streaming, async, and synchronous execution methods.
* [**Record Browser Sessions**](/sdk/gl-browser-use/guides/record-browser-sessions): Use hosted browser infrastructure with object storage for session recordings through Steel or OpenSandbox.


# Run Browser Automation Tasks

This guide shows how to run browser automation tasks with GL Browser Use using the three public run methods: `run()`, `run_once()`, and `run_sync()`.

<details>

<summary>Prerequisites</summary>

Complete the setup steps in [Prerequisites](/sdk/gl-browser-use/prerequisites). You need `gl-browser-use` installed and an OpenAI API key available through `OPENAI_API_KEY` or `BrowserUseClientConfig`.

</details>

## 1. Create a Client

Start with `BrowserUseClientConfig`. If `OPENAI_API_KEY` is set, both model API key fields default to that value.

```python
from gl_browser_use import BrowserUseClient, BrowserUseClientConfig

client = BrowserUseClient(
    config=BrowserUseClientConfig(
        llm_openai_model="o3",
        page_extraction_llm_openai_model="gpt-5-mini",
        max_session_retries=2,
        session_retry_delay_in_s=3.0,
    )
)
```

You can also pass `llm_openai_api_key` and `page_extraction_llm_openai_api_key` directly when your application does not use environment variables.

{% hint style="info" %}
The examples below use the default local browser setup so the guide can stay focused on `run()`, `run_once()`, and `run_sync()`. If you need hosted infrastructure such as Steel or OpenSandbox, configure it first in [Getting Started](/sdk/gl-browser-use/getting-started) or [Record Browser Sessions](/sdk/gl-browser-use/guides/record-browser-sessions), then use the same run methods shown here.
{% endhint %}

## 2. Choose a Run Method

Use the method that fits your application runtime.

{% tabs %}
{% tab title="Streaming" %}

```python
import asyncio

from gl_browser_use import BrowserUseClient, BrowserUseClientConfig


async def main() -> None:
    client = BrowserUseClient(config=BrowserUseClientConfig())

    async for event in client.run("Compare pricing from two product pages"):
        print(event.content)


asyncio.run(main())
```

{% endtab %}

{% tab title="Async Result" %}

```python
import asyncio

from gl_browser_use import BrowserUseClient, BrowserUseClientConfig


async def main() -> None:
    client = BrowserUseClient(config=BrowserUseClientConfig())
    result = await client.run_once("Compare pricing from two product pages")

    print(result.status)
    print(result.final_output)
    print(len(result.events))


asyncio.run(main())
```

{% endtab %}

{% tab title="Sync Result" %}

```python
from gl_browser_use import BrowserUseClient, BrowserUseClientConfig

client = BrowserUseClient(config=BrowserUseClientConfig())
result = client.run_sync("Compare pricing from two product pages")

print(result.status)
print(result.final_output)
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
`run_sync()` uses `asyncio.run()` internally and must not be called from an already running event loop.
{% endhint %}

## 3. Handle Stream Events

Each streaming item is a `BrowserUseStreamEvent`:

```python
async for event in client.run("Find the latest release notes for a project"):
    if event.content == "Receive streaming URL":
        print("Browser stream:", event.thinking_and_activity_info)
    elif event.is_final:
        print("Finished:", event.content)
    else:
        print("Progress:", event.content)
```

Important event contents include:

1. `Receive streaming URL`: emitted when the hosted browser streaming URL is available.
2. `Receive recording URL`: emitted when a recording URL can be resolved.
3. `Task completed`: emitted for the final successful step.

Activity events encode iframe URLs in `thinking_and_activity_info["data_value"]` as a JSON string:

```json
{"type": "iframe", "message": "<url>"}
```

## 4. Inspect the Result

`BrowserUseRunResult` gives your application a stable result object:

```python
result = await client.run_once("Summarize the homepage of gdplabs.id")

if result.is_success:
    print(result.final_output)
else:
    print(result.error)

print(result.steps)
print(result.session_id)
print(result.streaming_url)
print(result.recording_url)
print(result.metadata)
```

The `events` field is populated by `run_once()`. Streaming consumers receive events as they happen through `run()`.

## 5. Configure Retries

The client retries only classified recoverable browser-session failures, such as browser closure or websocket disconnect messages.

```python
client = BrowserUseClient(
    config=BrowserUseClientConfig(
        max_session_retries=3,
        session_retry_delay_in_s=2.0,
    )
)
```

Total attempts are `max_session_retries + 1`. Non-recoverable task failures return `BrowserUseRunResult(status="error")`. Recoverable session failures that exhaust all attempts raise `BrowserUseRetryExhaustedError`.


# Record Browser Sessions

This guide shows how to run GL Browser Use with hosted browser infrastructure and object storage so your application can return browser streaming and recording URLs.

<details>

<summary>Prerequisites</summary>

Complete the setup steps in [Prerequisites](/sdk/gl-browser-use/prerequisites). You need:

1. `gl-browser-use[steel]` or `gl-browser-use[opensandbox]` for hosted browser infrastructure.
2. `gl-browser-use[minio]` for MinIO or S3-compatible object storage.
3. Hosted infrastructure credentials configured for the provider you use.
4. `OBJECT_STORAGE_*` variables configured when you want session recording uploads.

</details>

## 1. Install Optional Providers

Install only the providers your application uses:

{% tabs %}
{% tab title="Steel + MinIO" %}

```bash
pip install "gl-browser-use[steel]"
pip install "gl-browser-use[minio]"
```

{% endtab %}

{% tab title="OpenSandbox + MinIO" %}

```bash
pip install "gl-browser-use[opensandbox]"
playwright install chromium  # one-time per environment
pip install "gl-browser-use[minio]"
```

{% endtab %}
{% endtabs %}

Or install all currently available providers:

```bash
pip install "gl-browser-use[full]"
```

## 2. Configure Environment Variables

Configure the hosted browser provider your application uses:

{% tabs %}
{% tab title="Steel" %}

```bash
export STEEL_API_KEY="your-steel-api-key"
```

{% endtab %}

{% tab title="OpenSandbox" %}

```bash
export OPENSANDBOX_DOMAIN="localhost:8080"
export OPENSANDBOX_API_KEY="your-opensandbox-api-key"
```

{% endtab %}
{% endtabs %}

Configure object storage for recording uploads:

```bash
export OBJECT_STORAGE_URL="localhost:9001"
export OBJECT_STORAGE_USERNAME="your-access-key"
export OBJECT_STORAGE_PASSWORD="your-secret-key"
export OBJECT_STORAGE_BUCKET_NAME="browser-recordings"
export OBJECT_STORAGE_DIRECTORY_PREFIX="production"
export OBJECT_STORAGE_SECURE="false"
```

`MinIOS3CompatibleStorage` creates the bucket if it does not already exist.

## 3. Create the Client

Attach both the infrastructure and storage provider to `BrowserUseClient`:

{% tabs %}
{% tab title="Steel" %}

```python
from gl_browser_use import BrowserUseClient, BrowserUseClientConfig
from gl_browser_use.infrastructure import SteelBrowserInfrastructure
from gl_browser_use.storage import MinIOS3CompatibleStorage

client = BrowserUseClient(
    config=BrowserUseClientConfig(),
    infrastructure=SteelBrowserInfrastructure(),
    storage=MinIOS3CompatibleStorage.from_environment(),
)
```

{% endtab %}

{% tab title="OpenSandbox" %}

```python
from gl_browser_use import BrowserUseClient, BrowserUseClientConfig
from gl_browser_use.infrastructure import OpenSandboxBrowserInfrastructure
from gl_browser_use.storage import MinIOS3CompatibleStorage

client = BrowserUseClient(
    config=BrowserUseClientConfig(),
    infrastructure=OpenSandboxBrowserInfrastructure(),
    storage=MinIOS3CompatibleStorage.from_environment(),
)
```

{% endtab %}
{% endtabs %}

`SteelBrowserInfrastructure()` reads `STEEL_API_KEY` when `api_key` is not passed. `OpenSandboxBrowserInfrastructure()` reads `OPENSANDBOX_DOMAIN` and `OPENSANDBOX_API_KEY` when they are not passed directly. `MinIOS3CompatibleStorage.from_environment()` reads the `OBJECT_STORAGE_*` variables.

{% hint style="info" %}
OpenSandbox API keys are generally required for shared clusters but can be omitted when you run against a local insecure server. Complete the one-time Chromium setup from [Prerequisites](/sdk/gl-browser-use/prerequisites) before running OpenSandbox recording flows.
{% endhint %}

## 4. Run a Task

Use streaming mode when you want to surface the live browser view as soon as it is available:

{% tabs %}
{% tab title="Steel" %}

```python
import asyncio

from gl_browser_use import BrowserUseClient, BrowserUseClientConfig
from gl_browser_use.infrastructure import SteelBrowserInfrastructure
from gl_browser_use.storage import MinIOS3CompatibleStorage


async def main() -> None:
    client = BrowserUseClient(
        config=BrowserUseClientConfig(),
        infrastructure=SteelBrowserInfrastructure(),
        storage=MinIOS3CompatibleStorage.from_environment(),
    )

    async for event in client.run("Open Hacker News and list five article titles"):
        print(event.content)


asyncio.run(main())
```

{% endtab %}

{% tab title="OpenSandbox" %}

```python
import asyncio

from gl_browser_use import BrowserUseClient, BrowserUseClientConfig
from gl_browser_use.infrastructure import OpenSandboxBrowserInfrastructure
from gl_browser_use.storage import MinIOS3CompatibleStorage


async def main() -> None:
    client = BrowserUseClient(
        config=BrowserUseClientConfig(),
        infrastructure=OpenSandboxBrowserInfrastructure(),
        storage=MinIOS3CompatibleStorage.from_environment(),
    )

    async for event in client.run("Open Hacker News and list five article titles"):
        print(event.content)


asyncio.run(main())
```

{% endtab %}
{% endtabs %}

For a single aggregated result:

```python
result = client.run_sync("Open Hacker News and list five article titles")

print(result.session_id)
print(result.streaming_url)
print(result.recording_url)
print(result.metadata)
```

## 5. Understand Recording Metadata

Recording metadata is returned in `result.metadata`:

1. `disabled`: infrastructure, storage, or browser context is not available.
2. `unsupported`: the selected infrastructure does not support recording.
3. `unavailable`: storage is configured but not available.
4. `scheduled`: a background recording upload has been scheduled.
5. `unknown`: recording may have started, but the terminal error did not include enough context to determine the final state.

When recording is available, GL Browser Use resolves the expected object URL and schedules the recording upload in the background during cleanup.

{% hint style="info" %}
Recording requires both an infrastructure provider that supports recordings and an available object storage provider. Local browser execution can still run tasks, but it does not produce hosted streaming or recording URLs.
{% endhint %}




---

[Next Page](/sdk/llms-full.txt/1)

