virtual-context 0.3.2__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 (233) hide show
  1. {virtual_context-0.3.2 → virtual_context-0.3.3}/PKG-INFO +1 -1
  2. {virtual_context-0.3.2 → virtual_context-0.3.3}/pyproject.toml +2 -1
  3. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/__init__.py +1 -1
  4. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/cli/main.py +181 -17
  5. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/model_catalog.py +15 -3
  6. virtual_context-0.3.3/virtual_context/data/models.yaml +207 -0
  7. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/handlers.py +78 -0
  8. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/server.py +8 -1
  9. {virtual_context-0.3.2 → virtual_context-0.3.3}/.gitignore +0 -0
  10. {virtual_context-0.3.2 → virtual_context-0.3.3}/LICENSE +0 -0
  11. {virtual_context-0.3.2 → virtual_context-0.3.3}/README-draft.md +0 -0
  12. {virtual_context-0.3.2 → virtual_context-0.3.3}/README.md +0 -0
  13. {virtual_context-0.3.2 → virtual_context-0.3.3}/README.md.backup +0 -0
  14. {virtual_context-0.3.2 → virtual_context-0.3.3}/assets/dashboard.png +0 -0
  15. {virtual_context-0.3.2 → virtual_context-0.3.3}/assets/hero.png +0 -0
  16. {virtual_context-0.3.2 → virtual_context-0.3.3}/models.yaml +0 -0
  17. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/REGRESSION_MAP.md +0 -0
  18. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/conftest.py +0 -0
  19. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/docker-compose.test.yml +0 -0
  20. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/haiku/__init__.py +0 -0
  21. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/haiku/conftest.py +0 -0
  22. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/haiku/test_compaction.py +0 -0
  23. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/haiku/test_retrieval.py +0 -0
  24. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/haiku/test_tagging.py +0 -0
  25. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/ollama/__init__.py +0 -0
  26. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/ollama/conftest.py +0 -0
  27. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/ollama/test_compactor.py +0 -0
  28. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/ollama/test_pipeline.py +0 -0
  29. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/ollama/test_provider.py +0 -0
  30. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/ollama/test_tag_generator.py +0 -0
  31. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/proxy/__init__.py +0 -0
  32. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/proxy/test_dashboard_cors.py +0 -0
  33. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/proxy/test_metrics.py +0 -0
  34. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_assembler.py +0 -0
  35. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_backend_integration.py +0 -0
  36. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_budget_enforcement.py +0 -0
  37. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_cli_init.py +0 -0
  38. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_compaction_commit_prune.py +0 -0
  39. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_compactor.py +0 -0
  40. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_compactor_concurrent.py +0 -0
  41. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_composite_store.py +0 -0
  42. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_config.py +0 -0
  43. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_context_bleed.py +0 -0
  44. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_conversation_identity.py +0 -0
  45. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_conversation_lifecycle.py +0 -0
  46. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_conversation_scoping.py +0 -0
  47. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_embedding_tag_generator.py +0 -0
  48. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_empty_turn_skip.py +0 -0
  49. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_engine_integration.py +0 -0
  50. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_engine_lookback.py +0 -0
  51. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_engine_state.py +0 -0
  52. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_engine_sync_turns.py +0 -0
  53. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_fact_enrichment.py +0 -0
  54. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_fact_graph_integration.py +0 -0
  55. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_fact_link_checker.py +0 -0
  56. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_fact_link_query.py +0 -0
  57. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_fact_link_types.py +0 -0
  58. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_fact_links_sqlite.py +0 -0
  59. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_fact_redesign.py +0 -0
  60. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_fill_pass.py +0 -0
  61. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_find_quote.py +0 -0
  62. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_format_agnostic.py +0 -0
  63. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_headless.py +0 -0
  64. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_history_filter.py +0 -0
  65. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_idf_retrieval.py +0 -0
  66. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_ingest_index_integrity.py +0 -0
  67. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_longmemeval_auth.py +0 -0
  68. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_mcp_server.py +0 -0
  69. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_media.py +0 -0
  70. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_message_filter.py +0 -0
  71. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_metrics_persistence.py +0 -0
  72. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_model_catalog.py +0 -0
  73. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_model_limits.py +0 -0
  74. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_monitor.py +0 -0
  75. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_multi_instance.py +0 -0
  76. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_noop_fact_link_store.py +0 -0
  77. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_openrouter_provider.py +0 -0
  78. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_paging.py +0 -0
  79. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_passthrough_filter.py +0 -0
  80. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_presets.py +0 -0
  81. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_prev_context_leak.py +0 -0
  82. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_provider_adapters.py +0 -0
  83. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_proxy.py +0 -0
  84. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_proxy_dashboard.py +0 -0
  85. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_proxy_formats.py +0 -0
  86. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_proxy_message_filter.py +0 -0
  87. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_proxy_session.py +0 -0
  88. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_proxy_streaming.py +0 -0
  89. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_raw_content.py +0 -0
  90. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_recall_all.py +0 -0
  91. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_registry_lifecycle.py +0 -0
  92. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_request_captures_persistence.py +0 -0
  93. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_retriever.py +0 -0
  94. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_rrf_scoring.py +0 -0
  95. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_segmenter.py +0 -0
  96. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_semantic_search.py +0 -0
  97. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_sender_identity.py +0 -0
  98. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_session_cache.py +0 -0
  99. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_session_date.py +0 -0
  100. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_session_state.py +0 -0
  101. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_storage_protocols.py +0 -0
  102. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_store_recovery.py +0 -0
  103. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_store_sqlite.py +0 -0
  104. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_stub_turn_handling.py +0 -0
  105. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_supersession.py +0 -0
  106. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_supersession_migration.py +0 -0
  107. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_tag_canonicalizer.py +0 -0
  108. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_tag_consolidator.py +0 -0
  109. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_tag_generator.py +0 -0
  110. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_tag_splitter.py +0 -0
  111. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_telemetry.py +0 -0
  112. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_telemetry_integration.py +0 -0
  113. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_tool_loop.py +0 -0
  114. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_tool_output_interceptor.py +0 -0
  115. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_tool_result_filter.py +0 -0
  116. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_tool_tags.py +0 -0
  117. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_tui.py +0 -0
  118. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_turn_grouping.py +0 -0
  119. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_turn_tag_index.py +0 -0
  120. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_unified_budget.py +0 -0
  121. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_upstream_trim.py +0 -0
  122. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_vcattach.py +0 -0
  123. {virtual_context-0.3.2 → virtual_context-0.3.3}/tests/test_verb_expansion.py +0 -0
  124. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual-context.yaml +0 -0
  125. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual-context.yaml.example +0 -0
  126. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/cli/__init__.py +0 -0
  127. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/config.py +0 -0
  128. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/conversation_identity.py +0 -0
  129. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/__init__.py +0 -0
  130. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/assembler.py +0 -0
  131. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/compaction_pipeline.py +0 -0
  132. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/compactor.py +0 -0
  133. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/composite_store.py +0 -0
  134. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/conversation_store.py +0 -0
  135. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/embedding_provider.py +0 -0
  136. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/embedding_tag_generator.py +0 -0
  137. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/engine_utils.py +0 -0
  138. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/fact_query.py +0 -0
  139. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/fts_preprocessor.py +0 -0
  140. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/hint_builder.py +0 -0
  141. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/llm_utils.py +0 -0
  142. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/math_utils.py +0 -0
  143. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/monitor.py +0 -0
  144. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/paging_manager.py +0 -0
  145. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/protocols.py +0 -0
  146. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/provider_adapters.py +0 -0
  147. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/quote_search.py +0 -0
  148. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/retrieval_assembler.py +0 -0
  149. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/retrieval_scoring.py +0 -0
  150. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/retriever.py +0 -0
  151. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/search_engine.py +0 -0
  152. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/segmenter.py +0 -0
  153. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/semantic_search.py +0 -0
  154. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/store.py +0 -0
  155. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/tag_canonicalizer.py +0 -0
  156. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/tag_consolidator.py +0 -0
  157. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/tag_generator.py +0 -0
  158. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/tag_scoring.py +0 -0
  159. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/tag_splitter.py +0 -0
  160. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/tagging_pipeline.py +0 -0
  161. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/telemetry.py +0 -0
  162. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/temporal_resolver.py +0 -0
  163. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/tool_loop.py +0 -0
  164. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/tool_query.py +0 -0
  165. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/core/turn_tag_index.py +0 -0
  166. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/data/anthropic-tokenizer/tokenizer.json +0 -0
  167. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/engine.py +0 -0
  168. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/ingest/__init__.py +0 -0
  169. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/ingest/curator.py +0 -0
  170. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/ingest/date_resolver.py +0 -0
  171. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/ingest/parsers.py +0 -0
  172. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/ingest/supersession.py +0 -0
  173. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/mcp/__init__.py +0 -0
  174. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/mcp/server.py +0 -0
  175. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/model_limits.py +0 -0
  176. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/openclaw/virtual-context.mjs +0 -0
  177. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/patterns.py +0 -0
  178. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/presets/__init__.py +0 -0
  179. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/presets/agentic.py +0 -0
  180. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/presets/base.py +0 -0
  181. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/presets/coding.py +0 -0
  182. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/providers/__init__.py +0 -0
  183. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/providers/anthropic.py +0 -0
  184. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/providers/base.py +0 -0
  185. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/providers/generic_openai.py +0 -0
  186. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/providers/ollama_native.py +0 -0
  187. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/__init__.py +0 -0
  188. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/_envelope.py +0 -0
  189. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/dashboard.html +0 -0
  190. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/dashboard.py +0 -0
  191. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/formats.py +0 -0
  192. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/helpers.py +0 -0
  193. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/media.py +0 -0
  194. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/message_filter.py +0 -0
  195. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/metrics.py +0 -0
  196. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/multi.py +0 -0
  197. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/registry.py +0 -0
  198. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/session_cache.py +0 -0
  199. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/session_state.py +0 -0
  200. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/state.py +0 -0
  201. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/static/android-chrome-192x192.png +0 -0
  202. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/static/android-chrome-512x512.png +0 -0
  203. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/static/apple-touch-icon.png +0 -0
  204. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/static/favicon-16x16.png +0 -0
  205. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/static/favicon-32x32.png +0 -0
  206. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/static/favicon.ico +0 -0
  207. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/static/site.webmanifest +0 -0
  208. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/tool_output_interceptor.py +0 -0
  209. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/proxy/vcattach.py +0 -0
  210. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/storage/__init__.py +0 -0
  211. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/storage/falkordb.py +0 -0
  212. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/storage/filesystem.py +0 -0
  213. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/storage/helpers.py +0 -0
  214. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/storage/neo4j.py +0 -0
  215. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/storage/noop_fact_link_store.py +0 -0
  216. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/storage/postgres.py +0 -0
  217. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/storage/sqlite.py +0 -0
  218. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/token_counter.py +0 -0
  219. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/__init__.py +0 -0
  220. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/app.py +0 -0
  221. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/chat.tcss +0 -0
  222. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/chat_provider.py +0 -0
  223. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/headless.py +0 -0
  224. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/modals/__init__.py +0 -0
  225. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/modals/turn_inspector.py +0 -0
  226. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/state.py +0 -0
  227. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/widgets/__init__.py +0 -0
  228. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/widgets/budget_bar.py +0 -0
  229. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/widgets/chat_view.py +0 -0
  230. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/widgets/input_box.py +0 -0
  231. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/widgets/tag_panel.py +0 -0
  232. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/tui/widgets/turn_list.py +0 -0
  233. {virtual_context-0.3.2 → virtual_context-0.3.3}/virtual_context/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: virtual-context
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: OS-style virtual memory for LLM session context management
5
5
  Project-URL: Homepage, https://virtual-context.com
