Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save jamesjfoong/29c23a0b9e1581ca751deaaf2c6e2043 to your computer and use it in GitHub Desktop.

Select an option

Save jamesjfoong/29c23a0b9e1581ca751deaaf2c6e2043 to your computer and use it in GitHub Desktop.
GDP Labs AI Stack Field Guide + full CATAPA DE GitBook (GL SDK, Connectors, Digital Employee Core)

GDP Labs AI Stack Field Guide

A concise map of the moving pieces: GL SDK / GLAIP, GLAIR Connectors, and CATAPA Digital Employee.

1. Ecosystem map

flowchart TB
    subgraph GL["GL SDK / GLAIP"]
        A["Agent runtime<br/>LLM calls, memory, streaming<br/>PII masking, tracing"]
    end

    subgraph CATAPA_SDK["CATAPA SDK"]
        C["catapa<br/>Public CATAPA API"]
        CP["catapa_private<br/>Internal CATAPA API"]
    end

    subgraph CONN_SDK["GL Connectors SDK / Tools"]
        CS["gl_connectors_sdk<br/>Direct connector API"]
        CT["gl_connectors_tools<br/>Skill factory + MCPs"]
    end

    subgraph CONN_HOST["GLAIR Connectors host"]
        H1["connectors.glair.ai<br/>Public API"]
        H2["connectors.gdplabs.id<br/>Internal runtime"]
        CON["Connectors Console"]
    end

    subgraph DE["CATAPA Digital Employee"]
        D["LangChain/LangGraph agents<br/>tools + MCPs"]
    end

    A -->|calls| C
    A -->|calls| CP
    A -->|forwards| CS
    A -->|uses| CT
    CS -->|REST| H1
    CS -->|REST| H2
    CT -->|installs skills/MCPs| H2
    A -->|gl_connectors_token| D
    D -->|catapa SDK| C
    D -->|catapa_private SDK| CP
    D -->|sync connector methods| CS
    H1 -->|OAuth callback| D
    H2 -->|MCP server| D
    CON -->|configure integrations| H1
    CON -->|configure integrations| H2
Loading

Everything in the diagram is connected, but the arrow style matters:

  • Solid arrows = direct code/API dependencies.
  • Labeled arrows = token propagation or runtime wiring.
  • GLAIP can talk to CATAPA data, GL Connectors API, and GL Connectors MCP servers.
  • A Digital Employee reuses the same SDKs and connector runtime, but adds its own agent topology and CATAPA-specific guardrails.

2. GL SDK / GLAIP

GL SDK = GDP Labs Software Development Kit. GLAIP = the agent-interaction layer (SDK + runtime).

Key packages:

Package What it does
glaip-sdk Agent runtime, Agent, run_agent, streaming, runtime_config, trace, MCP
gl-connectors-sdk Direct connector API fluent interface
gl-connectors-tools / gl-connectors-tools-binary Skill factory, install skills from GitHub
catapa Public CATAPA API SDK
catapa_private Internal/private CATAPA API SDK

Common AIP patterns:

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"]}},
)

Token propagation for connector auth:

client.run_agent(
    agent_id="...",
    message="...",
    gl_connectors_token="<user-token>",
)
  • gl_connectors_token is forwarded to /agents/{agent_id}/run and used for GL Connectors pre-checks.
  • During local make run it may not reach custom tools; add env fallback (GL_CONNECTORS_TOKEN) in the tool.

3. GLAIR Connectors

GLAIR Connectors is an OAuth gateway and tool catalog for external services (Google, GitHub, Slack, SQL, etc.).

Three ways to use it

Use when Approach
One precise external operation Direct API (gl_connectors_sdk)
Agent needs broad/uncertain access to a service MCP server with allowed_tools
Repeatable workflow, formatting, rules Agent Skill

API surface (admin/registry)

Base URLs:

  • https://connectors.glair.ai — common public API
  • https://connectors.gdplabs.id — internal/GL ecosystem runtime
  • Console: https://connectors.glair.ai/console

Main endpoints:

  • POST /clients — create client (API key holder)
  • GET /clients, PATCH /clients — list / update
  • POST /users — create user
  • POST /auth/tokens — login, get user token
  • DELETE /auth/tokens — logout
  • GET /users/me
  • GET /connectors/{name}/auth-schema — auth config shape
  • POST /connectors/{name}/integrations — create integration
  • GET|POST|DELETE /connectors/{name}/integrations/{user_identifier}
  • GET /connectors/{name}/success-authorize-callback — OAuth callback
  • GET /catalog/mcp — list MCP servers
  • GET /catalog/tools — list native tools
  • GET /skills/list — curated skills registry
  • GET /skills/openclaw — UGC skills
  • GET /api/skills — skill details list
  • POST /api/skills — register a new skill
  • POST /api/skills/tenants — attach skill to tenant
  • GET /api/skills/tenants/{client_id}
  • PUT|GET|DELETE /api/skills/{skill_id}

SDK fluent shape

from gl_connectors_sdk.connector import GLConnectors

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()
)

MCP server pattern

https://connectors.gdplabs.id/<connector>/mcp

Examples:

  • GitHub: https://connectors.gdplabs.id/github/mcp
  • Google Mail: https://connectors.gdplabs.id/google_mail/mcp
  • Slack: https://connectors.gdplabs.id/slack/mcp

Auth: X-Api-Key header for client, Authorization: Bearer <user-token> for user. Optional X-Integration to pick a specific integration.

Always restrict tools:

mcp_configs={
    "github": {"allowed_tools": ["github_list_pull_requests"]}
}

4. CATAPA Digital Employee

A Digital Employee (DE) is an LLM-driven agent inside CATAPA that answers domain-specific requests and performs workflows.

Topology

  • Single agent: one domain, few tools, no specialist boundary.
  • Coordinator + sub-agents: multiple specialists, different tools per responsibility, coordinator routes work.

Default: prefer single agent unless multi-agent clearly reduces risk.

Build workflow (de-build-de-catapa)

Source of truth repo: https://github.com/GDP-ADMIN/prompt-template/tree/main/project-wide/digital-employee

Steps:

  1. Prepare PRD.
  2. Read de-build-de-catapa/README.md and AGENTS.md.
  3. Fill <REPLACE: ...> placeholders in step prompts.
  4. step-1-scaffolding.sh
  5. step-2-architecture-specification.md
  6. Review architecture (tools, MCPs, sub-agents, missing/unnecessary parts).
  7. step-3-implementation-specification.md
  8. Review spec (no invented endpoints, no invented query syntax, clear env vars, good errors).
  9. step-4-implementation.md
  10. Configure .env.
  11. make run MESSAGE="...".
  12. step-5-validation-and-compliance.md.
  13. step-6-integration-test-verification.md (live tests when feasible).

Prompt templates

  • prompt-template-single-agent-instructions.md
  • prompt-template-multi-agent-coordinator-instructions.md
  • prompt-template-multi-agent-subagent-instructions.md

These are instruction scaffolding, not runtime code.

CATAPA SDK notes

Public import:

from catapa import Catapa

Private/internal import:

from catapa_private import CatapaPrivate

SDK version: minimum >=0.3.3; TMO pins 0.3.6. Pin to latest compatible per DE.

Querying CATAPA API

Use RSQL ?filter=:

?filter=companyId==zfrl;status==active
?filter=employeeId=in=(123,456)
?filter=createdAt=gt=2025-01-01

Operators: ==, =in=, =gt=, =ge=, =lt=, =le=, =contains=. Combine with ; (AND) or , (OR within same field).

Legacy ?query= with : / > / < / , is deprecated and overloaded; avoid in new code.

Pagination: default size is small; use up to 50 per page from CATAPA-API OpenAPI spec. TMO uses internal RECAPITULATION_DETAIL_PAGE_SIZE = 400 for its own batching.

Guardrails

  • Never guess CATAPA endpoints or query params.
  • Enforce tenant isolation.
  • No raw PII in logs/output.
  • No logger.info() on raw result objects.
  • Use HITL for risky writes.
  • Register MCPs per-agent, not globally.
  • Prefer built-in tools/MCPs over custom code.
  • Keep business reasoning in prompts/instructions, not tool/client code.

5. Integration patterns

When to use what

Need Use
Single deterministic external call gl_connectors_sdk API
Agent chooses among many service actions MCP server with allowed_tools
Repeatable format/checklist/workflow Agent Skill
CATAPA HRIS data catapa / catapa_private SDK
Live CATAPA action CATAPA SDK + correct tenant/user

Export + notification pattern

For Excel/PDF artifacts + email:

  1. Generate artifact, upload to object storage, get presigned URL.
  2. Call google_mail sync method inside LangChain _run (async fails inside running event loop).
  3. Build email body in tool with _format_email_body() so markdown table/sections survive LLM collapse.
  4. Use real presigned URL; never leave placeholder variables.

Verifying sent email

Use gogcli (gog gmail get/search) rather than browser automation. Faster and authoritative.

6. Quick command cheat sheet

# Run a DE locally
make run MESSAGE="Run lateness frequency analysis for Finance last month"

# GL Connectors SDK install
uv add gl-connectors-sdk

# GL Connectors tools/skill install
uv add gl-connectors-tools-binary

# AIP SDK install
uv add glaip-sdk

# CATAPA SDK
uv add catapa catapa-private

# GitHub prompt-template source
gh api repos/GDP-ADMIN/prompt-template/contents/project-wide/digital-employee/de-build-de-catapa/README.md

7. Digital Employee Core (digital-employee-core)

digital-employee-core is the Python framework library every CATAPA DE is built on. It wraps glaip-sdk and adds DE-specific primitives.

Install

uv add digital-employee-core
# or from CodeArtifact:
uv pip install --index-url https://aws:$CODEARTIFACT_AUTH_TOKEN@$CODEARTIFACT_REPOSITORY_ENDPOINT/simple/ digital-employee-core

Main exports

from digital_employee_core import (
    DigitalEmployee,
    DigitalEmployeeAgent,
    DigitalEmployeeBuilder,
    DigitalEmployeeConfig,
    DigitalEmployeePipelineBuilder,
    DigitalEmployeeState,
    DigitalEmployeeIdentity,
    DigitalEmployeeJob,
    DigitalEmployeeSupervisor,
    ConfigTemplateLoader,
)

from digital_employee_core.constants import (
    DEFAULT_MODEL_NAME,
    GPT_5_MODEL_NAME,
    GPT_5_MINI_MODEL_NAME,
    GPT_5_1_MODEL_NAME,
    GPT_5_2_MODEL_NAME,
)

What it provides

Concern What digital-employee-core gives you
Identity DigitalEmployeeIdentity, DigitalEmployeeJob, DigitalEmployeeSupervisor
Configuration DigitalEmployeeConfig + ConfigTemplateLoader for YAML placeholder substitution
Runtime DigitalEmployee.run(message=..., local=True) and .deploy()
MCPs Pre-built connector MCP imports (google_mail_mcp, google_calendar_mcp, google_docs_mcp)
Tools Utility tool imports and LangChain tool registration helpers
Scheduling ScheduleItemConfig for recurring DE runs
Escalation Escalation channels and supervisor wiring
BVT DeploymentVerifier, BVTCheckResult, BVTStatus
Agents DigitalEmployeeAgent / Agent for coordinator + sub-agents

Relationship to GLAIP

flowchart TB
    subgraph DE["CATAPA Digital Employee"]
        D["main.py / custom tools"]
    end

    subgraph DECore["digital-employee-core"]
        Core["DigitalEmployee\nDigitalEmployeeIdentity\nMCP/tool wiring\nBVT / schedule / escalation"]
    end

    subgraph AIP["GL SDK / GLAIP"]
        A["Agent, MCP, run_agent\nmemory, streaming, PTC, trace"]
    end

    D -->|imports| Core
    Core -->|wraps| A
    D -->|may also use directly| A
Loading

glaip-sdk is the lower-level agent runtime; digital-employee-core is the CATAPA DE abstraction on top. A DE imports from both: digital_employee_core.* for DE primitives and glaip_sdk.* when it needs direct Agent, MCP, PTC, or schedule access.

Current versions in repo

DE / template digital-employee-core version
Template default 0.0.35
Weekly Report >=0.0.23
Personnel Admin >=0.0.33,<0.1.0
Payroll Officer ==0.0.31
Dummy SQL ==0.0.32

Pin per DE; newer isn't automatically safer because DEs depend on specific internal APIs.

Source

  • Local source: ~/Documents/github/CATAPA/CATAPA-SDK/main/python/digital-employee-core/
  • Published to AWS CodeArtifact catapa-digital-employee-core PyPI repo.
  • GitBook docs: same CATAPA Digital Employee section.

8. Source-of-truth links

Topic Location
GL SDK docs /llms-full.txt on SDK GitBook
GL Connectors API spec /tmp/glair-openapi.json (or connectors.glair.ai/openapi.json)
GL Connectors SDK usage skill_view:glair-connectors
GL Connectors HTTP endpoints skill_view:glair-connectors-api
CATAPA DE GitBook https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/
CATAPA DE GitBook markdown trick append .md to page URL
CATAPA DE build prompts https://github.com/GDP-ADMIN/prompt-template/tree/main/project-wide/digital-employee
CATAPA DE repo ~/Documents/github/CATAPA/digital-employee/main
CATAPA API/OpenAPI ~/Documents/github/CATAPA/CATAPA-API
CATAPA SDK ~/Documents/github/CATAPA/CATAPA-SDK

Last updated: 2026-07-02. If a link breaks, prefer the local CATAPA clone or the SDK GitBook /llms-full.txt over web search snippets.


Appendix: Full CATAPA Digital Employee GitBook

CATAPA Digital Employee GitBook

catapa/developer documentation/digital employee

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Digital Employee 4| 5|- Digital Employee Architecture 6|- Tech Stack Overview 7|- Digital Employee Detailed Block Diagram 8|- Multi-tenant 9|- Install and Configure 10|- Getting Started Example 11|- Advanced Examples 12|- Extend 13|- Instantiation 14|- Digital Employee Supervisor 15|- Sub Agents Configuration 16|- Skills Configuration 17|- MCP Allowed Tools Configuration 18|- Escalation Configuration 19|- Scheduler Configuration 20|- Memory Configuration 21|- Programmatic Tool Calling (PTC) Configuration 22|- Build Verification Tests (BVT) 23|- User Information in Digital Employee Runs 24|- Run History 25|- Recommended Project Structure 26| 27| 28|--- 29| 30|# Agent Instructions 31|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 32| 33|## Querying This Documentation 34|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 35| 36|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 37| 38| 39|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee.md?ask=<question>&goal=<endgoal> 40| 41| 42|ask is the immediate question: it should be specific, self-contained, and written in natural language. 43|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 44| 45|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 46| 47|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 48|


advanced examples

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Advanced Examples 4| 5|- Extend 6|- Instantiation 7|- Digital Employee Supervisor 8|- Sub Agents Configuration 9|- Skills Configuration 10|- MCP Allowed Tools Configuration 11|- Escalation Configuration 12|- Scheduler Configuration 13|- Memory Configuration 14|- Programmatic Tool Calling (PTC) Configuration 15|- Build Verification Tests (BVT) 16|- User Information in Digital Employee Runs 17|- Run History 18|- Recommended Project Structure 19| 20| 21|--- 22| 23|# Agent Instructions 24|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 25| 26|## Querying This Documentation 27|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 28| 29|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 30| 31| 32|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples.md?ask=<question>&goal=<endgoal> 33| 34| 35|ask is the immediate question: it should be specific, self-contained, and written in natural language. 36|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 37| 38|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 39| 40|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 41|


