Agent Configuration

To allow your agent to be configurable in Open Agent Platform, you must set custom configuration metadata on your agent’s configurable fields. There are currently three types of configurable fields:

  1. General Agent Config: This consists of general configuration settings like the model name, system prompt, temperature, etc. These are where essentially all of your custom configurable fields should go.
  2. MCP Tools Config: This is the config which defines the MCP server and tools to give your agent access to.
  3. RAG Config: This is the config which defines the RAG server, and collection name to give your agent access to.

This section assumes you have a basic understanding of configurable fields in LangGraph. If you do not, read the LangGraph documentation (Python, TypeScript) for more information.

General Agent Config

By default, Open Agent Platform will show all fields listed in your configurable object as configurable in the UI. Each field will be configurable via a simple text input. To add more complex configurable field types (e.g boolean, dropdown, slider, etc), you should add a x_oap_ui_config object to metadata on the field.

Inside this object is where you define the custom UI config for that specific field. The available options are:

export type ConfigurableFieldUIType =
  | "text"
  | "textarea"
  | "number"
  | "boolean"
  | "slider"
  | "select"
  | "json";

/**
 * The type interface for options in a select field.
 */
export interface ConfigurableFieldOption {
  label: string;
  value: string;
}

/**
 * The UI configuration for a field in the configurable object.
 */
export type ConfigurableFieldUIMetadata = {
  /**
   * The label of the field. This will be what is rendered in the UI.
   */
  label: string;
  /**
   * The default value to render in the UI component.
   *
   * @default undefined
   */
  default?: unknown;
  /**
   * The type of the field.
   * @default "text"
   */
  type?: ConfigurableFieldUIType;
  /**
   * The description of the field. This will be rendered below the UI component.
   */
  description?: string;
  /**
   * The validator function to validate the field value. This is a string that will be parsed as a function.
   * You can also include a custom error message to show to the user if the validation fails.
   */
  validator?: {
    /**
     * The validator function to validate the field value.
     */
    fn: string;
    /**
     * The error message to show to the user if the validation fails. If not provided, a default error message will be shown.
     */
    message?: string;
  };
  /**
   * The component specific props. This is only used for certain field types.
   * "slider" - will contain min, max, step
   * "select" - will contain options (array of {label: string, value: string})
   */
  componentProps?: {
    [key: string]: unknown;
  };
};

Here’s an example in TypeScript of how to define this configuration:

TypeScript Configurable
import "@langchain/langgraph/zod";
import { z } from "zod";

export const GraphConfiguration = z.object({
  /**
   * The model ID to use for the reflection generation.
   * Should be in the format `provider/model_name`.
   * Defaults to `anthropic/claude-3-7-sonnet-latest`.
   */
  modelName: z
    .string()
    .optional()
    .langgraph.metadata({
      x_oap_ui_config: {
        type: "select",
        default: "anthropic/claude-3-7-sonnet-latest",
        description: "The model to use in all generations",
        options: [
          {
            label: "Claude 3.7 Sonnet",
            value: "anthropic/claude-3-7-sonnet-latest",
          },
          {
            label: "Claude 3.5 Sonnet",
            value: "anthropic/claude-3-5-sonnet-latest",
          },
          {
            label: "GPT 4o",
            value: "openai/gpt-4o",
          },
          {
            label: "GPT 4.1",
            value: "openai/gpt-4.1",
          },
          {
            label: "o3",
            value: "openai/o3",
          },
          {
            label: "o3 mini",
            value: "openai/o3-mini",
          },
          {
            label: "o4",
            value: "openai/o4",
          },
        ],
      },
    }),
  /**
   * The temperature to use for the reflection generation.
   * Defaults to `0.7`.
   */
  temperature: z
    .number()
    .optional()
    .langgraph.metadata({
      x_oap_ui_config: {
        type: "slider",
        default: 0.7,
        min: 0,
        max: 2,
        step: 0.1,
        description: "Controls randomness (0 = deterministic, 2 = creative)",
      },
    }),
  /**
   * The maximum number of tokens to generate.
   * Defaults to `1000`.
   */
  maxTokens: z
    .number()
    .optional()
    .langgraph.metadata({
      x_oap_ui_config: {
        type: "number",
        default: 4000,
        min: 1,
        description: "The maximum number of tokens to generate",
      },
    }),
  systemPrompt: z
    .string()
    .optional()
    .langgraph.metadata({
      x_oap_ui_config: {
        type: "textarea",
        placeholder: "Enter a system prompt...",
        description: "The system prompt to use in all generations",
      },
    }),
});

// ENSURE YOU PASS THE GRAPH CONFIGURABLE SCHEMA TO THE StateGraph:
const workflow = new StateGraph(MyStateSchema, GraphConfiguration)

And in Python, this would look like:

Python Configurable
from pydantic import BaseModel, Field
from typing import Optional

