Files

1 line
34 KiB
JSON

{"repo": "5eanxlee/open-research", "files": {"src/open_research/core/config.py": {"8526d9635db920f53a77532e90950ecd74fbe6d9": {"t": 1785746897.786547, "n": 16166, "h": "a40d60c6b851a0f1", "c": "from __future__ import annotations\n\nimport importlib.util\nfrom functools import lru_cache\nfrom typing import Literal\n\nfrom pydantic import AliasChoices, Field, SecretStr\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\n\ndef _looks_like_openai_key(secret: SecretStr | None) -> bool:\n if secret is None:\n return False\n value = secret.get_secret_value().strip()\n # OpenAI project/user keys are currently issued with an sk- prefix.\n return value.startswith(\"sk-\")\n\n\nclass Settings(BaseSettings):\n model_config = SettingsConfigDict(\n env_file=\".env\",\n env_file_encoding=\"utf-8\",\n env_prefix=\"OPEN_RESEARCH_\",\n populate_by_name=True,\n env_ignore_empty=True,\n extra=\"ignore\",\n )\n\n app_name: str = \"Open Research\"\n environment: Literal[\"development\", \"test\", \"production\"] = \"development\"\n database_url: str = Field(\n default=\"sqlite+aiosqlite:///./openresearch.db\",\n validation_alias=AliasChoices(\"DATABASE_URL\", \"OPEN_RESEARCH_DATABASE_URL\"),\n )\n\n llm_backend: Literal[\"auto\", \"heuristic\", \"openai\", \"openai_compatible\"] = \"auto\"\n search_backend: Literal[\"auto\", \"mock\", \"openai\", \"brave\", \"exa\", \"tavily\"] = \"auto\"\n fetch_backend: Literal[\n \"auto\",\n \"mock\",\n \"firecrawl\",\n \"browserbase\",\n \"browserbase_session\",\n \"playwright\",\n ] = \"auto\"\n workflow_backend: Literal[\"auto\", \"local\", \"temporal\"] = \"auto\"\n database_bootstrap_mode: Literal[\"auto\", \"create_all\"] = \"auto\"\n artifact_store_backend: Literal[\"auto\", \"disabled\", \"local\", \"s3\"] = \"auto\"\n embedding_backend: Literal[\"auto\", \"disabled\", \"mock\", \"openai\", \"openai_compatible\"] = \"auto\"\n reranker_backend: Literal[\"auto\", \"disabled\", \"heuristic\", \"sentence_transformers\"] = \"auto\"\n process_role: Literal[\"all\", \"api\", \"worker\"] = \"all\"\n event_pubsub_mode: Literal[\"memory\", \"database\"] = \"database\"\n\n openai_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"OPENAI_API_KEY\", \"OPEN_RESEARCH_OPENAI_API_KEY\"),\n )\n openai_base_url: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"OPENAI_BASE_URL\", \"OPEN_RESEARCH_OPENAI_BASE_URL\"),\n )\n llm_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"LLM_API_KEY\", \"OPEN_RESEARCH_LLM_API_KEY\"),\n )\n llm_base_url: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"LLM_BASE_URL\", \"OPEN_RESEARCH_LLM_BASE_URL\"),\n )\n embedding_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"EMBEDDING_API_KEY\",\n \"OPEN_RESEARCH_EMBEDDING_API_KEY\",\n ),\n )\n embedding_base_url: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"EMBEDDING_BASE_URL\",\n \"OPEN_RESEARCH_EMBEDDING_BASE_URL\",\n ),\n )\n brave_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"BRAVE_API_KEY\", \"OPEN_RESEARCH_BRAVE_API_KEY\"),\n )\n exa_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"EXA_API_KEY\", \"OPEN_RESEARCH_EXA_API_KEY\"),\n )\n tavily_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"TAVILY_API_KEY\", \"OPEN_RESEARCH_TAVILY_API_KEY\"),\n )\n serper_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"SERPER_API_KEY\", \"OPEN_RESEARCH_SERPER_API_KEY\"),\n )\n firecrawl_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"FIRECRAWL_API_KEY\", \"OPEN_RESEARCH_FIRECRAWL_API_KEY\"),\n )\n browserbase_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"BROWSERBASE_API_KEY\",\n \"OPEN_RESEARCH_BROWSERBASE_API_KEY\",\n ),\n )\n browserbase_project_id: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"BROWSERBASE_PROJECT_ID\",\n \"OPEN_RESEARCH_BROWSERBASE_PROJECT_ID\",\n ),\n )\n worker_id: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"WORKER_ID\", \"OPEN_RESEARCH_WORKER_ID\"),\n )\n\n temporal_target_url: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"TEMPORAL_TARGET_URL\",\n \"OPEN_RESEARCH_TEMPORAL_TARGET_URL\",\n ),\n )\n temporal_namespace: str = Field(\n default=\"default\",\n validation_alias=AliasChoices(\n \"TEMPORAL_NAMESPACE\",\n \"OPEN_RESEARCH_TEMPORAL_NAMESPACE\",\n ),\n )\n temporal_task_queue: str = Field(\n default=\"open-research\",\n validation_alias=AliasChoices(\n \"TEMPORAL_TASK_QUEUE\",\n \"OPEN_RESEARCH_TEMPORAL_TASK_QUEUE\",\n ),\n )\n temporal_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"TEMPORAL_API_KEY\",\n \"OPEN_RESEARCH_TEMPORAL_API_KEY\",\n ),\n )\n temporal_tls: bool = Field(\n default=True,\n validation_alias=AliasChoices(\"TEMPORAL_TLS\", \"OPEN_RESEARCH_TEMPORAL_TLS\"),\n )\n\n lead_model: str = \"gpt-5.5\"\n planner_model: str = \"gpt-5.5\"\n worker_model: str = \"gpt-5.5\"\n verifier_model: str = \"gpt-5.5\"\n embedding_model: str = \"text-embedding-3-large\"\n reranker_model: str = \"BAAI/bge-reranker-v2-m3\"\n openai_web_search_model: str | None = None\n openai_web_search_context_size: Literal[\"low\", \"medium\", \"high\"] = \"medium\"\n openai_web_search_reasoning_effort: Literal[\"low\", \"medium\", \"high\"] = \"high\"\n openai_web_search_external_web_access: bool = True\n openai_web_search_max_output_tokens: int = 4096\n openai_web_search_timeout_seconds: float = 180.0\n llm_reasoning_effort: Literal[\"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"] = \"high\"\n llm_api_style: Literal[\"auto\", \"responses\", \"chat_completions\"] = \"auto\"\n llm_structured_output_mode: Literal[\"auto\", \"parse\", \"json_schema\", \"prompted\"] = \"auto\"\n llm_supports_reasoning_effort: bool | None = None\n llm_model_family: Literal[\"auto\", \"generic\", \"openai\", \"glm\", \"qwen\", \"deepseek\"] = \"auto\"\n prompt_mode: Literal[\"code\", \"template\", \"hybrid\"] = \"hybrid\"\n prompt_template_root: str | None = None\n prompt_template_strict: bool = False\n prompt_template_family_fallback: bool = True\n prompt_reload_in_dev: bool = True\n prompt_externalization_enabled: bool = True\n custom_responses_runtime_backend: Literal[\"auto\", \"pipeline\", \"deepagents\"] = \"auto\"\n research_runtime_backend: Literal[\"auto\", \"langgraph\", \"deepagents\", \"hybrid\"] = \"auto\"\n deep_plan_approval_enabled: bool = True\n source_registry_ui_enabled: bool = True\n async_jobs_enabled: bool = True\n enforce_maximal_research_path: bool = True\n\n max_streams: int = 30\n max_replans: int = 1\n max_queries_per_stream: int = 25\n max_results_per_query: int = 5\n max_sources_per_stream: int = 3\n per_domain_limit: int = 2\n planner_min_discovery_queries: int = 10\n planner_max_discovery_queries: int = 16\n planner_min_total_sources_retrieved: int = 8\n planner_min_total_cited_sources: int = 4\n planner_validation_enabled: bool = True\n planner_max_validation_retries: int = 2\n planner_discovery_concurrency: int = 3\n deepagents_max_research_batches: int = 6\n deepagents_require_critic_pass: bool = True\n deepagents_require_source_audit_pass: bool = True\n deepagents_require_citation_pass: bool = True\n deepagents_grounding_enabled: bool = True\n deepagents_grounding_strict: bool = False\n completion_gate_min_chars: int = 2000\n completion_gate_min_headings: int = 2\n completion_gate_max_attempts: int = 5\n tool_registry_enabled: bool = True\n max_search_tool_calls_per_run: int = 200\n max_fetch_tool_calls_per_run: int = 200\n max_embedding_tool_calls_per_run: int = 500\n max_upload_file_size_bytes: int = 50 * 1024 * 1024\n max_upload_files_per_batch: int = 20\n max_ocr_pdf_pages: int = 200\n pdf_text_extraction_min_chars: int = 80\n\n http_timeout_seconds: float = 30.0\n sse_keepalive_seconds: float = 10.0\n automatic_run_recovery: bool = True\n max_claim_repairs: int = 1\n claim_repair_max_results: int = 2\n search_request_cost_usd: float = 0.0\n fetch_request_cost_usd: float = 0.0\n embedding_request_cost_usd: float = 0.0\n browserbase_use_proxies: bool = False\n browserbase_session_keep_alive: bool = False\n playwright_timeout_seconds: float = 15.0\n temporal_activity_timeout_seconds: int = 5400\n temporal_heartbeat_seconds: int = 10\n temporal_start_worker: bool = True\n temporal_worker_shutdown_seconds: float = 5.0\n run_heartbeat_seconds: float = 10.0\n stale_run_timeout_seconds: float = 120.0\n reconciler_interval_seconds: float = 15.0\n artifact_store_path: str = \"./artifacts\"\n artifact_store_s3_bucket: str | None = None\n artifact_store_s3_prefix: str = \"open-research\"\n artifact_store_s3_endpoint_url: str | None = None\n embedding_dimensions: int = 1536\n grounding_candidate_limit: int = 12\n grounding_max_claims_per_run: int = 4\n provider_retry_attempts: int = 3\n provider_retry_base_seconds: float = 0.5\n provider_retry_max_seconds: float = 4.0\n provider_cooldown_failures: int = 3\n provider_cooldown_seconds: float = 30.0\n metrics_enabled: bool = True\n profile_memory_enabled: bool = True\n behavior_assessment_enabled: bool = True\n otlp_endpoint: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"OTLP_ENDPOINT\", \"OPEN_RESEARCH_OTLP_ENDPOINT\"),\n )\n otlp_headers: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"OTLP_HEADERS\", \"OPEN_RESEARCH_OTLP_HEADERS\"),\n )\n langfuse_public_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"LANGFUSE_PUBLIC_KEY\",\n \"OPEN_RESEARCH_LANGFUSE_PUBLIC_KEY\",\n ),\n )\n langfuse_secret_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"LANGFUSE_SECRET_KEY\",\n \"OPEN_RESEARCH_LANGFUSE_SECRET_KEY\",\n ),\n )\n langfuse_host: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"LANGFUSE_HOST\", \"OPEN_RESEARCH_LANGFUSE_HOST\"),\n )\n trace_redaction_fields: str = (\n \"authorization,cookie,set-cookie,api_key,token,password,secret,prompt,content,headers,body\"\n )\n\n @property\n def resolved_llm_backend(self) -> Literal[\"heuristic\", \"openai\", \"openai_compatible\"]:\n if self.llm_backend != \"auto\":\n return self.llm_backend\n if _looks_like_openai_key(self.openai_api_key):\n return \"openai\"\n if self.llm_base_url or self.llm_api_key:\n return \"openai_compatible\"\n return \"heuristic\"\n\n @property\n def resolved_llm_api_style(self) -> Literal[\"responses\", \"chat_completions\"]:\n if self.llm_api_style != \"auto\":\n return self.llm_api_style\n if self.resolved_llm_backend == \"openai\":\n return \"responses\"\n return \"chat_completions\"\n\n @property\n def resolved_llm_structured_output_mode(\n self,\n ) -> Literal[\"parse\", \"json_schema\", \"prompted\"]:\n if self.llm_structured_output_mode != \"auto\":\n return self.llm_structured_output_mode\n if self.resolved_llm_backend == \"openai\":\n return \"parse\"\n return \"json_schema\"\n\n @property\n def resolved_llm_supports_reasoning_effort(self) -> bool:\n if self.llm_supports_reasoning_effort is not None:\n return self.llm_supports_reasoning_effort\n return self.resolved_llm_backend == \"openai\"\n\n @property\n def resolved_llm_model_family(self) -> Literal[\"generic\", \"openai\", \"glm\", \"qwen\", \"deepseek\"]:\n if self.llm_model_family != \"auto\":\n return self.llm_model_family\n model_names = \" \".join(\n [self.lead_model, self.planner_model, self.worker_model, self.verifier_model]\n ).lower()\n if \"gpt\" in model_names:\n return \"openai\"\n if \"glm\" in model_names:\n return \"glm\"\n if \"qwen\" in model_names:\n return \"qwen\"\n if \"deepseek\" in model_names:\n return \"deepseek\"\n return \"generic\"\n\n @property\n def resolved_custom_responses_runtime_backend(self) -> Literal[\"pipeline\", \"deepagents\"]:\n if self.custom_responses_runtime_backend != \"auto\":\n return self.custom_responses_runtime_backend\n if (\n self.resolved_llm_backend == \"openai\"\n and _looks_like_openai_key(self.openai_api_key)\n and importlib.util.find_spec(\"deepagents\") is not None\n and importlib.util.find_spec(\"langchain_openai\") is not None\n ):\n return \"deepagents\"\n return \"pipeline\"\n\n @property\n def resolved_research_runtime_backend(self) -> Literal[\"langgraph\", \"deepagents\", \"hybrid\"]:\n if self.research_runtime_backend != \"auto\":\n return self.research_runtime_backend\n if (\n self.resolved_llm_backend == \"openai\"\n and _looks_like_openai_key(self.openai_api_key)\n and importlib.util.find_spec(\"deepagents\") is not None\n and importlib.util.find_spec(\"langchain_openai\") is not None\n ):\n return \"hybrid\"\n return \"langgraph\"\n\n @property\n def resolved_search_backend(self) -> Literal[\"mock\", \"openai\", \"brave\", \"exa\", \"tavily\"]:\n if self.search_backend != \"auto\":\n return self.search_backend\n if self.brave_api_key:\n return \"brave\"\n if self.exa_api_key:\n return \"exa\"\n if self.tavily_api_key:\n return \"tavily\"\n if _looks_like_openai_key(self.openai_api_key):\n return \"openai\"\n return \"mock\"\n\n @property\n def resolved_fetch_backend(\n self,\n ) -> Literal[\"mock\", \"firecrawl\", \"browserbase\", \"browserbase_session\", \"playwright\"]:\n if self.fetch_backend != \"auto\":\n return self.fetch_backend\n if self.firecrawl_api_key:\n return \"firecrawl\"\n if self.browserbase_api_key:\n return \"browserbase\"\n return \"mock\"\n\n @property\n def resolved_workflow_backend(self) -> Literal[\"local\", \"temporal\"]:\n if self.workflow_backend != \"auto\":\n return self.workflow_backend\n return \"temporal\" if self.temporal_target_url else \"local\"\n\n @property\n def resolved_database_bootstrap_mode(self) -> Literal[\"create_all\"]:\n if self.database_bootstrap_mode != \"auto\":\n return self.database_bootstrap_mode\n return \"create_all\"\n\n @property\n def resolved_artifact_store_backend(self) -> Literal[\"disabled\", \"local\", \"s3\"]:\n if self.artifact_store_backend != \"auto\":\n return self.artifact_store_backend\n if self.artifact_store_s3_bucket:\n return \"s3\"\n if self.environment == \"test\":\n return \"disabled\"\n return \"local\"\n\n @property\n def resolved_embedding_backend(\n self,\n ) -> Literal[\"disabled\", \"mock\", \"openai\", \"openai_compatible\"]:\n if self.embedding_backend != \"auto\":\n return self.embedding_backend\n if _looks_like_openai_key(self.openai_api_key):\n return \"openai\"\n if (\n self.embedding_base_url\n or self.embedding_api_key\n or self.llm_base_url\n or self.llm_api_key\n ):\n return \"openai_compatible\"\n return \"mock\"\n\n @property\n def resolved_reranker_backend(\n self,\n ) -> Literal[\"disabled\", \"heuristic\", \"sentence_transformers\"]:\n if self.reranker_backend != \"auto\":\n return self.reranker_backend\n return \"heuristic\"\n\n\n@lru_cache(maxsize=1)\ndef get_settings() -> Settings:\n return Settings()\n"}, "77f2492d02c8f7afcd3ce2f3e68088e6a3047e91": {"t": 1785768627.3198814, "n": 16205, "h": "aafd499b360050c3", "c": "from __future__ import annotations\n\nimport importlib.util\nfrom functools import lru_cache\nfrom typing import Literal\n\nfrom pydantic import AliasChoices, Field, SecretStr\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\n\ndef _looks_like_openai_key(secret: SecretStr | None) -> bool:\n if secret is None:\n return False\n value = secret.get_secret_value().strip()\n # OpenAI project/user keys are currently issued with an sk- prefix.\n return value.startswith(\"sk-\")\n\n\nclass Settings(BaseSettings):\n model_config = SettingsConfigDict(\n env_file=\".env\",\n env_file_encoding=\"utf-8\",\n env_prefix=\"OPEN_RESEARCH_\",\n populate_by_name=True,\n env_ignore_empty=True,\n extra=\"ignore\",\n )\n\n app_name: str = \"Open Research\"\n environment: Literal[\"development\", \"test\", \"production\"] = \"development\"\n database_url: str = Field(\n default=\"sqlite+aiosqlite:///./openresearch.db\",\n validation_alias=AliasChoices(\"DATABASE_URL\", \"OPEN_RESEARCH_DATABASE_URL\"),\n )\n\n llm_backend: Literal[\"auto\", \"heuristic\", \"openai\", \"openai_compatible\"] = \"auto\"\n search_backend: Literal[\"auto\", \"mock\", \"openai\", \"brave\", \"exa\", \"tavily\"] = \"auto\"\n fetch_backend: Literal[\n \"auto\",\n \"mock\",\n \"firecrawl\",\n \"browserbase\",\n \"browserbase_session\",\n \"playwright\",\n ] = \"auto\"\n workflow_backend: Literal[\"auto\", \"local\", \"temporal\"] = \"auto\"\n database_bootstrap_mode: Literal[\"auto\", \"create_all\"] = \"auto\"\n artifact_store_backend: Literal[\"auto\", \"disabled\", \"local\", \"s3\"] = \"auto\"\n embedding_backend: Literal[\"auto\", \"disabled\", \"mock\", \"openai\", \"openai_compatible\"] = \"auto\"\n reranker_backend: Literal[\"auto\", \"disabled\", \"heuristic\", \"sentence_transformers\"] = \"auto\"\n process_role: Literal[\"all\", \"api\", \"worker\"] = \"all\"\n event_pubsub_mode: Literal[\"memory\", \"database\"] = \"database\"\n\n openai_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"OPENAI_API_KEY\", \"OPEN_RESEARCH_OPENAI_API_KEY\"),\n )\n openai_base_url: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"OPENAI_BASE_URL\", \"OPEN_RESEARCH_OPENAI_BASE_URL\"),\n )\n llm_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"LLM_API_KEY\", \"OPEN_RESEARCH_LLM_API_KEY\"),\n )\n llm_base_url: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"LLM_BASE_URL\", \"OPEN_RESEARCH_LLM_BASE_URL\"),\n )\n embedding_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"EMBEDDING_API_KEY\",\n \"OPEN_RESEARCH_EMBEDDING_API_KEY\",\n ),\n )\n embedding_base_url: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"EMBEDDING_BASE_URL\",\n \"OPEN_RESEARCH_EMBEDDING_BASE_URL\",\n ),\n )\n brave_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"BRAVE_API_KEY\", \"OPEN_RESEARCH_BRAVE_API_KEY\"),\n )\n exa_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"EXA_API_KEY\", \"OPEN_RESEARCH_EXA_API_KEY\"),\n )\n tavily_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"TAVILY_API_KEY\", \"OPEN_RESEARCH_TAVILY_API_KEY\"),\n )\n serper_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"SERPER_API_KEY\", \"OPEN_RESEARCH_SERPER_API_KEY\"),\n )\n firecrawl_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\"FIRECRAWL_API_KEY\", \"OPEN_RESEARCH_FIRECRAWL_API_KEY\"),\n )\n browserbase_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"BROWSERBASE_API_KEY\",\n \"OPEN_RESEARCH_BROWSERBASE_API_KEY\",\n ),\n )\n browserbase_project_id: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"BROWSERBASE_PROJECT_ID\",\n \"OPEN_RESEARCH_BROWSERBASE_PROJECT_ID\",\n ),\n )\n worker_id: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"WORKER_ID\", \"OPEN_RESEARCH_WORKER_ID\"),\n )\n\n temporal_target_url: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"TEMPORAL_TARGET_URL\",\n \"OPEN_RESEARCH_TEMPORAL_TARGET_URL\",\n ),\n )\n temporal_namespace: str = Field(\n default=\"default\",\n validation_alias=AliasChoices(\n \"TEMPORAL_NAMESPACE\",\n \"OPEN_RESEARCH_TEMPORAL_NAMESPACE\",\n ),\n )\n temporal_task_queue: str = Field(\n default=\"open-research\",\n validation_alias=AliasChoices(\n \"TEMPORAL_TASK_QUEUE\",\n \"OPEN_RESEARCH_TEMPORAL_TASK_QUEUE\",\n ),\n )\n temporal_api_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"TEMPORAL_API_KEY\",\n \"OPEN_RESEARCH_TEMPORAL_API_KEY\",\n ),\n )\n temporal_tls: bool = Field(\n default=True,\n validation_alias=AliasChoices(\"TEMPORAL_TLS\", \"OPEN_RESEARCH_TEMPORAL_TLS\"),\n )\n\n lead_model: str = \"gpt-5.5\"\n planner_model: str = \"gpt-5.5\"\n worker_model: str = \"gpt-5.5\"\n verifier_model: str = \"gpt-5.5\"\n embedding_model: str = \"text-embedding-3-large\"\n reranker_model: str = \"BAAI/bge-reranker-v2-m3\"\n openai_web_search_model: str | None = None\n openai_web_search_context_size: Literal[\"low\", \"medium\", \"high\"] = \"medium\"\n openai_web_search_reasoning_effort: Literal[\"low\", \"medium\", \"high\"] = \"high\"\n openai_web_search_external_web_access: bool = True\n openai_web_search_max_output_tokens: int = 4096\n openai_web_search_timeout_seconds: float = 180.0\n llm_reasoning_effort: Literal[\"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"] = \"high\"\n llm_api_style: Literal[\"auto\", \"responses\", \"chat_completions\"] = \"auto\"\n llm_structured_output_mode: Literal[\"auto\", \"parse\", \"json_schema\", \"prompted\"] = \"auto\"\n llm_supports_reasoning_effort: bool | None = None\n llm_model_family: Literal[\"auto\", \"generic\", \"openai\", \"glm\", \"qwen\", \"deepseek\"] = \"auto\"\n prompt_mode: Literal[\"code\", \"template\", \"hybrid\"] = \"hybrid\"\n prompt_template_root: str | None = None\n prompt_template_strict: bool = False\n prompt_template_family_fallback: bool = True\n prompt_reload_in_dev: bool = True\n prompt_externalization_enabled: bool = True\n custom_responses_runtime_backend: Literal[\"auto\", \"pipeline\", \"deepagents\"] = \"auto\"\n research_runtime_backend: Literal[\"auto\", \"langgraph\", \"deepagents\", \"hybrid\"] = \"auto\"\n deep_plan_approval_enabled: bool = True\n source_registry_ui_enabled: bool = True\n async_jobs_enabled: bool = True\n debug_console_enabled: bool = True\n enforce_maximal_research_path: bool = True\n\n max_streams: int = 30\n max_replans: int = 1\n max_queries_per_stream: int = 25\n max_results_per_query: int = 5\n max_sources_per_stream: int = 3\n per_domain_limit: int = 2\n planner_min_discovery_queries: int = 10\n planner_max_discovery_queries: int = 16\n planner_min_total_sources_retrieved: int = 8\n planner_min_total_cited_sources: int = 4\n planner_validation_enabled: bool = True\n planner_max_validation_retries: int = 2\n planner_discovery_concurrency: int = 3\n deepagents_max_research_batches: int = 6\n deepagents_require_critic_pass: bool = True\n deepagents_require_source_audit_pass: bool = True\n deepagents_require_citation_pass: bool = True\n deepagents_grounding_enabled: bool = True\n deepagents_grounding_strict: bool = False\n completion_gate_min_chars: int = 2000\n completion_gate_min_headings: int = 2\n completion_gate_max_attempts: int = 5\n tool_registry_enabled: bool = True\n max_search_tool_calls_per_run: int = 200\n max_fetch_tool_calls_per_run: int = 200\n max_embedding_tool_calls_per_run: int = 500\n max_upload_file_size_bytes: int = 50 * 1024 * 1024\n max_upload_files_per_batch: int = 20\n max_ocr_pdf_pages: int = 200\n pdf_text_extraction_min_chars: int = 80\n\n http_timeout_seconds: float = 30.0\n sse_keepalive_seconds: float = 10.0\n automatic_run_recovery: bool = True\n max_claim_repairs: int = 1\n claim_repair_max_results: int = 2\n search_request_cost_usd: float = 0.0\n fetch_request_cost_usd: float = 0.0\n embedding_request_cost_usd: float = 0.0\n browserbase_use_proxies: bool = False\n browserbase_session_keep_alive: bool = False\n playwright_timeout_seconds: float = 15.0\n temporal_activity_timeout_seconds: int = 5400\n temporal_heartbeat_seconds: int = 10\n temporal_start_worker: bool = True\n temporal_worker_shutdown_seconds: float = 5.0\n run_heartbeat_seconds: float = 10.0\n stale_run_timeout_seconds: float = 120.0\n reconciler_interval_seconds: float = 15.0\n artifact_store_path: str = \"./artifacts\"\n artifact_store_s3_bucket: str | None = None\n artifact_store_s3_prefix: str = \"open-research\"\n artifact_store_s3_endpoint_url: str | None = None\n embedding_dimensions: int = 1536\n grounding_candidate_limit: int = 12\n grounding_max_claims_per_run: int = 4\n provider_retry_attempts: int = 3\n provider_retry_base_seconds: float = 0.5\n provider_retry_max_seconds: float = 4.0\n provider_cooldown_failures: int = 3\n provider_cooldown_seconds: float = 30.0\n metrics_enabled: bool = True\n profile_memory_enabled: bool = True\n behavior_assessment_enabled: bool = True\n otlp_endpoint: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"OTLP_ENDPOINT\", \"OPEN_RESEARCH_OTLP_ENDPOINT\"),\n )\n otlp_headers: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"OTLP_HEADERS\", \"OPEN_RESEARCH_OTLP_HEADERS\"),\n )\n langfuse_public_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"LANGFUSE_PUBLIC_KEY\",\n \"OPEN_RESEARCH_LANGFUSE_PUBLIC_KEY\",\n ),\n )\n langfuse_secret_key: SecretStr | None = Field(\n default=None,\n validation_alias=AliasChoices(\n \"LANGFUSE_SECRET_KEY\",\n \"OPEN_RESEARCH_LANGFUSE_SECRET_KEY\",\n ),\n )\n langfuse_host: str | None = Field(\n default=None,\n validation_alias=AliasChoices(\"LANGFUSE_HOST\", \"OPEN_RESEARCH_LANGFUSE_HOST\"),\n )\n trace_redaction_fields: str = (\n \"authorization,cookie,set-cookie,api_key,token,password,secret,prompt,content,headers,body\"\n )\n\n @property\n def resolved_llm_backend(self) -> Literal[\"heuristic\", \"openai\", \"openai_compatible\"]:\n if self.llm_backend != \"auto\":\n return self.llm_backend\n if _looks_like_openai_key(self.openai_api_key):\n return \"openai\"\n if self.llm_base_url or self.llm_api_key:\n return \"openai_compatible\"\n return \"heuristic\"\n\n @property\n def resolved_llm_api_style(self) -> Literal[\"responses\", \"chat_completions\"]:\n if self.llm_api_style != \"auto\":\n return self.llm_api_style\n if self.resolved_llm_backend == \"openai\":\n return \"responses\"\n return \"chat_completions\"\n\n @property\n def resolved_llm_structured_output_mode(\n self,\n ) -> Literal[\"parse\", \"json_schema\", \"prompted\"]:\n if self.llm_structured_output_mode != \"auto\":\n return self.llm_structured_output_mode\n if self.resolved_llm_backend == \"openai\":\n return \"parse\"\n return \"json_schema\"\n\n @property\n def resolved_llm_supports_reasoning_effort(self) -> bool:\n if self.llm_supports_reasoning_effort is not None:\n return self.llm_supports_reasoning_effort\n return self.resolved_llm_backend == \"openai\"\n\n @property\n def resolved_llm_model_family(self) -> Literal[\"generic\", \"openai\", \"glm\", \"qwen\", \"deepseek\"]:\n if self.llm_model_family != \"auto\":\n return self.llm_model_family\n model_names = \" \".join(\n [self.lead_model, self.planner_model, self.worker_model, self.verifier_model]\n ).lower()\n if \"gpt\" in model_names:\n return \"openai\"\n if \"glm\" in model_names:\n return \"glm\"\n if \"qwen\" in model_names:\n return \"qwen\"\n if \"deepseek\" in model_names:\n return \"deepseek\"\n return \"generic\"\n\n @property\n def resolved_custom_responses_runtime_backend(self) -> Literal[\"pipeline\", \"deepagents\"]:\n if self.custom_responses_runtime_backend != \"auto\":\n return self.custom_responses_runtime_backend\n if (\n self.resolved_llm_backend == \"openai\"\n and _looks_like_openai_key(self.openai_api_key)\n and importlib.util.find_spec(\"deepagents\") is not None\n and importlib.util.find_spec(\"langchain_openai\") is not None\n ):\n return \"deepagents\"\n return \"pipeline\"\n\n @property\n def resolved_research_runtime_backend(self) -> Literal[\"langgraph\", \"deepagents\", \"hybrid\"]:\n if self.research_runtime_backend != \"auto\":\n return self.research_runtime_backend\n if (\n self.resolved_llm_backend == \"openai\"\n and _looks_like_openai_key(self.openai_api_key)\n and importlib.util.find_spec(\"deepagents\") is not None\n and importlib.util.find_spec(\"langchain_openai\") is not None\n ):\n return \"hybrid\"\n return \"langgraph\"\n\n @property\n def resolved_search_backend(self) -> Literal[\"mock\", \"openai\", \"brave\", \"exa\", \"tavily\"]:\n if self.search_backend != \"auto\":\n return self.search_backend\n if self.brave_api_key:\n return \"brave\"\n if self.exa_api_key:\n return \"exa\"\n if self.tavily_api_key:\n return \"tavily\"\n if _looks_like_openai_key(self.openai_api_key):\n return \"openai\"\n return \"mock\"\n\n @property\n def resolved_fetch_backend(\n self,\n ) -> Literal[\"mock\", \"firecrawl\", \"browserbase\", \"browserbase_session\", \"playwright\"]:\n if self.fetch_backend != \"auto\":\n return self.fetch_backend\n if self.firecrawl_api_key:\n return \"firecrawl\"\n if self.browserbase_api_key:\n return \"browserbase\"\n return \"mock\"\n\n @property\n def resolved_workflow_backend(self) -> Literal[\"local\", \"temporal\"]:\n if self.workflow_backend != \"auto\":\n return self.workflow_backend\n return \"temporal\" if self.temporal_target_url else \"local\"\n\n @property\n def resolved_database_bootstrap_mode(self) -> Literal[\"create_all\"]:\n if self.database_bootstrap_mode != \"auto\":\n return self.database_bootstrap_mode\n return \"create_all\"\n\n @property\n def resolved_artifact_store_backend(self) -> Literal[\"disabled\", \"local\", \"s3\"]:\n if self.artifact_store_backend != \"auto\":\n return self.artifact_store_backend\n if self.artifact_store_s3_bucket:\n return \"s3\"\n if self.environment == \"test\":\n return \"disabled\"\n return \"local\"\n\n @property\n def resolved_embedding_backend(\n self,\n ) -> Literal[\"disabled\", \"mock\", \"openai\", \"openai_compatible\"]:\n if self.embedding_backend != \"auto\":\n return self.embedding_backend\n if _looks_like_openai_key(self.openai_api_key):\n return \"openai\"\n if (\n self.embedding_base_url\n or self.embedding_api_key\n or self.llm_base_url\n or self.llm_api_key\n ):\n return \"openai_compatible\"\n return \"mock\"\n\n @property\n def resolved_reranker_backend(\n self,\n ) -> Literal[\"disabled\", \"heuristic\", \"sentence_transformers\"]:\n if self.reranker_backend != \"auto\":\n return self.reranker_backend\n return \"heuristic\"\n\n\n@lru_cache(maxsize=1)\ndef get_settings() -> Settings:\n return Settings()\n"}}}}