virtual-context 0.3.1__tar.gz → 0.3.2__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 (234) hide show
  1. virtual_context-0.3.2/PKG-INFO +583 -0
  2. {virtual_context-0.3.1 → virtual_context-0.3.2}/README-draft.md +28 -15
  3. virtual_context-0.3.2/README.md +536 -0
  4. {virtual_context-0.3.1 → virtual_context-0.3.2}/pyproject.toml +1 -1
  5. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/__init__.py +1 -1
  6. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/handlers.py +411 -14
  7. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/metrics.py +10 -1
  8. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/server.py +22 -12
  9. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/types.py +3 -0
  10. virtual_context-0.3.1/PKG-INFO +0 -1177
  11. virtual_context-0.3.1/README.md +0 -1130
  12. {virtual_context-0.3.1 → virtual_context-0.3.2}/.gitignore +0 -0
  13. {virtual_context-0.3.1 → virtual_context-0.3.2}/LICENSE +0 -0
  14. {virtual_context-0.3.1 → virtual_context-0.3.2}/README.md.backup +0 -0
  15. {virtual_context-0.3.1 → virtual_context-0.3.2}/assets/dashboard.png +0 -0
  16. {virtual_context-0.3.1 → virtual_context-0.3.2}/assets/hero.png +0 -0
  17. {virtual_context-0.3.1 → virtual_context-0.3.2}/models.yaml +0 -0
  18. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/REGRESSION_MAP.md +0 -0
  19. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/conftest.py +0 -0
  20. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/docker-compose.test.yml +0 -0
  21. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/haiku/__init__.py +0 -0
  22. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/haiku/conftest.py +0 -0
  23. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/haiku/test_compaction.py +0 -0
  24. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/haiku/test_retrieval.py +0 -0
  25. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/haiku/test_tagging.py +0 -0
  26. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/ollama/__init__.py +0 -0
  27. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/ollama/conftest.py +0 -0
  28. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/ollama/test_compactor.py +0 -0
  29. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/ollama/test_pipeline.py +0 -0
  30. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/ollama/test_provider.py +0 -0
  31. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/ollama/test_tag_generator.py +0 -0
  32. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/proxy/__init__.py +0 -0
  33. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/proxy/test_dashboard_cors.py +0 -0
  34. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/proxy/test_metrics.py +0 -0
  35. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_assembler.py +0 -0
  36. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_backend_integration.py +0 -0
  37. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_budget_enforcement.py +0 -0
  38. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_cli_init.py +0 -0
  39. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_compaction_commit_prune.py +0 -0
  40. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_compactor.py +0 -0
  41. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_compactor_concurrent.py +0 -0
  42. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_composite_store.py +0 -0
  43. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_config.py +0 -0
  44. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_context_bleed.py +0 -0
  45. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_conversation_identity.py +0 -0
  46. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_conversation_lifecycle.py +0 -0
  47. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_conversation_scoping.py +0 -0
  48. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_embedding_tag_generator.py +0 -0
  49. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_empty_turn_skip.py +0 -0
  50. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_engine_integration.py +0 -0
  51. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_engine_lookback.py +0 -0
  52. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_engine_state.py +0 -0
  53. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_engine_sync_turns.py +0 -0
  54. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_fact_enrichment.py +0 -0
  55. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_fact_graph_integration.py +0 -0
  56. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_fact_link_checker.py +0 -0
  57. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_fact_link_query.py +0 -0
  58. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_fact_link_types.py +0 -0
  59. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_fact_links_sqlite.py +0 -0
  60. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_fact_redesign.py +0 -0
  61. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_fill_pass.py +0 -0
  62. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_find_quote.py +0 -0
  63. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_format_agnostic.py +0 -0
  64. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_headless.py +0 -0
  65. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_history_filter.py +0 -0
  66. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_idf_retrieval.py +0 -0
  67. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_ingest_index_integrity.py +0 -0
  68. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_longmemeval_auth.py +0 -0
  69. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_mcp_server.py +0 -0
  70. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_media.py +0 -0
  71. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_message_filter.py +0 -0
  72. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_metrics_persistence.py +0 -0
  73. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_model_catalog.py +0 -0
  74. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_model_limits.py +0 -0
  75. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_monitor.py +0 -0
  76. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_multi_instance.py +0 -0
  77. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_noop_fact_link_store.py +0 -0
  78. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_openrouter_provider.py +0 -0
  79. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_paging.py +0 -0
  80. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_passthrough_filter.py +0 -0
  81. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_presets.py +0 -0
  82. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_prev_context_leak.py +0 -0
  83. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_provider_adapters.py +0 -0
  84. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_proxy.py +0 -0
  85. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_proxy_dashboard.py +0 -0
  86. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_proxy_formats.py +0 -0
  87. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_proxy_message_filter.py +0 -0
  88. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_proxy_session.py +0 -0
  89. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_proxy_streaming.py +0 -0
  90. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_raw_content.py +0 -0
  91. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_recall_all.py +0 -0
  92. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_registry_lifecycle.py +0 -0
  93. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_request_captures_persistence.py +0 -0
  94. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_retriever.py +0 -0
  95. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_rrf_scoring.py +0 -0
  96. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_segmenter.py +0 -0
  97. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_semantic_search.py +0 -0
  98. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_sender_identity.py +0 -0
  99. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_session_cache.py +0 -0
  100. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_session_date.py +0 -0
  101. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_session_state.py +0 -0
  102. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_storage_protocols.py +0 -0
  103. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_store_recovery.py +0 -0
  104. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_store_sqlite.py +0 -0
  105. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_stub_turn_handling.py +0 -0
  106. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_supersession.py +0 -0
  107. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_supersession_migration.py +0 -0
  108. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_tag_canonicalizer.py +0 -0
  109. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_tag_consolidator.py +0 -0
  110. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_tag_generator.py +0 -0
  111. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_tag_splitter.py +0 -0
  112. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_telemetry.py +0 -0
  113. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_telemetry_integration.py +0 -0
  114. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_tool_loop.py +0 -0
  115. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_tool_output_interceptor.py +0 -0
  116. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_tool_result_filter.py +0 -0
  117. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_tool_tags.py +0 -0
  118. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_tui.py +0 -0
  119. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_turn_grouping.py +0 -0
  120. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_turn_tag_index.py +0 -0
  121. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_unified_budget.py +0 -0
  122. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_upstream_trim.py +0 -0
  123. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_vcattach.py +0 -0
  124. {virtual_context-0.3.1 → virtual_context-0.3.2}/tests/test_verb_expansion.py +0 -0
  125. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual-context.yaml +0 -0
  126. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual-context.yaml.example +0 -0
  127. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/cli/__init__.py +0 -0
  128. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/cli/main.py +0 -0
  129. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/config.py +0 -0
  130. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/conversation_identity.py +0 -0
  131. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/__init__.py +0 -0
  132. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/assembler.py +0 -0
  133. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/compaction_pipeline.py +0 -0
  134. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/compactor.py +0 -0
  135. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/composite_store.py +0 -0
  136. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/conversation_store.py +0 -0
  137. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/embedding_provider.py +0 -0
  138. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/embedding_tag_generator.py +0 -0
  139. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/engine_utils.py +0 -0
  140. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/fact_query.py +0 -0
  141. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/fts_preprocessor.py +0 -0
  142. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/hint_builder.py +0 -0
  143. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/llm_utils.py +0 -0
  144. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/math_utils.py +0 -0
  145. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/model_catalog.py +0 -0
  146. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/monitor.py +0 -0
  147. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/paging_manager.py +0 -0
  148. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/protocols.py +0 -0
  149. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/provider_adapters.py +0 -0
  150. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/quote_search.py +0 -0
  151. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/retrieval_assembler.py +0 -0
  152. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/retrieval_scoring.py +0 -0
  153. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/retriever.py +0 -0
  154. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/search_engine.py +0 -0
  155. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/segmenter.py +0 -0
  156. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/semantic_search.py +0 -0
  157. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/store.py +0 -0
  158. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/tag_canonicalizer.py +0 -0
  159. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/tag_consolidator.py +0 -0
  160. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/tag_generator.py +0 -0
  161. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/tag_scoring.py +0 -0
  162. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/tag_splitter.py +0 -0
  163. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/tagging_pipeline.py +0 -0
  164. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/telemetry.py +0 -0
  165. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/temporal_resolver.py +0 -0
  166. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/tool_loop.py +0 -0
  167. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/tool_query.py +0 -0
  168. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/core/turn_tag_index.py +0 -0
  169. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/data/anthropic-tokenizer/tokenizer.json +0 -0
  170. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/engine.py +0 -0
  171. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/ingest/__init__.py +0 -0
  172. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/ingest/curator.py +0 -0
  173. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/ingest/date_resolver.py +0 -0
  174. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/ingest/parsers.py +0 -0
  175. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/ingest/supersession.py +0 -0
  176. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/mcp/__init__.py +0 -0
  177. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/mcp/server.py +0 -0
  178. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/model_limits.py +0 -0
  179. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/openclaw/virtual-context.mjs +0 -0
  180. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/patterns.py +0 -0
  181. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/presets/__init__.py +0 -0
  182. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/presets/agentic.py +0 -0
  183. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/presets/base.py +0 -0
  184. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/presets/coding.py +0 -0
  185. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/providers/__init__.py +0 -0
  186. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/providers/anthropic.py +0 -0
  187. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/providers/base.py +0 -0
  188. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/providers/generic_openai.py +0 -0
  189. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/providers/ollama_native.py +0 -0
  190. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/__init__.py +0 -0
  191. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/_envelope.py +0 -0
  192. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/dashboard.html +0 -0
  193. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/dashboard.py +0 -0
  194. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/formats.py +0 -0
  195. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/helpers.py +0 -0
  196. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/media.py +0 -0
  197. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/message_filter.py +0 -0
  198. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/multi.py +0 -0
  199. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/registry.py +0 -0
  200. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/session_cache.py +0 -0
  201. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/session_state.py +0 -0
  202. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/state.py +0 -0
  203. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/static/android-chrome-192x192.png +0 -0
  204. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/static/android-chrome-512x512.png +0 -0
  205. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/static/apple-touch-icon.png +0 -0
  206. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/static/favicon-16x16.png +0 -0
  207. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/static/favicon-32x32.png +0 -0
  208. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/static/favicon.ico +0 -0
  209. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/static/site.webmanifest +0 -0
  210. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/tool_output_interceptor.py +0 -0
  211. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/proxy/vcattach.py +0 -0
  212. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/storage/__init__.py +0 -0
  213. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/storage/falkordb.py +0 -0
  214. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/storage/filesystem.py +0 -0
  215. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/storage/helpers.py +0 -0
  216. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/storage/neo4j.py +0 -0
  217. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/storage/noop_fact_link_store.py +0 -0
  218. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/storage/postgres.py +0 -0
  219. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/storage/sqlite.py +0 -0
  220. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/token_counter.py +0 -0
  221. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/__init__.py +0 -0
  222. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/app.py +0 -0
  223. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/chat.tcss +0 -0
  224. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/chat_provider.py +0 -0
  225. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/headless.py +0 -0
  226. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/modals/__init__.py +0 -0
  227. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/modals/turn_inspector.py +0 -0
  228. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/state.py +0 -0
  229. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/widgets/__init__.py +0 -0
  230. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/widgets/budget_bar.py +0 -0
  231. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/widgets/chat_view.py +0 -0
  232. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/widgets/input_box.py +0 -0
  233. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/widgets/tag_panel.py +0 -0
  234. {virtual_context-0.3.1 → virtual_context-0.3.2}/virtual_context/tui/widgets/turn_list.py +0 -0
@@ -0,0 +1,583 @@
1
+ Metadata-Version: 2.4
2
+ Name: virtual-context
3
+ Version: 0.3.2
4
+ Summary: OS-style virtual memory for LLM session context management
5
+ Project-URL: Homepage, https://virtual-context.com
6
+ Project-URL: Repository, https://github.com/virtual-context/virtual-context
7
+ Project-URL: Documentation, https://virtual-context.com/docs
8
+ Author: Y. Ahmed Kidwai
9
+ License-Expression: AGPL-3.0-or-later
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Requires-Python: >=3.11
16
+ Requires-Dist: anthropic>=0.40
17
+ Requires-Dist: dateparser>=1.2
18
+ Requires-Dist: fastapi>=0.115
19
+ Requires-Dist: httpx[http2]>=0.27
20
+ Requires-Dist: mcp>=1.0
21
+ Requires-Dist: openai>=1.50
22
+ Requires-Dist: pillow>=10.0
23
+ Requires-Dist: pyyaml>=6.0
24
+ Requires-Dist: rich>=13.0
25
+ Requires-Dist: sentence-transformers>=3.0
26
+ Requires-Dist: textual>=3.0
27
+ Requires-Dist: tiktoken>=0.7
28
+ Requires-Dist: torch>=2.0
29
+ Requires-Dist: uvicorn>=0.30
30
+ Provides-Extra: all
31
+ Requires-Dist: psycopg[binary]>=3.1; extra == 'all'
32
+ Requires-Dist: redis>=5.0; extra == 'all'
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest-timeout>=2.3; extra == 'dev'
35
+ Requires-Dist: pytest-xdist>=3.5; extra == 'dev'
36
+ Requires-Dist: pytest>=8.0; extra == 'dev'
37
+ Requires-Dist: ruff>=0.8; extra == 'dev'
38
+ Provides-Extra: falkordb
39
+ Requires-Dist: falkordb>=1.0; extra == 'falkordb'
40
+ Provides-Extra: neo4j
41
+ Requires-Dist: neo4j>=5.0; extra == 'neo4j'
42
+ Provides-Extra: postgres
43
+ Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
44
+ Provides-Extra: redis
45
+ Requires-Dist: redis>=5.0; extra == 'redis'
46
+ Description-Content-Type: text/markdown
47
+
48
+ <!-- [![PyPI](https://img.shields.io/pypi/v/virtual-context.svg)](https://pypi.org/project/virtual-context/) -->
49
+ <!-- [![Python](https://img.shields.io/pypi/pyversions/virtual-context.svg)](https://pypi.org/project/virtual-context/) -->
50
+ <!-- [![Downloads](https://img.shields.io/pypi/dm/virtual-context.svg)](https://pypistats.org/packages/virtual-context) -->
51
+ <!-- [![License](https://img.shields.io/badge/license-AGPL--3.0-blue.svg)](https://github.com/yursilkidwai/virtual-context/blob/main/LICENSE) -->
52
+ [![Discord](https://img.shields.io/badge/Discord-Chat%20with%20us-5865F2?logo=discord&logoColor=white)](https://discord.gg/YxDHKEZz)
53
+ [![Twitter](https://img.shields.io/badge/Twitter-Follow-1DA1F2?logo=x&logoColor=white)](https://x.com/virtualctx)
54
+
55
+ <p align="center">
56
+ <a href="assets/dashboard.png">
57
+ <img src="assets/dashboard.png" alt="virtual-context dashboard" width="800">
58
+ </a>
59
+ </p>
60
+ <p align="center"><sub>virtual-context cloud: running 3 million virtual token window at 80k actual tokens</sub></p>
61
+
62
+ # virtual-context
63
+
64
+ **100x your agent's context by virtualizing it. Better reasoning. Persistent memory. Shared across platforms. Lower costs.**
65
+
66
+ *95% accuracy vs 33% baseline on the same model, at half the cost. [See benchmark →](#benchmark-results)*
67
+
68
+ Your client sets `contextWindow: 20000000` (20 million). Your model's real window is 200K. virtual-context sits between them and makes it work, the same way your OS lets a process address more memory than physically exists. The client sends its full conversation history. VC compresses, indexes, and pages. The model sees a dense 60K window where every token is signal.
69
+
70
+ Virtualizing the context window has many advantages:
71
+
72
+ - **Compression**: Topic-level summarization with structured fact extraction. A 937K-token payload collapses to ~65K. Everything is stored, indexed, and recoverable at full fidelity.
73
+ - **Memory**: Your agent recalls what the user said at turn 12 when it reaches turn 1000. Facts, preferences, and decisions persist across the full conversation, not just what fits in the raw window.
74
+ - **Reasoning quality**: A curated 60K window of dense signal produces measurably better answers than a raw 200K window full of noise. The model reasons over what matters, not over everything.
75
+ - **Cost**: Smaller payloads, fewer tokens billed. A conversation running at a 1M-token virtual window regularly produces 60-90K actual payloads, a fraction of the raw cost. The payload is organized to maximize prompt cache hits, so even compressed conversations achieve significant caching in most cases.
76
+ - **Collaboration**: VCATTACH lets agents share memory across platforms and sessions. Custom agents, local tools, and API clients can all work from the same context. Multiple agents collaborate through shared memory. Conversations survive client restarts, platform switches, and session boundaries.
77
+
78
+ This is what makes virtual-context fundamentally different from memory systems that bolt a vector database onto your LLM. Those systems are *additive*: they retrieve chunks and compete for the context window your agent is working in right now. They do nothing to evict or curate what's already there.
79
+
80
+ virtual-context *manages* the window itself: compressing by topic, extracting structured facts, paging in what's needed, and paging out what's not. The client thinks it has 20M tokens. The model sees 60K of curated signal. Nothing is lost. Everything is addressable, at varying levels of compression.
81
+
82
+ ```
83
+ Layer 0: Raw conversation turns (active memory, in the context window)
84
+ Layer 1: Segment summaries + Facts per tag (compressed pages, per-topic summaries)
85
+ Layer 2: Tag summaries via greedy set cover (working set descriptors, bird's-eye view)
86
+ ```
87
+
88
+ **[Full documentation →](https://virtual-context.com/docs/)** including [architecture and pipeline](https://virtual-context.com/docs/architecture/), [features deep dive](https://virtual-context.com/docs/capabilities/), [proxy internals](https://virtual-context.com/docs/proxy/), [design decisions](https://virtual-context.com/docs/design/), and [user commands](https://virtual-context.com/docs/vcattach/).
89
+
90
+ ## Cloud Offering
91
+
92
+ [https://virtual-context.com](https://virtual-context.com) is the fastest way to get going. Sign up and change your base-url. Statistics, visibility into the context window, and cost savings reports included.
93
+
94
+ ## Install
95
+
96
+ ```bash
97
+ pip install virtual-context
98
+ ```
99
+
100
+ Python 3.11+, all core dependencies in the base install.
101
+
102
+ Optional storage backends: `pip install virtual-context[postgres]`, `[neo4j]`, or `[falkordb]`.
103
+
104
+ ## Integration
105
+
106
+ virtual-context runs as a local HTTP proxy between your client and the upstream LLM API. Point your client at `localhost:5757` instead of the upstream. The proxy handles everything transparently: tagging, retrieval, history filtering, compaction, tool interception. Auto-detects Anthropic, OpenAI (Chat + Codex/Responses), and Gemini request formats.
107
+
108
+ ```bash
109
+ virtual-context proxy --upstream https://api.anthropic.com
110
+ # OR
111
+ virtual-context proxy --upstream https://api.openai.com
112
+ # OR
113
+ virtual-context proxy --upstream https://generativelanguage.googleapis.com
114
+ ```
115
+
116
+ No config file needed for basic usage. For customization:
117
+
118
+ ```bash
119
+ cp virtual-context.yaml.example virtual-context.yaml
120
+ virtual-context -c virtual-context.yaml proxy
121
+ ```
122
+
123
+ ### Claude Code
124
+
125
+ Point Claude Code at the proxy. Either set the environment variable:
126
+
127
+ ```bash
128
+ export ANTHROPIC_BASE_URL=http://127.0.0.1:5757
129
+ ```
130
+
131
+ Or add it to your shell profile (`~/.bashrc`, `~/.zshrc`) to make it permanent:
132
+
133
+ ```bash
134
+ alias claudevc='ANTHROPIC_BASE_URL=http://127.0.0.1:5757 claude'
135
+ ```
136
+
137
+ Claude Code's tool chains (file reads, searches, command output) are automatically compressed. A 937K-token payload with 52 tool chains collapses to ~65K. When Claude Code truncates history to manage its own context window, virtual-context detects the truncation and recovers stored context transparently.
138
+
139
+ ### OpenClaw
140
+
141
+ Set these to allow OpenClaw to maintain large context windows from a client perspective:
142
+
143
+ ```
144
+ // 1. History limits (the real bottleneck most users will hit)
145
+ // channels.<provider> (e.g. channels.telegram)
146
+ "historyLimit": 99999,
147
+ "dmHistoryLimit": 99999
148
+
149
+ // global fallback
150
+ "messages": { "groupChat": { "historyLimit": 99999 } }
151
+
152
+ // 2. Model context window: must be on the provider in the per-agent models.json, with
153
+ // explicit model entries:
154
+ "anthropic": {
155
+ "baseUrl": "https://anthropic.virtual-context.com?vckey=...",
156
+ "api": "anthropic-messages",
157
+ "models": [
158
+ {
159
+ "id": "claude-opus-4-6",
160
+ "contextWindow": 2000000, // Note this is 2M
161
+ ...
162
+ }
163
+ ]
164
+ }
165
+ ```
166
+
167
+ Just setting baseUrl alone isn't enough. Without model entries, it falls back to pi-ai's
168
+ hardcoded 200K. And models.overrides in the global config is display only; it doesn't affect
169
+ actual windowing.
170
+
171
+ ```
172
+ 3. Context pruning: disable it so the proxy controls windowing:
173
+ "agents": {
174
+ "defaults": {
175
+ "contextPruning": { "mode": "off" },
176
+ "contextTokens": 2000000 // Note this is 2M
177
+ }
178
+ }
179
+
180
+ 4. Session idle timeout: prevent OpenClaw from resetting sessions too early.
181
+ Without this, sessions reset after 12 hours by default, wiping the client-side
182
+ history before VC can manage it:
183
+ "session": {
184
+ "resetByType": {
185
+ "group": { "idleMinutes": 2880 } // 48 hours (default is 720 / 12h)
186
+ }
187
+ }
188
+ ```
189
+
190
+ A dedicated [OpenClaw plugin](https://github.com/openclaw/openclaw/pull/12082) is also in progress, using lifecycle hooks for sync retrieval (`message.pre`) and fire-and-forget compaction (`agent.post`).
191
+
192
+ ### Other Clients (Cursor, Continue, any OpenAI-compatible client)
193
+
194
+ Any client that lets you set a base URL works. Point it at `http://127.0.0.1:5757` (Anthropic format) or `http://127.0.0.1:5757/v1` (OpenAI format):
195
+
196
+ ```python
197
+ # Python (anthropic SDK)
198
+ import anthropic
199
+ client = anthropic.Anthropic(base_url="http://127.0.0.1:5757")
200
+
201
+ # Python (openai SDK)
202
+ from openai import OpenAI
203
+ client = OpenAI(base_url="http://127.0.0.1:5757/v1")
204
+ ```
205
+
206
+ **Multi-instance mode** runs multiple providers on different ports in one process:
207
+
208
+ ```yaml
209
+ proxy:
210
+ instances:
211
+ - port: 5757
212
+ upstream: https://api.anthropic.com
213
+ label: anthropic
214
+ - port: 5758
215
+ upstream: https://api.openai.com
216
+ label: openai
217
+ - port: 5760
218
+ upstream: https://generativelanguage.googleapis.com
219
+ label: gemini
220
+ ```
221
+
222
+ **Daemon mode** runs the proxy as a background service:
223
+
224
+ ```bash
225
+ virtual-context daemon install --upstream https://api.anthropic.com
226
+ virtual-context onboard --wizard --install-daemon
227
+ ```
228
+
229
+ Daemon lifecycle: `daemon status | start | stop | restart | uninstall`
230
+
231
+ Full setup docs (macOS `launchd`, Linux `systemd --user`, Windows Task Scheduler): [`docs/install.md`](docs/install.md)
232
+
233
+ ### Python SDK
234
+
235
+ Two function calls wrap your existing LLM pipeline:
236
+
237
+ ```python
238
+ from virtual_context import VirtualContextEngine, Message
239
+
240
+ engine = VirtualContextEngine(config_path="./virtual-context.yaml")
241
+
242
+ # BEFORE sending to LLM: retrieve relevant stored context
243
+ assembled = engine.on_message_inbound(
244
+ message="What was the Henninger filing deadline?",
245
+ conversation_history=messages,
246
+ )
247
+ # assembled.prepend_text → enriched system prompt with retrieved summaries
248
+ # assembled.matched_tags → ["legal", "filing"]
249
+
250
+ # AFTER LLM responds: tag, index, compact if needed
251
+ report = engine.on_turn_complete(messages)
252
+ if report:
253
+ print(f"Compacted {report.segments_compacted} segments, freed {report.tokens_freed:,} tokens")
254
+ ```
255
+
256
+ ### MCP Server
257
+
258
+ virtual-context also exposes an MCP server for Claude Desktop, Cursor, or any MCP-compatible client. The model calls tools like `recall_all`, `remember_when`, `find_quote`, `query_facts`, `expand_topic`, and `collapse_topic` internally to build robust memory. These are not user-facing commands; the model decides when to use them based on what the conversation needs.
259
+
260
+ ## What It Does
261
+
262
+ ### Automatic Topic Tagging
263
+
264
+ There are no predefined domains to configure. An LLM tagger reads each turn and generates semantic tags (`database`, `auth`, `fitness`, `legal`) that naturally converge over the session. A vocabulary feedback loop passes known tags back into the tagger prompt, so it reuses `storage` instead of inventing `data-persistence` or `file-management`. When synonyms slip through (`db` vs `database`), a canonicalizer detects aliases via edit distance and normalizes them automatically.
265
+
266
+ When a tag appears on too many turns and loses discriminative power, virtual-context detects this and automatically splits it into narrower sub-tags. In a 143-turn OpenClaw session, `reservation-request` (43 turns, 30%) was split into `reservation-platform-troubleshooting`, `reservation-availability-search`, `reservation-browser-access`, and `reservation-general`. The vocabulary evolves toward maximum precision without manual curation.
267
+
268
+ ### Structured Fact Extraction
269
+
270
+ Summaries compress information but inevitably lose specific details. When the user says "I run 5K every morning" at turn 14, a summary might retain "runs regularly" but drop the exact distance and timing.
271
+
272
+ virtual-context extracts structured facts during compaction: subject, verb, object, fact type (`preference`, `biographical`, `decision`, `plan`, `routine`, `medical`, `financial`), temporal status (`active`, `completed`, `planned`, `abandoned`, `recurring`), session provenance, and source turn numbers. Facts are queryable by any combination of these fields.
273
+
274
+ When new information contradicts a stored fact ("I moved from NYC to LA"), the supersession checker detects the conflict and marks the old fact as superseded. Facts have typed relationships (`SUPERSEDES`, `CAUSED_BY`, `PART_OF`, `CONTRADICTS`, `SAME_AS`, `RELATED_TO`) that are automatically detected and traversed during queries.
275
+
276
+ ### Tool Chain Compression
277
+
278
+ Agent conversations are dominated by tool calls. A coding session with 50 tool rounds might have 900K tokens of tool output but only 60K of actual conversation.
279
+
280
+ virtual-context collapses entire tool chains into compact stubs:
281
+
282
+ ```
283
+ Before (3 messages, ~18K tokens):
284
+ assistant: [tool_use: Read file.py]
285
+ user: [tool_result: <full 500-line file contents>]
286
+ assistant: "The file has a bug on line 42..."
287
+
288
+ After (2 messages, ~200 tokens):
289
+ user: [compacted turn: Read(file.py)]
290
+ assistant: "The file has a bug on line 42..."
291
+ ```
292
+
293
+ Handles all four provider formats (Anthropic, OpenAI Chat, OpenAI Responses, Gemini). Full raw tool output is stored durably and recoverable on demand. Past a configurable age threshold, stubs are dropped entirely (the segment summaries already cover that content).
294
+
295
+ ### Media Compression
296
+
297
+ Base64 images in API payloads are enormous: a single screenshot is 300-500KB of base64. Providers process images through vision encoders with fixed token costs based on dimensions, not base64 string length, but payload size still matters for bandwidth, latency, and TTFB. virtual-context compresses images on first sight: a 391KB screenshot becomes ~40KB, cutting payload size by ~90%. Originals are stored to disk for recovery. This runs on both passthrough and active paths, so even conversations that haven't triggered compaction benefit.
298
+
299
+ ### Virtual Memory Paging
300
+
301
+ RAG retrieves content and appends it to the context window. It never frees space from what's already there. virtual-context treats the context window as managed memory with bidirectional paging:
302
+
303
+ ```
304
+ Tag summaries <-------> Segment summaries <-------> Full stored text
305
+ ^ ^ ^
306
+ collapse default expand
307
+ (~200t) (~2,000t) (~8,000t+)
308
+ ```
309
+
310
+ When the model needs more detail on a topic, it expands that topic from summary to full stored text. When budget pressure hits, cold topics are automatically collapsed. The working set persists across turns, so expansion decisions are stateful.
311
+
312
+ ### Cross-Vocabulary Retrieval
313
+
314
+ Users don't use the same words every time. "Materialized views for feed performance" at turn 46 might be recalled as "that caching trick for the feed" at turn 71. Pure tag overlap finds nothing.
315
+
316
+ virtual-context uses 3-signal retrieval scoring via Reciprocal Rank Fusion: IDF-weighted tag overlap, BM25 keyword search on summaries, and embedding cosine similarity. Related tags generated at both write time and query time bridge vocabulary gaps. When tag-based retrieval misses entirely, full-text and semantic search across stored conversation text provide a fallback.
317
+
318
+ ### Time-Scoped Recall
319
+
320
+ Queries like "going back to the very beginning, what were the key decisions?" or "between June and July, what changed?" reference a position in time, not just a topic. virtual-context combines semantic query matching with structured time ranges. Date math is backend-resolved, not LLM-resolved, so results are deterministic. Session dates propagate through the entire pipeline: every segment knows when it happened, and temporal ordering is always accurate.
321
+
322
+ ### Configurable Context Ceiling
323
+
324
+ Most teams set `context_window` to whatever the model supports and let it fill up. This is expensive and degrades quality. Research on "lost in the middle" shows that LLM attention degrades in long contexts: facts buried in 200K tokens of raw history are missed more often than the same facts concentrated in a managed window.
325
+
326
+ ```yaml
327
+ context_window: 60000 # run a 200K model at 60K
328
+ compaction:
329
+ soft_threshold: 0.70
330
+ hard_threshold: 0.90
331
+ ```
332
+
333
+ A 200K-capable model running at 60K uses ~70% fewer input tokens per request. The model's attention is concentrated on curated, high-signal context rather than spread across mostly-stale history.
334
+
335
+ ### Store-Backed Recovery
336
+
337
+ Clients (Claude Code, OpenClaw) sometimes truncate conversation history to manage their own context windows. virtual-context detects the truncation and recovers from its durable store: chain snapshots, recent raw turns, sanitized and restored transparently. The payload that reaches the LLM contains the recovered context as if it had never been truncated.
338
+
339
+ ## User Commands
340
+
341
+ Type these as normal messages in any client connected through the proxy. Case-insensitive. The proxy intercepts them before they reach the LLM, so no tokens are consumed.
342
+
343
+ | Command | What it does |
344
+ |---|---|
345
+ | `VCATTACH <label\|id>` | Reattach to another conversation by label or UUID |
346
+ | `VCLABEL <name>` | Set label on current conversation (no arg = show current) |
347
+ | `VCSTATUS` | Show conversation ID, label, turns, segments, working set, active tags |
348
+ | `VCRECALL <query>` | Search stored context, promote matching tags to working set for next turn |
349
+ | `VCCOMPACT` | Force compaction of uncompacted turns |
350
+ | `VCLIST` | List all conversations with labels and turn counts |
351
+ | `VCFORGET <tag>` | Delete segments and summaries for a specific tag |
352
+
353
+ ### VCATTACH: Shared Memory Across Platforms
354
+
355
+ Every conversation gets a stable identity derived from the system prompt hash and conversation markers embedded in assistant responses. This identity persists across restarts, deploys, and client changes.
356
+
357
+ When identity detaches (system prompt changes, client truncation loses the marker, a deploy produces a different hash), type `VCATTACH <label>` to reconnect to the original conversation with all segments, facts, and tags intact.
358
+
359
+ **Cross-platform shared memory.** Build up deep context in Claude Code (architecture decisions, code patterns, debugging history), then type `VCATTACH code-project` in a Telegram conversation with a different model. Both clients now share the same conversation identity: messages from either platform enrich the same compacted knowledge base. This isn't document sharing or chat mirroring. It's shared memory across platforms and models.
360
+
361
+ **Multi-agent collaboration.** Two agents (or two humans using different clients) can work on the same problem space simultaneously. Agent A researches in Claude Code, compacting findings. Agent B drafts a proposal in Telegram, pulling from the same segments. Each agent's contributions are compacted into the shared store. The virtual context IS the shared workspace.
362
+
363
+ **Conversation merging.** Two conversations about the same topic? Pick the one with richer context and `VCATTACH` the other to it. The old conversation is deleted; the target keeps all its compacted data. The alias table is persistent, so stale markers follow the alias instead of creating orphans.
364
+
365
+ ## Virtual-Context vs RAG vs Compaction
366
+
367
+ These approaches are complementary. RAG, other memory systems, and compaction can all run alongside virtual-context.
368
+
369
+ | | RAG | Compaction-only | virtual-context |
370
+ |---|---|---|---|
371
+ | **Primary mechanism** | Query-time retrieval by embedding similarity | Summarize old history to fit window | Tagged memory + retrieval + compaction + paging tools |
372
+ | **What gets kept** | External documents + recent raw chat | Summaries of old turns + recent raw chat | Multi-layer memory (raw turns, segment summaries, tag summaries) |
373
+ | **Specific fact lookup** | Depends on embedding/query phrasing alignment | Lossy after summarization | Structured fact queries + full-text search + summary drill-down |
374
+ | **Broad overview** | Weak unless special orchestration | Can summarize, but often generic | All topic summaries loaded within budget |
375
+ | **Time-scoped recall** | Custom logic outside core RAG | Requires date fidelity in summaries | Backend-resolved time ranges with session date propagation |
376
+ | **Vocabulary mismatch tolerance** | Embedding-dependent | Low | 3-signal RRF fusion + related-tag expansion + semantic search fallback |
377
+ | **Context budget control** | Append retrieved chunks | Compression with limited rehydration | Explicit paging: expand/collapse topics with bounded assembly |
378
+ | **Cost at scale** | Grows with corpus size | Grows with conversation length | Configurable ceiling: run a 200K model at 30K |
379
+ | **Best fit** | Knowledge/doc retrieval | Simple long-chat cost reduction | Long-running agent memory with mixed query types |
380
+
381
+ ## Proxy Features
382
+
383
+ The proxy includes a [live dashboard](#live-dashboard) at `http://localhost:5757/dashboard` with request grid, turn inspector, session stats, telemetry, and SSE live updates.
384
+
385
+ - **Conversation continuity** via invisible markers in assistant responses, with stable identity derived from system prompt hash
386
+ - **Redis session cache** for lossless restarts across container deploys (falls back gracefully if Redis is unavailable)
387
+ - **Four-format support** auto-detected per request (Anthropic, OpenAI Chat, OpenAI Responses, Gemini)
388
+ - **History ingestion** bootstraps the tag index from existing conversation on the first request
389
+ - **Streaming with zero added latency** (SSE forwarded byte-for-byte, text accumulated in background)
390
+ - **Error-resilient** (engine failures fall back to unmodified passthrough; bloat fallback reverts to original payload)
391
+ - **Envelope stripping** extracts sender identity and timestamps from metadata blocks (group chat participants appear as real names)
392
+ - **Image-aware token counting** using Anthropic formula, not raw base64 tokenization
393
+ - **Per-port config** for multi-instance setups with isolated engines and storage
394
+ - **Telemetry** on every LLM call: token counts, cost, timing across five components (`compactor`, `tagger`, `tool_loop`, `fact_curator`, `proxy_upstream`)
395
+
396
+ ## CLI
397
+
398
+ ```bash
399
+ virtual-context proxy -u https://api.anthropic.com # start proxy
400
+ virtual-context status # tag stats and token usage
401
+ virtual-context tags # list all tags
402
+ virtual-context domains # tags with turn counts and summaries
403
+ virtual-context recall auth # retrieve stored summaries for a tag
404
+ virtual-context retrieve -m "What about auth?" # tag + retrieve (JSON)
405
+ virtual-context transform -m "What about auth?" # tag + retrieve + assemble
406
+ virtual-context compact -i msgs.json # manual compaction
407
+ virtual-context aliases list|suggest|add # tag alias management
408
+ virtual-context init coding # create config from preset
409
+ virtual-context onboard [--wizard] # guided setup
410
+ virtual-context daemon install|status|start|stop # background service
411
+ virtual-context config validate # check config syntax
412
+ virtual-context telemetry [--verbose] [--json] # cost, tokens, timing
413
+ virtual-context chat [--headless] [--replay ...] # interactive TUI or headless
414
+ ```
415
+
416
+ ## Interactive Chat (TUI)
417
+
418
+ ```bash
419
+ virtual-context chat --config virtual-context.yaml
420
+ ```
421
+
422
+ Terminal chat interface with live context visualization: tag panel with activity levels, real-time budget bar, turn inspector (Ctrl+I), manual compaction (`/compact` or Ctrl+K), session export (Ctrl+S). Headless mode (`--headless --replay prompts.txt`) for automated testing and regression validation.
423
+
424
+ ## Stress-Tested
425
+
426
+ Validated against adversarial 100-turn conversations with deliberately overlapping domains, vocabulary mismatches, ambiguous callbacks, and cross-domain synthesis queries, using a 3,000-token context window with Claude Haiku. 89% pass rate on 28 deliberately adversarial prompts. Tag vocabulary stabilizes within 10-15 turns via the feedback loop.
427
+
428
+ Also validated in production with OpenClaw (Telegram) handling real multi-topic conversations: tool chain preservation across 90-message conversations (52 messages filtered to 27 without breaking a single tool dependency), live embedding matching against 40+ tag vocabularies, and single-pass history ingestion of 43 pre-existing turns.
429
+
430
+ ## Benchmark Results
431
+
432
+ ### LongMemEval (100 Questions)
433
+
434
+ 100 random questions from [LongMemEval-500](https://github.com/xiaowu0162/LongMemEval) (5 batches x 20, seeds 42/99/777/1234/2025).
435
+
436
+ **Configuration:**
437
+ - **VC:** MiMo-V2-Flash (ingestion) + Claude Sonnet 4.5 (reader) + Gemini 3 Pro Preview (judge)
438
+ - **Baseline:** Claude Sonnet 4.5 with full conversation history (~118K tokens) + Gemini 3 Pro Preview (judge)
439
+
440
+ | Metric | VC | Baseline |
441
+ |--------|-----|----------|
442
+ | Accuracy | 95/100 (95%) | 33/100 (33%) |
443
+ | Avg Tokens/Question | 52,347 | 117,582 |
444
+ | Avg Cost/Question | $0.16 | $0.36 |
445
+ | Total Cost | $15.99 | $35.56 |
446
+ | Token Reduction | 2.2x fewer | -- |
447
+
448
+ #### Accuracy by Question Type
449
+
450
+ | Category | Count | VC | Baseline |
451
+ |----------|-------|----|----------|
452
+ | knowledge-update | 17 | 100.0% (17/17) | 29.4% (5/17) |
453
+ | multi-session | 26 | 88.5% (23/26) | 15.4% (4/26) |
454
+ | temporal-reasoning | 28 | 92.9% (26/28) | 32.1% (9/28) |
455
+ | single-session-user | 13 | 100.0% (13/13) | 46.2% (6/13) |
456
+ | single-session-assistant | 11 | 100.0% (11/11) | 72.7% (8/11) |
457
+ | single-session-preference | 5 | 100.0% (5/5) | 20.0% (1/5) |
458
+
459
+ <details>
460
+ <summary>Click to expand full results table (100 questions)</summary>
461
+
462
+ | ID | Type | BL | BL Tokens | BL Cost | VC | VC Tokens | VC Cost |
463
+ |----|------|-----|-----------|---------|-----|-----------|---------|
464
+ | `07741c44` | knowledge-update | FAIL | 116,404 | $0.35 | pass | 49,721 | $0.15 |
465
+ | `0977f2af` | knowledge-update | FAIL | 117,359 | $0.35 | pass | 49,734 | $0.15 |
466
+ | `0ddfec37` | knowledge-update | FAIL | 115,848 | $0.35 | pass | 43,780 | $0.13 |
467
+ | `2133c1b5_abs` | knowledge-update | pass | 116,186 | $0.36 | pass | 56,533 | $0.17 |
468
+ | `2698e78f_abs` | knowledge-update | FAIL | 118,841 | $0.36 | pass | 36,039 | $0.11 |
469
+ | `3ba21379` | knowledge-update | FAIL | 116,604 | $0.35 | pass | 46,034 | $0.14 |
470
+ | `4b24c848` | knowledge-update | pass | 117,107 | $0.35 | pass | 32,494 | $0.10 |
471
+ | `4d6b87c8` | knowledge-update | FAIL | 115,104 | $0.35 | pass | 47,262 | $0.14 |
472
+ | `50635ada` | knowledge-update | FAIL | 118,682 | $0.36 | pass | 41,677 | $0.13 |
473
+ | `5a4f22c0` | knowledge-update | pass | 118,775 | $0.36 | pass | 35,437 | $0.11 |
474
+ | `6071bd76` | knowledge-update | FAIL | 117,904 | $0.36 | pass | 36,618 | $0.11 |
475
+ | `6aeb4375` | knowledge-update | pass | 115,001 | $0.35 | pass | 38,984 | $0.12 |
476
+ | `89941a94` | knowledge-update | FAIL | 117,038 | $0.35 | pass | 45,347 | $0.14 |
477
+ | `8fb83627` | knowledge-update | pass | 115,488 | $0.35 | pass | 35,041 | $0.11 |
478
+ | `a1eacc2a` | knowledge-update | FAIL | 117,513 | $0.35 | pass | 46,401 | $0.14 |
479
+ | `cf22b7bf` | knowledge-update | FAIL | 115,784 | $0.35 | pass | 49,002 | $0.15 |
480
+ | `ed4ddc30` | knowledge-update | FAIL | 118,045 | $0.36 | pass | 37,708 | $0.11 |
481
+ | `099778bb` | multi-session | FAIL | 118,622 | $0.36 | pass | 33,375 | $0.10 |
482
+ | `09ba9854` | multi-session | FAIL | 115,128 | $0.35 | FAIL | 36,120 | $0.11 |
483
+ | `0ea62687` | multi-session | FAIL | 116,840 | $0.36 | pass | 36,910 | $0.11 |
484
+ | `21d02d0d` | multi-session | FAIL | 119,667 | $0.36 | pass | 44,069 | $0.13 |
485
+ | `36b9f61e` | multi-session | FAIL | 116,713 | $0.35 | pass | 42,919 | $0.13 |
486
+ | `3fe836c9` | multi-session | FAIL | 117,954 | $0.35 | pass | 45,463 | $0.14 |
487
+ | `46a3abf7` | multi-session | FAIL | 117,783 | $0.35 | pass | 132,933 | $0.40 |
488
+ | `6456829e_abs` | multi-session | FAIL | 117,467 | $0.35 | pass | 42,898 | $0.13 |
489
+ | `681a1674` | multi-session | FAIL | 118,545 | $0.36 | pass | 62,141 | $0.19 |
490
+ | `720133ac` | multi-session | FAIL | 120,053 | $0.37 | pass | 50,205 | $0.15 |
491
+ | `7405e8b1` | multi-session | FAIL | 118,694 | $0.36 | pass | 50,989 | $0.16 |
492
+ | `88432d0a` | multi-session | FAIL | 118,401 | $0.36 | pass | 46,391 | $0.14 |
493
+ | `88432d0a_abs` | multi-session | pass | 119,275 | $0.36 | pass | 55,463 | $0.17 |
494
+ | `9d25d4e0` | multi-session | FAIL | 117,978 | $0.36 | pass | 83,295 | $0.25 |
495
+ | `a11281a2` | multi-session | FAIL | 119,807 | $0.36 | pass | 49,939 | $0.15 |
496
+ | `a346bb18` | multi-session | FAIL | 118,452 | $0.36 | pass | 44,404 | $0.14 |
497
+ | `a96c20ee` | multi-session | FAIL | 117,282 | $0.35 | pass | 42,068 | $0.13 |
498
+ | `bf659f65` | multi-session | FAIL | 114,781 | $0.35 | FAIL | 41,952 | $0.13 |
499
+ | `d682f1a2` | multi-session | FAIL | 117,856 | $0.35 | pass | 48,821 | $0.15 |
500
+ | `dd2973ad` | multi-session | pass | 117,351 | $0.36 | pass | 56,463 | $0.17 |
501
+ | `e56a43b9` | multi-session | pass | 119,177 | $0.36 | pass | 47,528 | $0.14 |
502
+ | `e6041065` | multi-session | FAIL | 117,316 | $0.35 | pass | 38,473 | $0.12 |
503
+ | `eeda8a6d` | multi-session | FAIL | 118,197 | $0.36 | pass | 45,726 | $0.14 |
504
+ | `ef66a6e5` | multi-session | FAIL | 116,328 | $0.35 | pass | 152,680 | $0.46 |
505
+ | `gpt4_372c3eed` | multi-session | pass | 117,552 | $0.36 | FAIL | 46,299 | $0.14 |
506
+ | `gpt4_d84a3211` | multi-session | FAIL | 116,459 | $0.35 | pass | 51,487 | $0.16 |
507
+ | `0db4c65d` | temporal-reasoning | FAIL | 115,780 | $0.35 | pass | 45,639 | $0.14 |
508
+ | `2ebe6c90` | temporal-reasoning | FAIL | 115,113 | $0.35 | pass | 39,883 | $0.12 |
509
+ | `6613b389` | temporal-reasoning | pass | 119,268 | $0.37 | pass | 41,228 | $0.13 |
510
+ | `a3045048` | temporal-reasoning | FAIL | 116,689 | $0.35 | pass | 47,120 | $0.14 |
511
+ | `b29f3365` | temporal-reasoning | FAIL | 118,078 | $0.36 | pass | 43,563 | $0.13 |
512
+ | `c8090214_abs` | temporal-reasoning | pass | 116,460 | $0.35 | pass | 79,046 | $0.24 |
513
+ | `cc6d1ec1` | temporal-reasoning | pass | 116,218 | $0.35 | pass | 47,747 | $0.15 |
514
+ | `eac54adc` | temporal-reasoning | FAIL | 119,492 | $0.36 | pass | 40,470 | $0.12 |
515
+ | `f0853d11` | temporal-reasoning | pass | 116,117 | $0.35 | pass | 46,903 | $0.14 |
516
+ | `gpt4_18c2b244` | temporal-reasoning | FAIL | 119,183 | $0.36 | pass | 53,922 | $0.17 |
517
+ | `gpt4_1a1dc16d` | temporal-reasoning | FAIL | 120,646 | $0.37 | pass | 52,119 | $0.16 |
518
+ | `gpt4_1e4a8aec` | temporal-reasoning | pass | 118,208 | $0.36 | pass | 48,286 | $0.15 |
519
+ | `gpt4_21adecb5` | temporal-reasoning | FAIL | 119,249 | $0.36 | pass | 125,864 | $0.38 |
520
+ | `gpt4_483dd43c` | temporal-reasoning | FAIL | 117,942 | $0.35 | pass | 43,327 | $0.13 |
521
+ | `gpt4_4929293b` | temporal-reasoning | FAIL | 118,774 | $0.37 | pass | 58,869 | $0.18 |
522
+ | `gpt4_4cd9eba1` | temporal-reasoning | pass | 119,611 | $0.36 | pass | 46,083 | $0.14 |
523
+ | `gpt4_5438fa52` | temporal-reasoning | FAIL | 114,753 | $0.35 | pass | 51,194 | $0.16 |
524
+ | `gpt4_65aabe59` | temporal-reasoning | FAIL | 115,392 | $0.35 | pass | 39,931 | $0.12 |
525
+ | `gpt4_70e84552` | temporal-reasoning | FAIL | 117,453 | $0.35 | pass | 42,109 | $0.13 |
526
+ | `gpt4_7ca326fa` | temporal-reasoning | FAIL | 116,432 | $0.35 | pass | 51,589 | $0.16 |
527
+ | `gpt4_7de946e7` | temporal-reasoning | pass | 117,096 | $0.35 | pass | 44,183 | $0.14 |
528
+ | `gpt4_8279ba02` | temporal-reasoning | FAIL | 115,780 | $0.35 | pass | 156,923 | $0.47 |
529
+ | `gpt4_88806d6e` | temporal-reasoning | FAIL | 119,052 | $0.36 | pass | 33,463 | $0.10 |
530
+ | `gpt4_98f46fc6` | temporal-reasoning | pass | 117,366 | $0.36 | pass | 58,524 | $0.18 |
531
+ | `gpt4_d6585ce9` | temporal-reasoning | FAIL | 115,862 | $0.35 | pass | 50,320 | $0.15 |
532
+ | `gpt4_d9af6064` | temporal-reasoning | pass | 116,298 | $0.35 | pass | 48,037 | $0.15 |
533
+ | `gpt4_f420262c` | temporal-reasoning | FAIL | 116,610 | $0.35 | FAIL | 134,691 | $0.41 |
534
+ | `gpt4_f420262d` | temporal-reasoning | FAIL | 118,803 | $0.36 | FAIL | 52,815 | $0.16 |
535
+ | `001be529` | ss-user | FAIL | 117,394 | $0.35 | pass | 40,375 | $0.12 |
536
+ | `15745da0` | ss-user | FAIL | 120,384 | $0.37 | pass | 53,318 | $0.16 |
537
+ | `19b5f2b3` | ss-user | pass | 115,688 | $0.35 | pass | 42,046 | $0.13 |
538
+ | `19b5f2b3_abs` | ss-user | pass | 116,214 | $0.35 | pass | 44,256 | $0.14 |
539
+ | `37d43f65` | ss-user | FAIL | 117,911 | $0.35 | pass | 72,955 | $0.22 |
540
+ | `4fd1909e` | ss-user | FAIL | 119,200 | $0.36 | pass | 50,759 | $0.15 |
541
+ | `577d4d32` | ss-user | pass | 116,583 | $0.35 | pass | 48,225 | $0.15 |
542
+ | `60d45044` | ss-user | FAIL | 119,224 | $0.36 | pass | 47,125 | $0.14 |
543
+ | `853b0a1d` | ss-user | FAIL | 116,684 | $0.35 | pass | 48,110 | $0.15 |
544
+ | `8e9d538c` | ss-user | pass | 118,317 | $0.36 | pass | 42,345 | $0.13 |
545
+ | `ad7109d1` | ss-user | FAIL | 114,263 | $0.34 | pass | 49,802 | $0.15 |
546
+ | `af8d2e46` | ss-user | pass | 114,690 | $0.35 | pass | 53,504 | $0.16 |
547
+ | `f4f1d8a4_abs` | ss-user | pass | 118,760 | $0.36 | pass | 46,426 | $0.14 |
548
+ | `0e5e2d1a` | ss-assistant | pass | 118,067 | $0.35 | pass | 45,569 | $0.14 |
549
+ | `1de5cff2` | ss-assistant | FAIL | 118,432 | $0.36 | pass | 45,809 | $0.14 |
550
+ | `28bcfaac` | ss-assistant | pass | 118,509 | $0.36 | pass | 44,713 | $0.14 |
551
+ | `41275add` | ss-assistant | FAIL | 118,490 | $0.36 | pass | 51,010 | $0.16 |
552
+ | `58470ed2` | ss-assistant | pass | 118,116 | $0.36 | pass | 80,240 | $0.25 |
553
+ | `6222b6eb` | ss-assistant | pass | 118,378 | $0.36 | pass | 41,408 | $0.13 |
554
+ | `8aef76bc` | ss-assistant | pass | 118,739 | $0.36 | pass | 32,131 | $0.10 |
555
+ | `ceb54acb` | ss-assistant | pass | 118,463 | $0.37 | pass | 45,166 | $0.14 |
556
+ | `dc439ea3` | ss-assistant | pass | 118,782 | $0.36 | pass | 57,967 | $0.18 |
557
+ | `e3fc4d6e` | ss-assistant | FAIL | 115,974 | $0.35 | pass | 51,285 | $0.16 |
558
+ | `f523d9fe` | ss-assistant | pass | 119,321 | $0.36 | pass | 58,638 | $0.18 |
559
+ | `1a1907b4` | ss-preference | FAIL | 117,865 | $0.35 | pass | 51,663 | $0.16 |
560
+ | `1da05512` | ss-preference | FAIL | 120,425 | $0.37 | pass | 54,796 | $0.17 |
561
+ | `b0479f84` | ss-preference | FAIL | 117,425 | $0.36 | pass | 48,987 | $0.15 |
562
+ | `b6025781` | ss-preference | FAIL | 119,376 | $0.36 | pass | 46,189 | $0.14 |
563
+ | `fca70973` | ss-preference | pass | 117,421 | $0.36 | pass | 59,228 | $0.19 |
564
+ | **Total** | **100** | **33** | **11,758,181** | **$35.56** | **95** | **5,234,716** | **$15.99** |
565
+
566
+ </details>
567
+
568
+ ## Development
569
+
570
+ ```bash
571
+ git clone https://github.com/virtual-context/virtual-context.git
572
+ cd virtual-context
573
+ python -m venv .venv && source .venv/bin/activate
574
+ pip install -e ".[dev]"
575
+ python -m pytest tests/ -v --ignore=tests/ollama # ~1500 unit tests
576
+ python -m pytest tests/ollama/ -v -m ollama # integration (requires Ollama)
577
+ ```
578
+
579
+ ## License
580
+
581
+ AGPL-3.0, Copyright Y. Ahmed Kidwai
582
+
583
+ For commercial licensing inquiries, contact: ahmed@kidw.ai