advanced examples/build verification tests bvt

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Build Verification Tests (BVT) 4| 5|### Overview 6| 7|Build Verification Tests (BVT) provide a pre-deployment validation step for DigitalEmployee. Before the underlying agent is deployed, BVT verifies that the resolved agent graph and its MCP integrations are usable. 8| 9|BVT is implemented by DeploymentVerifier in digital_employee_core.bvt.verifier and is executed automatically by DigitalEmployee.deploy() unless you explicitly disable it. 10| 11|At a high level, the default verifier checks: 12| 13|* The root agent and all nested sub-agents recursively 14|* Every MCP attached to each agent node 15|* Whether the MCP URL is present and well-formed 16|* Whether an MCP session can actually be created and initialized 17| 18|This helps catch deployment issues early, before they fail at runtime. 19| 20|### When BVT Runs 21| 22|BVT runs during deployment: 23| 24|python 25|digital_employee.deploy() 26| 27| 28|By default, deploy() does this sequence: 29| 30|1. Build the resolved glaip_sdk.Agent instance 31|2. Run self.verifier.verify(self.agent) 32|3. Raise BuildVerificationError if any check failed 33|4. Continue to agent.deploy() only when all checks passed 34| 35|The implementation also supports skipping verification: 36| 37|python 38|digital_employee.deploy(run_bvt=False) 39| 40| 41|Use run_bvt=False only when you intentionally want to bypass pre-deployment validation. 42| 43|### Key Concepts 44| 45|#### What the default verifier checks 46| 47|The built-in DeploymentVerifier performs MCP-focused checks on the fully resolved agent tree: 48| 49|* Recursive agent traversal: walks the top-level agent and every nested sub-agent 50|* URL validation: checks that each MCP config contains a URL with both scheme and host 51|* Session initialization: creates an MCP session and calls session.initialize() 52|* Authentication propagation check by execution: auth headers are built from the resolved config and used during session creation 53| 54|This means BVT validates the final resolved configuration, not just the original constructor inputs. 55| 56|#### Pass, fail, and skip semantics 57| 58|Each check produces a BVTCheckResult with one of three statuses: 59| 60|* passed: the check succeeded 61|* failed: the check failed and should block deployment 62|* skipped: the check was intentionally not run 63| 64|Important behavior: 65| 66|* BVTResults.all_passed only returns False when at least one check is failed 67|* skipped checks do not block deployment by themselves 68| 69|For example, if an MCP exists on the agent but no matching config is found, the default verifier marks it as skipped with the message No configuration found — skipped. 70| 71|#### What causes deployment to fail 72| 73|Deployment is blocked when any BVT check returns failed. 74| 75|Common failure conditions in the default verifier include: 76| 77|* MCP has no name 78|* MCP URL is missing or empty 79|* MCP URL is malformed 80|* MCP session initialization raises an exception 81|* Authentication is invalid 82|* The MCP endpoint is unreachable or times out 83| 84|### Default Verification Flow 85| 86|The built-in DeploymentVerifier follows this sequence: 87| 88|1. Reset previous results 89|2. Run _pre_checks(agent) 90|3. Traverse the agent tree depth-first 91|4. Run _check_agent_node(agent) for each visited node 92|5. Verify each MCP on that node 93|6. Run _post_checks(agent) 94| 95|Each MCP verification does: 96| 97|1. Resolve the MCP config from agent.mcp_configs 98|2. Extract the URL from config["config"]["url"] 99|3. Validate the URL format 100|4. Build an MCPConfiguration for create_session() 101|5. Attempt real session initialization 102| 103|This is not a schema-only validation. The verifier performs a real initialization attempt, which makes it useful for catching network, auth, and protocol issues. 104| 105|### Handling BVT Failures 106| 107|Catch BuildVerificationError if you want to inspect or log the failure before exiting: 108| 109|{% code lineNumbers="true" %} 110| 111|python 112|from digital_employee_core import BuildVerificationError 113| 114|try: 115| digital_employee.deploy() 116|except BuildVerificationError as exc: 117| print(exc) 118| 119| 120|{% endcode %} 121| 122|The exception message is generated from BVTResults.summary(), which includes: 123| 124|* Total passed checks 125|* Total failed checks 126|* Total skipped checks 127|* Names of failed checks 128|* Names of skipped checks 129| 130|### Custom Verifiers 131| 132|The verifier is injectable. DigitalEmployee accepts a verifier parameter: 133| 134|{% code lineNumbers="true" %} 135| 136|python 137|from digital_employee_core import DeploymentVerifier, DigitalEmployee 138| 139|verifier = DeploymentVerifier(timeout=15) 140| 141|digital_employee = DigitalEmployee( 142| identity=identity, 143| mcps=[google_mail_mcp], 144| configurations=configurations, 145| verifier=verifier, 146|) 147| 148| 149|{% endcode %} 150| 151|You can also subclass DeploymentVerifier to add organization-specific checks. 152| 153|#### Extension points 154| 155|The base class provides three hooks: 156| 157|* _pre_checks(agent): runs before MCP traversal 158|* _check_agent_node(agent): runs once per visited agent node 159|* _post_checks(agent): runs after traversal finishes 160| 161|Each hook should yield or return BVTCheckResult instances. 162| 163|#### Example: add pre-deployment policy checks 164| 165|The repository already includes a working example in examples/custom_deployment_verifier_example.py. 166| 167|This example defines StrictDeploymentVerifier, which adds: 168| 169|* Required environment variable checks 170|* A deployment policy check 171|* The standard MCP verification from the base verifier 172| 173|Example structure: 174| 175|{% code lineNumbers="true" %} 176| 177|python 178|from collections.abc import Iterable 179| 180|from glaip_sdk import Agent 181| 182|from digital_employee_core import BVTCheckResult, BVTStatus, DeploymentVerifier 183| 184| 185|class StrictDeploymentVerifier(DeploymentVerifier): 186| def _pre_checks(self, agent: Agent) -> Iterable[BVTCheckResult]: 187| yield BVTCheckResult( 188| name="deployment_policy", 189| item_type="policy", 190| status=BVTStatus.PASSED, 191| message="Custom policy passed", 192| ) 193| 194| 195|{% endcode %} 196| 197|This pattern is useful when you want to validate things such as: 198| 199|* Required environment variables 200|* Required configuration keys 201|* Service health checks 202|* Naming conventions 203|* Deployment environment policy 204| 205|#### BVTStatus 206| 207|BVTStatus is a StrEnum with these values: 208| 209|* BVTStatus.PASSED 210|* BVTStatus.FAILED 211|* BVTStatus.SKIPPED 212| 213|#### BVTCheckResult 214| 215|Represents a single check result: 216| 217|{% code lineNumbers="true" %} 218| 219|python 220|BVTCheckResult( 221| name="google_mail_mcp", 222| item_type="mcp", 223| status=BVTStatus.PASSED, 224| message="MCP session initialized successfully", 225| details={}, 226|) 227| 228| 229|{% endcode %} 230| 231|Fields: 232| 233|* name: item being checked 234|* item_type: category such as mcp, agent, env_var, or policy 235|* status: one of the BVTStatus values 236|* message: human-readable result description 237|* details: optional diagnostic metadata 238| 239|#### BVTResults 240| 241|Aggregates all check results and provides convenience properties: 242| 243|{% code lineNumbers="true" %} 244| 245|python 246|results = verifier.verify(agent) 247| 248|print(results.all_passed) 249|print(results.failed_checks) 250|print(results.skipped_checks) 251|print(results.summary()) 252| 253| 254|{% endcode %} 255| 256|Available helpers: 257| 258|* all_passed 259|* failed_checks 260|* skipped_checks 261|* summary() 262| 263|### Transport and Timeout Notes 264| 265|The default verifier supports MCP transports via the MCP definition on each agent node. 266| 267|Behavior worth knowing: 268| 269|* If an MCP does not define a transport, the verifier uses streamable_http 270|* For non-stdio transports, the generated session config includes timeout=self.timeout 271|* For stdio, the verifier applies asyncio.wait_for(..., timeout=self.timeout) around session.initialize() 272| 273|In practice, this means the timeout constructor parameter on DeploymentVerifier controls how long initialization is allowed to take before failing. 274| 275|Example: 276| 277|{% code lineNumbers="true" %} 278| 279|python 280|verifier = DeploymentVerifier(timeout=30) 281| 282| 283|{% endcode %} 284| 285|### Best Practices 286| 287|#### 1. Keep BVT enabled in normal deployments 288| 289|The default deploy() behavior is correct for most cases. Bypass it only when you have a deliberate operational reason. 290| 291|#### 2. Treat skipped checks as signals 292| 293|A skipped MCP check usually means the MCP exists on the agent but no resolved config was found. That may be intentional, but it is often a configuration gap worth reviewing. 294| 295|#### 3. Use custom verifiers for organization rules 296| 297|If your deployment process depends on environment flags, external services, or policy enforcement, encode those rules in a custom DeploymentVerifier subclass instead of checking them manually elsewhere. 298| 299|#### 4. Use the built agent as the source of truth 300| 301|BVT runs against the resolved agent returned by _build_agent_instance(). This is the correct layer for validation because it includes propagated and merged configs. 302| 303|#### 5. Log or surface results.summary() 304| 305|When deployment fails, the BVT summary provides a concise diagnosis that is suitable for CI logs or deployment output. 306| 307|### Troubleshooting 308| 309|#### BuildVerificationError during deploy 310| 311|Problem: digital_employee.deploy() raises BuildVerificationError. 312| 313|What it means: At least one BVT check returned failed. 314| 315|Solution: 316| 317|* Inspect the exception message 318|* Review the failed check names 319|* Confirm MCP URLs are present and valid 320|* Confirm authentication headers are correct 321|* Verify the MCP endpoint is reachable from the deployment environment 322| 323|#### MCP check is skipped 324| 325|Problem: A result is marked as skipped with a message like No configuration found — skipped. 326| 327|What it means: The MCP exists on the agent, but no matching config entry was found in agent.mcp_configs. 328| 329|Solution: 330| 331|* Confirm the MCP was configured through DigitalEmployeeConfiguration 332|* Confirm the configuration key matches the connector template 333|* Confirm the config was propagated to the final built agent 334| 335|#### URL format failure 336| 337|Problem: The result message indicates an invalid URL format. 338| 339|What it means: The resolved MCP URL is missing a scheme or host. 340| 341|Solution: 342| 343|* Use a full URL such as https://example.com/mcp 344|* Avoid bare hostnames like example.com/mcp 345|* Avoid empty values produced by missing environment variables 346| 347|#### Session initialization failure 348| 349|Problem: The URL looks valid, but session initialization still fails. 350| 351|What it usually means: 352| 353|* The endpoint is down 354|* Authentication is invalid 355|* The MCP server is not speaking the expected protocol 356|* Initialization timed out 357| 358|Solution: 359| 360|* Verify endpoint reachability 361|* Verify auth headers and tokens 362|* Increase verifier timeout if the service is slow to initialize 363|* Test the MCP independently if needed 364| 365|### API Summary 366| 367|Most users only need these exported symbols: 368| 369|{% code lineNumbers="true" %} 370| 371|python 372|from digital_employee_core import ( 373| BuildVerificationError, 374| BVTCheckResult, 375| BVTResults, 376| BVTStatus, 377| DeploymentVerifier, 378|) 379| 380| 381|{% endcode %} 382| 383|These cover: 384| 385|* Failure handling with BuildVerificationError 386|* Modeling individual and aggregate results 387|* Creating default or custom verifiers 388| 389| 390|--- 391| 392|# Agent Instructions 393|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 394| 395|## Querying This Documentation 396|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 397| 398|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 399| 400| 401|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/build-verification-tests-bvt.md?ask=<question>&goal=<endgoal> 402| 403| 404|ask is the immediate question: it should be specific, self-contained, and written in natural language. 405|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 406| 407|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 408| 409|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 410|


advanced examples/digital employee supervisor

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Digital Employee Supervisor 4| 5|### Overview 6| 7|A Digital Employee Supervisor represents the human point-of-contact a Digital Employee can route decisions or blockers to. 8| 9|In Digital Employee Core, a supervisor is modeled on the identity: 10| 11|* DigitalEmployeeIdentity.supervisor 12|* DigitalEmployeeSupervisor(name=..., email=...) 13| 14|### Minimal Setup 15| 16|#### 1) Create a supervisor 17| 18|{% code lineNumbers="true" %} 19| 20|python 21|import os 22| 23|from digital_employee_core import DigitalEmployeeSupervisor 24| 25|supervisor = DigitalEmployeeSupervisor( 26| name=os.getenv("SUPERVISOR_NAME", ""), 27| email=os.getenv("SUPERVISOR_EMAIL", ""), 28|) 29| 30| 31|{% endcode %} 32| 33|#### 2) Attach the supervisor to the identity 34| 35|{% code lineNumbers="true" %} 36| 37|python 38|from digital_employee_core import DigitalEmployeeIdentity, DigitalEmployeeJob 39| 40|job = DigitalEmployeeJob( 41| title="Operations Assistant", 42| description="A digital employee that can escalate to a supervisor when blocked", 43| instruction=( 44| "You help with operational tasks. " 45| "If a tool fails or you encounter a critical blocker, follow the escalation protocol." 46| ), 47|) 48| 49|identity = DigitalEmployeeIdentity( 50| name="Ops Assistant - Example", 51| email="ops.assistant@example.com", 52| job=job, 53| supervisor=supervisor, 54|) 55| 56| 57|{% endcode %} 58| 59|### Where It Is Used 60| 61|* Escalation Configuration 62| 63| 64|--- 65| 66|# Agent Instructions 67|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 68| 69|## Querying This Documentation 70|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 71| 72|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 73| 74| 75|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/digital-employee-supervisor.md?ask=<question>&goal=<endgoal> 76| 77| 78|ask is the immediate question: it should be specific, self-contained, and written in natural language. 79|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 80| 81|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 82| 83|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 84|


advanced examples/escalation configuration

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Escalation Configuration 4| 5|### Overview 6| 7|Escalation allows a Digital Employee to route a task to a human supervisor (see Digital Employee Supervisor) when it is blocked (e.g., tool failures, missing permissions, critical ambiguity). Escalation is opt-in and must be explicitly enabled. 8| 9|In this repository, see examples/escalation_example.py for a working end-to-end example. 10| 11|### Key Concepts 12| 13|#### Supervisor 14| 15|Escalation is designed to reach a supervisor configured on the Digital Employee identity: 16| 17|* DigitalEmployeeIdentity.supervisor 18|* DigitalEmployeeSupervisor(name=..., email=...) 19| 20|If escalation is enabled and a supervisor exists, the escalation protocol is included in the generated prompt. 21| 22|#### Escalation Channels 23| 24|Escalation is delivered via one or more channels (e.g., email). 25| 26|Channels can introduce additional runtime dependencies (MCP connectors/tools). This matters at deployment time. 27| 28|In this guide, we will use the GoogleMailMCPEscalationChannel as an example. 29| 30|### Example 31| 32|#### Step 1: Import dependencies 33| 34|{% code lineNumbers="true" %} 35| 36|python 37|import os 38| 39|from digital_employee_core import ( 40| DigitalEmployee, 41| DigitalEmployeeConfiguration, 42| DigitalEmployeeIdentity, 43| DigitalEmployeeJob, 44| DigitalEmployeeSupervisor, 45|) 46|from digital_employee_core.connectors.mcps import google_docs_mcp 47|from digital_employee_core.escalation.channels.google_mail_mcp_channel import ( 48| GoogleMailMCPEscalationChannel, 49|) 50| 51| 52|{% endcode %} 53| 54|#### Step 2: Define the job with escalation instructions 55| 56|{% code lineNumbers="true" %} 57| 58|python 59|job = DigitalEmployeeJob( 60| title="Operations Assistant", 61| description="A digital employee that can escalate to a supervisor when blocked", 62| instruction=( 63| "You help with operational tasks. " 64| "If a tool fails or you encounter a critical blocker, follow the escalation protocol." 65| ), 66|) 67| 68| 69|{% endcode %} 70| 71|{% hint style="warning" %} 72|Important: Use the term "escalation protocol" in the Digital Employee instructions whenever we need to refer to or trigger the escalation flow. 73|{% endhint %} 74| 75|#### Step 3: Configure the supervisor 76| 77|{% code lineNumbers="true" %} 78| 79|python 80|supervisor = DigitalEmployeeSupervisor( 81| name=os.getenv("SUPERVISOR_NAME", ""), 82| email=os.getenv("SUPERVISOR_EMAIL", ""), 83|) 84| 85| 86|{% endcode %} 87| 88|{% hint style="info" %} 89|Note: The following environment variables are required to enable escalation: 90| 91|* SUPERVISOR_NAME 92|* SUPERVISOR_EMAIL 93| {% endhint %} 94| 95|#### Step 4: Create the identity 96| 97|{% code lineNumbers="true" %} 98| 99|python 100|identity = DigitalEmployeeIdentity( 101| name="Ops Assistant - Example", 102| email="ops.assistant@example.com", 103| job=job, 104| supervisor=supervisor, 105|) 106| 107| 108|{% endcode %} 109| 110|#### Step 5: Set up configurations 111| 112|{% code lineNumbers="true" %} 113| 114|python 115|configurations = [ 116| DigitalEmployeeConfiguration(key="GOOGLE_MAIL_MCP_URL", value=os.getenv("GOOGLE_MAIL_MCP_URL", "")), 117| DigitalEmployeeConfiguration(key="GOOGLE_DOCS_MCP_URL", value=os.getenv("GOOGLE_DOCS_MCP_URL", "")), 118| DigitalEmployeeConfiguration(key="GOOGLE_MCP_X_API_KEY", value=os.getenv("GOOGLE_MCP_X_API_KEY", "")), 119|] 120| 121| 122|{% endcode %} 123| 124|{% hint style="info" %} 125|Note: The following environment variables are required to enable the Google Mail MCP escalation channel: 126| 127|* GOOGLE_MAIL_MCP_URL 128|* GOOGLE_MCP_X_API_KEY 129| 130|These values are typically passed into DigitalEmployeeConfiguration so they become part of the deployed agent configuration. Adjust the environment variables based on your escalation channel. 131|{% endhint %} 132| 133|#### Step 6: Initialize the Digital Employee 134| 135|{% code lineNumbers="true" %} 136| 137|python 138|digital_employee = DigitalEmployee( 139| identity=identity, 140| mcps=[google_docs_mcp], 141| configurations=configurations, 142|) 143| 144| 145|{% endcode %} 146| 147|#### Step 7: Enable escalation and add channels 148| 149|{% code lineNumbers="true" %} 150| 151|python 152|digital_employee.enable_escalation() 153|digital_employee.add_escalation_channel(GoogleMailMCPEscalationChannel()) 154| 155| 156|{% endcode %} 157| 158|#### Step 8: Deploy and run 159| 160|{% code lineNumbers="true" %} 161| 162|python 163|digital_employee.deploy() 164|result = digital_employee.run(message="Read google docs with document_id='123413'") 165| 166| 167|{% endcode %} 168| 169|#### Deployment Order Matters 170| 171|* Enable escalation and add channels before calling digital_employee.deploy(). 172|* The deploy step will bundle any required MCP connectors/tools introduced by escalation channels. 173| 174|### Custom Escalation Channels 175| 176|Escalation channels are extensible. To create your own channel, implement EscalationChannel (see digital_employee_core/escalation/base_escalation_channel.py) and register it via digital_employee.add_escalation_channel(...). 177| 178|#### 1) Implement the channel 179| 180|Create a new class that extends EscalationChannel that defines: 181| 182|* get_required_mcps(): MCP connectors the channel needs at runtime. 183|* get_required_tools(): Additional tools (if any). Return [] if not needed. 184|* get_prompt_header(): Short title shown in the escalation protocol. 185|* get_prompt_body(supervisor, ...): Concrete instructions describing how the agent should escalate using your tools/MCP. 186| 187|Minimal skeleton: 188| 189|{% code lineNumbers="true" %} 190| 191|python 192|from typing import Any 193| 194|from glaip_sdk import MCP, Tool 195| 196|from digital_employee_core.escalation.base_escalation_channel import EscalationChannel 197|from digital_employee_core.identity.identity import DigitalEmployeeSupervisor 198| 199| 200|class CustomEscalationChannel(EscalationChannel): 201| def get_required_mcps(self) -> list[MCP]: 202| return [] 203| 204| def get_required_tools(self) -> list[Tool]: 205| return [] 206| 207| def get_prompt_header(self, **kwargs: Any) -> str: 208| return "Custom Escalation" 209| 210| def get_prompt_body(self, supervisor: DigitalEmployeeSupervisor, **kwargs: Any) -> str: 211| return ( 212| f"When blocked, notify {supervisor.name} ({supervisor.email}) using <YOUR_TOOL>. " 213| "Include: timestamp, failed action, what you tried, and what you need from the supervisor." 214| ) 215| 216| 217|{% endcode %} 218| 219|For a reference implementation, see digital_employee_core/escalation/channels/google_mail_mcp_channel.py. 220| 221|#### 2) Register the channel before deploy 222| 223|python 224|digital_employee.enable_escalation() 225|digital_employee.add_escalation_channel(CustomEscalationChannel()) 226|digital_employee.deploy() 227| 228| 229|#### Notes 230| 231|* One instance per channel type: EscalationChannel equality is based on class type, so adding the same channel type multiple times is treated as a duplicate. 232|* Tool restrictions: If your channel uses MCP tools, ensure those tools are allowed (if you are using whitelisted MCP tools, see MCP Allowed Tools Configuration). 233| 234|### Best Practices 235| 236|* Define clear escalation triggers in DigitalEmployeeJob.instruction (e.g., tool failures, permission issues, urgent blockers). 237|* Configure least-privilege tools for MCPs where possible (see MCP Allowed Tools Configuration). 238|* Validate supervisor identity (non-empty name/email) during development to avoid “silent” non-actionable escalations. 239|* Test with prompt preview (build_prompt()) before deploying. 240| 241| 242|--- 243| 244|# Agent Instructions 245|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 246| 247|## Querying This Documentation 248|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 249| 250|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 251| 252| 253|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/escalation-configuration.md?ask=<question>&goal=<endgoal> 254| 255| 256|ask is the immediate question: it should be specific, self-contained, and written in natural language. 257|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 258| 259|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 260| 261|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 262|


