forecasting-tools 0.3.1__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/PKG-INFO +6 -12
  2. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/README.md +5 -11
  3. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/__init__.py +3 -0
  4. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/ai_utils/response_types.py +1 -0
  5. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/general_llm.py +80 -1
  6. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/questions.py +4 -1
  7. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/helpers/metaculus_client.py +32 -3
  8. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/pyproject.toml +1 -1
  9. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/LICENSE +0 -0
  10. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/__init__.py +0 -0
  11. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/ai_congress_v2/__init__.py +0 -0
  12. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/ai_congress_v2/congress_member_agent.py +0 -0
  13. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/ai_congress_v2/congress_orchestrator.py +0 -0
  14. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/ai_congress_v2/data_models.py +0 -0
  15. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/ai_congress_v2/member_profiles.py +0 -0
  16. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/ai_congress_v2/tools.py +0 -0
  17. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/base_rates/base_rate_researcher.py +0 -0
  18. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/base_rates/deduplicator.py +0 -0
  19. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/base_rates/estimator.py +0 -0
  20. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/base_rates/niche_list_researcher.py +0 -0
  21. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/deprecated/configured_llms.py +0 -0
  22. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/deprecated/general_researcher.py +0 -0
  23. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/deprecated/question_generator.py +0 -0
  24. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/deprecated/question_responder.py +0 -0
  25. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/deprecated/question_router.py +0 -0
  26. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/deprecated/research_coordinator.py +0 -0
  27. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/minor_tools.py +0 -0
  28. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/other/data_analyzer.py +0 -0
  29. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/other/hosted_file.py +0 -0
  30. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/question_generators/generated_question.py +0 -0
  31. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/question_generators/harmful_question_identifier.py +0 -0
  32. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/question_generators/q3_q4_quarterly_questions.json +0 -0
  33. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/question_generators/question_decomposer.py +0 -0
  34. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/question_generators/question_operationalizer.py +0 -0
  35. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/question_generators/simple_question.py +0 -0
  36. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/question_generators/topic_generator.py +0 -0
  37. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/research/computer_use.py +0 -0
  38. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/research/find_a_dataset.py +0 -0
  39. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/research/key_factors_researcher.py +0 -0
  40. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/research/smart_searcher.py +0 -0
  41. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/__init__.py +0 -0
  42. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/agent_runner.py +0 -0
  43. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/data_models.py +0 -0
  44. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/effect_engine.py +0 -0
  45. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/example_situations/industrial_basin.json +0 -0
  46. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/example_situations/milbrook.json +0 -0
  47. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/example_situations/simple_business.json +0 -0
  48. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/example_situations/simple_dnd.json +0 -0
  49. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/example_situations/simple_election.json +0 -0
  50. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/example_situations/willowbrook.json +0 -0
  51. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/example_situations/z_broken_mafia.json +0 -0
  52. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/intervention_testing/__init__.py +0 -0
  53. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/intervention_testing/data_models.py +0 -0
  54. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/intervention_testing/forecast_resolver.py +0 -0
  55. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/intervention_testing/intervention_policy_agent.py +0 -0
  56. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/intervention_testing/intervention_runner.py +0 -0
  57. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/intervention_testing/intervention_storage.py +0 -0
  58. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/simulator.py +0 -0
  59. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/situation_simulator/situation_generator.py +0 -0
  60. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/README.md +0 -0
  61. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/__init__.py +0 -0
  62. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/benchmark.py +0 -0
  63. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/canonicalize.py +0 -0
  64. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/catalog.py +0 -0
  65. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/cli.py +0 -0
  66. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/config.py +0 -0
  67. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/content_store.py +0 -0
  68. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/cost.py +0 -0
  69. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/coverage.py +0 -0
  70. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/fetchers/__init__.py +0 -0
  71. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/fetchers/base.py +0 -0
  72. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/fetchers/cloakbrowser_fetcher.py +0 -0
  73. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/fetchers/firecrawl_fetcher.py +0 -0
  74. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/fetchers/hyperbrowser_fetcher.py +0 -0
  75. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/fetchers/pdf_fetcher.py +0 -0
  76. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/fetchers/playwright_fetcher.py +0 -0
  77. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/fetchers/tiered.py +0 -0
  78. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/ingest/__init__.py +0 -0
  79. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/ingest/trace_extraction.py +0 -0
  80. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/ingest/url_extraction.py +0 -0
  81. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/layout.py +0 -0
  82. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/manifest.py +0 -0
  83. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/models.py +0 -0
  84. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/pipeline.py +0 -0
  85. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/quality.py +0 -0
  86. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/reindex.py +0 -0
  87. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/reports.py +0 -0
  88. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/storage/__init__.py +0 -0
  89. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/storage/blob_store.py +0 -0
  90. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/storage/local_store.py +0 -0
  91. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/storage/s3_store.py +0 -0
  92. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/agents_and_tools/source_archive/viewer.py +0 -0
  93. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/__init__.py +0 -0
  94. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/agent_wrappers.py +0 -0
  95. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/ai_utils/__init__.py +0 -0
  96. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/ai_utils/openai_utils.py +0 -0
  97. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/deprecated_model_classes/README.md +0 -0
  98. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/deprecated_model_classes/claude35sonnet.py +0 -0
  99. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/deprecated_model_classes/deepseek_r1.py +0 -0
  100. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/deprecated_model_classes/gpt4o.py +0 -0
  101. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/deprecated_model_classes/gpt4ovision.py +0 -0
  102. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/deprecated_model_classes/gpto1.py +0 -0
  103. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/deprecated_model_classes/gpto1preview.py +0 -0
  104. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/deprecated_model_classes/metaculus4o.py +0 -0
  105. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/deprecated_model_classes/perplexity.py +0 -0
  106. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/exa_searcher.py +0 -0
  107. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/__init__.py +0 -0
  108. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/ai_model.py +0 -0
  109. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/combined_llm_archetype.py +0 -0
  110. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/incurs_cost.py +0 -0
  111. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/named_model.py +0 -0
  112. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/outputs_text.py +0 -0
  113. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/priced_per_request.py +0 -0
  114. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/request_limited_model.py +0 -0
  115. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/retryable_model.py +0 -0
  116. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/time_limited_model.py +0 -0
  117. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/token_limited_model.py +0 -0
  118. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/tokens_are_calculatable.py +0 -0
  119. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_interfaces/tokens_incur_cost.py +0 -0
  120. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/model_tracker.py +0 -0
  121. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/resource_managers/__init__.py +0 -0
  122. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/resource_managers/hard_limit_manager.py +0 -0
  123. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/resource_managers/monetary_cost_manager.py +0 -0
  124. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/ai_models/resource_managers/refreshing_bucket_rate_limiter.py +0 -0
  125. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/auto_optimizers/bot_evaluator.py +0 -0
  126. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/auto_optimizers/bot_optimizer.py +0 -0
  127. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/auto_optimizers/control_prompt.py +0 -0
  128. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/auto_optimizers/customizable_bot.py +0 -0
  129. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/auto_optimizers/prompt_data_models.py +0 -0
  130. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/auto_optimizers/prompt_optimizer.py +0 -0
  131. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/auto_optimizers/question_plus_research.py +0 -0
  132. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/calibration_adjustment/.gitignore +0 -0
  133. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/calibration_adjustment/__init__.py +0 -0
  134. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/calibration_adjustment/_training_data.py +0 -0
  135. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/calibration_adjustment/benchmark.ipynb +0 -0
  136. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/calibration_adjustment/calibration_adjuster.py +0 -0
  137. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/calibration_adjustment/constant_shift_adjuster.py +0 -0
  138. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/calibration_adjustment/decision_tree_adjuster.py +0 -0
  139. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/calibration_adjustment/k_means_adjuster.py +0 -0
  140. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/calibration_adjustment/logistic_recalibration_adjuster.py +0 -0
  141. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/calibration_adjustment/step_adjuster.py +0 -0
  142. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/cp_benchmarking/benchmark_displayer.py +0 -0
  143. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/cp_benchmarking/benchmark_for_bot.py +0 -0
  144. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/cp_benchmarking/benchmarker.py +0 -0
  145. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/__init__.py +0 -0
  146. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/binary_report.py +0 -0
  147. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/coherence_link.py +0 -0
  148. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/conditional_models.py +0 -0
  149. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/conditional_report.py +0 -0
  150. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/data_organizer.py +0 -0
  151. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/forecast_report.py +0 -0
  152. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/markdown_tree.py +0 -0
  153. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/multiple_choice_report.py +0 -0
  154. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/numeric_report.py +0 -0
  155. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/timestamped_predictions.py +0 -0
  156. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/data_models/user_response.py +0 -0
  157. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/__init__.py +0 -0
  158. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/bot_lists.py +0 -0
  159. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/__init__.py +0 -0
  160. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q1_veritas_bot.py +0 -0
  161. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q1t_w_convert_to_binary.py +0 -0
  162. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q1t_w_personas_and_exa.py +0 -0
  163. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q2t_w_decomposition.py +0 -0
  164. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q3t_w_asknews.py +0 -0
  165. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q3t_w_exa.py +0 -0
  166. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q3t_w_q4vbinary.py +0 -0
  167. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q4_veritas_bot.py +0 -0
  168. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q4v_w_exa.py +0 -0
  169. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q4v_w_exa_and_dseekr1.py +0 -0
  170. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/experiments/q4v_w_exa_and_o1_preview.py +0 -0
  171. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/forecast_bot.py +0 -0
  172. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/main_bot.py +0 -0
  173. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/__init__.py +0 -0
  174. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/gpt_4_1_optimized_bot.py +0 -0
  175. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/no_research_one_shot_bot.py +0 -0
  176. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/q1_template_bot.py +0 -0
  177. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/q2_template_bot.py +0 -0
  178. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/q3_template_bot.py +0 -0
  179. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/q4_template_bot.py +0 -0
  180. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/research_only_bot_2025_fall.py +0 -0
  181. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/template_bot_2025_fall.py +0 -0
  182. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/template_bot_2026_fall.py +0 -0
  183. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/template_bot_2026_spring.py +0 -0
  184. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/template_bot_2026_summer.py +0 -0
  185. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/official_bots/uniform_probability_bot.py +0 -0
  186. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/forecast_bots/template_bot.py +0 -0
  187. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/Home.py +0 -0
  188. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/__init__.py +0 -0
  189. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/base_rate_page.py +0 -0
  190. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/benchmark_page.py +0 -0
  191. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/chat_page.py +0 -0
  192. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/congress_v2_page.py +0 -0
  193. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/csv_agent.py +0 -0
  194. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/estimator_page.py +0 -0
  195. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/forecaster_page.py +0 -0
  196. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/intervention_leaderboard_page.py +0 -0
  197. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/key_factors_page.py +0 -0
  198. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/niche_list_researcher_page.py +0 -0
  199. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/app_pages/simulator_page.py +0 -0
  200. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/example_outputs/base_rate_page_examples.json +0 -0
  201. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/example_outputs/congress_page_example.json +0 -0
  202. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/example_outputs/congress_v2_page_example.json +0 -0
  203. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/example_outputs/estimator_page_examples.json +0 -0
  204. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/example_outputs/forecast_page_examples.json +0 -0
  205. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/example_outputs/key_factors_page_examples.json +0 -0
  206. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/example_outputs/niche_list_page_examples.json +0 -0
  207. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/example_outputs/question_generator_page_examples.json +0 -0
  208. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/helpers/app_page.py +0 -0
  209. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/helpers/custom_auth.py +0 -0
  210. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/helpers/report_displayer.py +0 -0
  211. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/front_end/helpers/tool_page.py +0 -0
  212. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/helpers/__init__.py +0 -0
  213. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/helpers/asknews_cache.py +0 -0
  214. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/helpers/asknews_searcher.py +0 -0
  215. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/helpers/forecast_database_manager.py +0 -0
  216. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/helpers/metaculus_api.py +0 -0
  217. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/helpers/prediction_extractor.py +0 -0
  218. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/helpers/structure_output.py +0 -0
  219. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/helpers/works_cited_creator.py +0 -0
  220. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/util/__init__.py +0 -0
  221. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/util/async_batching.py +0 -0
  222. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/util/coda_utils.py +0 -0
  223. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/util/custom_logger.py +0 -0
  224. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/util/file_manipulation.py +0 -0
  225. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/util/jsonable.py +0 -0
  226. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/util/misc.py +0 -0
  227. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/util/optional_imports.py +0 -0
  228. {forecasting_tools-0.3.1 → forecasting_tools-0.3.3}/forecasting_tools/util/stats.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forecasting-tools
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: AI forecasting and research tools to help humans reason about and forecast the future
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -207,7 +207,7 @@ Note: You'll need to have your environment variables set up (see the section bel
207
207
 
