topos-node 1.2.7__tar.gz → 1.3.0__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 (569) hide show
  1. {topos_node-1.2.7/topos_node.egg-info → topos_node-1.3.0}/PKG-INFO +1 -1
  2. {topos_node-1.2.7 → topos_node-1.3.0}/pyproject.toml +8 -2
  3. {topos_node-1.2.7 → topos_node-1.3.0}/topos/__version__.py +2 -2
  4. topos_node-1.3.0/topos/api/conversation_context.py +142 -0
  5. topos_node-1.3.0/topos/api/facts_llm_config.py +63 -0
  6. topos_node-1.3.0/topos/api/local_mcp.py +119 -0
  7. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/signal.py +47 -1
  8. {topos_node-1.2.7 → topos_node-1.3.0}/topos/app.py +4 -0
  9. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/browser_activity_mapper.py +8 -0
  10. {topos_node-1.2.7 → topos_node-1.3.0}/topos/cli/commands.py +4 -0
  11. topos_node-1.3.0/topos/config/conversation_context_llm.py +106 -0
  12. topos_node-1.3.0/topos/config/facts_llm.py +128 -0
  13. {topos_node-1.2.7 → topos_node-1.3.0}/topos/config/settings.py +6 -0
  14. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/config.py +134 -0
  15. topos_node-1.3.0/topos/core/handlers/query.py +175 -0
  16. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/signal_features.py +62 -0
  17. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/generative_prompts.py +34 -0
  18. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/generative_response.py +4 -0
  19. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/ollama.py +138 -1
  20. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/usage_observation.py +2 -1
  21. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/catalog.py +13 -0
  22. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/__init__.py +3 -0
  23. topos_node-1.3.0/topos/enrichment/jobs/canonical/attention_triage_job.py +66 -0
  24. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/dimension_summary_job.py +13 -0
  25. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/fact_extraction_job.py +5 -1
  26. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/orchestrator.py +14 -3
  27. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/declared_mappings.py +55 -0
  28. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/facts/extract.py +12 -2
  29. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/facts/llm_extract.py +15 -10
  30. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/facts/reads.py +1 -0
  31. topos_node-1.3.0/topos/features/facts/verdicts.py +209 -0
  32. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/fit/evaluator.py +58 -4
  33. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/fit/opportunity_types.json +9 -0
  34. topos_node-1.3.0/topos/features/signal/conversation_context.py +145 -0
  35. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/intentions.json +40 -9
  36. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/time.json +16 -4
  37. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/extraction/artifact_router.py +21 -0
  38. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/extraction/rule_extractors.py +28 -2
  39. topos_node-1.3.0/topos/features/signal/typed_stores/aggregates.py +347 -0
  40. topos_node-1.3.0/topos/features/signal/typed_stores/commitments.py +136 -0
  41. topos_node-1.3.0/topos/features/signal/typed_stores/rhythm.py +171 -0
  42. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/typed_stores/scope_materializer.py +6 -0
  43. topos_node-1.3.0/topos/features/triage/__init__.py +4 -0
  44. topos_node-1.3.0/topos/features/triage/badges.py +223 -0
  45. topos_node-1.3.0/topos/features/triage/daily.py +609 -0
  46. topos_node-1.3.0/topos/features/triage/dashboard.py +80 -0
  47. topos_node-1.3.0/topos/features/triage/instruments.py +216 -0
  48. topos_node-1.3.0/topos/features/triage/intents.py +102 -0
  49. topos_node-1.3.0/topos/features/triage/readiness.py +58 -0
  50. topos_node-1.3.0/topos/protocol/handled_message_types.json +194 -0
  51. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/retrieval.py +172 -0
  52. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/scope_registry.json +36 -5
  53. topos_node-1.3.0/topos/query/truth_facts.py +74 -0
  54. topos_node-1.3.0/topos/query/truth_prompts.py +131 -0
  55. topos_node-1.3.0/topos/query/verify.py +388 -0
  56. topos_node-1.3.0/topos/query/verify_modes.py +147 -0
  57. topos_node-1.3.0/topos/runtime_housekeeping.py +117 -0
  58. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/bundled_canonical_triples.py +24 -5
  59. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/canonical_signal_defaults.py +1 -0
  60. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/install_service.py +55 -1
  61. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/__init__.py +23 -0
  62. topos_node-1.3.0/topos/storage/db/migrations/attention_triage_v1.py +60 -0
  63. topos_node-1.3.0/topos/storage/db/migrations/attention_triage_v2.py +44 -0
  64. topos_node-1.3.0/topos/storage/db/migrations/conversation_context_v1.py +52 -0
  65. {topos_node-1.2.7 → topos_node-1.3.0}/topos/upgrades/manifests.json +36 -0
  66. {topos_node-1.2.7 → topos_node-1.3.0/topos_node.egg-info}/PKG-INFO +1 -1
  67. {topos_node-1.2.7 → topos_node-1.3.0}/topos_node.egg-info/SOURCES.txt +24 -0
  68. topos_node-1.2.7/topos/api/local_mcp.py +0 -46
  69. topos_node-1.2.7/topos/core/handlers/query.py +0 -86
  70. topos_node-1.2.7/topos/features/signal/typed_stores/aggregates.py +0 -108
  71. topos_node-1.2.7/topos/protocol/handled_message_types.json +0 -181
  72. {topos_node-1.2.7 → topos_node-1.3.0}/LICENSE +0 -0
  73. {topos_node-1.2.7 → topos_node-1.3.0}/MANIFEST.in +0 -0
  74. {topos_node-1.2.7 → topos_node-1.3.0}/README.md +0 -0
  75. {topos_node-1.2.7 → topos_node-1.3.0}/setup.cfg +0 -0
  76. {topos_node-1.2.7 → topos_node-1.3.0}/shared/__init__.py +0 -0
  77. {topos_node-1.2.7 → topos_node-1.3.0}/shared/filtering.py +0 -0
  78. {topos_node-1.2.7 → topos_node-1.3.0}/shared/schema_registry.py +0 -0
  79. {topos_node-1.2.7 → topos_node-1.3.0}/tests/test_extensions.py +0 -0
  80. {topos_node-1.2.7 → topos_node-1.3.0}/tests/test_llm_integrations_storage.py +0 -0
  81. {topos_node-1.2.7 → topos_node-1.3.0}/tests/test_protocol_handled_types.py +0 -0
  82. {topos_node-1.2.7 → topos_node-1.3.0}/topos/__init__.py +0 -0
  83. {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/__init__.py +0 -0
  84. {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/duckdb_adapter.py +0 -0
  85. {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/messenger_communities.py +0 -0
  86. {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/messenger_graph.py +0 -0
  87. {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/messenger_labels.py +0 -0
  88. {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/profiles.py +0 -0
  89. {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/query_engine.py +0 -0
  90. {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/raw_queries.py +0 -0
  91. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/__init__.py +0 -0
  92. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/analytics.py +0 -0
  93. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/app_registry.py +0 -0
  94. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/backup.py +0 -0
  95. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/compute_remote.py +0 -0
  96. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/data_commit.py +0 -0
  97. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/data_explorer_table_prefs.py +0 -0
  98. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/database_explorer.py +0 -0
  99. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/db.py +0 -0
  100. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/device.py +0 -0
  101. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/engine_run.py +0 -0
  102. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/enrichment.py +0 -0
  103. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/enrichment_lab.py +0 -0
  104. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/filter_lab.py +0 -0
  105. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/health.py +0 -0
  106. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/home_chat.py +0 -0
  107. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/ingestion_api.py +0 -0
  108. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/ingestion_compat.py +0 -0
  109. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/ingestion_sources.py +0 -0
  110. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/intelligence_lifecycle.py +0 -0
  111. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/llm.py +0 -0
  112. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/messenger_analytics.py +0 -0
  113. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/privacy_disclose.py +0 -0
  114. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/query_api.py +0 -0
  115. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/runtime_bootstrap.py +0 -0
  116. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/sanitization_ollama_config.py +0 -0
  117. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/signal_extraction_config.py +0 -0
  118. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/source_install.py +0 -0
  119. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/source_scrub.py +0 -0
  120. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/sources.py +0 -0
  121. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/sources_overview.py +0 -0
  122. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/sync.py +0 -0
  123. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/tool_index.py +0 -0
  124. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/ui_config.py +0 -0
  125. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/uma_data.py +0 -0
  126. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/upgrades.py +0 -0
  127. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/usage.py +0 -0
  128. {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/user_identity.py +0 -0
  129. {topos_node-1.2.7 → topos_node-1.3.0}/topos/auth.py +0 -0
  130. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/__init__.py +0 -0
  131. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/__init__.py +0 -0
  132. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/base.py +0 -0
  133. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/chatgpt_mapper.py +0 -0
  134. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/demo_mappers.py +0 -0
  135. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/documents_mapper.py +0 -0
  136. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/github_activity_mapper.py +0 -0
  137. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/google_calendar_mapper.py +0 -0
  138. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/grok_mapper.py +0 -0
  139. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/messenger_mapper.py +0 -0
  140. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/models.py +0 -0
  141. {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/resolver.py +0 -0
  142. {topos_node-1.2.7 → topos_node-1.3.0}/topos/cli/__init__.py +0 -0
  143. {topos_node-1.2.7 → topos_node-1.3.0}/topos/cli/__main__.py +0 -0
  144. {topos_node-1.2.7 → topos_node-1.3.0}/topos/config/__init__.py +0 -0
  145. {topos_node-1.2.7 → topos_node-1.3.0}/topos/config/sanitization_ollama.py +0 -0
  146. {topos_node-1.2.7 → topos_node-1.3.0}/topos/config/signal_extraction.py +0 -0
  147. {topos_node-1.2.7 → topos_node-1.3.0}/topos/config/uvicorn_logging.json +0 -0
  148. {topos_node-1.2.7 → topos_node-1.3.0}/topos/contacts/__init__.py +0 -0
  149. {topos_node-1.2.7 → topos_node-1.3.0}/topos/contacts/identity.py +0 -0
  150. {topos_node-1.2.7 → topos_node-1.3.0}/topos/control_plane_client.py +0 -0
  151. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/__init__.py +0 -0
  152. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/api_models.py +0 -0
  153. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/connection_resilience.py +0 -0
  154. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/device_helpers.py +0 -0
  155. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/errors.py +0 -0
  156. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/events.py +0 -0
  157. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/__init__.py +0 -0
  158. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/common.py +0 -0
  159. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/contacts_import.py +0 -0
  160. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/database_explorer.py +0 -0
  161. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/device.py +0 -0
  162. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/enrichment.py +0 -0
  163. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/enrichment_lab.py +0 -0
  164. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/filter_lab.py +0 -0
  165. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/home_chat.py +0 -0
  166. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/ingest.py +0 -0
  167. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/messages.py +0 -0
  168. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/messenger_analytics.py +0 -0
  169. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/registry.py +0 -0
  170. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/routines.py +0 -0
  171. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/sources.py +0 -0
  172. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/tool_index.py +0 -0
  173. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/uma.py +0 -0
  174. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/logging.py +0 -0
  175. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/metrics.py +0 -0
  176. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/routine_access.py +0 -0
  177. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/startup_banner.py +0 -0
  178. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/state.py +0 -0
  179. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/table_layers.py +0 -0
  180. {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/types.py +0 -0
  181. {topos_node-1.2.7 → topos_node-1.3.0}/topos/data_explorer_row_delete.py +0 -0
  182. {topos_node-1.2.7 → topos_node-1.3.0}/topos/data_explorer_table_prefs.py +0 -0
  183. {topos_node-1.2.7 → topos_node-1.3.0}/topos/data_explorer_tables.py +0 -0
  184. {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/__init__.py +0 -0
  185. {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/canonical_writer.py +0 -0
  186. {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/content_policy.py +0 -0
  187. {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/field_registry.py +0 -0
  188. {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/privacy_layer.py +0 -0
  189. {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/tier.py +0 -0
  190. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/__init__.py +0 -0
  191. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/__init__.py +0 -0
  192. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/base.py +0 -0
  193. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/huggingface.py +0 -0
  194. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/openai.py +0 -0
  195. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/openai_compatible.py +0 -0
  196. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/redpill.py +0 -0
  197. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/stub.py +0 -0
  198. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/client.py +0 -0
  199. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/engine.py +0 -0
  200. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/intake.py +0 -0
  201. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/memory_utils.py +0 -0
  202. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/model_cache.py +0 -0
  203. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/pipeline_memory.py +0 -0
  204. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/queue_manager.py +0 -0
  205. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/registration.py +0 -0
  206. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/result_formatter.py +0 -0
  207. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/router.py +0 -0
  208. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/scoped_token.py +0 -0
  209. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/tasks.py +0 -0
  210. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/transport.py +0 -0
  211. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/usage_guard.py +0 -0
  212. {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/validator.py +0 -0
  213. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/__init__.py +0 -0
  214. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/derived_tables.py +0 -0
  215. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/job_writer.py +0 -0
  216. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/base.py +0 -0
  217. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/__init__.py +0 -0
  218. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/_batch_limits.py +0 -0
  219. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/_engine_runner.py +0 -0
  220. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/availability_scores_job.py +0 -0
  221. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/brief_fallback.py +0 -0
  222. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/embeddings_job.py +0 -0
  223. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/emo_27_job.py +0 -0
  224. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/entities_job.py +0 -0
  225. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/goal_extraction_job.py +0 -0
  226. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/pii_redaction_job.py +0 -0
  227. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/relationship_edges_job.py +0 -0
  228. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/sentiment_job.py +0 -0
  229. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/statistics_job.py +0 -0
  230. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/timeline_job.py +0 -0
  231. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/topic_clusters_job.py +0 -0
  232. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/topics_job.py +0 -0
  233. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/url_classification_core.py +0 -0
  234. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/url_classification_enrichment_job.py +0 -0
  235. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/url_classification_signal_job.py +0 -0
  236. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/raw/__init__.py +0 -0
  237. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
  238. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/raw/language_job.py +0 -0
  239. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
  240. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
  241. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/model_overrides.py +0 -0
  242. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/models/__init__.py +0 -0
  243. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/models/manager.py +0 -0
  244. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/models/mvp_defaults.py +0 -0
  245. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/models/registry.py +0 -0
  246. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/models/versioning.py +0 -0
  247. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/processor.py +0 -0
  248. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/progress_bar.py +0 -0
  249. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/registry_contract.py +0 -0
  250. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/signal_derivation_config.json +0 -0
  251. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/source_overrides.py +0 -0
  252. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/website_classifier.py +0 -0
  253. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/__init__.py +0 -0
  254. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/bundles.py +0 -0
  255. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/model_resolve.py +0 -0
  256. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/schema.py +0 -0
  257. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/service.py +0 -0
  258. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/store.py +0 -0
  259. {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/worker.py +0 -0
  260. {topos_node-1.2.7 → topos_node-1.3.0}/topos/evals/__init__.py +0 -0
  261. {topos_node-1.2.7 → topos_node-1.3.0}/topos/evals/enrichment_eval.py +0 -0
  262. {topos_node-1.2.7 → topos_node-1.3.0}/topos/extensions.py +0 -0
  263. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/__init__.py +0 -0
  264. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/consolidation.py +0 -0
  265. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/dossier.py +0 -0
  266. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/edges.py +0 -0
  267. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/fact_materializer.py +0 -0
  268. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/graph_enrichers.py +0 -0
  269. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/graph_refresh.py +0 -0
  270. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/graph_search.py +0 -0
  271. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/linking.py +0 -0
  272. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/maintenance.py +0 -0
  273. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/reads.py +0 -0
  274. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/resolver.py +0 -0
  275. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/facts/__init__.py +0 -0
  276. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/facts/store.py +0 -0
  277. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/lifecycle/__init__.py +0 -0
  278. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/lifecycle/derived_scrub.py +0 -0
  279. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/lifecycle/exclusions.py +0 -0
  280. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/lifecycle/gc.py +0 -0
  281. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/provenance/__init__.py +0 -0
  282. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/provenance/posture.py +0 -0
  283. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/provenance/roles.py +0 -0
  284. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/__init__.py +0 -0
  285. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/brief_canonical_loader.py +0 -0
  286. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/brief_ontology.py +0 -0
  287. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/brief_renderer.py +0 -0
  288. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/brief_schemas.py +0 -0
  289. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/chunking.py +0 -0
  290. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/cluster_labels.py +0 -0
  291. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/data_health.py +0 -0
  292. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/brief_ontologies.json +0 -0
  293. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/profile.json +0 -0
  294. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/relationships.json +0 -0
  295. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/schema/dimension_definition.schema.json +0 -0
  296. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/work.json +0 -0
  297. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/dimension_briefs.py +0 -0
  298. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/dimension_definition_loader.py +0 -0
  299. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/dimension_profiles.py +0 -0
  300. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/dimension_registry.py +0 -0
  301. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/embed_context.py +0 -0
  302. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/extraction/artifact_store.py +0 -0
  303. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/graph_sanitize.py +0 -0
  304. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/hybrid_search.py +0 -0
  305. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/incremental_clustering.py +0 -0
  306. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/model_recommendations.py +0 -0
  307. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/query_embed_cache.py +0 -0
  308. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/schemas.py +0 -0
  309. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/service.py +0 -0
  310. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/signal_object_store.py +0 -0
  311. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/source_hydration.py +0 -0
  312. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/structured_signal.py +0 -0
  313. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/tool_index.py +0 -0
  314. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/topic_clustering.py +0 -0
  315. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/vector_codec.py +0 -0
  316. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/vector_math.py +0 -0
  317. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/vector_settings.py +0 -0
  318. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/stats/__init__.py +0 -0
  319. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/stats/definitions.py +0 -0
  320. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/stats/engine.py +0 -0
  321. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/stats/fold.py +0 -0
  322. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/stats/insights.py +0 -0
  323. {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/timeline_projection.py +0 -0
  324. {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/__init__.py +0 -0
  325. {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/bundles.py +0 -0
  326. {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/schema.py +0 -0
  327. {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/service.py +0 -0
  328. {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/store.py +0 -0
  329. {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/worker.py +0 -0
  330. {topos_node-1.2.7 → topos_node-1.3.0}/topos/home_chat/__init__.py +0 -0
  331. {topos_node-1.2.7 → topos_node-1.3.0}/topos/home_chat/schema.py +0 -0
  332. {topos_node-1.2.7 → topos_node-1.3.0}/topos/home_chat/store.py +0 -0
  333. {topos_node-1.2.7 → topos_node-1.3.0}/topos/hosted_pool_lease.py +0 -0
  334. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/__init__.py +0 -0
  335. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/canonical_pipeline.py +0 -0
  336. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/checkpoints/__init__.py +0 -0
  337. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
  338. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
  339. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/inbox_crypto.py +0 -0
  340. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/inbox_drain.py +0 -0
  341. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/ingest_helpers.py +0 -0
  342. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/jobs.py +0 -0
  343. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/journal_location_fanout.py +0 -0
  344. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/journal_time_log_normalize.py +0 -0
  345. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/local_sync.py +0 -0
  346. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/log_preview.py +0 -0
  347. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/manager.py +0 -0
  348. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parser.py +0 -0
  349. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/__init__.py +0 -0
  350. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/base.py +0 -0
  351. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/browser_parser.py +0 -0
  352. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/calendar_parser.py +0 -0
  353. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
  354. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
  355. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/demo_file_parsers.py +0 -0
  356. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/documents_parser.py +0 -0
  357. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/github_activity_parser.py +0 -0
  358. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/google_calendar_parser.py +0 -0
  359. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/grok_parser.py +0 -0
  360. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/messenger_parser.py +0 -0
  361. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/voxterm_parser.py +0 -0
  362. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/progress.py +0 -0
  363. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/reprocess.py +0 -0
  364. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/__init__.py +0 -0
  365. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/base.py +0 -0
  366. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/calendar.py +0 -0
  367. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/chatgpt.py +0 -0
  368. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/contact_importers.py +0 -0
  369. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/grok.py +0 -0
  370. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/imessage_reader.py +0 -0
  371. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/signal_export_parser.py +0 -0
  372. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/signal_reader.py +0 -0
  373. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/state_machine.py +0 -0
  374. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/triggers/__init__.py +0 -0
  375. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/triggers/file_trigger.py +0 -0
  376. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
  377. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/usage_inbox_dedupe.py +0 -0
  378. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/validation/__init__.py +0 -0
  379. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/validation/base.py +0 -0
  380. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/validation/schema_registry.py +0 -0
  381. {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/validation/schema_validator.py +0 -0
  382. {topos_node-1.2.7 → topos_node-1.3.0}/topos/lineage/__init__.py +0 -0
  383. {topos_node-1.2.7 → topos_node-1.3.0}/topos/lineage/provenance.py +0 -0
  384. {topos_node-1.2.7 → topos_node-1.3.0}/topos/lineage/tracker.py +0 -0
  385. {topos_node-1.2.7 → topos_node-1.3.0}/topos/llm_integrations_storage.py +0 -0
  386. {topos_node-1.2.7 → topos_node-1.3.0}/topos/mcp_stdio_proxy.py +0 -0
  387. {topos_node-1.2.7 → topos_node-1.3.0}/topos/observability/__init__.py +0 -0
  388. {topos_node-1.2.7 → topos_node-1.3.0}/topos/observability/alerts.py +0 -0
  389. {topos_node-1.2.7 → topos_node-1.3.0}/topos/observability/metrics.py +0 -0
  390. {topos_node-1.2.7 → topos_node-1.3.0}/topos/observability/tracing.py +0 -0
  391. {topos_node-1.2.7 → topos_node-1.3.0}/topos/openai_client.py +0 -0
  392. {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/__init__.py +0 -0
  393. {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/audit.py +0 -0
  394. {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/envelope.py +0 -0
  395. {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/job_runner.py +0 -0
  396. {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/job_store.py +0 -0
  397. {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/stages.py +0 -0
  398. {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/stub_enqueue.py +0 -0
  399. {topos_node-1.2.7 → topos_node-1.3.0}/topos/projections/__init__.py +0 -0
  400. {topos_node-1.2.7 → topos_node-1.3.0}/topos/projections/vector_index/__init__.py +0 -0
  401. {topos_node-1.2.7 → topos_node-1.3.0}/topos/projections/vector_index/base.py +0 -0
  402. {topos_node-1.2.7 → topos_node-1.3.0}/topos/projections/vector_index/builders.py +0 -0
  403. {topos_node-1.2.7 → topos_node-1.3.0}/topos/projections/vector_index/health_checks.py +0 -0
  404. {topos_node-1.2.7 → topos_node-1.3.0}/topos/protocol/__init__.py +0 -0
  405. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/__init__.py +0 -0
  406. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/audit.py +0 -0
  407. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/ddr.py +0 -0
  408. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/disclosure.py +0 -0
  409. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/fingerprint.py +0 -0
  410. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/game_layer.py +0 -0
  411. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/grant_cache.py +0 -0
  412. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/inference.py +0 -0
  413. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/intent.py +0 -0
  414. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/manifest.py +0 -0
  415. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/manifest_validation.py +0 -0
  416. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/minimizer.py +0 -0
  417. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/negotiation.py +0 -0
  418. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/pipeline.py +0 -0
  419. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/planner.py +0 -0
  420. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/runtime.py +0 -0
  421. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/scope_registry_loader.py +0 -0
  422. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/session.py +0 -0
  423. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/session_utils.py +0 -0
  424. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/source_generation.py +0 -0
  425. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/turn_classifier.py +0 -0
  426. {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/types.py +0 -0
  427. {topos_node-1.2.7 → topos_node-1.3.0}/topos/rate_limit.py +0 -0
  428. {topos_node-1.2.7 → topos_node-1.3.0}/topos/routines/__init__.py +0 -0
  429. {topos_node-1.2.7 → topos_node-1.3.0}/topos/routines/schema.py +0 -0
  430. {topos_node-1.2.7 → topos_node-1.3.0}/topos/routines/store.py +0 -0
  431. {topos_node-1.2.7 → topos_node-1.3.0}/topos/runtime_shutdown.py +0 -0
  432. {topos_node-1.2.7 → topos_node-1.3.0}/topos/runtime_update.py +0 -0
  433. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sanitization/__init__.py +0 -0
  434. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sanitization/nsfw_classifier.py +0 -0
  435. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sanitization/ollama_transforms.py +0 -0
  436. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sanitization/prewarm.py +0 -0
  437. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sanitization/privacy_filter.py +0 -0
  438. {topos_node-1.2.7 → topos_node-1.3.0}/topos/scope_resolution.py +0 -0
  439. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/__init__.py +0 -0
  440. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/container.py +0 -0
  441. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/embeddings/__init__.py +0 -0
  442. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/embeddings/base.py +0 -0
  443. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/embeddings/local.py +0 -0
  444. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/embeddings/remote.py +0 -0
  445. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/interfaces.py +0 -0
  446. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/llm/__init__.py +0 -0
  447. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/llm/base.py +0 -0
  448. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/llm/openai.py +0 -0
  449. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/local.py +0 -0
  450. {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/postgres.py +0 -0
  451. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/__init__.py +0 -0
  452. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/definitions.py +0 -0
  453. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/registry.py +0 -0
  454. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/runtime_install.py +0 -0
  455. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/scrub_attribution.py +0 -0
  456. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/scrub_service.py +0 -0
  457. {topos_node-1.2.7 → topos_node-1.3.0}/topos/startup_banner.py +0 -0
  458. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/__init__.py +0 -0
  459. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/__init__.py +0 -0
  460. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/factory.py +0 -0
  461. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/fakes.py +0 -0
  462. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/postgres/stores.py +0 -0
  463. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/protocols.py +0 -0
  464. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/sqlite/__init__.py +0 -0
  465. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/sqlite/stores.py +0 -0
  466. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/sqlite/vector_search.py +0 -0
  467. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/__init__.py +0 -0
  468. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/activity_tables.py +0 -0
  469. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/ai_chat/__init__.py +0 -0
  470. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/ai_chat/canonicalizer.py +0 -0
  471. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/ai_chat/mapper.py +0 -0
  472. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/ai_chat/model.py +0 -0
  473. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/ai_chat/tables.py +0 -0
  474. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/calendar_contacts_tables.py +0 -0
  475. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/canonical_store.py +0 -0
  476. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/conversations_tables.py +0 -0
  477. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/mapping_store.py +0 -0
  478. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/postgres.py +0 -0
  479. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/__init__.py +0 -0
  480. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/client.py +0 -0
  481. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/connection_tuning.py +0 -0
  482. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/activity_events_content_v1.py +0 -0
  483. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/actor_role_v1.py +0 -0
  484. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/calendar_events_scheduling_v1.py +0 -0
  485. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/canonical_address_book_v1.py +0 -0
  486. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/canonical_disclosure_v1.py +0 -0
  487. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/canonical_nsfw_v1.py +0 -0
  488. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/derivation_ledger_v1.py +0 -0
  489. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/documents_v1.py +0 -0
  490. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/entity_edges_validity_v1.py +0 -0
  491. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/episodes_v1.py +0 -0
  492. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/extraction_artifacts.py +0 -0
  493. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/journal_entries_duration_v1.py +0 -0
  494. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/journal_entries_ends_at_v1.py +0 -0
  495. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/journal_entries_people_v1.py +0 -0
  496. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/journal_entries_place_name_v1.py +0 -0
  497. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/journal_entries_starts_at_v1.py +0 -0
  498. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/pipeline_jobs_v1.py +0 -0
  499. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/remediation_person_model.py +0 -0
  500. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/scope_source_generation.py +0 -0
  501. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/signal_dimension_backfill_v1.py +0 -0
  502. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/signal_dimension_harness.py +0 -0
  503. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/signal_objects.py +0 -0
  504. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/signal_objects_period_v1.py +0 -0
  505. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/signal_objects_updated_by_v1.py +0 -0
  506. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
  507. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/vector_storage_v1.py +0 -0
  508. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/vector_storage_v2.py +0 -0
  509. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/vector_storage_v3.py +0 -0
  510. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/vector_storage_v4.py +0 -0
  511. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_clusters_v2.py +0 -0
  512. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_entities_v1.py +0 -0
  513. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_entity_review_v2.py +0 -0
  514. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_facts_v1.py +0 -0
  515. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_lifecycle_v1.py +0 -0
  516. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_phase0.py +0 -0
  517. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_phase1.py +0 -0
  518. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +0 -0
  519. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +0 -0
  520. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +0 -0
  521. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_query_quality.py +0 -0
  522. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +0 -0
  523. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_stats_v1.py +0 -0
  524. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_timeline_v1.py +0 -0
  525. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/paths.py +0 -0
  526. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/postgres.py +0 -0
  527. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/schema.py +0 -0
  528. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/storage_breakdown.py +0 -0
  529. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/write_gate.py +0 -0
  530. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/enrichment/__init__.py +0 -0
  531. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
  532. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
  533. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/normalized/__init__.py +0 -0
  534. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/normalized/normalized_store.py +0 -0
  535. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/oplog/__init__.py +0 -0
  536. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/oplog/decision.py +0 -0
  537. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/oplog/oplog_store.py +0 -0
  538. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/oplog/postgres.py +0 -0
  539. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/person/identity_resolver.py +0 -0
  540. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/projections/__init__.py +0 -0
  541. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/projections/index_ops_store.py +0 -0
  542. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/projections/vector_index_store.py +0 -0
  543. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/__init__.py +0 -0
  544. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/browser_flat_tables.py +0 -0
  545. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/file_store.py +0 -0
  546. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/raw_store.py +0 -0
  547. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/raw_tables_manager.py +0 -0
  548. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/sqlite_raw_store.py +0 -0
  549. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/security/encryption.py +0 -0
  550. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/signal_identity.py +0 -0
  551. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/source_settings.py +0 -0
  552. {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/user_identity.py +0 -0
  553. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sync/__init__.py +0 -0
  554. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sync/client.py +0 -0
  555. {topos_node-1.2.7 → topos_node-1.3.0}/topos/sync_handlers.py +0 -0
  556. {topos_node-1.2.7 → topos_node-1.3.0}/topos/testing/__init__.py +0 -0
  557. {topos_node-1.2.7 → topos_node-1.3.0}/topos/testing/lifespan.py +0 -0
  558. {topos_node-1.2.7 → topos_node-1.3.0}/topos/uma_contact_enrichment.py +0 -0
  559. {topos_node-1.2.7 → topos_node-1.3.0}/topos/uma_filters.py +0 -0
  560. {topos_node-1.2.7 → topos_node-1.3.0}/topos/uma_resource_id.py +0 -0
  561. {topos_node-1.2.7 → topos_node-1.3.0}/topos/uma_rpt.py +0 -0
  562. {topos_node-1.2.7 → topos_node-1.3.0}/topos/upgrades/__init__.py +0 -0
  563. {topos_node-1.2.7 → topos_node-1.3.0}/topos/upgrades/runner.py +0 -0
  564. {topos_node-1.2.7 → topos_node-1.3.0}/topos/utils/base_object.py +0 -0
  565. {topos_node-1.2.7 → topos_node-1.3.0}/topos/websocket_client.py +0 -0
  566. {topos_node-1.2.7 → topos_node-1.3.0}/topos_node.egg-info/dependency_links.txt +0 -0
  567. {topos_node-1.2.7 → topos_node-1.3.0}/topos_node.egg-info/entry_points.txt +0 -0
  568. {topos_node-1.2.7 → topos_node-1.3.0}/topos_node.egg-info/requires.txt +0 -0
  569. {topos_node-1.2.7 → topos_node-1.3.0}/topos_node.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: topos-node
3
- Version: 1.2.7
3
+ Version: 1.3.0
4
4
  Summary: Topos personal AI engine (FastAPI): local data, sync, control plane WebSocket client
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://topos.dialogues.ai
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "topos-node"
7
- version = "1.2.7"
7
+ version = "1.3.0"
8
8
  description = "Topos personal AI engine (FastAPI): local data, sync, control plane WebSocket client"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -84,6 +84,12 @@ where = ["."]
84
84
  include = ["topos*", "shared*"]
85
85
 
86
86
  [tool.pytest.ini_options]
87
+ # tmp_path hygiene: this suite's fixtures build whole node DBs (100s of MB per
88
+ # run). Keep only the last run's FAILED dirs — passed dirs are removed as tests
89
+ # finish, so tmp never accumulates across runs. Killed runs can still leave
90
+ # locked roots behind; topos.runtime_housekeeping sweeps those on node start.
91
+ tmp_path_retention_count = 1
92
+ tmp_path_retention_policy = "failed"
87
93
  filterwarnings = [
88
94
  "ignore::DeprecationWarning:pydantic.*",
89
95
  "ignore:on_event is deprecated.*:DeprecationWarning:fastapi.*",
@@ -106,5 +112,5 @@ markers = [
106
112
  "eval_nightly: statistical privacy eval (attacker advantage, minimality, latency); nightly",
107
113
  "eval_release: release-tier privacy eval (negotiation A/B, Pareto); run per release",
108
114
  ]
109
- pythonpath = ["tests/gap/p3/engine", "tests/gap/p4/engine", "tests/gap/qq/engine", "tests/acceptance/wiki_mvp"]
115
+ pythonpath = ["tests/gap/p3/engine", "tests/gap/p4/engine", "tests/gap/qq/engine", "tests/acceptance/wiki_mvp", "tests/evals/time_signal"]
110
116
  testpaths = ["tests"]
@@ -1,6 +1,6 @@
1
1
  """Topos Control Plane Version Information."""
2
2
 
3
- __version__ = "1.2.7"
4
- __version_info__ = (1, 2, 7)
3
+ __version__ = "1.3.0"
4
+ __version_info__ = (1, 3, 0)
5
5
 
6
6
  __all__ = ["__version__", "__version_info__"]
@@ -0,0 +1,142 @@
1
+ """Owner-set conversation context tag (work | personal).
2
+
3
+ Second labeling axis alongside source posture: posture says whose words the
4
+ content is; context_tag says which life domain the thread belongs to. Set at
5
+ the conversation level (the thread in `conversations`); every message in the
6
+ thread inherits it at read/derivation time. Owner-only; never inferred here.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from fastapi import APIRouter, Body, Depends, HTTPException
12
+
13
+ from ..auth import require_api_key
14
+ from ..core.state import get_db_connection
15
+ from ..storage.db.migrations.conversation_context_v1 import CONTEXT_TAG_VALUES
16
+
17
+ router = APIRouter()
18
+
19
+
20
+ def _conversation_row(conn, conversation_id: str, dataset_id: str):
21
+ return conn.execute(
22
+ "SELECT conversation_id, dataset_id, context_tag, context_tag_source "
23
+ "FROM conversations WHERE conversation_id=? AND dataset_id=?",
24
+ (conversation_id, dataset_id),
25
+ ).fetchone()
26
+
27
+
28
+ def read_conversation_context(conn, conversation_id: str, dataset_id: str) -> dict | None:
29
+ """Context-tag payload for a conversation, or None when it is unknown.
30
+
31
+ Shared by the HTTP endpoint below and the WS handler
32
+ (core.handlers.config get_conversation_context) so both stay one source.
33
+ """
34
+ row = _conversation_row(conn, conversation_id, dataset_id)
35
+ if row is None:
36
+ return None
37
+ return {
38
+ "status": "ok",
39
+ "conversation_id": row[0],
40
+ "dataset_id": row[1],
41
+ "context_tag": row[2],
42
+ "context_tag_source": row[3],
43
+ }
44
+
45
+
46
+ def write_conversation_context(conn, conversation_id: str, dataset_id: str, raw_tag) -> dict:
47
+ """Owner set/clear of the context tag.
48
+
49
+ Raises ValueError on an invalid tag, LookupError when the conversation is
50
+ unknown. Shared by the HTTP endpoint and the WS handler.
51
+ """
52
+ tag = str(raw_tag).strip().lower() if raw_tag is not None else None
53
+ if tag is not None and tag not in CONTEXT_TAG_VALUES:
54
+ raise ValueError(f"context_tag must be one of {sorted(CONTEXT_TAG_VALUES)} or null")
55
+ if _conversation_row(conn, conversation_id, dataset_id) is None:
56
+ raise LookupError("Unknown conversation")
57
+ # Owner decisions always win: stamped 'owner' even when clearing, so the
58
+ # auto-classifier never refills a conversation the owner chose to untag.
59
+ conn.execute(
60
+ "UPDATE conversations SET context_tag=?, context_tag_source='owner', "
61
+ "updated_at=datetime('now') WHERE conversation_id=? AND dataset_id=?",
62
+ (tag, conversation_id, dataset_id),
63
+ )
64
+ conn.commit()
65
+ return {
66
+ "status": "ok",
67
+ "conversation_id": conversation_id,
68
+ "dataset_id": dataset_id,
69
+ "context_tag": tag,
70
+ "context_tag_source": "owner",
71
+ }
72
+
73
+
74
+ @router.get(
75
+ "/conversations/{conversation_id}/context",
76
+ dependencies=[Depends(require_api_key)],
77
+ )
78
+ async def get_conversation_context(conversation_id: str, dataset_id: str) -> dict:
79
+ conn = get_db_connection()
80
+ if conn is None:
81
+ raise HTTPException(status_code=503, detail="Database not available")
82
+ data = read_conversation_context(conn, conversation_id, dataset_id)
83
+ if data is None:
84
+ raise HTTPException(status_code=404, detail="Unknown conversation")
85
+ return data
86
+
87
+
88
+ @router.put(
89
+ "/conversations/{conversation_id}/context",
90
+ dependencies=[Depends(require_api_key)],
91
+ )
92
+ async def set_conversation_context(
93
+ conversation_id: str,
94
+ payload: dict = Body(default_factory=dict),
95
+ ) -> dict:
96
+ dataset_id = str(payload.get("dataset_id") or "").strip()
97
+ if not dataset_id:
98
+ raise HTTPException(status_code=422, detail="dataset_id is required")
99
+ conn = get_db_connection()
100
+ if conn is None:
101
+ raise HTTPException(status_code=503, detail="Database not available")
102
+ try:
103
+ return write_conversation_context(conn, conversation_id, dataset_id, payload.get("context_tag"))
104
+ except ValueError as exc:
105
+ raise HTTPException(status_code=422, detail=str(exc)) from exc
106
+ except LookupError as exc:
107
+ raise HTTPException(status_code=404, detail=str(exc)) from exc
108
+
109
+
110
+ # --- classifier model config (settings surface) -----------------------------------
111
+
112
+
113
+ @router.get("/conversation-context-llm-config", dependencies=[Depends(require_api_key)])
114
+ async def get_context_llm_config() -> dict:
115
+ from ..config.conversation_context_llm import effective_config_for_api
116
+ from ..config.settings import settings
117
+
118
+ conn = get_db_connection()
119
+ if conn is None:
120
+ raise HTTPException(status_code=503, detail="Database not available")
121
+ return {"status": "ok", **effective_config_for_api(settings, conn)}
122
+
123
+
124
+ @router.put("/conversation-context-llm-config", dependencies=[Depends(require_api_key)])
125
+ async def put_context_llm_config(payload: dict = Body(default=None)) -> dict:
126
+ from ..config.conversation_context_llm import (
127
+ ENGINE_CONFIG_KEY_CONVERSATION_CONTEXT_LLM_MODEL,
128
+ effective_config_for_api,
129
+ normalize_put_model,
130
+ )
131
+ from ..config.settings import settings
132
+ from ..core.state import set_engine_config_value
133
+
134
+ conn = get_db_connection()
135
+ if conn is None:
136
+ raise HTTPException(status_code=503, detail="Database not available")
137
+ try:
138
+ model = normalize_put_model(payload)
139
+ except ValueError as exc:
140
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
141
+ set_engine_config_value(conn, ENGINE_CONFIG_KEY_CONVERSATION_CONTEXT_LLM_MODEL, model)
142
+ return {"status": "ok", **effective_config_for_api(settings, conn)}
@@ -0,0 +1,63 @@
1
+ """Read/update the owner-selected facts-LLM extraction model (engine_config)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from typing import Any
7
+
8
+ from fastapi import APIRouter, Body, Depends, HTTPException
9
+
10
+ from ..auth import require_api_key
11
+ from ..config.facts_llm import (
12
+ ENGINE_CONFIG_KEY_FACTS_LLM_MODEL,
13
+ effective_config_for_api,
14
+ normalize_put_model,
15
+ )
16
+ from ..config.settings import settings
17
+ from ..core.state import get_db_connection, set_engine_config_value
18
+
19
+ logger = logging.getLogger("topos.api.facts_llm_config")
20
+
21
+ router = APIRouter(tags=["facts-llm"])
22
+
23
+
24
+ @router.get("/v1/facts-llm-config", dependencies=[Depends(require_api_key)])
25
+ async def get_facts_llm_config() -> dict[str, Any]:
26
+ conn = get_db_connection()
27
+ if not conn:
28
+ raise HTTPException(status_code=503, detail="Database not available")
29
+ try:
30
+ return {"status": "ok", **effective_config_for_api(settings, conn)}
31
+ except Exception as exc: # noqa: BLE001
32
+ logger.warning("get_facts_llm_config failed: %s", exc)
33
+ raise HTTPException(status_code=500, detail="Failed to read config") from exc
34
+
35
+
36
+ @router.put("/v1/facts-llm-config", dependencies=[Depends(require_api_key)])
37
+ async def put_facts_llm_config(body: dict[str, Any] = Body(default=None)) -> dict[str, Any]:
38
+ conn = get_db_connection()
39
+ if not conn:
40
+ raise HTTPException(status_code=503, detail="Database not available")
41
+ try:
42
+ model = normalize_put_model(body)
43
+ set_engine_config_value(conn, ENGINE_CONFIG_KEY_FACTS_LLM_MODEL, model)
44
+ return {"status": "ok", **effective_config_for_api(settings, conn)}
45
+ except ValueError as exc:
46
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
47
+ except Exception as exc: # noqa: BLE001
48
+ logger.warning("put_facts_llm_config failed: %s", exc)
49
+ raise HTTPException(status_code=500, detail="Failed to save config") from exc
50
+
51
+
52
+ @router.delete("/v1/facts-llm-config", dependencies=[Depends(require_api_key)])
53
+ async def delete_facts_llm_model_override() -> dict[str, Any]:
54
+ """Clear the device override; the effective model reverts to env defaults."""
55
+ conn = get_db_connection()
56
+ if not conn:
57
+ raise HTTPException(status_code=503, detail="Database not available")
58
+ try:
59
+ set_engine_config_value(conn, ENGINE_CONFIG_KEY_FACTS_LLM_MODEL, "")
60
+ return {"status": "ok", **effective_config_for_api(settings, conn)}
61
+ except Exception as exc: # noqa: BLE001
62
+ logger.warning("delete facts_llm model override failed: %s", exc)
63
+ raise HTTPException(status_code=500, detail="Failed to clear config") from exc
@@ -0,0 +1,119 @@
1
+ """Local API for MCP-style tools (no Control Plane). Same auth as engine; for same-device/offline use."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+
7
+ from fastapi import APIRouter, Body, Depends
8
+
9
+ from ..auth import require_api_key
10
+ from ..core.handlers import handle_control_plane_request
11
+
12
+ router = APIRouter(prefix="/api/local", tags=["local-mcp"])
13
+
14
+
15
+ def _local_mcp_payload(extra: dict | None = None) -> dict:
16
+ """Payload for local MCP requests; source=claude_desktop so engine counts per source."""
17
+ p = {"mcp_source": "claude_desktop"}
18
+ if extra:
19
+ p.update(extra)
20
+ return p
21
+
22
+
23
+ @router.post("/list_database_tables")
24
+ async def local_list_database_tables(_: None = Depends(require_api_key)) -> dict: # noqa: B008
25
+ """List tables (same as CP-forwarded tool). Requires Bearer TOPOS_KEY."""
26
+ msg = {"id": str(uuid.uuid4()), "type": "list_database_tables", "payload": _local_mcp_payload()}
27
+ out = await handle_control_plane_request(msg)
28
+ if out.get("status") == "error":
29
+ return {"status": "error", "error": out.get("error", "unknown")}
30
+ return out.get("payload", {})
31
+
32
+
33
+ @router.post("/verify_claim")
34
+ async def local_verify_claim(
35
+ body: dict = Body(default_factory=dict),
36
+ _: None = Depends(require_api_key), # noqa: B008
37
+ ) -> dict:
38
+ """Same-device truth check (PLAN_TRUTHFULNESS_PLUGIN.md). Owner-key only;
39
+ mirrors the CP door: `app_id` is mandatory and `mode` is pinned to fun —
40
+ this route cannot reach a mode the registry doesn't ship. Body:
41
+ {"statement": "...", "app_id": "truth-mirror"}."""
42
+ statement = str(body.get("statement") or "").strip()
43
+ app_id = str(body.get("app_id") or "").strip()
44
+ if not statement or not app_id:
45
+ return {"status": "error", "error": "statement and app_id required"}
46
+ msg = {
47
+ "id": str(uuid.uuid4()),
48
+ "type": "verify_claim",
49
+ "payload": {"statement": statement, "mode": "fun", "caller_app_id": app_id},
50
+ }
51
+ out = await handle_control_plane_request(msg)
52
+ if out.get("status") == "error":
53
+ return {"status": "error", "error": out.get("error", "unknown")}
54
+ return out.get("payload", {})
55
+
56
+
57
+ @router.post("/truth_prompts")
58
+ async def local_truth_prompts(
59
+ body: dict = Body(default_factory=dict),
60
+ _: None = Depends(require_api_key), # noqa: B008
61
+ ) -> dict:
62
+ """Same-device "ask me" prompt seeds (fun aperture; topics only, no
63
+ stances). Body: {"app_id": "truth-mirror", "limit": 5}."""
64
+ app_id = str(body.get("app_id") or "").strip()
65
+ if not app_id:
66
+ return {"status": "error", "error": "app_id required"}
67
+ msg = {
68
+ "id": str(uuid.uuid4()),
69
+ "type": "truth_prompts",
70
+ "payload": {"mode": "fun", "caller_app_id": app_id,
71
+ "limit": int(body.get("limit") or 5)},
72
+ }
73
+ out = await handle_control_plane_request(msg)
74
+ if out.get("status") == "error":
75
+ return {"status": "error", "error": out.get("error", "unknown")}
76
+ return out.get("payload", {})
77
+
78
+
79
+ @router.post("/truth_seed_fact")
80
+ async def local_truth_seed_fact(
81
+ body: dict = Body(default_factory=dict),
82
+ _: None = Depends(require_api_key), # noqa: B008
83
+ ) -> dict:
84
+ """Owner adds a fun fact to their own sheet (refused outside the fun
85
+ aperture). Body: {"predicate": "favorite_food", "value": "tacos",
86
+ "app_id": "truth-mirror"}."""
87
+ app_id = str(body.get("app_id") or "").strip()
88
+ if not app_id:
89
+ return {"status": "error", "error": "app_id required"}
90
+ msg = {
91
+ "id": str(uuid.uuid4()),
92
+ "type": "truth_seed_fact",
93
+ "payload": {
94
+ "mode": "fun",
95
+ "caller_app_id": app_id,
96
+ "predicate": str(body.get("predicate") or ""),
97
+ "value": str(body.get("value") or ""),
98
+ },
99
+ }
100
+ out = await handle_control_plane_request(msg)
101
+ if out.get("status") == "error":
102
+ return {"status": "error", "error": out.get("error", "unknown")}
103
+ return out.get("payload", {})
104
+
105
+
106
+ @router.post("/get_table_schema")
107
+ async def local_get_table_schema(
108
+ body: dict = Body(default_factory=dict),
109
+ _: None = Depends(require_api_key), # noqa: B008
110
+ ) -> dict:
111
+ """Get table schema (same as CP-forwarded tool). Body: {"table_name": "..."}. Requires Bearer TOPOS_KEY."""
112
+ table_name = (body.get("table_name") or "").strip()
113
+ if not table_name:
114
+ return {"status": "error", "error": "table_name required"}
115
+ msg = {"id": str(uuid.uuid4()), "type": "get_table_schema", "payload": _local_mcp_payload({"table_name": table_name})}
116
+ out = await handle_control_plane_request(msg)
117
+ if out.get("status") == "error":
118
+ return {"status": "error", "error": out.get("error", "unknown")}
119
+ return out.get("payload", {})
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  import logging
6
6
  from typing import Any, Dict, Optional
7
7
 
8
- from fastapi import APIRouter, Depends, HTTPException, Query
8
+ from fastapi import APIRouter, Body, Depends, HTTPException, Query
9
9
  from pydantic import BaseModel, Field
10
10
 
11
11
  from ..auth import require_api_key
@@ -480,6 +480,34 @@ async def list_facts(
480
480
  )
481
481
 
482
482
 
483
+ @router.post("/facts/verdict")
484
+ async def post_fact_verdict(
485
+ object_id: str = Body(...),
486
+ action: str = Body(..., description="confirm | reject | edit"),
487
+ object_value: Optional[str] = Body(default=None),
488
+ asserted_by: Optional[str] = Body(default=None),
489
+ note: Optional[str] = Body(default=None),
490
+ _api_key: str = Depends(require_api_key),
491
+ ):
492
+ """Owner verdict on one fact: confirm (attest true), reject (close +
493
+ tombstone this value), or edit (correct the value and/or attribution)."""
494
+ from ..features.facts.verdicts import apply_fact_verdict
495
+
496
+ try:
497
+ return apply_fact_verdict(
498
+ _entities_conn(),
499
+ object_id=object_id,
500
+ action=action,
501
+ object_value=object_value,
502
+ asserted_by=asserted_by,
503
+ note=note,
504
+ )
505
+ except LookupError as exc:
506
+ raise HTTPException(status_code=404, detail=str(exc))
507
+ except ValueError as exc:
508
+ raise HTTPException(status_code=400, detail=str(exc))
509
+
510
+
483
511
  @router.get("/insights")
484
512
  async def list_stat_insights(
485
513
  dimension: Optional[str] = Query(default=None, max_length=40),
@@ -623,3 +651,21 @@ async def refresh_dimension_brief(
623
651
  return await service.refresh_brief(dimension, limit=limit)
624
652
  except ValueError as exc:
625
653
  raise HTTPException(status_code=400, detail=str(exc)) from exc
654
+
655
+
656
+ # --------------------------------------------------------------- attention triage
657
+
658
+ @router.get("/attention/dashboard")
659
+ async def attention_dashboard(
660
+ _api_key: str = Depends(require_api_key),
661
+ days: int = Query(14, ge=1, le=90),
662
+ include_titles: bool = Query(True),
663
+ ):
664
+ """Data spine for the /data/attention tab (PLAN_ATTENTION_ANALYTICS_EXECUTION WS5.1)."""
665
+ from ..core.state import get_db_connection
666
+ from ..features.triage.dashboard import attention_dashboard_data
667
+
668
+ conn = get_db_connection()
669
+ if conn is None:
670
+ raise HTTPException(status_code=503, detail="database unavailable")
671
+ return attention_dashboard_data(conn, days=days, include_titles=include_titles)
@@ -15,6 +15,7 @@ from .api import (
15
15
  app_registry as app_registry_routes,
16
16
  backup as backup_routes,
17
17
  compute_remote as compute_remote_routes,
18
+ conversation_context as conversation_context_routes,
18
19
  engine_run as engine_run_routes,
19
20
  data_commit as data_commit_routes,
20
21
  db as db_routes,
@@ -39,6 +40,7 @@ from .api import (
39
40
  ui_config as ui_config_routes,
40
41
  data_explorer_table_prefs as data_explorer_table_prefs_routes,
41
42
  sanitization_ollama_config as sanitization_ollama_config_routes,
43
+ facts_llm_config as facts_llm_config_routes,
42
44
  signal_extraction_config as signal_extraction_config_routes,
43
45
  filter_lab as filter_lab_routes,
44
46
  enrichment_lab as enrichment_lab_routes,
@@ -106,6 +108,7 @@ app.include_router(device_routes.router)
106
108
  app.include_router(backup_routes.router)
107
109
  app.include_router(analytics_routes.router)
108
110
  app.include_router(sources_routes.router)
111
+ app.include_router(conversation_context_routes.router, prefix="/v1")
109
112
  app.include_router(source_install_routes.router, prefix="/v1")
110
113
  app.include_router(source_scrub_routes.router, prefix="/v1")
111
114
  app.include_router(intelligence_lifecycle_routes.router, prefix="/v1")
@@ -123,6 +126,7 @@ app.include_router(ui_config_routes.router)
123
126
  app.include_router(data_explorer_table_prefs_routes.router)
124
127
  app.include_router(user_identity_routes.router)
125
128
  app.include_router(sanitization_ollama_config_routes.router)
129
+ app.include_router(facts_llm_config_routes.router)
126
130
  app.include_router(signal_extraction_config_routes.router)
127
131
  app.include_router(filter_lab_routes.router)
128
132
  app.include_router(enrichment_lab_routes.router)
@@ -24,6 +24,7 @@ from __future__ import annotations
24
24
  import json
25
25
  from dataclasses import dataclass
26
26
  from typing import Any, Optional
27
+ from urllib.parse import urlparse
27
28
 
28
29
  from ...ingestion.parsers.base import NormalizedRecord
29
30
  from .base import CanonicalMapper, CanonicalRecord, MappingMetadata
@@ -77,6 +78,13 @@ class BrowserActivityCanonicalMapper(CanonicalMapper):
77
78
  "schema": payload.get("schema") or payload.get("schema_id"),
78
79
  }
79
80
  hostname = payload.get("hostname")
81
+ if not hostname and payload.get("url"):
82
+ # BT6 (PLAN_ATTENTION_TRIAGE.md): some plugin batches send url
83
+ # without hostname; derive it so downstream vocab never goes empty.
84
+ try:
85
+ hostname = urlparse(str(payload.get("url"))).hostname
86
+ except ValueError:
87
+ hostname = None
80
88
  if hostname:
81
89
  metadata["hostname"] = hostname
82
90
 
@@ -230,6 +230,10 @@ def main(db_path, topos_key, set_topos_key, discover, port, host, skip_update_ch
230
230
  os.environ["TOPOS_DATABASE_PATH"] = db_path
231
231
  click.echo(f"Database path: {db_path}")
232
232
 
233
+ from topos.runtime_housekeeping import start_background_housekeeping
234
+
235
+ start_background_housekeeping()
236
+
233
237
  _emit_startup_banner(host=host, port=port)
234
238
  uvicorn.run(app, host=host, port=port, log_config=get_uvicorn_log_config())
235
239
 
@@ -0,0 +1,106 @@
1
+ """Conversation-context classifier model: env default + per-node device override.
2
+
3
+ The owner picks which local model auto-categorizes new conversations as
4
+ work/personal (features.signal.conversation_context). Resolution order, first
5
+ non-empty wins — same contract as facts_llm:
6
+
7
+ 1. engine_config["conversation_context_llm_model"] — device override the UI
8
+ writes; takes effect on the next enrichment batch, no restart needed.
9
+ 2. Settings.ollama_extraction_model — the ingest-time extraction tier.
10
+ 3. Settings.ollama_query_model — the floor tier.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import logging
16
+ import sqlite3
17
+ from typing import Any, Dict, Optional
18
+
19
+ logger = logging.getLogger("topos.config.conversation_context_llm")
20
+
21
+ ENGINE_CONFIG_KEY_CONVERSATION_CONTEXT_LLM_MODEL = "conversation_context_llm_model"
22
+
23
+ _MAX_MODEL_NAME_LEN = 200
24
+
25
+
26
+ def _read_engine_config_value(conn: Optional[sqlite3.Connection], key: str) -> Optional[str]:
27
+ if conn is None:
28
+ return None
29
+ try:
30
+ row = conn.execute("SELECT value FROM engine_config WHERE key = ?", (key,)).fetchone()
31
+ if not row:
32
+ return None
33
+ try:
34
+ return str(row["value"]) # sqlite3.Row
35
+ except (TypeError, IndexError, KeyError):
36
+ return str(row[0])
37
+ except Exception: # noqa: BLE001 — missing table/row on fresh DB is not fatal
38
+ return None
39
+
40
+
41
+ def device_context_llm_model(conn: Optional[sqlite3.Connection]) -> str:
42
+ raw = _read_engine_config_value(conn, ENGINE_CONFIG_KEY_CONVERSATION_CONTEXT_LLM_MODEL)
43
+ return str(raw or "").strip()
44
+
45
+
46
+ def resolve_context_llm_model(settings: Any, conn: Optional[sqlite3.Connection] = None) -> str:
47
+ override = device_context_llm_model(conn)
48
+ if override:
49
+ return override
50
+ for attr in ("ollama_extraction_model", "ollama_query_model"):
51
+ value = str(getattr(settings, attr, "") or "").strip()
52
+ if value:
53
+ return value
54
+ return ""
55
+
56
+
57
+ def normalize_put_model(payload: Any) -> str:
58
+ """{"model": "<name>"} or bare string → stored value; empty clears."""
59
+ if payload is None:
60
+ return ""
61
+ if isinstance(payload, str):
62
+ model = payload
63
+ elif isinstance(payload, dict):
64
+ model = payload.get("model") or ""
65
+ else:
66
+ raise ValueError("body must be a JSON object with a 'model' string")
67
+ model = str(model).strip()
68
+ if len(model) > _MAX_MODEL_NAME_LEN:
69
+ raise ValueError(f"model name too long (max {_MAX_MODEL_NAME_LEN} chars)")
70
+ if model and any(ch in model for ch in " \t\n\r"):
71
+ raise ValueError("model name must not contain whitespace")
72
+ return model
73
+
74
+
75
+ def effective_config_for_api(settings: Any, conn: Optional[sqlite3.Connection]) -> Dict[str, Any]:
76
+ """Resolved classifier model + local model catalog for the settings picker."""
77
+ override = device_context_llm_model(conn)
78
+ effective = resolve_context_llm_model(settings, conn)
79
+ if override:
80
+ source = "device_override"
81
+ elif str(getattr(settings, "ollama_extraction_model", "") or "").strip():
82
+ source = "extraction_model_default"
83
+ else:
84
+ source = "query_model_fallback"
85
+
86
+ available = []
87
+ try:
88
+ from ..engine.backends.ollama import OllamaAdapter
89
+
90
+ adapter = OllamaAdapter()
91
+ for name in adapter.list_models():
92
+ available.append(
93
+ {
94
+ "name": name,
95
+ "supports_thinking": adapter.model_supports_thinking(name),
96
+ }
97
+ )
98
+ except Exception as exc: # noqa: BLE001 — catalog is a nicety, never a failure
99
+ logger.debug("context_llm available-model probe failed: %s", exc)
100
+
101
+ return {
102
+ "model": effective,
103
+ "override": override or None,
104
+ "source": source,
105
+ "available_models": available,
106
+ }