advanced examples/extend

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Extend 4| 5|Some digital employee core components can be extended, for example, identity, connectors (tools & MCPs), and the digital employee object itself. 6| 7|## Extend Use Cases 8| 9|### Identity 10| 11|Digital employee core can be extended using this code example: 12| 13|{% code lineNumbers="true" %} 14| 15|python 16|from digital_employee_core import DigitalEmployeeIdentity 17| 18|class ExtendedDigitalEmployeeIdentity(DigitalEmployeeIdentity): 19| """Extended Digital Employee Identity with additional attributes.""" 20| 21| employee_id: str 22| 23| 24|{% endcode %} 25| 26|### Connectors 27| 28|#### Tools 29| 30|We can add our own tools in addition to those already provided by GL Connectors by extending the BaseTool. 31| 32|Here is the example: 33| 34|{% code lineNumbers="true" %} 35| 36|python 37|import calendar 38|from datetime import datetime, timedelta 39|from typing import Any 40| 41|from gllm_plugin.tools import tool_plugin 42|from langchain_core.runnables import RunnableConfig 43|from langchain_core.tools import BaseTool 44|from pydantic import BaseModel, Field 45| 46| 47|class InterviewDateInput(BaseModel): 48| """Input schema for interview date tool.""" 49| 50| reference_date: str = Field( 51| default=None, 52| description="Reference date in ISO format (YYYY-MM-DD, e.g., 2024-12-16). If not provided, uses current date.", 53| ) 54| 55| 56|class GenerateInterviewDateConfig(BaseModel): 57| """Configuration schema for interview date generation.""" 58| 59| days_to_add: int = Field( 60| default=7, 61| description="Number of days to add to the reference date before finding the next available weekday", 62| ) 63| excluded_weekdays: list[int] = Field( 64| default=[calendar.SATURDAY, calendar.SUNDAY], 65| description=( 66| "List of weekday numbers to exclude (0=Monday, 1=Tuesday, " 67| "..., 6=Sunday). Default excludes Saturday and Sunday." 68| ), 69| ) 70| 71| 72|@tool_plugin(version="1.0.0") 73|class ConfigurableGenerateInterviewDateTool(BaseTool): 74| """Generate an interview date with configurable days offset and excluded weekdays.""" 75| 76| name: str = "configurable_generate_interview_date" 77| description: str = ( 78| "Generate interview date: adds configurable days to reference date, " 79| "returns next available weekday excluding configured weekdays." 80| ) 81| args_schema: type[BaseModel] = InterviewDateInput 82| tool_config_schema: type[BaseModel] = GenerateInterviewDateConfig 83| 84| def _run( 85| self, 86| reference_date: str | None = None, 87| config: RunnableConfig = None, 88| **_kwargs: Any, 89| ) -> str: 90| """Generate interview date with configuration. 91| 92| Adds a configurable number of days to the reference date and returns 93| the next available weekday, excluding configured weekdays. 94| 95| Args: 96| reference_date (str | None, optional): Reference date in ISO format 97| (YYYY-MM-DD, e.g., 2024-12-16). If not provided, uses current 98| date. Defaults to None. 99| config (RunnableConfig, optional): Runnable configuration containing 100| tool settings. Defaults to None. 101| **_kwargs (Any): Additional keyword arguments (ignored). 102| 103| Returns: 104| str: Interview date in ISO format (YYYY-MM-DD) or error message if 105| date format is invalid. 106| """ 107| try: 108| # Get tool config 109| tool_config = self.get_tool_config(config) 110| except Exception as e: 111| return f"Error: Failed to retrieve tool configuration. " f"Details: {e}" 112| 113| try: 114| # Parse reference date 115| base_date = ( 116| datetime.strptime(reference_date, "%Y-%m-%d").date() if reference_date else datetime.now().date() 117| ) 118| except ValueError as e: 119| return f"Error: Invalid date format. Please use YYYY-MM-DD " f"(e.g., 2024-12-16). Details: {e}" 120| 121| # Add configured days to base date 122| target_date = base_date + timedelta(days=tool_config.days_to_add) 123| 124| # Find next available weekday (not in excluded list) 125| max_iterations = 7 # Prevent infinite loop 126| iterations = 0 127| while target_date.weekday() in tool_config.excluded_weekdays and iterations < max_iterations: 128| target_date += timedelta(days=1) 129| iterations += 1 130| 131| if iterations >= max_iterations: 132| return ( 133| f"Error: Could not find available weekday after " 134| f"{max_iterations} days. All weekdays may be excluded." 135| ) 136| 137| return f"Interview date: {target_date.isoformat()}" 138| 139| 140|{% endcode %} 141| 142|To configure the tools, we need to create a config_templates/tools_configs.yaml file. Here is an example of tools_configs.yaml : 143| 144|yaml 145|configurable_generate_interview_date: 146| days_to_add: ${INTERVIEW_DAYS_TO_ADD} 147| excluded_weekdays: ${INTERVIEW_EXCLUDED_WEEKDAYS} 148| 149| 150|To define default value for configs, create a config_templates/defaults.yaml file. Here is an example of defaults.yaml : 151| 152|yaml 153|INTERVIEW_DAYS_TO_ADD: 7 154|INTERVIEW_EXCLUDED_WEEKDAYS: 5,6 155| 156| 157|#### MCPs 158| 159|Here is how we can create our own MCP: 160| 161|{% code lineNumbers="true" %} 162| 163|python 164|from glaip_sdk.mcps import MCP 165| 166|new_google_calendar_mcp = MCP( 167| name="new_google_calendar_mcp", 168| description="MCP for Google Calendar Operation for DE", 169| transport="http", 170| config={"url": "https://default.com/google_calendar/mcp"}, 171|) 172| 173| 174|{% endcode %} 175| 176|We need to provide the config_templates/mcp_configs.yaml file to be able to use the MCP. Here is an example of mcp_configs.yaml: 177| 178|yaml 179|new_google_calendar_mcp: 180| config: 181| url: ${NEW_GOOGLE_CALENDAR_MCP_URL} 182| authentication: 183| type: api-key 184| key: X-API-Key 185| value: ${NEW_GOOGLE_MCP_X_API_KEY} 186| 187| 188|### Digital Employee 189| 190|{% code lineNumbers="true" %} 191| 192|python 193|from digital_employee_core import ( 194| DEFAULT_MODEL_NAME, 195| ConfigTemplateLoader, 196|) 197|from gllm_core.utils import LoggerManager 198|from typing import Any 199| 200|logger = LoggerManager().get_logger(__name__) 201| 202|class ExtendedDigitalEmployee(DigitalEmployee): 203| """Extended Digital Employee with extended tool and MCP configurations. 204| 205| This subclass demonstrates how to extend the base DigitalEmployee 206| with additional specific configurations. 207| """ 208| 209| def __init__( 210| self, 211| identity: DigitalEmployeeIdentity, 212| tools: list[Any] | None = None, 213| sub_agents: list[Any] | None = None, 214| mcps: list[Any] | None = None, 215| configurations: list[DigitalEmployeeConfiguration] | None = None, 216| model: str | None = DEFAULT_MODEL_NAME, 217| ): 218| """Initialize the Specific Digital Employee. 219| 220| Args: 221| identity (DigitalEmployeeIdentity): The Digital Employee's identity. 222| tools (list[Any] | None, optional): List of tools the Digital Employee can use. Defaults to None. 223| sub_agents (list[Any] | None, optional): List of sub-agents (for future use). Defaults to None. 224| mcps (list[Any] | None, optional): List of MCPs the Digital Employee can use. Defaults to None. 225| configurations (list[DigitalEmployeeConfiguration] | None, optional): List of configuration objects. 226| Defaults to None. 227| model (str | None, optional): Model identifier to use for the 228| agent. Defaults to DEFAULT_MODEL_NAME. 229| """ 230| super().__init__( 231| identity=identity, 232| tools=tools, 233| sub_agents=sub_agents, 234| mcps=mcps, 235| configurations=configurations, 236| model=model, 237| ) 238| 239| # Create a separate config loader for specific templates 240| # You can place tool_configs.yaml and mcp_configs.yaml in a separate directory 241| additional_config_dir = Path(__file__).parent / "config_templates" 242| additional_config_loader = ConfigTemplateLoader(template_dir=additional_config_dir) 243| # Simply add the additional config loader - the base class handles the rest! 244| # build_prompt() will use all loaders automatically 245| # build_tool_config() and build_mcp_config() will merge configs from all loaders 246| self.add_config_loader(additional_config_loader) 247| 248| 249| 250|{% endcode %} 251| 252|{% hint style="info" %} 253|To see more examples, please check the Digital Employee Example. 254|{% endhint %} 255| 256| 257|--- 258| 259|# Agent Instructions 260|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 261| 262|## Querying This Documentation 263|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 264| 265|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 266| 267| 268|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/extend.md?ask=<question>&goal=<endgoal> 269| 270| 271|ask is the immediate question: it should be specific, self-contained, and written in natural language. 272|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 273| 274|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 275| 276|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 277|


advanced examples/instantiation

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Instantiation 4| 5|## Prerequisites 6| 7|For these examples, you will need to: 8| 9|* Complete the Extend section 10| 11|## Instantiate Digital Employee 12| 13|### Import the Package 14| 15|{% code lineNumbers="true" %} 16| 17|python 18|from extended_digital_employee.connectors.mcps import new_google_calendar_mcp # new MCP 19|from extended_digital_employee.connectors.tools import ConfigurableGenerateInterviewDateTool # new Tool 20|from extended_digital_employee.digital_employee import ExtendedDigitalEmployee 21|from extended_digital_employee.identity import ExtendedDigitalEmployeeIdentity 22|from glaip_sdk import Tool 23| 24|from digital_employee_core import ( 25| DigitalEmployeeConfiguration, 26| DigitalEmployeeJob, 27|) 28| 29| 30|{% endcode %} 31| 32|### Initialize the Extended Digital Employee 33| 34|{% code lineNumbers="true" %} 35| 36|python 37|job = DigitalEmployeeJob( 38| title="Recruitment Coordinator", 39| description="Coordinates technical interviews and manages candidate scheduling", 40| instruction="When candidates pass the initial screening, schedule their technical interview. Always confirm the date clearly and provide a warm and professional response.", 41|) 42|extended_identity = ExtendedDigitalEmployeeIdentity( 43| name="Alex Morgan", email="alex.morgan@example.com", job=job, employee_id="EMP-123" 44|) 45|configurations = [ 46| DigitalEmployeeConfiguration(key="INTERVIEW_DAYS_TO_ADD", value="10"), 47| DigitalEmployeeConfiguration(key="INTERVIEW_EXCLUDED_WEEKDAYS", value="5,6"), 48| DigitalEmployeeConfiguration(key="NEW_GOOGLE_CALENDAR_MCP_URL", value="https://api.bosa.id/google_calendar/mcp"), 49| DigitalEmployeeConfiguration(key="NEW_GOOGLE_MCP_X_API_KEY", value="[gl-connectors-x-api-key]"), 50|] 51| 52|# Initialize extended digital employee 53|extended_digital_employee = ExtendedDigitalEmployee( 54| identity=extended_identity, 55| mcps=[new_google_calendar_mcp], 56| tools=[Tool.from_langchain(ConfigurableGenerateInterviewDateTool)], 57| configurations=configurations, 58|) 59|extended_digital_employee.deploy() 60| 61| 62|{% endcode %} 63| 64|{% hint style="info" %} 65|In this example, we use new MCPs (mcps=[new_google_calendar_mcp]) and tools (tools=[Tool.from_langchain(ConfigurableGenerateInterviewDateTool)]) that are specifically created for the extended digital employee. 66|{% endhint %} 67| 68|{% hint style="info" %} 69|We also use INTERVIEW_DAYS_TO_ADD, INTERVIEW_EXCLUDED_WEEKDAYS, NEW_GOOGLE_CALENDAR_MCP_URL and NEW_GOOGLE_MCP_X_API_KEY configurations, which are defined in the config template of the new tool and MCP. 70|{% endhint %} 71| 72|### Run the Extended Digital Employee 73| 74|{% code lineNumbers="true" %} 75| 76|python 77|# Run the extended digital employee using a prompt 78|result = extended_digital_employee.run( 79| message="I need to schedule a technical interview for a software engineer candidate who just passed the screening round. Can you generate an interview date?", 80|) 81| 82| 83|{% endcode %} 84| 85|{% hint style="info" %} 86|Before running the sample code, replace the following placeholders: 87| 88|1. Replace [gl-connectors-x-api-key] with x-api-key from GL Connectors. See below for one way to do it. 89|2. (Optional) Replace NEW_GOOGLE_CALENDAR_MCP_URL if you are using a different GL Connectors server instance. 90| 91|

92| 93|🔑 Get GL Connectors x-api-key 94| 95|1. Open https://api.bosa.id/console, then sign in. 96|2. In the Credentials section, expand the x-api-key panel and click Copy combined value button. Paste this value to replace [gl-connectors-x-api-key] . 97| 98| 99| 100|3. If your Gmail account has not been integrated yet, continue with the steps below. 101|4. Under Available Modules section, find the Google_mail integration and click Add New Integration button. 102| 103| 104| 105|5. An authorization URL will appear. Click or copy the URL, then authenticate using your Gmail account. 106| 107| 108| 109|6. Below is an example of a successfully integrated Gmail account. 110| 111| 112| 113|
114|{% endhint %} 115| 116| 117|--- 118| 119|# Agent Instructions 120|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 121| 122|## Querying This Documentation 123|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 124| 125|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 126| 127| 128|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/instantiation.md?ask=<question>&goal=<endgoal> 129| 130| 131|ask is the immediate question: it should be specific, self-contained, and written in natural language. 132|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 133| 134|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 135| 136|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 137|