208
208
  ## Customizing the Bot
209
209
  ### General Customization
210
- Generally all you have to do to make your own bot is inherit from the TemplateBot and override any combination of the 3 forecasting methods and the 1 research method. This saves you the headache of interacting with the Metaculus API, implementing aggregation of predictions, creating benchmarking interfaces, etc. Below is an example. It may also be helpful to look at the `TemplateBot` code (`forecasting_tools/forecast_bots/template_bot.py`) for a more complete example.
210
+ Generally all you have to do to make your own bot is inherit from the TemplateBot and override any combination of the 3 forecasting methods and the 1 research method. This saves you the headache of interacting with the Metaculus API, implementing aggregation of predictions, etc. Below is an example. It may also be helpful to look at the `TemplateBot` code (`forecasting_tools/forecast_bots/template_bot.py`) for a more complete example.
211
211
 
212
212
 
213
213
  ```python
@@ -380,11 +380,6 @@ file_path = "temp/questions.json"
380
380
  DataOrganizer.save_questions_to_file_path(questions, file_path) # Overwrites the file if it already exists
381
381
  questions = DataOrganizer.load_questions_from_file_path(file_path)
382
382
 
383
- benchmark_questions = metaculus_client.get_benchmark_questions(
384
- num_of_questions_to_return=20
385
- )
386
- print(f"Num benchmark questions: {len(benchmark_questions)}")
387
-
388
383
  metaculus_client.post_binary_question_prediction(
389
384
  question_id=578, # Note that the question ID is not always the same as the post ID
390
385
  prediction_in_decimal=0.012, # Must be between 0.001 and 0.999
@@ -402,7 +397,6 @@ print("Posted comment")
402
397
  Question found with url: https://www.metaculus.com/questions/578
403
398
  Num tournament questions: 11
404
399
  Num filtered questions: 50
405
- Num benchmark questions: 20
406
400
  Posted prediction
407
401
  Posted comment
408
402
 
@@ -413,7 +407,7 @@ Several of the methods above accept a `group_question_mode` parameter that contr
413
407
  - `"exclude"` — drop group questions from the result.
414
408
  - `"unpack_subquestions"` — turn each subquestion into a separate normal question.
415
409
 
416
- For backwards compatibility, the default is `"exclude"` for `get_question_by_post_id`, `get_question_by_url`, `ApiFilter` (used by `get_questions_matching_filter`), and `get_benchmark_questions` — so group questions don't get overweighted in benchmarks. The exception is `get_all_open_questions_from_tournament`, which defaults to `"unpack_subquestions"` so all subquestions are forecasted as normal questions.
410
+ For backwards compatibility, the default is `"exclude"` for `get_question_by_post_id`, `get_question_by_url`, and `ApiFilter` (used by `get_questions_matching_filter`). The exception is `get_all_open_questions_from_tournament`, which defaults to `"unpack_subquestions"` so all subquestions are forecasted as normal questions.
417
411
 
418
412
  ```python
