local-deep-research 0.4.3__py3-none-any.whl → 0.5.0__py3-none-any.whl

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 (222) hide show
  1. local_deep_research/__init__.py +7 -0
  2. local_deep_research/__version__.py +1 -1
  3. local_deep_research/advanced_search_system/answer_decoding/__init__.py +5 -0
  4. local_deep_research/advanced_search_system/answer_decoding/browsecomp_answer_decoder.py +421 -0
  5. local_deep_research/advanced_search_system/candidate_exploration/README.md +219 -0
  6. local_deep_research/advanced_search_system/candidate_exploration/__init__.py +25 -0
  7. local_deep_research/advanced_search_system/candidate_exploration/adaptive_explorer.py +329 -0
  8. local_deep_research/advanced_search_system/candidate_exploration/base_explorer.py +341 -0
  9. local_deep_research/advanced_search_system/candidate_exploration/constraint_guided_explorer.py +436 -0
  10. local_deep_research/advanced_search_system/candidate_exploration/diversity_explorer.py +457 -0
  11. local_deep_research/advanced_search_system/candidate_exploration/parallel_explorer.py +250 -0
  12. local_deep_research/advanced_search_system/candidate_exploration/progressive_explorer.py +255 -0
  13. local_deep_research/advanced_search_system/candidates/__init__.py +5 -0
  14. local_deep_research/advanced_search_system/candidates/base_candidate.py +59 -0
  15. local_deep_research/advanced_search_system/constraint_checking/README.md +150 -0
  16. local_deep_research/advanced_search_system/constraint_checking/__init__.py +35 -0
  17. local_deep_research/advanced_search_system/constraint_checking/base_constraint_checker.py +122 -0
  18. local_deep_research/advanced_search_system/constraint_checking/constraint_checker.py +223 -0
  19. local_deep_research/advanced_search_system/constraint_checking/constraint_satisfaction_tracker.py +387 -0
  20. local_deep_research/advanced_search_system/constraint_checking/dual_confidence_checker.py +424 -0
  21. local_deep_research/advanced_search_system/constraint_checking/evidence_analyzer.py +174 -0
  22. local_deep_research/advanced_search_system/constraint_checking/intelligent_constraint_relaxer.py +503 -0
  23. local_deep_research/advanced_search_system/constraint_checking/rejection_engine.py +143 -0
  24. local_deep_research/advanced_search_system/constraint_checking/strict_checker.py +259 -0
  25. local_deep_research/advanced_search_system/constraint_checking/threshold_checker.py +213 -0
  26. local_deep_research/advanced_search_system/constraints/__init__.py +6 -0
  27. local_deep_research/advanced_search_system/constraints/base_constraint.py +58 -0
  28. local_deep_research/advanced_search_system/constraints/constraint_analyzer.py +143 -0
  29. local_deep_research/advanced_search_system/evidence/__init__.py +12 -0
  30. local_deep_research/advanced_search_system/evidence/base_evidence.py +57 -0
  31. local_deep_research/advanced_search_system/evidence/evaluator.py +159 -0
  32. local_deep_research/advanced_search_system/evidence/requirements.py +122 -0
  33. local_deep_research/advanced_search_system/filters/base_filter.py +3 -1
  34. local_deep_research/advanced_search_system/filters/cross_engine_filter.py +8 -2
  35. local_deep_research/advanced_search_system/filters/journal_reputation_filter.py +43 -29
  36. local_deep_research/advanced_search_system/findings/repository.py +54 -17
  37. local_deep_research/advanced_search_system/knowledge/standard_knowledge.py +3 -1
  38. local_deep_research/advanced_search_system/query_generation/adaptive_query_generator.py +405 -0
  39. local_deep_research/advanced_search_system/questions/__init__.py +16 -0
  40. local_deep_research/advanced_search_system/questions/atomic_fact_question.py +171 -0
  41. local_deep_research/advanced_search_system/questions/browsecomp_question.py +287 -0
  42. local_deep_research/advanced_search_system/questions/decomposition_question.py +13 -4
  43. local_deep_research/advanced_search_system/questions/entity_aware_question.py +184 -0
  44. local_deep_research/advanced_search_system/questions/standard_question.py +9 -3
  45. local_deep_research/advanced_search_system/search_optimization/cross_constraint_manager.py +624 -0
  46. local_deep_research/advanced_search_system/source_management/diversity_manager.py +613 -0
  47. local_deep_research/advanced_search_system/strategies/__init__.py +42 -0
  48. local_deep_research/advanced_search_system/strategies/adaptive_decomposition_strategy.py +564 -0
  49. local_deep_research/advanced_search_system/strategies/base_strategy.py +4 -4
  50. local_deep_research/advanced_search_system/strategies/browsecomp_entity_strategy.py +1031 -0
  51. local_deep_research/advanced_search_system/strategies/browsecomp_optimized_strategy.py +778 -0
  52. local_deep_research/advanced_search_system/strategies/concurrent_dual_confidence_strategy.py +446 -0
  53. local_deep_research/advanced_search_system/strategies/constrained_search_strategy.py +1348 -0
  54. local_deep_research/advanced_search_system/strategies/constraint_parallel_strategy.py +522 -0
  55. local_deep_research/advanced_search_system/strategies/direct_search_strategy.py +217 -0
  56. local_deep_research/advanced_search_system/strategies/dual_confidence_strategy.py +320 -0
  57. local_deep_research/advanced_search_system/strategies/dual_confidence_with_rejection.py +219 -0
  58. local_deep_research/advanced_search_system/strategies/early_stop_constrained_strategy.py +369 -0
  59. local_deep_research/advanced_search_system/strategies/entity_aware_source_strategy.py +140 -0
  60. local_deep_research/advanced_search_system/strategies/evidence_based_strategy.py +1248 -0
  61. local_deep_research/advanced_search_system/strategies/evidence_based_strategy_v2.py +1337 -0
  62. local_deep_research/advanced_search_system/strategies/focused_iteration_strategy.py +537 -0
  63. local_deep_research/advanced_search_system/strategies/improved_evidence_based_strategy.py +782 -0
  64. local_deep_research/advanced_search_system/strategies/iterative_reasoning_strategy.py +760 -0
  65. local_deep_research/advanced_search_system/strategies/iterdrag_strategy.py +55 -21
  66. local_deep_research/advanced_search_system/strategies/llm_driven_modular_strategy.py +865 -0
  67. local_deep_research/advanced_search_system/strategies/modular_strategy.py +1142 -0
  68. local_deep_research/advanced_search_system/strategies/parallel_constrained_strategy.py +506 -0
  69. local_deep_research/advanced_search_system/strategies/parallel_search_strategy.py +34 -16
  70. local_deep_research/advanced_search_system/strategies/rapid_search_strategy.py +29 -9
  71. local_deep_research/advanced_search_system/strategies/recursive_decomposition_strategy.py +492 -0
  72. local_deep_research/advanced_search_system/strategies/smart_decomposition_strategy.py +284 -0
  73. local_deep_research/advanced_search_system/strategies/smart_query_strategy.py +515 -0
  74. local_deep_research/advanced_search_system/strategies/source_based_strategy.py +48 -24
  75. local_deep_research/advanced_search_system/strategies/standard_strategy.py +34 -14
  76. local_deep_research/advanced_search_system/tools/base_tool.py +7 -2
  77. local_deep_research/api/benchmark_functions.py +6 -2
  78. local_deep_research/api/research_functions.py +10 -4
  79. local_deep_research/benchmarks/__init__.py +9 -7
  80. local_deep_research/benchmarks/benchmark_functions.py +6 -2
  81. local_deep_research/benchmarks/cli/benchmark_commands.py +27 -10
  82. local_deep_research/benchmarks/cli.py +38 -13
  83. local_deep_research/benchmarks/comparison/__init__.py +4 -2
  84. local_deep_research/benchmarks/comparison/evaluator.py +316 -239
  85. local_deep_research/benchmarks/datasets/__init__.py +1 -1
  86. local_deep_research/benchmarks/datasets/base.py +91 -72
  87. local_deep_research/benchmarks/datasets/browsecomp.py +54 -33
  88. local_deep_research/benchmarks/datasets/custom_dataset_template.py +19 -19
  89. local_deep_research/benchmarks/datasets/simpleqa.py +14 -14
  90. local_deep_research/benchmarks/datasets/utils.py +48 -29
  91. local_deep_research/benchmarks/datasets.py +4 -11
  92. local_deep_research/benchmarks/efficiency/__init__.py +8 -4
  93. local_deep_research/benchmarks/efficiency/resource_monitor.py +223 -171
  94. local_deep_research/benchmarks/efficiency/speed_profiler.py +62 -48
  95. local_deep_research/benchmarks/evaluators/browsecomp.py +3 -1
  96. local_deep_research/benchmarks/evaluators/composite.py +6 -2
  97. local_deep_research/benchmarks/evaluators/simpleqa.py +36 -13
  98. local_deep_research/benchmarks/graders.py +32 -10
  99. local_deep_research/benchmarks/metrics/README.md +1 -1
  100. local_deep_research/benchmarks/metrics/calculation.py +25 -10
  101. local_deep_research/benchmarks/metrics/reporting.py +7 -3
  102. local_deep_research/benchmarks/metrics/visualization.py +42 -23
  103. local_deep_research/benchmarks/metrics.py +1 -1
  104. local_deep_research/benchmarks/optimization/__init__.py +3 -1
  105. local_deep_research/benchmarks/optimization/api.py +7 -1
  106. local_deep_research/benchmarks/optimization/optuna_optimizer.py +75 -26
  107. local_deep_research/benchmarks/runners.py +48 -15
  108. local_deep_research/citation_handler.py +65 -92
  109. local_deep_research/citation_handlers/__init__.py +15 -0
  110. local_deep_research/citation_handlers/base_citation_handler.py +70 -0
  111. local_deep_research/citation_handlers/forced_answer_citation_handler.py +179 -0
  112. local_deep_research/citation_handlers/precision_extraction_handler.py +550 -0
  113. local_deep_research/citation_handlers/standard_citation_handler.py +80 -0
  114. local_deep_research/config/llm_config.py +271 -169
  115. local_deep_research/config/search_config.py +14 -5
  116. local_deep_research/defaults/__init__.py +0 -1
  117. local_deep_research/defaults/default_settings.json +35 -35
  118. local_deep_research/metrics/__init__.py +13 -0
  119. local_deep_research/metrics/database.py +58 -0
  120. local_deep_research/metrics/db_models.py +115 -0
  121. local_deep_research/metrics/migrate_add_provider_to_token_usage.py +148 -0
  122. local_deep_research/metrics/migrate_call_stack_tracking.py +105 -0
  123. local_deep_research/metrics/migrate_enhanced_tracking.py +75 -0
  124. local_deep_research/metrics/migrate_research_ratings.py +31 -0
  125. local_deep_research/metrics/models.py +61 -0
  126. local_deep_research/metrics/pricing/__init__.py +12 -0
  127. local_deep_research/metrics/pricing/cost_calculator.py +237 -0
  128. local_deep_research/metrics/pricing/pricing_cache.py +143 -0
  129. local_deep_research/metrics/pricing/pricing_fetcher.py +240 -0
  130. local_deep_research/metrics/query_utils.py +51 -0
  131. local_deep_research/metrics/search_tracker.py +380 -0
  132. local_deep_research/metrics/token_counter.py +1078 -0
  133. local_deep_research/migrate_db.py +3 -1
  134. local_deep_research/report_generator.py +22 -8
  135. local_deep_research/search_system.py +390 -9
  136. local_deep_research/test_migration.py +15 -5
  137. local_deep_research/utilities/db_utils.py +7 -4
  138. local_deep_research/utilities/es_utils.py +115 -104
  139. local_deep_research/utilities/llm_utils.py +15 -5
  140. local_deep_research/utilities/log_utils.py +151 -0
  141. local_deep_research/utilities/search_cache.py +387 -0
  142. local_deep_research/utilities/search_utilities.py +14 -6
  143. local_deep_research/utilities/threading_utils.py +92 -0
  144. local_deep_research/utilities/url_utils.py +6 -0
  145. local_deep_research/web/api.py +347 -0
  146. local_deep_research/web/app.py +13 -17
  147. local_deep_research/web/app_factory.py +71 -66
  148. local_deep_research/web/database/migrate_to_ldr_db.py +12 -4
  149. local_deep_research/web/database/migrations.py +5 -3
  150. local_deep_research/web/database/models.py +51 -2
  151. local_deep_research/web/database/schema_upgrade.py +49 -29
  152. local_deep_research/web/models/database.py +51 -61
  153. local_deep_research/web/routes/api_routes.py +56 -22
  154. local_deep_research/web/routes/benchmark_routes.py +4 -1
  155. local_deep_research/web/routes/globals.py +22 -0
  156. local_deep_research/web/routes/history_routes.py +71 -46
  157. local_deep_research/web/routes/metrics_routes.py +1155 -0
  158. local_deep_research/web/routes/research_routes.py +227 -41
  159. local_deep_research/web/routes/settings_routes.py +156 -55
  160. local_deep_research/web/services/research_service.py +310 -103
  161. local_deep_research/web/services/resource_service.py +36 -11
  162. local_deep_research/web/services/settings_manager.py +58 -18
  163. local_deep_research/web/services/settings_service.py +12 -4
  164. local_deep_research/web/services/socket_service.py +295 -188
  165. local_deep_research/web/static/css/custom_dropdown.css +180 -0
  166. local_deep_research/web/static/css/styles.css +39 -1
  167. local_deep_research/web/static/js/components/detail.js +633 -267
  168. local_deep_research/web/static/js/components/details.js +751 -0
  169. local_deep_research/web/static/js/components/fallback/formatting.js +11 -11
  170. local_deep_research/web/static/js/components/fallback/ui.js +23 -23
  171. local_deep_research/web/static/js/components/history.js +76 -76
  172. local_deep_research/web/static/js/components/logpanel.js +61 -13
  173. local_deep_research/web/static/js/components/progress.js +13 -2
  174. local_deep_research/web/static/js/components/research.js +99 -12
  175. local_deep_research/web/static/js/components/results.js +239 -106
  176. local_deep_research/web/static/js/components/settings.js +70 -47
  177. local_deep_research/web/static/js/main.js +40 -40
  178. local_deep_research/web/static/js/services/audio.js +1 -1
  179. local_deep_research/web/static/js/services/formatting.js +11 -11
  180. local_deep_research/web/static/js/services/keyboard.js +157 -0
  181. local_deep_research/web/static/js/services/pdf.js +80 -80
  182. local_deep_research/web/static/sounds/README.md +1 -1
  183. local_deep_research/web/templates/base.html +1 -0
  184. local_deep_research/web/templates/components/log_panel.html +7 -1
  185. local_deep_research/web/templates/components/mobile_nav.html +1 -1
  186. local_deep_research/web/templates/components/sidebar.html +3 -0
  187. local_deep_research/web/templates/pages/cost_analytics.html +1245 -0
  188. local_deep_research/web/templates/pages/details.html +325 -24
  189. local_deep_research/web/templates/pages/history.html +1 -1
  190. local_deep_research/web/templates/pages/metrics.html +1929 -0
  191. local_deep_research/web/templates/pages/progress.html +2 -2
  192. local_deep_research/web/templates/pages/research.html +53 -17
  193. local_deep_research/web/templates/pages/results.html +12 -1
  194. local_deep_research/web/templates/pages/star_reviews.html +803 -0
  195. local_deep_research/web/utils/formatters.py +9 -3
  196. local_deep_research/web_search_engines/default_search_engines.py +5 -3
  197. local_deep_research/web_search_engines/engines/full_search.py +8 -2
  198. local_deep_research/web_search_engines/engines/meta_search_engine.py +59 -20
  199. local_deep_research/web_search_engines/engines/search_engine_arxiv.py +19 -6
  200. local_deep_research/web_search_engines/engines/search_engine_brave.py +6 -2
  201. local_deep_research/web_search_engines/engines/search_engine_ddg.py +3 -1
  202. local_deep_research/web_search_engines/engines/search_engine_elasticsearch.py +81 -58
  203. local_deep_research/web_search_engines/engines/search_engine_github.py +46 -15
  204. local_deep_research/web_search_engines/engines/search_engine_google_pse.py +16 -6
  205. local_deep_research/web_search_engines/engines/search_engine_guardian.py +39 -15
  206. local_deep_research/web_search_engines/engines/search_engine_local.py +58 -25
  207. local_deep_research/web_search_engines/engines/search_engine_local_all.py +15 -5
  208. local_deep_research/web_search_engines/engines/search_engine_pubmed.py +63 -21
  209. local_deep_research/web_search_engines/engines/search_engine_searxng.py +37 -11
  210. local_deep_research/web_search_engines/engines/search_engine_semantic_scholar.py +27 -9
  211. local_deep_research/web_search_engines/engines/search_engine_serpapi.py +12 -4
  212. local_deep_research/web_search_engines/engines/search_engine_wayback.py +31 -10
  213. local_deep_research/web_search_engines/engines/search_engine_wikipedia.py +12 -3
  214. local_deep_research/web_search_engines/search_engine_base.py +83 -35
  215. local_deep_research/web_search_engines/search_engine_factory.py +25 -8
  216. local_deep_research/web_search_engines/search_engines_config.py +9 -3
  217. {local_deep_research-0.4.3.dist-info → local_deep_research-0.5.0.dist-info}/METADATA +8 -2
  218. local_deep_research-0.5.0.dist-info/RECORD +265 -0
  219. local_deep_research-0.4.3.dist-info/RECORD +0 -177
  220. {local_deep_research-0.4.3.dist-info → local_deep_research-0.5.0.dist-info}/WHEEL +0 -0
  221. {local_deep_research-0.4.3.dist-info → local_deep_research-0.5.0.dist-info}/entry_points.txt +0 -0
  222. {local_deep_research-0.4.3.dist-info → local_deep_research-0.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -991,7 +991,7 @@
991
991
  "options": null,
992
992
  "step": null,
993
993
  "type": "SEARCH",
994
- "ui_element": "text",
994
+ "ui_element": "json",
995
995
  "value": [
996
996
  "scientific papers",
997
997
  "academic research",
@@ -1014,7 +1014,7 @@
1014
1014
  "options": null,
1015
1015
  "step": null,
1016
1016
  "type": "SEARCH",
1017
- "ui_element": "text",
1017
+ "ui_element": "json",
1018
1018
  "value": [
1019
1019
  "non-academic topics",
1020
1020
  "consumer products",
@@ -1159,7 +1159,7 @@
1159
1159
  "options": null,
1160
1160
  "step": null,
1161
1161
  "type": "SEARCH",
1162
- "ui_element": "text",
1162
+ "ui_element": "json",
1163
1163
  "value": [
1164
1164
  "intelligent engine selection",
1165
1165
  "adaptable to query type",
@@ -1177,7 +1177,7 @@
1177
1177
  "options": null,
1178
1178
  "step": null,
1179
1179
  "type": "SEARCH",
1180
- "ui_element": "text",
1180
+ "ui_element": "json",
1181
1181
  "value": [
1182
1182
  "slightly slower due to LLM analysis"
1183
1183
  ],
@@ -1375,7 +1375,7 @@
1375
1375
  "options": null,
1376
1376
  "step": null,
1377
1377
  "type": "SEARCH",
1378
- "ui_element": "text",
1378
+ "ui_element": "json",
1379
1379
  "value": [
1380
1380
  "privacy-focused web search",
1381
1381
  "product information",
@@ -1410,7 +1410,7 @@
1410
1410
  "options": null,
1411
1411
  "step": null,
1412
1412
  "type": "SEARCH",
1413
- "ui_element": "text",
1413
+ "ui_element": "json",
1414
1414
  "value": [
1415
1415
  "requires API key with usage limits",
1416
1416
  "smaller index than Google"
@@ -1640,7 +1640,7 @@
1640
1640
  "options": null,
1641
1641
  "step": null,
1642
1642
  "type": "SEARCH",
1643
- "ui_element": "text",
1643
+ "ui_element": "json",
1644
1644
  "value": [
1645
1645
  "code repositories",
1646
1646
  "software documentation",
@@ -1675,7 +1675,7 @@
1675
1675
  "options": null,
1676
1676
  "step": null,
1677
1677
  "type": "SEARCH",
1678
- "ui_element": "text",
1678
+ "ui_element": "json",
1679
1679
  "value": [
1680
1680
  "non-technical content",
1681
1681
  "content outside GitHub",
@@ -1861,7 +1861,7 @@
1861
1861
  "options": null,
1862
1862
  "step": null,
1863
1863
  "type": "SEARCH",
1864
- "ui_element": "text",
1864
+ "ui_element": "json",
1865
1865
  "value": [
1866
1866
  "custom search scope",
1867
1867
  "high-quality results",
@@ -1895,7 +1895,7 @@
1895
1895
  "options": null,
1896
1896
  "step": null,
1897
1897
  "type": "SEARCH",
1898
- "ui_element": "text",
1898
+ "ui_element": "json",
1899
1899
  "value": [
1900
1900
  "requires API key with usage limits",
1901
1901
  "limited to 10,000 queries/day on free tier",
@@ -2025,7 +2025,7 @@
2025
2025
  "options": null,
2026
2026
  "step": null,
2027
2027
  "type": "SEARCH",
2028
- "ui_element": "text",
2028
+ "ui_element": "json",
2029
2029
  "value": [
2030
2030
  "searches all local collections",
2031
2031
  "personal documents",
@@ -2043,7 +2043,7 @@
2043
2043
  "options": null,
2044
2044
  "step": null,
2045
2045
  "type": "SEARCH",
2046
- "ui_element": "text",
2046
+ "ui_element": "json",
2047
2047
  "value": [
2048
2048
  "may return too many results",
2049
2049
  "requires indexing"
@@ -2232,9 +2232,9 @@
2232
2232
  "options": null,
2233
2233
  "step": null,
2234
2234
  "type": "SEARCH",
2235
- "ui_element": "text",
2235
+ "ui_element": "json",
2236
2236
  "value": [
2237
- "@format ${DOCS_DIR}/personal_notes"
2237
+ "/local_collections/personal_notes"
2238
2238
  ],
2239
2239
  "visible": true
2240
2240
  },
@@ -2262,7 +2262,7 @@
2262
2262
  "options": null,
2263
2263
  "step": null,
2264
2264
  "type": "SEARCH",
2265
- "ui_element": "text",
2265
+ "ui_element": "json",
2266
2266
  "value": [
2267
2267
  "personal knowledge",
2268
2268
  "notes",
@@ -2280,7 +2280,7 @@
2280
2280
  "options": null,
2281
2281
  "step": null,
2282
2282
  "type": "SEARCH",
2283
- "ui_element": "text",
2283
+ "ui_element": "json",
2284
2284
  "value": [
2285
2285
  "subjective content",
2286
2286
  "informal information"
@@ -2469,9 +2469,9 @@
2469
2469
  "options": null,
2470
2470
  "step": null,
2471
2471
  "type": "SEARCH",
2472
- "ui_element": "text",
2472
+ "ui_element": "json",
2473
2473
  "value": [
2474
- "@format ${DOCS_DIR}/project_documents"
2474
+ "/local_collections/project_docs/"
2475
2475
  ],
2476
2476
  "visible": true
2477
2477
  },
@@ -2499,7 +2499,7 @@
2499
2499
  "options": null,
2500
2500
  "step": null,
2501
2501
  "type": "SEARCH",
2502
- "ui_element": "text",
2502
+ "ui_element": "json",
2503
2503
  "value": [
2504
2504
  "project documentation",
2505
2505
  "specifications",
@@ -2517,7 +2517,7 @@
2517
2517
  "options": null,
2518
2518
  "step": null,
2519
2519
  "type": "SEARCH",
2520
- "ui_element": "text",
2520
+ "ui_element": "json",
2521
2521
  "value": [
2522
2522
  "no external information",
2523
2523
  "limited to organizational knowledge"
@@ -2730,7 +2730,7 @@
2730
2730
  "options": null,
2731
2731
  "step": null,
2732
2732
  "type": "SEARCH",
2733
- "ui_element": "text",
2733
+ "ui_element": "json",
2734
2734
  "value": [
2735
2735
  "biomedical literature",
2736
2736
  "medical research",
@@ -2751,7 +2751,7 @@
2751
2751
  "options": null,
2752
2752
  "step": null,
2753
2753
  "type": "SEARCH",
2754
- "ui_element": "text",
2754
+ "ui_element": "json",
2755
2755
  "value": [
2756
2756
  "non-medical topics",
2757
2757
  "very recent papers may be missing",
@@ -2941,9 +2941,9 @@
2941
2941
  "options": null,
2942
2942
  "step": null,
2943
2943
  "type": "SEARCH",
2944
- "ui_element": "text",
2944
+ "ui_element": "json",
2945
2945
  "value": [
2946
- "@format ${DOCS_DIR}/research_papers"
2946
+ "/local_collections/research_papers/"
2947
2947
  ],
2948
2948
  "visible": true
2949
2949
  },
@@ -2971,7 +2971,7 @@
2971
2971
  "options": null,
2972
2972
  "step": null,
2973
2973
  "type": "SEARCH",
2974
- "ui_element": "text",
2974
+ "ui_element": "json",
2975
2975
  "value": [
2976
2976
  "academic research",
2977
2977
  "scientific papers",
@@ -2989,7 +2989,7 @@
2989
2989
  "options": null,
2990
2990
  "step": null,
2991
2991
  "type": "SEARCH",
2992
- "ui_element": "text",
2992
+ "ui_element": "json",
2993
2993
  "value": [
2994
2994
  "potentially outdated",
2995
2995
  "limited to collected papers"
@@ -3062,7 +3062,7 @@
3062
3062
  "options": null,
3063
3063
  "step": null,
3064
3064
  "type": "SEARCH",
3065
- "ui_element": "text",
3065
+ "ui_element": "json",
3066
3066
  "value": [
3067
3067
  "general"
3068
3068
  ],
@@ -3231,7 +3231,7 @@
3231
3231
  "options": null,
3232
3232
  "step": null,
3233
3233
  "type": "SEARCH",
3234
- "ui_element": "text",
3234
+ "ui_element": "json",
3235
3235
  "value": [
3236
3236
  "comprehensive general information",
3237
3237
  "current events and news",
@@ -3270,7 +3270,7 @@
3270
3270
  "options": null,
3271
3271
  "step": null,
3272
3272
  "type": "SEARCH",
3273
- "ui_element": "text",
3273
+ "ui_element": "json",
3274
3274
  "value": [
3275
3275
  "requires self-hosting",
3276
3276
  "depends on other search engines",
@@ -3470,7 +3470,7 @@
3470
3470
  "options": null,
3471
3471
  "step": null,
3472
3472
  "type": "SEARCH",
3473
- "ui_element": "text",
3473
+ "ui_element": "json",
3474
3474
  "value": [
3475
3475
  "comprehensive web search",
3476
3476
  "product information",
@@ -3505,7 +3505,7 @@
3505
3505
  "options": null,
3506
3506
  "step": null,
3507
3507
  "type": "SEARCH",
3508
- "ui_element": "text",
3508
+ "ui_element": "json",
3509
3509
  "value": [
3510
3510
  "requires API key with usage limits",
3511
3511
  "not specialized for academic content"
@@ -3662,7 +3662,7 @@
3662
3662
  "options": null,
3663
3663
  "step": null,
3664
3664
  "type": "SEARCH",
3665
- "ui_element": "text",
3665
+ "ui_element": "json",
3666
3666
  "value": [
3667
3667
  "historical web content",
3668
3668
  "archived websites",
@@ -3696,7 +3696,7 @@
3696
3696
  "options": null,
3697
3697
  "step": null,
3698
3698
  "type": "SEARCH",
3699
- "ui_element": "text",
3699
+ "ui_element": "json",
3700
3700
  "value": [
3701
3701
  "limited to previously archived content",
3702
3702
  "may miss recent changes",
@@ -3868,7 +3868,7 @@
3868
3868
  "options": null,
3869
3869
  "step": null,
3870
3870
  "type": "SEARCH",
3871
- "ui_element": "text",
3871
+ "ui_element": "json",
3872
3872
  "value": [
3873
3873
  "factual information",
3874
3874
  "general knowledge",
@@ -3889,7 +3889,7 @@
3889
3889
  "options": null,
3890
3890
  "step": null,
3891
3891
  "type": "SEARCH",
3892
- "ui_element": "text",
3892
+ "ui_element": "json",
3893
3893
  "value": [
3894
3894
  "recent events",
3895
3895
  "specialized academic topics",
@@ -0,0 +1,13 @@
1
+ """Metrics module for tracking LLM usage and token counts."""
2
+
3
+ from .database import get_metrics_db
4
+ from .db_models import ModelUsage, TokenUsage
5
+ from .token_counter import TokenCounter, TokenCountingCallback
6
+
7
+ __all__ = [
8
+ "TokenCounter",
9
+ "TokenCountingCallback",
10
+ "TokenUsage",
11
+ "ModelUsage",
12
+ "get_metrics_db",
13
+ ]
@@ -0,0 +1,58 @@
1
+ """Database utilities for metrics module with SQLAlchemy."""
2
+
3
+ from contextlib import contextmanager
4
+ from typing import Generator
5
+
6
+ from loguru import logger
7
+ from sqlalchemy import create_engine
8
+ from sqlalchemy.orm import Session, sessionmaker
9
+
10
+ from ..utilities.db_utils import DB_PATH
11
+ from .db_models import Base
12
+
13
+
14
+ class MetricsDatabase:
15
+ """Database manager for metrics using SQLAlchemy."""
16
+
17
+ def __init__(self):
18
+ # Use the same database as the rest of the app
19
+ self.engine = create_engine(
20
+ f"sqlite:///{DB_PATH}", connect_args={"check_same_thread": False}
21
+ )
22
+ self.SessionLocal = sessionmaker(
23
+ bind=self.engine, autocommit=False, autoflush=False
24
+ )
25
+ self._init_database()
26
+
27
+ def _init_database(self):
28
+ """Initialize database tables for metrics."""
29
+ try:
30
+ Base.metadata.create_all(self.engine)
31
+ logger.info("Metrics tables initialized successfully")
32
+ except Exception as e:
33
+ logger.exception(f"Error initializing metrics tables: {e}")
34
+
35
+ @contextmanager
36
+ def get_session(self) -> Generator[Session, None, None]:
37
+ """Get a database session with automatic cleanup."""
38
+ session = self.SessionLocal()
39
+ try:
40
+ yield session
41
+ session.commit()
42
+ except Exception:
43
+ session.rollback()
44
+ raise
45
+ finally:
46
+ session.close()
47
+
48
+
49
+ # Singleton instance
50
+ _metrics_db = None
51
+
52
+
53
+ def get_metrics_db() -> MetricsDatabase:
54
+ """Get the singleton metrics database instance."""
55
+ global _metrics_db
56
+ if _metrics_db is None:
57
+ _metrics_db = MetricsDatabase()
58
+ return _metrics_db
@@ -0,0 +1,115 @@
1
+ """SQLAlchemy models for metrics."""
2
+
3
+ from sqlalchemy import (
4
+ Column,
5
+ DateTime,
6
+ Integer,
7
+ String,
8
+ Text,
9
+ UniqueConstraint,
10
+ func,
11
+ )
12
+ from sqlalchemy.ext.declarative import declarative_base
13
+
14
+ Base = declarative_base()
15
+
16
+
17
+ class TokenUsage(Base):
18
+ """Model for tracking individual token usage events."""
19
+
20
+ __tablename__ = "token_usage"
21
+
22
+ id = Column(Integer, primary_key=True)
23
+ research_id = Column(
24
+ Integer
25
+ ) # Removed foreign key constraint to fix token tracking
26
+ model_name = Column(String)
27
+ provider = Column(
28
+ String
29
+ ) # Added provider column for accurate cost tracking
30
+ prompt_tokens = Column(Integer)
31
+ completion_tokens = Column(Integer)
32
+ total_tokens = Column(Integer)
33
+
34
+ # Phase 1 Enhancement: Research context
35
+ research_query = Column(Text)
36
+ research_mode = Column(String) # 'quick' or 'detailed'
37
+ research_phase = Column(String) # 'init', 'iteration_1', etc.
38
+ search_iteration = Column(Integer)
39
+
40
+ # Phase 1 Enhancement: Performance metrics
41
+ response_time_ms = Column(Integer)
42
+ success_status = Column(
43
+ String, default="success"
44
+ ) # 'success', 'error', 'timeout'
45
+ error_type = Column(String)
46
+
47
+ # Phase 1 Enhancement: Search engine context
48
+ search_engines_planned = Column(Text) # JSON array as text
49
+ search_engine_selected = Column(String)
50
+
51
+ # Call stack tracking
52
+ calling_file = Column(String) # File that made the LLM call
53
+ calling_function = Column(String) # Function that made the LLM call
54
+ call_stack = Column(Text) # Full call stack as JSON
55
+
56
+ timestamp = Column(DateTime, server_default=func.now())
57
+
58
+
59
+ class ModelUsage(Base):
60
+ """Model for aggregated token usage by model and research."""
61
+
62
+ __tablename__ = "model_usage"
63
+ __table_args__ = (UniqueConstraint("research_id", "model_name"),)
64
+
65
+ id = Column(Integer, primary_key=True)
66
+ research_id = Column(
67
+ Integer
68
+ ) # Removed foreign key constraint to fix token tracking
69
+ model_name = Column(String)
70
+ provider = Column(String)
71
+ prompt_tokens = Column(Integer, default=0)
72
+ completion_tokens = Column(Integer, default=0)
73
+ total_tokens = Column(Integer, default=0)
74
+ calls = Column(Integer, default=0)
75
+ timestamp = Column(DateTime, server_default=func.now())
76
+
77
+
78
+ class ResearchRating(Base):
79
+ """Model for storing user ratings of research sessions."""
80
+
81
+ __tablename__ = "research_ratings"
82
+
83
+ id = Column(Integer, primary_key=True)
84
+ research_id = Column(Integer, unique=True) # References research session ID
85
+ rating = Column(Integer) # 1-5 star rating
86
+ rated_at = Column(DateTime, server_default=func.now())
87
+ updated_at = Column(
88
+ DateTime, server_default=func.now(), onupdate=func.now()
89
+ )
90
+
91
+
92
+ class SearchCall(Base):
93
+ """Model for individual search engine calls."""
94
+
95
+ __tablename__ = "search_calls"
96
+
97
+ id = Column(Integer, primary_key=True)
98
+ research_id = Column(Integer)
99
+ research_query = Column(Text)
100
+ research_mode = Column(String)
101
+ research_phase = Column(String)
102
+ search_iteration = Column(Integer)
103
+
104
+ # Search details
105
+ search_engine = Column(String)
106
+ query = Column(Text)
107
+ results_count = Column(Integer)
108
+ response_time_ms = Column(Integer)
109
+
110
+ # Status tracking
111
+ success_status = Column(String, default="success")
112
+ error_type = Column(String)
113
+ error_message = Column(Text)
114
+
115
+ timestamp = Column(DateTime, server_default=func.now())
@@ -0,0 +1,148 @@
1
+ """
2
+ Migration: Add provider column to TokenUsage table
3
+
4
+ This migration adds the provider column to the TokenUsage table to enable
5
+ accurate cost tracking based on both model and provider information.
6
+ """
7
+
8
+ import logging
9
+ from pathlib import Path
10
+
11
+ from sqlalchemy import text
12
+
13
+ from .database import get_metrics_db
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ def add_provider_column_to_token_usage():
19
+ """Add provider column to TokenUsage table."""
20
+ try:
21
+ db = get_metrics_db()
22
+
23
+ with db.get_session() as session:
24
+ # Check if provider column already exists
25
+ result = session.execute(
26
+ text(
27
+ """
28
+ SELECT COUNT(*) as count
29
+ FROM pragma_table_info('token_usage')
30
+ WHERE name='provider'
31
+ """
32
+ )
33
+ )
34
+
35
+ provider_exists = result.fetchone()[0] > 0
36
+
37
+ if provider_exists:
38
+ logger.info(
39
+ "Provider column already exists in token_usage table"
40
+ )
41
+ return True
42
+
43
+ logger.info("Adding provider column to token_usage table...")
44
+
45
+ # Add the provider column
46
+ session.execute(
47
+ text(
48
+ """
49
+ ALTER TABLE token_usage
50
+ ADD COLUMN provider VARCHAR
51
+ """
52
+ )
53
+ )
54
+
55
+ # Try to populate provider info for existing records based on model name patterns
56
+ logger.info("Populating provider info for existing records...")
57
+
58
+ # Update known local model providers
59
+ local_model_updates = [
60
+ (
61
+ "ollama",
62
+ [
63
+ "ollama",
64
+ "llama",
65
+ "mistral",
66
+ "gemma",
67
+ "qwen",
68
+ "codellama",
69
+ "vicuna",
70
+ "alpaca",
71
+ ],
72
+ ),
73
+ ("openai", ["gpt-", "davinci", "curie", "babbage", "ada"]),
74
+ ("anthropic", ["claude"]),
75
+ ("google", ["gemini", "bard"]),
76
+ ]
77
+
78
+ for provider, model_patterns in local_model_updates:
79
+ for pattern in model_patterns:
80
+ session.execute(
81
+ text(
82
+ """
83
+ UPDATE token_usage
84
+ SET provider = :provider
85
+ WHERE provider IS NULL
86
+ AND (LOWER(model_name) LIKE :pattern OR LOWER(model_name) LIKE :pattern_percent)
87
+ """
88
+ ),
89
+ {
90
+ "provider": provider,
91
+ "pattern": pattern,
92
+ "pattern_percent": f"%{pattern}%",
93
+ },
94
+ )
95
+
96
+ # Set any remaining NULL providers to 'unknown'
97
+ session.execute(
98
+ text(
99
+ """
100
+ UPDATE token_usage
101
+ SET provider = 'unknown'
102
+ WHERE provider IS NULL
103
+ """
104
+ )
105
+ )
106
+
107
+ session.commit()
108
+ logger.info(
109
+ "Successfully added provider column and populated existing data"
110
+ )
111
+ return True
112
+
113
+ except Exception as e:
114
+ logger.error(f"Error adding provider column to token_usage: {e}")
115
+ return False
116
+
117
+
118
+ def run_migration():
119
+ """Run the provider column migration."""
120
+ logger.info("Starting migration: Add provider column to TokenUsage")
121
+
122
+ success = add_provider_column_to_token_usage()
123
+
124
+ if success:
125
+ logger.info("Migration completed successfully")
126
+ else:
127
+ logger.error("Migration failed")
128
+
129
+ return success
130
+
131
+
132
+ if __name__ == "__main__":
133
+ # Allow running migration directly
134
+ import sys
135
+
136
+ # Add the project root to the path
137
+ project_root = Path(__file__).parent.parent.parent.parent
138
+ sys.path.insert(0, str(project_root))
139
+
140
+ logging.basicConfig(level=logging.INFO)
141
+ success = run_migration()
142
+
143
+ if success:
144
+ print("✅ Migration completed successfully")
145
+ sys.exit(0)
146
+ else:
147
+ print("❌ Migration failed")
148
+ sys.exit(1)