advanced examples/mcp allowed tools configuration

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# MCP Allowed Tools Configuration 4| 5|### Overview 6| 7|The allowed_tools configuration enables you to restrict which tools a Digital Employee can access from Model Context Protocol (MCP) servers. This is useful for security, cost control, and ensuring your Digital Employee only uses approved functionality. 8| 9|### Key Concepts 10| 11|#### What are Allowed Tools? 12| 13|Allowed tools are a whitelist of specific tool names that an MCP connector is permitted to use. When configured, the Digital Employee will only have access to the specified tools from that MCP, even if the MCP server provides additional capabilities. 14| 15|#### Benefits 16| 17|* Security: Limit access to sensitive operations 18|* Cost Control: Prevent usage of expensive API calls 19|* Compliance: Ensure only approved tools are used 20|* Clarity: Make it explicit which capabilities are available 21| 22|### Configuration 23| 24|#### Basic Setup 25| 26|Allowed tools are configured using DigitalEmployeeConfiguration objects with specific key patterns: 27| 28|{% code lineNumbers="true" %} 29| 30|python 31|DigitalEmployeeConfiguration( 32| key="<MCP_NAME>_ALLOWED_TOOLS", 33| value="tool1,tool2,tool3" 34|) 35| 36| 37|{% endcode %} 38| 39|#### Key Pattern 40| 41|The configuration key follows this pattern: 42| 43|* <MCP_NAME>_ALLOWED_TOOLS 44| 45|Where <MCP_NAME> matches the MCP connector's configuration prefix (e.g., GOOGLE_MAIL_MCP, GOOGLE_CALENDAR_MCP). 46| 47|#### Value Format 48| 49|The value is a comma-separated string of tool names that will be automatically converted to a list: 50| 51|{% code lineNumbers="true" %} 52| 53|python 54|# This string... 55|value="google_mail_send_email,google_mail_get_email_details,google_mail_list_emails" 56| 57|# ...is automatically converted to this list: 58|['google_mail_send_email', 'google_mail_get_email_details', 'google_mail_list_emails'] 59| 60| 61|{% endcode %} 62| 63|### Complete Example 64| 65|#### Step 1: Import Required Components 66| 67|{% code lineNumbers="true" %} 68| 69|python 70|import os 71|from dotenv import load_dotenv 72|from digital_employee_core import ( 73| DigitalEmployee, 74| DigitalEmployeeConfiguration, 75| DigitalEmployeeIdentity, 76| DigitalEmployeeJob, 77|) 78|from digital_employee_core.connectors.mcps import google_calendar_mcp, google_mail_mcp 79| 80|load_dotenv() 81| 82| 83|{% endcode %} 84| 85|#### Step 2: Create Identity 86| 87|{% code lineNumbers="true" %} 88| 89|python 90|job = DigitalEmployeeJob( 91| title="Email Assistant", 92| description="Helps manage emails and calendars", 93| instruction="You are an email assistant that helps users manage their emails efficiently.", 94|) 95| 96|identity = DigitalEmployeeIdentity( 97| name="Email Bot", 98| email="emailbot@example.com", 99| job=job, 100|) 101| 102| 103|{% endcode %} 104| 105|#### Step 3: Configure MCP URLs and Allowed Tools 106| 107|{% code lineNumbers="true" %} 108| 109|python 110|configurations = [ 111| # MCP URLs 112| DigitalEmployeeConfiguration( 113| key="GOOGLE_MAIL_MCP_URL", 114| value=os.getenv("GOOGLE_MAIL_MCP_URL", ""), 115| ), 116| DigitalEmployeeConfiguration( 117| key="GOOGLE_MCP_X_API_KEY", 118| value=os.getenv("GOOGLE_MCP_X_API_KEY", ""), 119| ), 120| # Allowed tools - comma-separated strings 121| DigitalEmployeeConfiguration( 122| key="GOOGLE_MAIL_MCP_ALLOWED_TOOLS", 123| value="google_mail_send_email,google_mail_get_email_details,google_mail_list_emails", 124| ), 125|] 126| 127| 128|{% endcode %} 129| 130|{% hint style="info" %} 131|Note: Replace the example values above with your actual configuration: 132| 133|* GOOGLE_MAIL_MCP_URL: Your MCP server endpoints 134|* GOOGLE_MCP_X_API_KEY: Your actual API key (consider using environment variables) 135| {% endhint %} 136| 137|#### Step 4: Create and Deploy the Digital Employee 138| 139|{% code lineNumbers="true" %} 140| 141|python 142|# Create digital employee with MCPs 143|mcps = [google_mail_mcp] 144| 145|digital_employee = DigitalEmployee( 146| identity=identity, 147| mcps=mcps, 148| configurations=configurations, 149|) 150| 151|# Deploy applies the configurations 152|digital_employee.deploy() 153| 154| 155|{% endcode %} 156| 157|#### Step 5 (Optional): Verify Configuration 158| 159|If you want to verify the configuration was applied correctly, you can check the deployed MCP config: 160| 161|{% code lineNumbers="true" %} 162| 163|python 164|mail_mcp_config = digital_employee.agent.mcp_configs.get(google_mail_mcp.name).get("config") 165|print(f"Mail MCP allowed_tools in config: {mail_mcp_config.get('allowed_tools')}") 166|# Output: ['google_mail_send_email', 'google_mail_read_email', 'google_mail_search'] 167| 168| 169|{% endcode %} 170| 171|#### Step 6: Run the Digital Employee 172| 173|Now you can run the Digital Employee and it will only have access to the allowed tools: 174| 175|{% code lineNumbers="true" %} 176| 177|python 178|# The Digital Employee will only be able to use the allowed tools 179|response = digital_employee.run( 180| message="Read and summarize my latest email" 181|) 182|print(response) 183| 184| 185|{% endcode %} 186| 187|In this example: 188| 189|* The Digital Employee can use google_mail_get_email_details, google_mail_list_emails to find the latest email. 190|* It cannot use tools like google_mail_delete_email because they weren't in the allowed list. 191| 192|For the list of tools that are available via GLConnector, please refer to https://api.bosa.id/docs. 193| 194|### Common Use Cases 195| 196|#### Restricting Email Operations 197| 198|Only allow reading and searching emails, but not sending: 199| 200|{% code lineNumbers="true" %} 201| 202|python 203|DigitalEmployeeConfiguration( 204| key="GOOGLE_MAIL_MCP_ALLOWED_TOOLS", 205| value="google_mail_get_email_details,google_mail_list_emails", 206|) 207| 208| 209|{% endcode %} 210| 211|#### Read-Only Calendar Access 212| 213|Only allow listing events, but not creating or modifying: 214| 215|{% code lineNumbers="true" %} 216| 217|python 218|DigitalEmployeeConfiguration( 219| key="GOOGLE_CALENDAR_MCP_ALLOWED_TOOLS", 220| value="google_calendar_events_list", 221|) 222| 223| 224|{% endcode %} 225| 226|#### Multiple Tool Permissions 227| 228|Grant access to multiple related tools: 229| 230|{% code lineNumbers="true" %} 231| 232|python 233|DigitalEmployeeConfiguration( 234| key="GOOGLE_MAIL_MCP_ALLOWED_TOOLS", 235| value="google_mail_send_email,google_mail_get_email_details,google_mail_delete_email", 236|) 237| 238| 239|{% endcode %} 240| 241|### Best Practices 242| 243|#### 1. Principle of Least Privilege 244| 245|Only grant access to tools that are absolutely necessary for the Digital Employee's job: 246| 247|{% code lineNumbers="true" %} 248| 249|python 250|# Good: Specific tools for specific job 251|DigitalEmployeeConfiguration( 252| key="GOOGLE_MAIL_MCP_ALLOWED_TOOLS", 253| value="google_mail_get_email_details,google_mail_list_emails", 254|) 255| 256|# Avoid: Granting all available tools without restriction 257| 258| 259|{% endcode %} 260| 261|#### 2. Document Your Tool Choices 262| 263|Add comments explaining why specific tools are allowed: 264| 265|{% code lineNumbers="true" %} 266| 267|python 268|# Allow email reading and searching for customer support queries 269|DigitalEmployeeConfiguration( 270| key="GOOGLE_MAIL_MCP_ALLOWED_TOOLS", 271| value="google_mail_get_email_details,google_mail_list_emails", 272|) 273| 274| 275|{% endcode %} 276| 277|#### 3. Use Environment Variables for Sensitive Data 278| 279|Store API keys and URLs in environment variables: 280| 281|{% code lineNumbers="true" %} 282| 283|python 284|import os 285| 286|DigitalEmployeeConfiguration( 287| key="GOOGLE_MCP_X_API_KEY", 288| value=os.getenv("GOOGLE_MCP_API_KEY"), 289|) 290| 291| 292|{% endcode %} 293| 294|### Troubleshooting 295| 296|#### Tools Not Being Restricted 297| 298|Problem: All tools are still accessible despite configuration. 299| 300|Solution: Ensure the configuration key matches the MCP's expected pattern: 301| 302|* Check the MCP connector's documentation for the correct prefix 303|* Verify the key format: <MCP_PREFIX>_ALLOWED_TOOLS 304| 305|#### Tool Names Incorrect 306| 307|Problem: Tools are not recognized. 308| 309|Solution: Verify the exact tool names from the MCP server documentation. Tool names are case-sensitive and must match exactly. 310| 311| 312|--- 313| 314|# Agent Instructions 315|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 316| 317|## Querying This Documentation 318|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 319| 320|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 321| 322| 323|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/mcp-allowed-tools-configuration.md?ask=<question>&goal=<endgoal> 324| 325| 326|ask is the immediate question: it should be specific, self-contained, and written in natural language. 327|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 328| 329|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 330| 331|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 332|


advanced examples/memory configuration

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Memory Configuration 4| 5|### Overview 6| 7|Digital Employee Core supports user-scoped memory so an agent can remember facts and preferences across multiple calls. Memory is opt-in: 8| 9|* Enable a memory provider in agent_config. 10|* Pass a stable memory_user_id on every run() / arun() call. 11| 12|### Key Concepts 13| 14|#### What is memory_user_id? 15| 16|memory_user_id is the user identifier used to scope memory. 17| 18|* Same memory_user_id + same agent => the agent can recall previously stored facts. 19|* Different memory_user_id + same agent => isolated memory (no cross-user leakage). 20|* Same memory_user_id + different agent => isolated memory (each agent maintains its own memory scope). 21| 22|#### Memory Provider 23| 24|Memory is enabled by setting AgentConfigKeys.MEMORY to a provider (e.g. MemoryProvider.MEM0). Currently we utilize GL SDK Memory via AIP Memory. 25| 26|### Minimal Example 27| 28|#### 1) Create a memory-enabled Digital Employee 29| 30|{% code lineNumbers="true" %} 31| 32|python 33|from digital_employee_core import DigitalEmployee, DigitalEmployeeIdentity, DigitalEmployeeJob 34|from digital_employee_core.configuration.agent_configuration import AgentConfigKeys, MemoryProvider 35| 36|job = DigitalEmployeeJob( 37| title="Memory-Enabled Assistant", 38| description="A digital employee that can remember user-specific facts across calls", 39| instruction=( 40| "When the user tells you a personal preference or fact, remember it for future conversation." 41| ), 42|) 43| 44|identity = DigitalEmployeeIdentity(name="memory_assistant", email="memory.assistant@example.com", job=job) 45| 46|digital_employee = DigitalEmployee( 47| identity=identity, 48| agent_config={AgentConfigKeys.MEMORY: MemoryProvider.MEM0}, 49|) 50| 51| 52|{% endcode %} 53| 54|#### 2) Deploy, then call with a stable memory_user_id 55| 56|{% code lineNumbers="true" %} 57| 58|python 59|digital_employee.deploy() 60| 61|memory_user_id = "user-123" 62| 63|# Store a preference 64|result_1 = digital_employee.run( 65| message="My favorite color is beige. Please remember this for next time.", 66| memory_user_id=memory_user_id, 67|) 68| 69|# Recall later 70|result_2 = digital_employee.run( 71| message="What is my favorite color?", 72| memory_user_id=memory_user_id, 73|) 74| 75| 76|{% endcode %} 77| 78|{% hint style="info" %} 79|Note: After storing a memory, there may be a slight delay from the provider before it becomes available for retrieval, so you may need to wait a moment (manually or via Python's sleep() ) before querying for recently stored information. 80|{% endhint %} 81| 82|#### 3) Different user, different memory 83| 84|{% code lineNumbers="true" %} 85| 86|python 87|other_user_id = "user-456" 88| 89|result_3 = digital_employee.run( 90| message="What is my favorite color?", 91| memory_user_id=other_user_id, 92|) 93| 94| 95|{% endcode %} 96| 97|### Local Usage 98| 99|To use MemoryProvider.MEM0 locally, you must provide MEM0_API_KEY in your environment variables. 100| 101|bash 102|export MEM0_API_KEY="<your_api_key>" 103| 104| 105|If you load environment variables via .env, ensure your entrypoint calls load_dotenv(). 106| 107|Then, run the digital employee with local=True to run it locally. 108| 109|{% code lineNumbers="true" %} 110| 111|python 112|result_3 = digital_employee.run( 113| message="What is my favorite color?", 114| memory_user_id=memory_user_id, 115| local=True, 116|) 117| 118| 119|{% endcode %} 120| 121|### Notes / Best Practices 122| 123|* memory_user_id is required when memory is enabled; the agent cannot store or recall memories without it. 124|* Use stable identifiers (e.g., internal user ID) and do not use PII (like emails) unless necessary. 125|* Write clear instructions in the job prompt indicating what to remember (preferences, long-term facts) vs what not to (secrets). 126| 127| 128|--- 129| 130|# Agent Instructions 131|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 132| 133|## Querying This Documentation 134|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 135| 136|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 137| 138| 139|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/memory-configuration.md?ask=<question>&goal=<endgoal> 140| 141| 142|ask is the immediate question: it should be specific, self-contained, and written in natural language. 143|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 144| 145|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 146| 147|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 148|


advanced examples/programmatic tool calling ptc configuration

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Programmatic Tool Calling (PTC) Configuration 4| 5|### Overview 6| 7|Programmatic Tool Calling (PTC) lets a Digital Employee orchestrate tools through Python code executed in a sandboxed environment, rather than making individual API round-trips for each tool call. 8| 9|When PTC is enabled, the agent gets access to an execute_ptc_code tool. The agent can write Python code that calls its registered tools, processes intermediate results, and returns only the final output to its context window. 10| 11|> Note: PTC is currently only supported for local runs (run(..., local=True)). 12| 13|For the canonical guide, see the AIP PTC Guide. 14| 15|### Key Concepts 16| 17|#### Why use PTC? 18| 19|| Benefit | Description | 20|| ------------------------------ | --------------------------------------------------------------------------------------------------- | 21|| Context Window Protection | Intermediate results stay in the sandbox — only the final output is returned to the agent's context | 22|| Parallel Execution | The agent can call multiple tools concurrently within a single code block | 23|| Reduced Inference Overhead | One model pass writes the code; execution replaces multiple model-tool-model round-trips | 24| 25|#### How PTC works 26| 27|1. The agent receives a task requiring multiple tool calls. 28|2. The agent writes a Python script and invokes execute_ptc_code. 29|3. The script runs inside an E2B sandbox with all registered tools available. 30|4. Only the final printed output is returned to the agent's context. 31| 32|#### The PTC configuration object 33| 34|PTC is configured via the PTC class from glaip_sdk.ptc: 35| 36|{% code lineNumbers="true" %} 37| 38|python 39|from glaip_sdk.ptc import PTC 40| 41|ptc_config = PTC( 42| enabled=True, 43| sandbox_timeout=120.0, 44|) 45| 46| 47|{% endcode %} 48| 49|The instance is passed to DigitalEmployee via the ptc parameter. Tools registered on the Digital Employee are automatically made available in the sandbox — you do not need to configure them separately. 50| 51|#### Prerequisites 52| 53|* E2B_API_KEY must be set (get one at https://e2b.dev) 54|* OPENAI_API_KEY (or another supported model key) must be set 55|* glaip-sdk installed with [local] extras 56| 57|### Complete Example 58| 59|The file examples/ptc/ptc_example.py demonstrates the PTC workflow. 60| 61|#### Step 1: Import required components 62| 63|{% code lineNumbers="true" %} 64| 65|python 66|from dotenv import load_dotenv 67|from glaip_sdk import Tool 68|from glaip_sdk.ptc import PTC 69| 70|from digital_employee_core import ( 71| DigitalEmployee, 72| DigitalEmployeeIdentity, 73| DigitalEmployeeJob, 74|) 75|from digital_employee_core.connectors.tools.utility_tools import time_tool 76|from examples.ptc.tools.calculator_tool import CalculatorTool 77| 78|load_dotenv() 79| 80| 81|{% endcode %} 82| 83|#### Step 2: Create the Digital Employee identity 84| 85|{% code lineNumbers="true" %} 86| 87|python 88|job = DigitalEmployeeJob( 89| title="PTC Assistant", 90| description="A helpful assistant with Programmatic Tool Calling enabled", 91| instruction=( 92| "You are a helpful assistant with Programmatic Tool Calling (PTC) enabled. " 93| "When you need to orchestrate multiple tool calls or process data programmatically, " 94| "you can write Python code using the execute_ptc_code tool.\n\n" 95| "Use PTC when you need to:\n" 96| "1. Call multiple tools and process their results\n" 97| "2. Perform calculations or data transformations\n" 98| "3. Keep intermediate results out of context\n\n" 99| "Provide clear and helpful responses." 100| ), 101|) 102| 103|identity = DigitalEmployeeIdentity( 104| name="PTC Assistant", 105| email="ptc.assistant@example.com", 106| job=job, 107|) 108| 109| 110|{% endcode %} 111| 112|#### Step 3: Configure PTC and attach tools 113| 114|{% code lineNumbers="true" %} 115| 116|python 117|ptc_config = PTC( 118| enabled=True, 119| sandbox_timeout=120.0, # Maximum execution time in seconds, optional 120|) 121| 122|calculator_tool = Tool.from_langchain(CalculatorTool) 123| 124|digital_employee = DigitalEmployee( 125| identity=identity, 126| tools=[time_tool, calculator_tool], 127| ptc=ptc_config, 128|) 129| 130| 131|{% endcode %} 132| 133|All tools passed to DigitalEmployee are automatically available inside the PTC sandbox. 134| 135|#### Step 4: Run locally 136| 137|{% code lineNumbers="true" %} 138| 139|python 140|message = "Calculate what time it will be in 3.5 hours. Directly show me the time without any intermediate output." 141| 142|result = digital_employee.run(message=message, local=True) 143|print(result) 144| 145| 146|{% endcode %} 147| 148|> Note: Do not call deploy() for local PTC runs. Use run(..., local=True) directly. 149| 150|#### What this example shows 151| 152|* PTC is activated with PTC(enabled=True). 153|* Tools are registered on the Digital Employee — no separate sandbox configuration needed. 154|* The agent can orchestrate time_tool and calculator_tool in a single code block. 155|* Intermediate results (e.g., the raw time value) stay in the sandbox; only the final answer is returned to the model context. 156| 157|### Configuration Reference 158| 159|| Parameter | Type | Default | Description | 160|| ---------------------- | ------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | 161|| enabled | bool | False | Activates PTC. Must be True to use PTC. | 162|| sandbox_timeout | float | 120.0 | Maximum execution time (seconds) for a sandbox run. | 163|| default_tool_timeout | float | 60.0 | Per-tool call timeout (seconds) inside the sandbox. | 164|| sandbox_template | str \| None | "aip-agents-ptc-v1" | E2B sandbox template identifier. | 165|| prompt | dict \| None | None | Prompt configuration for the execute_ptc_code tool description. Accepts {"mode": "...", "include_example": bool}. | 166|| ptc_packages | list[str] \| None | None | Additional Python packages to install in the sandbox. None uses smart package selection; an explicit list is additive to the defaults. | 167| 168|> Not supported: custom_tools — tools are always auto-derived from the DigitalEmployee.tools list. 169| 170|### Common Use Cases 171| 172|#### Parallel tool calls 173| 174|The agent can call multiple tools concurrently in one code block, without extra round-trips: 175| 176|{% code lineNumbers="true" %} 177| 178|python 179|# Agent-generated code running inside the sandbox 180|result_a = time_tool() 181|result_b = calculator_tool(expression="365 * 24") 182|print(f"Time: {result_a}, Hours in a year: {result_b}") 183| 184| 185|{% endcode %} 186| 187|#### Installing extra sandbox packages 188| 189|{% code lineNumbers="true" %} 190| 191|python 192|ptc_config = PTC( 193| enabled=True, 194| ptc_packages=["pandas==2.2.0", "numpy"], 195|) 196| 197| 198|{% endcode %} 199| 200|#### Extending the sandbox timeout for long-running tasks 201| 202|{% code lineNumbers="true" %} 203| 204|python 205|ptc_config = PTC( 206| enabled=True, 207| sandbox_timeout=300.0, # 5 minutes 208| default_tool_timeout=90.0, 209|) 210| 211| 212|{% endcode %} 213| 214|### Best Practices 215| 216|#### 1. Mention execute_ptc_code in the job instruction 217| 218|Explicitly tell the agent when and how to use PTC in the instruction field: 219| 220|{% code lineNumbers="true" %} 221| 222|python 223|instruction=( 224| "When orchestrating multiple tool calls, use execute_ptc_code to run them " 225| "in a single Python block and return only the final result." 226|) 227| 228| 229|{% endcode %} 230| 231|Without this hint, the agent may fall back to individual tool calls. 232| 233|#### 2. Keep sandbox_timeout proportional to task complexity 234| 235|A short timeout is fine for quick calculations; increase it for tasks that involve many sequential tool calls or heavy data processing. 236| 237|#### 3. Use ptc_packages only when needed 238| 239|If ptc_packages is None (the default), aip-agents selects packages automatically based on which tools are registered. Only set it explicitly when you need a package that is not auto-detected. 240| 241|#### 4. Do not call deploy() for local PTC runs 242| 243|PTC is a local-only feature. Call run(..., local=True) directly — skip deploy(). 244| 245|#### 5. Use a single DigitalEmployee instance per session 246| 247|Constructing a new DigitalEmployee on every request means a cold sandbox start for each run. Reuse the instance across calls to amortize sandbox startup time. 248| 249|### Troubleshooting 250| 251|#### E2B_API_KEY not set 252| 253|Problem: The sandbox fails to start with an authentication error. 254| 255|Solution: Obtain an API key from https://e2b.dev and add it to your .env file: 256| 257|{% code lineNumbers="true" %} 258| 259|bash 260|E2B_API_KEY=your_key_here 261| 262| 263|{% endcode %} 264| 265|#### glaip-sdk[local] not installed 266| 267|Problem: Import errors or missing sandbox dependencies. 268| 269|Solution: Install the local extras: 270| 271|{% code lineNumbers="true" %} 272| 273|bash 274|poetry add "glaip-sdk[local]" 275| 276| 277|{% endcode %} 278| 279|#### Agent not using execute_ptc_code 280| 281|Problem: The agent calls tools individually instead of using PTC. 282| 283|Solution: Add explicit PTC guidance to the job instruction. The model needs to be told when PTC is the preferred approach (see Best Practice 1 above). 284| 285|#### Sandbox timeout exceeded 286| 287|Problem: Execution is cut off mid-run with a timeout error. 288| 289|Solution: Increase sandbox_timeout and, if tools are slow, default_tool_timeout: 290| 291|{% code lineNumbers="true" %} 292| 293|python 294|ptc_config = PTC( 295| enabled=True, 296| sandbox_timeout=300.0, 297| default_tool_timeout=90.0, 298|) 299| 300| 301|{% endcode %} 302| 303|#### Tool not available inside the sandbox 304| 305|Problem: The agent's PTC code raises an import or NameError for a registered tool. 306| 307|Solution: Verify the tool is passed to DigitalEmployee(tools=[...]). Tools are auto-derived from this list — no additional sandbox configuration is required. 308| 309| 310|--- 311| 312|# Agent Instructions 313|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 314| 315|## Querying This Documentation 316|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 317| 318|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 319| 320| 321|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/programmatic-tool-calling-ptc-configuration.md?ask=<question>&goal=<endgoal> 322| 323| 324|ask is the immediate question: it should be specific, self-contained, and written in natural language. 325|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 326| 327|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 328| 329|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 330|


