Skip to content

Unified Prompt Architecture

Overview

The Unified Prompt Architecture provides a single, coherent entry point for prompt construction across all execution paths in Victor. It bridges the legacy YAML workflow and StateGraph agent systems, enabling evolved content injection and constraint activation throughout the framework.

Motivation

Problem 1: Dual Prompt Builders (Disconnected)
- Legacy builder: victor/agent/prompt_builder.py (700+ lines, uses PromptDocument)
- Framework builder: victor/framework/prompt_builder.py (uses PromptBuilder)
- No integration between them
- Different section names (e.g., "tool_effectiveness_guidance" vs "ASI_TOOL_EFFECTIVENESS_GUIDANCE")
- Missing evolvable sections in framework builder

Problem 2: Constraint Activation Gap
- Legacy YAML workflow: ✅ Uses IsolationMapper.from_constraints() → activates WritePathPolicy
- StateGraph agent nodes: ❌ No constraint activation
- SubAgent.spawn(): ❌ No constraint activation
- Missing: Shared constraint activation utility

Problem 3: Evolved Content Not Consumed
- 5 EVOLVABLE_SECTIONS defined (ASI_TOOL_EFFECTIVENESS_GUIDANCE, GROUNDING_RULES, COMPLETION_GUIDANCE, FEW_SHOT_EXAMPLES, INIT_SYNTHESIS_RULES)
- RL system evolves these sections
- Framework builder doesn't check OptimizationInjector for evolved content
- No pathway for evolved candidates to flow into framework prompts

Solution Architecture

┌─────────────────────────────────────────────────────────────────┐
│                     Application Layer                           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │ Legacy YAML  │  │ StateGraph   │  │ SubAgent     │          │
│  │ Workflows    │  │ Agent Nodes  │  │ spawn()      │          │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘          │
└─────────┼──────────────────┼──────────────────┼───────────────────┘
          │                  │                  │
          ▼                  ▼                  ▼
┌─────────────────────────────────────────────────────────────────┐
│                   Facade Layer (New)                            │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │    PromptOrchestrator (Unified Entry Point)              │   │
│  │  - Coordinates builder selection                         │   │
│  │  - Manages evolved content injection                     │   │
│  │  - Handles constraint activation                         │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
          │                  │                  │
          ▼                  ▼                  ▼
┌─────────────────────────────────────────────────────────────────┐
│                   Service Layer                                 │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │ Constraint   │  │ Evolved      │  │ Prompt       │          │
│  │ Activator    │  │ Content      │  │ Section      │          │
│  │ Service      │  │ Resolver     │  │ Registry     │          │
│  └──────────────┘  └──────────────┘  └──────────────┘          │
└─────────────────────────────────────────────────────────────────┘
          │                  │                  │
          ▼                  ▼                  ▼
┌─────────────────────────────────────────────────────────────────┐
│                   Foundation Layer                              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │ Legacy       │  │ Framework    │  │ Optimiz.     │          │
│  │ Prompt       │  │ Prompt       │  │ Injector     │          │
│  │ Builder      │  │ Builder      │  │              │          │
│  └──────────────┘  └──────────────┘  └──────────────┘          │
│  ┌──────────────┐  ┌──────────────┐                          │
│  │ Isolation    │  │ Content      │                          │
│  │ Mapper       │  │ Registry     │                          │
│  └──────────────┘  └──────────────┘                          │
└─────────────────────────────────────────────────────────────────┘

Core Components

1. PromptOrchestrator (Facade)

Location: victor/agent/prompt_orchestrator.py

Purpose: Unified entry point for prompt construction across legacy and StateGraph paths.

Key Features:
- Auto-detects builder type (legacy vs framework) based on kwargs
- Injects evolved content from OptimizationInjector
- Activates constraints before prompt construction
- Singleton pattern for consistent state management

Usage Example:

from victor.agent.prompt_orchestrator import get_prompt_orchestrator
from victor.workflows.definition import FullAccessConstraints

# Get singleton instance
orchestrator = get_prompt_orchestrator()

# Build system prompt (auto-detects builder type)
prompt = orchestrator.build_system_prompt(
    builder_type="auto",  # "legacy", "framework", or "auto"
    provider="anthropic",
    model="claude-sonnet-4-6",
    task_type="edit",
    base_prompt="You are an assistant.",  # For framework builder
    prompt_contributors=[],  # For legacy builder
)

# Activate constraints
constraints = FullAccessConstraints()
success = orchestrator.activate_constraints(constraints, "coding")

# ... use prompt ...

# Cleanup
orchestrator.deactivate_constraints()

Configuration:

from victor.agent.prompt_orchestrator import OrchestratorConfig

