Skip to content

Configuration & Template Rendering

Open Ticket AI allows you to create dynamic configurations using YAML plus Jinja2 template expressions like

{ { ... } } without spaces
This lets you reuse values, read environment variables, and reference results from other pipes — all while keeping configuration clean and declarative.

Key Concepts

Injectable Configuration Structure

Both Services and Pipes in Open Ticket AI use the same configuration structure called InjectableConfig. Understanding these three core attributes will help you configure any component in the system.

Configuration Attributes

AttributeTypeDescriptionExample
useTEXTIdentifies which component to create. Format: plugin-name:ComponentName"base:FetchTicketsPipe"
injectsname:value pairsMaps constructor parameter names to service IDs, connecting dependencies to this component{ ticket_system: "otobo_znuny" }
paramsname:value pairsConfiguration parameters specific to this component. Each component type expects different parameters{ limit: 25, queue: "Support" }

Key Differences: Services vs. Pipes

While both use InjectableConfig, they differ in usage:

Services

  • Defined once in the services section
  • Reusable across multiple pipes
  • Must have an id field for reference
  • Usually represent external systems

Example:

yaml
services:
  otobo_znuny:
    use: "otobo-znuny:OTOBOZnunyTicketSystemService"
    injects: { }
    params:
      base_url: "https://helpdesk.example.com"
      password: "{{ get_env('OTOBO_PASSWORD') }}"

Pipes

  • Defined inside pipeline steps
  • Execute actions in sequence
  • Also have an id field to reference results
  • Use services via injects to perform work

Example:

yaml
steps:
  - id: fetch_tickets
    use: "base:FetchTicketsPipe"
    injects:
      ticket_system: "otobo_znuny"
    params:
      ticket_search_criteria:
        limit: 25

Template Rendering

All params and injects values support Jinja2 templating for dynamic configuration:

yaml
params:
  api_key: "{{ get_env('API_KEY') }}"
  queue: "{{ get_pipe_result('classify', 'label') }}"

**Related: ** Template Rendering · Dependency Injection

Config Reference

Here is the Markdown table describing the full config structure clean and ready for your docs.

PathTypeDescriptionExample
otaiOpenTicketAIConfigMain application config root.
otai.api_versionstrAPI version for compatibility."1"
otai.plugins[]list[str]Python module paths of plugins to load."otai_hf_local"
otai.infrastructureInfrastructureConfigInfra-level settings.
otai.infrastructure.loggingLoggingConfigLogging configuration.
otai.infrastructure.logging.levelstrMin log level."INFO"
otai.infrastructure.logging.log_to_fileboolEnable file logging.false
otai.infrastructure.logging.log_file_path`strNone`Log file path when enabled."/var/log/app.log"
otai.infrastructure.logging.log_formatstrPython logging format string."%(asctime)s - %(levelname)s - %(message)s"
otai.infrastructure.logging.date_formatstrDate format for logs."%Y-%m-%d %H:%M:%S"
otai.servicesdict[str, InjectableConfigBase]Map of service-id → DI config.
otai.services.<id>InjectableConfigBaseOne service definition.
otai.services.<id>.usestrPython class path to instantiate."pkg.mod.Class"
otai.services.<id>.injectsdict[str,str]DI bindings: ctor-param → service-id.{ "db": "ticket-db" }
otai.services.<id>.paramsdict[str,Any]Constructor params (templating allowed).{ "url": "{\{ get_env('DB_URL') }\}" }
otai.services.<id>.idstrOptional explicit identifier (when using InjectableConfig)."ticket-db"
otai.orchestratorPipeConfigOrchestrator pipeline root.
otai.orchestrator.idstrPipe identifier (for referencing). (inherits)"root"
otai.orchestrator.usestrPython class path of the Pipe. (inherits)"project.pipes.CompositePipe"
otai.orchestrator.injectsdict[str,str]DI to sub-pipes/services. (inherits){ "step1": "ticket-db" }
otai.orchestrator.paramsdict[str,Any]Pipe parameters (templating allowed). (inherits){}

Tiny example

yaml
otai:
  api_version: "1"
  plugins: [ ]
  infrastructure:
    logging:
      level: "INFO"
  services:
    ticket-db:
      use: "plugin_name:Database"
      params:
        url: "{{ get_env('DB_URL') }}"
  orchestrator:
    id: "root"
    use: "base:CompositePipe"
    injects:
      step1: "ticket-db"
    params: { }

Available helper functions (for config.yml templates)

FunctionParametersReturnsErrors if…
at_pathvalue: Any, path: textNested value at "a.b.c" path; supports dicts + Pydantic modelsInvalid path format
has_failedpipe_id: textTrue if the given pipe result is marked failedUnknown pipe ID
get_pipe_resultpipe_id: text, data_key: text;default = "value"Value stored in previous pipe result under given data_keyPipe or key missing
get_parent_paramparam_key: textInherited parent parameter valueParent missing or key missing
get_envname: textValue of environment variableEnv var missing
fail(none)A “FailMarker” sentinel object to signal explicit failure paths

Usage examples in config.yml

Read an environment variable

yaml
api:
  token: "{{ get_env('API_TOKEN') }}"
  baseUrl: "https://api.example.com"

Consume a previous pipe’s result

yaml
classification:
  label: "{{ get_pipe_result('classify_ticket', 'label') }}"
  confidence: "{{ get_pipe_result('classify_ticket', 'score') }}"
  isLowConfidence: "{{ get_pipe_result('classify_ticket', 'score') < 0.6 }}"

Check if a pipe failed

yaml
shouldRetry: "{{ has_failed('fetch_customer') }}"

Read a parent parameter

yaml
timeoutMs: "{{ get_parent_param('timeoutMs') }}"

Emit an explicit failure marker

yaml
result: "{{ fail() }}"

Access nested data (dict or Pydantic model)

yaml
userCity: "{{ at_path(user, 'address.city') }}"