advanced examples/recommended project structure

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Recommended Project Structure 4| 5|Here is the recommended project structure when building a digital employee. 6| 7| 8|digital-employee/ 9|├── agents/ 10|│ ├── agent_1.py 11|│ ├── agent_2.py 12|│ └── agent_3.py 13|├── config_templates/ 14|│ ├── defaults.yaml 15|│ ├── mcp_configs.yaml 16|│ └── tool_configs.yaml 17|├── connectors/ 18|│ ├── mcps/ 19|│ │ ├── mcp_1.py 20|│ │ ├── mcp_2.py 21|│ │ └── mcp_3.py 22|│ └── tools/ 23|│ ├── tool_1.py 24|│ ├── tool_2.py 25|│ └── tool_3.py 26|├── identity/ 27|│ └── identity.py 28|└── main.py 29| 30| 31|## Agents 32| 33|The agents folder contains a list of agents used by the digital employee to perform tasks. This is optional and depends on the digital employee's use cases. 34| 35|## Config Templates 36| 37|Config templates contain mcp_configs.yaml and tool_configs.yaml, which are configurations used when running the MCPs and tools. You can also add defaults.yaml to store your default values for each MCP and tool configuration. 38| 39|## Connectors 40| 41|The connectors folder contains MCPs and tools used by that specific digital employee. Please see the Extend section to learn how to create new MCPs and tools. 42| 43|## Identity 44| 45|Identity contains the extended identity of the digital employee if needed. This folder is optional if all the identity from the digital employee core is sufficient. 46| 47| 48|--- 49| 50|# Agent Instructions 51|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 52| 53|## Querying This Documentation 54|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 55| 56|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 57| 58| 59|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/recommended-project-structure.md?ask=<question>&goal=<endgoal> 60| 61| 62|ask is the immediate question: it should be specific, self-contained, and written in natural language. 63|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 64| 65|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 66| 67|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 68|


advanced examples/run history

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Run History 4| 5|### Overview 6| 7|We use GLAIP Audit Trails to review a Digital Employee agent’s run history for auditing. 8| 9|### Retrieve Run History (via AIP CLI) 10| 11|#### 1) Start the AIP CLI 12| 13|Run: 14| 15|bash 16|aip 17| 18| 19|#### 2) Open the agents list 20| 21|In the CLI: 22| 23| 24|/agents 25| 26| 27|Find the agent by Digital Employee name, then select the matching agent entry. 28| 29|

30| 31|#### 4) View runs 32| 33|In the CLI: 34| 35| 36|/runs 37| 38| 39|

40| 41|#### 5) Review runs in the TUI 42| 43|The console will display a TUI list of runs (run history) for the selected agent. 44| 45|

46| 47| 48|--- 49| 50|# Agent Instructions 51|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 52| 53|## Querying This Documentation 54|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 55| 56|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 57| 58| 59|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/run-history.md?ask=<question>&goal=<endgoal> 60| 61| 62|ask is the immediate question: it should be specific, self-contained, and written in natural language. 63|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 64| 65|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 66| 67|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 68|


advanced examples/scheduler configuration

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Scheduler Configuration 4| 5|### Overview 6| 7|The Scheduler feature enables you to configure Digital Employees to execute tasks automatically at specified times using cron-based scheduling. This is ideal for recurring tasks, automated reports, periodic checks, and time-based workflows. 8| 9|Currently we utilize AIP Scheduled Run feature to manage these workflows. 10| 11|{% hint style="info" %} 12|Note: Schedules are only available for remote runs (deployed Digital Employees). Local runs do not support scheduled execution. 13|{% endhint %} 14| 15|### Key Concepts 16| 17|#### What is a Scheduler? 18| 19|A scheduler allows your Digital Employee to run tasks automatically based on time-based triggers. Each schedule consists of: 20| 21|* Schedule Configuration: Defines when the task should run (using cron syntax) 22|* Input: The message or instruction to execute when the schedule triggers 23| 24|#### Benefits 25| 26|* Automation: Execute tasks without manual intervention 27|* Consistency: Ensure tasks run at predictable times 28|* Efficiency: Free up human resources for higher-value work 29|* Reliability: Never miss scheduled tasks or reminders 30| 31|### Configuration 32| 33|#### Basic Components 34| 35|Schedules are configured using two main classes: 36| 37|1. ScheduleConfig: Defines the timing using cron-like parameters 38|2. ScheduleItemConfig: Combines the schedule with the input to execute 39| 40|#### Schedule Configuration Parameters 41| 42|The ScheduleConfig class uses cron-style parameters: 43| 44|{% code lineNumbers="true" %} 45| 46|python 47|from glaip_sdk.models.schedule import ScheduleConfig 48| 49|schedule = ScheduleConfig( 50| minute="0", # 0-59 or "*" for every minute 51| hour="8", # 0-23 or "*" for every hour 52| day_of_month="*", # 1-31 or "*" for every day 53| month="*", # 1-12 or "*" for every month 54| day_of_week="0-4", # 0-6 (0=Monday, 6=Sunday) or "*" for every day 55|) 56| 57| 58|{% endcode %} 59| 60|Reference to GLAIP Python SDK. 61| 62|#### Cron Syntax Guide 63| 64|| Field | Values | Special Characters | Examples | 65|| -------------- | ------ | ------------------------------------ | ---------------------- | 66|| minute | 0-59 | * (every), - (range), , (list) | 0, */15, 0,30 | 67|| hour | 0-23 | * (every), - (range), , (list) | 8, 9-17, 8,12,18 | 68|| day_of_month | 1-31 | * (every), - (range), , (list) | 1, 1-15, 1,15 | 69|| month | 1-12 | * (every), - (range), , (list) | *, 1-6, 1,7 | 70|| day_of_week | 0-6 | * (every), - (range), , (list) | 0-4, 0,6, * | 71| 72|Note: Day of week starts with Monday (0) and ends with Sunday (6). 73| 74|### Complete Example 75| 76|#### Step 1: Import Required Components 77| 78|{% code lineNumbers="true" %} 79| 80|python 81|from glaip_sdk.models.schedule import ScheduleConfig 82|from digital_employee_core import ( 83| DigitalEmployee, 84| DigitalEmployeeIdentity, 85| DigitalEmployeeJob, 86|) 87|from digital_employee_core.schedule import ScheduleItemConfig 88| 89| 90|{% endcode %} 91| 92|#### Step 2: Create Digital Employee Identity 93| 94|{% code lineNumbers="true" %} 95| 96|python 97|# Define the job 98|job = DigitalEmployeeJob( 99| title="Friendly Greeter", 100| description="A friendly digital employee that greets people at different times", 101| instruction="You are a friendly greeter. Always respond with a cheerful greeting!", 102|) 103| 104|# Create identity 105|identity = DigitalEmployeeIdentity( 106| name="Sunny", 107| email="sunny@example.com", 108| job=job, 109|) 110| 111| 112|{% endcode %} 113| 114|#### Step 3: Configure Schedule 115| 116|{% code lineNumbers="true" %} 117| 118|python 119|# Morning greeting - weekdays at 8 AM 120|morning_schedule = ScheduleConfig( 121| minute="0", 122| hour="8", 123| day_of_month="*", 124| month="*", 125| day_of_week="0-4", # Monday to Friday 126|) 127| 128| 129|{% endcode %} 130| 131|#### Step 4: Create Schedule Item 132| 133|{% code lineNumbers="true" %} 134| 135|python 136|# Create schedule item with input 137|morning_schedule_item = ScheduleItemConfig( 138| schedule_config=morning_schedule, 139| input="Morning greeting" 140|) 141| 142| 143|{% endcode %} 144| 145|#### Step 5: Create and Deploy Digital Employee 146| 147|{% code lineNumbers="true" %} 148| 149|python 150|# Create Digital Employee with schedule 151|digital_employee = DigitalEmployee( 152| identity=identity, 153| schedules=[morning_schedule_item], 154|) 155| 156|# Deploy the Digital Employee (this also creates the schedule) 157|digital_employee.deploy() 158| 159| 160|{% endcode %} 161| 162|#### Step 6: Verify Schedules (Optional) 163| 164|{% code lineNumbers="true" %} 165| 166|python 167|# Get schedules from the Digital Employee 168|schedules = digital_employee.get_schedule() 169|print(f"Number of schedules: {len(schedules)}") 170| 171|# Display schedule details 172|for i, schedule_item in enumerate(schedules, 1): 173| print(f"Schedule {i}:") 174| print(f" Input: {schedule_item.input}") 175| print(f" Cron: {schedule_item.schedule_config.to_cron_string()}") 176| 177| 178|{% endcode %} 179| 180|#### Step 7: Monitor Schedule Runs (Optional) 181| 182|{% code lineNumbers="true" %} 183| 184|python 185|from glaip_sdk import Client 186| 187|# Get the deployed agent 188|client = Client() 189|agent = client.get_agent_by_id(digital_employee.agent.id) 190| 191|# List all schedules 192|agent_schedules = agent.schedule.list() 193|print(f"Found {len(agent_schedules)} schedule(s)") 194| 195|# Check runs for a specific schedule 196|for schedule in agent_schedules: 197| runs = agent.schedule.list_runs(schedule.id) 198| print(f"\nSchedule: {schedule.input}") 199| print(f"Runs: {len(runs)}") 200| 201| # Display recent runs 202| for run in runs[-5:]: # Last 5 runs 203| print(f" - Run ID: {run.id}") 204| print(f" Status: {run.status}") 205| if run.status == "success": 206| result = run.get_result() 207| print(f" Result: {result}") 208| 209| 210|{% endcode %} 211| 212|### Common Use Cases 213| 214|#### Daily Morning Report 215| 216|Send a daily report every weekday at 9 AM: 217| 218|{% code lineNumbers="true" %} 219| 220|python 221|daily_report_schedule = ScheduleConfig( 222| minute="0", 223| hour="9", 224| day_of_month="*", 225| month="*", 226| day_of_week="0-4", # Monday to Friday 227|) 228| 229|report_item = ScheduleItemConfig( 230| schedule_config=daily_report_schedule, 231| input="Generate and send the daily morning report" 232|) 233| 234| 235|{% endcode %} 236| 237|#### Hourly Data Check 238| 239|Check data every hour during business hours: 240| 241|{% code lineNumbers="true" %} 242| 243|python 244|hourly_check_schedule = ScheduleConfig( 245| minute="0", 246| hour="9-17", # 9 AM to 5 PM 247| day_of_month="*", 248| month="*", 249| day_of_week="0-4", # Monday to Friday 250|) 251| 252|check_item = ScheduleItemConfig( 253| schedule_config=hourly_check_schedule, 254| input="Check system status and alert if issues found" 255|) 256| 257| 258|{% endcode %} 259| 260|#### Weekly Summary 261| 262|Generate a weekly summary every Friday at 5 PM: 263| 264|{% code lineNumbers="true" %} 265| 266|python 267|weekly_summary_schedule = ScheduleConfig( 268| minute="0", 269| hour="17", 270| day_of_month="*", 271| month="*", 272| day_of_week="4", # Friday 273|) 274| 275|summary_item = ScheduleItemConfig( 276| schedule_config=weekly_summary_schedule, 277| input="Generate weekly summary report" 278|) 279| 280| 281|{% endcode %} 282| 283|#### Monthly Reminder 284| 285|Send a reminder on the first day of each month: 286| 287|{% code lineNumbers="true" %} 288| 289|python 290|monthly_reminder_schedule = ScheduleConfig( 291| minute="0", 292| hour="9", 293| day_of_month="1", # First day of month 294| month="*", 295| day_of_week="*", 296|) 297| 298|reminder_item = ScheduleItemConfig( 299| schedule_config=monthly_reminder_schedule, 300| input="Send monthly reminder to review pending tasks" 301|) 302| 303| 304|{% endcode %} 305| 306|#### Every 15 Minutes 307| 308|Run a task every 15 minutes: 309| 310|{% code lineNumbers="true" %} 311| 312|python 313|frequent_check_schedule = ScheduleConfig( 314| minute="*/15", # Every 15 minutes 315| hour="*", 316| day_of_month="*", 317| month="*", 318| day_of_week="*", 319|) 320| 321|frequent_item = ScheduleItemConfig( 322| schedule_config=frequent_check_schedule, 323| input="Check for urgent notifications" 324|) 325| 326| 327|{% endcode %} 328| 329|### Best Practices 330| 331|#### 1. Use Descriptive Inputs 332| 333|Provide clear, actionable instructions in the schedule input: 334| 335|{% code lineNumbers="true" %} 336| 337|python 338|# Good: Specific and actionable 339|ScheduleItemConfig( 340| schedule_config=schedule, 341| input="Review unread emails from VIP customers and respond to urgent ones" 342|) 343| 344|# Avoid: Vague or unclear 345|ScheduleItemConfig( 346| schedule_config=schedule, 347| input="Check emails" 348|) 349| 350| 351|{% endcode %} 352| 353|#### 2. Consider Time Zones 354| 355|Be aware of the time zone used by your deployment: 356| 357|{% code lineNumbers="true" %} 358| 359|python 360|# Document the time zone in comments 361|# Schedule runs at 9 AM UTC 362|morning_schedule = ScheduleConfig( 363| minute="0", 364| hour="9", 365| day_of_month="*", 366| month="*", 367| day_of_week="0-4", 368|) 369| 370| 371|{% endcode %} 372| 373|#### 3. Avoid Overlapping Schedules 374| 375|Ensure schedules don't conflict or create excessive load: 376| 377|{% code lineNumbers="true" %} 378| 379|python 380|# Good: Staggered schedules 381|schedule_1 = ScheduleConfig(minute="0", hour="9", ...) # 9:00 AM 382|schedule_2 = ScheduleConfig(minute="30", hour="9", ...) # 9:30 AM 383| 384|# Avoid: Multiple schedules at the same time 385|schedule_1 = ScheduleConfig(minute="0", hour="9", ...) # 9:00 AM 386|schedule_2 = ScheduleConfig(minute="0", hour="9", ...) # 9:00 AM (conflict) 387| 388| 389|{% endcode %} 390| 391|#### 4. Test Schedule Timing 392| 393|Verify your cron expressions produce the expected schedule: 394| 395|{% code lineNumbers="true" %} 396| 397|python 398|schedule = ScheduleConfig( 399| minute="0", 400| hour="9", 401| day_of_month="*", 402| month="*", 403| day_of_week="0-4", 404|) 405| 406|# Check the cron string 407|cron_string = schedule.to_cron_string() 408|print(f"Cron expression: {cron_string}") 409|# Output: "0 9 * * 0-4" 410| 411| 412|{% endcode %} 413| 414|#### 5. Monitor Schedule Execution 415| 416|Regularly check schedule runs to ensure they're executing as expected: 417| 418|{% code lineNumbers="true" %} 419| 420|python 421|# Check recent failed runs 422|failed_runs = agent.schedule.list_runs(schedule_id, status="failed") 423| 424|if failed_runs: 425| print(f"Warning: {len(failed_runs)} failed runs detected") 426| 427| 428|{% endcode %} 429| 430|#### 6. Use Multiple Schedules Strategically 431| 432|Group related schedules in a single Digital Employee: 433| 434|{% code lineNumbers="true" %} 435| 436|python 437|# Good: Related schedules for a single purpose 438|digital_employee = DigitalEmployee( 439| identity=identity, 440| schedules=[ 441| morning_report_item, # Daily morning report 442| afternoon_check_item, # Afternoon status check 443| evening_summary_item, # Evening summary 444| ], 445|) 446| 447|# Avoid: Unrelated schedules in one employee 448|# Consider creating separate Digital Employees for different purposes 449| 450| 451|{% endcode %} 452| 453|### Advanced Configuration 454| 455|#### Dynamic Schedule Inputs 456| 457|Use detailed inputs to provide context: 458| 459|{% code lineNumbers="true" %} 460| 461|python 462|schedule_item = ScheduleItemConfig( 463| schedule_config=schedule, 464| input=""" 465| Generate a daily report including: 466| 1. Summary of completed tasks 467| 2. Pending items requiring attention 468| 3. Any system alerts or issues 469| 4. Send the report to the team channel 470| """ 471|) 472| 473| 474|{% endcode %} 475| 476|#### Combining with Other Features 477| 478|Schedules work seamlessly with other Digital Employee features: 479| 480|{% code lineNumbers="true" %} 481| 482|python 483|from digital_employee_core.connectors.mcps import google_mail_mcp 484| 485|# Digital Employee with schedules and MCP tools 486|digital_employee = DigitalEmployee( 487| identity=identity, 488| schedules=[email_check_schedule_item], 489| mcps=[google_mail_mcp], # Can use email tools in scheduled tasks 490| configurations=configurations, 491|) 492| 493| 494|{% endcode %} 495| 496|### Troubleshooting 497| 498|#### Schedule Not Triggering 499| 500|Problem: Schedule was created but tasks are not running. 501| 502|Solution: 503| 504|* Verify the Digital Employee is deployed: digital_employee.deploy() 505|* Check the cron expression is valid: schedule.to_cron_string() 506|* Confirm the schedule exists: agent.schedule.list() 507|* Check for failed runs: agent.schedule.list_runs(schedule_id) 508| 509|#### Incorrect Timing 510| 511|Problem: Schedule runs at unexpected times. 512| 513|Solution: 514| 515|* Verify time zone settings 516|* Double-check cron parameters (especially day_of_week where 0=Monday) 517|* Test with to_cron_string() to see the actual cron expression 518|* Review the next_run_time field in the schedule object 519| 520|#### Schedule Runs Failed 521| 522|Problem: Schedule triggers but execution fails. 523| 524|Solution: 525| 526|* Check run details: run.get_result() for error messages 527|* Verify the input instruction is clear and actionable 528|* Ensure required tools/MCPs are configured and accessible 529|* Review Digital Employee logs for detailed error information 530| 531|#### Multiple Schedules Conflict 532| 533|Problem: Multiple schedules running simultaneously cause issues. 534| 535|Solution: 536| 537|* Stagger schedule times by adjusting minute/hour values 538|* Consider if schedules can be combined into a single task 539|* Monitor system resources and adjust frequency if needed 540| 541|### API Reference 542| 543|#### ScheduleConfig 544| 545|{% code lineNumbers="true" %} 546| 547|python 548|from glaip_sdk.models.schedule import ScheduleConfig 549| 550|schedule = ScheduleConfig( 551| minute: str, # "0-59", "*", "*/15", "0,30" 552| hour: str, # "0-23", "*", "9-17", "8,12,18" 553| day_of_month: str, # "1-31", "*", "1,15" 554| month: str, # "1-12", "*", "1-6" 555| day_of_week: str, # "0-6", "*", "0-4", "0,6" 556|) 557| 558|# Convert to cron string 559|cron_string = schedule.to_cron_string() 560| 561| 562|{% endcode %} 563| 564|#### ScheduleItemConfig 565| 566|{% code lineNumbers="true" %} 567| 568|python 569|from digital_employee_core.schedule import ScheduleItemConfig 570| 571|schedule_item = ScheduleItemConfig( 572| schedule_config: ScheduleConfig, # The timing configuration 573| input: str, # The instruction to execute 574|) 575| 576| 577|{% endcode %} 578| 579|#### DigitalEmployee with Schedules 580| 581|{% code lineNumbers="true" %} 582| 583|python 584|from digital_employee_core import DigitalEmployee 585| 586|digital_employee = DigitalEmployee( 587| identity: DigitalEmployeeIdentity, 588| schedules: list[ScheduleItemConfig] = [], # Optional list of schedules 589| mcps: list = [], # Optional MCP connectors 590| configurations: list = [], # Optional configurations 591|) 592| 593|# Deploy to activate schedules 594|digital_employee.deploy() 595| 596|# Get configured schedules 597|schedules = digital_employee.get_schedule() 598| 599| 600|{% endcode %} 601| 602|#### Managing Schedules via Agent 603| 604|{% code lineNumbers="true" %} 605| 606|python 607|from glaip_sdk import Client 608| 609|client = Client() 610|agent = client.get_agent_by_id(agent_id) 611| 612|# List all schedules 613|schedules = agent.schedule.list() 614| 615|# Get runs for a schedule 616|runs = agent.schedule.list_runs(schedule_id) 617| 618|# Access run details 619|for run in runs: 620| print(f"Status: {run.status}") 621| print(f"ID: {run.id}") 622| if run.status == "success": 623| result = run.get_result() 624| 625| 626|{% endcode %} 627| 628|### Examples in Repository 629| 630|For complete working examples, see: 631| 632|* https://github.com/GDP-ADMIN/CATAPA-SDK/blob/main/python/digital-employee-core/examples/scheduler_usage.py - Comprehensive scheduler demonstration 633| 634| 635|--- 636| 637|# Agent Instructions 638|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 639| 640|## Querying This Documentation 641|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 642| 643|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 644| 645| 646|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/scheduler-configuration.md?ask=<question>&goal=<endgoal> 647| 648| 649|ask is the immediate question: it should be specific, self-contained, and written in natural language. 650|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 651| 652|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 653| 654|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 655|