class GraphConfigPydantic(BaseModel):
    model_name: Optional[str] = Field(
        default="anthropic:claude-3-7-sonnet-latest",
        metadata={
            "x_oap_ui_config": {
                "type": "select",
                "default": "anthropic:claude-3-7-sonnet-latest",
                "description": "The model to use in all generations",
                "options": [
                    {
                        "label": "Claude 3.7 Sonnet",
                        "value": "anthropic:claude-3-7-sonnet-latest",
                    },
                    {
                        "label": "Claude 3.5 Sonnet",
                        "value": "anthropic:claude-3-5-sonnet-latest",
                    },
                    {"label": "GPT 4o", "value": "openai:gpt-4o"},
                    {"label": "GPT 4o mini", "value": "openai:gpt-4o-mini"},
                    {"label": "GPT 4.1", "value": "openai:gpt-4.1"},
                ],
            }
        }
    )
    temperature: Optional[float] = Field(
        default=0.7,
        metadata={
            "x_oap_ui_config": {
                "type": "slider",
                "default": 0.7,
                "min": 0,
                "max": 2,
                "step": 0.1,
                "description": "Controls randomness (0 = deterministic, 2 = creative)",
            }
        }
    )
    max_tokens: Optional[int] = Field(
        default=4000,
        metadata={
            "x_oap_ui_config": {
                "type": "number",
                "default": 4000,
                "min": 1,
                "description": "The maximum number of tokens to generate",
            }
        }
    )
    system_prompt: Optional[str] = Field(
        default=None,
        metadata={
            "x_oap_ui_config": {
                "type": "textarea",
                "placeholder": "Enter a system prompt...",
                "description": "The system prompt to use in all generations",
            }
        }
    )

# ENSURE YOU PASS THE GRAPH CONFIGURABLE SCHEMA TO THE StateGraph:
workflow = StateGraph(State, config_schema=GraphConfigPydantic)

MCP Tools Config

To allow an agent to be configurable with MCP tools in Open Agent Platform, you must set a specific x_oap_config_type metadata field on the configurable field. This field should be set to oap_mcp_tools_config. You only need to set this on a single field in your configurable object. Optionally, you can provide a default value for this field, which will be used when the user is creating a new agent.

Here’s an example in TypeScript:

TypeScript Configurable
export const MCPConfig = z.object({
  /**
   * The MCP server URL.
   */
  url: z.string(),
  /**
   * The list of tools to provide to the LLM.
   */
  tools: z.array(z.string()),
});

export const GraphConfiguration = z.object({
  /**
   * MCP configuration for tool selection. The key (in this case it's `mcpConfig`)
   * can be any value you want.
   */
  mcpConfig: z
    .lazy(() => MCPConfig)
    .optional()
    .langgraph.metadata({
      x_oap_ui_config: {
        // Ensure the type is `mcp`
        type: "mcp",
        // Add custom tools to default to here:
        // default: {
        //   tools: ["Math_Divide", "Math_Mod"]
        // }
      },
    }),
});

And in Python:

Python Configurable
class MCPConfig(BaseModel):
    url: Optional[str] = Field(
        default=None,
        optional=True,
    )
    """The URL of the MCP server"""
    tools: Optional[List[str]] = Field(
        default=None,
        optional=True,
    )
    """The tools to make available to the LLM"""


class GraphConfigPydantic(BaseModel):
    # The key (in this case it's `mcp_config`)
    # can be any value you want.
    mcp_config: Optional[MCPConfig] = Field(
        default=None,
        metadata={
            "x_oap_ui_config": {
                # Ensure the type is `mcp`
                "type": "mcp",
                # Here is where you would set the default tools.
                # "default": {
                #     "tools": ["Math_Divide", "Math_Mod"]
                # }
            }
        }
    )

RAG Config

Configuring RAG is similar to MCP tools. You need to set a specific x_oap_config_type metadata field on the configurable field. This field should be set to oap_rag_config. You only need to set this on a single field in your configurable object.

Here’s an example in TypeScript:

TypeScript Configurable
export const RAGConfig = z.object({
  /**
   * The LangConnect RAG server URL.
   */
  rag_url: z.string(),
  /**
   * The collections to use for RAG. Will be an
   * array of collection IDs
   */
  collections: z.string().array(),
});

export const GraphConfiguration = z.object({
  /**
   * LangConnect RAG configuration. The key (in this case it's `rag`)
   * can be any value you want.
   */
  rag: z
    .lazy(() => RAGConfig)
    .optional()
    .langgraph.metadata({
      x_oap_ui_config: {
        // Ensure the type is `rag`
        type: "rag",
        // Here is where you would set the default collection. Use collection IDs
        // default: {
        //   collections: [
        //     "fd4fac19-886c-4ac8-8a59-fff37d2b847f",
        //     "659abb76-fdeb-428a-ac8f-03b111183e25",
        //   ]
        // }
      },
    }),
});

And in Python:

Python Configurable
class RagConfig(BaseModel):
    rag_url: Optional[str] = None
    """The URL of the rag server"""
    collections: Optional[List[str]] = None
    """The collections to use for rag. Will be a list of collection IDs"""


class GraphConfigPydantic(BaseModel):
    # Once again, the key (in this case it's `rag`)
    # can be any value you want.
    rag: Optional[RagConfig] = Field(
        default=None,
        optional=True,
        metadata={
            "x_oap_ui_config": {
                # Ensure the type is `rag`
                "type": "rag",
                # Here is where you would set the default collection. Use collection IDs
                # "default": {
                #     "collections": [
                #         "fd4fac19-886c-4ac8-8a59-fff37d2b847f",
                #         "659abb76-fdeb-428a-ac8f-03b111183e25",
                #     ]
                # },
            }
        }
    )

Troubleshooting

If your configurable fields aren’t showing up correctly in the OAP UI, check the following:

  1. Make sure you’ve set the correct metadata fields on your configurable fields.
  2. Ensure your configurable field schema matches the expected schema.
  3. For select fields, make sure the options are formatted correctly.
  4. For validator functions, ensure they’re valid JavaScript functions.
  5. If it’s still not working, confirm your x_oap_ui_config metadata has the proper fields set.