419
413
  from forecasting_tools import MetaculusClient, ApiFilter
@@ -572,8 +566,8 @@ Some features need heavier dependencies that a bot does not, so they are opt-in.
572
566
 
573
567
  | Extra | You need it for |
574
568
  | --- | --- |
575
- | `agents` | Anything built on the agent SDK: `QuestionDecomposer`, `QuestionOperationalizer`, `TopicGenerator`, `DataAnalyzer`, `Benchmarker`, `BenchmarkForBot`, `BotOptimizer`, `CustomizableBot`, `ComputerUse` (browser-driving agent), and the AI Congress tools |
576
- | `front-end` | The Streamlit app in `forecasting_tools/front_end/` and `run_benchmark_streamlit_page` |
569
+ | `agents` | Anything built on the agent SDK: `QuestionDecomposer`, `QuestionOperationalizer`, `TopicGenerator`, `DataAnalyzer`, `BotOptimizer`, `CustomizableBot`, `ComputerUse` (browser-driving agent), and the AI Congress tools |
570
+ | `front-end` | The Streamlit app in `forecasting_tools/front_end/` |
577
571
  | `stats` | `forecasting_tools.util.stats` and the calibration adjusters in `forecasting_tools/calibration_adjustment/` |
578
572
  | `all` | Everything above |