advanced examples/skills configuration

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Skills Configuration 4| 5|### Overview 6| 7|Skills let a Digital Employee follow a reusable operating guide for a specific task or domain. 8| 9|This repository follows the AIP skills configuration model. For the canonical guide, see the AIP Skills Guide. 10| 11|There are two supported usage patterns demonstrated by the examples: 12| 13|* Remote GitHub-based skills 14|* Local path-based skills 15| 16|Use remote skills when you want a deployable Digital Employee that references skills stored in GitHub. Use local skills when you want to develop and test skill behavior locally without deploying. 17| 18|### Key Concepts 19| 20|#### What is a skill? 21| 22|A skill is an instruction package that gives the Digital Employee a narrowly scoped behavior. In practice, the examples in this repository show two ways to provide a skill: 23| 24|* A GitHub URL pointing to a skill directory 25|* A local filesystem path loaded with Skill.from_path(...) 26| 27|#### How skills are attached 28| 29|You attach skills when constructing DigitalEmployee: 30| 31|{% code lineNumbers="true" %} 32| 33|python 34|from digital_employee_core import DigitalEmployee 35| 36|DigitalEmployee( 37| identity=identity, 38| skills=skills, 39|) 40| 41| 42|{% endcode %} 43| 44|You can also add skills later using digital_employee.add_skills(...) before deployment or execution. 45| 46|#### Skill source types 47| 48|Remote GitHub skills 49| 50|In examples/skills_example.py, the skill source is a GitHub URL: 51| 52|{% code lineNumbers="true" %} 53| 54|python 55|canvas_design_skill = "https://github.com/anthropics/skills/tree/main/skills/canvas-design" 56| 57|return DigitalEmployee(identity=identity, skills=[canvas_design_skill]) 58| 59| 60|{% endcode %} 61| 62|This is the right choice when: 63| 64|* You want skills stored in a versioned repository 65|* You want the Digital Employee to be deployed and run remotely 66|* You want to share the same skill source across environments 67| 68|Local path-based skills 69| 70|In examples/local_skills/local_skills_example.py, the skill source is loaded from disk: 71| 72|{% code lineNumbers="true" %} 73| 74|python 75|from glaip_sdk.skills import Skill 76| 77|local_skill = Skill.from_path(str(skill_path)) 78|return DigitalEmployee(identity=identity, skills=[local_skill]) 79| 80| 81|{% endcode %} 82| 83|This is the right choice when: 84| 85|* You are developing a skill locally 86|* You want deterministic testing during development 87|* You do not want to deploy the skill first 88| 89|### Remote GitHub Skills Example 90| 91|The file examples/skills_example.py demonstrates the remote workflow. 92| 93|#### 1) Create the Digital Employee identity 94| 95|{% code lineNumbers="true" %} 96| 97|python 98|from digital_employee_core import DigitalEmployee, DigitalEmployeeIdentity, DigitalEmployeeJob 99| 100|job = DigitalEmployeeJob( 101| title="Skills-enabled Assistant - Example", 102| description="A digital employee using remote skills from GitHub", 103| instruction="You are a helpful assistant.", 104|) 105| 106|identity = DigitalEmployeeIdentity( 107| name="skills_github_assistant", 108| email="skills.github@example.com", 109| job=job, 110|) 111| 112| 113|{% endcode %} 114| 115|#### 2) Attach a GitHub-hosted skill 116| 117|{% code lineNumbers="true" %} 118| 119|python 120|canvas_design_skill = "https://github.com/anthropics/skills/tree/main/skills/canvas-design" 121| 122|github_de = DigitalEmployee(identity=identity, skills=[canvas_design_skill]) 123| 124| 125|{% endcode %} 126| 127|#### 3) Deploy before running 128| 129|{% code lineNumbers="true" %} 130| 131|python 132|github_de.deploy() 133| 134|message = ( 135| "Create a canvas design with a blue background and the text 'Hello, World!' " 136| "in white, do not ask any follow-up questions, just create the design." 137|) 138|result = github_de.run(message=message) 139| 140| 141|{% endcode %} 142| 143|#### What this example shows 144| 145|* The Digital Employee accepts a GitHub URL as a skill source 146|* Remote skills are used in the normal deployed workflow 147|* deploy() is called before run(...) 148| 149|#### Private GitHub repositories 150| 151|The example notes that public repositories work directly. For private repositories, you must provide one of these environment variables: 152| 153|* GITHUB_PERSONAL_ACCESS_TOKEN 154|* GITHUB_TOKEN 155|* GH_TOKEN 156| 157|### Local Skills Example 158| 159|The directory examples/local_skills/ demonstrates the local workflow. 160| 161|#### 1) Define the skill directory 162| 163|Make a file in ./.agents/skills/haiku-standup/SKILL.md with the following content: 164| 165|{% code lineNumbers="true" %} 166| 167|md 168|--- 169|name: haiku-standup 170|description: > 171| Format daily standup updates into the team's custom standup template. 172| Use when the user mentions "standup", "daily update", "what I did yesterday", 173| or asks to format their work status. 174|--- 175| 176|# Haiku Standup Formatter 177| 178|Format every standup update using the exact structure below. Never skip sections. 179|Never reorder them. Always generate the haiku — do not ask the user to write one. 180| 181|## Output Template 182| 183|```text 184|📋 STANDUP — [TODAY'S DATE in YYYY-MM-DD] 185| 186|🎋 [A haiku summarizing the update — must be valid 5-7-5 syllable structure] 187| 188|🔥 BLOCKER [PRIORITY-CODE] 189|[Blocker description — what it is and what it's blocking] 190|(If no blockers, write: "☁️ ALL CLEAR — No blockers today") 191| 192|✅ DONE 193|- [Completed item 1] 194|- [Completed item 2] 195| 196|🎯 TODAY 197|- [Planned item 1] 198|- [Planned item 2] 199| 200|Vibe Check: [MOON-RATING] ([N]/5) 201|``` 202| 203| 204|{% endcode %} 205| 206|#### 2) Load the local skill 207| 208|{% code lineNumbers="true" %} 209| 210|python 211|from pathlib import Path 212| 213|skill_path = Path(__file__).parent / ".agents/skills/haiku-standup" 214| 215| 216|{% endcode %} 217| 218|#### 3) Load the local skill 219| 220|{% code lineNumbers="true" %} 221| 222|python 223|from glaip_sdk.skills import Skill 224| 225|local_skill = Skill.from_path(str(skill_path)) 226| 227| 228|{% endcode %} 229| 230|#### 4) Attach the skill to a Digital Employee 231| 232|{% code lineNumbers="true" %} 233| 234|python 235|job = DigitalEmployeeJob( 236| title="Local Skills Assistant", 237| description="A digital employee using local skills for deterministic development", 238| instruction="You are a helpful assistant. Use the attached local skill as your operating guide.", 239|) 240| 241|identity = DigitalEmployeeIdentity( 242| name="skills_local_assistant", 243| email="skills.local@example.com", 244| job=job, 245|) 246| 247|local_de = DigitalEmployee(identity=identity, skills=[local_skill]) 248| 249| 250|{% endcode %} 251| 252|#### 5) Run locally without deployment 253| 254|{% code lineNumbers="true" %} 255| 256|python 257|message = ( 258| "Standup: Yesterday I migrated the user table to the new schema and pair-programmed with Alex on the search " 259| "feature. Today I'm writing tests for the migration. I'm stuck waiting on QA to finish their test plan." 260|) 261|result = local_de.run(message=message, local=True) 262| 263| 264|{% endcode %} 265| 266|#### What this example shows 267| 268|* A local skill is loaded from a filesystem path 269|* The skill folder is expected to exist before execution 270|* Path-based skills are intended for local execution only 271|* Local skills should be run with run(..., local=True) 272|* The example does not call deploy() 273| 274|### When to Use Which Approach 275| 276|#### Use remote GitHub skills when 277| 278|* You want a deployable Digital Employee 279|* Your skill definitions are stored in GitHub 280|* You want centralized version control for skill content 281|* You are building a remotely hosted assistant workflow 282| 283|#### Use local skills when 284| 285|* You are iterating on skill content locally 286|* You want quick testing without deployment 287|* You need local-only experimentation or deterministic development loops 288|* You already have a local skill folder with a valid SKILL.md 289| 290|### Best Practices 291| 292|#### 1. Keep skills narrowly scoped 293| 294|Write each skill for a specific job, such as copywriting or standup formatting, rather than combining many unrelated behaviors into one skill. 295| 296|#### 2. Use deploy() only for remote workflows 297| 298|Follow the examples: 299| 300|* Remote GitHub skill example: call deploy() before run(...) 301|* Local path-based skill example: skip deploy and call run(..., local=True) 302| 303|#### 3. Validate the local path before running 304| 305|The local example checks that the path exists before creating the employee. This is a good pattern when developing local skills. 306| 307|#### 4. Keep SKILL.md explicit 308| 309|A strong skill file should clearly define: 310| 311|* When the skill applies 312|* The expected output structure 313|* Rules and constraints 314|* What the model must infer versus what it must ask about 315| 316|### Troubleshooting 317| 318|#### Local skill is not being found 319| 320|Problem: The local skill does not load. 321| 322|Solution: 323| 324|* Verify the directory path is correct 325|* Verify SKILL.md exists at the root of the skill directory 326|* Verify you are calling Skill.from_path(str(skill_path)) 327| 328|#### Local skill does not behave as expected 329| 330|Problem: The output ignores the intended format. 331| 332|Solution: 333| 334|* Make the instructions in SKILL.md more explicit 335|* Add stricter output templates and rules 336|* Ensure the employee instruction does not conflict with the skill behavior 337| 338|#### Remote GitHub skill cannot be accessed 339| 340|Problem: The Digital Employee cannot use the GitHub-based skill. 341| 342|Solution: 343| 344|* Verify the GitHub URL points to the correct skill directory 345|* If the repository is private, set GITHUB_PERSONAL_ACCESS_TOKEN, GITHUB_TOKEN, or GH_TOKEN 346|* Ensure you call deploy() before run(...) 347| 348| 349|--- 350| 351|# Agent Instructions 352|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 353| 354|## Querying This Documentation 355|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 356| 357|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 358| 359| 360|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/skills-configuration.md?ask=<question>&goal=<endgoal> 361| 362| 363|ask is the immediate question: it should be specific, self-contained, and written in natural language. 364|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 365| 366|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 367| 368|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 369|


advanced examples/sub agents configuration

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Sub Agents Configuration 4| 5|### Overview 6| 7|A Digital Employee can be composed of a coordinator agent plus one or more sub-agents. Sub-agents are attached as nested agents on the underlying glaip_sdk.Agent instance. 8| 9|In this repository, see examples/configuration_propagation_example.py for a working example (including config propagation). 10| 11|### Key Concepts 12| 13|#### What is a “sub-agent”? 14| 15|A sub-agent is a glaip_sdk.Agent instance attached under the coordinator agent. At deploy-time, DigitalEmployee builds a single root Agent and passes sub-agents into the Agent(..., agents=[...]) field. 16| 17|#### How sub-agents are attached 18| 19|You attach sub-agents by providing them to DigitalEmployee: 20| 21|* DigitalEmployee(sub_agents=[...]) (recommended) 22|* digital_employee.add_sub_agents([...]) 23| 24|#### Configuration propagation (tools + MCPs) 25| 26|When the Digital Employee is deployed, it will process sub_agents and automatically propagate tool/MCP configs from the parent to sub-agents when: 27| 28|* The sub-agent uses a tool/MCP. 29|* The sub-agent does not already define a config for that tool/MCP. 30| 31|Notes: 32| 33|* Existing sub-agent configs take precedence over propagated configs. 34|* Propagation is recursive: nested sub-agents (sub-agents of sub-agents) are processed as well. 35|* Currently only glaip_sdk.Agent is supported as a sub-agent type; unsupported types are skipped with a warning. 36| 37|### Minimal Example 38| 39|#### 1) Create a coordinator Digital Employee 40| 41|python 42|from digital_employee_core import DigitalEmployeeIdentity, DigitalEmployeeJob 43| 44|job = DigitalEmployeeJob( 45| title="Coordinator", 46| description="Delegates tasks to specialists", 47| instruction="You are the coordinator. Delegate tasks to your sub-agents.", 48|) 49|identity = DigitalEmployeeIdentity(name="Coordinator", email="coordinator@example.com", job=job) 50| 51| 52|#### 2) Define one or more sub-agents 53| 54|python 55|from glaip_sdk import Agent 56| 57|reminder_agent = Agent( 58| name="ReminderAgent", 59| instruction="You are a reminder specialist.", 60|) 61| 62| 63|#### 3) Attach sub-agents and deploy 64| 65|python 66|from digital_employee_core import DigitalEmployee 67| 68|digital_employee = DigitalEmployee( 69| identity=identity, 70| sub_agents=[reminder_agent], 71|) 72| 73|digital_employee.deploy() 74| 75| 76|### Notes / Best Practices 77| 78|* Add or remove sub-agents before deploy; changes after deploy require re-deploying to update the agent graph. 79|* Prefer stable, unique Agent.name values (removal uses name matching). 80|* If sub-agents use MCPs/tools that require configs, prefer putting shared configs on the parent DigitalEmployee.configurations and rely on propagation; override only when a sub-agent needs different settings. 81| 82| 83|--- 84| 85|# Agent Instructions 86|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 87| 88|## Querying This Documentation 89|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 90| 91|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 92| 93| 94|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/sub-agents-configuration.md?ask=<question>&goal=<endgoal> 95| 96| 97|ask is the immediate question: it should be specific, self-contained, and written in natural language. 98|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 99| 100|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 101| 102|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 103|


