Feature: Actor options propagation to LLM constructor
  Tests that actor-level `options` (openai_api_base, openai_api_key, etc.)
  are correctly forwarded to `ProviderRegistry.create_llm()` across all
  call sites: Strategize phase, Execute phase, and SessionWorkflow.

  Forgejo: #11256

  # ------------------------------------------------------------------
  # build_llm_kwargs_from_options shared utility
  # ------------------------------------------------------------------

  Scenario: build_llm_kwargs_from_options forwards openai_api_base
    Given aop actor options with "openai_api_base" set to "http://localhost:8000/v1"
    When I call build_llm_kwargs_from_options
    Then the result should contain "openai_api_base" with value "http://localhost:8000/v1"

  Scenario: build_llm_kwargs_from_options routes openai_api_key through sentinel
    Given aop actor options with "openai_api_key" set to "none"
    When I call build_llm_kwargs_from_options
    Then the result should contain "__api_key_sentinel" with value "none"
    And the result should not contain "openai_api_key"

  Scenario: build_llm_kwargs_from_options forwards allowed temperature
    Given aop actor options with "temperature" set to "0.7"
    When I call build_llm_kwargs_from_options
    Then the result should contain "temperature" with value 0.7

  Scenario: build_llm_kwargs_from_options rejects reserved keys
    Given aop actor options with "provider_type" set to "anthropic"
    When I call build_llm_kwargs_from_options
    Then the result should not contain "provider_type"

  Scenario: build_llm_kwargs_from_options rejects unknown keys
    Given aop actor options with "dangerous_param" set to "value"
    When I call build_llm_kwargs_from_options
    Then the result should not contain "dangerous_param"

  Scenario: build_llm_kwargs_from_options with None returns empty dict
    Given aop actor options is None
    When I call build_llm_kwargs_from_options
    Then the result should be an empty dict

  Scenario: build_llm_kwargs_from_options with empty dict returns empty dict
    Given aop actor options is an empty dict
    When I call build_llm_kwargs_from_options
    Then the result should be an empty dict

  Scenario: build_llm_kwargs_from_options forwards multiple allowed keys
    Given aop actor options with "openai_api_base" set to "http://local:8000/v1"
    And aop actor options with "max_tokens" set to "2048"
    And aop actor options with "timeout" set to "60"
    When I call build_llm_kwargs_from_options
    Then the result should contain "openai_api_base" with value "http://local:8000/v1"
    And the result should contain "max_tokens" with value 2048
    And the result should contain "timeout" with value 60

  # ------------------------------------------------------------------
  # StrategyActor forwards actor options to create_llm
  # ------------------------------------------------------------------

Scenario: StrategyActor resolves actor options and forwards to create_llm
    Given aop a mock lifecycle service that resolves actor "local/test-strategist"
    And aop the resolved actor options contain "openai_api_base" set to "http://backend:9000/v1"
    And aop the resolved actor options contain "openai_api_key" set to "test-key"
    And aop a mock provider registry that captures create_llm kwargs with LLM response
    When aop the StrategyActor executes with LLM for plan "01KSQ4ADB3AVXTWEK2DD0ZJDKN"
    Then aop create_llm should have been called
    And aop create_llm kwargs should contain "openai_api_base" with value "http://backend:9000/v1"
    And aop create_llm kwargs should contain "__api_key_sentinel" with value "test-key"

  Scenario: StrategyActor creates LLM without options when actor has no options
    Given aop a mock lifecycle service that resolves actor "openai/gpt-4"
    And aop the resolved actor options is None
    And aop a mock provider registry that captures create_llm kwargs with LLM response
    When aop the StrategyActor executes with LLM for plan "01KSQ4ADB3AVXTWEK2DD0ZJCKN"
    Then aop create_llm should have been called
    And aop create_llm kwargs should not contain "openai_api_base"

  # ------------------------------------------------------------------
  # LLMStrategizeActor forwards actor options to create_llm
  # ------------------------------------------------------------------

  Scenario: LLMStrategizeActor forwards actor options to create_llm
    Given aop a valid LLMStrategizeActor with actor options
    When aop I call strategize execute with plan_id "PLAN_OPT" and stream callback
    Then aop the strategize create_llm should have received "openai_api_base" with value "http://custom-backend:7000/v1"
    And aop the strategize create_llm should have received "__api_key_sentinel" with value "local-key"

  Scenario: LLMStrategizeActor creates LLM without options when none exist
    Given aop a valid LLMStrategizeActor without actor options
    When aop I call strategize execute with plan_id "PLAN_NOOPT" and no stream callback
    Then aop the strategize create_llm should not have received "openai_api_base"
    And aop the strategize create_llm should not have received "__api_key_sentinel"

  # ------------------------------------------------------------------
  # LLMExecuteActor forwards actor options to create_llm
  # ------------------------------------------------------------------

  Scenario: LLMExecuteActor forwards actor options to create_llm
    Given aop a valid LLMExecuteActor with actor options
    When aop I call execute actor with plan_id "EXEC_OPT" and read_only False
    Then aop the execute create_llm should have received "openai_api_base" with value "http://custom-executor:9000/v1"
    And aop the execute create_llm should have received "__api_key_sentinel" with value "exec-key"

  Scenario: LLMExecuteActor creates LLM without options when none exist
    Given aop a valid LLMExecuteActor without actor options
    When aop I call execute actor with plan_id "EXEC_NOOPT" and read_only False
    Then aop the execute create_llm should not have received "openai_api_base"
    And aop the execute create_llm should not have received "__api_key_sentinel"