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"