config = OrchestratorConfig(
    use_evolved_content=True,  # Enable evolved content injection
    enable_constraint_activation=True,  # Enable constraint activation
    fallback_to_static=True,  # Fall back to static content if evolved unavailable
    cache_evolved_content=True,  # Cache evolved content for performance
)

orchestrator = PromptOrchestrator(config=config)

2. EvolvedContentResolver

Location: victor/agent/evolved_content_resolver.py

Purpose: Bridges OptimizationInjector and prompt builders, providing unified interface for fetching evolved content with fallback to static defaults.

Key Features:
- Queries OptimizationInjector for evolved content
- Falls back to static content when evolved version unavailable
- Caches results for performance
- Supports batch resolution for multiple sections

Usage Example:

from victor.agent.evolved_content_resolver import EvolvedContentResolver

# Create resolver (typically done internally by PromptOrchestrator)
resolver = EvolvedContentResolver(optimization_injector=None)

# Resolve single section
result = resolver.resolve_section(
    section_name="ASI_TOOL_EFFECTIVENESS_GUIDANCE",
    provider="anthropic",
    model="claude-sonnet-4-6",
    task_type="edit",
    fallback_text="Use tools judiciously.",
)

print(result.text)  # Evolved or fallback content
print(result.source)  # "evolved" or "static"

# Resolve multiple sections
results = resolver.resolve_multiple(
    section_names=[
        "ASI_TOOL_EFFECTIVENESS_GUIDANCE",
        "GROUNDING_RULES",
        "COMPLETION_GUIDANCE",
    ],
    fallback_map={
        "ASI_TOOL_EFFECTIVENESS_GUIDANCE": "Tool guidance",
        "GROUNDING_RULES": "Grounding text",
        "COMPLETION_GUIDANCE": "Completion text",
    },
)

# Clear cache
resolver.clear_cache()

ResolvedContent Structure:

@dataclass(frozen=True)
class ResolvedContent:
    section_name: str  # Canonical section name
    text: str  # Resolved content text
    source: str  # "evolved", "static", or "custom"
    metadata: Dict[str, Any]  # Additional metadata

    def is_evolved(self) -> bool:
        return self.source == "evolved"

    def is_static(self) -> bool:
        return self.source == "static"

3. ConstraintActivationService

Location: victor/agent/constraint_activation_service.py

Purpose: Single service for activating constraints across all execution paths (legacy YAML, StateGraph, SubAgent).

Key Features:
- Singleton pattern for consistent constraint state
- Integrates with IsolationMapper.from_constraints()
- Activates WritePathPolicy based on constraints
- Automatic cleanup on deactivation

Usage Example:

from victor.agent.constraint_activation_service import get_constraint_activator
from victor.workflows.definition import FullAccessConstraints, ComputeOnlyConstraints

# Get singleton instance
activator = get_constraint_activator()

# Activate constraints
constraints = FullAccessConstraints()
result = activator.activate_constraints(constraints, "coding")

if result.success:
    print(f"Policy: {result.write_path_policy}")
    print(f"Isolation: {result.isolation_config}")

# Check active state
active_policy = activator.get_active_policy()
active_constraints = activator.get_active_constraints()

# Deactivate (cleanup)
activator.deactivate_constraints()

ActivationResult Structure:

@dataclass(frozen=True)
class ActivationResult:
    success: bool  # Whether activation succeeded
    write_path_policy: Optional[WritePathPolicy]  # Activated policy
    isolation_config: Optional[dict]  # Isolation configuration
    error: Optional[str]  # Error message if failed

4. UnifiedSectionRegistry

Location: victor/agent/prompt_section_registry.py

Purpose: Single source of truth for all prompt sections with consistent naming and alias support.

Key Features:
- Canonical uppercase names (e.g., "ASI_TOOL_EFFECTIVENESS_GUIDANCE")
- Alias support for backward compatibility (e.g., "tool_effectiveness_guidance")
- Section categories (grounding, tool_guidance, completion, etc.)
- Evolvable section tracking

Usage Example:

from victor.agent.prompt_section_registry import get_section_registry, SectionDefinition, SectionCategory

# Get singleton registry
registry = get_section_registry()

# Register new section
section = SectionDefinition(
    name="CUSTOM_SECTION",
    aliases={"custom_section", "custom"},
    category=SectionCategory.TASK_HINTS,
    default_text="Default text",
    evolvable=True,
    required=False,
    priority=50,
)
registry.register(section)

# Get section by name or alias
section = registry.get("ASI_TOOL_EFFECTIVENESS_GUIDANCE")
section = registry.get("tool_effectiveness_guidance")  # Alias works too

# Get all evolvable sections
evolvable = registry.get_evolvable_sections()

Integration Points

Legacy YAML Workflows

Location: victor/agent/prompt_builder.py (unchanged)

Integration: Legacy builder continues working as before. PromptOrchestrator detects legacy usage via prompt_contributors parameter.

# Legacy workflow (unchanged)
from victor.agent.prompt_builder import SystemPromptBuilder

builder = SystemPromptBuilder(
    provider="anthropic",
    model="claude-sonnet-4-6",
    vertical="coding",
)
prompt = builder.build(prompt_contributors=[])

# NEW: Via PromptOrchestrator
from victor.agent.prompt_orchestrator import get_prompt_orchestrator

orchestrator = get_prompt_orchestrator()
prompt = orchestrator.build_system_prompt(
    builder_type="legacy",
    provider="anthropic",
    model="claude-sonnet-4-6",
    vertical="coding",
    prompt_contributors=[],
)

StateGraph Agent Nodes

Location: victor/workflows/executors/agent.py (modified)

Integration: AgentNodeExecutor now activates constraints before spawning sub-agent.

# Before (no constraint activation)
async def execute(self, node: "AgentNode", state: "WorkflowState") -> "WorkflowState":
    # ... execute agent ...
    return state

# After (with constraint activation)
async def execute(self, node: "AgentNode", state: "WorkflowState") -> "WorkflowState":
    from victor.agent.constraint_activation_service import get_constraint_activator

    activator = get_constraint_activator()
    result = activator.activate_constraints(
        constraints=node.constraints,
        vertical=getattr(node, "vertical", "coding"),
    )

    if not result.success:
        logger.error(f"Constraint activation failed: {result.error}")

    try:
        # ... existing execution logic ...
        return state
    finally:
        activator.deactivate_constraints()

SubAgent Spawning

Location: victor/agent/subagents/orchestrator.py (modified)

Integration: SubAgent.spawn() now accepts constraints parameter.

# Before (no constraint support)
result = await subagent.spawn(
    role=SubAgentRole.RESEARCHER,
    task="Investigate X",
)

# After (with constraint support)
from victor.workflows.definition import ComputeOnlyConstraints

constraints = ComputeOnlyConstraints()
result = await subagent.spawn(
    role=SubAgentRole.RESEARCHER,
    task="Investigate X",
    constraints=constraints,  # NEW parameter
)

Framework Prompt Builder

Location: victor/framework/prompt_builder.py (modified)

Integration: Added add_evolved_section() method for evolved content support.

from victor.framework.prompt_builder import PromptBuilder

builder = PromptBuilder()
builder.add_system_prompt("You are an assistant.")
builder.add_evolved_section(
    section_name="ASI_TOOL_EFFECTIVENESS_GUIDANCE",
    provider="anthropic",
    model="claude-sonnet-4-6",
    task_type="edit",
)

prompt = builder.build()

Migration Guide

For Legacy Code

Step 1: Identify Prompt Builder Usage

Find all places where SystemPromptBuilder or PromptBuilder is used directly.

# Find legacy builder usage
grep -r "SystemPromptBuilder" --include="*.py" .

# Find framework builder usage
grep -r "from victor.framework.prompt_builder import" --include="*.py" .

Step 2: Migrate to PromptOrchestrator

Replace direct builder usage with PromptOrchestrator:

# Before
from victor.agent.prompt_builder import SystemPromptBuilder

builder = SystemPromptBuilder(provider="anthropic", model="claude-sonnet-4-6")
prompt = builder.build(prompt_contributors=[])

# After
from victor.agent.prompt_orchestrator import get_prompt_orchestrator

orchestrator = get_prompt_orchestrator()
prompt = orchestrator.build_system_prompt(
    builder_type="auto",
    provider="anthropic",
    model="claude-sonnet-4-6",
    prompt_contributors=[],
)

Step 3: Add Constraint Activation

Add constraint activation where needed:

# Before
result = await agent.run(task)

# After
from victor.workflows.definition import FullAccessConstraints

orchestrator = get_prompt_orchestrator()
constraints = FullAccessConstraints()
orchestrator.activate_constraints(constraints, "coding")

try:
    result = await agent.run(task)
finally:
    orchestrator.deactivate_constraints()

For New Code

Recommended Pattern:

from victor.agent.prompt_orchestrator import get_prompt_orchestrator
from victor.workflows.definition import FullAccessConstraints

async def execute_with_constraints(task: str):
    orchestrator = get_prompt_orchestrator()

    # Build prompt with evolved content
    prompt = orchestrator.build_system_prompt(
        builder_type="auto",
        provider="anthropic",
        model="claude-sonnet-4-6",
        task_type="edit",
    )

    # Activate constraints
    constraints = FullAccessConstraints()
    orchestrator.activate_constraints(constraints, "coding")

    try:
        # Execute task
        result = await execute_task(task, prompt)
        return result
    finally:
        # Always cleanup
        orchestrator.deactivate_constraints()

Design Principles

1. Single Responsibility

  • Each class has one clear purpose
  • Resolver resolves, Activator activates, Orchestrator coordinates

2. Open/Closed

  • Extensible via new strategies without modifying existing code
  • New sections can be registered without changing core logic

3. Dependency Inversion

  • Depend on abstractions (protocols), not concrete implementations
  • Easy to mock for testing

4. Framework-First

  • Reuse existing utilities (OptimizationInjector, IsolationMapper)
  • Don't reinvent functionality that already exists

5. Backward Compatibility

  • Legacy builder continues working
  • Gradual migration path
  • No breaking changes to existing code

6. Facade Pattern

  • PromptOrchestrator provides unified API
  • Doesn't reimplement builder logic
  • Delegates to existing builders

Performance Considerations

Caching

Evolved content is cached by default to reduce redundant OptimizationInjector queries:

config = OrchestratorConfig(
    cache_evolved_content=True,  # Default: True
)

Cache can be cleared manually:

from victor.agent.evolved_content_resolver import EvolvedContentResolver

resolver = EvolvedContentResolver()
# ... use resolver ...
resolver.clear_cache()  # Clear cache

Builder Detection

Auto-detection adds minimal overhead (<1ms):

# Auto-detection (recommended)
prompt = orchestrator.build_system_prompt(
    builder_type="auto",  # Detects based on kwargs
    ...
)

# Explicit (slightly faster if builder type is known)
prompt = orchestrator.build_system_prompt(
    builder_type="legacy",  # Skip detection
    ...
)

Constraint Activation

Constraint activation is lightweight (~5-10ms):

# Most of the time is spent in IsolationMapper
# WritePathPolicy activation is <1ms

Testing

Unit Tests

  • tests/unit/agent/test_prompt_orchestrator.py (39 tests)
  • tests/unit/agent/test_evolved_content_resolver.py (39 tests)
  • tests/unit/agent/test_constraint_activation_service.py (39 tests)

Integration Tests

  • tests/integration/agent/test_unified_prompt_construction.py (10 tests)

Running Tests

# Run all unified prompt tests
pytest tests/unit/agent/test_prompt_orchestrator.py \
       tests/unit/agent/test_evolved_content_resolver.py \
       tests/unit/agent/test_constraint_activation_service.py \
       tests/integration/agent/test_unified_prompt_construction.py \
       -v

# Run backward compatibility tests
pytest tests/unit/agent/test_orchestrator_core.py \
       tests/unit/agent/test_tool_graph_builder.py \
       -v

Troubleshooting

Issue: Evolved Content Not Loading

Symptoms: ResolvedContent.source == "static" when expecting "evolved"

Solutions:
1. Check OptimizationInjector is initialized: get_rl_coordinator()
2. Verify section is in EVOLVABLE_SECTIONS
3. Check prompt optimization is enabled: settings.prompt_optimization.enabled
4. Verify provider/model/task_type match evolved content

Issue: Constraint Activation Fails

Symptoms: ActivationResult.success == False

Solutions:
1. Check constraints object is valid (FullAccessConstraints, ComputeOnlyConstraints)
2. Verify vertical is correct ("coding", "dataanalysis", etc.)
3. Check IsolationMapper logs for errors
4. Verify WritePathPolicy is not already active

Issue: Builder Detection Wrong

Symptoms: Wrong builder type selected with builder_type="auto"

Solutions:
1. Use explicit builder_type="legacy" or builder_type="framework"
2. Check kwargs match expected pattern:
- Legacy: prompt_contributors parameter
- Framework: base_prompt parameter

Future Enhancements

Phase 4+ (Deferred)

  • Performance monitoring and metrics
  • Advanced caching strategies (LRU, TTL)
  • Multi-provider evolved content resolution
  • Constraint composition (combining multiple constraints)
  • Prompt versioning and rollback
  • A/B testing for evolved content

References

  • Plan Document: See approved plan for detailed implementation timeline
  • FEP-XXXX: Framework Enhancement Proposal (if applicable)
  • Related Docs:
  • docs/architecture/prompt-optimization.md
  • docs/architecture/constraint-system.md
  • docs/architecture/workflow-execution.md

Changelog

2026-04-30

  • ✅ Phase 1: UnifiedSectionRegistry, EvolvedContentResolver
  • ✅ Phase 2: ConstraintActivationService
  • ✅ Phase 3: PromptOrchestrator
  • ✅ Phase 4: Integration points (AgentNodeExecutor, SubAgent.spawn())
  • ✅ Phase 5: Testing and verification (49 new tests + 428 total passing)