579
573
 
@@ -624,7 +618,7 @@ If you choose not to run Docker, you can use poetry to set up a local virtual en
624
618
 
625
619
 
626
620
  ## Installing dependencies
627
- Local development uses the optional extras (the tests cover the front end, the agent tools, and benchmarking), so install with:
621
+ Local development uses the optional extras (the tests cover the front end and the agent tools), so install with:
628
622
 
629
623
  ```bash
630
624
  poetry install --all-extras
@@ -145,7 +145,7 @@ Note: You'll need to have your environment variables set up (see the section bel
145
145
 
146
146
  ## Customizing the Bot
147
147
  ### General Customization
148
- Generally all you have to do to make your own bot is inherit from the TemplateBot and override any combination of the 3 forecasting methods and the 1 research method. This saves you the headache of interacting with the Metaculus API, implementing aggregation of predictions, creating benchmarking interfaces, etc. Below is an example. It may also be helpful to look at the `TemplateBot` code (`forecasting_tools/forecast_bots/template_bot.py`) for a more complete example.
148
+ Generally all you have to do to make your own bot is inherit from the TemplateBot and override any combination of the 3 forecasting methods and the 1 research method. This saves you the headache of interacting with the Metaculus API, implementing aggregation of predictions, etc. Below is an example. It may also be helpful to look at the `TemplateBot` code (`forecasting_tools/forecast_bots/template_bot.py`) for a more complete example.
149
149
 
150
150
 
151
151
  ```python