advanced examples/user information in digital employee runs

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# User Information in Digital Employee Runs 4| 5|### Overview 6| 7|Digital Employee Core handles user information in two different ways: 8| 9|* User-scoped memory uses memory_user_id to isolate remembered facts per user. 10|* User-authenticated tools use delegated user tokens so external systems can authorize actions as the current user. 11| 12|These two mechanisms are related, but they solve different problems. memory_user_id controls memory isolation. Delegation tokens control what a tool is allowed to do on behalf of the user. 13| 14|For the GL AIP delegation flow, see: 15| 16|* Delegate to Agent for the delegation token object and scope structure. 17|* Validate Delegation Token for how receiving services validate delegation tokens and enforce scopes. 18| 19|For GL Connectors integration setup, see Integration Setup. 20| 21|### Key Concepts 22| 23|#### memory_user_id 24| 25|memory_user_id is the stable user identifier used by the memory provider. 26| 27|* Same memory_user_id + same agent => the agent can recall that user's previous facts. 28|* Different memory_user_id + same agent => memory stays isolated. 29|* It should be a stable internal user ID. Avoid PII such as email addresses unless required. 30| 31|See also: Memory Configuration. 32| 33|#### user_authentication 34| 35|user_authentication is an opt-in flag in a tool config. When it is enabled, GL AIP knows that the dependency needs a delegated user token. 36| 37|Use it for tools that call user-scoped APIs, such as calendars, mail, HR self-service, finance self-service, GL Connectors, or other systems where permissions depend on the current user. 38| 39|#### Delegated tokens 40| 41|Delegated tokens are passed at run time, not written into prompts. GL AIP validates the incoming delegation token, resolves which downstream token is needed for each user-authenticated dependency, then exposes that token to tools through runtime metadata. 42| 43|For example, a GL Connectors-enabled dependency receives gl_connectors_token in RunnableConfig.metadata. For local or manual runs, you can pass the token explicitly to run(): 44| 45|python 46|result = digital_employee.run( 47| message="Show my pending requests", 48| gl_connectors_token=os.getenv("GL_CONNECTORS_TOKEN"), 49|) 50| 51| 52|The token name depends on the downstream integration. For GL Connectors, use gl_connectors_token. 53| 54|#### GL AIP handoff 55| 56|Tools should not parse the original GL IAM delegation token object directly. Treat GL AIP as the boundary that: 57| 58|1. Receives the delegation token object described in Delegate to Agent. 59|2. Validates the delegation token as described in Validate Delegation Token. 60|3. Looks up user-authenticated dependencies and attaches the appropriate integration token, such as gl_connectors_token, to tool runtime metadata. 61| 62|In custom tools, read only the integration-specific token from RunnableConfig.metadata and use it to authenticate with the downstream connector. 63| 64|When using GL Connectors, configure the connector integration first. See GL Connectors Integration Setup. 65| 66|### Runtime User Context in RunnableConfig 67| 68|Digital Employee tools can receive user and conversation context through RunnableConfig.metadata. This context can be used by the tools to act on behalf of human (OBOH). 69| 70|The runtime parameter contract is sent by GLChat to AIP from the AIP execution strategy. 71| 72|The main chat-message path populates this context from the Agent message processor. Pipeline-based runs may provide context through the Pipeline service. 73| 74|| Parameter | Location | Purpose | 75|| --------------------- | --------------------------------------------- | ----------------------------------------------- | 76|| gl_connectors_token | RunnableConfig.metadata.gl_connectors_token | Delegated connector token for the current user. | 77|| user_id | RunnableConfig.metadata.user_id | Current user identifier. | 78|| tenant_id | RunnableConfig.metadata.tenant_id | Current tenant context. | 79|| conversation_id | RunnableConfig.metadata.conversation_id | Conversation associated with the run. | 80|| message_id | RunnableConfig.metadata.message_id | User message associated with the run. | 81|| email | RunnableConfig.metadata.email | Current user email or username fallback. | 82|| organization_id | RunnableConfig.metadata.organization_id | Organization context. | 83|| chatbot_id | RunnableConfig.metadata.chatbot_id | Chatbot or assistant identifier. | 84|| agent | RunnableConfig.metadata.agent | Agent-specific metadata, when provided. | 85| 86|Example usage in a custom tool: 87| 88|python 89|def _run(self, config: RunnableConfig = None, **kwargs): 90| metadata = ((config or {}).get("metadata") or {}) 91| 92| gl_connectors_token = metadata.get("gl_connectors_token") 93| user_id = metadata.get("user_id") 94| tenant_id = metadata.get("tenant_id") 95| conversation_id = metadata.get("conversation_id") 96| message_id = metadata.get("message_id") 97| email = metadata.get("email") 98| organization_id = metadata.get("organization_id") 99| chatbot_id = metadata.get("chatbot_id") 100| agent_metadata = metadata.get("agent") 101| 102| 103|Do not store these values in tool configuration or prompts. Treat them as runtime context for the current Digital Employee run. 104| 105|### User-Scoped Memory Example 106| 107|Enable memory in agent_config, then pass memory_user_id on each run() or arun() call. 108| 109|{% code lineNumbers="true" %} 110| 111|python 112|from digital_employee_core import DigitalEmployee, DigitalEmployeeIdentity, DigitalEmployeeJob 113|from digital_employee_core.configuration.agent_configuration import AgentConfigKeys, MemoryProvider 114| 115|job = DigitalEmployeeJob( 116| title="Memory-Enabled Assistant", 117| description="A digital employee that can remember user-specific facts across calls", 118| instruction="When the user tells you a personal preference or fact, remember it for future conversation.", 119|) 120| 121|identity = DigitalEmployeeIdentity(name="memory_assistant", email="memory.assistant@example.com", job=job) 122| 123|digital_employee = DigitalEmployee( 124| identity=identity, 125| agent_config={AgentConfigKeys.MEMORY: MemoryProvider.MEM0}, 126|) 127| 128|digital_employee.deploy() 129| 130|memory_user_id = "user-123" 131| 132|digital_employee.run( 133| message="My preferred report format is a short bullet summary. Please remember this.", 134| memory_user_id=memory_user_id, 135|) 136| 137|digital_employee.run( 138| message="How should you format my reports?", 139| memory_user_id=memory_user_id, 140|) 141| 142| 143|{% endcode %} 144| 145|> Note: If memory is enabled, memory_user_id is required. Digital Employee Core raises an error when run() or arun() is called without it. 146| 147|### User Information in Custom Tools 148| 149|Custom tools should treat delegated user tokens as runtime credentials. Do not store them in static config and do not include them in prompts. 150| 151|Digital Employee Core custom tools follow the LangChain BaseTool pattern: 152| 153|* Define an input schema with Pydantic. 154|* Define a tool config schema with Pydantic. 155|* Set tool_config_schema on the tool. 156|* Read static config with self.get_tool_config(config). 157|* Read delegated user tokens from RunnableConfig.metadata, such as config.get("metadata").get("gl_connectors_token"). 158| 159|#### 1) Create a custom tool 160| 161|This example creates a custom user_profile_tool that calls GL Connectors to fetch the current user's profile. The API key is service-level authentication. The gl_connectors_token is delegated user authentication for the current run. 162| 163|Before using this pattern, ensure the target connector integration is configured in GL Connectors. See Integration Setup. 164| 165|{% code lineNumbers="true" %} 166| 167|python 168|import json 169|import requests 170|from typing import Any 171| 172|from gl_connectors_sdk import GLConnectors 173|from langchain_core.runnables import RunnableConfig 174|from langchain_core.tools import BaseTool 175|from pydantic import BaseModel, Field 176| 177|REQUEST_TIMEOUT_SECONDS = 30 178| 179| 180|class UserProfileToolInput(BaseModel): 181| """Input schema for user profile tool.""" 182| 183| include_contact: bool = Field(default=False, description="Whether to include contact fields in the response.") 184| 185| 186|class UserProfileToolConfig(BaseModel): 187| """Configuration schema for user profile tool.""" 188| 189| user_api_base_url: str = Field(description="The base URL for the downstream user profile API.") 190| gl_connectors_api_base_url: str = Field(description="The base URL for the GL Connectors API.") 191| gl_connectors_api_key: str = Field(description="The API key for authenticating with the GL Connectors API.") 192| user_authentication: bool = Field(description="Whether this tool requires delegated user authentication.", default=True) 193| 194| 195|class UserProfileTool(BaseTool): 196| """Tool for reading the current user's profile through GL Connectors.""" 197| 198| name: str = "user_profile_tool" 199| description: str = "Read the current user's profile information." 200| args_schema: type[BaseModel] = UserProfileToolInput 201| tool_config_schema: type[BaseModel] = UserProfileToolConfig 202| 203| def _run(self, include_contact: bool = False, config: RunnableConfig = None, **_kwargs: Any) -> str: 204| """Read the current user's profile.""" 205| tool_config = self.get_tool_config(config) 206| gl_connectors_token = ((config or {}).get("metadata") or {}).get("gl_connectors_token") 207| 208| if not gl_connectors_token: 209| return "Error: gl_connectors_token is required for this user-authenticated tool." 210| 211| try: 212| access_token = self._get_access_token_from_gl_connectors(tool_config, gl_connectors_token) 213| headers = {"Authorization": f"Bearer {access_token}"} 214| params = {"include_contact": include_contact} 215| 216| base_url = tool_config.user_api_base_url.rstrip("/") 217| url = f"{base_url}/user/profile" 218| response = requests.get(url, headers=headers, params=params, timeout=REQUEST_TIMEOUT_SECONDS) 219| response.raise_for_status() 220| return response.text 221| except requests.HTTPError as e: 222| return f"Failed to read user profile. Status code: {e.response.status_code}, Response: {e.response.text}" 223| except Exception as e: 224| return f"Error reading user profile: {str(e)}" 225| 226| def _get_access_token_from_gl_connectors( 227| self, 228| tool_config: UserProfileToolConfig, 229| gl_connectors_token: str, 230| ) -> str: 231| """Exchange the delegated GL Connectors token for downstream auth info.""" 232| connector = GLConnectors( 233| api_base_url=tool_config.gl_connectors_api_base_url, 234| api_key=tool_config.gl_connectors_api_key, 235| ) 236| 237| # Check which integration belongs to this delegated user. 238| user_info = connector.get_user_info(gl_connectors_token) 239| user_identifier = next( 240| integration.user_identifier 241| for integration in user_info.integrations 242| if integration.connector == "user-profile" 243| ) 244| 245| # GL Connectors returns integration-specific auth information as auth_string. 246| integration_info = connector.get_integration("user-profile", gl_connectors_token, user_identifier) 247| auth_string = integration_info.get("auth_string") 248| if not auth_string: 249| raise ValueError("auth_string is missing or empty") 250| 251| return json.loads(auth_string)["access_token"] 252| 253| 254|{% endcode %} 255| 256|#### 2) Add user_authentication in tool config 257| 258|Set user_authentication: true in the tool config template. This tells GL AIP that the tool needs delegated user authentication. 259| 260|config_templates/tool_configs.yaml: 261| 262|yaml 263|user_profile_tool: 264| user_api_base_url: "${USER_API_BASE_URL}" 265| gl_connectors_api_base_url: "${GL_CONNECTORS_API_BASE_URL}" 266| gl_connectors_api_key: "${GL_CONNECTORS_API_KEY}" 267| user_authentication: true 268| 269| 270|The config key must match the tool name: 271| 272|python 273|class UserProfileTool(BaseTool): 274| name: str = "user_profile_tool" 275| 276| 277|#### 3) Handle delegated tokens in tool logic 278| 279|The delegated token is passed to digital_employee.run() and then forwarded to the tool call through RunnableConfig.metadata. In the custom tool, read it from config.get("metadata").get("gl_connectors_token"). 280| 281|python 282|def _run(self, include_contact: bool = False, config: RunnableConfig = None, **_kwargs: Any) -> str: 283| tool_config = self.get_tool_config(config) 284| gl_connectors_token = ((config or {}).get("metadata") or {}).get("gl_connectors_token") 285| 286| if not gl_connectors_token: 287| return "Error: gl_connectors_token is required for this user-authenticated tool." 288| 289| access_token = self._get_access_token_from_gl_connectors(tool_config, gl_connectors_token) 290| 291| headers = { 292| "Authorization": f"Bearer {access_token}", 293| } 294| 295| 296|Use the GL Connectors token to retrieve the integration auth_string, then parse the auth string for the downstream API credential. The connector and its integration must already be set up in GL Connectors. See Integration Setup. 297| 298|python 299|def _get_access_token_from_gl_connectors( 300| self, 301| tool_config: UserProfileToolConfig, 302| gl_connectors_token: str, 303|) -> str: 304| connector = GLConnectors( 305| api_base_url=tool_config.gl_connectors_api_base_url, 306| api_key=tool_config.gl_connectors_api_key, 307| ) 308| 309| user_info = connector.get_user_info(gl_connectors_token) 310| user_identifier = next( 311| integration.user_identifier 312| for integration in user_info.integrations 313| if integration.connector == "user-profile" 314| ) 315| 316| integration_info = connector.get_integration("user-profile", gl_connectors_token, user_identifier) 317| auth_string = integration_info.get("auth_string") 318| if not auth_string: 319| raise ValueError("auth_string is missing or empty") 320| 321| return json.loads(auth_string)["access_token"] 322| 323| 324|In this pattern: 325| 326|* gl_connectors_api_key authenticates the tool to GL Connectors. 327|* gl_connectors_token identifies the current delegated user in GL Connectors. 328|* auth_string contains the downstream integration credential for that delegated user. 329|* user_authentication: true signals that GL AIP should delegate the appropriate token to the tool. 330| 331|For GL Connectors setup details, see GL Connectors Integration Setup. 332| 333|### Configuration Propagation to Sub-Agents 334| 335|Digital Employee Core propagates tool configs from the parent Digital Employee to sub-agents by dependency name. 336| 337|This means a parent can define user_authentication: true once for a shared tool, and a sub-agent that uses the same dependency can receive the config automatically. 338| 339|{% code lineNumbers="true" %} 340| 341|python 342|digital_employee = DigitalEmployee( 343| identity=identity, 344| tools=[Tool.from_langchain(UserProfileTool)], 345| sub_agents=[profile_helper_agent], 346| configurations=configurations, 347|) 348| 349|digital_employee.deploy() 350| 351| 352|{% endcode %} 353| 354|If the sub-agent defines its own config for the same tool, the sub-agent config takes precedence. 355| 356|See also: Sub-Agents Configuration. 357| 358|### Integrate the Custom Tool in Digital Employee 359| 360|Wrap the custom tool with Tool.from_langchain() and add a config loader for the tool config template. 361| 362|For deployed GL AIP runs, AIP validates the delegation token and attaches integration-specific tokens to runtime metadata. For local or manual runs, pass the delegated token explicitly in run(). 363| 364|{% code lineNumbers="true" %} 365| 366|python 367|import os 368|from pathlib import Path 369| 370|from dotenv import load_dotenv 371|from glaip_sdk import MCP, Agent, Tool 372| 373|from digital_employee_core import ( 374| DEFAULT_MODEL_NAME, 375| ConfigTemplateLoader, 376| DigitalEmployee, 377| DigitalEmployeeConfiguration, 378| DigitalEmployeeIdentity, 379| DigitalEmployeeJob, 380|) 381| 382|from my_project.tools.user_profile_tool import UserProfileTool 383| 384|load_dotenv() 385| 386| 387|class MyDigitalEmployee(DigitalEmployee): 388| """Digital Employee with custom tool config templates.""" 389| 390| def __init__( 391| self, 392| identity: DigitalEmployeeIdentity, 393| tools: list[Tool] | None = None, 394| sub_agents: list[Agent] | None = None, 395| mcps: list[MCP] | None = None, 396| configurations: list[DigitalEmployeeConfiguration] | None = None, 397| model: str | None = DEFAULT_MODEL_NAME, 398| ): 399| super().__init__(identity, tools, sub_agents, mcps, configurations, model) 400| 401| config_dir = Path(__file__).parent / "config_templates" 402| self.add_config_loader(ConfigTemplateLoader(template_dir=config_dir)) 403| 404| 405|identity = DigitalEmployeeIdentity( 406| name="profile_assistant", 407| email="profile.assistant@example.com", 408| job=DigitalEmployeeJob( 409| title="Profile Assistant", 410| description="Helps users retrieve their own profile information", 411| instruction="Use the user profile tool when the user asks about their own profile.", 412| ), 413|) 414| 415|configurations = [ 416| DigitalEmployeeConfiguration(key="USER_API_BASE_URL", value=os.getenv("USER_API_BASE_URL", "")), 417| DigitalEmployeeConfiguration(key="GL_CONNECTORS_API_BASE_URL", value=os.getenv("GL_CONNECTORS_API_BASE_URL", "")), 418| DigitalEmployeeConfiguration(key="GL_CONNECTORS_API_KEY", value=os.getenv("GL_CONNECTORS_API_KEY", "")), 419|] 420| 421|# GL_CONNECTORS_TOKEN is a delegated user token for the current run. 422|# See the GL AIP Delegate to Agent guide for how to obtain it. 423|gl_connectors_token = os.getenv("GL_CONNECTORS_TOKEN") 424| 425|digital_employee = MyDigitalEmployee( 426| identity=identity, 427| tools=[Tool.from_langchain(UserProfileTool)], 428| configurations=configurations, 429|) 430| 431|digital_employee.deploy() 432| 433|result = digital_employee.run( 434| message="Show my profile information", 435| gl_connectors_token=gl_connectors_token, 436|) 437| 438| 439|{% endcode %} 440| 441|### Notes / Best Practices 442| 443|* Do not put tokens in prompts. Pass delegated tokens as run() / arun() keyword arguments only for local/manual runs; in deployed GL AIP runs, read the resolved token from RunnableConfig.metadata. 444|* Do not parse GL IAM delegation tokens in custom tools. Use GL AIP for delegation-token validation and only consume the integration-specific token exposed to the tool. 445|* Use memory_user_id only for memory scoping. Do not use it as an authorization token. 446|* Enable user_authentication only when needed. Tools that only use service credentials do not need delegated user tokens. 447|* Keep service credentials in configuration. Use DigitalEmployeeConfiguration, config templates or environment variables. 448|* Propagate configs intentionally. Shared parent configs are convenient for sub-agents, but sub-agent-specific configs should be explicit when permissions differ. 449|* Validate original delegation tokens at service boundaries. If a receiving service handles the original GL IAM delegation token directly, validate it according to Validate Delegation Token. 450| 451|### Troubleshooting 452| 453|#### Memory is enabled but the run fails 454| 455|Check that every run() or arun() call includes a non-empty memory_user_id. 456| 457|python 458|digital_employee.run( 459| message="What did I tell you earlier?", 460| memory_user_id="user-123", 461|) 462| 463| 464|#### Tool does not receive the user token 465| 466|Check that: 467| 468|1. The tool config includes user_authentication: true. 469|2. The run call passes the integration token, for example gl_connectors_token. 470|3. The token is available in the environment when running locally. 471| 472|bash 473|export GL_CONNECTORS_TOKEN="<delegated_token>" 474| 475| 476| 477|--- 478| 479|# Agent Instructions 480|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 481| 482|## Querying This Documentation 483|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 484| 485|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 486| 487| 488|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/advanced-examples/user-information-in-digital-employee-runs.md?ask=<question>&goal=<endgoal> 489| 490| 491|ask is the immediate question: it should be specific, self-contained, and written in natural language. 492|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 493| 494|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 495| 496|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 497|


