DSL Configuration¶
Configure agents using Kotlin or YAML DSLs.
Overview¶
Regulus supports two DSL formats for agent configuration:
- Kotlin DSL - Type-safe, IDE support, compile-time validation
- YAML DSL - Human-readable, easy to edit, runtime validation
Kotlin DSL¶
Basic Agent Configuration¶
// src/main/kotlin/com/example/AgentConfig.kt
import com.neullabs.regulus.dsl.agent
import com.neullabs.regulus.dsl.tool
import com.neullabs.regulus.dsl.policy
val customerSupportAgent = agent("customer-support") {
description = "Customer support agent for banking inquiries"
llm {
provider = "gemini"
model = "gemini-2.0-flash"
temperature = 0.7
}
systemPrompt = """
You are a helpful customer support agent for a UK bank.
Be polite, professional, and helpful.
Never share sensitive customer data.
""".trimIndent()
tools {
tool("get_balance") {
description = "Get account balance"
parameter("accountId", String::class) {
description = "The account ID"
required = true
}
handler = { params -> accountService.getBalance(params["accountId"]) }
}
tool("get_transactions") {
description = "Get recent transactions"
parameter("accountId", String::class) { required = true }
parameter("limit", Int::class) { default = 10 }
handler = { params ->
accountService.getTransactions(
params["accountId"],
params["limit"] ?: 10
)
}
}
}
policies {
policy("purpose-code") {
require { context -> context.purposeCode in allowedPurposeCodes }
onViolation { "Invalid purpose code" }
}
policy("consent") {
require { context -> context.hasConsent }
onViolation { "Consent required" }
}
}
privacy {
redact("nino", "sort-code", "account-number")
customPattern("employee-id", "EMP-\\d{6}")
}
observability {
metrics = true
tracing = true
auditLogging = true
}
}
Registering the Agent¶
@Configuration
class AgentConfiguration {
@Bean
fun customerSupport(): Agent {
return customerSupportAgent.build()
}
}
Multi-Agent Configuration¶
val agents = agents {
agent("customer-support") {
description = "Handles customer inquiries"
// ...
}
agent("payment-processor") {
description = "Processes payments"
// ...
}
agent("fraud-detector") {
description = "Detects fraudulent activity"
// ...
}
// Define agent interactions
interactions {
"customer-support" canCall "payment-processor"
"customer-support" canCall "fraud-detector"
}
}
YAML DSL¶
Basic Configuration¶
# src/main/resources/agents/customer-support.yml
agent:
id: customer-support
description: Customer support agent for banking inquiries
llm:
provider: gemini
model: gemini-2.0-flash
temperature: 0.7
max-tokens: 4096
system-prompt: |
You are a helpful customer support agent for a UK bank.
Be polite, professional, and helpful.
Never share sensitive customer data.
tools:
- name: get_balance
description: Get account balance
parameters:
- name: accountId
type: string
required: true
description: The account ID
- name: get_transactions
description: Get recent transactions
parameters:
- name: accountId
type: string
required: true
- name: limit
type: integer
required: false
default: 10
policies:
require-purpose-code: true
require-consent: true
allowed-purpose-codes:
- CUSTOMER_SUPPORT
- ACCOUNT_INQUIRY
privacy:
redaction:
enabled: true
patterns:
- nino
- sort-code
- account-number
custom:
- name: employee-id
pattern: "EMP-\\d{6}"
replacement: "[EMPLOYEE ID REDACTED]"
observability:
metrics: true
tracing: true
audit-logging: true
Loading YAML Configuration¶
@Configuration
public class YamlAgentConfig {
@Bean
public Agent customerSupportAgent(
@Value("classpath:agents/customer-support.yml") Resource config) {
return YamlAgentLoader.load(config);
}
}
Multiple Agents¶
# src/main/resources/agents/agents.yml
agents:
- id: customer-support
description: Handles customer inquiries
llm:
provider: gemini
model: gemini-2.0-flash
system-prompt: |
You are a customer support agent...
- id: payment-processor
description: Processes payments
llm:
provider: gemini
model: gemini-2.0-flash
system-prompt: |
You are a payment processing agent...
interactions:
customer-support:
can-call:
- payment-processor
- fraud-detector
Pipeline Configuration¶
Kotlin Pipeline DSL¶
val supportPipeline = pipeline("support-pipeline") {
// Input preprocessing
stage("preprocess") {
redactPii()
validateInput()
}
// Policy enforcement
stage("policy") {
enforcePolicies()
}
// LLM processing
stage("llm") {
callLlm {
model = "gemini-2.0-flash"
temperature = 0.7
}
}
// Tool execution
stage("tools") {
executeTools()
}
// Output postprocessing
stage("postprocess") {
redactPii()
addDisclosure()
}
// Error handling
onError { error ->
when (error) {
is PolicyViolationException -> fallbackToError(error.message)
is LlmException -> retry(maxAttempts = 3)
else -> escalateToHuman()
}
}
}
YAML Pipeline¶
pipeline:
id: support-pipeline
stages:
- name: preprocess
actions:
- redact-pii
- validate-input
- name: policy
actions:
- enforce-policies
- name: llm
config:
model: gemini-2.0-flash
temperature: 0.7
- name: tools
actions:
- execute-tools
- name: postprocess
actions:
- redact-pii
- add-disclosure
error-handling:
policy-violation:
action: fallback-error
llm-error:
action: retry
max-attempts: 3
default:
action: escalate-human
RAG Configuration¶
Kotlin RAG DSL¶
val ragAgent = agent("knowledge-base") {
description = "Knowledge base agent with RAG"
rag {
vectorStore {
type = "pinecone"
index = "knowledge-base"
namespace = "banking-faqs"
}
embedding {
provider = "openai"
model = "text-embedding-3-small"
}
retrieval {
topK = 5
similarityThreshold = 0.7
reranking = true
}
chunking {
strategy = "semantic"
maxChunkSize = 500
overlap = 50
}
}
systemPrompt = """
Answer questions using the retrieved context.
If the context doesn't contain the answer, say so.
""".trimIndent()
}
YAML RAG¶
agent:
id: knowledge-base
description: Knowledge base agent with RAG
rag:
vector-store:
type: pinecone
index: knowledge-base
namespace: banking-faqs
embedding:
provider: openai
model: text-embedding-3-small
retrieval:
top-k: 5
similarity-threshold: 0.7
reranking: true
chunking:
strategy: semantic
max-chunk-size: 500
overlap: 50
system-prompt: |
Answer questions using the retrieved context.
If the context doesn't contain the answer, say so.
Validation¶
Kotlin DSL Validation¶
val agent = customerSupportAgent.build()
// Validate at build time
agent.validate().let { result ->
if (!result.isValid) {
result.errors.forEach { error ->
logger.error("Validation error: ${error.message}")
}
throw ConfigurationException("Agent configuration invalid")
}
}
YAML Validation¶
@Component
public class YamlValidator {
public ValidationResult validate(Resource yamlResource) {
AgentConfig config = loadConfig(yamlResource);
List<String> errors = new ArrayList<>();
if (config.getAgentId() == null) {
errors.add("Agent ID is required");
}
if (config.getLlm() == null) {
errors.add("LLM configuration is required");
}
// More validations...
return new ValidationResult(errors.isEmpty(), errors);
}
}
Environment Variable Interpolation¶
YAML with Environment Variables¶
agent:
id: customer-support
llm:
provider: ${LLM_PROVIDER:gemini}
model: ${LLM_MODEL:gemini-2.0-flash}
api-keys:
openai: ${OPENAI_API_KEY}
gemini: ${GOOGLE_CLOUD_PROJECT}
Kotlin with Environment Variables¶
val agent = agent("customer-support") {
llm {
provider = env("LLM_PROVIDER", "gemini")
model = env("LLM_MODEL", "gemini-2.0-flash")
}
}
Best Practices¶
- Use Kotlin for complex logic - Type safety catches errors early
- Use YAML for simple configs - Easy to read and modify
- Validate early - Check configuration at startup
- Externalize secrets - Use environment variables
- Version control - Track configuration changes
- Test configurations - Unit test DSL configurations