TruvaG3 Framework Environment Variables Guide
This document provides a comprehensive reference for all environment variables supported by the TruvaG3 framework. Variables are organized by module/functionality with their default values, descriptions, and verification status.
Table of Contents
- Kubernetes Deployment Requirements (Start here for K8s)
- Core Configuration
- HTTP Server Configuration
- CORS Configuration
- Discovery Configuration
- AI Configuration
- AI Provider-Specific Variables
- Telemetry Configuration
- Memory Configuration
- Shared Memory Configuration
- Activity Coordination Configuration
- Logging Configuration
- Development Configuration
- Kubernetes Configuration
- Orchestration Configuration
- LLM Debug Configuration
- Execution Debug Store Configuration
- Human-in-the-Loop (HITL) Configuration
- Async Task Configuration
- Prompt Configuration
- Agent Skills Configuration
- Quick Reference Table
Important Notes
Variable Status Legend:
- Implemented - Read by the documented owning constructor/configuration path (
Getenvor presence-awareLookupEnv); setting it does not automatically wire that feature into an application - Struct Tag Only - Defined in struct tags but NOT currently loaded (requires code changes to work)
- Example Only - Used in example applications, not core framework
Related code-only controls
The following controls have no dedicated environment variable. Use the owning API; setting a similarly named env key does not configure them.
| Behavior | Programmatic control | Default / scope |
|---|---|---|
| Reasoning-as-answer compatibility | ai.WithReasoningContentFallback(bool), ai.WithChainReasoningContentFallback(bool), direct codec ReasoningContentFallback | false; compatible-codec response policy, not a model/token limit |
| Shared-memory lookback | WithMemoryLookback(d) / direct WithEnrichmentLookback(d) | 24h; independent of event retention and digest TTL |
| Event-summary batch size | WithSummarizerMaxStepsPerBatch(n) | 20; excess steps get heuristic fallback |
| Calculated summary tokens per step | WithSummarizerTokensPerStep(n) | Explicit option selects calculated budgeting (floor 300 per call); otherwise 10000 fixed; explicit fixed override wins |
| Failed-input disclosure restriction | FailedOperationViewConfig.InputPolicy | nil permits bounded views; applications can restrict or disable |
| Recording-only request entities | WithBuilderRecordRequestEntityExtractor / direct WithRecordRequestEntityExtractor | unset; enrichment/claim acquisition unchanged |
| Per-acquisition claim expiry | core.InvestigationLeaseRequest.TTL | 0 selects provider default; negative invalid |
The reasoning token multiplier is configurable by environment:
TRUVAG3_AI_REASONING_TOKEN_MULTIPLIER (default 3). A positive
ai.WithReasoningTokenMultiplier(int) or ai.WithChainReasoningTokenMultiplier(int)
overrides it; explicit 1 keeps caps exact. Reviewed-model ceiling checks still
apply. See AI Configuration.
Returned completion provenance, request lifecycle revisions and physical dispatch counts need no new enablement flag. Existing debug-store enablement, access and retention settings still govern persistence. There is no env knob for rewriting provider finish reasons or turning empty completion into success.
Kubernetes Deployment Requirements
This section provides a quick reference for deploying TruvaG3 agents and tools in Kubernetes. Variables are categorized by requirement level to help you configure deployments correctly.
Working Examples: See agent-example/k8-deployment.yaml for a complete agent deployment and tool-example/k8-deployment.yaml for a complete tool deployment.
Required Variables (All Deployments)
These variables are mandatory for proper operation in Kubernetes:
| Variable | Why Required | How to Set |
|---|---|---|
TRUVAG3_AGENT_NAME | Validation fails without it (core/config.go — if c.Name == "" check in Validate) | Static value |
| Redis connection source | Required when discovery is enabled (auto-enabled in K8s): use either standalone REDIS_URL or structured TRUVAG3_REDIS_MODE + TRUVAG3_REDIS_ADDRS | ConfigMap, Secret, or static value as appropriate |
TRUVAG3_K8S_SERVICE_NAME | Critical for service-fronted discovery URL registration | Must match your K8s Service name |
TRUVAG3_K8S_SERVICE_PORT | Service port for discovery URL (default: 80) | Must match your K8s Service port |
Required Variables (via fieldRef)
These are populated automatically by Kubernetes using fieldRef:
| Variable | fieldRef Source | Purpose |
|---|---|---|
TRUVAG3_K8S_NAMESPACE | metadata.namespace | Pod namespace for service URL construction |
TRUVAG3_K8S_POD_IP | status.podIP | Pod IP address for health checks |
TRUVAG3_K8S_NODE_NAME | spec.nodeName | Node placement info for debugging |
Required for AI Agents Only
Tools don't need AI configuration, but agents using AI features require:
| Variable | Purpose |
|---|---|
OPENAI_API_KEY | Or any other AI provider key (see AI Provider-Specific Variables) |
Strongly Recommended
| Variable | Default | Why Recommended |
|---|---|---|
TRUVAG3_DISCOVERY_RETRY | false | Set to true to handle Redis startup race conditions |
TRUVAG3_DISCOVERY_RETRY_INTERVAL | 30s | Background retry interval when Redis unavailable |
TRUVAG3_DEV_MODE | false | Explicitly disable for production |
Auto-Detected (No Need to Set)
| Variable | Auto-Detection |
|---|---|
KUBERNETES_SERVICE_HOST | Set by K8s automatically, triggers K8s mode |
HOSTNAME | Set by K8s to pod name |
TRUVAG3_ADDRESS | Auto-set to 0.0.0.0 in K8s mode |
TRUVAG3_LOG_FORMAT | Auto-set to json in K8s mode |
Minimal Tool Deployment
env:
# REQUIRED - Core Identity
- name: TRUVAG3_AGENT_NAME
value: "weather-tool"
# REQUIRED - Service Discovery
- name: REDIS_URL
value: "redis://redis.truvag3-examples:6379"
# REQUIRED - Service-Fronted Discovery (must match Service definition)
- name: TRUVAG3_K8S_SERVICE_NAME
value: "weather-tool-service"
- name: TRUVAG3_K8S_SERVICE_PORT
value: "80"
# REQUIRED - K8s Metadata (via fieldRef)
- name: TRUVAG3_K8S_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: TRUVAG3_K8S_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: TRUVAG3_K8S_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
# RECOMMENDED - Resilience
- name: TRUVAG3_DISCOVERY_RETRY
value: "true"
- name: TRUVAG3_DISCOVERY_RETRY_INTERVAL
value: "30s"
Minimal Agent Deployment (with AI)
env:
# Same as Tool (above), plus:
# REQUIRED - AI Provider Key
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: ai-provider-keys
key: OPENAI_API_KEY
# OPTIONAL - Telemetry
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://otel-collector.truvag3-examples:4318"
Common Mistakes to Avoid
-
Missing
TRUVAG3_K8S_SERVICE_NAME: Without this, discovery registers the wrong URL and other services can't find your tool/agent. -
Mismatched Service Name/Port: The
TRUVAG3_K8S_SERVICE_NAMEmust exactly match your Kubernetes Service'smetadata.name, andTRUVAG3_K8S_SERVICE_PORTmust match the Service'sport(nottargetPort). -
Combining Redis connection sources: Set exactly one of
REDIS_URL, the structuredTRUVAG3_REDIS_*topology form. The removedTRUVAG3_REDIS_URLalias is rejected. Contradictory forms fail startup rather than using precedence. PreferREDIS_URLfor standalone deployments and structured configuration for Sentinel or cluster. -
Setting
TRUVAG3_ADDRESS: This is auto-detected as0.0.0.0in K8s - no need to set it.
Core Configuration
These variables configure the fundamental settings of a TruvaG3 agent or tool.
The resilience-shaped declarations below are struct tags only, not env
inputs consumed by core.Config.LoadFromEnv. They are listed to avoid confusing
them with the implemented AI and orchestration retry budgets. Configure the
owning component programmatically instead.
| Reserved declaration | Default in core configuration | Status |
|---|---|---|
TRUVAG3_CB_ENABLED | false | Struct Tag Only |
TRUVAG3_CB_THRESHOLD | 5 | Struct Tag Only |
TRUVAG3_CB_TIMEOUT | 30s | Struct Tag Only |
TRUVAG3_CB_HALF_OPEN | 3 | Struct Tag Only |
TRUVAG3_RETRY_MAX_ATTEMPTS | 3 | Struct Tag Only |
TRUVAG3_RETRY_INITIAL_INTERVAL | 1s | Struct Tag Only |
TRUVAG3_RETRY_MAX_INTERVAL | 30s | Struct Tag Only |
TRUVAG3_RETRY_MULTIPLIER | 2.0 | Struct Tag Only |
TRUVAG3_TIMEOUT_DEFAULT | 30s | Struct Tag Only |
TRUVAG3_TIMEOUT_MAX | 5m | Struct Tag Only |
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_AGENT_NAME | truvag3-agent | Implemented | Name of the agent | core/config.go |
TRUVAG3_AGENT_ID | (auto-generated) | Implemented | Unique identifier for the agent instance | core/config.go |
TRUVAG3_PORT | 8080 | Implemented | HTTP server port | core/config.go |
TRUVAG3_ADDRESS | localhost (local) / 0.0.0.0 (K8s) | Implemented | Bind address for the HTTP server | core/config.go |
TRUVAG3_NAMESPACE | default | Implemented | Logical namespace for multi-tenancy | core/config.go |
Example
export TRUVAG3_AGENT_NAME="weather-tool"
export TRUVAG3_PORT=8085
export TRUVAG3_NAMESPACE="production"
HTTP Server Configuration
Configure HTTP server timeouts and health check settings.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_HTTP_READ_TIMEOUT | 300s in DefaultConfig | Implemented | Maximum duration for reading the entire request | core/config.go |
TRUVAG3_HTTP_WRITE_TIMEOUT | 35m | Implemented | Maximum duration for writing the response | core/config.go |
TRUVAG3_HTTP_READ_HEADER_TIMEOUT | 10s | Struct Tag Only | Maximum duration for reading request headers | core/config.go |
TRUVAG3_HTTP_IDLE_TIMEOUT | 120s | Struct Tag Only | Maximum duration to wait for the next request | core/config.go |
TRUVAG3_HTTP_MAX_HEADER_BYTES | 1048576 (1MB) | Struct Tag Only | Maximum size of request headers | core/config.go |
TRUVAG3_HTTP_SHUTDOWN_TIMEOUT | 10s | Implemented | Joined HTTP shutdown budget for built-in agents/tools. Present values must be positive Go durations; empty, malformed and non-positive values fail loading. Explicit code configuration overrides valid env values; zero typed value selects 10s. This does not forcibly terminate active handlers or hijacked connections. | core/config.go |
TRUVAG3_HTTP_HEALTH_CHECK | true | Struct Tag Only | Enable health check endpoint | core/config.go |
TRUVAG3_HTTP_HEALTH_PATH | /health | Struct Tag Only | Path for health check endpoint | core/config.go |
Example
# Explicit overrides; the write timeout below is shorter than the 35m default
export TRUVAG3_HTTP_READ_TIMEOUT="5m"
export TRUVAG3_HTTP_WRITE_TIMEOUT="5m"
CORS Configuration
Configure Cross-Origin Resource Sharing settings.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_CORS_ENABLED | false | Implemented | Enable CORS support | core/config.go |
TRUVAG3_CORS_ORIGINS | (none) | Implemented | Comma-separated list of allowed origins | core/config.go |
TRUVAG3_CORS_METHODS | GET,POST,PUT,DELETE,OPTIONS | Implemented | Allowed HTTP methods | core/config.go |
TRUVAG3_CORS_HEADERS | Content-Type,Authorization | Implemented | Allowed request headers | core/config.go |
TRUVAG3_CORS_CREDENTIALS | false | Implemented | Allow credentials (cookies, auth headers) | core/config.go |
TRUVAG3_CORS_EXPOSED_HEADERS | (none) | Struct Tag Only | Headers exposed to the browser | core/config.go |
TRUVAG3_CORS_MAX_AGE | 86400 (24h) | Struct Tag Only | Preflight cache duration in seconds | core/config.go |
Example
export TRUVAG3_CORS_ENABLED=true
export TRUVAG3_CORS_ORIGINS="https://app.example.com,https://*.example.com"
export TRUVAG3_CORS_CREDENTIALS=true
Discovery Configuration
Configure service discovery for agent/tool registration and lookup.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_DISCOVERY_ENABLED | false (local) / true (K8s) | Implemented | Enable service discovery | core/config.go |
TRUVAG3_DISCOVERY_PROVIDER | redis | Implemented | Discovery backend provider | core/config.go |
TRUVAG3_REDIS_NAMESPACE | default | Implemented | Validated deployment segment shared by every versioned DB-0 key (1–128 ASCII letters, digits, ., _, or -) | core/redis_keyspace.go |
REDIS_URL | redis://localhost:6379 | Implemented | Standard DB-0 standalone Redis/Valkey URL shorthand | core/redis_connection.go |
TRUVAG3_REDIS_MODE | standalone | Implemented | Structured topology: standalone, sentinel, or cluster | core/redis_connection.go |
TRUVAG3_REDIS_ADDRS | localhost:6379 | Implemented | Comma-separated standalone address, Sentinel addresses, or cluster seed addresses. Required with structured mode | core/redis_connection.go |
TRUVAG3_REDIS_MASTER_NAME | — | Implemented | Sentinel master name; required only in Sentinel mode | core/redis_connection.go |
TRUVAG3_REDIS_USERNAME | — | Implemented | Data-node ACL username | core/redis_connection.go |
TRUVAG3_REDIS_PASSWORD | — | Implemented | Data-node password; supply via a Secret | core/redis_connection.go |
TRUVAG3_REDIS_SENTINEL_USERNAME | — | Implemented | Sentinel ACL username | core/redis_connection.go |
TRUVAG3_REDIS_SENTINEL_PASSWORD | — | Implemented | Sentinel password; supply via a Secret | core/redis_connection.go |
TRUVAG3_REDIS_DB | 0 | Implemented | Shared logical DB; only 0 is accepted in standalone, Sentinel, and cluster mode | core/redis_connection.go |
TRUVAG3_REDIS_TLS_ENABLED | false | Implemented | Enables TLS with a minimum of TLS 1.2 | core/redis_connection.go |
TRUVAG3_REDIS_TLS_SERVER_NAME | — | Implemented | TLS server name; requires TLS enabled | core/redis_connection.go |
TRUVAG3_REDIS_CA_FILE | — | Implemented | Mounted PEM CA file, read once at startup; requires TLS enabled | core/redis_connection.go |
TRUVAG3_REDIS_POOL_SIZE | 10 | Implemented | Maximum connections per node (1–10000) | core/redis_connection.go |
TRUVAG3_REDIS_MIN_IDLE_CONNS | 5 | Implemented | Minimum idle connections per node (0 through pool size) | core/redis_connection.go |
TRUVAG3_REDIS_DIAL_TIMEOUT | 5s | Implemented | Positive connection timeout, at most 10m | core/redis_connection.go |
TRUVAG3_REDIS_READ_TIMEOUT | 3s | Implemented | Read timeout, at most 10m; exact go-redis sentinels -1ns and -2ns are preserved | core/redis_connection.go |
TRUVAG3_REDIS_WRITE_TIMEOUT | 3s | Implemented | Write timeout, at most 10m; exact go-redis sentinels -1ns and -2ns are preserved | core/redis_connection.go |
TRUVAG3_REDIS_MAX_RETRIES | 3 | Implemented | Per-command retry count (-1 disables; maximum 100) | core/redis_connection.go |
TRUVAG3_DISCOVERY_CACHE | true | Implemented | Enable local caching of discovery results | core/config.go |
TRUVAG3_DISCOVERY_RETRY | false | Implemented | Enable background retry on initial connection failure | core/config.go |
TRUVAG3_DISCOVERY_RETRY_INTERVAL | 30s | Implemented | Starting retry interval (increases exponentially) | core/config.go |
TRUVAG3_DISCOVERY_TTL | 30s | Implemented | Registration TTL for service keys (min 5s) | core/config.go |
TRUVAG3_DISCOVERY_HEARTBEAT | 0 (= TTL/2) | Implemented | Heartbeat interval for registration refresh (min 2s) | core/config.go |
TRUVAG3_DISCOVERY_CACHE_TTL | 5m | Struct Tag Only | Cache time-to-live | core/config.go |
Variable Precedence
The development-stage cleanup removed TRUVAG3_REDIS_URL, role-specific
TRUVAG3_*_REDIS_DB routing variables, and raw Redis HITL/LLM-debug prefixes.
A non-empty removed setting fails construction for its selected backend role;
an unselected role's settings are ignored. Empty values count as absent.
Use TRUVAG3_REDIS_NAMESPACE and typed keyspace options for isolation.
TRUVAG3_EXECUTION_DEBUG_KEY_PREFIX applies only to the generic storage
adapter, not Redis.
Redis connection selection is:
- Complete explicit Go configuration (
WithRedisConnectionor a direct constructor), without merging environment connection fields. - Exactly one environment form:
REDIS_URL, structuredTRUVAG3_REDIS_MODE+ related connection fields. - Local DB-0 standalone default.
Operational pool, timeout, and retry variables may accompany either standard
environment form. REDIS_URL and structured topology fields are different,
mutually exclusive representations; combining them fails validation. Cluster
mode, standalone, and Sentinel all require DB 0. A single seed address is valid when cluster mode is
explicit—the framework never infers topology from address count.
Example
export REDIS_URL="redis://redis:6379"
export TRUVAG3_DISCOVERY_CACHE=true
export TRUVAG3_DISCOVERY_RETRY=true
export TRUVAG3_DISCOVERY_RETRY_INTERVAL="30s"
export TRUVAG3_DISCOVERY_TTL="60s"
export TRUVAG3_DISCOVERY_HEARTBEAT="20s"
Sentinel example:
export TRUVAG3_REDIS_MODE="sentinel"
export TRUVAG3_REDIS_ADDRS="sentinel-a:26379,sentinel-b:26379,sentinel-c:26379"
export TRUVAG3_REDIS_MASTER_NAME="mymaster"
export TRUVAG3_REDIS_PASSWORD="${REDIS_DATA_PASSWORD}"
export TRUVAG3_REDIS_SENTINEL_PASSWORD="${REDIS_SENTINEL_PASSWORD}"
Cluster/Valkey cluster example:
export TRUVAG3_REDIS_MODE="cluster"
export TRUVAG3_REDIS_ADDRS="cache-a:6379,cache-b:6379,cache-c:6379"
export TRUVAG3_REDIS_DB="0"
export TRUVAG3_REDIS_POOL_SIZE="20" # per cluster node
Code equivalent (functional options override env vars):
core.NewConfig(
core.WithRedisDiscovery("redis://redis:6379"),
core.WithDiscoveryCacheEnabled(true),
core.WithDiscoveryTTL(60 * time.Second),
core.WithHeartbeatInterval(20 * time.Second),
)
AI Configuration
Configure AI client settings for LLM integration.
This table distinguishes the core configuration object from direct provider
construction. core.Config.LoadFromEnv reads rows marked Implemented into
core.Config.AI; it does not automatically pass those values to
ai.NewClient or ai.NewRequestClient. Applications using the direct
constructors must pass the corresponding ai.With* options. Rows marked
Struct Tag Only are metadata declarations that LoadFromEnv does not
currently read. Provider-specific variables in the next section and
TRUVAG3_AI_RETRY_ATTEMPTS, TRUVAG3_AI_RETRY_DELAY,
TRUVAG3_AI_SSE_EVENT_MAX_BYTES, and TRUVAG3_AI_REASONING_TOKEN_MULTIPLIER
are read directly by the ai module as
documented.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_AI_ENABLED | false | Implemented | Enable AI features | core/config.go |
TRUVAG3_AI_API_KEY | (none) | Implemented | API key for the provider (auto-enables AI) | core/config.go |
OPENAI_API_KEY | (fallback) | Implemented | Fallback API key (auto-enables AI) | core/config.go |
TRUVAG3_AI_MODEL | gpt-4 | Implemented | Model name to use | core/config.go |
TRUVAG3_AI_BASE_URL | Provider-specific | Implemented | Custom base URL for API calls | core/config.go |
TRUVAG3_AI_REASONING_TOKEN_MULTIPLIER | 3 | Implemented | Reasoning headroom on reviewed scaling profiles. Positive code values win; code zero is unset. Empty, malformed, non-positive or overflowing environment values and negative code values fail construction. Explicit 1 keeps budgets exact. Active scaling binds the resolved multiplier into AI-output cache identity. | ai/reasoning_budget.go |
TRUVAG3_AI_PROVIDER | openai | Struct Tag Only | AI provider | core/config.go |
TRUVAG3_AI_TEMPERATURE | 0.7 | Struct Tag Only | Sampling temperature declaration; permitted values and field support are provider/model-specific | core/config.go |
TRUVAG3_AI_MAX_TOKENS | 2000 | Struct Tag Only | Maximum tokens in response | core/config.go |
TRUVAG3_AI_TIMEOUT | 5m; explicit standalone Bedrock 60m | Implemented in AI constructors | Read by ai.NewClient, ai.NewRequestClient, ai.NewChainClient and managed ProviderEntry construction, not core.Config.LoadFromEnv or direct provider constructors/factory calls. Positive code > environment > applicable default. A present value must be a positive Go duration (for example 12m); empty, malformed, zero, negative and overflowing values fail construction even with a code override. Nonpositive code means unset. Injected clients remain caller-owned; earlier caller/phase/HTTP-client deadlines still win. | ai/request_timeout.go, ai/client.go |
TRUVAG3_AI_RETRY_ATTEMPTS | 3 for independently constructed clients and heterogeneous ProviderEntry; 0 per provider in legacy NewChainClient | Implemented | Per-provider retry budget. ai/providers/openai and its registered aliases share this one budget across transport/HTTP and eligible decoded/in-body failures; direct Azure remains transport-only. Retry permission comes from the adapter classifier, and Retry-After can affect delay without adding attempts. Precedence is explicit WithMaxRetries(n) / WithChainMaxRetries(n) > positive environment value > constructor-specific default. NewClient, NewRequestClient, and each NewChain ProviderEntry default to 3. Legacy NewChainClient defaults each provider to 0 so provider retries do not multiply ordered failover attempts. ClientEntry is caller-owned. Zero, negative, and non-integer environment values are rejected and fall through; use an explicit programmatic 0 to disable retries. | ai/client.go, ai/chain_client.go, ai/chain_entries.go |
TRUVAG3_AI_SSE_EVENT_MAX_BYTES | 1048576 (1 MiB) | Implemented | Maximum bytes in one OpenAI-compatible server-sent event. A positive AIConfig.SSEEventMaxBytes wins; invalid, zero, and negative environment values fall back to 1 MiB. The ceiling is per event, not per response. | ai/client.go, ai/providerkit/openaiwire/sse.go |
TRUVAG3_AI_RETRY_DELAY | 1s | Implemented | Initial exponential delay between provider attempts, including eligible decoded retries in adopting adapters. A positive AIConfig.RetryDelay wins over a positive Go-duration environment value, then the one-second default. Invalid, zero, and negative environment values fall back safely. For an eligible HTTP 429/503 or decoded semantic 429/503, a valid response Retry-After seconds/date value is honored only when it is greater than exponential backoff. It does not grant retry permission or add attempts. Every retry wait ends at the earlier caller deadline or an absolute wait cap: the positive HTTP-client timeout, or the 180-second framework fallback when that timeout is disabled. The cap applies to the wait timer rather than the transport context, so it does not make a successful streaming response body unreadable. | ai/client.go, ai/providers/base.go |
Example
export TRUVAG3_AI_ENABLED=true
export TRUVAG3_AI_MODEL="smart"
export TRUVAG3_AI_BASE_URL="https://api.openai.com/v1"
Reaching the provider retry-wait cap returns context.DeadlineExceeded; it
does not shorten a required cooldown and then resend early. A caller deadline
or cancellation also stops the wait without another provider attempt.
AI Provider-Specific Variables
The framework supports multiple AI providers with automatic detection based on
available API keys and provider-specific indicators. Detection considers only
factories linked into the application; import each selected provider package,
normally as a blank import. Bedrock must also be compiled with -tags bedrock.
See the
AI Providers Setup Guide
for the registration pattern.
OpenAI (Priority: 1000)
For the ai/providers/openai implementation and its registered aliases
(including OpenRouter), the existing provider retry settings also cover eligible
decoded/in-body failures, sharing one budget with HTTP/transport errors. Direct
Azure OpenAI adapters retain transport-only retries. These settings do not
configure orchestration tool-step retries or outer-chain
failover. Adapters opting into ExecuteWithRetryDecoded own the retry decision
for actual HTTP 429/5xx as well. OpenRouter uses its conservative typed/status
classifier; no new retry env setting enables rejected error types. Eligible
decoded semantic 429/503 can use the existing Retry-After wait handling.
The same configured budget covers eligible OpenRouter HTTP/in-body 408 timeouts.
Known terminal and unknown nonempty types remain conservative, and other
compatible aliases keep their existing 408 behavior. Zero chain retries still
permit no same-provider retry; another entry is needed for failover. Caller
cancellation, caller/provider-call deadlines and delivered stream output stop recovery.
A provider's own TRUVAG3_AI_TIMEOUT expiration stops chain recovery even if the
outer caller remains active: returned deadline identity is authoritative. A
provider-returned 408 while the attempt context is active remains eligible. No new
environment setting or timeout/default change accompanies this classification.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
OPENAI_API_KEY | (none) | Implemented | OpenAI API key | ai/providers/openai/factory.go |
OPENAI_BASE_URL | https://api.openai.com/v1 | Implemented | OpenAI API base URL | ai/providers/openai/factory.go |
Anthropic Claude (Priority: 900)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
ANTHROPIC_API_KEY | (none) | Implemented | Anthropic API key | ai/providers/anthropic/factory.go |
ANTHROPIC_BASE_URL | https://api.anthropic.com/v1 | Implemented | Anthropic API base URL | ai/providers/anthropic/client.go, ai/providers/anthropic/factory.go |
OpenRouter (Priority: 850)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
OPENROUTER_API_KEY | (none) | Implemented | OpenRouter API key; activates openai.openrouter auto-detection | ai/providers/openai/factory.go |
OPENROUTER_BASE_URL | https://openrouter.ai/api/v1 | Implemented | OpenRouter API base URL | ai/providers/openai/factory.go |
Built-in aliases are default=smart=openrouter/auto,
fast=openai/gpt-6-luna, and code=openrouter/pareto-code. Every alias can
be overridden independently without code changes:
OPENROUTER_API_KEY=...
TRUVAG3_OPENROUTER_MODEL_DEFAULT=openai/gpt-5.6-sol
TRUVAG3_OPENROUTER_MODEL_SMART=moonshotai/kimi-k3
TRUVAG3_OPENROUTER_MODEL_FAST=google/gemini-2.5-flash
TRUVAG3_OPENROUTER_MODEL_CODE=moonshotai/kimi-k3
_DEFAULT applies when a call leaves its model unspecified or selects
default; _SMART, _FAST, and _CODE apply only when that alias is
selected. A per-request exact model wins over the constructor default. See the
OpenRouter configuration examples
for programmatic and request-aware forms.
Repository example setup scripts also accept the shell-only selector below for
an isolated live test when .env contains multiple provider keys:
TRUVAG3_SETUP_AI_PROVIDER=together ./setup.sh rollout
The shared setup helper excludes this selector from application ConfigMaps. Without it, all configured provider keys are deployed for normal failover.
The framework intentionally has no built-in free alias at this time: the
protected privacy probe failed for the tested free routes. Exact :free IDs or
TRUVAG3_OPENROUTER_MODEL_FREE remain experimental pass-through options, and
must support the framework's mandatory data_collection=deny and zdr=true
request constraints. Their availability and quotas follow OpenRouter's
current free-model and account limits.
Google Gemini (Priority: 800)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
GEMINI_API_KEY | (none) | Implemented | Google Gemini API key | ai/providers/gemini/factory.go |
GOOGLE_API_KEY | (fallback) | Implemented | Alternative Google API key (either activates Gemini) | ai/providers/gemini/factory.go |
GEMINI_BASE_URL | https://generativelanguage.googleapis.com/v1beta | Implemented | Gemini API base URL | ai/providers/gemini/client.go, ai/providers/gemini/factory.go |
Groq (Priority: 700)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
GROQ_API_KEY | (none) | Implemented | Groq API key | ai/providers/openai/factory.go |
GROQ_BASE_URL | https://api.groq.com/openai/v1 | Implemented | Groq API base URL | ai/providers/openai/factory.go |
DeepSeek (Priority: 600)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
DEEPSEEK_API_KEY | (none) | Implemented | DeepSeek API key | ai/providers/openai/factory.go |
DEEPSEEK_BASE_URL | https://api.deepseek.com | Implemented | DeepSeek API base URL | ai/providers/openai/factory.go |
xAI Grok (Priority: 500)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
XAI_API_KEY | (none) | Implemented | xAI API key | ai/providers/openai/factory.go |
XAI_BASE_URL | https://api.x.ai/v1 | Implemented | xAI API base URL | ai/providers/openai/factory.go |
Mistral AI (Priority: 450)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
MISTRAL_API_KEY | (none) | Implemented | Mistral AI API key | ai/providers/openai/factory.go |
MISTRAL_BASE_URL | https://api.mistral.ai/v1 | Implemented | Mistral AI API base URL | ai/providers/openai/factory.go |
Alibaba Qwen (Priority: 400)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
QWEN_API_KEY | (none) | Implemented | Qwen API key | ai/providers/openai/factory.go |
QWEN_BASE_URL | https://dashscope-intl.aliyuncs.com/compatible-mode/v1 | Implemented | Qwen API base URL | ai/providers/openai/factory.go |
Together AI (Priority: 300)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TOGETHER_API_KEY | (none) | Implemented | Together AI API key | ai/providers/openai/factory.go |
TOGETHER_BASE_URL | https://api.together.ai/v1 | Implemented | Together AI API base URL | ai/providers/openai/factory.go |
The built-in Together aliases, authenticated and live-tested on August 20,
2026, are default=deepseek-ai/DeepSeek-V4-Flash-0731,
fast=google/gemma-4-31B-it, and
smart=code=moonshotai/Kimi-K3. Exact caller-supplied model IDs continue to
pass through unchanged.
Ollama (Priority: 100 - Local)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
OLLAMA_BASE_URL | http://localhost:11434/v1 | Implemented | Ollama local server URL (must be explicitly set to activate detection) | ai/providers/openai/factory.go |
Note: Ollama is only auto-detected when
OLLAMA_BASE_URLis explicitly set. The framework does not probelocalhost:11434by default to avoid a 2-second timeout penalty in environments where Ollama is not running.
AWS Bedrock (Priority: 200, or 250 for detected Lambda/ECS environments)
Bedrock support is compiled only when the application is built with
-tags bedrock. Without that tag the provider is not registered and none of
the detection rows below can select it.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
AWS_ACCESS_KEY_ID | (none) | Implemented | AWS access key; triggers framework auto-detection only when AWS_SECRET_ACCESS_KEY is also non-empty | ai/providers/bedrock/factory.go |
AWS_SECRET_ACCESS_KEY | (none) | Implemented | AWS secret key; triggers framework auto-detection only when AWS_ACCESS_KEY_ID is also non-empty | ai/providers/bedrock/factory.go |
AWS_SESSION_TOKEN | (none) | Implemented by AWS SDK | Optional session token used with temporary static credentials; does not trigger framework auto-detection by itself | AWS SDK for Go v2 configuration |
AWS_REGION | us-east-1 | Implemented | AWS region. If this resolves outside us-east-1, request preparation rejects an invocation that would use the implicit Sonnet 5 default; configure an explicit framework client or per-request model/profile, an endpoint resolver, or direct-package Client.SetDefaultModel. | ai/providers/bedrock/factory.go, ai/providers/bedrock/client.go |
AWS_DEFAULT_REGION | (fallback) | Implemented | Alternative region variable; the same post-model-selection implicit Sonnet 5 guard applies | ai/providers/bedrock/factory.go, ai/providers/bedrock/client.go |
AWS_PROFILE | (none) | Implemented | AWS CLI profile name | ai/providers/bedrock/factory.go |
AWS_EXECUTION_ENV | (auto) | Implemented | Managed AWS runtime indicator, including Lambda/ECS environments | ai/providers/bedrock/factory.go |
AWS_LAMBDA_FUNCTION_NAME | (auto) | Implemented | Set in Lambda environment | ai/providers/bedrock/factory.go |
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI | (auto) | Implemented | Set in ECS environment | ai/providers/bedrock/factory.go |
The factory returns priority 250 when availability is established by
AWS_EXECUTION_ENV, AWS_LAMBDA_FUNCTION_NAME, or
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI. A static environment credential pair
or AWS_PROFILE is checked first and yields priority 200 even if a managed
runtime indicator is also present; a detected ~/.aws/credentials file also
uses priority 200. Credential loading then delegates to the AWS SDK default
credential chain unless explicit ai.WithAWSCredentials values were supplied.
Framework auto-detection is intentionally narrower than the AWS SDK credential
chain. Explicit ai.WithProvider("bedrock") construction can use other
SDK-supported sources—such as web identity, ECS/EKS container credentials, or
an EC2 instance role—even when those sources alone do not satisfy TruvaG3's
detector. See the official
AWS SDK for Go v2 configuration guide.
Semantic Model Alias Overrides
Model override variables change the semantic model selected for a portable
alias. They do not rewrite route-owned Azure deployment names, Vertex
publisher-model IDs, Bedrock modelId values, inference-profile IDs, or ARNs.
Only a non-empty environment value overrides the built-in mapping.
The OpenAI default alias maps to gpt-6.1-sol; this applies to all calls
inheriting it, including planning and synthesis. Existing pins still win. Use
TRUVAG3_OPENAI_MODEL_DEFAULT=gpt-5.6-terra to retain the previous default.
The fast aliases now map to gpt-6-luna (OpenAI) and openai/gpt-6-luna
(OpenRouter). Pin the previous choices with
TRUVAG3_OPENAI_MODEL_FAST=gpt-5.6-luna and
TRUVAG3_OPENROUTER_MODEL_FAST=openai/gpt-5.6-luna if required. Other aliases
are unchanged. Azure and other shared-catalog consumers resolve both new models;
their application-owned deployment mappings must support it or use a pin.
GPT-6.1 Sol does not accept reasoning effort none; this alias setting does not change
effort, token budgets or phase-specific model overrides.
| Provider/profile | Override pattern | Examples and route behavior |
|---|---|---|
| OpenAI, Azure OpenAI, Google-hosted OpenAI compatibility | TRUVAG3_OPENAI_MODEL_{ALIAS} | TRUVAG3_OPENAI_MODEL_SMART=gpt-5.6-sol; Azure resolver maps are keyed by the resulting semantic model |
| DeepSeek | TRUVAG3_DEEPSEEK_MODEL_{ALIAS} | Applies to openai.deepseek |
| Groq | TRUVAG3_GROQ_MODEL_{ALIAS} | Applies to openai.groq |
| OpenRouter | TRUVAG3_OPENROUTER_MODEL_{ALIAS} | Applies to openai.openrouter; e.g. TRUVAG3_OPENROUTER_MODEL_DEFAULT=openai/gpt-5.6-sol |
| Together AI | TRUVAG3_TOGETHER_MODEL_{ALIAS} | Applies to openai.together |
| xAI | TRUVAG3_XAI_MODEL_{ALIAS} | Applies to openai.xai |
| Mistral | TRUVAG3_MISTRAL_MODEL_{ALIAS} | Applies to openai.mistral |
| Qwen | TRUVAG3_QWEN_MODEL_{ALIAS} | Applies to openai.qwen |
| Ollama | TRUVAG3_OLLAMA_MODEL_{ALIAS} | Applies to openai.ollama |
| Anthropic direct and Vertex-hosted Claude | TRUVAG3_ANTHROPIC_MODEL_{ALIAS} | Vertex resolver maps are keyed by the resulting semantic model |
| Google Gemini | TRUVAG3_GEMINI_MODEL_{ALIAS} | Applies to the native Gemini provider |
| AWS Bedrock | No provider-specific alias environment variable | Use ai.WithModel or an SDK-destination EndpointResolver |
Resolver maps receive EndpointRequest.ResolvedModel, which is the concrete
post-alias semantic model. For example, a map must use "gpt-5.6-sol" rather
than "smart" after TRUVAG3_OPENAI_MODEL_SMART=gpt-5.6-sol.
Azure semantic resolution uses the immutable built-in OpenAI catalog plus the
environment overrides above. Runtime mutations of the compatibility variable
openai.ModelAliases apply to the OpenAI provider, but not to Azure.
Hosted Enterprise Profiles Without Auto-Detection
The following profiles intentionally have no framework-owned API-key or base-URL environment shortcut:
| Surface | Selection | Required construction |
|---|---|---|
| Azure OpenAI v1 | ai.WithProviderAlias("azureopenai.v1") | ai.NewRequestClient with WithEndpointResolver plus WithAPIKey, WithCredentialSource, or WithAuthHeader |
| Azure OpenAI classic | ai.WithProviderAlias("azureopenai.classic") | Same as v1; resolver must supply the deployment URL and exactly one non-empty api-version |
| Vertex-hosted Claude | ai.WithProviderAlias("anthropic.vertex") | ai.NewRequestClient with a Vertex route and Google bearer-token credential source |
| Google Cloud OpenAI compatibility | ai.WithProviderAlias("openai") | ai.NewRequestClient with the Google OpenAI-compatible route and bearer-token credential source |
The Azure factory returns (0, false) from provider auto-detection. Anthropic
auto-detection can select only the direct anthropic profile; it never proposes
anthropic.vertex. Vertex also rejects direct Anthropic APIKey and BaseURL
configuration, so setting ANTHROPIC_API_KEY or ANTHROPIC_BASE_URL does not
configure that profile. Provider SDKs used inside application-owned token
sources may honor their own environment variables, but those variables are not
read or interpreted by TruvaG3.
Official provider contracts: Azure OpenAI v1 chat completions, Azure OpenAI classic versioned REST endpoints, OpenAI compatibility on Google Cloud, and Claude request predictions on Google Cloud.
Auto-Detection Priority
When no explicit provider is specified, the framework auto-detects available, linked providers:
- OpenAI (1000) -
OPENAI_API_KEY - Anthropic (900) -
ANTHROPIC_API_KEY - OpenRouter (850) -
OPENROUTER_API_KEY - Gemini (800) -
GOOGLE_API_KEYorGEMINI_API_KEY;GOOGLE_API_KEYwins when both are set - Groq (700) -
GROQ_API_KEY - DeepSeek (600) -
DEEPSEEK_API_KEY - xAI (500) -
XAI_API_KEY - Mistral (450) -
MISTRAL_API_KEY - Qwen (400) -
QWEN_API_KEY - Together AI (300) -
TOGETHER_API_KEY - Bedrock (200, or 250 when detected through Lambda/ECS indicators) - AWS credentials; static credential/profile indicators take precedence; available only with
-tags bedrock - Ollama (100) - Requires
OLLAMA_BASE_URLto be explicitly set
Azure OpenAI, Vertex-hosted Claude, and Google Cloud OpenAI compatibility are not additional auto-detection candidates. They require explicit request-aware construction as described above.
Adding OPENROUTER_API_KEY can therefore change an unpinned
ai.NewClient() or ai.NewRequestClient() selection: when neither OpenAI nor
Anthropic is available, OpenRouter wins over Gemini and every lower-priority
provider. Pin ai.WithProviderAlias("openai.openrouter") when that selection
must not depend on the process environment.
Overriding Auto-Detection Priority
The priority values above are hardcoded defaults used only during auto-detection (when calling ai.NewClient() without specifying a provider). Developers can override this behavior in several ways:
1. Explicit Provider Selection - Bypasses auto-detection entirely:
// Use Anthropic regardless of OpenAI having higher priority
client, _ := ai.NewClient(ai.WithProvider("anthropic"))
2. Provider Aliases - Select specific OpenAI-compatible services:
// Use DeepSeek even if OPENAI_API_KEY is also set
client, _ := ai.NewClient(ai.WithProviderAlias("openai.deepseek"))
3. Chain Client - Define your own failover order:
// Your order: Groq → DeepSeek → OpenAI (ignores default priorities)
client, _ := ai.NewChainClient(
ai.WithProviderChain("openai.groq", "openai.deepseek", "openai"),
)
4. Custom Provider with Higher Priority - Become the default:
func (p *CustomProvider) DetectEnvironment() (priority int, available bool) {
if os.Getenv("CUSTOM_LLM_KEY") != "" {
return 1100, true // Higher than OpenAI's 1000
}
return 0, false
}
Note: There is no environment variable to change the priority order. To use a specific provider, use explicit selection or provider aliases in your code. See AI Module README for detailed examples.
Telemetry Configuration
Configure OpenTelemetry-based observability (metrics and tracing).
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_TELEMETRY_ENABLED | false | Implemented | Enable telemetry collection | core/config.go |
TRUVAG3_TELEMETRY_ENDPOINT | (none) | Implemented | OTLP receiver endpoint (auto-enables telemetry) | core/config.go |
OTEL_EXPORTER_OTLP_ENDPOINT | (fallback) | Implemented | Standard OTEL endpoint variable (auto-enables telemetry) | core/config.go |
TRUVAG3_TELEMETRY_SERVICE_NAME | Agent name | Implemented | Service name for traces/metrics | core/config.go |
TRUVAG3_TELEMETRY_SERVICE_INSTANCE_ID | Generated UUID v4 | Implemented | Identity per emitting OpenTelemetry provider, shared by traces and metrics. Non-empty telemetry.Config.ServiceInstanceID / WithServiceInstanceID overrides it. Read once at construction; present-empty, invalid UTF-8, surrounding whitespace and control characters are rejected. Explicit IDs must differ across concurrent service replicas. | telemetry/otel.go |
OTEL_SERVICE_NAME | (fallback) | Implemented | Standard OTEL service name | core/config.go |
TRUVAG3_TELEMETRY_PROVIDER | otel | Struct Tag Only | Telemetry provider | core/config.go |
TRUVAG3_TELEMETRY_METRICS | true | Struct Tag Only | Enable metrics collection | core/config.go |
TRUVAG3_TELEMETRY_TRACING | true | Struct Tag Only | Enable distributed tracing | core/config.go |
TRUVAG3_TELEMETRY_INSECURE | true | Struct Tag Only | Use insecure connection (no TLS) | core/config.go |
The endpoint/name rows configure core.Config.Telemetry; applications still
initialize the optional telemetry module and pass the resolved values. Direct
telemetry.Initialize(Config) uses its supplied endpoint (empty defaults to
localhost:4318) and does not read those endpoint/name variables automatically.
EnableTelemetry(agent, "") reads the standard endpoint variable as its fallback.
Instance identity is resolved directly by the telemetry constructor as described
in its row.
TRUVAG3_TELEMETRY_SAMPLING_RATE has no current config field or reader. The stock
provider explicitly uses AlwaysSample, so OTEL_TRACES_SAMPLER and
OTEL_TRACES_SAMPLER_ARG also do not change its trace sampler. Profile selection
does not reduce trace sampling. Generic OTEL_RESOURCE_ATTRIBUTES does not merge
into the constructor's explicit resource.
Telemetry Logger Variables
These are used by the telemetry module's internal logger:
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_LOG_LEVEL | INFO | Implemented | Log level for telemetry logger | telemetry/logger.go |
TRUVAG3_DEBUG | false | Implemented | Enable debug logging | telemetry/logger.go |
TELEMETRY_DEBUG | false | Implemented | Enable telemetry-specific debug | telemetry/logger.go |
TRUVAG3_LOG_FORMAT | text (local) / json (K8s) | Implemented | Log format override | telemetry/logger.go |
KUBERNETES_SERVICE_HOST | (auto) | Implemented | Auto-detect K8s for JSON logging | telemetry/logger.go |
Example
export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector:4318"
export OTEL_SERVICE_NAME="weather-tool"
Memory Configuration
Configure state storage for agents.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_MEMORY_MAX_SIZE | 1000 | Reserved (struct tag only) | Reserved for future use; not yet consumed at runtime. | core/config.go — MemoryConfig.MaxSize |
TRUVAG3_MEMORY_DEFAULT_TTL | 1h | Reserved (struct tag only) | Reserved for future use; not yet consumed at runtime. | core/config.go — MemoryConfig.DefaultTTL |
TRUVAG3_MEMORY_CLEANUP_INTERVAL | 10m | Implemented | Sweep interval for the in-process *core.MemoryStore eviction sweeper, used by Framework.AutoRegisterMemorySweeper() and tools that register core.NewMemoryStoreSweeper(...) directly. Format: time.Duration (e.g. 5m, 30s). | core/config.go LoadFromEnv |
Removed env vars (no longer parsed as of the InMemoryStore cleanup): TRUVAG3_MEMORY_PROVIDER, TRUVAG3_MEMORY_REDIS_URL. The framework only ships one Memory implementation today (*core.MemoryStore, in-process); the prior "redis" provider option was unimplemented. To use Redis-backed memory, inject a custom core.Memory implementation by setting agent.Memory = redisStore before calling core.NewFramework.
Shared Memory Configuration
Configure cross-agent shared memory — episodic events, knowledge extraction, activity compaction, and digest caching. Shared memory enables agents in the same domain to see each other's actions and coordinate.
Core configuration validation: Config.LoadFromEnv/NewConfig now reject
explicitly empty, malformed, non-positive or overflowing core-owned numeric
memory/activity settings, including when disabled. Compaction recent detail
allows zero. Absent settings use DefaultConfig values; the enrichment budget
also checks the four-byte conversion bound. File and typed configuration receive
the same range checks. This startup rule does not alter runtime fail-open behavior.
The hook builder also validates generic parsing and ranges for hook-owned numeric
settings before checking optional dependencies; invalid input returns an error,
not a partial hook bundle. Implementation-specific arithmetic bounds, such as
the built-in compactor's five-times-target allowance, are additionally checked
when that implementation is selected.
The event-summarizer override is hook-owned, not parsed by core. Core validation
alone is not backend wiring: BuildMemoryHooks and NewSharedBackends do not
accept core.Config, and they do not consume SharedMemory or
ActivityCoordination values assigned in Go or loaded from JSON. Those fields
are loaded/validated data, not an automatic runtime override. Until an explicit
handoff is implemented, configure the standard bundles through their documented
environment variables/options, or construct hooks/backends directly with their
typed options. Direct composition must also carry any desired environment tuning;
it does not inherit tuning from an independently built bundle.
Ownership and precedence matter: BuildMemoryHooks reads hook-owned overrides
and otherwise keeps direct-constructor defaults. Its behavioral options include
entity extractors and lookback, but it does not accept direct-hook numeric
options. NewSharedBackends validates its own stream/claim settings before I/O.
Direct constructors do not inherit these environment overrides automatically.
Changing env after construction does not reconfigure existing instances.
JSON null, malformed numeric types and empty env values are explicit invalid
settings, not “unset.” Relative retrieval weights must be finite but may be
signed/zero and need not sum to one. This strict numeric-memory rule is separate
from general orchestration compatible-mode fallback and from skills' own
precedence rules.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_SHARED_MEMORY_PROVIDER | noop | Implemented | Storage provider (redis, noop). Agents must use redis for cross-agent memory. | core/config.go |
TRUVAG3_VECTOR_DB_URL | localhost:6334 for direct vector construction | Implemented | Qdrant gRPC address used by memory vector configuration; backend/embedding wiring remains explicit. Setting an address alone does not enable every memory hook. | memory/vector_config.go |
TRUVAG3_AGENT_DOMAIN | default | Implemented | Groups agents for memory scoping. Agents in the same domain see each other's events. | core/config.go |
TRUVAG3_SHARED_MEMORY_STREAM_MAXLEN | 100000 | Implemented | Max events in the Redis domain stream (approximate, uses ~MAXLEN). | core/config.go |
TRUVAG3_SHARED_MEMORY_INVESTIGATION_TTL | 30m | Implemented | Positive advisory investigation-claim expiry, not renewed. Managed request cleanup releases on exit/HITL suspension; resume acquires fresh ownership. It need not span the human wait. Legacy/direct-hook callers own their lifecycle. | core/config.go |
TRUVAG3_SHARED_MEMORY_ENRICHMENT_MAX_TOKENS | 2000 | Implemented | BuildMemoryHooks reads this at startup for both raw and compacted memory views. Bounds the hook's own contribution at four encoded bytes per token; complete records and omission markers fit inside that budget. Invalid/empty/non-positive/overflowing values fail construction. Direct construction uses WithEnrichmentMaxTokens, which rejects invalid values. | memory_hook_builder.go |
TRUVAG3_SHARED_MEMORY_RECENT_EVENTS_LIMIT | 20 | Implemented | Recent domain events for baseline situational awareness (without compactor). Higher values show more cross-agent activity but consume more prompt tokens. | core/config.go |
TRUVAG3_SHARED_MEMORY_SUMMARIZER_MODEL | "" (agent default) | Implemented | Model for LLM event summarization and activity compaction calls. Accepts aliases such as fast and smart only when the selected provider defines them, or a concrete model ID. | core/config.go |
TRUVAG3_SHARED_MEMORY_EVENT_SUMMARIZER_MAX_TOKENS | 10000 | Implemented | Positive fixed base output-token allowance per event-summary batch, before provider reasoning expansion. Read at startup by BuildMemoryHooks; invalid explicit values fail construction, including without an AI client. Independent of synthesis, compaction and stored summary size. Direct constructors use WithSummarizerMaxTokens(n) instead. | orchestration/memory_hook_builder.go |
TRUVAG3_SHARED_MEMORY_EVENT_SUMMARIZER_SUMMARY_MAX_BYTES | 1024 | Implemented | Per-entry stored derived prose limit (minimum 32 UTF-8 bytes). Overlong prose is explicitly marked shortened; exact entity IDs and raw LLM debug completions remain intact. Invalid explicit values fail builder construction. Direct constructor: WithSummarizerSummaryMaxBytes(n). | orchestration/event_summarizer.go |
TRUVAG3_SHARED_MEMORY_EVENT_SUMMARIZER_TIMEOUT | 2m | Implemented | Positive builtin AI-invocation deadline, not a memory-write timeout. Earlier parent deadline wins; invalid/empty/non-positive values fail BuildMemoryHooks even without dependencies. Direct constructor: WithSummarizerTimeout(d). | orchestration/memory_hook_tuning.go |
TRUVAG3_SHARED_MEMORY_EVENT_SUMMARIZER_MAX_RESPONSE_BYTES | 4000 | Implemented | Positive per-step encoded payload allowance shared by failure facts and response in the built-in summary prompt. Invalid/empty/overflow values fail builder construction, including without AI/memory dependencies. Direct construction uses WithSummarizerMaxResponseChars(n) (legacy name; byte units). Independent of output-token limits. | orchestration/event_summarizer.go |
TRUVAG3_SHARED_MEMORY_RECORD_FAILURE_CAUSE_MAX_BYTES | 256 | Implemented | Positive UTF-8 byte allowance for the cause in heuristic failure summaries. Framing and explicit shortening marker are additional. Invalid/empty/overflow values fail builder construction even without AI/memory dependencies. Direct option: WithRecordFailureCauseMaxBytes(n). Original execution errors and model/custom summaries stay unchanged. | orchestration/memory_hooks.go |
TRUVAG3_SHARED_MEMORY_ENRICHMENT_SUMMARY_MAX_TOKENS | 500 | Implemented | Requested digest length in the built-in compactor prompt. Full and incremental calls supply AIOptions.MaxTokens = 5 × target (2500 by default), before any provider reasoning scaling. A selected built-in compactor requires target ≤ math.MaxInt / 5; hook construction rejects overflow, and direct non-empty compaction calls enforce the same check before invoking AI. Custom compactors retain their own generation rules. The target is not a tokenizer-enforced cap; the final enrichment view has a separate byte budget. | orchestration/activity_compactor.go |
TRUVAG3_SHARED_MEMORY_COMPACTION_RAW_LIMIT | 200 | Implemented | Max raw events fetched before compaction. Higher values give the compactor more context but increase LLM input size. | core/config.go |
TRUVAG3_SHARED_MEMORY_COMPACTION_RECENT_DETAIL | 15 | Implemented | Raw events appended after the compacted digest for immediate detail access. Set to 0 to disable. | core/config.go |
TRUVAG3_SHARED_MEMORY_DIGEST_CACHE_TTL | 5m | Implemented | TTL for cached domain activity digests. When expired, next request triggers full compaction. Go duration format. | core/config.go |
TRUVAG3_SHARED_MEMORY_DIGEST_INCREMENTAL_THRESHOLD | 20 | Implemented | Max new events for incremental digest update. Above this threshold, full recompaction is triggered instead. | core/config.go |
TRUVAG3_SHARED_MEMORY_COMPACTION_ENABLED | false | Parsed; application wiring required | Loads Config.SharedMemory.CompactionEnabled. Applications must pass it through WithCompactorEnabled when constructing MemoryCompactor, then invoke RunCompaction on their chosen schedule. No background worker is started by this flag. It does not control the request-time activity digest that BuildMemoryHooks installs when an AI client is supplied. | core/config.go, orchestration/memory_compaction.go |
Builtin event-summary deadline
TRUVAG3_SHARED_MEMORY_EVENT_SUMMARIZER_TIMEOUT: positive Go duration, default
2m, resolved by orchestration.BuildMemoryHooks. Explicit empty, malformed,
non-positive or overflowing values fail construction even when AI or memory is
absent. Only the builtin AI invocation gets a child deadline; shorter enclosing
contexts win. Custom summarizers are unchanged. Direct constructor users choose
WithSummarizerTimeout; that layer does not read this environment variable.
User Memory Configuration
Configure per-user private memory for personal assistant agents. User memory stores learned facts (preferences, identity, constraints) across sessions and injects them into the planning prompt via a <user_profile> enrichment tag — enabling personalized agent responses without replaying raw conversation history. Numeric tuning uses environment variables; behavioural plugs (custom extractors, reconcilers) use WithXXX() options on BuildUserMemoryHooks.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_USER_MEMORY_COLLECTION | truvag3_user_memory | Implemented | Vector DB collection name for user facts. Separate from shared knowledge collection. Used by the reference implementation (VectorUserMemory). | memory/vector_user_memory.go |
TRUVAG3_USER_MEMORY_MAX_FACTS_IN_PROMPT | 15 | Implemented | Overall cap on facts injected into the <user_profile> enrichment tag after lifetime-aware selection. Higher values give the LLM more personalization context but consume more prompt tokens. | orchestration/user_memory_hooks.go |
TRUVAG3_USER_MEMORY_MAX_IDENTITY_FACTS | 5 | Implemented | Max identity facts (name, location, language) always included regardless of query relevance. | orchestration/user_memory_hooks.go |
TRUVAG3_USER_MEMORY_MAX_DURABLE_FACTS_IN_PROMPT | 8 | Implemented | Soft ceiling for durable facts (identity, preferences, constraints, relationships) selected before transient and summary facts compete for prompt space. | orchestration/user_memory_hooks.go |
TRUVAG3_USER_MEMORY_MAX_TRANSIENT_FACTS_IN_PROMPT | 4 | Implemented | Soft ceiling for transient/context facts in prompt selection after durable facts are considered. | orchestration/user_memory_hooks.go |
TRUVAG3_USER_MEMORY_MAX_SUMMARY_FACTS_IN_PROMPT | 3 | Implemented | Soft ceiling for summary facts included for cross-session continuity after durable and transient selection. | orchestration/user_memory_hooks.go |
TRUVAG3_USER_MEMORY_MAX_CONTEXT_FACTS | — | Legacy Compatibility | Legacy fallback for transient prompt-budget configuration. Used only when TRUVAG3_USER_MEMORY_MAX_TRANSIENT_FACTS_IN_PROMPT is unset. Prefer the lifetime-aware variable instead. | orchestration/user_memory_hooks.go |
TRUVAG3_USER_MEMORY_MAX_SUMMARY_FACTS | — | Legacy Compatibility | Legacy fallback for summary prompt-budget configuration. Used only when TRUVAG3_USER_MEMORY_MAX_SUMMARY_FACTS_IN_PROMPT is unset. Prefer the lifetime-aware variable instead. | orchestration/user_memory_hooks.go |
TRUVAG3_USER_MEMORY_MAX_STABLE_FACTS_PER_CATEGORY | 2 | Implemented | Max stable namespace facts (constraints, preferences, relationships) fetched per category via category-based retrieval — bypasses semantic similarity so durable user attributes (e.g., home airport, dietary restrictions) are always injected regardless of query relevance. Applied only in non-universal namespaces. | orchestration/user_memory_hooks.go |
TRUVAG3_USER_MEMORY_MAX_UNIVERSAL_FACTS | 5 | Implemented | Max universal-namespace facts (cross-agent preferences, constraints) retrieved per request. | orchestration/user_memory_hooks.go |
TRUVAG3_USER_MEMORY_MIN_CONFIDENCE | 0.3 | Implemented | Minimum confidence threshold for fact inclusion. Facts below this are excluded from enrichment. | orchestration/user_memory_hooks.go |
TRUVAG3_USER_MEMORY_RECONCILIATION_THRESHOLD | 0.75 | Implemented | Cosine similarity threshold for triggering LLM reconciliation. Below this, candidate facts are treated as new (ADD). | orchestration/user_memory_hook_builder.go |
TRUVAG3_USER_MEMORY_EXTRACTION_MODEL | "" (agent default) | Implemented | Model for fact extraction and session summary LLM calls. Use a fast/cheap model — these are high-volume, low-complexity calls. | orchestration/user_memory_hook_builder.go |
TRUVAG3_USER_MEMORY_RECONCILIATION_MODEL | extraction model | Implemented | Model for reconciliation LLM calls. Falls back to extraction model if unset. | orchestration/user_memory_hook_builder.go |
TRUVAG3_USER_MEMORY_SUMMARY_MAX_RESPONSE_LEN | 500 | Implemented | Max characters of agent response included in the session summary prompt. Truncated at UTF-8 rune boundary. | orchestration/user_memory_extraction.go |
TRUVAG3_USER_MEMORY_BATCH_TOKENS_PER_CANDIDATE | 400 | Implemented | Output token budget per candidate in the batched reconciliation LLM call (default reconciler collapses N per-candidate calls into one). Floors at 500 tokens for tiny batches. Increase if you see truncated merged_content on UPDATE-heavy turns; decrease for tighter cost control. | orchestration/user_memory_extraction.go |
TRUVAG3_USER_MEMORY_RECALL_OVERFETCH_MULTIPLIER | 3 | Implemented | Over-fetch multiplier used by vector-backed recall before lifetime filtering so transient cleanup and bucket selection do not under-fill results. | memory/vector_user_memory.go |
TRUVAG3_USER_MEMORY_TRANSIENT_MAX_AGE_HOURS | 168 | Implemented | Max age in hours for transient/context facts during recall-time filtering. Unset, invalid, or non-positive values fall back to 168 hours (7 days). | memory/user_memory_backend.go |
TRUVAG3_USER_MEMORY_MAX_SPLIT_CLAUSES | 3 | Implemented | Max number of clauses emitted when Phase 4 splitting expands a mixed extracted fact before storage/reconciliation. | orchestration/user_memory_extraction.go |
Framework Runnable Lifecycle
Background components implementing core.Runnable are registered with the framework via framework.RegisterRunnable(r). They start in goroutines when Run(ctx) is called and shut down when ctx is cancelled (typically by SIGTERM in Kubernetes). In-tree consumers include memory reflection/sweeping, schedulers and queue workers, Redis Streams reaping, and the provider-neutral HITL checkpoint-expiry processor. Any long-running background work an agent needs can implement the same lifecycle contract.
Because Go provides no mechanism for forcibly terminating goroutines, the framework gives each runnable a bounded grace period to honour ctx.Done() and exit cleanly. After the grace period, the framework logs a warning, returns from Run, and lets the OS reap any remaining goroutines on process exit. Buggy runnables that ignore ctx will leak until process exit — the framework cannot recover from this.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_FRAMEWORK_RUNNABLE_DRAIN_TIMEOUT | 10s | Implemented | Maximum time Framework.Run waits for registered core.Runnable instances to exit after ctx is cancelled. Go duration format (5s, 30s, 2m). Only positive values are honored — invalid or zero values fall back to the default. Shorter values trade clean shutdown for faster pod termination; longer values give in-flight reflection passes or other long-running jobs more time to finish their current iteration. | core/agent.go |
If you have a runnable that may legitimately need more than 10 seconds to wind down (e.g., a reflection pass mid-LLM-call), raise this. Conversely, if Kubernetes is killing your pods because shutdown takes too long, lower it — but be aware that runnables may be terminated mid-operation and any in-flight LLM calls or Redis writes will be abandoned.
The corresponding lifecycle log events are documented in LOGGING_IMPLEMENTATION_GUIDE.md under the framework_runnable_* operations and the runnable_drain_timeout error_type.
Reflection Job Configuration
Configure the background reflection job that bridges Tier 2 (episodic events in Redis) to Tier 3 (semantic knowledge fragments in Qdrant). The job runs on a periodic schedule, discovers entities with accumulated old events, asks an LLM to extract reusable patterns, embeds them, and stores them in the vector knowledge collection.
Configuration follows the Configuration Split principle from FRAMEWORK_DESIGN_PRINCIPLES.md: numeric tuning is via environment variables, behavioural plugs are via Go options. The available With* options are:
- On
NewReflectionJob/BuildReflectionJob(ReflectionJobOption):WithReflectionLock(core.DistributedLock),WithReflectionTelemetry(core.Telemetry). See memory/reflection_job.go. - On
NewLLMMemoryReflector(ReflectorOption):WithReflectorLogger(core.Logger),WithReflectorTelemetry(core.Telemetry),WithReflectorMinEvents(int),WithReflectorModel(string). See memory/reflector.go.
The reflection job is wired automatically by BuildReflectionJob when Phase 2 backends (SharedKnowledge + EmbeddingClient) are available. It is registered with the framework via framework.RegisterRunnable(job) and managed by the framework lifecycle (started on Run, stopped on context cancel).
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_REFLECTION_INTERVAL | 24h | Implemented | How often the reflection pass runs. Go duration format (5m, 6h, 24h). Shorter intervals increase LLM cost; longer intervals delay knowledge accumulation. | memory/reflection_job.go |
TRUVAG3_REFLECTION_AGE_THRESHOLD | 168h (7 days) | Implemented | Only events older than this are eligible for reflection. Should be longer than the activity compactor's window — events younger than this are still represented in the per-request activity digest, so reflecting them prematurely spends LLM tokens on under-developed patterns. Go duration format. | memory/reflection_job.go |
TRUVAG3_REFLECTION_MIN_EVENTS | 5 | Implemented | Minimum events per entity required to trigger reflection. Below this, the entity is skipped. Propagated to both the job's discovery pass and the LLM reflector — they share the same threshold. Lower values produce more fragments from less data (riskier); higher values produce fewer, more confident fragments. | memory/reflection_job.go, memory/reflection_job_builder.go |
TRUVAG3_REFLECTION_MODEL | "" (AIClient default) | Implemented | Model used for the reflection LLM call. Accepts a portable alias (fast, smart, default) when the selected provider defines that alias, or a concrete model ID. The selected provider performs alias resolution; Bedrock has no portable-alias catalog. Empty string means "use the AIClient's default selection." Reflection is durable—fragments influence every future request—so this is a real cost-vs-quality trade-off. See Choosing a model for reflection below. | memory/reflector.go, memory/reflection_job_builder.go |
Choosing a model for reflection
Reflection runs periodically (default: once per 24 hours, configurable via TRUVAG3_REFLECTION_INTERVAL) and writes durable knowledge fragments into Qdrant. Those fragments are recalled by semantic search and injected into <agent_memory> for every future request. The cost-vs-quality trade-off is therefore unlike per-request orchestration calls — a sloppy fragment isn't a one-off mistake, it lingers and surfaces as confident "prior knowledge" for as long as it remains in Qdrant.
Recommended configurations:
| Use case | TRUVAG3_REFLECTION_MODEL | TRUVAG3_REFLECTION_MIN_EVENTS | Reasoning |
|---|---|---|---|
| Default (production) | unset (uses agent default) | 5 | Best fragment quality. Reflection runs infrequently so cost is bounded. |
| High volume / cost-sensitive | fast | 5 | Cheaper and faster per pass. min_events=5 ensures the cheap model only sees entities with strong signal. |
| Aggressive learning | unset | 2 | Captures patterns from sparse-event entities. Use only with the strongest model — low signal × weak model = noise. |
| Bulk indexing of historical data | fast | 10 | When backfilling reflection over a large existing event log, the cheap model handles the volume and the high min_events floor filters out low-signal entities. |
Where supported, aliases (fast, smart, default, code, vision) are
resolved by the selected AI provider at call time. Bedrock does not define
portable alias mappings. The authoritative alias-to-model mappings live in the
provider source files, not in this guide—copying the concrete mappings here
would silently desynchronize them from code on every model release. See:
- Anthropic: ai/providers/anthropic/models.go
- OpenAI and OpenAI-compatible (Groq, DeepSeek, xAI, Together, Mistral, Qwen, Ollama): ai/providers/openai/models.go — sub-providers use the
openai.<sub>alias namespace - Google Gemini: ai/providers/gemini/models.go
Providers with an environment-backed model catalog can override an alias
without recompiling—for example,
TRUVAG3_ANTHROPIC_MODEL_FAST=claude-haiku-4-5 or
TRUVAG3_GROQ_MODEL_FAST=llama-3.1-8b-instant. See
Semantic Model Alias Overrides for the exact
supported prefixes and the hosted-provider semantic/wire boundary.
The Anthropic example above deliberately pins the previous fast model. The built-in fast model is now Haiku 5.5; smart/code/vision select Opus 5.5. For migration requirements and Vertex mapping impact, see the Anthropic alias refresh.
To set the model programmatically (Layer 3, bypassing the env var):
reflector, err := memory.NewLLMMemoryReflector(
aiClient, episodic, "infrastructure", logger,
memory.WithReflectorModel("fast"),
)
if err != nil {
return err
}
Activity Coordination Configuration
Configure real-time agent coordination signals. Activity signals are transient Redis KV entries with TTL that allow agents to see what other agents are currently working on — enabling coordination without waiting for episodic events (which are only written after execution completes).
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_ACTIVITY_COORDINATION_ENABLED | true | Implemented | Enable/disable the activity coordination layer. When false, no signals are emitted or read. | core/config.go |
TRUVAG3_ACTIVITY_SIGNAL_TTL | 5m | Implemented | Positive expiry for transient activity signals. Managed request segments renew at TTL/3 and join renewal before cleanup, so TTL need not exceed the request duration. Direct/unmanaged callers own renewal. | orchestration/execution_activity.go |
TRUVAG3_ACTIVITY_SIGNAL_MAX_IN_PROMPT | 10 | Implemented | Max activity signals shown in the <agent_coordination> prompt section. Most recent first after filtering. | core/config.go |
TRUVAG3_ACTIVITY_SIGNAL_QUERY_MAX_LEN | 200 | Implemented | Request-query byte prefix retained in activity signals; legacy helper appends ... when truncated. This is not a rune count or an exact final-size cap. | orchestration/activity_hooks.go |
Logging Configuration
Configure logging output format and level.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_LOG_LEVEL | info | Implemented | Minimum log level (debug, info, warn, error) | core/config.go |
TRUVAG3_LOG_FORMAT | json (K8s) / text (local) | Implemented | Output format | core/config.go |
TRUVAG3_LOG_OUTPUT | stdout | Struct Tag Only | Output destination | core/config.go |
TRUVAG3_LOG_TIME_FORMAT | RFC3339Nano | Struct Tag Only | Timestamp format | core/config.go |
Development Configuration
Configure development-mode settings.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_DEV_MODE | false | Implemented | Enable development mode (sets debug logging, text format) | core/config.go |
TRUVAG3_MOCK_AI | false | Implemented | Use mock AI responses | core/config.go |
TRUVAG3_MOCK_DISCOVERY | false | Implemented | Use in-memory mock discovery | core/config.go |
TRUVAG3_DEBUG | false | Implemented | Enable debug logging | core/config.go |
TRUVAG3_PRETTY_LOGS | false | Struct Tag Only | Enable human-readable logs | core/config.go |
Effects of TRUVAG3_DEV_MODE=true
When enabled, automatically sets:
TRUVAG3_LOG_LEVELtodebugTRUVAG3_LOG_FORMATtotext- Pretty logs enabled
Kubernetes Configuration
Kubernetes-specific settings. Most are auto-detected when running in K8s.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
KUBERNETES_SERVICE_HOST | (auto) | Implemented | Auto-set by K8s, triggers K8s mode | core/config.go |
HOSTNAME | (auto) | Implemented | Pod name, auto-set by K8s | core/config.go |
TRUVAG3_K8S_NAMESPACE | (auto-detected) | Implemented | Pod namespace | core/config.go |
TRUVAG3_K8S_SERVICE_NAME | Agent name | Implemented | Kubernetes service name | core/config.go |
TRUVAG3_K8S_SERVICE_PORT | 80 | Implemented | Kubernetes service port | core/config.go |
TRUVAG3_K8S_POD_IP | (auto) | Implemented | Pod IP address | core/config.go |
TRUVAG3_K8S_NODE_NAME | (auto) | Implemented | Node name where pod is running | core/config.go |
TRUVAG3_K8S_SA_PATH | /var/run/secrets/kubernetes.io/serviceaccount | Struct Tag Only | Service account mount path | core/config.go |
TRUVAG3_K8S_SERVICE_DISCOVERY | true | Struct Tag Only | Enable K8s service discovery | core/config.go |
TRUVAG3_K8S_LEADER_ELECTION | false | Struct Tag Only | Enable leader election | core/config.go |
Kubernetes Deployment Example
env:
- name: TRUVAG3_AGENT_NAME
value: "weather-tool"
- name: TRUVAG3_K8S_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: TRUVAG3_K8S_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: TRUVAG3_K8S_SERVICE_NAME
value: "weather-tool"
- name: TRUVAG3_K8S_SERVICE_PORT
value: "8080"
Orchestration Configuration
Configure the AI orchestrator for multi-agent coordination.
Failed-operation evidence (implemented)
TRUVAG3_FAILED_OPERATION_VIEW_DISABLED defaults to false.
TRUVAG3_FAILED_OPERATION_MAX_VALUE_BYTES,
TRUVAG3_FAILED_OPERATION_MAX_STEP_BYTES, and
TRUVAG3_FAILED_OPERATION_MAX_PROMPT_BYTES default to 4096, 16384, and
32768. Numeric values must be positive; canonical orchestration
EnvironmentStrict rejects invalid values and EnvironmentCompatible reports
ignored invalid overrides. Code zero means unset; negative code limits fail
validation. WithFailedOperationView replaces the entire environment-resolved
configuration. Omitted code fields resolve to defaults; they do not retain env values.
These are final-encoded child ceilings inside continuation's existing failure
share, not a way to raise its parent budget. See the Limits Cheatsheet and
Result Compaction Guide for measurement and omission semantics.
Execution and planning variables
Related controls used by the current planning/execution paths:
| Variable | Default | Scope and validation |
|---|---|---|
TRUVAG3_STEP_RETRY_MAX_ATTEMPTS | 3 total attempts | Positive integer; ExecutionOptions.RetryAttempts in canonical construction. Direct NewSmartExecutor also reads it; SetMaxAttempts(n) is the direct code seam (values below 1 become 1). Orchestrator capabilities remain single dispatch |
TRUVAG3_PLAN_REFINEMENT_ENABLED | false | Enables the post-orchestrator refinement pass; standard orchestration boolean resolution, not a provider setting |
TRUVAG3_EXCLUDED_CAPABILITIES | empty | Comma-separated capability names, trimmed and empty entries discarded; populates OrchestratorConfig.ExcludedCapabilities. Separate from capabilities marked Internal |
These existing controls are not new feature flags for the hardening work.
Explicit ToolError.Retryable=false stops all same-step retries, including
transient resends. Transient 408/429/5xx preserves admitted inputs; eligible
non-transient 4xx may be corrected, never resent unchanged. Increasing a retry
budget does not bypass refusal, immutable inputs or the delegated-call limit.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_ORCHESTRATION_TIMEOUT | 20m | Implemented | Base shared HTTP-client timeout per tool/agent call, not the whole execution. Orchestrator construction raises it to HITL.DefaultTimeout + ExecutionOptions.StepTimeout when that allowance is larger. Earlier enclosing deadlines still apply. | orchestration/orchestrator.go |
TRUVAG3_EXECUTION_MAX_CONCURRENCY | 25 | Implemented | Max parallel step executions in DAG. Controls goroutine concurrency during plan execution. | orchestration/interfaces.go |
TRUVAG3_EXECUTION_STEP_TIMEOUT | 15m | Implemented | Go-duration execution allowance added to HITL.DefaultTimeout for an orchestrator capability's per-call context deadline. Ordinary tool calls have no separate deadline from this setting; they use the shared HTTP timeout and enclosing context. The delegation allowance can also enlarge the shared client timeout and phase budget. | orchestration/executor.go, orchestration/orchestrator.go |
TRUVAG3_CONVERSATION_TOKEN_BUDGET | 48000 | Implemented | Maximum estimated tokens allowed for prepared <conversation_history> before Tier 1 truncation/elision. Default-on safety net for metadata and hook ingress paths. | orchestration/interfaces.go |
TRUVAG3_CONVERSATION_RECENT_TURNS_PRESERVED | 4 | Implemented | Number of newest turns always kept verbatim when turn-aware conversation preparation needs to shed context. | orchestration/interfaces.go |
TRUVAG3_CONVERSATION_SUMMARY_CACHE_SIZE | 256 | Implemented | LRU capacity for the optional Tier 2 recursive conversation-summary cache. Only used when the application injects a compaction-enabled conversation-history preparer. | orchestration/interfaces.go |
TRUVAG3_STEP_RETRY_INITIAL_DELAY | 500ms | Implemented | Initial step-retry backoff, with 2× growth and jitter. Canonical construction requires a positive Go duration: strict mode rejects invalid values; compatible mode diagnoses ignored overrides. Direct NewSmartExecutor retains compatibility with zero/negative delays. | orchestration/config_resolution.go, orchestration/executor.go |
TRUVAG3_STEP_RETRY_MAX_DELAY | 10s | Implemented | Maximum step-retry backoff. Canonical construction requires a positive Go duration: strict mode rejects invalid values; compatible mode diagnoses ignored overrides. Direct NewSmartExecutor retains compatibility with zero/negative delays. | orchestration/config_resolution.go, orchestration/executor.go |
TRUVAG3_OAUTH_TOKEN | (empty) | Implemented | OAuth Bearer token for outbound HTTP calls to tool/agent endpoints. Per-request tokens via WithOAuthToken() take priority. When set, executor requests include Authorization: Bearer <token>. | orchestration/executor.go |
TRUVAG3_TIERED_RESOLUTION_ENABLED | true | Implemented | Enable tiered capability resolution for LLM token optimization. Uses 2-phase approach to reduce tokens by 50-75%. | orchestration/interfaces.go |
TRUVAG3_TIERED_MIN_TOOLS | 20 | Implemented | Minimum tool count to trigger tiered resolution. Below this threshold, all tools are sent directly. Research-backed default. | orchestration/tiered_capability_provider.go |
TRUVAG3_TIERED_SELECTION_MAX_TOKENS | 2000 | Implemented | Max output tokens for tiered selection LLM calls. Higher values allow complex multi-tool selections but cost more tokens. | orchestration/tiered_capability_provider.go |
TRUVAG3_TIERED_SELECTION_RETRY_ENABLED | true | Implemented | Enable retry on empty LLM responses and parse failures during tiered tool selection. Set to false to disable. | orchestration/interfaces.go |
TRUVAG3_TIERED_SELECTION_RETRY_MAX | 2 | Implemented | Max retry attempts for tiered selection (0 = disabled). 2 means up to 3 total attempts (1 initial + 2 retries). | orchestration/interfaces.go |
TRUVAG3_CAPABILITY_SERVICE_URL | (none) | Implemented | External capability service URL | orchestration/capability_provider.go |
CAPABILITY_SERVICE_URL | (fallback) | Implemented | Alternative capability service URL | orchestration/capability_provider.go |
TRUVAG3_CAPABILITY_TOP_K | 20 | Implemented | Number of capabilities to return | orchestration/capability_provider.go |
TRUVAG3_CAPABILITY_THRESHOLD | 0.7 | Implemented | Minimum similarity threshold | orchestration/capability_provider.go |
TRUVAG3_PLAN_RETRY_ENABLED | true | Implemented | Retry initial/continuation generation on syntax or routing-intent decoding failures; other recovery paths have their own budgets | orchestration/interfaces.go |
TRUVAG3_PLAN_RETRY_MAX | 2 | Implemented | Maximum retry attempts for plan parsing (0 = disabled) | orchestration/interfaces.go |
TRUVAG3_PLAN_MAX_TOKENS | 20000 | Implemented | Max output tokens for plan generation LLM calls (including hallucination and validation retries) | orchestration/interfaces.go |
TRUVAG3_SYNTHESIS_MAX_TOKENS | 30000 | Implemented | Max output tokens for response synthesis LLM calls | orchestration/interfaces.go |
TRUVAG3_SYNTHESIS_TEMPERATURE | 0.5 | Implemented | LLM temperature for response synthesis (0.0–2.0). Lower = more deterministic | orchestration/interfaces.go |
TRUVAG3_PLAN_MODEL | "" | Implemented | Portable alias or model name for plan generation LLM calls. Aliases work across catalog-backed chain entries; leave unset for a chain containing Bedrock so each entry uses its configured default | orchestration/interfaces.go |
TRUVAG3_SYNTHESIS_MODEL | "" | Implemented | Portable alias or model name for response synthesis LLM calls (streaming + non-streaming) | orchestration/interfaces.go |
TRUVAG3_MICRO_RESOLUTION_MODEL | "" | Implemented | Portable alias or model name for micro-resolution and Layer 4 semantic retry (contextual re-resolution) LLM calls. When unset, both use the provider-default model | orchestration/interfaces.go |
TRUVAG3_MICRO_RESOLUTION_MAX_TOKENS | 2000 | Implemented | Maximum output tokens for micro-resolution (base default 2000) and Layer 4 semantic retry (base default 1000); setting this overrides both | orchestration/interfaces.go |
TRUVAG3_HALLUCINATION_VALIDATION_ENABLED | true | Implemented | Validate that LLM-generated plans only reference agents from the allowed list | orchestration/interfaces.go |
TRUVAG3_HALLUCINATION_RETRY_ENABLED | true | Implemented | Retry plan generation with enhanced context when hallucination is detected | orchestration/interfaces.go |
TRUVAG3_HALLUCINATION_MAX_RETRIES | 1 | Implemented | Maximum retry attempts for hallucination correction (0 = disabled) | orchestration/interfaces.go |
TRUVAG3_ITERATIVE_PLANNING_ENABLED | true | Implemented | Enable multi-phase iterative planning. LLM planner can generate partial plans that execute in phases. | orchestration/interfaces.go |
TRUVAG3_ITERATIVE_MAX_PHASES | 20 | Implemented | Maximum planning phases per request. Forces termination with synthesis if reached. | orchestration/interfaces.go |
TRUVAG3_ITERATIVE_MAX_TOTAL_STEPS | 200 | Implemented | Maximum total steps across all phases. Prevents runaway plan generation. | orchestration/interfaces.go |
TRUVAG3_ITERATIVE_PHASE_TIMEOUT | 25m | Implemented | Configured phase budget (plan generation + execution). The phase loop raises it to the delegation allowance (HITL.DefaultTimeout + StepTimeout) when larger, even if the plan has no delegated step. Earlier parent deadlines still apply. | orchestration/orchestrator.go |
TRUVAG3_ITERATIVE_MAX_VALIDATION_ROUNDS | 4 | Implemented | Regeneration attempts after the first validation failure; at most 1 + N validations. Malformed or intent-invalid regenerated JSON spends a round without validation; provider/boundary/cancellation errors and persistent continuation step-ID conflicts can stop earlier. | orchestration/interfaces.go |
TRUVAG3_ITERATIVE_REGENERATION_FEEDBACK_MAX_BYTES | 16384 | Implemented | Byte limit on encoded correction context added to a selected phase prompt. The effective value must be greater than zero when validated; environment handling follows the selected configuration-resolution mode. Omitted prior evidence is marked; failure to fit required feedback stops preparation. Not a whole-prompt/token limit. | orchestration/plan_attempt.go |
TRUVAG3_CONTINUATION_RESULT_MAX_CHARS | 10000 | Implemented | Floor-preview size in bytes (legacy setting name) for a non-JSON completed-step result. JSON results use a structural digest; delegation summaries have a separate projection. Visibility remains subject to digest and enclosing budgets. | orchestration/interfaces.go |
TRUVAG3_CONTINUATION_RESULT_MAX_TOTAL_CHARS | 196608 | Implemented | Soft byte target (legacy setting name) for completed-step views before enclosing prompt encoding. Older successful steps may be omitted; failed steps and the newest successful step are retained, and markers can exceed the target. Failed-operation evidence is sub-allocated and also bounded by its own encoded-byte limits. | orchestration/interfaces.go |
TRUVAG3_CONTINUATION_MAX_ESCALATIONS | 8 | Implemented | Phase 14: max non-JSON steps escalated to the continuation distiller (a fast-model summary) per phase, newest-first. Sequential fast-model calls on the phase-gating path, so the cap bounds latency. 0 disables; fires ~never on all-JSON workloads. | orchestration/interfaces.go |
TRUVAG3_CONTINUATION_DIGEST_ARRAY_SAMPLE | 3 | Implemented | Phase 14: per-array head-sample size in a continuation digest (arrays render as the first N elements + a length sentinel). | orchestration/interfaces.go |
TRUVAG3_CONTINUATION_DIGEST_SCALAR_MAX | 200 | Implemented | Phase 14: max length of a string value kept inline in a digest before elision. Raise it so the planner sees longer salient values (status/error strings) at plan time. | orchestration/interfaces.go |
TRUVAG3_CONTINUATION_DIGEST_MAX_KEYS | 50 | Implemented | Phase 14: per-object key cap in a digest. Schema objects kept whole; map-shaped objects (many dynamic-ID keys) sampled to this many sorted keys + a sentinel. | orchestration/interfaces.go |
TRUVAG3_FAILURE_PATTERN_MIN_FAILURES | 2 | Implemented | Minimum distinct failed upstream steps required for the remediation continuation prompt to embed a shared-error pattern summary. 1 would make every skip emit a summary (noisy); raise to make the analyzer more conservative. | orchestration/interfaces.go |
TRUVAG3_FAILURE_PATTERN_SIGNATURE_LEN | 120 | Implemented | Max chars of error text used to bucket failures into a shared signature for classification. Wider than the display cap to reduce false-positive collisions between distinct errors that share a common prefix. | orchestration/interfaces.go |
TRUVAG3_FAILURE_PATTERN_DISPLAY_LEN | 80 | Implemented | Max chars of the shared error rendered into the remediation prompt (trailing … on truncation). Kept short so the continuation prompt stays slim per EFFECTIVE_PROMPTS_GUIDE §4.5. | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_ENABLED | true | Implemented | Enable structural trimming of large step results before prompt construction. Prevents token budget overflow. | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_MAX_BYTES | 65536 | Implemented | Maximum bytes per individual step result (~16K tokens). Results exceeding this are structurally trimmed. | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_MAX_TOTAL_BYTES | 196608 | Implemented | Maximum total bytes across all step results in a synthesis prompt (~48K tokens). | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_MAX_MICRO_BYTES | 65536 | Implemented | Maximum bytes for source data in micro-resolution and semantic retry prompts (~26K tokens). | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_MAX_AGENT_INPUT_BYTES | 0 | Implemented | Maximum bytes per parameter value for agent/tool HTTP calls. Default 0 = no cap (fidelity-first): tool→tool data flows raw so downstream steps receive the full upstream output. Set > 0 (or supply deps.AgentInputProcessor) to enable the byte-budget guard. | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_SCHEMA_MAPPING_THRESHOLD | 16384 | Implemented | Result size threshold above which schema-guided mapping replaces direct value extraction. Set to 0 to disable. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_ENABLED | true | Implemented | Default-on LLM-based result distillation (two-stage: structural pre-filter → LLM distill). Active when an AIClient is configured and TRUVAG3_RESULT_TRIM_ENABLED is true; otherwise the structural floor is used. Set =false to opt out. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_THRESHOLD | 16384 | Implemented | Minimum result size (bytes) to trigger LLM distillation. Below this, structural trimming only. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_PREFILTER | 131072 | Implemented | StructuralTrimmer budget (bytes) applied before LLM distillation (Stage 1 pre-filter). 128 KB — fits the 64K fast-tier context floor. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_TARGET | 4096 | Implemented | Target output size for LLM distillation (Stage 2). | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_MODEL | fast | Implemented | Portable alias or model name for LLM distillation calls. Default fast resolves for catalog-backed providers. For a chain containing Bedrock, set ResultDistill.Model or WithResultDistillModel to an empty string programmatically so each entry uses its configured default; the environment loader ignores an empty value. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_CACHE_TTL | 5m | Implemented | How long a distillation result stays cached (keyed by result content + instruction + query + budget). Fail-open. Go duration format. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_DEADLINE | 45s | Implemented | Wall-clock bound on a single compaction in the synthesis hot path. On timeout, fails open to the structural floor (single-call) or returns completed chunks + a "partial" disclosure (map-reduce). Go duration format; the env var accepts only positive values — disable the deadline via the programmatic CompactionDeadline: 0. Keep it under the HTTP gateway timeout. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_CONTEXT_TOKENS | 150000 | Implemented | Usable context (tokens) of the compaction model. Results estimated above this are chunked and map-reduced instead of sent in one call (~525 KB at the default, using the framework's ≈3.5 bytes/token counter). | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_MAP_CONCURRENCY | 8 | Implemented | Max chunks compacted concurrently in the map-reduce path. ≤ 0 falls back to the default. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_MAPREDUCE_THRESHOLD | 0 | Implemented | Routes results larger than this (bytes) to map-reduce even when they fit the model context, so the whole result reaches an LLM instead of only the pre-filtered head. Independent of CONTEXT_TOKENS. 0 = disabled (context-only routing) — a deliberate deviation from the repo-wide > 0 convention so an explicit 0 can disable a future nonzero default. A positive value below PREFILTER is ignored with a factory warning (a result that small is one chunk — no fan-out benefit over the single-call distill). | orchestration/interfaces.go |
For every orchestration model override above, aliases are portable only across
providers with alias catalogs. Leave the plan, synthesis, and micro-resolution
model variables unset for a chain containing Bedrock so each entry can use its
configured default. Result distillation is the exception because its built-in
model is "fast"; use the programmatic empty override described in its row.
Tiered Capability Resolution
Tiered resolution is a research-backed optimization that reduces LLM token usage by 50-75% for deployments with 20+ tools. It works by first sending lightweight tool summaries to select relevant tools, then fetching full schemas only for selected tools.
# Tiered resolution is enabled by default
export TRUVAG3_TIERED_RESOLUTION_ENABLED=true
# Adjust threshold for when tiering kicks in (default: 20)
export TRUVAG3_TIERED_MIN_TOOLS=25
# Increase selection output tokens for complex multi-tool registries (default: 2000)
export TRUVAG3_TIERED_SELECTION_MAX_TOKENS=3000
# Disable for small deployments (< 20 tools)
export TRUVAG3_TIERED_RESOLUTION_ENABLED=false
# Retry on empty responses / parse failures (default: enabled, 2 retries)
export TRUVAG3_TIERED_SELECTION_RETRY_ENABLED=true
export TRUVAG3_TIERED_SELECTION_RETRY_MAX=2
When to use:
- < 20 tools: Disable tiered resolution (overhead not worth it)
- 20-100 tools: Use tiered resolution (default, 50-75% token savings)
- 100s+ tools: Consider ServiceCapabilityProvider for semantic search
Conversation History Preparation
Conversation history now has a framework-owned preparation layer that runs before planning. Tier 1 token protection is default-on; Tier 2 recursive compaction is opt-in.
# Raise/lower the default-on conversation-history budget (default: 48000)
export TRUVAG3_CONVERSATION_TOKEN_BUDGET=64000
# Keep more or fewer recent turns verbatim when history comes in as raw turns
export TRUVAG3_CONVERSATION_RECENT_TURNS_PRESERVED=6
# Only relevant when you inject a compaction-enabled preparer
export TRUVAG3_CONVERSATION_SUMMARY_CACHE_SIZE=512
How these settings apply:
TRUVAG3_CONVERSATION_TOKEN_BUDGETprotects both legacy formatted history and raw-turn metadata.TRUVAG3_CONVERSATION_RECENT_TURNS_PRESERVEDmatters only on the turn-aware path.TRUVAG3_CONVERSATION_SUMMARY_CACHE_SIZEmatters only when the application enables Tier 2 recursive compaction by injecting a preparer with a summary cache and compactor.
Plan Parse Retry
When LLMs generate execution plans, JSON parsing may fail due to:
- Missing or invalid routing-plan intent, including ambiguous empty plans
- Arithmetic expressions in values (e.g.,
"amount": 100 * price) - Malformed JSON syntax (trailing commas, missing quotes)
- Invalid JSON structures
Initial/continuation generation uses the parse-retry mechanism for these failures. Initial unavailable-agent replacements use the hallucination-recovery budget; validation-regeneration outputs instead spend validation rounds. A continuation unknown-agent recovery has only one regeneration attempt within that path; the outer phase loop may subsequently attempt fallback regeneration, subject to context and request-preparation success. These paths are distinct.
The parse-retry mechanism provides error feedback to the LLM:
# Disable retry (fail fast on parse errors)
export TRUVAG3_PLAN_RETRY_ENABLED=false
# Increase retry attempts (default: 2)
export TRUVAG3_PLAN_RETRY_MAX=3
# Disable by setting max retries to 0
export TRUVAG3_PLAN_RETRY_MAX=0
LLM Synthesis Parameters
Controls the base output-token allowance and temperature for LLM calls during plan generation and response synthesis. Planning defaults to 20000 tokens; synthesis defaults to 30000 tokens at temperature 0.5. These are base allowances, not guarantees against truncation: active reasoning profiles may expand them, reviewed model ceilings may bound the result, and hidden reasoning can consume the same output budget. Provider deadlines and model/context capacity still apply. Sampling controls are subject to the selected model's compatibility policy; a requested temperature is not guaranteed to reach every provider.
# Increase plan generation token limit (default: 20000)
export TRUVAG3_PLAN_MAX_TOKENS=60000
# Increase synthesis token limit (default: 30000)
export TRUVAG3_SYNTHESIS_MAX_TOKENS=40000
# Adjust synthesis temperature (default: 0.5, range: 0.0-2.0)
# Higher values produce more creative responses (good for streaming chat)
export TRUVAG3_SYNTHESIS_TEMPERATURE=0.7
# Reduce plan generation for cost savings
export TRUVAG3_PLAN_MAX_TOKENS=5000
# Model overrides — aliases are portable across catalog-backed chain entries;
# leave them unset for a chain containing Bedrock
export TRUVAG3_PLAN_MODEL=smart
export TRUVAG3_SYNTHESIS_MODEL=default
export TRUVAG3_MICRO_RESOLUTION_MODEL=fast
Hallucination Detection
LLMs can hallucinate non-existent agents when generating execution plans. For example, when asked about "time in CST", the LLM might invent a time-tool-v1 agent even though only weather-tool-v2 was provided in the prompt. Hallucination detection validates that all agents referenced in the plan were actually included in the capability information shown to the LLM.
When validation fails, the retry mechanism provides explicit error feedback with the list of allowed agents, giving the LLM a chance to self-correct:
# Disable hallucination validation entirely (not recommended)
export TRUVAG3_HALLUCINATION_VALIDATION_ENABLED=false
# Disable retry (fail immediately when hallucination detected)
export TRUVAG3_HALLUCINATION_RETRY_ENABLED=false
# Increase retry attempts (default: 1, usually sufficient for self-correction)
export TRUVAG3_HALLUCINATION_MAX_RETRIES=2
How it works:
- Plan Generated: LLM produces an execution plan with agent references
- Validation: Each agent name is checked against the allowed list (agents shown in the prompt)
- Hallucination Detected: If an agent name isn't in the allowed list, validation fails
- Enhanced Retry: The LLM receives error feedback with the exact hallucinated name and the complete allowed agent list
- Self-Correction: LLM regenerates the plan using only valid agents
When to disable:
- Testing/Development: When using mock agents not in the catalog
- Custom Validation: When implementing your own agent validation logic
- Debugging: To see raw LLM output without intervention
Semantic Retry Configuration (Layer 4)
Semantic Retry is an advanced error recovery feature that uses LLM analysis to compute corrected parameters when standard error analysis cannot fix the issue. When a tool call fails (e.g., amount: 0 instead of amount: 46828.5), the contextual re-resolver uses full execution context—including the user's original query and source data from dependent steps—to compute the correct value.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_SEMANTIC_RETRY_ENABLED | true | Implemented | Enable Layer 4 semantic retry with LLM-based parameter re-computation | orchestration/interfaces.go |
TRUVAG3_SEMANTIC_RETRY_MAX_ATTEMPTS | 2 | Implemented | Maximum semantic retry attempts per step (0 = disabled) | orchestration/interfaces.go |
TRUVAG3_SEMANTIC_RETRY_INDEPENDENT_STEPS | true | Implemented | Enable semantic retry for steps without dependencies (first steps, parallel steps) | orchestration/interfaces.go |
How Semantic Retry Works:
- Error Detected: Tool returns an eligible, correction-permitted 4xx error (e.g. 400, 404, 409, 422); explicit
retryable:falsestops all same-step retries first - Layer 3 Analysis: ErrorAnalyzer determines it cannot fix the issue
- Layer 4 Activation: ContextualReResolver receives full execution context:
- User's original query (intent)
- Source data from dependent steps (what to compute from)
- Failed parameters and error message
- LLM Computation: The LLM analyzes the context and computes corrected parameters
- Retry: The step is retried with computed parameters
Hypothetical opt-in scenario: The shipped currency-tool sends
retryable:false for amount validation, so it stops rather than following this
flow. This example assumes explicit retryable:true permission for that
correctable condition and all executor correction gates passing.
User: "Sell 100 Tesla shares and convert proceeds to EUR"
Step 1 (stock-tool): Returns {price: 468.285}
Step 2 (currency-tool): Fails with "amount must be > 0" (amount: 0)
→ Layer 4 computes: amount = 100 × 468.285 = 46828.5
→ Retries currency conversion with corrected amount
Disabling Semantic Retry:
# Disable semantic retry entirely
export TRUVAG3_SEMANTIC_RETRY_ENABLED=false
# Or limit retry attempts
export TRUVAG3_SEMANTIC_RETRY_MAX_ATTEMPTS=1
# Disable only for independent steps (revert to old behavior)
export TRUVAG3_SEMANTIC_RETRY_INDEPENDENT_STEPS=false
Iterative Planning (Multi-Phase DAG)
Iterative planning allows the LLM planner to generate partial plans (terminal: false) and continue planning after intermediate results are available. This enables "discovery → action" queries like "find famous tourist destinations in Germany and get their weather" where later steps depend on the semantic content of earlier results.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_ITERATIVE_PLANNING_ENABLED | true | Implemented | Enable multi-phase iterative planning. When enabled, the LLM planner can signal partial plans that execute in phases. | orchestration/interfaces.go |
TRUVAG3_ITERATIVE_MAX_PHASES | 20 | Implemented | Maximum number of planning phases per request. If reached without a terminal plan, the orchestrator forces termination and synthesizes with available results. Most queries need at most 2. | orchestration/interfaces.go |
TRUVAG3_ITERATIVE_MAX_TOTAL_STEPS | 200 | Implemented | Maximum total steps across all phases. Prevents runaway plan generation. | orchestration/interfaces.go |
TRUVAG3_ITERATIVE_PHASE_TIMEOUT | 25m | Implemented | Configured phase budget (plan generation + execution), raised to the delegation allowance when larger. Earlier parent deadlines still apply; see Execution Limits. | orchestration/orchestrator.go |
TRUVAG3_ITERATIVE_MAX_VALIDATION_ROUNDS | 4 | Implemented | Regeneration attempts after the first validation failure; at most 1 + N validations. Malformed or intent-invalid regenerated JSON spends a round without validation; provider/boundary/cancellation errors and persistent continuation step-ID conflicts can stop earlier. | orchestration/interfaces.go |
TRUVAG3_ITERATIVE_REGENERATION_FEEDBACK_MAX_BYTES | 16384 | Implemented | Byte limit on encoded correction context added to a selected phase prompt. The effective value must be greater than zero when validated; environment handling follows the selected configuration-resolution mode. Omitted prior evidence is marked; failure to fit required feedback stops preparation. Not a whole-prompt/token limit. | orchestration/plan_attempt.go |
How Iterative Planning Works:
- Phase 1: LLM generates a partial plan (
terminal: false) with steps it can confidently plan - Execution: Orchestrator executes Phase 1 steps (parallel where possible)
- Phase 2: LLM receives Phase 1 results and plans next steps based on actual data
- Repeat: Until the LLM sets
terminal: trueor budget limits are reached
Example scenario:
User: "Tell me about Canada - weather at famous destinations and latest news"
Phase 1: country-info + web-search("famous destinations") + news → terminal: false
Phase 2: geocode(Vancouver, Banff, ...) + weather(coordinates) → terminal: true
Configuration:
# Enable iterative planning (default: true)
export TRUVAG3_ITERATIVE_PLANNING_ENABLED=true
# Allow up to 5 phases for complex queries
export TRUVAG3_ITERATIVE_MAX_PHASES=20
# Allow up to 30 total steps across all phases
export TRUVAG3_ITERATIVE_MAX_TOTAL_STEPS=30
# Increase phase timeout for slow external APIs
export TRUVAG3_ITERATIVE_PHASE_TIMEOUT=60s
# Disable iterative planning (all plans treated as single-shot)
export TRUVAG3_ITERATIVE_PLANNING_ENABLED=false
When to adjust:
- Increase
MAX_PHASES: Complex research queries requiring multiple discovery rounds - Increase
MAX_TOTAL_STEPS: Queries that fan out to many services (e.g., weather for 10+ cities) - Decrease
MAX_PHASES: Cost-sensitive deployments (each phase costs an LLM planning call) - Disable entirely: When all queries are closed-form with known parameters upfront
Result Trimming (Large Result Data Management)
When tool/agent responses are large (e.g., full web pages, large API payloads), they can overflow the LLM's token budget during synthesis. Result trimming uses a StructuralTrimmer to intelligently reduce result sizes before they are embedded in prompts — preserving JSON structure, key names, and representative samples while dropping repetitive array elements and deeply nested data.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_CONTINUATION_RESULT_MAX_CHARS | 10000 | Implemented | Non-JSON floor-preview size in continuation prompts (JSON is digested). | orchestration/interfaces.go |
TRUVAG3_CONTINUATION_RESULT_MAX_TOTAL_CHARS | 196608 | Implemented | Soft target for all step digests in the continuation prompt (newest-first; N-of-M eviction) — not a hard cap: failed steps and the newest successful step are always kept, and notes are appended after the budget decision. | orchestration/interfaces.go |
TRUVAG3_CONTINUATION_MAX_ESCALATIONS | 8 | Implemented | Max non-JSON→fast-model-summary escalations per continuation phase (0 disables). | orchestration/interfaces.go |
TRUVAG3_CONTINUATION_DIGEST_ARRAY_SAMPLE | 3 | Implemented | Digest array head-sample size. | orchestration/interfaces.go |
TRUVAG3_CONTINUATION_DIGEST_SCALAR_MAX | 200 | Implemented | Digest inline-string elision threshold. | orchestration/interfaces.go |
TRUVAG3_CONTINUATION_DIGEST_MAX_KEYS | 50 | Implemented | Digest per-object key cap. | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_ENABLED | true | Implemented | Enable structural trimming of large step results before prompt construction. | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_MAX_BYTES | 65536 | Implemented | Maximum bytes per individual step result (~16K tokens). Results exceeding this are structurally trimmed. | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_MAX_TOTAL_BYTES | 196608 | Implemented | Maximum total bytes across all step results in a synthesis prompt (~48K tokens). | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_MAX_MICRO_BYTES | 65536 | Implemented | Maximum bytes for source data in micro-resolution and semantic retry prompts (64 KiB, not a token allowance). Controls how much of the original step result is included when the LLM resolves missing parameters or retries failed steps. | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_MAX_AGENT_INPUT_BYTES | 0 | Implemented | Maximum bytes per parameter value for agent/tool HTTP calls. Default 0 = no cap (fidelity-first): tool→tool data flows raw so downstream steps receive the full upstream output. Set > 0 (or supply deps.AgentInputProcessor) to enable the byte-budget guard that trims large parameter values before they are sent to downstream agents or tools. | orchestration/interfaces.go |
TRUVAG3_RESULT_TRIM_SCHEMA_MAPPING_THRESHOLD | 16384 | Implemented | Result size threshold (bytes) above which schema-guided mapping is used instead of direct value extraction for micro-resolution. Set to 0 to disable schema-guided mapping entirely. | orchestration/interfaces.go |
How it works:
- Per-result trimming: Each step result is individually limited to
MaxResultBytes. TheStructuralTrimmerpreserves JSON structure while dropping array elements beyond the first few and truncating deeply nested objects. - Total budget enforcement: After individual trimming, if the combined results still exceed
MaxTotalPromptBytes, theBudgetAllocatorreduces them proportionally. Allocation is distillation-aware: a result that will be distilled is counted at its post-distill footprint (~TargetSize, viaEffectiveSizer), not its raw size, so one large distillable result doesn't starve the others' budgets. - Micro-resolution budgets: When the LLM needs to resolve missing parameters from prior step results,
MaxMicroResolutionBytescontrols how much source data is included in the prompt. For very large results, schema-guided mapping (triggered aboveSchemaGuidedMappingThreshold) uses JSON schema analysis instead of passing raw data. - Agent input trimming (opt-in):
MaxAgentInputBytesdefaults to0(no cap) — tool→tool data flows raw so downstream steps receive the full upstream output (fidelity-first). Set it> 0to trim individual parameter values before they are sent to downstream agents/tools via HTTP, or supplydeps.AgentInputProcessorfor custom input shaping. - Fallback: Non-JSON results are truncated with a
... [trimmed]suffix.
Configuration:
# Disable result trimming (not recommended for production — may cause token overflow)
export TRUVAG3_RESULT_TRIM_ENABLED=false
# Example of a smaller per-result limit for tighter contexts
export TRUVAG3_RESULT_TRIM_MAX_BYTES=32768 # 32 KB per result
# Example of a smaller total result budget
export TRUVAG3_RESULT_TRIM_MAX_TOTAL_BYTES=65536 # 64 KB total
# Increase micro-resolution budget for complex data dependencies
export TRUVAG3_RESULT_TRIM_MAX_MICRO_BYTES=131072 # 128 KB for resolution prompts
# Increase agent input budget for data-heavy tool calls
export TRUVAG3_RESULT_TRIM_MAX_AGENT_INPUT_BYTES=131072 # 128 KB per parameter value
# Disable schema-guided mapping (always use direct value extraction)
export TRUVAG3_RESULT_TRIM_SCHEMA_MAPPING_THRESHOLD=0
Programmatic configuration:
config := orchestration.DefaultConfig()
config.ResultTrim = orchestration.ResultTrimConfig{
Enabled: true,
MaxResultBytes: 65536, // 64 KiB per result
MaxTotalPromptBytes: 196608, // 192 KiB total
MaxMicroResolutionBytes: 65536, // 64 KB for micro-resolution source data
MaxAgentInputBytes: 0, // 0 = no cap (fidelity-first); set > 0 to enable the guard
SchemaGuidedMappingThreshold: 16384, // 16 KB — use schema mapping above this
}
When to adjust:
- Increase limits: When LLM synthesis responses lack detail because results were trimmed too aggressively
- Decrease limits: When hitting token limits or getting slow synthesis responses
- Disable: Only for debugging — production deployments should always have trimming enabled
Result Distillation (Default-On LLM Summarization)
For results that are extremely large or contain domain-specific content that structural trimming cannot adequately compress, LLM distillation provides a two-stage pipeline: structural pre-filtering followed by LLM-based summarization. It is on by default (opt-out) and serves as the primary compaction path for oversized results when the orchestrator has an AIClient and Result Trimming is enabled; without an AIClient the framework falls back to the structural floor.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_RESULT_DISTILL_ENABLED | true | Implemented | Default-on LLM-based result distillation. Active when an AIClient is configured and TRUVAG3_RESULT_TRIM_ENABLED is true; otherwise the structural floor is used. Set =false to opt out (e.g. for cost- or latency-sensitive deployments). | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_THRESHOLD | 16384 | Implemented | Minimum result size (bytes) to trigger distillation. Below this threshold, structural trimming is used instead. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_PREFILTER | 131072 | Implemented | StructuralTrimmer budget (bytes) for Stage 1 pre-filtering. Reduces input to the LLM before distillation. 128 KB — fits the 64K fast-tier context floor. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_TARGET | 4096 | Implemented | Target output size for the LLM distillation (Stage 2). The LLM summarizes the pre-filtered result to approximately this size. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_MODEL | fast | Implemented | Portable alias or model name for distillation LLM calls. Default fast resolves for Anthropic, OpenAI-compatible, and Gemini providers. Bedrock has no alias catalog; for a chain containing Bedrock, set ResultDistill.Model or WithResultDistillModel to an empty string programmatically so each entry uses its configured default. The environment loader ignores an empty value. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_CACHE_TTL | 5m | Implemented | How long a distillation result stays cached (keyed by result content + instruction + query + budget). Fail-open — a nil cache disables it with no overhead. Go duration format. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_DEADLINE | 45s | Implemented | Wall-clock bound on a single compaction in the synthesis hot path. On timeout, fails open to the structural floor (single-call path) or returns the chunks that completed plus a "partial" disclosure (map-reduce path). Go duration format; the env var accepts only positive values — disable the deadline via the programmatic CompactionDeadline: 0. Keep it under the HTTP gateway timeout. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_CONTEXT_TOKENS | 150000 | Implemented | Usable context (tokens) of the compaction model. Results estimated above this are chunked and map-reduced instead of sent in one call (~525 KB at the default, using the framework's ≈3.5 bytes/token counter). | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_MAP_CONCURRENCY | 8 | Implemented | Max chunks compacted concurrently in the map-reduce path. ≤ 0 falls back to the default. | orchestration/interfaces.go |
TRUVAG3_RESULT_DISTILL_MAPREDUCE_THRESHOLD | 0 | Implemented | Routes results larger than this (bytes) to map-reduce even when they fit the model context, so the whole result reaches an LLM instead of only the pre-filtered head. Independent of CONTEXT_TOKENS. 0 = disabled (context-only routing) — a deliberate deviation from the repo-wide > 0 convention so an explicit 0 can disable a future nonzero default. A positive value below PREFILTER is ignored with a factory warning (a result that small is one chunk — no fan-out benefit over the single-call distill). | orchestration/interfaces.go |
How the two-stage pipeline works:
- Stage 1 — Structural Pre-Filter: The
StructuralTrimmerreduces the large result toPreFilterBudgetbytes, preserving JSON structure and key data points. - Stage 2 — LLM Distillation: An LLM call summarizes the pre-filtered result to approximately
TargetSizebytes, preserving the most relevant information for the user's query. - Map-reduce (very large results): When a result is estimated above the model's usable context (
ModelContextTokens) — or exceeds the opt-inMapReduceThresholdBytesbyte threshold (0/disabled by default), independent of the token estimate — it is chunked and each chunk is distilled concurrently (capped byMapConcurrency), then the chunk outputs are reduced into a final distillation. The byte threshold forces the whole result through map-reduce so an LLM sees all of it, not just the pre-filtered head. - Caching (opt-in): When a
DigestCacheis supplied viadeps.DistillCache— there is no cache by default — identical (result + instruction + query + budget) inputs reuse a prior distillation forCacheTTL, so scheduled and repetitive runs become cache hits instead of repeat LLM calls. Failed or partial outputs are not cached. (CacheTTL=0does not reliably disable caching — a Redis-backed cache treats 0 as "no expiration"; to disable, don't supply a cache.) - Deadline & fallback: Each compaction is bounded by
CompactionDeadline. On timeout or LLM error, the call fails open — the single-call path uses the Stage 1 pre-filtered result directly; the map-reduce path returns the chunks that completed plus an honest "partial" disclosure.
Configuration:
# Distillation is on by default — set =false to opt out
export TRUVAG3_RESULT_DISTILL_ENABLED=true
# Only distill results larger than 64 KB (default 16384 / 16 KB)
export TRUVAG3_RESULT_DISTILL_THRESHOLD=65536
# Pre-filter budget fed into the LLM (default 131072 / 128 KB)
export TRUVAG3_RESULT_DISTILL_PREFILTER=131072
# Target smaller output from LLM
export TRUVAG3_RESULT_DISTILL_TARGET=2048
export TRUVAG3_RESULT_DISTILL_MODEL=fast
# Cache identical distillations for longer (default 5m)
export TRUVAG3_RESULT_DISTILL_CACHE_TTL=10m
# Bound a single compaction in the synthesis hot path (default 45s; env accepts positive durations only)
export TRUVAG3_RESULT_DISTILL_DEADLINE=30s
# Above this model context (tokens), chunk → map-reduce (default 150000)
export TRUVAG3_RESULT_DISTILL_CONTEXT_TOKENS=150000
# Concurrent chunk distillations in the map-reduce path (default 8)
export TRUVAG3_RESULT_DISTILL_MAP_CONCURRENCY=8
# Byte threshold that routes a result to map-reduce even when it fits the model
# context, so the whole result reaches an LLM (0 = disabled; default 0)
export TRUVAG3_RESULT_DISTILL_MAPREDUCE_THRESHOLD=0
Programmatic configuration:
config := orchestration.DefaultConfig()
config.ResultDistill = orchestration.ResultDistillConfig{
Enabled: true,
DistillThreshold: 65536, // Only distill results > 64 KB
PreFilterBudget: 131072, // 128 KB pre-filter budget (default)
TargetSize: 2048, // 2 KB target output
Model: "fast", // Portable across catalog-backed providers
CacheTTL: 5 * time.Minute, // Reuse identical distillations (default 5m)
CompactionDeadline: 45 * time.Second, // Hot-path bound; 0 disables (default 45s)
ModelContextTokens: 150000, // Above this (tokens), chunk → map-reduce (default)
MapReduceThresholdBytes: 0, // Byte threshold → map-reduce even if it fits context; 0 = disabled (default)
MapConcurrency: 8, // Concurrent chunk distillations (default)
}
Why it's on by default:
- Large API responses: When tools return full web pages, large JSON payloads, or document content
- Quality over structural trimming: An LLM preserves semantically relevant content that structural trimming would drop
- Domain-specific content: When structural trimming loses important semantic content that only an LLM can preserve
When to opt out (=false):
- Cost-sensitive deployments: Each oversized result adds an LLM distillation call
- Low-latency requirements: The extra LLM call adds latency
- No AIClient configured: Distillation needs an AIClient; without one the framework already falls back to the structural floor, so nothing extra is needed
Example
# Base HTTP timeout per tool/agent call; enclosing request deadlines still apply
export TRUVAG3_ORCHESTRATION_TIMEOUT=5m
# For high-concurrency execution
export TRUVAG3_EXECUTION_MAX_CONCURRENCY=10
# Execution allowance added to the HITL timeout for delegated orchestrator calls
export TRUVAG3_EXECUTION_STEP_TIMEOUT=180s
# For step retry backoff tuning (exponential backoff between retries)
export TRUVAG3_STEP_RETRY_INITIAL_DELAY=500ms
export TRUVAG3_STEP_RETRY_MAX_DELAY=10s
# For capability service integration
export TRUVAG3_CAPABILITY_SERVICE_URL="http://capability-service:8080"
export TRUVAG3_CAPABILITY_TOP_K=30
export TRUVAG3_CAPABILITY_THRESHOLD=0.75
# For plan parse retry configuration
export TRUVAG3_PLAN_RETRY_ENABLED=true
export TRUVAG3_PLAN_RETRY_MAX=2
# For hallucination detection (validates LLM doesn't invent agents)
export TRUVAG3_HALLUCINATION_VALIDATION_ENABLED=true
export TRUVAG3_HALLUCINATION_RETRY_ENABLED=true
export TRUVAG3_HALLUCINATION_MAX_RETRIES=1
# For semantic retry configuration (Layer 4)
export TRUVAG3_SEMANTIC_RETRY_ENABLED=true
export TRUVAG3_SEMANTIC_RETRY_MAX_ATTEMPTS=2
export TRUVAG3_SEMANTIC_RETRY_INDEPENDENT_STEPS=true
# For iterative planning (multi-phase DAG)
export TRUVAG3_ITERATIVE_PLANNING_ENABLED=true
export TRUVAG3_ITERATIVE_MAX_PHASES=20
export TRUVAG3_ITERATIVE_MAX_TOTAL_STEPS=200
export TRUVAG3_ITERATIVE_PHASE_TIMEOUT=25m
# Continuation prompt budgeting (Phase 14: JSON results are digested; non-JSON gets a floor preview)
export TRUVAG3_CONTINUATION_RESULT_MAX_CHARS=10000 # non-JSON floor-preview size
export TRUVAG3_CONTINUATION_RESULT_MAX_TOTAL_CHARS=196608 # soft target (192 KiB); newest-first, N-of-M eviction (failed + newest kept)
export TRUVAG3_CONTINUATION_MAX_ESCALATIONS=8 # max non-JSON→fast-model-summary escalations/phase (0 disables)
export TRUVAG3_CONTINUATION_DIGEST_ARRAY_SAMPLE=3 # digest array head-sample size
export TRUVAG3_CONTINUATION_DIGEST_SCALAR_MAX=200 # digest inline-string elision threshold
export TRUVAG3_CONTINUATION_DIGEST_MAX_KEYS=50 # digest per-object key cap
# For result trimming (enabled by default)
export TRUVAG3_RESULT_TRIM_ENABLED=true
export TRUVAG3_RESULT_TRIM_MAX_BYTES=65536
export TRUVAG3_RESULT_TRIM_MAX_TOTAL_BYTES=196608
export TRUVAG3_RESULT_TRIM_MAX_MICRO_BYTES=65536
export TRUVAG3_RESULT_TRIM_MAX_AGENT_INPUT_BYTES=0 # 0 = no cap (fidelity-first); set > 0 to enable the guard
export TRUVAG3_RESULT_TRIM_SCHEMA_MAPPING_THRESHOLD=16384
# For result distillation (on by default; opt out with =false)
export TRUVAG3_RESULT_DISTILL_ENABLED=true
export TRUVAG3_RESULT_DISTILL_THRESHOLD=16384
export TRUVAG3_RESULT_DISTILL_PREFILTER=131072
export TRUVAG3_RESULT_DISTILL_TARGET=4096
export TRUVAG3_RESULT_DISTILL_MODEL=fast
export TRUVAG3_RESULT_DISTILL_CACHE_TTL=5m
export TRUVAG3_RESULT_DISTILL_DEADLINE=45s
export TRUVAG3_RESULT_DISTILL_CONTEXT_TOKENS=150000
export TRUVAG3_RESULT_DISTILL_MAP_CONCURRENCY=8
export TRUVAG3_RESULT_DISTILL_MAPREDUCE_THRESHOLD=0
LLM Debug Configuration
The removed TRUVAG3_LLM_DEBUG_REDIS_DB and
TRUVAG3_LLM_DEBUG_KEY_PREFIX are rejected when nonempty by owning Redis LLM
recorder/debug-store constructors. Use the canonical DB-0 deployment namespace
or typed keyspace option; empty values are absent, not a request for a legacy
key layout. New completion fields reuse existing enablement/retention settings.
Configure LLM debug payload storage for debugging orchestration issues. This feature captures full LLM request/response payloads to help diagnose planning failures, parse errors, and unexpected AI behavior.
Important: This feature is disabled by default to minimize storage overhead. Enable only when debugging is needed.
LLM Debug Variables
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_LLM_DEBUG_ENABLED | false | Implemented | Enable LLM debug payload storage | orchestration/interfaces.go |
TRUVAG3_LLM_DEBUG_TTL | 72h (3 days) | Implemented | Base retention for successful debug records; a longer execution-lineage floor is preserved | orchestration/redis_llm_debug_store.go |
TRUVAG3_LLM_DEBUG_ERROR_TTL | 72h (3 days) | Implemented | Base retention for error debug records; lineage, HITL, or investigation retention may extend it | orchestration/redis_llm_debug_store.go |
How It Works
When enabled, the orchestrator automatically captures:
- Request payloads: Full prompts sent to the LLM
- Response payloads: Complete LLM responses (parsed and raw)
- Timing metadata: Duration, timestamps, retry attempts
- Error context: The error value supplied to the recorder. A small set of legacy executor, skills, and provider paths still transforms errors before recording; this is not a general sanitization guarantee.
The built-in recorder preserves the prompt and response values it receives. This feature is therefore an informed opt-in: applications own access control, encryption, retention policy, and any explicit sanitization required for their data.
Example: Enable Debug Storage
# Enable LLM debug storage
export TRUVAG3_LLM_DEBUG_ENABLED=true
# Customize retention for debugging (optional; defaults are 72h for both)
export TRUVAG3_LLM_DEBUG_TTL=48h
export TRUVAG3_LLM_DEBUG_ERROR_TTL=168h
Example: Kubernetes Deployment
env:
- name: TRUVAG3_LLM_DEBUG_ENABLED
value: "true"
- name: TRUVAG3_LLM_DEBUG_TTL
value: "48h"
- name: TRUVAG3_LLM_DEBUG_ERROR_TTL
value: "168h"
Viewing Debug Records
Use the Registry Viewer App to view captured debug records:
- Navigate to the "LLM Debug" tab in the sidebar
- Browse records by agent, timestamp, or status (success/error)
- Inspect full request/response payloads for troubleshooting
Execution Debug Store Configuration
Configure execution debug storage for DAG visualization and debugging. This feature stores complete plan execution records (plan + result) to enable visualization of LLM-based plan execution as a directed acyclic graph (DAG).
Important: This feature is disabled by default to minimize storage overhead. Enable only when DAG visualization or execution debugging is needed.
Execution Debug Store Variables
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_EXECUTION_DEBUG_STORE_ENABLED | false | Implemented | Enable/disable execution debug storage | orchestration/interfaces.go |
TRUVAG3_EXECUTION_DEBUG_TTL | 72h (3 days) | Implemented | Base retention for successful execution records; related-lineage promotion may extend it | orchestration/redis_execution_store.go |
TRUVAG3_EXECUTION_DEBUG_ERROR_TTL | 72h (3 days) | Implemented | Base retention when the execution result fails or request lifecycle is failed/cancelled, including post-tool synthesis failures with successful steps. Existing longer/persistent retention, HITL approval windows and investigation extensions may retain records longer | orchestration/redis_execution_store.go |
TRUVAG3_EXECUTION_DEBUG_KEY_PREFIX | truvag3:v1:default:execution-debug: | Generic provider only | Logical prefix for generic StorageProvider execution keys; rejected by selected Redis backends. Use TRUVAG3_REDIS_NAMESPACE or typed Redis keyspace options for Redis isolation. | orchestration/execution_store.go |
TRUVAG3_EXECUTION_DEBUG_CONVERSATION_QUERY_LIMIT | 1000 | Implemented | Maximum executions returned by one framework conversation lookup | orchestration/interfaces.go |
TRUVAG3_EXECUTION_DEBUG_INDEX_SCAN_LIMIT | 5000 | Implemented | Maximum conversation-index members scanned by one framework lookup, including stale members | orchestration/interfaces.go |
TRUVAG3_EXECUTION_STORE_WRITE_TIMEOUT | 5s | Implemented | Per-write timeout for asynchronous execution-debug persistence. Code configuration through WithExecutionStoreWriteTimeout has higher precedence. | orchestration/config_resolution.go |
TRUVAG3_EXECUTION_CLEANUP_TIMEOUT | 5s | Implemented | Joined request-resource cleanup deadline, independent of caller cancellation. Explicit empty/invalid/non-positive values fail in strict and compatible modes. Error-returning factories reject before bootstrap; legacy errorless constructors retain the error and reject Start/execution. WithExecutionCleanupTimeout overrides valid env settings. | orchestration/execution_resources.go |
The two conversation limits accept only positive integers. Missing, malformed,
zero, or negative values retain the safe defaults. Environment values populate
DefaultOrchestratorConfig. A positive programmatic value applied after
default construction, or passed directly in ExecutionStoreConfig, is
authoritative. The per-call limit passed to ListByConversationID is clamped
to ConversationQueryLimit; stale-index work is independently bounded by
ConversationIndexScanLimit.
The TTL variables select the initial minimum, not an absolute deletion time. An interrupted record receives at least the larger of the normal TTL, error TTL, and remaining approval window. Storing or explicitly extending a related execution promotes the available lineage without shortening an existing longer or persistent lifetime. Final execution recording applies the corresponding minimum to current and root LLM-debug evidence, including late writes.
Correlation and baggage protocol limits
These limits are protocol constants rather than environment settings:
| Value | Limit | Contract |
|---|---|---|
conversation_id | 1–512 bytes | Visible-ASCII W3C-safe subset validated by core.ValidateConversationID |
| W3C baggage members | 64 | telemetry.MaxBaggageItems |
| Baggage key | 128 bytes | telemetry.MaxBaggageKeyLength |
| Baggage value | 512 bytes | telemetry.MaxBaggageValueLength |
| Complete serialized W3C baggage value | 8192 bytes | Includes separators, encoding, and member properties |
conversation_id is framework correlation metadata, not an application
session_id. A chat application may deliberately use the same opaque value
for both, but the framework does not infer that mapping. Conversation identity
is established on the first turn even when conversation_turns is empty.
Features (Same as LLM Debug Store)
The execution debug store has full feature parity with the LLM Debug Store:
- Gzip compression: Large payloads (>100KB) are automatically compressed
- Layer 1 resilience: Built-in retry with exponential backoff (3 retries, 100ms-2s backoff)
- Layer 2 resilience: Optional circuit breaker injection via
WithExecutionDebugCircuitBreaker() - Layer 3 resilience: NoOp fallback when Redis is unavailable
How It Works
When enabled, the orchestrator automatically stores:
- Plan data: LLM-generated routing plans with step dependencies
- Execution results: Step-by-step results with timing, status, and responses
- Trace correlation: Links to distributed tracing (Jaeger) via trace IDs
- Metadata: Investigation notes and custom annotations
Storage Key Patterns
Canonical provider composition derives execution-debug keys from
TRUVAG3_REDIS_NAMESPACE:
| Key Pattern | Purpose |
|---|---|
truvag3:v1:<deployment>:execution-debug:{<deployment>:execution-debug:<request_id>}:record | Main execution record (plan + result) |
truvag3:v1:<deployment>:execution-debug:index:recent | Sorted index for listing recent executions |
truvag3:v1:<deployment>:execution-debug:index:trace:<trace_id> | Trace ID → Request ID mapping |
truvag3:v1:<deployment>:execution-debug:index:conversation:<sha256(conversation_id)> | Chronological execution membership for one conversation |
The execution record's metadata.conversation_id is authoritative. The hashed
conversation index is a bounded lookup accelerator and may be lazily cleaned
when records expire; index maintenance never changes the execution record.
Request-local record and retention keys share a Redis Cluster slot. The recent, trace, and conversation indexes are repairable projections and are updated as separate single-key operations when they cannot participate in that slot.
Example: Enable Execution Debug Storage
# Enable execution debug storage
export TRUVAG3_EXECUTION_DEBUG_STORE_ENABLED=true
# Use default TTLs (72h / 3 days for both success and errors)
# Or customize retention:
export TRUVAG3_EXECUTION_DEBUG_TTL=48h
export TRUVAG3_EXECUTION_DEBUG_ERROR_TTL=336h # 14 days
# Optional bounded conversation lookup limits
export TRUVAG3_EXECUTION_DEBUG_CONVERSATION_QUERY_LIMIT=1000
export TRUVAG3_EXECUTION_DEBUG_INDEX_SCAN_LIMIT=5000
Example: Multi-Tenant Deployment
# Keep cooperating producers and viewers in the same versioned deployment scope.
export TRUVAG3_EXECUTION_DEBUG_STORE_ENABLED=true
export TRUVAG3_REDIS_NAMESPACE=myapp-prod
# Request-local records use the canonical execution-debug hash-tagged layout.
Example: Kubernetes Deployment
env:
# Enable execution debug storage
- name: TRUVAG3_EXECUTION_DEBUG_STORE_ENABLED
value: "true"
# Custom retention (optional)
- name: TRUVAG3_EXECUTION_DEBUG_TTL
value: "48h"
- name: TRUVAG3_EXECUTION_DEBUG_ERROR_TTL
value: "168h"
# Versioned deployment namespace isolation (optional)
- name: TRUVAG3_REDIS_NAMESPACE
value: "myteam"
- name: TRUVAG3_EXECUTION_DEBUG_CONVERSATION_QUERY_LIMIT
value: "1000"
- name: TRUVAG3_EXECUTION_DEBUG_INDEX_SCAN_LIMIT
value: "5000"
Viewing Execution Records
Use the Registry Viewer App to visualize execution DAGs:
- Navigate to the "Executions" tab in the sidebar
- Browse recent executions with success/failure status
- Click on an execution to view the DAG visualization
- Inspect step details, timing, and results
- Link to Jaeger traces for distributed tracing correlation
Storage Provider
The provider-neutral request-path contract is ExecutionStore. New application
bootstrap code should supply that capability through OrchestrationBackends;
the included redisprovider package is the default Redis composition, while a
PostgreSQL, DynamoDB, or other provider implements the same narrow contract.
NewRedisExecutionDebugStore() remains an environment-aware compatibility
constructor. NewExecutionStoreWithProvider() is a separate adapter for the
older generic StorageProvider interface; the direct Redis store does not use
that interface. Applications that already own Redis connection routing can use
NewRedisExecutionDebugStoreWithClient, which does not read Redis connection or
database environment variables and leaves the supplied client open.
Human-in-the-Loop (HITL) Configuration
Configure Human-in-the-Loop (HITL) checkpoints for human oversight of AI-generated plans and sensitive operations. HITL enables pausing execution for human approval before proceeding with critical steps.
Important: HITL is disabled by default. Enable it via
TRUVAG3_HITL_ENABLED=truewhen human oversight is required.
Core HITL Variables
Source: all HITL variables below are loaded by
DefaultConfig()inorchestration/interfaces.go— look for theHITLConfigstruct and the "HITL configuration from environment" block.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_HITL_ENABLED | false | Implemented | Enable/disable HITL globally | orchestration/interfaces.go |
TRUVAG3_HITL_REQUIRE_PLAN_APPROVAL | false | Implemented | Require human approval for all LLM-generated plans | orchestration/interfaces.go |
TRUVAG3_HITL_SENSITIVE_CAPABILITIES | (empty) | Implemented | Comma-separated list of capabilities requiring both plan AND step approval | orchestration/interfaces.go |
TRUVAG3_HITL_SENSITIVE_AGENTS | (empty) | Implemented | Comma-separated list of agents requiring both plan AND step approval | orchestration/interfaces.go |
TRUVAG3_HITL_STEP_SENSITIVE_CAPABILITIES | (empty) | Implemented | Comma-separated list of capabilities requiring step-only approval (no plan approval) | orchestration/interfaces.go |
TRUVAG3_HITL_STEP_SENSITIVE_AGENTS | (empty) | Implemented | Comma-separated list of agents requiring step-only approval (no plan approval) | orchestration/interfaces.go |
TRUVAG3_HITL_DEFAULT_TIMEOUT | 5m | Implemented | Timeout for human response before auto-action | orchestration/interfaces.go |
TRUVAG3_HITL_ESCALATE_AFTER_RETRIES | 3 | Implemented | Number of retries before escalating to human | orchestration/interfaces.go |
HITL Storage Variables
| Variable | Default | Status | Description | Source |
|---|
HITL Handler Variables
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_HITL_WEBHOOK_URL | (none) | Implemented | Webhook URL for checkpoint notifications | Application-specific |
HITL Expiry Behavior Variables
These variables control what happens when a checkpoint times out (expires) without a human response. See HITL User Guide: Expiry Behavior for detailed usage.
| Variable | Default | Values | Status | Description | Source |
|---|---|---|---|---|---|
TRUVAG3_HITL_DEFAULT_ACTION | reject | approve, reject, abort | Implemented | Action to take when apply_default expiry behavior is used. Fail-safe default is reject (HITL enabled = require explicit approval). | orchestration/interfaces.go |
TRUVAG3_HITL_STREAMING_EXPIRY | implicit_deny | implicit_deny, apply_default | Implemented | Expiry behavior for streaming (SSE) requests. implicit_deny = status→expired, no action. apply_default = auto-resume with DefaultAction. | orchestration/hitl_checkpoint_store.go |
TRUVAG3_HITL_NON_STREAMING_EXPIRY | apply_default | implicit_deny, apply_default | Implemented | Expiry behavior for non-streaming (HTTP 202) requests. apply_default = auto-apply DefaultAction on timeout. | orchestration/hitl_checkpoint_store.go |
TRUVAG3_HITL_DEFAULT_REQUEST_MODE | non_streaming | streaming, non_streaming | Implemented | Default request mode when not explicitly set via WithRequestMode(). A warning is logged when this fallback is used. | orchestration/hitl_checkpoint_store.go |
Expiry Behavior Matrix (see HITL User Guide: Expiry Behavior Matrix):
| Request Mode | Expiry Behavior | What Happens |
|---|---|---|
Streaming + implicit_deny | Status → expired | User saw dialog but didn't respond. No action taken. |
Streaming + apply_default | Status → expired_approved/rejected | Auto-resume enabled (see Auto-Resume) |
Non-Streaming + apply_default | Status → expired_approved/rejected | DefaultAction applied automatically |
Non-Streaming + implicit_deny | Status → expired | Require manual intervention |
HITL Expiry Processor Variables
The expiry processor is a lifecycle-owned core.Runnable that scans a
provider-neutral ExpiredCheckpointSource and processes claimed checkpoints
according to the configured action. Register it before Framework.Run(). See
HITL User Guide: Auto-Resume
for the auto-approval flow.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_HITL_EXPIRY_ENABLED | true | Implemented | Enable/disable the lifecycle-owned expiry processor. Set to false to disable automatic checkpoint expiration. | orchestration/hitl_checkpoint_store.go |
TRUVAG3_HITL_EXPIRY_INTERVAL | 10s | Implemented | How often the processor scans the configured expiry source. Lower values mean faster detection but more backend load. | orchestration/hitl_checkpoint_store.go |
TRUVAG3_HITL_EXPIRY_BATCH_SIZE | 100 | Implemented | Maximum checkpoints processed per scan cycle. Prevents overwhelming the system when many expire simultaneously. | orchestration/hitl_checkpoint_store.go |
TRUVAG3_HITL_EXPIRY_DELIVERY | at_most_once | Implemented | Callback delivery guarantee: at_most_once (safe default, no retries) or at_least_once (may retry, callback must be idempotent). | orchestration/hitl_checkpoint_store.go |
TRUVAG3_HITL_EXPIRY_CLAIM_LEASE | 30s | Implemented | Positive lease duration for an atomic expired-checkpoint claim. Load with LoadCheckpointExpiryRuntimeConfigFromEnvironment; a later WithCheckpointExpiryRuntimeConfig option wins. | orchestration/checkpoint_expiry_processor.go |
HITL Approval Modes
HITL supports two approval modes based on risk level:
| Mode | Variables | Behavior |
|---|---|---|
| Full HITL (Plan + Step) | TRUVAG3_HITL_SENSITIVE_CAPABILITIES, TRUVAG3_HITL_SENSITIVE_AGENTS | Pauses at plan generation for approval, then pauses again at each matching step |
| Step-Only | TRUVAG3_HITL_STEP_SENSITIVE_CAPABILITIES, TRUVAG3_HITL_STEP_SENSITIVE_AGENTS | Skips plan approval, only pauses when the specific step is about to execute |
Use Full HITL for high-risk operations (e.g., transfer_funds, delete_account) where you want to review the entire plan before any execution.
Use Step-Only for medium-risk operations (e.g., get_balance, view_orders) where you trust the plan but want confirmation before each action.
Example: Full HITL Configuration
# Enable HITL with plan approval
export TRUVAG3_HITL_ENABLED=true
export TRUVAG3_HITL_REQUIRE_PLAN_APPROVAL=true
# Configure high-risk operations (plan + step approval)
export TRUVAG3_HITL_SENSITIVE_CAPABILITIES=transfer_funds,delete_account,send_email
export TRUVAG3_HITL_SENSITIVE_AGENTS=payment-service,admin-tool
# Timeout and escalation
export TRUVAG3_HITL_DEFAULT_TIMEOUT=5m
export TRUVAG3_HITL_ESCALATE_AFTER_RETRIES=3
# Redis storage (shared DB 0, isolated by deployment and HITL hash tag)
export TRUVAG3_REDIS_NAMESPACE=production
# Webhook for notifications
export TRUVAG3_HITL_WEBHOOK_URL=https://my-service/internal/hitl-webhook
Example: Step-Only HITL Configuration
# Enable HITL (plan approval NOT required globally)
export TRUVAG3_HITL_ENABLED=true
export TRUVAG3_HITL_REQUIRE_PLAN_APPROVAL=false
# Full HITL (plan + step approval) for high-risk operations
export TRUVAG3_HITL_SENSITIVE_CAPABILITIES=transfer_funds,delete_account
export TRUVAG3_HITL_SENSITIVE_AGENTS=payment-service
# Step-only approval (no plan pause) for medium-risk operations
export TRUVAG3_HITL_STEP_SENSITIVE_CAPABILITIES=get_balance,view_orders,send_notification
export TRUVAG3_HITL_STEP_SENSITIVE_AGENTS=read-service,notification-tool
# Timeout and storage
export TRUVAG3_HITL_DEFAULT_TIMEOUT=5m
Example: Kubernetes Deployment
env:
# Enable HITL
- name: TRUVAG3_HITL_ENABLED
value: "true"
- name: TRUVAG3_HITL_REQUIRE_PLAN_APPROVAL
value: "true"
# Sensitive operations
- name: TRUVAG3_HITL_SENSITIVE_CAPABILITIES
value: "transfer_funds,delete_account"
- name: TRUVAG3_HITL_SENSITIVE_AGENTS
value: "payment-service"
# Step-only operations
- name: TRUVAG3_HITL_STEP_SENSITIVE_CAPABILITIES
value: "get_balance,view_orders"
# Timeout
- name: TRUVAG3_HITL_DEFAULT_TIMEOUT
value: "10m"
# Webhook
- name: TRUVAG3_HITL_WEBHOOK_URL
value: "http://notification-service/hitl-webhook"
Viewing HITL Checkpoints
Use the Registry Viewer App or the HITL API endpoints to monitor pending checkpoints:
GET /hitl/checkpoints- List pending checkpointsGET /hitl/checkpoints/{id}- Get checkpoint detailsPOST /hitl/command- Submit approval/rejection decision (with{"checkpoint_id": "...", "type": "approve|reject"})POST /hitl/resume-sync/{id}- Resume execution after approval (JSON response)POST /hitl/resume/{id}- Resume execution after approval (SSE stream)
See HUMAN_IN_THE_LOOP_USER_GUIDE.md for detailed usage and examples.
Async Task Configuration
Configure asynchronous task processing for long-running operations. The async task system enables the HTTP 202 + Polling pattern for operations that may take minutes to complete.
Related Framework Types
The async task system uses these core framework types (no additional env vars required):
core.Task- Task data structure with status, progress, resultcore.TaskQueue- Redis-backed task queue interfacecore.TaskStore- Redis-backed task state storagecore.TaskWorkerPool- Worker pool implementationorchestration.TaskAPIHandler- HTTP API handler for task endpoints
See Async Orchestration Guide for detailed usage.
Default Redis orchestration preset limits
redisprovider.NewDefaultBackends loads these variables automatically for the
selected backend roles. Lower-layer callers use
redisprovider.LoadOptionsFromEnvironment explicitly, then
redisprovider.ConfigureOptions when code configuration must win. Present
empty, malformed, non-positive, or overflowing durations are rejected before
backends are returned; later code options do not suppress that validation.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_EXECUTION_DEBUG_TTL | 72h (3 days) | Implemented | Successful execution retention applied to the actual Redis execution store by the preset | orchestration/redisprovider/options.go |
TRUVAG3_EXECUTION_DEBUG_ERROR_TTL | 72h (3 days) | Implemented | Failed/cancelled execution retention applied by the Redis preset; WithExecutionStoreConfig overrides valid environment values | orchestration/redisprovider/options.go |
TRUVAG3_LLM_DEBUG_TTL | 72h (3 days) | Implemented | Successful LLM-debug retention applied by the Redis preset | orchestration/redisprovider/options.go |
TRUVAG3_LLM_DEBUG_ERROR_TTL | 72h (3 days) | Implemented | Failed LLM-debug retention applied by the Redis preset | orchestration/redisprovider/options.go |
TRUVAG3_HITL_CHECKPOINT_TTL | 24h | Implemented | Checkpoint retention applied by the Redis preset | orchestration/redisprovider/options.go |
TRUVAG3_WORKFLOW_STATE_TTL | 24h | Implemented | Retention for workflow execution state composed by the default Redis backend preset | orchestration/redisprovider/options.go |
TRUVAG3_TASK_QUEUE_RETRY_ATTEMPTS | 3 | Implemented | Positive number of Redis task-queue operation attempts | orchestration/redisprovider/options.go |
TRUVAG3_TASK_QUEUE_RETRY_DELAY | 100ms | Implemented | Positive delay between Redis task-queue operation attempts | orchestration/redisprovider/options.go |
TRUVAG3_TASK_INDEX_RECONCILE_INTERVAL | 1m | Implemented | Positive interval for the framework-owned task-index repair runnable | orchestration/redisprovider/options.go |
TRUVAG3_TASK_INDEX_RECONCILE_MAX_IDS | 1000 | Implemented | Positive maximum IDs examined by one bounded task-index repair pass | orchestration/redisprovider/options.go |
TRUVAG3_SCHEDULER_MAX_SCHEDULES | 10000 | Implemented | Positive per-deployment schedule capacity enforced before inserting a new schedule | orchestration/redisprovider/options.go |
Scheduled Execution Configuration
Configure the scheduled-execution subsystem: delayed and recurring task execution across agents. The system has two components (scheduler-tool produces schedules, scheduled-executor consumes and dispatches them). Code-level configuration via ExecutorDeps fields takes priority over environment variables.
Scheduler-Tool (Producer)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_SCHEDULER_TICK_INTERVAL | 5s | Implemented | How often the Scheduler polls for due schedules (Go duration) | orchestration/scheduler.go |
TRUVAG3_SCHEDULER_LOCK_TTL | 30s | Implemented | Distributed lock TTL for leader election; must be > tick interval (Go duration) | orchestration/scheduler.go |
TRUVAG3_SCHEDULER_MAX_SCHEDULES | 10000 | Implemented | Maximum schedules retained in one deployment's explicit all/due indexes | orchestration/redis_schedule_store.go |
Scheduled-Executor (Consumer)
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_EXECUTOR_WORKER_COUNT | 5 | Implemented | Number of concurrent dispatch goroutines | examples/scheduled-executor/worker.go |
TRUVAG3_EXECUTOR_MAX_RETRIES | 3 | Implemented | Max retry attempts per task before dead-lettering | examples/scheduled-executor/worker.go |
TRUVAG3_EXECUTOR_RETRY_BASE_DELAY | 5s | Implemented | Base delay for exponential backoff (Go duration) | examples/scheduled-executor/worker.go |
TRUVAG3_EXECUTOR_RETRY_MAX_DELAY | 60s | Implemented | Maximum backoff cap (Go duration) | examples/scheduled-executor/worker.go |
TRUVAG3_EXECUTOR_DISPATCH_TIMEOUT | 15m | Implemented | Per-request HTTP timeout for POST to the target agent. Size it for that agent's entire synchronous request, including planning, phases, retries, synthesis and any blocking HITL wait. Matching only the target's per-call TRUVAG3_ORCHESTRATION_TIMEOUT is insufficient. | examples/scheduled-executor/worker.go |
Both components require REDIS_URL for the task queue and service registry. The scheduled-executor also requires TRUVAG3_K8S_SERVICE_NAME and standard framework variables for service registration.
Example: Tuning for High-Volume Scheduling
# Scheduler-tool: faster polling for time-sensitive schedules
export TRUVAG3_SCHEDULER_TICK_INTERVAL=2s
export TRUVAG3_SCHEDULER_LOCK_TTL=10s
# Scheduled-executor: more workers, more retries, tighter backoff
export TRUVAG3_EXECUTOR_WORKER_COUNT=10
export TRUVAG3_EXECUTOR_MAX_RETRIES=5
export TRUVAG3_EXECUTOR_RETRY_BASE_DELAY=2s
export TRUVAG3_EXECUTOR_RETRY_MAX_DELAY=30s
# Dispatch timeout defaults to 15m — only lower this if your agents
# complete the entire synchronous request faster, including all phases.
Code-Level Override
Environment variables are the deployment-time tuning layer. For stable compile-time defaults, set fields directly on ExecutorDeps:
worker, _ := NewWorker(ExecutorDeps{
WorkerCount: 10, // overrides TRUVAG3_EXECUTOR_WORKER_COUNT
MaxRetries: 5, // overrides TRUVAG3_EXECUTOR_MAX_RETRIES
DispatchTimeout: 30 * time.Second, // overrides TRUVAG3_EXECUTOR_DISPATCH_TIMEOUT
// other fields...
})
See Scheduled Tasks Guide for the full architecture and operational guide.
Prompt Configuration
Configure LLM prompt customization for orchestration.
| Variable | Default | Status | Description | Source |
|---|---|---|---|---|
TRUVAG3_PROMPT_TEMPLATE_FILE | (none) | Implemented | Path to custom prompt template file | orchestration/prompt_config_env.go |
TRUVAG3_PROMPT_DOMAIN | (none) | Implemented | Domain context (healthcare, finance, legal, retail) | orchestration/prompt_config_env.go |
TRUVAG3_PROMPT_TYPE_RULES | (none) | Implemented | JSON array of additional type rules | orchestration/prompt_config_env.go |
TRUVAG3_PROMPT_CUSTOM_INSTRUCTIONS | (none) | Implemented | JSON array of custom instructions | orchestration/prompt_config_env.go |
Example
export TRUVAG3_PROMPT_DOMAIN="healthcare"
export TRUVAG3_PROMPT_TYPE_RULES='[{"type_names":["uuid"],"json_type":"JSON strings","example":"\"abc-123\""}]'
export TRUVAG3_PROMPT_CUSTOM_INSTRUCTIONS='["Prefer local tools", "Minimize API calls"]'
Agent Skills Configuration
Skills are disabled by default. These variables are read only by the explicit
orchestration environment-resolution path (ResolveOrchestratorConfig with an
environment mode or CreateOrchestratorFromEnvironment). Empty or malformed
skill values that participate in effective resolution fail both compatible and
strict modes without echoing their contents; EnvironmentDisabled performs no
environment reads. A non-authoritative tuning value shadowed by an explicit
code value is not consulted.
Skill environment precedence is intentionally asymmetric. When present,
TRUVAG3_SKILLS_ENABLED and TRUVAG3_SKILL_BINDINGS_JSON are authoritative
deployment settings applied after code options; the binding value replaces the
complete developer-owned list and never appends or merges. Other skill
variables fill only fields that code left unset. Model and guidance-file
variables are read only after skills are effectively enabled with at least one
binding. This keeps every pod replica on the same eligibility policy while
preserving explicit code overrides for tuning values.
For a concept-to-operations walkthrough with authoring, binding, Kubernetes, and Registry Viewer examples, see the Agent Skills Guide.
Runtime and binding variables
| Variable | Default | Status | Description |
|---|---|---|---|
TRUVAG3_SKILLS_ENABLED | false | Implemented | Enable skill runtime. A non-empty binding list and injected SkillRegistry are also required. |
TRUVAG3_SKILL_BINDINGS_JSON | [] | Implemented | Complete JSON array of {namespace,name,version,activation,required} bindings. version defaults to published; activation is always, auto, or explicit. |
TRUVAG3_SKILL_DOMAIN_COMPATIBILITY_MODE | warn | Implemented | off, warn, or enforce comparison between an agent prompt domain and authored skill domains. Domain never changes skill identity. |
TRUVAG3_SKILL_CACHE_MODE | local | Implemented | local for verified immutable-body LRU caching or disabled. Aliases and catalog reads are never cached. |
TRUVAG3_SKILL_CACHE_MAX_BYTES | 16777216 | Implemented | Positive byte capacity of the process-local immutable-content cache. |
TRUVAG3_SKILL_REGISTRY_READ_TIMEOUT | 5s | Implemented | Positive timeout for each runtime registry operation. |
TRUVAG3_SKILL_RESOURCE_SELECTION_ATTEMPT_TIMEOUT | 0s | Implemented | Nonnegative duration for each built-in resource AI attempt; zero inherits parent. Resource v2 retries timeout within two total attempts. |
TRUVAG3_SKILL_ACTIVATION_MODEL | agent/client model | Implemented | Model intent for the bounded activation selector. |
TRUVAG3_SKILL_RESOURCE_MODEL | agent/client model | Implemented | Model intent for the bounded resource selector. |
TRUVAG3_SKILL_ACTIVATION_GUIDANCE_FILE | none | Implemented | Mounted UTF-8 file containing bounded additive activation-selector guidance. |
TRUVAG3_SKILL_RESOURCE_GUIDANCE_FILE | none | Implemented | Mounted UTF-8 file containing bounded additive resource-selector guidance. |
Example complete binding replacement:
export TRUVAG3_SKILLS_ENABLED=true
export TRUVAG3_SKILL_BINDINGS_JSON='[
{"namespace":"travel","name":"weather-assessment","version":"published","activation":"auto","required":false},
{"namespace":"travel","name":"safety-policy","version":"3","activation":"always","required":true}
]'
Binding behavior is precise:
| Field/value | Runtime behavior |
|---|---|
version: "published" | Resolve the mutable publication pointer once at request start, then pin its exact immutable revision and hashes for the execution. |
version: "N" | Resolve that positive immutable revision; later publications do not affect it. |
activation: "always" | Activate deterministically whenever candidate resolution admits the binding. |
activation: "auto" | Let the bounded selector activate it at initial planning or a later continuation boundary. |
activation: "explicit" | Activate only through the trusted host carrier; user text and ordinary request metadata cannot request it. |
required: true | Treat candidate/content availability failures as fatal when applicable. This does not force activation. A required binding is invalid while skills are disabled. |
SkillConfig.RuntimePolicyID is deliberately code-only and limited to 128
bytes. It identifies custom activation, resource-resolution, or token-counting
behavior for response-cache eligibility; it is not a deployment environment
switch.
Selector guidance is capped at 4,096 bytes and 512 estimated tokens. Selector
temperature (0.01), deliberately unset provider-native response format,
strict JSON parsing, retry count, fixed prompts, and output ceilings are
framework contracts and are not environment switches. The unset response
format avoids provider-specific wire values; the fixed prompt/parser/retry path
still enforces structured JSON output.
Resource selector v2 accepts a complete outer JSON/unlabelled fence before strict
body validation. Its retry eligibility includes child-attempt timeout, within
the unchanged two-attempt ceiling; activation is unchanged. The attempt-duration
setting is tunable: code zero is unset, nonzero code wins over env, and explicit
env 0s inherits the parent deadline. Invalid consulted values fail in both
compatible and strict modes; disabled-env mode ignores them. Optional omission
is diagnosed, while parent cancellation remains terminal.
Runtime limits
| Variable | Default | Status | Description |
|---|---|---|---|
TRUVAG3_SKILL_MAX_BINDINGS | 32 | Implemented | Maximum explicit bindings. |
TRUVAG3_SKILL_MAX_AUTO_CANDIDATES | 16 | Implemented | Maximum candidates presented to activation selection. |
TRUVAG3_SKILL_CATALOG_TOKEN_BUDGET | 2000 | Implemented | Body-free activation catalog budget. |
TRUVAG3_SKILL_MAX_RESOURCE_CANDIDATES | 32 | Implemented | Maximum resource-index candidates at one boundary. |
TRUVAG3_SKILL_RESOURCE_CATALOG_TOKEN_BUDGET | 2000 | Implemented | Body-free resource catalog budget. |
TRUVAG3_SKILL_MAX_ACTIVE_SKILLS | 6 | Implemented | Maximum admitted active skills in one execution. |
TRUVAG3_SKILL_TOTAL_TOKEN_BUDGET | 8192 | Implemented | Overall skill projection budget. |
TRUVAG3_SKILL_MAIN_TOKEN_BUDGET | 6144 | Implemented | Main instruction budget. |
TRUVAG3_SKILL_RESOURCE_TOKEN_BUDGET | 4096 | Implemented | Resource-content budget. |
TRUVAG3_SKILL_MAX_RESOURCES_PER_PHASE | 2 | Implemented | Resource bodies admitted at one boundary. |
TRUVAG3_SKILL_MAX_RESOURCES_PER_EXECUTION | 8 | Implemented | Distinct resource bodies admitted across an execution. |
TRUVAG3_SKILL_RESOLUTION_MAX_TOKENS | 512 | Implemented | Fixed upper output budget used by selectors. |
TRUVAG3_SKILL_SYNTHESIS_TOKEN_BUDGET | 6000 | Implemented | Skill contribution budget at synthesis. |
TRUVAG3_SKILL_EFFECTIVE_INPUT_TOKEN_BUDGET | 0 | Implemented | Optional model-context allowance. When positive, the effective total skill budget is min(total_token_budget, floor(effective_input_token_budget/10)); 0 disables this additional 10% cap. |
Response-cache short-circuits are eligible only when the behavior projection is
stable: either SkillConfig.RuntimePolicyID is set, or no custom skill runtime
component is installed and both selector models are explicitly pinned. Normal
execution, immutable content caching, and skill correctness do not depend on
this eligibility bit; an ineligible configuration simply bypasses cached
answers.
Included Redis and Registry Viewer host
| Variable | Default | Status | Description |
|---|---|---|---|
TRUVAG3_SKILL_AUTHORING_MAX_NAME_CHARS | 64 | Example Only | Registry Viewer skill-management host override. |
TRUVAG3_SKILL_AUTHORING_MAX_DESCRIPTION_CHARS | 1024 | Example Only | Registry Viewer host override. |
TRUVAG3_SKILL_AUTHORING_MAX_MANIFEST_TOKENS | 5000 | Example Only | Registry Viewer host override. |
TRUVAG3_SKILL_AUTHORING_MAX_MANIFEST_BYTES | 24576 | Example Only | Registry Viewer host override. |
TRUVAG3_SKILL_AUTHORING_MAX_RESOURCE_TOKENS | 8000 | Example Only | Per-resource host override. |
TRUVAG3_SKILL_AUTHORING_MAX_RESOURCE_BYTES | 32768 | Example Only | Per-resource host override. |
TRUVAG3_SKILL_AUTHORING_MAX_RESOURCES | 32 | Example Only | Resources per package host override. |
TRUVAG3_SKILL_AUTHORING_MAX_PACKAGE_BYTES | 1048576 | Example Only | HTTP package body host override. |
TRUVAG3_SKILL_ADMIN_MAX_DELETE_VERSIONS | 100 | Example Only | Maximum inclusive deletion range accepted by the host. |
TRUVAG3_SKILL_AUTHORING_ADVICE_MAX_OUTPUT_TOKENS | 1024 | Example Only | Optional authoring-advisor output ceiling; the bundled host does not configure an advisor in V1. |
JAEGER_UI_URL | http://jaeger.localhost | Example Only | Browser-facing Jaeger base URL used by the Registry Viewer trace redirect. |
These Registry Viewer variables belong to the example host, not framework-global
configuration. Other skills hosts pass SkillAuthoringLimits and
SkillAdministrationLimits directly to NewSkillAdminHandler. The Registry
Viewer binary reads these values from its process environment; its bundled
setup.sh does not automatically forward authoring/admin overrides from the
invoking shell into Kubernetes. It forwards JAEGER_UI_URL into the deployment
ConfigMap as an optional browser-navigation target. Registry Viewer does not
query Jaeger.
Quick Reference Table
Essential Variables for Production (All Implemented)
# Core
export TRUVAG3_AGENT_NAME="my-agent"
export TRUVAG3_PORT=8080
export TRUVAG3_NAMESPACE="production"
# Discovery
export REDIS_URL="redis://redis:6379"
# AI (one of these)
export OPENAI_API_KEY="sk-..."
# or: GROQ_API_KEY, ANTHROPIC_API_KEY, etc.
# Telemetry
export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector:4318"
export OTEL_SERVICE_NAME="my-agent"
# Orchestration (for long-running AI workflows)
export TRUVAG3_ORCHESTRATION_TIMEOUT=5m
export TRUVAG3_HTTP_WRITE_TIMEOUT=5m
export TRUVAG3_HTTP_READ_TIMEOUT=5m
Essential Variables for Development (All Implemented)
export TRUVAG3_DEV_MODE=true
export TRUVAG3_MOCK_DISCOVERY=true
export TRUVAG3_DEBUG=true
Iterative Planning Variables (for Multi-Phase DAG)
# Enable multi-phase planning (default: true)
export TRUVAG3_ITERATIVE_PLANNING_ENABLED=true
export TRUVAG3_ITERATIVE_MAX_PHASES=20 # Max planning phases per request
export TRUVAG3_ITERATIVE_MAX_TOTAL_STEPS=200 # Max total steps across all phases
export TRUVAG3_ITERATIVE_PHASE_TIMEOUT=25m # Configured phase budget; delegation may enlarge it
Step Retry Backoff Variables (for Retry Tuning)
# Exponential backoff for step retries (defaults shown)
export TRUVAG3_STEP_RETRY_INITIAL_DELAY=500ms # Base delay, doubles per attempt
export TRUVAG3_STEP_RETRY_MAX_DELAY=10s # Delay cap regardless of attempt count
Result Data Management Variables (for Large Responses)
# Result trimming (enabled by default — prevents token overflow)
export TRUVAG3_RESULT_TRIM_ENABLED=true
export TRUVAG3_RESULT_TRIM_MAX_BYTES=65536 # 64 KiB per result (~16K tokens)
export TRUVAG3_RESULT_TRIM_MAX_TOTAL_BYTES=196608 # 192 KiB total (~48K tokens)
export TRUVAG3_RESULT_TRIM_MAX_MICRO_BYTES=65536 # 64 KB for micro-resolution prompts
export TRUVAG3_RESULT_TRIM_MAX_AGENT_INPUT_BYTES=0 # 0 = no cap (fidelity-first); set > 0 to enable the guard
export TRUVAG3_RESULT_TRIM_SCHEMA_MAPPING_THRESHOLD=16384 # 16 KB — schema mapping above this
# Result distillation (on by default — adds LLM call per large result)
export TRUVAG3_RESULT_DISTILL_ENABLED=true
export TRUVAG3_RESULT_DISTILL_THRESHOLD=16384 # Min bytes to trigger
export TRUVAG3_RESULT_DISTILL_PREFILTER=131072 # Pre-filter budget (128 KB)
export TRUVAG3_RESULT_DISTILL_TARGET=4096 # LLM output target
export TRUVAG3_RESULT_DISTILL_MODEL=fast # Catalog-backed providers; Bedrock needs a programmatic empty override
export TRUVAG3_RESULT_DISTILL_CACHE_TTL=5m # Distillation cache TTL
export TRUVAG3_RESULT_DISTILL_DEADLINE=45s # Hot-path compaction bound (positive durations only)
export TRUVAG3_RESULT_DISTILL_CONTEXT_TOKENS=150000 # Above this, chunk → map-reduce
export TRUVAG3_RESULT_DISTILL_MAP_CONCURRENCY=8 # Concurrent chunk distillations
export TRUVAG3_RESULT_DISTILL_MAPREDUCE_THRESHOLD=0 # Byte threshold → map-reduce (0 = disabled)
Shared Memory Variables (for Cross-Agent Coordination)
# Domain scoping — agents in the same domain share memory
export TRUVAG3_AGENT_DOMAIN="infrastructure"
# Activity compaction — LLM-powered event digests
export TRUVAG3_SHARED_MEMORY_SUMMARIZER_MODEL=fast # Model for summarization/compaction
export TRUVAG3_SHARED_MEMORY_ENRICHMENT_SUMMARY_MAX_TOKENS=500 # Digest target; built-in generation allowance is 5x
export TRUVAG3_SHARED_MEMORY_COMPACTION_RAW_LIMIT=200 # Max events sent to compactor
export TRUVAG3_SHARED_MEMORY_COMPACTION_RECENT_DETAIL=15 # Raw events after digest
# Digest caching — reduces redundant LLM calls
export TRUVAG3_SHARED_MEMORY_DIGEST_CACHE_TTL=5m # Cache expiry
export TRUVAG3_SHARED_MEMORY_DIGEST_INCREMENTAL_THRESHOLD=20 # Above this → full recompact
# Activity coordination — real-time agent signals
export TRUVAG3_ACTIVITY_SIGNAL_TTL=5m # Signal expiry
export TRUVAG3_ACTIVITY_SIGNAL_MAX_IN_PROMPT=10 # Max signals in prompt
LLM Debug Variables (for Troubleshooting)
# Enable debug payload storage (disabled by default)
export TRUVAG3_LLM_DEBUG_ENABLED=true
export TRUVAG3_LLM_DEBUG_TTL=72h # Success record retention (3 days)
export TRUVAG3_LLM_DEBUG_ERROR_TTL=72h # Error record retention (3 days)
export TRUVAG3_REDIS_NAMESPACE=production # Shared DB-0 deployment namespace
Kubernetes ConfigMap Example
apiVersion: v1
kind: ConfigMap
metadata:
name: truvag3-config
data:
TRUVAG3_AGENT_NAME: "research-agent"
TRUVAG3_NAMESPACE: "production"
TRUVAG3_LOG_LEVEL: "info"
TRUVAG3_LOG_FORMAT: "json"
TRUVAG3_DISCOVERY_CACHE: "true"
OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector.observability:4318"
Kubernetes Secret Example
apiVersion: v1
kind: Secret
metadata:
name: truvag3-secrets
type: Opaque
stringData:
OPENAI_API_KEY: "sk-..."
REDIS_URL: "redis://:password@redis:6379"
Configuration Priority
Configuration is resolved in three layers, applied sequentially (last write wins):
| Step | Source | Example | Priority |
|---|---|---|---|
| 1 | DefaultConfig() | AllowedHeaders: ["Content-Type", "Authorization"] | Lowest |
| 2 | LoadFromEnv() | TRUVAG3_CORS_HEADERS=Content-Type,Authorization,X-User-ID | Medium |
| 3 | Functional options | WithCORS([]string{"*"}, true) | Highest |
Each step merges into the configuration struct. A later step only overwrites fields it explicitly sets — unset fields retain their value from earlier steps. For example, WithCORS sets Enabled, AllowedOrigins, and AllowCredentials but does not touch AllowedHeaders, so an env var override for headers survives.
This follows the standard Go / 12-factor convention (same as Viper, Cobra, Kong):
- Defaults provide safe baselines
- Environment variables allow deployment-time tuning without code changes (ideal for K8s ConfigMaps)
- Functional options express explicit developer intent and take precedence
See also:
NewConfig()incore/config.godocuments this sequence in its godoc.
For environment variables with multiple valid names, standard names take
precedence over framework-specific aliases. This rule does not make
contradictory forms mergeable: Redis connection sources are selected exactly
once, and REDIS_URL combined with either structured topology fields or the
removed TRUVAG3_REDIS_URL alias fails validation.
Variables Marked as "Struct Tag Only"
These variables are defined in Go struct tags with env:"..." annotations but are not currently loaded in the LoadFromEnv() function. They may work if you're using a reflection-based configuration loader, but the default LoadFromEnv() does not process them.
To use these variables, you would need to either:
- Use programmatic configuration via functional options
- Implement reflection-based struct tag parsing
- Submit a PR to add explicit loading for these variables