6
6
  Project-URL: Repository, https://github.com/virtual-context/virtual-context
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "virtual-context"
7
- version = "0.3.2"
7
+ version = "0.3.3"
8
8
  description = "OS-style virtual memory for LLM session context management"
9
9
  readme = "README.md"
10
10
  license = "AGPL-3.0-or-later"
@@ -71,6 +71,7 @@ exclude = [
71
71
  artifacts = [
72
72
  "virtual_context/proxy/static/*",
73
73
  "virtual_context/data/anthropic-tokenizer/tokenizer.json",
74
+ "virtual_context/data/models.yaml",
74
75
  ]
75
76
 
76
77
  [tool.hatch.build.targets.wheel]
@@ -14,7 +14,7 @@ from .types import (
14
14
  VirtualContextConfig,
15
15
  )
16
16
 
17
- __version__ = "0.3.2"
17
+ __version__ = "0.3.3"
18
18
 
19
19
  __all__ = [
20
20
  "VirtualContextEngine",
@@ -508,6 +508,23 @@ _PROVIDER_MODELS: dict[str, list[str]] = {
508
508
  "openrouter": ["qwen/qwen3-30b-a3b", "qwen/qwen3-32b", "google/gemini-2.5-flash-preview"],
509
509
  }
510
510
 
511
+ # Context window sizes for upstream providers — used to set correct defaults
512
+ _UPSTREAM_CONTEXT_WINDOWS: dict[str, int] = {
513
+ "anthropic": 1_000_000,
514
+ "openai": 128_000,
515
+ "gemini": 1_000_000,
516
+ "ollama": 128_000,
517
+ "openrouter": 200_000,
518
+ "custom": 128_000,
519
+ }
520
+
521
+ # API key env var names per provider
522
+ _PROVIDER_KEY_ENVS: dict[str, str] = {
523
+ "anthropic": "ANTHROPIC_API_KEY",
524
+ "openai": "OPENAI_API_KEY",
525
+ "openrouter": "OPENROUTER_API_KEY",
526
+ }
527
+
511
528
 
512
529
  def _prompt_tagging_provider() -> tuple[str, str]:
513
530
  provider = _prompt_choice(
@@ -542,31 +559,43 @@ def _provider_defaults(provider: str) -> tuple[str, str]:
542
559
 
543
560
  def _write_instance_config(
544
561
  base_dir: Path, label: str, provider: str, model: str, inbound_tagger_type: str,
562
+ *,
563
+ context_window: int = 200_000,
564
+ host: str = "127.0.0.1",
565
+ port: int = 5757,
566
+ dashboard_token: str = "",
567
+ tag_api_key_env: str = "",
545
568
  ) -> str:
546
569
  """Generate a standalone YAML config for one proxy instance.
547
570
 
548
- Creates isolated storage at ``<base_dir>/.virtualcontext/<label>/store.db``
571
+ Creates isolated storage at ``~/.virtual-context/<label>/store.db``
549
572
  and writes config to ``<base_dir>/virtual-context-proxy-<label>.yaml``.
550
573
  Returns the path to the written file.
551
574
  """
552
- storage_root = f".virtualcontext/{label}"
575
+ storage_root = str(Path.home() / ".virtual-context" / label)
553
576
  provider_label, base_url = _provider_defaults(provider)
554
577
  provider_block: dict = {}
555
578
  if provider == "ollama":
556
579
  provider_block = {provider_label: {"type": "generic_openai", "base_url": base_url + "/v1"}}
557
580
  elif provider == "anthropic":
558
- provider_block = {provider_label: {"type": "anthropic"}}
581
+ prov = {"type": "anthropic"}
582
+ if tag_api_key_env:
583
+ prov["api_key_env"] = tag_api_key_env
584
+ provider_block = {provider_label: prov}
559
585
  elif provider == "openai":
560
- provider_block = {provider_label: {"type": "generic_openai", "base_url": base_url}}
586
+ prov = {"type": "generic_openai", "base_url": base_url}
587
+ if tag_api_key_env:
588
+ prov["api_key_env"] = tag_api_key_env
589
+ provider_block = {provider_label: prov}
561
590
  elif provider == "openrouter":
562
- provider_block = {provider_label: {"type": "openrouter", "base_url": base_url, "api_key_env": "OPENROUTER_API_KEY"}}
591
+ provider_block = {provider_label: {"type": "openrouter", "base_url": base_url, "api_key_env": tag_api_key_env or "OPENROUTER_API_KEY"}}
563
592
  else:
564
593
  provider_block = {provider_label: {"type": "generic_openai", "base_url": base_url}}
565
594
 
566
595
  cfg: dict = {
567
596
  "version": "0.2",
568
597
  "storage_root": storage_root,
569
- "context_window": 120_000,
598
+ "context_window": context_window,
570
599
  "token_counter": "estimate",
571
600
  "tag_generator": {
572
601
  "type": "llm" if provider != "keyword" else "keyword",
@@ -596,6 +625,23 @@ def _write_instance_config(
596
625
  return str(out_path)
597
626
 
598
627
 
628
+ def _check_provider_reachable(provider: str) -> bool:
629
+ """Quick check if a tagging provider is reachable."""
630
+ if provider == "ollama":
631
+ try:
632
+ import urllib.request
633
+ urllib.request.urlopen("http://127.0.0.1:11434/api/tags", timeout=3)
634
+ return True
635
+ except Exception:
636
+ return False
637
+ return True # Remote providers — can't cheaply validate without a key
638
+
639
+
640
+ def _generate_dashboard_token() -> str:
641
+ import secrets
642
+ return secrets.token_urlsafe(24)
643
+
644
+
599
645
  def _run_instance_wizard() -> tuple[list[dict], list[str]]:
600
646
  """Interactive wizard for proxy instance setup.
601
647
 
@@ -606,13 +652,47 @@ def _run_instance_wizard() -> tuple[list[dict], list[str]]:
606
652
  print("\n--- Tagging & Summarization ---")
607
653
  tag_provider, tag_model = _prompt_tagging_provider()
608
654
 
655
+ # Validate tagging provider is reachable
656
+ if not _check_provider_reachable(tag_provider):
657
+ print(f"\n WARNING: {tag_provider} does not appear to be running.")
658
+ if tag_provider == "ollama":
659
+ print(" Start Ollama first: ollama serve")
660
+ if not _prompt_yes_no("Continue anyway?", default_yes=False):
661
+ sys.exit(0)
662
+
663
+ # API key for tagging provider
664
+ tag_api_key_env = ""
665
+ tag_key_env = _PROVIDER_KEY_ENVS.get(tag_provider)
666
+ if tag_key_env:
667
+ existing = os.environ.get(tag_key_env, "")
668
+ if existing:
669
+ print(f"\n Found {tag_key_env} in environment.")
670
+ tag_api_key_env = tag_key_env
671
+ else:
672
+ print(f"\n The {tag_provider} tagger needs an API key.")
673
+ print(f" Set {tag_key_env} in your environment before starting the proxy.")
674
+ tag_api_key_env = tag_key_env
675
+
609
676
  inbound_tagger_type = _prompt_choice(
610
677
  "Inbound tagging mode:",
611
678
  ["embedding", "llm", "keyword"],
612
679
  default="embedding",
613
680
  )
614
681
 
615
- multi = _prompt_yes_no("Configure multiple proxy instances?", default_yes=False)
682
+ # Client selection — determines post-wizard instructions
683
+ client = _prompt_choice(
684
+ "What client will you use with this proxy?",
685
+ ["Claude Code", "Claude Desktop", "Other / REST API"],
686
+ default="Claude Code",
687
+ )
688
+
689
+ # Dashboard token
690
+ print("\n--- Security ---")
691
+ dashboard_token = _generate_dashboard_token()
692
+ print(f" Generated dashboard token: {dashboard_token}")
693
+ print(" (protects dashboard mutating endpoints)")
694
+
695
+ multi = _prompt_yes_no("\nConfigure multiple proxy instances?", default_yes=False)
616
696
  count = 1
617
697
  if multi:
618
698
  count = _prompt_int("How many proxy instances?", default=2, min_value=1)
@@ -620,7 +700,8 @@ def _run_instance_wizard() -> tuple[list[dict], list[str]]:
620
700
  instances: list[dict] = []
621
701
  config_paths: list[str] = []
622
702
  used_ports: set[int] = set()
623
- base_dir = Path.cwd()
703
+ base_dir = Path.home() / ".virtual-context"
704
+ base_dir.mkdir(parents=True, exist_ok=True)
624
705
 
625
706
  for i in range(count):
626
707
  print(f"\n--- Instance {i + 1}/{count} ---")
@@ -634,6 +715,10 @@ def _run_instance_wizard() -> tuple[list[dict], list[str]]:
634
715
  label = _prompt("Label", default_label)
635
716
  upstream = _prompt("Upstream URL", default_upstream)
636
717
 
718
+ # Context window — default based on upstream provider
719
+ default_cw = _UPSTREAM_CONTEXT_WINDOWS.get(provider, 200_000)
720
+ context_window = _prompt_int("Context window (tokens)", default=default_cw, min_value=8_000)
721
+
637
722
  default_port = 5757 + i
638
723
  while True:
639
724
  port = _prompt_int("Port", default=default_port, min_value=1)
@@ -647,19 +732,26 @@ def _run_instance_wizard() -> tuple[list[dict], list[str]]:
647
732
 
648
733
  # Per-instance tagger override
649
734
  use_different_tagger = False
735
+ inst_tag_provider = tag_provider
736
+ inst_tag_model = tag_model
737
+ inst_tag_key_env = tag_api_key_env
650
738
  if count > 1:
651
739
  use_different_tagger = _prompt_yes_no(
652
740
  f"Use a different tagger provider for '{label}'?", default_yes=False,
653
741
  )
654
742
 
655
- inst_tag_provider = tag_provider
656
- inst_tag_model = tag_model
657
743
  if use_different_tagger:
658
744
  inst_tag_provider, inst_tag_model = _prompt_tagging_provider()
745
+ inst_tag_key_env = _PROVIDER_KEY_ENVS.get(inst_tag_provider, "")
659
746
 
660
747
  # Write per-instance config
661
748
  cfg_path = _write_instance_config(
662
749
  base_dir, label, inst_tag_provider, inst_tag_model, inbound_tagger_type,
750
+ context_window=context_window,
751
+ host=host,
752
+ port=port,
753
+ dashboard_token=dashboard_token,
754
+ tag_api_key_env=inst_tag_key_env,
663
755
  )
664
756
  config_paths.append(cfg_path)
665
757
 
@@ -670,13 +762,16 @@ def _run_instance_wizard() -> tuple[list[dict], list[str]]:
670
762
  "label": label,
671
763
  "host": host,
672
764
  "config": cfg_path,
765
+ "context_window": context_window,
766
+ "dashboard_token": dashboard_token,
673
767
  }
674
768
  )
675
769
 
676
770
  # Review screen
677
771
  print("\n--- Review ---")
678
772
  for inst in instances:
679
- print(f" [{inst['label']}] :{inst['port']} -> {inst['upstream']}")
773
+ print(f" [{inst['label']}] {inst['host']}:{inst['port']} -> {inst['upstream']}")
774
+ print(f" context window: {inst['context_window']:,} tokens")
680
775
  print(f" config: {inst['config']}")
681
776
  print()
682
777
 
@@ -684,6 +779,48 @@ def _run_instance_wizard() -> tuple[list[dict], list[str]]:
684
779
  print("Aborted.")
685
780
  sys.exit(0)
686
781
 
782
+ # Post-wizard summary
783
+ print("\n" + "=" * 60)
784
+ print("SETUP COMPLETE")
785
+ print("=" * 60)
786
+ vc_home = Path.home() / ".virtual-context"
787
+ print(f"\n Config files: {vc_home}/")
788
+ print(f" Storage: {vc_home}/<label>/")
789
+ print(f" Dashboard: http://{instances[0]['host']}:{instances[0]['port']}/dashboard")
790
+
791
+ # API key reminders
792
+ needed_keys = set()
793
+ if tag_key_env and not os.environ.get(tag_key_env, ""):
794
+ needed_keys.add(tag_key_env)
795
+ if needed_keys:
796
+ print("\n API keys needed (set before starting proxy):")
797
+ for k in sorted(needed_keys):
798
+ print(f" export {k}=\"your-key-here\"")
799
+
800
+ # Client-specific instructions
801
+ inst = instances[0]
802
+ if "Claude Code" in client:
803
+ print(f"\n Claude Code setup:")
804
+ print(f" Set this in your environment or .claude/settings.json:")
805
+ print(f" ANTHROPIC_BASE_URL=http://{inst['host']}:{inst['port']}/")
806
+ print(f"\n Disable auto-compact in Claude Code:")
807
+ print(f" Type /config -> Auto-compact -> disable")
808
+ print(f"\n Set VC_DASHBOARD_TOKEN in your environment:")
809
+ print(f" export VC_DASHBOARD_TOKEN=\"{dashboard_token}\"")
810
+ elif "Desktop" in client:
811
+ print(f"\n Claude Desktop setup:")
812
+ print(f" In Claude Desktop settings, set the API base URL to:")
813
+ print(f" http://{inst['host']}:{inst['port']}/")
814
+ else:
815
+ print(f"\n REST API / Custom client:")
816
+ print(f" Proxy endpoint: http://{inst['host']}:{inst['port']}/")
817
+ print(f" Forward your LLM API requests through this proxy.")
818
+
819
+ print(f"\n Logs:")
820
+ print(f" Proxy: tail -f ~/Library/Logs/virtual-context.log")
821
+ print(f" Errors: tail -f ~/Library/Logs/virtual-context.err.log")
822
+ print()
823
+
687
824
  return instances, config_paths
688
825
 
689
826
 
@@ -703,7 +840,10 @@ def _proxy_command(config_path: Path, upstream: str | None) -> str:
703
840
  return cmd
704
841
 
705
842
 
706
- def _install_launchd_daemon(config_path: Path, upstream: str | None, start: bool) -> None:
843
+ def _install_launchd_daemon(
844
+ config_path: Path, upstream: str | None, start: bool,
845
+ *, dashboard_token: str = "",
846
+ ) -> None:
707
847
  from xml.sax.saxutils import escape as _xml_escape
708
848
 
709
849
  launch_agents = Path.home() / "Library" / "LaunchAgents"
@@ -712,6 +852,17 @@ def _install_launchd_daemon(config_path: Path, upstream: str | None, start: bool
712
852
  cmd = _proxy_command(config_path, upstream)
713
853
  log_path = Path.home() / "Library" / "Logs" / "virtual-context.log"
714
854
  err_path = Path.home() / "Library" / "Logs" / "virtual-context.err.log"
855
+
856
+ # Build optional EnvironmentVariables block
857
+ env_block = ""
858
+ if dashboard_token:
859
+ env_block = f""" <key>EnvironmentVariables</key>
860
+ <dict>
861
+ <key>VC_DASHBOARD_TOKEN</key>
862
+ <string>{_xml_escape(dashboard_token)}</string>
863
+ </dict>
864
+ """
865
+
715
866
  # Escape XML special characters to prevent XML injection
716
867
  plist = f"""<?xml version="1.0" encoding="UTF-8"?>
717
868
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -733,7 +884,7 @@ def _install_launchd_daemon(config_path: Path, upstream: str | None, start: bool
733
884
  <string>{_xml_escape(str(log_path))}</string>
734
885
  <key>StandardErrorPath</key>
735
886
  <string>{_xml_escape(str(err_path))}</string>
736
- </dict>
887
+ {env_block}</dict>
737
888
  </plist>
738
889
  """
739
890
  plist_path.write_text(plist)
@@ -829,7 +980,9 @@ def _install_windows_task_daemon(config_path: Path, upstream: str | None, start:
829
980
 
830
981
 
831
982
  def cmd_onboard(args):
832
- config_path = Path(args.config) if args.config else Path.cwd() / "virtual-context.yaml"
983
+ vc_home = Path.home() / ".virtual-context"
984
+ vc_home.mkdir(parents=True, exist_ok=True)
985
+ config_path = Path(args.config) if args.config else vc_home / "virtual-context.yaml"
833
986
 
834
987
  if not config_path.exists():
835
988
  preset = get_preset(args.preset)
@@ -863,12 +1016,20 @@ def cmd_onboard(args):
863
1016
  interactive = bool(args.wizard and sys.stdin.isatty())
864
1017
  selected_upstream = args.upstream
865
1018
 
1019
+ _wizard_dashboard_token = ""
866
1020
  if interactive:
867
1021
  instances, _config_paths = _run_instance_wizard()
868
1022
  _apply_proxy_instances(config_path, instances)
869
1023
  print(f"Updated {config_path} with {len(instances)} proxy instance(s).")
870
- # In multi-instance mode, upstream comes from config; daemon command should omit it.
871
- selected_upstream = None
1024
+ # In wizard mode, use the first instance's config for daemon install
1025
+ if _config_paths:
1026
+ config_path = Path(_config_paths[0])
1027
+ # Extract upstream and dashboard token from first instance
1028
+ if instances:
1029
+ selected_upstream = instances[0].get("upstream")
1030
+ _wizard_dashboard_token = instances[0].get("dashboard_token", "")
1031
+ else:
1032
+ selected_upstream = None
872
1033
  if not daemon_requested:
873
1034
  daemon_requested = _prompt_yes_no("Install daemon/service now?", default_yes=True)
874
1035
 
@@ -884,7 +1045,10 @@ def cmd_onboard(args):
884
1045
  system = platform.system().lower()
885
1046
  try:
886
1047
  if system == "darwin":
887
- _install_launchd_daemon(config_path, selected_upstream, start=not args.no_start)
1048
+ _install_launchd_daemon(
1049
+ config_path, selected_upstream, start=not args.no_start,
1050
+ dashboard_token=_wizard_dashboard_token,
1051
+ )
888
1052
  elif system == "linux":
889
1053
  _install_systemd_user_daemon(config_path, selected_upstream, start=not args.no_start)
890
1054
  elif system == "windows":
@@ -30,11 +30,23 @@ class ModelCatalog:
30
30
 
31
31
  @classmethod
32
32
  def default(cls) -> ModelCatalog:
33
+ # Search order:
34
+ # 1. ~/.virtual-context/models.yaml (user override)
35
+ # 2. Bundled inside the package (virtual_context/data/models.yaml)
36
+ # 3. Project root (dev checkout)
37
+ user_path = os.path.join(os.path.expanduser("~"), ".virtual-context", "models.yaml")
38
+ if os.path.exists(user_path):
39
+ return cls(user_path)
40
+
33
41
  here = os.path.dirname(os.path.abspath(__file__))
34
- # core/ -> virtual_context/ -> project root
42
+ pkg_path = os.path.join(os.path.dirname(here), "data", "models.yaml")
43
+ if os.path.exists(pkg_path):
44
+ return cls(pkg_path)
45
+
46
+ # Dev checkout: core/ -> virtual_context/ -> project root
35
47
  root = os.path.dirname(os.path.dirname(here))
36
- path = os.path.join(root, "models.yaml")
37
- return cls(path)
48
+ root_path = os.path.join(root, "models.yaml")
49
+ return cls(root_path)
38
50
 
39
51
  def _load(self, path: str) -> None:
40
52
  if not os.path.exists(path):
@@ -0,0 +1,207 @@
1
+ # Model pricing catalog for Virtual Context telemetry.
2
+ # Prices in USD per million tokens. Updated 2026-03-15.
3
+
4
+ models:
5
+ # ---------------------------------------------------------------------------
6
+ # Anthropic
7
+ # ---------------------------------------------------------------------------
8
+ claude-haiku-4-5-20251001:
9
+ provider: anthropic
10
+ input_per_mtok: 1.00
11
+ output_per_mtok: 5.00
12
+ context_window: 200000
13
+ aliases: [haiku, claude-haiku, claude-haiku-4-5]
14
+
15
+ claude-sonnet-4-5-20250929:
16
+ provider: anthropic
17
+ input_per_mtok: 3.00
18
+ output_per_mtok: 15.00
19
+ context_window: 200000
20
+ aliases: [claude-sonnet-4-5, claude-sonnet-4-20250514]
21
+
22
+ claude-sonnet-4-6:
23
+ provider: anthropic
24
+ input_per_mtok: 3.00
25
+ output_per_mtok: 15.00
26
+ context_window: 200000
27
+ aliases: [sonnet, claude-sonnet]
28
+
29
+ claude-opus-4-5:
30
+ provider: anthropic
31
+ input_per_mtok: 5.00
32
+ output_per_mtok: 25.00
33
+ context_window: 200000
34
+ aliases: [claude-opus-4-20250514]
35
+
36
+ claude-opus-4-6:
37
+ provider: anthropic
38
+ input_per_mtok: 5.00
39
+ output_per_mtok: 25.00
40
+ context_window: 200000
41
+ aliases: [opus, claude-opus]
42
+
43
+ # ---------------------------------------------------------------------------
44
+ # OpenAI
45
+ # ---------------------------------------------------------------------------
46
+ gpt-5.2:
47
+ provider: openai
48
+ input_per_mtok: 1.75
49
+ output_per_mtok: 14.00
50
+ context_window: 128000
51
+ aliases: [gpt5.2]
52
+
53
+ gpt-5.2-pro:
54
+ provider: openai
55
+ input_per_mtok: 21.00
56
+ output_per_mtok: 168.00
57
+ context_window: 128000
58
+ aliases: [gpt5.2-pro]
59
+
60
+ gpt-5.3-codex:
61
+ provider: openai
62
+ input_per_mtok: 1.75
63
+ output_per_mtok: 14.00
64
+ context_window: 128000
65
+ aliases: [gpt5-codex, codex]
66
+
67
+ gpt-5.4:
68
+ provider: openai
69
+ input_per_mtok: 2.50
70
+ output_per_mtok: 15.00
71
+ context_window: 1050000
72
+ aliases: [gpt5.4]
73
+
74
+ gpt-5-mini:
75
+ provider: openai
76
+ input_per_mtok: 0.25
77
+ output_per_mtok: 2.00
78
+ context_window: 128000
79
+ aliases: [gpt5-mini]
80
+
81
+ gpt-5-nano:
82
+ provider: openai
83
+ input_per_mtok: 0.05
84
+ output_per_mtok: 0.40
85
+ context_window: 128000
86
+ aliases: [gpt5-nano]
87
+
88
+ gpt-4.1-nano:
89
+ provider: openai
90
+ input_per_mtok: 0.10
91
+ output_per_mtok: 0.40
92
+ context_window: 128000
93
+ aliases: [gpt4-nano]
94
+
95
+ gpt-4.1-mini:
96
+ provider: openai
97
+ input_per_mtok: 0.40
98
+ output_per_mtok: 1.60
99
+ context_window: 128000
100
+ aliases: [gpt4-mini]
101
+
102
+ gpt-4o:
103
+ provider: openai
104
+ input_per_mtok: 2.50
105
+ output_per_mtok: 10.00
106
+ context_window: 128000
107
+ aliases: [gpt4o]
108
+
109
+ gpt-4o-mini:
110
+ provider: openai
111
+ input_per_mtok: 0.15
112
+ output_per_mtok: 0.60
113
+ context_window: 128000
114
+ aliases: [gpt4o-mini]
115
+
116
+ gpt-4.1:
117
+ provider: openai
118
+ input_per_mtok: 2.00
119
+ output_per_mtok: 8.00
120
+ context_window: 1050000
121
+ aliases: [gpt4.1]
122
+
123
+ gpt-5:
124
+ provider: openai
125
+ input_per_mtok: 1.25
126
+ output_per_mtok: 10.00
127
+ context_window: 128000
128
+ aliases: [gpt5]
129
+
130
+ o1:
131
+ provider: openai
132
+ input_per_mtok: 15.00
133
+ output_per_mtok: 60.00
134
+ context_window: 200000
135
+ aliases: []
136
+
137
+ o3:
138
+ provider: openai
139
+ input_per_mtok: 2.00
140
+ output_per_mtok: 8.00
141
+ context_window: 200000
142
+ aliases: []
143
+
144
+ o4-mini:
145
+ provider: openai
146
+ input_per_mtok: 1.10
147
+ output_per_mtok: 4.40
148
+ context_window: 200000
149
+ aliases: []
150
+
151
+ # ---------------------------------------------------------------------------
152
+ # Google Gemini
153
+ # ---------------------------------------------------------------------------
154
+ gemini-2.5-pro:
155
+ provider: google
156
+ input_per_mtok: 1.25
157
+ output_per_mtok: 10.00
158
+ context_window: 1000000
159
+ aliases: [gemini-pro, gemini-2.5-pro-preview-03-25]
160
+
161
+ gemini-2.5-flash:
162
+ provider: google
163
+ input_per_mtok: 0.30
164
+ output_per_mtok: 2.50
165
+ context_window: 1000000
166
+ aliases: [gemini-flash, gemini-2.5-flash-preview-04-17]
167
+
168
+ gemini-3.1-pro-preview:
169
+ provider: google
170
+ input_per_mtok: 2.00
171
+ output_per_mtok: 12.00
172
+ context_window: 1000000
173
+ aliases: [gemini-3.1-pro]
174
+
175
+ gemini-3-pro-preview:
176
+ provider: google
177
+ input_per_mtok: 2.00
178
+ output_per_mtok: 12.00
179
+ context_window: 1000000
180
+ aliases: [gemini-3-pro]
181
+
182
+ gemini-2.0-flash:
183
+ provider: google
184
+ input_per_mtok: 0.10
185
+ output_per_mtok: 0.40
186
+ context_window: 1000000
187
+ aliases: [gemini-2.0-flash-001]
188
+
189
+ # ---------------------------------------------------------------------------
190
+ # Xiaomi MiMo
191
+ # ---------------------------------------------------------------------------
192
+ mimo-v2-flash:
193
+ provider: xiaomi
194
+ input_per_mtok: 0.09
195
+ output_per_mtok: 0.29
196
+ context_window: 262000
197
+ aliases: [mimo, mimo-flash]
198
+
199
+ # ---------------------------------------------------------------------------
200
+ # Local / Ollama (free)
201
+ # ---------------------------------------------------------------------------
202
+ qwen3:4b-instruct-2507-fp16:
203
+ provider: ollama
204
+ input_per_mtok: 0.00
205
+ output_per_mtok: 0.00
206
+ context_window: 32768
207
+ aliases: [qwen3-4b]