digital employee architecture

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Digital Employee Architecture 4| 5|## Overview 6| 7|

8| 9|The Digital Employee system is an AI-powered automation platform built upon the AI Agent Platform (AIP). It enables autonomous workflow execution through intelligent agents. AIP manages agent operations, configurations, and orchestration of these digital employees. 10| 11|The current implementation features a specific digital employee: the HR Recruiter, designed to streamline recruitment pipeline operations. 12| 13|{% hint style="info" %} 14|To learn more about the digital employee, please refer to the Digital Employee GitBook. 15|{% endhint %} 16| 17|## Core Components 18| 19|The architecture consists of three primary layers: the User Interaction Layer, the Digital Employee instance, and the underlying AI Agent Platform (AIP). 20| 21|### 1. User Interaction Layer 22| 23|This layer facilitates communication between human users and the digital employee. 24| 25|* Claudia UI: A manual interface that allows users to provide direct instructions and interact via prompts. 26|* WhatsApp: A mobile interface enabling direct user instructions and prompt-based interactions, where users can send prompts and receive answers directly through the messaging app. 27| 28|### 2. Digital Employee 29| 30|The digital employee is the core component and contains multiple agents with diverse capabilities. 31| 32|* Function: Operates as an intelligent agent utilizing specialized capabilities to execute tasks. 33|* Current Application: The HR Recruiter digital employee processes candidates throughout the entire recruitment lifecycle. 34| 35|### 3. AI Agent Platform (AIP) 36| 37|AIP is the foundation for the system. 38| 39|* Role: Manages creation, configuration, and orchestration of all agents and digital employees. 40|* Environment: All agents are created and maintained within the AIP environment. 41| 42|## Integration Architecture: Model Context Protocol (MCP) 43| 44|The Digital Employee application uses Model Context Protocol (MCP) services to enable agents to interact securely with external systems and services. MCPs are managed through the AIP and use HTTP transport. 45| 46|### Google Workspace Integration 47| 48|The system integrates with Google Workspace services using API Key authentication (X-API-Key header). 49| 50|| MCP Service | Description | Purpose | 51|| ------------------- | ---------------------- | ----------------------------------------------------------------------------- | 52|| Google Calendar | Calendar Operations | Manages calendar events, schedules interviews, and coordinates meetings. | 53|| Google Docs | Document Operations | Handles document creation, editing, and management for recruitment workflows. | 54|| Google Drive | File Operations | Enables storage, retrieval, and management of recruitment documents. | 55|| Google Mail | Email Operations | Facilitates sending candidate communications and managing recruitment emails. | 56|| Google Sheets | Spreadsheet Operations | Manages recruitment data tracking and reporting via spreadsheets. | 57| 58|### External Platform Integration 59| 60|In addition to Google Workspace, the system connects to specialized enterprise platforms. 61| 62|#### SQL Tool MCP 63| 64|* Description: Connects to CATAPA's digital_employee PostgreSQL database. 65|* Transport: HTTP. 66|* Authentication: Custom Headers (Bearer token, X-Api-Key, and X-Bosa-Integration headers). 67|* Purpose: Provides direct access to query and manage recruitment data stored in CATAPA's database system. 68| 69|#### Evalground MCP 70| 71|* Description: Handles operations for the Evalground platform. 72|* Transport: HTTP. 73|* Authentication: Bearer Token (Authorization header). 74|* Purpose: Enables candidate evaluation and assessment operations, specifically for practical test processes. 75| 76|## Tools Framework 77| 78|Digital employees utilize "Tools" to interact with applications outside the scope of MCPs (for example, the CATAPA API). Tools are categorized into two types: Built-in Tools and User-Defined Tools. 79| 80|### Built-in Tools 81| 82|Generic, pre-configured collections provided by the AI Agent Platform. Designed for ease of use without coding. These are some of the built-in tools: 83| 84|* date_range_tool: Utility for handling date ranges. 85|* cv_extractor_tool: Utility for extracting information from Curricula Vitae. 86|* time_tool: Utility for time management. 87| 88|### User-Defined Tools 89| 90|Custom tools created to handle specific tasks not covered by generic tools. Implemented as single-file Python code. These are some of the user-defined tools: 91| 92|* get_employee_info_tool: Retrieves specific employee information. 93|* update_candidate_phase_tool: Updates the recruitment phase of a candidate. 94|* detect_sister_company_tool: Logic to detect associated sister companies. 95| 96|## Key Benefits 97| 98|{% stepper %} 99|{% step %} 100|Automation 101| 102|Significantly reduces manual intervention by enabling scheduled operations. 103|{% endstep %} 104| 105|{% step %} 106|Integration 107| 108|Offers seamless connectivity with Google Workspace and other enterprise systems. 109|{% endstep %} 110| 111|{% step %} 112|Flexibility 113| 114|Features an extensible architecture that supports both standard (Built-in) and custom (User-Defined) tools. 115|{% endstep %} 116| 117|{% step %} 118|Scalability 119| 120|The MCP-based architecture allows for the easy addition of new services and capabilities as needs evolve. 121|{% endstep %} 122|{% endstepper %} 123| 124| 125|--- 126| 127|# Agent Instructions 128|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 129| 130|## Querying This Documentation 131|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 132| 133|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 134| 135| 136|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/digital-employee-architecture.md?ask=<question>&goal=<endgoal> 137| 138| 139|ask is the immediate question: it should be specific, self-contained, and written in natural language. 140|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 141| 142|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 143| 144|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 145|


digital employee architecture/digital employee detailed block diagram

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Digital Employee Detailed Block Diagram 4| 5|

6| 7|#### Digital Employee Overview 8| 9|Digital Employee Core is the SDK designed to make building digital employees easier. The SDK contains common connectors, agents, and functions to build or run a digital employee. One of the components is the digital employee class itself. 10| 11|When creating a digital employee, you will use a pipeline (GL Pipeline) as the foundation. For each step in the pipeline, we can customize the step as desired. We can create many implementations for each step. For example, we can execute an agent in that step (Agent as step), execute a pipeline in that step (Pipeline as step), or implement another simple logic (Non-agent and non-pipeline as step). 12| 13|#### Why a Pipeline Is Introduced 14| 15|1. Efficiency: Fewer LLM calls — reduced operational cost 16|2. Maintainability: Modular step design — independent changes without cascading effects 17|3. Reproducibility: Deterministic execution — same inputs produce same outputs 18|4. Responsiveness: Fewer LLM calls — reduced end-to-end latency 19|5. Testability: Isolated step boundaries — independent testing of each step 20| 21|#### Digital Employee Application 22| 23|Previously, digital employees ran on an AIP server, but now, by default, each digital employee should have its own server to run the digital employee pipeline so that it doesn't have a dependency on the AIP server. 24| 25|Since digital employees now have a pipeline component, it is beneficial to run it in the digital employee application itself for scalability reasons, and there is no equivalent AIP runner for the GL pipeline. 26| 27|The digital employee application will be integrated with GLChat so that GLChat can execute digital employees with the GL pipeline as a foundation instead of executing agents on the AIP server. When the digital employee pipeline consists of a step related to an agent, the execution of that agent also doesn't run on the AIP server; it will run on the digital employee server itself. 28| 29|The digital employee runner should be isolated from the main digital employee application so that it will not affect the main application when there are errors or any risks in the runner. We can call this running in a sandbox. 30| 31|We recommend reusing the digital employee application for multiple digital employee instances. For example, CATAPA can create one digital employee application that consists of two digital employee instances: digital employee payroll officer and digital employee payroll analyst. Choosing whether to combine a new digital employee with an existing digital employee application or create a new digital employee application currently depends on your use case and requirements, especially from a scalability perspective. 32| 33| 34|--- 35| 36|# Agent Instructions 37|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 38| 39|## Querying This Documentation 40|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 41| 42|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 43| 44| 45|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/digital-employee-architecture/digital-employee-detailed-block-diagram.md?ask=<question>&goal=<endgoal> 46| 47| 48|ask is the immediate question: it should be specific, self-contained, and written in natural language. 49|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 50| 51|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 52| 53|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 54|


digital employee architecture/tech stack overview

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Tech Stack Overview 4| 5|

6| 7|A Digital Employee (DE) is built on top of GDP Labs’ core technologies—AI Agent Package (AIP), GL Connectors, and GLChat—which together provide the foundation for an intelligent, integrated, and scalable knowledge worker. AIP supplies the agentic “brain,” enabling the DE to reason, plan, and execute tasks. GL Connectors serve as the integration layer, securely linking the DE to the tools, data sources, and enterprise systems it needs to do real work. GLChat delivers the conversational interface that allows the DE to collaborate naturally with human teams, making it easy to assign work, review outcomes, and keep operations transparent. 8| 9| 10|--- 11| 12|# Agent Instructions 13|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 14| 15|## Querying This Documentation 16|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 17| 18|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 19| 20| 21|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/digital-employee-architecture/tech-stack-overview.md?ask=<question>&goal=<endgoal> 22| 23| 24|ask is the immediate question: it should be specific, self-contained, and written in natural language. 25|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 26| 27|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 28| 29|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 30|


getting started example

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Getting Started Example 4| 5|This quickstart guide walks you through a simple setup to create a digital employee in just a few minutes. 6| 7|## Prerequisites 8| 9|To follow this example, you will need to: 10| 11|* Install the digital-employee-core package 12|* If you are planning to deploy and/or the digital employee in a remote AIP server, set the AIP_API_URL and AIP_API_KEY environment variables in your terminal or in a .env file 13| 14|{% hint style="info" %} 15|You should provide AIP_API_URL and AIP_API_KEY, because the digital employee depends on these two environment variables when you are using a remote AIP server. 16| 17|To get the values for these environment variables, please ask your team which AIP server has been deployed, and then obtain the AIP key. For example, in CATAPA, we use AIP_API_URL=https://aip-dev.catapa.com/ as our AIP development environment. 18| 19|You can set the environment variables in your terminal by using: 20| 21|

export AIP_API_URL=<AIP_API_URL>
22|export AIP_API_KEY=<AIP_API_KEY>
23|
24| 25|{% endhint %} 26| 27|* If you are planning to run the digital employee locally, set the OPENAI_API_KEY environment variables in your terminal or in a .env file 28| 29|{% hint style="info" %} 30|Similar to AIP_API_URL and AIP_API_KEY, you can set OPENAI_API_KEY environment variable by using: 31| 32|console 33|export OPENAI_API_KEY=<OPENAI_API_KEY> 34| 35| 36|{% endhint %} 37| 38|## Build Digital Employee - A Basic Example 39| 40|Start by creating a simple digital employee that can interact with Gmail. This agent will use OpenAI GPT-5.1 as its language model, an MCP setup, and a simple prompt to guide its behavior. 41| 42|### Import the Package 43| 44|{% code lineNumbers="true" %} 45| 46|python 47|from digital_employee_core import ( 48| DigitalEmployee, 49| DigitalEmployeeConfiguration, 50| DigitalEmployeeIdentity, 51| DigitalEmployeeJob, 52|) 53|from digital_employee_core.connectors.mcps import google_mail_mcp 54| 55| 56|{% endcode %} 57| 58|### Initialize the Digital Employee 59| 60|{% code lineNumbers="true" %} 61| 62|python 63|# Identity and configuration 64|job = DigitalEmployeeJob( 65| title="Digital Assistant", 66| description="A helpful digital employee assistant", 67| instruction="You are a helpful digital employee assistant. When asked to send a welcome email, craft a warm, professional message that introduces the team and includes helpful resources. Do not ask for clarification, just proceed with sending the email.", 68|) 69|identity = DigitalEmployeeIdentity(name="Claudia", email="claudia@example.com", job=job) 70|configurations = [ 71| DigitalEmployeeConfiguration(key="GOOGLE_MAIL_MCP_URL", value="https://api.bosa.id/google_mail/mcp"), 72| DigitalEmployeeConfiguration(key="GOOGLE_MCP_X_API_KEY", value="[gl-connectors-x-api-key]"), 73|] 74| 75|# Initialize digital employee 76|digital_employee = DigitalEmployee(identity=identity, configurations=configurations, mcps=[google_mail_mcp]) 77| 78| 79|{% endcode %} 80| 81|### Run the Digital Employee Locally 82| 83|{% code lineNumbers="true" %} 84| 85|python 86|# Run the digital employee locally using a prompt 87|result = digital_employee.run( 88| message="Send a welcome email to [your-email] welcoming them to the team. Include a warm greeting, mention that you're excited to have them on board, and let them know you're here to help with any questions.", 89| local=True 90|) 91|print(result) 92| 93| 94|{% endcode %} 95| 96|### Run the Digital Employee in Remote AIP Server 97| 98|{% code lineNumbers="true" %} 99| 100|python 101|# Deploy the digital employee to AIP server 102|digital_employee.deploy() 103| 104|# Run the deployed digital employee using a prompt 105|result = digital_employee.run(message="Send a welcome email to [your-email] welcoming them to the team. Include a warm greeting, mention that you're excited to have them on board, and let them know you're here to help with any questions.") 106|print(result) 107| 108| 109|{% endcode %} 110| 111|{% hint style="info" %} 112|Before running the sample code, replace the following placeholders: 113| 114|1. Replace [your-email] with your email address. 115|2. Replace [gl-connectors-x-api-key] with x-api-key from GL Connectors. See below for one way to do it. 116|3. (Optional) Replace GOOGLE_MAIL_MCP_URL if you are using a different GL Connectors server instance. 117| 118|
119| 120|🔑 Get GL Connectors x-api-key 121| 122|1. Open https://api.bosa.id/console, then sign in. 123|2. In the Credentials section, expand the x-api-key panel and click Copy combined value button. Paste this value to replace [gl-connectors-x-api-key] . 124| 125| 126| 127|3. If your Gmail account has not been integrated yet, continue with the steps below. 128|4. Under Available Modules section, find the Google_mail integration and click Add New Integration button. 129| 130| 131| 132|5. An authorization URL will appear. Click or copy the URL, then authenticate using your Gmail account. 133| 134| 135| 136|6. Below is an example of a successfully integrated Gmail account. 137| 138| 139| 140|
141|{% endhint %} 142| 143| 144|--- 145| 146|# Agent Instructions 147|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 148| 149|## Querying This Documentation 150|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 151| 152|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 153| 154| 155|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/getting-started-example.md?ask=<question>&goal=<endgoal> 156| 157| 158|ask is the immediate question: it should be specific, self-contained, and written in natural language. 159|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 160| 161|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 162| 163|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 164|


install and configure

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Install and Configure 4| 5|To install the digital employee core package: 6| 7|{% tabs %} 8|{% tab title="pip" %} 9| 10|console 11|pip install digital-employee-core 12| 13| 14|{% endtab %} 15| 16|{% tab title="poetry" %} 17| 18|console 19|poetry add digital-employee-core 20| 21| 22|{% endtab %} 23| 24|{% tab title="uv" %} 25| 26|console 27|uv add digital-employee-core 28| 29| 30|{% endtab %} 31|{% endtabs %} 32| 33|Please ensure you have installed pip, poetry, or uv before installing the digital employee core package. 34| 35|{% hint style="info" %} 36|You can check the PyPI resource: Digital Employee Core PyPI. 37|{% endhint %} 38| 39| 40|--- 41| 42|# Agent Instructions 43|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 44| 45|## Querying This Documentation 46|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 47| 48|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 49| 50| 51|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/install-and-configure.md?ask=<question>&goal=<endgoal> 52| 53| 54|ask is the immediate question: it should be specific, self-contained, and written in natural language. 55|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 56| 57|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 58| 59|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 60|


multi tenant

1|> For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown. 2| 3|# Multi-tenant 4| 5|To support multi-tenancy, we created one digital employee per each tenant and can customize the prompt configuration, tool configuration, and MCP configuration at creation or runtime from each tenant. This approach allows us to make our digital employee generic. 6| 7|### Prompt Configuration 8| 9|Prompt configuration means we can configure the placeholders in the agent prompt (instruction), because sometimes we need to add placeholders to our prompt. 10| 11|Here is an example of a prompt (instruction) with placeholders: 12| 13| 14|**A3.2.6 Find matched experience** 15|- Check if detected_sister_companies list is not empty. 16|- If there is at least one match in detected_sister_companies: 17| - **A3.2.6.1** Send confirmation email (HTML) via MCP Gmail: 18| - Use `google_mail_send_email` tool 19| - To: candidate email; CC: {sister_company_email_cc}// Some code 20| 21| 22|{sister_company_email_cc} is the placeholder that needs to be replaced at runtime. 23| 24|### Tool Configuration 25| 26|Tool configuration is the configuration for the tool that will be consumed by the agent. Agent tools need an input to run the tool. For example, the audio_transcription tool needs a Prosa API key. In this case, we can configure which API key we will use for a specific tenant. 27| 28|### MCP Configuration 29| 30|MCP configuration is similar to tool configuration, but this works for MCP. For example, MCP Google Mail needs a BOSA API key to be able to send emails to specific recipients. We can configure that key for a specific tenant. 31| 32| 33|--- 34| 35|# Agent Instructions 36|This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. 37| 38|## Querying This Documentation 39|If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. 40| 41|Perform an HTTP GET request on the current page URL with the ask query parameter, and the optional goal query parameter: 42| 43| 44|GET https://gdplabs.gitbook.io/catapa/developer-documentation/digital-employee/multi-tenant.md?ask=<question>&goal=<endgoal> 45| 46| 47|ask is the immediate question: it should be specific, self-contained, and written in natural language. 48|goal is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. 49| 50|The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. 51| 52|Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. 53|


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment