Feature: Consolidated Routing
  Combined scenarios from: message_router_new_coverage, reactive_registry_adapter_coverage, reactive_routing_port, route_bridge_coverage, route_bridge_uncovered_lines, route_coverage_comprehensive, routing_adapter_coverage, routing_langgraph_port, stream_router_additional_coverage, stream_router_agent_tool_coverage, stream_router_coverage, stream_router_misc_uncovered, stream_router_new_branches, stream_router_remaining_coverage, stream_router_uncovered_paths, stream_router_unsafe_and_llm_coverage

  # ============================================================
  # Originally from: message_router_new_coverage.feature
  # Feature: Message router new coverage
  # ============================================================

  Scenario: build_message_router_node creates NodeConfig with correct type
    When I build a message router node named "router1" with rules
    Then the node name should be "router1"
    And the node type should be MESSAGE_ROUTER
    And the node metadata should contain rules


  Scenario: build_message_router_edges creates edges from rules
    When I build message router edges for "router1" with two target rules
    Then the edge count should be 3
    And the last edge target should be "end"


  Scenario: build_message_router_edges handles empty rules
    When I build message router edges for "router1" with no rules
    Then the edge count should be 1
    And the last edge target should be "end"


  Scenario: build_message_router_edges skips rules without target
    When I build message router edges for "router1" with a rule missing target
    Then the edge count should be 1


  # ============================================================
  # Originally from: reactive_registry_adapter_coverage.feature
  # Feature: Reactive registry adapter coverage
  # ============================================================

  Scenario: Registry list failure propagates to caller
    Given a reactive stream router and route bridge
    And an actor registry that raises on list
    When I attempt to register registry actors with the adapter
    Then a RuntimeError is raised


  Scenario: Registers only actors with processing methods
    Given a reactive stream router and route bridge
    And an actor registry with mixed capabilities
    When I register registry actors with the adapter
    Then only actors with processing are registered on the stream router
    And the route bridge agents cache includes all listed actors


  Scenario: Route bridge refresh failure propagates to caller
    Given a reactive stream router and route bridge
    And an actor registry that returns actors without names
    When I attempt to register registry actors with the adapter
    Then an AttributeError is raised


  Scenario: Route bridge refresh failure propagates when registry returns none
    Given a reactive stream router and route bridge
    And an actor registry that returns none
    When I attempt to register registry actors with the adapter
    Then a TypeError is raised


  # ============================================================
  # Originally from: reactive_routing_port.feature
  # Feature: Reactive routing and route bridge port
  # ============================================================

  Scenario: Create a cold stream and send a message
    Given a reactive stream router
    When I create a cold stream named "alpha"
    And I send message "hello" to stream "alpha"
    Then the stream "alpha" should exist


  Scenario: Initialize route bridge with dummy registry
    Given a reactive stream router
    And a dummy actor registry
    When I create a route bridge
    Then the route bridge should include agent "dummy"


  Scenario: Convert stream route to graph config via bridge
    Given a reactive stream router
    And a dummy actor registry
    And a stream route config named "s1" with a map agent operator
    When I create a route bridge
    And I convert the stream route to a graph config
    Then the graph config should contain nodes


  # ============================================================
  # Originally from: route_bridge_coverage.feature
  # Feature: Route Bridge Module Coverage
  # ============================================================

  Scenario: Test RouteBridge initialization
    Given I have a clean test environment for route bridge
    Given I have a route bridge stream router and agents
    When I create the route bridge instance
    Then the route bridge should be initialized correctly
    And the route bridge logger should be set up
    And route bridge active conversions should be empty


  Scenario: Test RouteBridge initialization with scheduler
    Given I have a clean test environment for route bridge
    Given I have a route bridge stream router and agents
    And I have an AsyncIO scheduler
    When I create a RouteBridge instance with scheduler
    Then the route bridge should be initialized with scheduler
    And the route bridge scheduler should be stored correctly


  Scenario: Test check_upgrade_conditions - no bridge config
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a route config without bridge configuration
    And I have a stream message
    When I check upgrade conditions
    Then the route bridge upgrade result should be False


  Scenario: Test check_upgrade_conditions - wrong route type
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a graph route config with bridge configuration
    And I have a stream message
    When I check upgrade conditions
    Then the route bridge upgrade result should be False


  Scenario: Test check_upgrade_conditions - needs_state condition
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a stream route config with needs_state upgrade condition
    And I have a stream message with requires_state metadata
    When I check upgrade conditions
    Then the route bridge upgrade result should be True


  Scenario: Test check_upgrade_conditions - message_count condition
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a stream route config with message_count upgrade condition
    And I have processed enough messages to trigger upgrade
    When I check upgrade conditions
    Then the route bridge upgrade result should be True
    And the route bridge message count should be at least 5


  Scenario: Test check_upgrade_conditions - complexity_threshold condition
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a stream route config with complexity_threshold upgrade condition
    And I have a complex route configuration
    When I check upgrade conditions
    Then the route bridge upgrade result should be True


  Scenario: Test check_upgrade_conditions - non-callable predicate
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a stream route config with non-callable custom_predicate
    And I have a stream message
    When I check upgrade conditions
    Then the route bridge upgrade result should be False


  Scenario: Test check_downgrade_conditions - no bridge config
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a route config without bridge configuration
    And I have a graph state
    When I check downgrade conditions
    Then the downgrade result should be False


  Scenario: Test check_downgrade_conditions - wrong route type
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a stream route config with bridge configuration
    And I have a graph state
    When I check downgrade conditions
    Then the downgrade result should be False


  Scenario: Test check_downgrade_conditions - idle_time condition
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a graph route config with idle_time downgrade condition
    And I have a graph state that has been idle too long
    When I check downgrade conditions
    Then the downgrade result should be True


  Scenario: Test check_downgrade_conditions - state_size condition
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a graph route config with state_size downgrade condition
    And I have a graph state with minimal messages
    When I check downgrade conditions
    Then the downgrade result should be True


  Scenario: Test check_downgrade_conditions - no_conditionals_used condition
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a graph route config with no_conditionals_used downgrade condition
    And I have a graph state with no conditional edges used
    When I check downgrade conditions
    Then the downgrade result should be True


  Scenario: Test _get_message_count functionality
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I seed a message count for the route
    When I get message count for a route
    Then the route bridge message count should be returned
    And the route bridge message count result should be a valid integer


  Scenario: Test error handling in downgrade_graph_to_stream
    Given I have a clean test environment for route bridge
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a graph route config for downgrade
    And I have a corrupted LangGraph instance
    When I attempt to downgrade graph to stream
    Then route bridge error handling should occur
    And the route bridge system should remain stable



  Scenario: Test complex upgrade downgrade cycle
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a route config that supports both upgrade and downgrade
    And I have a stream message with requires_state metadata
    When I perform an upgrade and then downgrade cycle
    Then the cycle should complete successfully
    And the final configuration should be consistent
    And active conversions should be tracked correctly


  # ============================================================
  # Originally from: route_bridge_uncovered_lines.feature
  # Feature: Additional route bridge uncovered lines coverage
  # ============================================================

  Scenario: Bridge falls back to empty agents on registry failure
    Given I have a clean test environment for route bridge
    Given I have a failing agent registry for route bridge
    When I create the route bridge instance
    Then the route bridge should be initialized correctly
    And the route bridge agents should be empty


  Scenario: Upgrade conditions not met when below message_count threshold
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a stream route config with message_count upgrade condition
    And I have a pending message count below threshold
    And I have a stream message
    When I check upgrade conditions
    Then the route bridge upgrade result should be False


  Scenario: Complexity threshold too high prevents upgrade
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a simple stream route config with high complexity threshold
    And I have a stream message
    When I check upgrade conditions
    Then the route bridge upgrade result should be False


  Scenario: Callable custom predicate triggers upgrade
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a stream route config with callable custom_predicate
    And I have a stream message
    When I check upgrade conditions synchronously
    Then the route bridge upgrade result should be True


  Scenario: Upgrade applies state extractor and preserves subscriptions loop
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a stream route config with state extractor and subscriptions
    And I have a stream message
    When I upgrade the stream route to graph
    Then the graph initial state should include extracted data


  Scenario: Downgrade uses flattener and checkpointing
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a graph route config with flattener and checkpointing
    And I have a LangGraph instance with checkpointing
    When I downgrade the graph with flattener
    Then the state flattener should run
    And the checkpoint should be saved


  Scenario: _create_graph_from_stream uses function node when no agent
    Given I have a clean test environment for route bridge
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    When I create a graph config from a stream without agents
    Then the resulting graph should use function nodes


  Scenario: _get_message_count falls back to update_count attribute
    Given I have a clean test environment for route bridge
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I seed a fallback update_count conversion
    When I get message count for a route
    Then the route bridge fallback message count should be returned


  Scenario: Downgrade conditions not met when idle time short
    Given I have a clean test environment for route bridge
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a graph route config with idle_time not exceeded
    And I have a graph state
    When I check downgrade conditions
    Then the downgrade result should be False


  Scenario: Downgrade conditions not met when state size large
    Given I have a clean test environment for route bridge
    Given I have a clean test environment for route bridge
    Given I have a RouteBridge instance
    And I have a graph route config with large state size
    And I have a graph state with multiple messages
    When I check downgrade conditions
    Then the downgrade result should be False


  # ============================================================
  # Originally from: route_coverage_comprehensive.feature
  # Feature: Route Module Comprehensive Coverage
  # ============================================================

  Scenario: RouteConfig validation for graph routes without nodes
    Given the route system is available
    Given I create a RouteConfig with graph type but no nodes
    When I validate the configuration
    Then I should get a ConfigurationError about missing nodes


  Scenario: RouteConfig to_stream_config conversion error
    Given the route system is available
    Given I create a RouteConfig with graph type
    When I try to convert it to StreamConfig
    Then I should get a ValueError about invalid conversion


  Scenario: RouteConfig to_graph_config conversion error
    Given the route system is available
    Given I create a RouteConfig with stream type
    When I try to convert it to GraphConfig
    Then I should get a ValueError about invalid conversion


  Scenario: RouteConfig from_stream_config class method
    Given the route system is available
    Given I have a valid StreamConfig
    When I create a RouteConfig from the StreamConfig
    Then the RouteConfig should have stream type
    And it should preserve all stream configuration details


  Scenario: RouteConfig from_graph_config class method
    Given the route system is available
    Given I have a valid GraphConfig with nodes and edges
    When I create a RouteConfig from the GraphConfig
    Then the RouteConfig should have graph type
    And it should preserve all graph configuration details
    And node configurations should be converted to dictionaries
    And edge configurations should be converted to dictionaries


  Scenario: RouteComplexityAnalyzer bridge type analysis
    Given the route system is available
    Given I have a RouteConfig with bridge type
    When I analyze the route complexity
    Then it should return bridge complexity analysis
    And the complexity should be "bridge"
    And the score should be 0


  Scenario: Stream complexity analysis with various features
    Given the route system is available
    Given I have stream routes with different features
    When I analyze each route complexity
    Then routes with more operators should have higher complexity scores
    And routes with routing connections should get additional score
    And hot streams should get additional score
    And the complexity classification should match the score ranges


  Scenario: Graph complexity analysis with conditional edges
    Given the route system is available
    Given I have graph routes with conditional edges
    When I analyze the graph complexity
    Then conditional edges should increase the complexity score
    And the features should include conditional edge information
    And checkpointing should increase the score
    And time travel should increase the score


  Scenario: Stream complexity recommendation logic
    Given the route system is available
    Given I have streams with different complexity scores
    When I get recommendations for each stream
    Then simple streams should get simple transformation recommendation
    And moderate streams should get multi-step processing recommendation
    And complex streams should get graph consideration recommendation


  Scenario: Graph complexity recommendation logic
    Given the route system is available
    Given I have graphs with different complexity scores
    When I get recommendations for each graph
    Then moderate graphs should get conditional logic recommendation
    And complex graphs should get stateful workflow recommendation
    And advanced graphs should get feature evaluation recommendation


  Scenario: Route type suggestion based on requirements
    Given the route system is available
    Given I have different requirement scenarios
    When I ask for route type suggestions
    Then persistence requirements should suggest graph
    And state with conditionals should suggest graph
    And conditionals without continuous should suggest graph
    And stateless continuous should suggest stream
    And simple cases should default to stream


  Scenario: RouteConfig post_init stream type defaulting
    Given the route system is available
    Given I create a stream RouteConfig without specifying stream_type
    When the post_init validation runs
    Then the stream_type should default to COLD


  Scenario: RouteConfig to_graph_config with complex node types
    Given the route system is available
    Given I have a RouteConfig with various node types and configurations
    When I convert it to GraphConfig
    Then all node types should be properly converted
    And all node properties should be preserved
    And retry policies and timeouts should be included
    And conditions and subgraphs should be handled
    And node metadata should be preserved in conversion


  # ============================================================
  # Originally from: routing_adapter_coverage.feature
  # Feature: Routing adapter coverage
  # ============================================================

  Scenario: Map operator creates agent node chain
    Given route operators include a map agent and function
    When I build route nodes from that stream
    Then it creates an agent node and chained edges to end
    And the function node is created with its type


  Scenario: Map without agent falls back to function node
    Given route operators include a map without agent
    When I build route nodes from that stream
    Then it treats the map as function and terminates chain with end node


  # ============================================================
  # Originally from: routing_langgraph_port.feature
  # Feature: Actor-first port of v2 routing and LangGraph suites
  # ============================================================

  Scenario: Route bridge converts stream to graph configuration
    Given the routing system is initialized for actor-first operation
    Given I have a stream route configuration
      """
      name: "test-stream"
      type: "stream"
      stream_type: "sequential"
      batch_size: 10
      """
    When I bridge the route to graph type
    Then the bridged route should be a graph configuration
    And the graph should have sequential execution
    And the graph should preserve batch settings


  Scenario: Unified route handles actor-only context variables
    Given the routing system is initialized for actor-first operation
    Given I have a unified route with context
      """
      name: "actor-route"
      type: "graph"
      actor: "openai/gpt-4"
      context_vars:
        temperature: 0.7
        max_tokens: 2000
      """
    When I process the unified route
    Then the route should use the specified actor
    And the context should include temperature and max_tokens
    And no provider/model fields should exist


  Scenario: Stream router validates actor configuration
    Given the routing system is initialized for actor-first operation
    Given I have a stream router configuration
      """
      routes:
        - name: "primary"
          actor: "anthropic/claude-3"
          stream_type: "parallel"
        - name: "fallback"  
          actor: "openai/gpt-3.5-turbo"
          stream_type: "sequential"
      """
    When I initialize the stream router
    Then the router should have 2 routes
    And each route should use its configured actor
    And the router should support actor-based fallback


  Scenario: LangGraph bridge handles state management
    Given the routing system is initialized for actor-first operation
    Given I have a LangGraph configuration with state
      """
      name: "stateful-graph"
      type: "graph"
      actor: "local/custom-agent"
      enable_checkpointing: true
      state_schema:
        current_task: "string"
        completed_steps: "array"
      """
    When I create a LangGraph bridge
    Then the bridge should enable checkpointing
    And the state schema should be preserved
    And the bridge should use the custom actor


  Scenario: Route complexity analysis with actor paths
    Given the routing system is initialized for actor-first operation
    Given I have a complex actor route configuration
      """
      name: "complex-route"
      type: "graph"
      nodes:
        - name: "analyze"
          actor: "openai/gpt-4"
          type: "llm"
        - name: "generate"
          actor: "anthropic/claude-3"
          type: "llm"
        - name: "validate"
          actor: "local/validator"
          type: "tool"
      edges:
        - from: "analyze"
          to: "generate"
        - from: "generate"
          to: "validate"
      """
    When I analyze the actor route complexity
    Then the complexity score should reflect multi-actor coordination
    And the analysis should identify 3 nodes and 2 edges
    And each node should use its assigned actor


  Scenario: Stream router handles parallel actor execution
    Given the routing system is initialized for actor-first operation
    Given I have parallel stream routes
      """
      routes:
        - name: "fast-route"
          actor: "openai/gpt-3.5-turbo"
          stream_type: "parallel"
          priority: 1
        - name: "accurate-route"
          actor: "anthropic/claude-3-opus"
          stream_type: "parallel"
          priority: 2
      execution_mode: "race"
      """
    When I execute the parallel streams
    Then both actors should be invoked concurrently
    And the first completion should be used
    And unused results should be properly cleaned up


  Scenario: Conditional routing based on actor capabilities
    Given the routing system is initialized for actor-first operation
    Given I have conditional routing configuration
      """
      name: "conditional-graph"
      type: "graph"
      nodes:
        - name: "router"
          type: "conditional"
          conditions:
            - if: "requires_vision"
              then: "vision_node"
            - if: "requires_code"
              then: "code_node"
            - else: "default_node"
        - name: "vision_node"
          actor: "openai/gpt-4-vision"
          type: "llm"
        - name: "code_node"
          actor: "anthropic/claude-3-opus"
          type: "llm"
        - name: "default_node"
          actor: "openai/gpt-3.5-turbo"
          type: "llm"
      """
    When I route with vision requirements
    Then the vision actor should be selected
    And the routing decision should be logged


  Scenario: Route validation rejects invalid actors
    Given the routing system is initialized for actor-first operation
    Given I have a route with invalid actor
      """
      name: "invalid-route"
      type: "stream"
      actor: "nonexistent/model"
      """
    When I validate the route configuration
    Then validation should fail with actor not found error
    And the error should suggest available actors


  Scenario: Bridge preserves actor-specific options
    Given the routing system is initialized for actor-first operation
    Given I have a route with actor options
      """
      name: "options-route"
      type: "stream"
      actor: "openai/gpt-4"
      actor_options:
        temperature: 0.9
        top_p: 0.95
        frequency_penalty: 0.5
      """
    When I bridge to a different route type
    Then the actor options should be preserved
    And the options should override defaults
    And the bridged route should maintain actor identity


  Scenario: Reactive streams with actor-based transformations
    Given the routing system is initialized for actor-first operation
    Given I have a reactive stream configuration
      """
      name: "transform-stream"
      type: "stream"
      stream_type: "transform"
      transformations:
        - stage: "parse"
          actor: "local/parser"
        - stage: "enrich"  
          actor: "openai/gpt-3.5-turbo"
        - stage: "format"
          actor: "local/formatter"
      """
    When I process data through the stream
    Then each transformation should use its actor
    And the data should flow through all stages
    And errors should be handled per-actor

  # ============================================================
  # Originally from: stream_router_additional_coverage.feature
  # Feature: Stream Router additional uncovered branches
  # ============================================================

  Scenario: Copying stream message with metadata override uses provided metadata
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    Given I have a base stream message with context metadata
    When I copy the message with explicit metadata override
    Then the copy should use the provided metadata


  Scenario: Creating a hot stream initializes with initial value
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I create a hot stream named "hot_stream" with initial value 5
    Then the hot stream should store the initial value


  Scenario: Creating a replay stream uses buffer size
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I create a replay stream named "replay_stream" with buffer size 3
    Then the replay stream should be created with buffer size 3


  Scenario: LangGraph operator without bridge raises routing error
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I build a langgraph operator "graph_execute" without bridge
    Then I should get a stream routing error about missing langgraph bridge


  Scenario: Map operator with unknown agent raises routing error
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I build a map operator targeting unknown agent "ghost"
    Then I should get a stream routing error about missing agent


  Scenario: Debounce, throttle, and delay operators are created
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I build debounce, throttle, and delay operators
    Then the temporal operators should be created successfully


  Scenario: Buffer and window operators with count are created
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I build buffer and window operators with count 2
    Then the buffer and window operators should be created successfully


  Scenario: Take and skip operators are created
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I build take and skip operators
    Then the take and skip operators should be created successfully


  Scenario: Merge operator merges existing streams
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    Given I have two source streams named "merge_x" and "merge_y"
    When I create a merge operator for those streams
    Then the merge operator should be usable


  Scenario: Accumulate operator with sum processes numbers
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I build an accumulate operator with sum
    Then the accumulate operator should sum incoming numbers


  Scenario: Transform extract_field returns field value
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I apply an extract_field transform to a dictionary message
    Then the extracted field should be returned


  Scenario: Evaluate condition equals and empty cases
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I evaluate empty and equals conditions against messages
    Then the empty condition should be true and equals should match


  Scenario: Agent mapper uses sync processor and handles errors
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I map messages through agent mapper success and failure paths
    Then the mapper should emit processed content and blank on error


  Scenario: Append accumulator with non-list leaves accumulator unchanged
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I apply append accumulator to non-list accumulator
    Then the accumulator should remain unchanged


  Scenario: Setup subscriptions ignores missing sources
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I setup subscriptions including a missing source
    Then no subscription should be added for the missing source


  Scenario: Split stream routes message when condition matches
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    Given I have a stream "source_split" and target "target_split"
    When I split the source stream with a matching condition
    Then the target stream should receive the routed message


  Scenario: Subscribing to output and error streams delivers messages
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    When I subscribe to output and error streams and emit messages
    Then the observers should receive the respective messages


  Scenario: Dispose handles stream dispose errors gracefully
    Given the CleverAgents reactive system is available
    And I have a base stream message with context metadata
    Given I have a stream router with disposable streams and subscriptions that may fail
    When I dispose the stream router with failing disposables
    Then the stream router internals should be cleared even on dispose errors


  # ============================================================
  # Originally from: stream_router_agent_tool_coverage.feature
  # Feature: Stream Router agent and tool coverage
  # ============================================================

  Scenario: SimpleToolAgent returns content when tool code is missing
    Given a SimpleToolAgent with a tool missing code
    When I process "payload" through the SimpleToolAgent
    Then the SimpleToolAgent result should be "payload"


  Scenario: SimpleToolAgent rejects tool with code block
    Given a SimpleToolAgent with a code block tool
    When I process "payload" through the SimpleToolAgent expecting rejection
    Then the SimpleToolAgent should raise a routing error about code blocks


  Scenario: SimpleToolAgent rejects code block via process_message_sync
    Given a SimpleToolAgent with a code block tool
    When I call process_message_sync with "payload" expecting rejection
    Then the SimpleToolAgent should raise a routing error about code blocks

    # TODO: Uncomment when step definitions are implemented
    #   Scenario: SimpleLLMAgent returns empty prompt for blank template
    #     Given a SimpleLLMAgent for prompt rendering
    #     When I render the template "<empty>" with context:
    #       | key  | value |
    #       | name | Ada   |
    #     Then the rendered prompt should be "<empty>"
    #
    # TODO: Uncomment when step definitions are implemented
    #   Scenario: SimpleLLMAgent returns raw template when environment is missing
    #     Given a SimpleLLMAgent for prompt rendering
    #     And the SimpleLLMAgent template environment is "none"
    #     When I render the template "Hello" with context:
    #       | key  | value |
    #       | name | Ada   |
    #     Then the rendered prompt should be "Hello"
    #
    # TODO: Uncomment when step definitions are implemented
    #   Scenario: SimpleLLMAgent renders template when environment succeeds
    #     Given a SimpleLLMAgent for prompt rendering
    #     And the SimpleLLMAgent template environment is "working"
    #     When I render the template "Hello {{ name }}" with context:
    #       | key  | value |
    #       | name | Ada   |
    #     Then the rendered prompt should be "Hello Ada"
    #
    # TODO: Uncomment when step definitions are implemented
    #   Scenario: SimpleLLMAgent falls back to template on render failure
    #     Given a SimpleLLMAgent for prompt rendering
    #     And the SimpleLLMAgent template environment is "failing"
    #     When I render the template "Hello {{ name }}" with context:
    #       | key  | value |
    #       | name | Ada   |
    #     Then the rendered prompt should be "Hello {{ name }}"


  Scenario: SimpleLLMAgent resolves LLM with configured kwargs and caching
    Given a SimpleLLMAgent with provider config
    And a stub provider registry is installed
    When I resolve the LLM twice
    Then the registry should be called once with the configured kwargs
    And the resolved LLM should be cached


  Scenario: SimpleLLMAgent raises when LangChain messages are unavailable
    Given a SimpleLLMAgent with provider config
    And a stub provider registry is installed
    And LangChain message classes are unavailable
    When I process "ping" through the LLM agent
    Then I should receive a stream routing error about missing messages


  Scenario: SimpleLLMAgent process_message_sync returns LLM content
    Given a SimpleLLMAgent with system prompt and provider config
    And a stub provider registry is installed
    And LangChain message stubs are installed
    When I process 123 through the LLM agent via process_message_sync
    Then the LLM should receive system and human messages
    And the LLM agent result should be "llm-output"


  # ============================================================
  # Originally from: stream_router_coverage.feature
  # Feature: Stream Router Coverage
  # ============================================================

  # ============================================================
  # Originally from: stream_router_misc_uncovered.feature
  # Feature: Stream Router remaining uncovered lines
  # ============================================================

  Scenario: Converting dict route config uses defaults
    Given the CleverAgents reactive system is available
    When I convert a dict route config with only a name
    Then the stream config should use default values


  Scenario: Converting object route config uses defaults for missing attrs
    Given the CleverAgents reactive system is available
    When I convert a minimal object route config
    Then the stream config should use default values


  Scenario: Transform operator with type parameter applies replace
    Given the CleverAgents reactive system is available
    When I apply a transform operator with type replace
    Then the transform operator should update the field


  Scenario: Switch operator emits original message with no matches or defaults
    Given the CleverAgents reactive system is available
    When I run a switch operator with no matches and no defaults
    Then the switch operator should emit the original message


  Scenario: Unsupported condition returns false
    Given the CleverAgents reactive system is available
    When I evaluate an unsupported condition
    Then the unsupported condition result should be false


  Scenario: Agent mapper falls back when no processing methods exist
    Given the CleverAgents reactive system is available
    When I map a message with an agent lacking processors
    Then the mapper should return the original content with metadata


  # ============================================================
  # Originally from: stream_router_new_branches.feature
  # Feature: Stream Router additional uncovered branches
  # ============================================================

  Scenario: LangGraph operator uses bridge factory when available
    Given the CleverAgents reactive system is available
    Given a LangGraph bridge stub is registered on the stream router
    When I build a graph_execute operator through the bridge
    Then the bridge factory should be invoked and map data


  Scenario: Map operator processes message through registered agent
    Given the CleverAgents reactive system is available
    Given a dummy agent is registered on the stream router
    When I map a message using that agent
    Then the agent-mapped content should be returned with metadata


  Scenario: Filter operator passes matching condition
    Given the CleverAgents reactive system is available
    When I build a filter operator with equals condition
    Then the filter should emit only matching values


  Scenario: Transform operator rejects unregistered fn string
    Given the CleverAgents reactive system is available
    When I build a transform operator with an unregistered function string
    Then I should get a stream routing error about unregistered transform


  Scenario: Switch operator handles case operators pipeline
    Given the CleverAgents reactive system is available
    When I run a switch operator with a case operator pipeline
    Then the switch case should apply its operators


  Scenario: Switch operator routes to a target stream case
    Given the CleverAgents reactive system is available
    Given I have an existing target stream named "case_target"
    When I run a switch operator that routes to that case target
    Then the case target stream should receive the message


  Scenario: Unknown operator raises routing error
    Given the CleverAgents reactive system is available
    When I build an operator with an unknown type
    Then I should get a stream routing error about unknown operator


  Scenario: Extract field transform returns requested value and fallback
    Given the CleverAgents reactive system is available
    When I apply an extract_field transform to different message types
    Then the transform should return the field value or original message


  Scenario: Evaluate condition supports equals and field branches
    Given the CleverAgents reactive system is available
    When I evaluate equals and field conditions
    Then both condition checks should return true


  Scenario: Append accumulator returns unchanged when accumulator is not a list
    Given the CleverAgents reactive system is available
    When I apply the append accumulator to a non-list accumulator
    Then the accumulator should be returned unchanged


  Scenario: Setup subscriptions skips missing sources and subscribes existing
    Given the CleverAgents reactive system is available
    Given I prepare stream config with existing and missing subscriptions
    When I setup subscriptions for that config
    Then only existing sources should be subscribed


  # ============================================================
  # Originally from: stream_router_remaining_coverage.feature
  # Feature: Reactive Stream Router Edge Cases
  # ============================================================

  Scenario: Registering an operation with non-alphanumeric characters is rejected
    Given a fresh SimpleToolAgent registry
    When I register an operation named "bad-name!" with a lambda
    Then a ValueError should be raised about operation name format


  Scenario: A tool agent with a malformed tool entry passes content through unchanged
    Given a SimpleToolAgent whose tools list contains a non-dict entry
    When I process content "hello" through that SimpleToolAgent
    Then the SimpleToolAgent should return "hello" unchanged


  Scenario: A tool agent with an unrecognised operation name passes content through unchanged
    Given a SimpleToolAgent with an unknown operation "nonexistent_op"
    When I process content "data" through that SimpleToolAgent
    Then the SimpleToolAgent should return "data" unchanged


  Scenario: A tool agent safely returns empty output when an operation throws
    Given a SimpleToolAgent with an operation that raises an exception
    When I process content "boom" through that SimpleToolAgent
    Then the SimpleToolAgent should return an empty string

    # Transform registration safety


  Scenario: Registering a transform with non-alphanumeric characters is rejected
    Given a fresh ReactiveStreamRouter registry
    When I register a transform named "bad@name" with a lambda
    Then a ValueError should be raised about transform name format

    # Operator construction validation


  Scenario: A transform operator created without a function or type is rejected
    Given a reactive stream router for coverage
    And a stream named "transform_test" exists on the router
    When I create a transform operator with neither fn nor type
    Then a StreamRoutingError should be raised about missing transform params

    # LLM agent provider resolution


  Scenario: An LLM agent resolves its provider without forwarding absent optional parameters
    Given a SimpleLLMAgent with no temperature or max_tokens or max_retries
    And a stub provider registry is active
    When I resolve the LLM on that agent
    Then the LLM should be resolved without optional kwargs


  Scenario: An LLM agent with no system prompt sends only the user message to the model
    Given a SimpleLLMAgent with an empty system prompt
    And a stub provider registry is active
    When I process content "test input" through that SimpleLLMAgent
    Then the LLM should receive only a HumanMessage

    # LangGraph bridge delegation


  Scenario: A graph operator delegates to the bridge factory when the method exists
    Given a reactive stream router for coverage
    And a LangGraph bridge stub with a graph_execute factory is registered
    When I create a graph_execute operator via the bridge
    Then the bridge factory method should produce a valid operator


  Scenario: A graph operator raises a clear error when the bridge lacks the factory method
    Given a reactive stream router for coverage
    And a LangGraph bridge stub without the requested factory method is registered
    When I attempt to create a graph_execute operator via the bridge
    Then a StreamRoutingError should be raised about LangGraph bridge

    # Switch operator resilience


  Scenario: A switch case pipeline tolerates an operator that resolves to nothing
    Given a reactive stream router for coverage
    And a stream named "switch_null_op" exists on the router
    When I run a switch operator whose case pipeline includes a None operator
    Then the switch should still emit the message through the pipeline


  Scenario: A switch case with a nonexistent target stream falls through to the default
    Given a reactive stream router for coverage
    And a stream named "switch_missing_target" exists on the router
    When I run a switch with a matching case whose target stream does not exist
    Then the switch should fall through to the default


  Scenario: A switch default pipeline tolerates an operator that resolves to nothing
    Given a reactive stream router for coverage
    And a stream named "switch_default_null" exists on the router
    When I run a switch operator whose default pipeline includes a None operator
    Then the switch should still emit the message through the default pipeline

    # Message transformation edge cases


  Scenario: A replace transform on a non-dictionary message passes it through unchanged
    Given a reactive stream router for coverage
    When I apply a replace transform to a non-dict message
    Then the message should be returned unchanged


  Scenario: An extract-field transform retrieves the named value from a dictionary message
    Given a reactive stream router for coverage
    When I apply an extract_field transform to a dict message with the field
    Then the extracted field value should be returned


  Scenario: An extract-field transform on a non-dictionary message passes it through
    Given a reactive stream router for coverage
    When I apply an extract_field transform to a non-dict message
    Then the non-dict message should be returned from extract_field


  Scenario: An unrecognised transform type passes the message through unchanged
    Given a reactive stream router for coverage
    When I apply a transform with unknown type to a message
    Then the original message should be returned

    # Condition evaluation edge cases


  Scenario: A field condition matches when the dictionary message contains the field
    Given a reactive stream router for coverage
    When I evaluate a field condition against a dict message containing the field
    Then the condition should return true


  Scenario: A field condition does not match when the dictionary message lacks the field
    Given a reactive stream router for coverage
    When I evaluate a field condition against a dict message missing the field
    Then the condition should return false


  Scenario: A field condition does not match against a non-dictionary message
    Given a reactive stream router for coverage
    When I evaluate a field condition against a non-dict message
    Then the condition should return false

    # Stream splitting and merging edge cases


  Scenario: Splitting a stream ignores condition targets that do not exist
    Given a reactive stream router for coverage
    And a stream named "split_source" exists on the router
    When I split the stream with a condition targeting a nonexistent stream
    Then no error should occur and the message should not route


  Scenario: Merging streams into a nonexistent target auto-creates it
    Given a reactive stream router for coverage
    And a stream named "merge_src_a" exists on the router
    And a stream named "merge_src_b" exists on the router
    When I merge streams into a target that does not exist yet
    Then the target stream should be created and receive merged messages


  Scenario: Merging streams silently skips source streams that do not exist
    Given a reactive stream router for coverage
    And a stream named "merge_src_c" exists on the router
    When I merge streams including a nonexistent source into an existing target
    Then only the existing source should be subscribed

    # Router disposal


  Scenario: Disposing the router tolerates streams that lack a dispose method
    Given a reactive stream router for coverage
    And a stream that lacks a dispose method is injected into the router
    When I dispose the router
    Then the router should be fully cleared without errors


  # ============================================================
  # Originally from: stream_router_uncovered_paths.feature
  # Feature: Stream Router uncovered branches
  # ============================================================

  Scenario: Copying stream message without metadata override deep copies entries
    Given the CleverAgents reactive system is available
    Given I have a base stream message with context metadata
    When I copy the message without metadata override
    Then the metadata should be deep-copied except context


  Scenario: Map operator without params should raise routing error
    Given the CleverAgents reactive system is available
    When I build a map operator without required params
    Then I should get a stream routing error about missing map params


  Scenario: Buffer operator without count should raise routing error
    Given the CleverAgents reactive system is available
    When I build a buffer operator without count
    Then I should get a stream routing error about buffer count


  Scenario: Window operator without count should raise routing error
    Given the CleverAgents reactive system is available
    When I build a window operator without count
    Then I should get a stream routing error about window count


  Scenario: Condition check for missing field returns false
    Given the CleverAgents reactive system is available
    When I evaluate a field condition against a message without that field
    Then the condition result should be false


  Scenario: Accumulator append initializes list and appends items
    Given the CleverAgents reactive system is available
    When I apply the append accumulator with list initialization
    Then the accumulator should return a list with the item


  Scenario: Sending message to unknown stream raises routing error
    Given the CleverAgents reactive system is available
    When I send a message to an unknown stream
    Then I should get a stream routing error about missing stream


  Scenario: Splitting from unknown source raises routing error
    Given the CleverAgents reactive system is available
    When I split a stream from an unknown source
    Then I should get a stream routing error about missing source


  Scenario: Creating stream using string name initializes config
    Given the CleverAgents reactive system is available
    When I create a stream from the string name "string_stream"
    Then the stream should exist in the router


  Scenario: Duplicate stream creation raises routing error
    Given the CleverAgents reactive system is available
    Given I have already created a stream named "dup_stream"
    When I try to create the stream "dup_stream" again
    Then I should get a stream routing error about duplicate stream


  Scenario: Map operator with function param uses fallback
    Given the CleverAgents reactive system is available
    When I map a message using function param "noop_function"
    Then the mapped result should equal the original message


  Scenario: Transform operator with unregistered fn raises error
    Given the CleverAgents reactive system is available
    When I build a transform operator with an invalid function string
    Then I should get a stream routing error about unregistered transform fn


  Scenario: Filter operator without condition raises routing error
    Given the CleverAgents reactive system is available
    When I build a filter operator without condition
    Then I should get a stream routing error about missing filter condition


  Scenario: Switch operator applies default operators pipeline
    Given the CleverAgents reactive system is available
    When I run a switch operator with default operators against a message
    Then the switch operator should output the transformed value


  Scenario: Switch operator routes to default stream subject
    Given the CleverAgents reactive system is available
    When I run a switch operator that targets a default stream subject
    Then the default stream should emit its initial value


  Scenario: Apply replace transform updates dictionary field
    Given the CleverAgents reactive system is available
    When I apply a replace transform to a dictionary message
    Then the dictionary field should be updated


  Scenario: Sum accumulator initializes and sums numeric messages
    Given the CleverAgents reactive system is available
    When I apply the sum accumulator to numeric messages
    Then the accumulator should produce the summed value


  Scenario: Merge streams creates target when missing
    Given the CleverAgents reactive system is available
    Given I have two source streams named "merge_a" and "merge_b"
    When I merge the streams into a new target "merge_output"
    Then the merged target stream should exist


  Scenario: Dispose cleans up subscriptions and stream disposables
    Given the CleverAgents reactive system is available
    Given I have a stream router with disposable streams and subscriptions
    When I dispose the stream router
    Then the stream router internals should be cleared


  # ============================================================
  # Originally from: stream_router_unsafe_and_llm_coverage.feature
  # Feature: SimpleToolAgent code block rejection and SimpleLLMAgent render_prompt coverage
  # ============================================================

  Scenario: SimpleToolAgent rejects code block even with unsafe flag
    Given a stream router unsafe tool agent with a valid code block
    When the stream router unsafe agent processes input expecting rejection
    Then the stream router unsafe agent should raise StreamRoutingError about code


  Scenario: SimpleToolAgent rejects failing code block even with unsafe flag
    Given a stream router unsafe tool agent with a failing code block
    When the stream router unsafe agent processes input expecting rejection
    Then the stream router unsafe agent should raise StreamRoutingError about code


  Scenario: SimpleToolAgent safe mode rejects code blocks
    Given a stream router safe tool agent with a code block
    When the stream router safe agent processes input expecting rejection
    Then the stream router safe agent should raise StreamRoutingError about code


  Scenario: SimpleLLMAgent render_prompt with no template env returns template as-is
    Given a stream router llm agent with no template env
    When the stream router llm agent renders "Hello {{ name }}" with context name "World"
    Then the stream router llm render result should be "Hello {{ name }}"


  Scenario: SimpleLLMAgent render_prompt with template env failure returns template
    Given a stream router llm agent with a failing template env
    When the stream router llm agent renders "Hello {{ name }}" with context name "World"
    Then the stream router llm render result should be "Hello {{ name }}"


  Scenario: SimpleLLMAgent render_prompt with empty template returns empty string
    Given a stream router llm agent for empty template test
    When the stream router llm agent renders empty template
    Then the stream router llm render result should be empty string


  Scenario: SimpleToolAgent processes named operation successfully
    Given a stream router tool agent with uppercase operation
    When the stream router tool agent processes "hello" through operation
    Then the stream router tool agent operation result should be "HELLO"


  Scenario: SimpleToolAgent processes unknown operation falls back to identity
    Given a stream router tool agent with unknown operation "nonexistent_xyz"
    When the stream router tool agent processes "keep_me" through operation
    Then the stream router tool agent operation result should be "keep_me"

  # M5: SimpleLLMAgent._resolve_llm forwards options to registry.create_llm (#11223).
  @tdd_issue @tdd_issue_11223
  Scenario: SimpleLLMAgent forwards options block to LLM constructor
    Given a stream router llm agent with options block containing custom base url
    When the stream router llm agent resolves the llm
    Then the llm constructor should have received the custom base url

  # M5: actor without options block is unaffected (#11223).
  @tdd_issue @tdd_issue_11223
  Scenario: SimpleLLMAgent without options block calls LLM constructor without extra kwargs
    Given a stream router llm agent without options block
    When the stream router llm agent resolves the llm
    Then the llm constructor should not have received extra kwargs

  # M5: top-level keys take precedence over duplicates in options (#11223).
  @tdd_issue @tdd_issue_11223
  Scenario: SimpleLLMAgent top-level key takes precedence over options duplicate
    Given a stream router llm agent with top-level temperature and options block
    When the stream router llm agent resolves the llm
    Then the llm constructor should have received the top-level temperature