@@ -318,11 +318,6 @@ file_path = "temp/questions.json"
318
318
  DataOrganizer.save_questions_to_file_path(questions, file_path) # Overwrites the file if it already exists
319
319
  questions = DataOrganizer.load_questions_from_file_path(file_path)
320
320
 
321
- benchmark_questions = metaculus_client.get_benchmark_questions(
322
- num_of_questions_to_return=20
323
- )
324
- print(f"Num benchmark questions: {len(benchmark_questions)}")
325
-
326
321
  metaculus_client.post_binary_question_prediction(
327
322
  question_id=578, # Note that the question ID is not always the same as the post ID
328
323
  prediction_in_decimal=0.012, # Must be between 0.001 and 0.999
@@ -340,7 +335,6 @@ print("Posted comment")
340
335
  Question found with url: https://www.metaculus.com/questions/578
341
336
  Num tournament questions: 11
342
337
  Num filtered questions: 50
343
- Num benchmark questions: 20
344
338
  Posted prediction
345
339
  Posted comment
346
340
 
@@ -351,7 +345,7 @@ Several of the methods above accept a `group_question_mode` parameter that contr
351
345
  - `"exclude"` — drop group questions from the result.
352
346
  - `"unpack_subquestions"` — turn each subquestion into a separate normal question.
353
347
 
354
- For backwards compatibility, the default is `"exclude"` for `get_question_by_post_id`, `get_question_by_url`, `ApiFilter` (used by `get_questions_matching_filter`), and `get_benchmark_questions` — so group questions don't get overweighted in benchmarks. The exception is `get_all_open_questions_from_tournament`, which defaults to `"unpack_subquestions"` so all subquestions are forecasted as normal questions.
348
+ For backwards compatibility, the default is `"exclude"` for `get_question_by_post_id`, `get_question_by_url`, and `ApiFilter` (used by `get_questions_matching_filter`). The exception is `get_all_open_questions_from_tournament`, which defaults to `"unpack_subquestions"` so all subquestions are forecasted as normal questions.
355
349
 
356
350
  ```python
357
351
  from forecasting_tools import MetaculusClient, ApiFilter
@@ -510,8 +504,8 @@ Some features need heavier dependencies that a bot does not, so they are opt-in.
510
504
 
511
505
  | Extra | You need it for |
512
506
  | --- | --- |
513
- | `agents` | Anything built on the agent SDK: `QuestionDecomposer`, `QuestionOperationalizer`, `TopicGenerator`, `DataAnalyzer`, `Benchmarker`, `BenchmarkForBot`, `BotOptimizer`, `CustomizableBot`, `ComputerUse` (browser-driving agent), and the AI Congress tools |
514
- | `front-end` | The Streamlit app in `forecasting_tools/front_end/` and `run_benchmark_streamlit_page` |
507
+ | `agents` | Anything built on the agent SDK: `QuestionDecomposer`, `QuestionOperationalizer`, `TopicGenerator`, `DataAnalyzer`, `BotOptimizer`, `CustomizableBot`, `ComputerUse` (browser-driving agent), and the AI Congress tools |
508
+ | `front-end` | The Streamlit app in `forecasting_tools/front_end/` |
515
509
  | `stats` | `forecasting_tools.util.stats` and the calibration adjusters in `forecasting_tools/calibration_adjustment/` |
516
510
  | `all` | Everything above |
517
511
 
@@ -562,7 +556,7 @@ If you choose not to run Docker, you can use poetry to set up a local virtual en
562
556
 
563
557
 
564
558
  ## Installing dependencies
565
- Local development uses the optional extras (the tests cover the front end, the agent tools, and benchmarking), so install with:
559
+ Local development uses the optional extras (the tests cover the front end and the agent tools), so install with:
566
560
 
567
561
  ```bash
568
562
  poetry install --all-extras
@@ -172,6 +172,9 @@ from forecasting_tools.helpers.asknews_searcher import (
172
172
  from forecasting_tools.helpers.metaculus_api import MetaculusApi as MetaculusApi
173
173
  from forecasting_tools.helpers.metaculus_api import MetaculusClient as MetaculusClient
174
174
  from forecasting_tools.helpers.metaculus_client import ApiFilter as ApiFilter
175
+ from forecasting_tools.helpers.metaculus_client import (
176
+ AuthorMismatchError as AuthorMismatchError,
177
+ )
175
178
  from forecasting_tools.helpers.prediction_extractor import (
176
179
  PredictionExtractor as PredictionExtractor,
177
180
  )
@@ -17,3 +17,4 @@ class TextTokenResponse(ModelResponse):
17
17
 
18
18
  class TextTokenCostResponse(TextTokenResponse):
19
19
  cost: float
20
+ serving_provider: str | None = None
@@ -4,6 +4,7 @@ import asyncio
4
4
  import inspect
5
5
  import logging
6
6
  import os
7
+ import re
7
8
  from typing import Any, Literal
8
9
 
9
10
  import litellm
@@ -57,6 +58,25 @@ class GeneralLlm(
57
58
  Litellm support every model, most every parameter, and acts as one interface for every provider.
58
59
  """
59
60
 
61
+ _logged_model_provider_pairs: set[tuple[str, str]] = set()
62
+
63
+ _CREDENTIAL_KWARGS: frozenset[str] = frozenset(
64
+ {
65
+ "api_key",
66
+ "extra_headers",
67
+ "headers",
68
+ "model_list",
69
+ "aws_access_key_id",
70
+ "aws_secret_access_key",
71
+ "aws_session_token",
72
+ "aws_web_identity_token",
73
+ "vertex_credentials",
74
+ "azure_ad_token",
75
+ "azure_password",
76
+ "client_secret",
77
+ }
78
+ )
79
+
60
80
  _defaults: dict[str, Any] = {
61
81
  # The lowest matching model substring is used as default (default 60s timeout)
62
82
  "gpt-4o": {
@@ -318,6 +338,7 @@ class GeneralLlm(
318
338
  ModelTracker.give_cost_tracking_warning_if_needed(
319
339
  self._litellm_model, observed_no_cost=observed_no_cost
320
340
  )
341
+ serving_provider = self._get_checked_serving_provider(response)
321
342
 
322
343
  if self.populate_citations:
323
344
  citations = self._extract_citations(response, choices)
@@ -341,6 +362,7 @@ class GeneralLlm(
341
362
  total_tokens_used=total_tokens,
342
363
  model=self.model,
343
364
  cost=direct_cost,
365
+ serving_provider=serving_provider,
344
366
  )
345
367
 
346
368
  return response
@@ -390,6 +412,58 @@ class GeneralLlm(
390
412
  )
391
413
  return mentions_temperature and is_unsupported
392
414
 
415
+ def _get_checked_serving_provider(self, response: ModelResponse) -> str | None:
416
+ serving_provider = typeguard.check_type(
417
+ (response.model_extra or {}).get("provider"), str | None
418
+ )
419
+ self._error_if_not_served_by_pinned_provider(serving_provider)
420
+ if serving_provider is None:
421
+ return None
422
+ model_and_provider = (self.model, serving_provider)
423
+ if model_and_provider not in GeneralLlm._logged_model_provider_pairs:
424
+ GeneralLlm._logged_model_provider_pairs.add(model_and_provider)
425
+ logger.info(
426
+ f"{self.model} is being served by provider '{serving_provider}'"
427
+ )
428
+ return serving_provider
429
+
430
+ def _get_pinned_provider_slugs(self) -> list[str]:
431
+ provider_routing = (self.litellm_kwargs.get("extra_body") or {}).get(
432
+ "provider"
433
+ ) or {}
434
+ if provider_routing.get("allow_fallbacks", True) is not False:
435
+ return []
436
+ return provider_routing.get("order", [])
437
+
438
+ def _error_if_not_served_by_pinned_provider(
439
+ self, serving_provider: str | None
440
+ ) -> None:
441
+ pinned_slugs = self._get_pinned_provider_slugs()
442
+ if not pinned_slugs:
443
+ return
444
+ if serving_provider is None or not any(
445
+ self._provider_name_matches_slug(serving_provider, slug)
446
+ for slug in pinned_slugs
447
+ ):
448
+ raise RuntimeError(
449
+ f"{self.model} is pinned to {pinned_slugs} with fallbacks disabled, "
450
+ f"but was served by provider '{serving_provider}'"
451
+ )
452
+
453
+ @staticmethod
454
+ def _provider_name_matches_slug(provider_name: str, endpoint_slug: str) -> bool:
455
+ """
456
+ OpenRouter reports display names that can be shorter or longer than the slug
457
+ (e.g. "Google" for "google-vertex", "Mancer 2" for "mancer"), so match on prefix.
458
+ """
459
+ normalized_name = re.sub(r"[^a-z0-9]", "", provider_name.lower())
460
+ normalized_slug = re.sub(r"[^a-z0-9]", "", endpoint_slug.split("/")[0].lower())
461
+ if not normalized_name or not normalized_slug:
462
+ return False
463
+ return normalized_slug.startswith(
464
+ normalized_name
465
+ ) or normalized_name.startswith(normalized_slug)
466
+
393
467
  def _answer_from_reasoning_content(self, message: Message) -> str | None:
394
468
  reasoning_content = getattr(message, "reasoning_content", None)
395
469
  if isinstance(reasoning_content, str) and reasoning_content:
@@ -494,6 +568,7 @@ class GeneralLlm(
494
568
  setattr(model_response, "choices", choices)
495
569
 
496
570
  model_response.model = self.model
571
+ model_response._hidden_params = raw_response._hidden_params
497
572
 
498
573
  setattr(
499
574
  model_response,
@@ -620,7 +695,11 @@ class GeneralLlm(
620
695
  return {
621
696
  "original_model": self.model,
622
697
  "allowed_tries": self.allowed_tries,
623
- **{k: v for k, v in self.litellm_kwargs.items()},
698
+ **{
699
+ key: value
700
+ for key, value in self.litellm_kwargs.items()
701
+ if key not in self._CREDENTIAL_KWARGS
702
+ },
624
703
  }
625
704
 
626
705
  @classmethod
@@ -340,6 +340,10 @@ class BinaryQuestion(MetaculusQuestion):
340
340
  q2_center_community_prediction = aggregations["unweighted"]["latest"]["centers"] # type: ignore
341
341
  assert len(q2_center_community_prediction) == 1
342
342
  community_prediction_at_access_time = q2_center_community_prediction[0]
343
+ except (KeyError, TypeError):
344
+ community_prediction_at_access_time = None
345
+
346
+ try:
343
347
  history = api_json["question"]["my_forecasts"]["history"]
344
348
  previous_forecasts = None
345
349
  if history:
@@ -360,7 +364,6 @@ class BinaryQuestion(MetaculusQuestion):
360
364
  for forecast in history
361
365
  ]
362
366
  except (KeyError, TypeError):
363
- community_prediction_at_access_time = None
364
367
  previous_forecasts = None
365
368
  return BinaryQuestion(
366
369
  community_prediction_at_access_time=community_prediction_at_access_time,
@@ -101,6 +101,10 @@ class ApiFilter(BaseModel):
101
101
  return add_timezone_to_dates_in_base_model(self)
102
102
 
103
103
 
104
+ class AuthorMismatchError(ValueError):
105
+ pass
106
+
107
+
104
108
  class MetaculusClient:
105
109
  """
106
110
  Documentation for the API can be found at https://www.metaculus.com/api/
@@ -1212,8 +1216,14 @@ class MetaculusClient:
1212
1216
  logger.info(f"Unresolved question ID {question_id}")
1213
1217
 
1214
1218
  @retry_with_exponential_backoff()
1215
- def create_question(self, question: MetaculusQuestion) -> MetaculusQuestion:
1216
- question_data = self._get_post_create_data(question)
1219
+ def create_question(
1220
+ self, question: MetaculusQuestion, author_username: str | None = None
1221
+ ) -> MetaculusQuestion:
1222
+ """
1223
+ Setting author_username creates the post as that user, which requires
1224
+ the API token to belong to a Metaculus superuser.
1225
+ """
1226
+ question_data = self._get_post_create_data(question, author_username)
1217
1227
  self._sleep_between_requests()
1218
1228
  response = requests.post(
1219
1229
  f"{self.base_url}/posts/create/",
@@ -1241,6 +1251,16 @@ class MetaculusClient:
1241
1251
  single_created_question.id_of_post
1242
1252
  )
1243
1253
 
1254
+ if author_username is not None:
1255
+ actual_author = full_created_question.api_json.get("author_username")
1256
+ if actual_author != author_username:
1257
+ raise AuthorMismatchError(
1258
+ f"Post {full_created_question.id_of_post} was created with author "
1259
+ f"{actual_author!r} instead of {author_username!r} and has not been "
1260
+ "approved. Either the API token is not a superuser or the server "
1261
+ "ignored the author override."
1262
+ )
1263
+
1244
1264
  return full_created_question
1245
1265
 
1246
1266
  @retry_with_exponential_backoff()
@@ -1286,12 +1306,20 @@ class MetaculusClient:
1286
1306
  logger.info(f"Approved question {question.page_url}")
1287
1307
 
1288
1308
  @staticmethod
1289
- def _get_post_create_data(question: MetaculusQuestion) -> dict:
1309
+ def _get_post_create_data(
1310
+ question: MetaculusQuestion, author_username: str | None = None
1311
+ ) -> dict:
1290
1312
  if question.published_time is None:
1291
1313
  publish_time = question.open_time
1292
1314
  else:
1293
1315
  publish_time = question.published_time
1294
1316
 
1317
+ author_override_fields = (
1318
+ {"author_username": author_username, "is_staff_override": True}
1319
+ if author_username is not None
1320
+ else {}
1321
+ )
1322
+
1295
1323
  return {
1296
1324
  "title": question.question_text,
1297
1325
  "short_title": question.custom_metadata.get("short_name", None)
@@ -1355,4 +1383,5 @@ class MetaculusClient:
1355
1383
  "fine_print": question.fine_print or "",
1356
1384
  "group_rank": None, # only group questions
1357
1385
  },
1386
+ **author_override_fields,
1358
1387
  }
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "forecasting-tools"
3
- version = "0.3.1"
3
+ version = "0.3.3"
4
4
  description = "AI forecasting and research tools to help humans reason about and forecast the future"
5
5
  authors = ["Benjamin Wilson <ben@metaculus.com>"]
6
6
  license = "MIT"