topos-node 1.2.3__tar.gz → 1.2.5__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 (546) hide show
  1. {topos_node-1.2.3/topos_node.egg-info → topos_node-1.2.5}/PKG-INFO +71 -1
  2. {topos_node-1.2.3 → topos_node-1.2.5}/README.md +70 -0
  3. {topos_node-1.2.3 → topos_node-1.2.5}/pyproject.toml +1 -1
  4. topos_node-1.2.5/tests/test_extensions.py +32 -0
  5. {topos_node-1.2.3 → topos_node-1.2.5}/topos/__version__.py +2 -2
  6. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/enrichment.py +105 -39
  7. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/llm.py +15 -0
  8. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/signal.py +15 -4
  9. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/source_install.py +2 -1
  10. topos_node-1.2.5/topos/api/tool_index.py +86 -0
  11. {topos_node-1.2.3 → topos_node-1.2.5}/topos/app.py +37 -0
  12. {topos_node-1.2.3 → topos_node-1.2.5}/topos/canonicalization/mappers/__init__.py +6 -0
  13. topos_node-1.2.5/topos/canonicalization/mappers/base.py +37 -0
  14. topos_node-1.2.5/topos/canonicalization/mappers/documents_mapper.py +43 -0
  15. topos_node-1.2.5/topos/canonicalization/mappers/github_activity_mapper.py +214 -0
  16. topos_node-1.2.5/topos/canonicalization/mappers/google_calendar_mapper.py +278 -0
  17. {topos_node-1.2.3 → topos_node-1.2.5}/topos/cli/commands.py +3 -0
  18. {topos_node-1.2.3 → topos_node-1.2.5}/topos/config/settings.py +2 -1
  19. {topos_node-1.2.3 → topos_node-1.2.5}/topos/control_plane_client.py +52 -0
  20. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/__init__.py +12 -0
  21. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/common.py +9 -1
  22. topos_node-1.2.5/topos/core/handlers/enrichment.py +362 -0
  23. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/home_chat.py +3 -2
  24. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/ingest.py +86 -133
  25. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/query.py +12 -3
  26. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/routines.py +27 -10
  27. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/signal_features.py +10 -5
  28. topos_node-1.2.5/topos/core/handlers/tool_index.py +97 -0
  29. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/state.py +22 -0
  30. {topos_node-1.2.3 → topos_node-1.2.5}/topos/data_explorer_tables.py +1 -0
  31. {topos_node-1.2.3 → topos_node-1.2.5}/topos/disclosure/field_registry.py +3 -0
  32. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/backends/huggingface.py +13 -1
  33. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/backends/ollama.py +19 -4
  34. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/backends/openai_compatible.py +24 -6
  35. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/engine.py +34 -0
  36. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/tasks.py +3 -0
  37. topos_node-1.2.5/topos/engine/usage_observation.py +406 -0
  38. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/catalog.py +4 -0
  39. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/derived_tables.py +13 -14
  40. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/job_writer.py +43 -1
  41. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/_batch_limits.py +1 -1
  42. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/_engine_runner.py +2 -1
  43. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/availability_scores_job.py +27 -2
  44. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/entities_job.py +103 -17
  45. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/fact_extraction_job.py +21 -2
  46. topos_node-1.2.5/topos/enrichment/jobs/canonical/timeline_job.py +44 -0
  47. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/models/mvp_defaults.py +5 -1
  48. topos_node-1.2.5/topos/extensions.py +41 -0
  49. topos_node-1.2.5/topos/features/entities/declared_mappings.py +156 -0
  50. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/edges.py +60 -8
  51. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/fact_materializer.py +87 -2
  52. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/graph_enrichers.py +6 -27
  53. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/graph_refresh.py +63 -1
  54. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/reads.py +6 -2
  55. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/resolver.py +23 -2
  56. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/facts/llm_extract.py +325 -91
  57. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/lifecycle/derived_scrub.py +32 -14
  58. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/brief_canonical_loader.py +2 -1
  59. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/cluster_labels.py +3 -2
  60. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/structured_signal.py +2 -0
  61. topos_node-1.2.5/topos/features/signal/tool_index.py +332 -0
  62. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/topic_clustering.py +51 -40
  63. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/stats/definitions.py +10 -1
  64. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/stats/engine.py +2 -0
  65. topos_node-1.2.5/topos/features/timeline_projection.py +353 -0
  66. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/canonical_pipeline.py +50 -9
  67. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/ingest_helpers.py +20 -2
  68. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/local_sync.py +11 -0
  69. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/manager.py +7 -2
  70. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/__init__.py +8 -0
  71. topos_node-1.2.5/topos/ingestion/parsers/documents_parser.py +77 -0
  72. topos_node-1.2.5/topos/ingestion/parsers/google_calendar_parser.py +52 -0
  73. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/usage_inbox_dedupe.py +48 -0
  74. {topos_node-1.2.3 → topos_node-1.2.5}/topos/llm_integrations_storage.py +167 -50
  75. topos_node-1.2.5/topos/pipeline/job_runner.py +242 -0
  76. topos_node-1.2.5/topos/pipeline/job_store.py +310 -0
  77. {topos_node-1.2.3 → topos_node-1.2.5}/topos/protocol/handled_message_types.json +3 -0
  78. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/retrieval.py +5 -8
  79. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/scope_registry.json +61 -7
  80. topos_node-1.2.5/topos/runtime_shutdown.py +86 -0
  81. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sanitization/nsfw_classifier.py +12 -0
  82. topos_node-1.2.5/topos/sanitization/prewarm.py +32 -0
  83. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sanitization/privacy_filter.py +10 -0
  84. {topos_node-1.2.3 → topos_node-1.2.5}/topos/scope_resolution.py +2 -0
  85. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sources/bundled_canonical_triples.py +4 -0
  86. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sources/definitions.py +48 -0
  87. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sources/install_service.py +11 -5
  88. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sources/registry.py +118 -9
  89. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sources/scrub_attribution.py +88 -0
  90. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/adapters/factory.py +19 -2
  91. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/adapters/sqlite/stores.py +18 -15
  92. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/canonical_store.py +104 -6
  93. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/conversations_tables.py +13 -3
  94. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/connection_tuning.py +1 -1
  95. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/__init__.py +30 -0
  96. topos_node-1.2.5/topos/storage/db/migrations/calendar_events_scheduling_v1.py +101 -0
  97. topos_node-1.2.5/topos/storage/db/migrations/canonical_address_book_v1.py +103 -0
  98. topos_node-1.2.5/topos/storage/db/migrations/documents_v1.py +58 -0
  99. topos_node-1.2.5/topos/storage/db/migrations/pipeline_jobs_v1.py +75 -0
  100. topos_node-1.2.5/topos/storage/db/write_gate.py +110 -0
  101. {topos_node-1.2.3 → topos_node-1.2.5/topos_node.egg-info}/PKG-INFO +71 -1
  102. {topos_node-1.2.3 → topos_node-1.2.5}/topos_node.egg-info/SOURCES.txt +20 -0
  103. topos_node-1.2.3/topos/canonicalization/mappers/base.py +0 -26
  104. topos_node-1.2.3/topos/canonicalization/mappers/github_activity_mapper.py +0 -112
  105. topos_node-1.2.3/topos/core/handlers/enrichment.py +0 -582
  106. topos_node-1.2.3/topos/engine/usage_observation.py +0 -129
  107. topos_node-1.2.3/topos/enrichment/jobs/canonical/timeline_job.py +0 -67
  108. {topos_node-1.2.3 → topos_node-1.2.5}/LICENSE +0 -0
  109. {topos_node-1.2.3 → topos_node-1.2.5}/MANIFEST.in +0 -0
  110. {topos_node-1.2.3 → topos_node-1.2.5}/setup.cfg +0 -0
  111. {topos_node-1.2.3 → topos_node-1.2.5}/shared/__init__.py +0 -0
  112. {topos_node-1.2.3 → topos_node-1.2.5}/shared/filtering.py +0 -0
  113. {topos_node-1.2.3 → topos_node-1.2.5}/shared/schema_registry.py +0 -0
  114. {topos_node-1.2.3 → topos_node-1.2.5}/tests/test_llm_integrations_storage.py +0 -0
  115. {topos_node-1.2.3 → topos_node-1.2.5}/tests/test_protocol_handled_types.py +0 -0
  116. {topos_node-1.2.3 → topos_node-1.2.5}/topos/__init__.py +0 -0
  117. {topos_node-1.2.3 → topos_node-1.2.5}/topos/analytics/__init__.py +0 -0
  118. {topos_node-1.2.3 → topos_node-1.2.5}/topos/analytics/duckdb_adapter.py +0 -0
  119. {topos_node-1.2.3 → topos_node-1.2.5}/topos/analytics/messenger_communities.py +0 -0
  120. {topos_node-1.2.3 → topos_node-1.2.5}/topos/analytics/messenger_graph.py +0 -0
  121. {topos_node-1.2.3 → topos_node-1.2.5}/topos/analytics/messenger_labels.py +0 -0
  122. {topos_node-1.2.3 → topos_node-1.2.5}/topos/analytics/profiles.py +0 -0
  123. {topos_node-1.2.3 → topos_node-1.2.5}/topos/analytics/query_engine.py +0 -0
  124. {topos_node-1.2.3 → topos_node-1.2.5}/topos/analytics/raw_queries.py +0 -0
  125. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/__init__.py +0 -0
  126. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/analytics.py +0 -0
  127. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/app_registry.py +0 -0
  128. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/backup.py +0 -0
  129. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/compute_remote.py +0 -0
  130. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/data_commit.py +0 -0
  131. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/data_explorer_table_prefs.py +0 -0
  132. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/database_explorer.py +0 -0
  133. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/db.py +0 -0
  134. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/device.py +0 -0
  135. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/engine_run.py +0 -0
  136. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/enrichment_lab.py +0 -0
  137. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/filter_lab.py +0 -0
  138. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/health.py +0 -0
  139. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/home_chat.py +0 -0
  140. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/ingestion_api.py +0 -0
  141. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/ingestion_compat.py +0 -0
  142. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/ingestion_sources.py +0 -0
  143. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/intelligence_lifecycle.py +0 -0
  144. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/local_mcp.py +0 -0
  145. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/messenger_analytics.py +0 -0
  146. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/privacy_disclose.py +0 -0
  147. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/query_api.py +0 -0
  148. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/runtime_bootstrap.py +0 -0
  149. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/sanitization_ollama_config.py +0 -0
  150. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/signal_extraction_config.py +0 -0
  151. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/source_scrub.py +0 -0
  152. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/sources.py +0 -0
  153. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/sources_overview.py +0 -0
  154. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/sync.py +0 -0
  155. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/ui_config.py +0 -0
  156. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/uma_data.py +0 -0
  157. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/upgrades.py +0 -0
  158. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/usage.py +0 -0
  159. {topos_node-1.2.3 → topos_node-1.2.5}/topos/api/user_identity.py +0 -0
  160. {topos_node-1.2.3 → topos_node-1.2.5}/topos/auth.py +0 -0
  161. {topos_node-1.2.3 → topos_node-1.2.5}/topos/canonicalization/__init__.py +0 -0
  162. {topos_node-1.2.3 → topos_node-1.2.5}/topos/canonicalization/mappers/browser_activity_mapper.py +0 -0
  163. {topos_node-1.2.3 → topos_node-1.2.5}/topos/canonicalization/mappers/chatgpt_mapper.py +0 -0
  164. {topos_node-1.2.3 → topos_node-1.2.5}/topos/canonicalization/mappers/demo_mappers.py +0 -0
  165. {topos_node-1.2.3 → topos_node-1.2.5}/topos/canonicalization/mappers/grok_mapper.py +0 -0
  166. {topos_node-1.2.3 → topos_node-1.2.5}/topos/canonicalization/mappers/messenger_mapper.py +0 -0
  167. {topos_node-1.2.3 → topos_node-1.2.5}/topos/canonicalization/models.py +0 -0
  168. {topos_node-1.2.3 → topos_node-1.2.5}/topos/canonicalization/resolver.py +0 -0
  169. {topos_node-1.2.3 → topos_node-1.2.5}/topos/cli/__init__.py +0 -0
  170. {topos_node-1.2.3 → topos_node-1.2.5}/topos/cli/__main__.py +0 -0
  171. {topos_node-1.2.3 → topos_node-1.2.5}/topos/config/__init__.py +0 -0
  172. {topos_node-1.2.3 → topos_node-1.2.5}/topos/config/sanitization_ollama.py +0 -0
  173. {topos_node-1.2.3 → topos_node-1.2.5}/topos/config/signal_extraction.py +0 -0
  174. {topos_node-1.2.3 → topos_node-1.2.5}/topos/config/uvicorn_logging.json +0 -0
  175. {topos_node-1.2.3 → topos_node-1.2.5}/topos/contacts/__init__.py +0 -0
  176. {topos_node-1.2.3 → topos_node-1.2.5}/topos/contacts/identity.py +0 -0
  177. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/__init__.py +0 -0
  178. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/api_models.py +0 -0
  179. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/connection_resilience.py +0 -0
  180. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/device_helpers.py +0 -0
  181. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/errors.py +0 -0
  182. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/events.py +0 -0
  183. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/config.py +0 -0
  184. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/contacts_import.py +0 -0
  185. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/database_explorer.py +0 -0
  186. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/device.py +0 -0
  187. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/enrichment_lab.py +0 -0
  188. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/filter_lab.py +0 -0
  189. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/messages.py +0 -0
  190. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/messenger_analytics.py +0 -0
  191. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/registry.py +0 -0
  192. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/sources.py +0 -0
  193. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/handlers/uma.py +0 -0
  194. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/logging.py +0 -0
  195. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/metrics.py +0 -0
  196. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/routine_access.py +0 -0
  197. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/startup_banner.py +0 -0
  198. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/table_layers.py +0 -0
  199. {topos_node-1.2.3 → topos_node-1.2.5}/topos/core/types.py +0 -0
  200. {topos_node-1.2.3 → topos_node-1.2.5}/topos/data_explorer_row_delete.py +0 -0
  201. {topos_node-1.2.3 → topos_node-1.2.5}/topos/data_explorer_table_prefs.py +0 -0
  202. {topos_node-1.2.3 → topos_node-1.2.5}/topos/disclosure/__init__.py +0 -0
  203. {topos_node-1.2.3 → topos_node-1.2.5}/topos/disclosure/canonical_writer.py +0 -0
  204. {topos_node-1.2.3 → topos_node-1.2.5}/topos/disclosure/content_policy.py +0 -0
  205. {topos_node-1.2.3 → topos_node-1.2.5}/topos/disclosure/privacy_layer.py +0 -0
  206. {topos_node-1.2.3 → topos_node-1.2.5}/topos/disclosure/tier.py +0 -0
  207. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/__init__.py +0 -0
  208. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/backends/__init__.py +0 -0
  209. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/backends/base.py +0 -0
  210. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/backends/generative_prompts.py +0 -0
  211. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/backends/generative_response.py +0 -0
  212. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/backends/openai.py +0 -0
  213. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/backends/redpill.py +0 -0
  214. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/backends/stub.py +0 -0
  215. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/client.py +0 -0
  216. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/intake.py +0 -0
  217. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/memory_utils.py +0 -0
  218. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/model_cache.py +0 -0
  219. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/pipeline_memory.py +0 -0
  220. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/queue_manager.py +0 -0
  221. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/registration.py +0 -0
  222. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/result_formatter.py +0 -0
  223. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/router.py +0 -0
  224. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/scoped_token.py +0 -0
  225. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/transport.py +0 -0
  226. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/usage_guard.py +0 -0
  227. {topos_node-1.2.3 → topos_node-1.2.5}/topos/engine/validator.py +0 -0
  228. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/__init__.py +0 -0
  229. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/__init__.py +0 -0
  230. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/base.py +0 -0
  231. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/__init__.py +0 -0
  232. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/brief_fallback.py +0 -0
  233. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/dimension_summary_job.py +0 -0
  234. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/embeddings_job.py +0 -0
  235. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/emo_27_job.py +0 -0
  236. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/goal_extraction_job.py +0 -0
  237. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/pii_redaction_job.py +0 -0
  238. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/relationship_edges_job.py +0 -0
  239. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/sentiment_job.py +0 -0
  240. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/statistics_job.py +0 -0
  241. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/topic_clusters_job.py +0 -0
  242. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/topics_job.py +0 -0
  243. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/url_classification_core.py +0 -0
  244. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/url_classification_enrichment_job.py +0 -0
  245. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/canonical/url_classification_signal_job.py +0 -0
  246. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/raw/__init__.py +0 -0
  247. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
  248. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/raw/language_job.py +0 -0
  249. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
  250. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
  251. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/model_overrides.py +0 -0
  252. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/models/__init__.py +0 -0
  253. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/models/manager.py +0 -0
  254. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/models/registry.py +0 -0
  255. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/models/versioning.py +0 -0
  256. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/orchestrator.py +0 -0
  257. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/processor.py +0 -0
  258. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/progress_bar.py +0 -0
  259. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/registry_contract.py +0 -0
  260. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/signal_derivation_config.json +0 -0
  261. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/source_overrides.py +0 -0
  262. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment/website_classifier.py +0 -0
  263. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment_lab/__init__.py +0 -0
  264. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment_lab/bundles.py +0 -0
  265. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment_lab/model_resolve.py +0 -0
  266. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment_lab/schema.py +0 -0
  267. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment_lab/service.py +0 -0
  268. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment_lab/store.py +0 -0
  269. {topos_node-1.2.3 → topos_node-1.2.5}/topos/enrichment_lab/worker.py +0 -0
  270. {topos_node-1.2.3 → topos_node-1.2.5}/topos/evals/__init__.py +0 -0
  271. {topos_node-1.2.3 → topos_node-1.2.5}/topos/evals/enrichment_eval.py +0 -0
  272. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/__init__.py +0 -0
  273. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/consolidation.py +0 -0
  274. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/dossier.py +0 -0
  275. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/graph_search.py +0 -0
  276. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/linking.py +0 -0
  277. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/entities/maintenance.py +0 -0
  278. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/facts/__init__.py +0 -0
  279. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/facts/extract.py +0 -0
  280. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/facts/reads.py +0 -0
  281. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/facts/store.py +0 -0
  282. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/fit/evaluator.py +0 -0
  283. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/fit/opportunity_types.json +0 -0
  284. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/lifecycle/__init__.py +0 -0
  285. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/lifecycle/exclusions.py +0 -0
  286. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/lifecycle/gc.py +0 -0
  287. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/provenance/__init__.py +0 -0
  288. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/provenance/posture.py +0 -0
  289. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/provenance/roles.py +0 -0
  290. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/__init__.py +0 -0
  291. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/brief_ontology.py +0 -0
  292. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/brief_renderer.py +0 -0
  293. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/brief_schemas.py +0 -0
  294. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/chunking.py +0 -0
  295. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/data_health.py +0 -0
  296. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/definitions/brief_ontologies.json +0 -0
  297. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/definitions/intentions.json +0 -0
  298. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/definitions/profile.json +0 -0
  299. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/definitions/relationships.json +0 -0
  300. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/definitions/schema/dimension_definition.schema.json +0 -0
  301. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/definitions/time.json +0 -0
  302. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/definitions/work.json +0 -0
  303. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/dimension_briefs.py +0 -0
  304. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/dimension_definition_loader.py +0 -0
  305. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/dimension_profiles.py +0 -0
  306. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/dimension_registry.py +0 -0
  307. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/embed_context.py +0 -0
  308. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/extraction/artifact_router.py +0 -0
  309. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/extraction/artifact_store.py +0 -0
  310. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/extraction/rule_extractors.py +0 -0
  311. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/graph_sanitize.py +0 -0
  312. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/hybrid_search.py +0 -0
  313. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/incremental_clustering.py +0 -0
  314. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/model_recommendations.py +0 -0
  315. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/query_embed_cache.py +0 -0
  316. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/schemas.py +0 -0
  317. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/service.py +0 -0
  318. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/signal_object_store.py +0 -0
  319. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/source_hydration.py +0 -0
  320. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/typed_stores/aggregates.py +0 -0
  321. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/typed_stores/scope_materializer.py +0 -0
  322. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/vector_codec.py +0 -0
  323. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/vector_math.py +0 -0
  324. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/signal/vector_settings.py +0 -0
  325. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/stats/__init__.py +0 -0
  326. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/stats/fold.py +0 -0
  327. {topos_node-1.2.3 → topos_node-1.2.5}/topos/features/stats/insights.py +0 -0
  328. {topos_node-1.2.3 → topos_node-1.2.5}/topos/filter_lab/__init__.py +0 -0
  329. {topos_node-1.2.3 → topos_node-1.2.5}/topos/filter_lab/bundles.py +0 -0
  330. {topos_node-1.2.3 → topos_node-1.2.5}/topos/filter_lab/schema.py +0 -0
  331. {topos_node-1.2.3 → topos_node-1.2.5}/topos/filter_lab/service.py +0 -0
  332. {topos_node-1.2.3 → topos_node-1.2.5}/topos/filter_lab/store.py +0 -0
  333. {topos_node-1.2.3 → topos_node-1.2.5}/topos/filter_lab/worker.py +0 -0
  334. {topos_node-1.2.3 → topos_node-1.2.5}/topos/home_chat/__init__.py +0 -0
  335. {topos_node-1.2.3 → topos_node-1.2.5}/topos/home_chat/schema.py +0 -0
  336. {topos_node-1.2.3 → topos_node-1.2.5}/topos/home_chat/store.py +0 -0
  337. {topos_node-1.2.3 → topos_node-1.2.5}/topos/hosted_pool_lease.py +0 -0
  338. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/__init__.py +0 -0
  339. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/checkpoints/__init__.py +0 -0
  340. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
  341. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
  342. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/inbox_crypto.py +0 -0
  343. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/inbox_drain.py +0 -0
  344. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/jobs.py +0 -0
  345. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/journal_location_fanout.py +0 -0
  346. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/journal_time_log_normalize.py +0 -0
  347. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/log_preview.py +0 -0
  348. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parser.py +0 -0
  349. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/base.py +0 -0
  350. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/browser_parser.py +0 -0
  351. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/calendar_parser.py +0 -0
  352. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
  353. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
  354. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/demo_file_parsers.py +0 -0
  355. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/github_activity_parser.py +0 -0
  356. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/grok_parser.py +0 -0
  357. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/messenger_parser.py +0 -0
  358. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/parsers/voxterm_parser.py +0 -0
  359. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/progress.py +0 -0
  360. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/reprocess.py +0 -0
  361. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/sources/__init__.py +0 -0
  362. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/sources/base.py +0 -0
  363. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/sources/calendar.py +0 -0
  364. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/sources/chatgpt.py +0 -0
  365. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/sources/contact_importers.py +0 -0
  366. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/sources/grok.py +0 -0
  367. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/sources/imessage_reader.py +0 -0
  368. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/sources/signal_export_parser.py +0 -0
  369. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/sources/signal_reader.py +0 -0
  370. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/state_machine.py +0 -0
  371. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/triggers/__init__.py +0 -0
  372. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/triggers/file_trigger.py +0 -0
  373. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
  374. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/validation/__init__.py +0 -0
  375. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/validation/base.py +0 -0
  376. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/validation/schema_registry.py +0 -0
  377. {topos_node-1.2.3 → topos_node-1.2.5}/topos/ingestion/validation/schema_validator.py +0 -0
  378. {topos_node-1.2.3 → topos_node-1.2.5}/topos/lineage/__init__.py +0 -0
  379. {topos_node-1.2.3 → topos_node-1.2.5}/topos/lineage/provenance.py +0 -0
  380. {topos_node-1.2.3 → topos_node-1.2.5}/topos/lineage/tracker.py +0 -0
  381. {topos_node-1.2.3 → topos_node-1.2.5}/topos/mcp_stdio_proxy.py +0 -0
  382. {topos_node-1.2.3 → topos_node-1.2.5}/topos/observability/__init__.py +0 -0
  383. {topos_node-1.2.3 → topos_node-1.2.5}/topos/observability/alerts.py +0 -0
  384. {topos_node-1.2.3 → topos_node-1.2.5}/topos/observability/metrics.py +0 -0
  385. {topos_node-1.2.3 → topos_node-1.2.5}/topos/observability/tracing.py +0 -0
  386. {topos_node-1.2.3 → topos_node-1.2.5}/topos/openai_client.py +0 -0
  387. {topos_node-1.2.3 → topos_node-1.2.5}/topos/pipeline/__init__.py +0 -0
  388. {topos_node-1.2.3 → topos_node-1.2.5}/topos/pipeline/audit.py +0 -0
  389. {topos_node-1.2.3 → topos_node-1.2.5}/topos/pipeline/envelope.py +0 -0
  390. {topos_node-1.2.3 → topos_node-1.2.5}/topos/pipeline/stages.py +0 -0
  391. {topos_node-1.2.3 → topos_node-1.2.5}/topos/pipeline/stub_enqueue.py +0 -0
  392. {topos_node-1.2.3 → topos_node-1.2.5}/topos/projections/__init__.py +0 -0
  393. {topos_node-1.2.3 → topos_node-1.2.5}/topos/projections/vector_index/__init__.py +0 -0
  394. {topos_node-1.2.3 → topos_node-1.2.5}/topos/projections/vector_index/base.py +0 -0
  395. {topos_node-1.2.3 → topos_node-1.2.5}/topos/projections/vector_index/builders.py +0 -0
  396. {topos_node-1.2.3 → topos_node-1.2.5}/topos/projections/vector_index/health_checks.py +0 -0
  397. {topos_node-1.2.3 → topos_node-1.2.5}/topos/protocol/__init__.py +0 -0
  398. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/__init__.py +0 -0
  399. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/audit.py +0 -0
  400. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/ddr.py +0 -0
  401. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/disclosure.py +0 -0
  402. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/fingerprint.py +0 -0
  403. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/game_layer.py +0 -0
  404. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/grant_cache.py +0 -0
  405. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/inference.py +0 -0
  406. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/intent.py +0 -0
  407. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/manifest.py +0 -0
  408. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/manifest_validation.py +0 -0
  409. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/minimizer.py +0 -0
  410. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/negotiation.py +0 -0
  411. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/pipeline.py +0 -0
  412. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/planner.py +0 -0
  413. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/runtime.py +0 -0
  414. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/scope_registry_loader.py +0 -0
  415. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/session.py +0 -0
  416. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/session_utils.py +0 -0
  417. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/source_generation.py +0 -0
  418. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/turn_classifier.py +0 -0
  419. {topos_node-1.2.3 → topos_node-1.2.5}/topos/query/types.py +0 -0
  420. {topos_node-1.2.3 → topos_node-1.2.5}/topos/rate_limit.py +0 -0
  421. {topos_node-1.2.3 → topos_node-1.2.5}/topos/routines/__init__.py +0 -0
  422. {topos_node-1.2.3 → topos_node-1.2.5}/topos/routines/schema.py +0 -0
  423. {topos_node-1.2.3 → topos_node-1.2.5}/topos/routines/store.py +0 -0
  424. {topos_node-1.2.3 → topos_node-1.2.5}/topos/runtime_update.py +0 -0
  425. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sanitization/__init__.py +0 -0
  426. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sanitization/ollama_transforms.py +0 -0
  427. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/__init__.py +0 -0
  428. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/container.py +0 -0
  429. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/embeddings/__init__.py +0 -0
  430. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/embeddings/base.py +0 -0
  431. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/embeddings/local.py +0 -0
  432. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/embeddings/remote.py +0 -0
  433. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/interfaces.py +0 -0
  434. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/llm/__init__.py +0 -0
  435. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/llm/base.py +0 -0
  436. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/llm/openai.py +0 -0
  437. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/local.py +0 -0
  438. {topos_node-1.2.3 → topos_node-1.2.5}/topos/services/postgres.py +0 -0
  439. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sources/__init__.py +0 -0
  440. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sources/canonical_signal_defaults.py +0 -0
  441. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sources/runtime_install.py +0 -0
  442. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sources/scrub_service.py +0 -0
  443. {topos_node-1.2.3 → topos_node-1.2.5}/topos/startup_banner.py +0 -0
  444. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/__init__.py +0 -0
  445. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/adapters/__init__.py +0 -0
  446. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/adapters/fakes.py +0 -0
  447. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/adapters/postgres/stores.py +0 -0
  448. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/adapters/protocols.py +0 -0
  449. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/adapters/sqlite/__init__.py +0 -0
  450. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/adapters/sqlite/vector_search.py +0 -0
  451. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/__init__.py +0 -0
  452. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/activity_tables.py +0 -0
  453. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/ai_chat/__init__.py +0 -0
  454. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/ai_chat/canonicalizer.py +0 -0
  455. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/ai_chat/mapper.py +0 -0
  456. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/ai_chat/model.py +0 -0
  457. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/ai_chat/tables.py +0 -0
  458. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/calendar_contacts_tables.py +0 -0
  459. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/mapping_store.py +0 -0
  460. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/canonical/postgres.py +0 -0
  461. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/__init__.py +0 -0
  462. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/client.py +0 -0
  463. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/activity_events_content_v1.py +0 -0
  464. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/actor_role_v1.py +0 -0
  465. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/canonical_disclosure_v1.py +0 -0
  466. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/canonical_nsfw_v1.py +0 -0
  467. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/derivation_ledger_v1.py +0 -0
  468. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/entity_edges_validity_v1.py +0 -0
  469. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/episodes_v1.py +0 -0
  470. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/extraction_artifacts.py +0 -0
  471. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/journal_entries_duration_v1.py +0 -0
  472. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/journal_entries_ends_at_v1.py +0 -0
  473. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/journal_entries_people_v1.py +0 -0
  474. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/journal_entries_place_name_v1.py +0 -0
  475. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/journal_entries_starts_at_v1.py +0 -0
  476. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/remediation_person_model.py +0 -0
  477. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/scope_source_generation.py +0 -0
  478. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/signal_dimension_backfill_v1.py +0 -0
  479. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/signal_dimension_harness.py +0 -0
  480. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/signal_objects.py +0 -0
  481. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/signal_objects_period_v1.py +0 -0
  482. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/signal_objects_updated_by_v1.py +0 -0
  483. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
  484. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/vector_storage_v1.py +0 -0
  485. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/vector_storage_v2.py +0 -0
  486. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/vector_storage_v3.py +0 -0
  487. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/vector_storage_v4.py +0 -0
  488. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_clusters_v2.py +0 -0
  489. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_entities_v1.py +0 -0
  490. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_entity_review_v2.py +0 -0
  491. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_facts_v1.py +0 -0
  492. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_lifecycle_v1.py +0 -0
  493. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_mvp_phase0.py +0 -0
  494. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_mvp_phase1.py +0 -0
  495. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +0 -0
  496. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +0 -0
  497. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +0 -0
  498. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_mvp_query_quality.py +0 -0
  499. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +0 -0
  500. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_stats_v1.py +0 -0
  501. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/migrations/wiki_timeline_v1.py +0 -0
  502. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/paths.py +0 -0
  503. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/postgres.py +0 -0
  504. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/schema.py +0 -0
  505. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/db/storage_breakdown.py +0 -0
  506. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/enrichment/__init__.py +0 -0
  507. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
  508. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
  509. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/normalized/__init__.py +0 -0
  510. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/normalized/normalized_store.py +0 -0
  511. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/oplog/__init__.py +0 -0
  512. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/oplog/decision.py +0 -0
  513. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/oplog/oplog_store.py +0 -0
  514. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/oplog/postgres.py +0 -0
  515. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/person/identity_resolver.py +0 -0
  516. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/projections/__init__.py +0 -0
  517. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/projections/index_ops_store.py +0 -0
  518. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/projections/vector_index_store.py +0 -0
  519. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/raw/__init__.py +0 -0
  520. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/raw/browser_flat_tables.py +0 -0
  521. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/raw/file_store.py +0 -0
  522. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/raw/raw_store.py +0 -0
  523. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/raw/raw_tables_manager.py +0 -0
  524. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/raw/sqlite_raw_store.py +0 -0
  525. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/security/encryption.py +0 -0
  526. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/signal_identity.py +0 -0
  527. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/source_settings.py +0 -0
  528. {topos_node-1.2.3 → topos_node-1.2.5}/topos/storage/user_identity.py +0 -0
  529. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sync/__init__.py +0 -0
  530. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sync/client.py +0 -0
  531. {topos_node-1.2.3 → topos_node-1.2.5}/topos/sync_handlers.py +0 -0
  532. {topos_node-1.2.3 → topos_node-1.2.5}/topos/testing/__init__.py +0 -0
  533. {topos_node-1.2.3 → topos_node-1.2.5}/topos/testing/lifespan.py +0 -0
  534. {topos_node-1.2.3 → topos_node-1.2.5}/topos/uma_contact_enrichment.py +0 -0
  535. {topos_node-1.2.3 → topos_node-1.2.5}/topos/uma_filters.py +0 -0
  536. {topos_node-1.2.3 → topos_node-1.2.5}/topos/uma_resource_id.py +0 -0
  537. {topos_node-1.2.3 → topos_node-1.2.5}/topos/uma_rpt.py +0 -0
  538. {topos_node-1.2.3 → topos_node-1.2.5}/topos/upgrades/__init__.py +0 -0
  539. {topos_node-1.2.3 → topos_node-1.2.5}/topos/upgrades/manifests.json +0 -0
  540. {topos_node-1.2.3 → topos_node-1.2.5}/topos/upgrades/runner.py +0 -0
  541. {topos_node-1.2.3 → topos_node-1.2.5}/topos/utils/base_object.py +0 -0
  542. {topos_node-1.2.3 → topos_node-1.2.5}/topos/websocket_client.py +0 -0
  543. {topos_node-1.2.3 → topos_node-1.2.5}/topos_node.egg-info/dependency_links.txt +0 -0
  544. {topos_node-1.2.3 → topos_node-1.2.5}/topos_node.egg-info/entry_points.txt +0 -0
  545. {topos_node-1.2.3 → topos_node-1.2.5}/topos_node.egg-info/requires.txt +0 -0
  546. {topos_node-1.2.3 → topos_node-1.2.5}/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.3
3
+ Version: 1.2.5
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
@@ -213,6 +213,76 @@ pip install -e ".[dev,engine]"
213
213
  pytest tests -m "public and not e2e" -q
214
214
  ```
215
215
 
216
+ ## Plugins
217
+
218
+ Topos Node supports **optional plugins**: separate Python packages installed alongside
219
+ `topos-node` that register handlers, connectors, or other runtime hooks. The core node
220
+ does not hardcode plugin names — discovery is entirely via setuptools entry points.
221
+
222
+ ### Contract: `topos.extensions`
223
+
224
+ | Rule | Detail |
225
+ | --- | --- |
226
+ | **Entry-point group** | `topos.extensions` |
227
+ | **Entry-point target** | A callable, e.g. `my_plugin:register` |
228
+ | **When it runs** | At process startup, before the server accepts traffic (`topos/extensions.py`) |
229
+ | **Failure mode** | A broken plugin is logged and skipped; the node keeps running |
230
+ | **Dependencies** | Your plugin declares `topos-node` (or `topos-node[local]`) in its own `pyproject.toml` |
231
+
232
+ **Minimal plugin**
233
+
234
+ `pyproject.toml`:
235
+
236
+ ```toml
237
+ [project]
238
+ name = "my-topos-plugin"
239
+ dependencies = ["topos-node[local]"]
240
+
241
+ [project.entry-points."topos.extensions"]
242
+ my_plugin = "my_topos_plugin:register"
243
+ ```
244
+
245
+ `my_topos_plugin/__init__.py`:
246
+
247
+ ```python
248
+ def register() -> None:
249
+ from my_topos_plugin.handlers import example # noqa: F401 — registers @handles
250
+ ```
251
+
252
+ `my_topos_plugin/handlers/example.py`:
253
+
254
+ ```python
255
+ from typing import Any, Dict, Optional
256
+ from topos.core.handlers.registry import handles
257
+
258
+ @handles("my_message_type")
259
+ async def handle_my_message(message: Dict[str, Any]) -> Optional[Dict[str, Any]]:
260
+ return {"status": "ok", "payload": {"received": message.get("type")}}
261
+ ```
262
+
263
+ **Install and run**
264
+
265
+ ```bash
266
+ pip install topos-node my-topos-plugin
267
+ topos-node
268
+ ```
269
+
270
+ Handlers registered in `register()` are available to the control-plane WebSocket
271
+ and local API paths that dispatch through `topos.core.handlers`.
272
+
273
+ ### Starter template
274
+
275
+ Fork **[dialoguesai/topos-plugin-template](https://github.com/dialoguesai/topos-plugin-template)**
276
+ for a working package with tests and CI. It registers a sample `plugin_template_ping`
277
+ handler you can copy and rename.
278
+
279
+ ### Guidelines
280
+
281
+ - Use **unique message type names** (prefix with your project) to avoid colliding with core handlers.
282
+ - Keep plugins in **separate repositories** — do not add proprietary logic to this repo.
283
+ - Message types your plugin handles do not need to appear in the public engine protocol
284
+ snapshot unless the hosted control plane will send them to all nodes.
285
+
216
286
  ## Contributing
217
287
 
218
288
  See `CONTRIBUTING.md` for:
@@ -156,6 +156,76 @@ pip install -e ".[dev,engine]"
156
156
  pytest tests -m "public and not e2e" -q
157
157
  ```
158
158
 
159
+ ## Plugins
160
+
161
+ Topos Node supports **optional plugins**: separate Python packages installed alongside
162
+ `topos-node` that register handlers, connectors, or other runtime hooks. The core node
163
+ does not hardcode plugin names — discovery is entirely via setuptools entry points.
164
+
165
+ ### Contract: `topos.extensions`
166
+
167
+ | Rule | Detail |
168
+ | --- | --- |
169
+ | **Entry-point group** | `topos.extensions` |
170
+ | **Entry-point target** | A callable, e.g. `my_plugin:register` |
171
+ | **When it runs** | At process startup, before the server accepts traffic (`topos/extensions.py`) |
172
+ | **Failure mode** | A broken plugin is logged and skipped; the node keeps running |
173
+ | **Dependencies** | Your plugin declares `topos-node` (or `topos-node[local]`) in its own `pyproject.toml` |
174
+
175
+ **Minimal plugin**
176
+
177
+ `pyproject.toml`:
178
+
179
+ ```toml
180
+ [project]
181
+ name = "my-topos-plugin"
182
+ dependencies = ["topos-node[local]"]
183
+
184
+ [project.entry-points."topos.extensions"]
185
+ my_plugin = "my_topos_plugin:register"
186
+ ```
187
+
188
+ `my_topos_plugin/__init__.py`:
189
+
190
+ ```python
191
+ def register() -> None:
192
+ from my_topos_plugin.handlers import example # noqa: F401 — registers @handles
193
+ ```
194
+
195
+ `my_topos_plugin/handlers/example.py`:
196
+
197
+ ```python
198
+ from typing import Any, Dict, Optional
199
+ from topos.core.handlers.registry import handles
200
+
201
+ @handles("my_message_type")
202
+ async def handle_my_message(message: Dict[str, Any]) -> Optional[Dict[str, Any]]:
203
+ return {"status": "ok", "payload": {"received": message.get("type")}}
204
+ ```
205
+
206
+ **Install and run**
207
+
208
+ ```bash
209
+ pip install topos-node my-topos-plugin
210
+ topos-node
211
+ ```
212
+
213
+ Handlers registered in `register()` are available to the control-plane WebSocket
214
+ and local API paths that dispatch through `topos.core.handlers`.
215
+
216
+ ### Starter template
217
+
218
+ Fork **[dialoguesai/topos-plugin-template](https://github.com/dialoguesai/topos-plugin-template)**
219
+ for a working package with tests and CI. It registers a sample `plugin_template_ping`
220
+ handler you can copy and rename.
221
+
222
+ ### Guidelines
223
+
224
+ - Use **unique message type names** (prefix with your project) to avoid colliding with core handlers.
225
+ - Keep plugins in **separate repositories** — do not add proprietary logic to this repo.
226
+ - Message types your plugin handles do not need to appear in the public engine protocol
227
+ snapshot unless the hosted control plane will send them to all nodes.
228
+
159
229
  ## Contributing
160
230
 
161
231
  See `CONTRIBUTING.md` for:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "topos-node"
7
- version = "1.2.3"
7
+ version = "1.2.5"
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"
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+
5
+ from topos.core.handlers.registry import handles
6
+ from topos.extensions import load_extensions
7
+
8
+
9
+ @pytest.mark.public
10
+ def test_load_extensions_does_not_raise_when_no_plugins_installed() -> None:
11
+ load_extensions()
12
+
13
+
14
+ @pytest.mark.public
15
+ def test_load_extensions_invokes_entry_point_callables(monkeypatch: pytest.MonkeyPatch) -> None:
16
+ seen: list[str] = []
17
+
18
+ def _init() -> None:
19
+ seen.append("ran")
20
+
21
+ class _FakeEntryPoint:
22
+ name = "test"
23
+
24
+ def load(self) -> object:
25
+ return _init
26
+
27
+ monkeypatch.setattr(
28
+ "topos.extensions._iter_extension_entry_points",
29
+ lambda: [_FakeEntryPoint()],
30
+ )
31
+ load_extensions()
32
+ assert seen == ["ran"]
@@ -1,6 +1,6 @@
1
1
  """Topos Control Plane Version Information."""
2
2
 
3
- __version__ = "1.2.3"
4
- __version_info__ = (1, 2, 3)
3
+ __version__ = "1.2.5"
4
+ __version_info__ = (1, 2, 5)
5
5
 
6
6
  __all__ = ["__version__", "__version_info__"]
@@ -319,7 +319,14 @@ def _enrichment_coverage_core(source_id: str) -> Dict[str, Any]:
319
319
  "output_rows": {},
320
320
  }
321
321
  coverage_table = coverage_table_for_job(job_id)
322
- if coverage_table and _table_exists(conn, coverage_table):
322
+ if job_id == "timeline":
323
+ from ..features.timeline_projection import timeline_coverage_for_source
324
+
325
+ timeline_stats = timeline_coverage_for_source(conn, source_id)
326
+ job_info["enriched_records"] = timeline_stats["enriched_records"]
327
+ job_info["coverage_percent"] = timeline_stats["coverage_percent"]
328
+ job_info["output_rows"]["timeline"] = timeline_stats["enriched_records"]
329
+ elif coverage_table and _table_exists(conn, coverage_table):
323
330
  cols = _table_columns(conn, coverage_table)
324
331
  id_col = "message_id" if "message_id" in cols else "record_id"
325
332
  if "source_id" in cols and id_col in cols:
@@ -552,24 +559,50 @@ async def _generic_backfill_core(
552
559
  scanned = len(records)
553
560
 
554
561
  if only_missing:
555
- coverage_table = coverage_table_for_job(job_name)
556
- if coverage_table and _table_exists(db_conn, coverage_table):
557
- cols = _table_columns(db_conn, coverage_table)
558
- id_col = "message_id" if "message_id" in cols else "record_id"
559
- if "source_id" in cols and id_col in cols:
560
- done = {
561
- str(row[0])
562
- for row in db_conn.execute(
563
- f"SELECT DISTINCT {id_col} FROM {coverage_table} WHERE source_id=?",
564
- (source_id,),
565
- ).fetchall()
566
- if row[0]
562
+ if job_name == "timeline":
563
+ from ..features.timeline_projection import timeline_coverage_for_source
564
+
565
+ stats = timeline_coverage_for_source(db_conn, source_id)
566
+ if stats["missing_records"] == 0:
567
+ return {
568
+ "rows_scanned": scanned,
569
+ "rows_processed": 0,
570
+ "rows_skipped": scanned,
571
+ "rows_failed": 0,
572
+ "errors": [],
567
573
  }
568
- records = [r for r in records if _record_identifier(r) not in done]
574
+ else:
575
+ coverage_table = coverage_table_for_job(job_name)
576
+ if coverage_table and _table_exists(db_conn, coverage_table):
577
+ cols = _table_columns(db_conn, coverage_table)
578
+ id_col = "message_id" if "message_id" in cols else "record_id"
579
+ if "source_id" in cols and id_col in cols:
580
+ done = {
581
+ str(row[0])
582
+ for row in db_conn.execute(
583
+ f"SELECT DISTINCT {id_col} FROM {coverage_table} WHERE source_id=?",
584
+ (source_id,),
585
+ ).fetchall()
586
+ if row[0]
587
+ }
588
+ records = [r for r in records if _record_identifier(r) not in done]
569
589
 
570
590
  if isinstance(limit, int) and limit > 0:
571
591
  records = records[:limit]
572
592
 
593
+ if job_name == "timeline":
594
+ from ..features.timeline_projection import repair_timeline_for_source
595
+
596
+ report = repair_timeline_for_source(db_conn, source_id, missing_only=True, dry_run=False)
597
+ processed = int(report.get("totals", {}).get("written", 0))
598
+ return {
599
+ "rows_scanned": scanned,
600
+ "rows_processed": processed,
601
+ "rows_skipped": max(scanned - processed, 0),
602
+ "rows_failed": 0,
603
+ "errors": [],
604
+ }
605
+
573
606
  if not records:
574
607
  return {
575
608
  "rows_scanned": scanned,
@@ -950,6 +983,7 @@ async def _process_enrichment_core(
950
983
  job_names: Optional[List[str]] = None,
951
984
  force_reprocess: bool = False,
952
985
  include_signal: bool = True,
986
+ progress_updater: Optional[Any] = None,
953
987
  ) -> Dict[str, Any]:
954
988
  """Core logic for processing enrichment (reusable from HTTP and WebSocket).
955
989
 
@@ -1024,32 +1058,64 @@ async def _process_enrichment_core(
1024
1058
 
1025
1059
  # Define progress callback to update progress during execution
1026
1060
  progress_callback = None
1027
- try:
1028
- from ..enrichment.progress import get_progress
1029
- # Try to get progress object if it exists (created by handler)
1030
- progress_obj = get_progress(source_id) # Use source_id as fallback lookup
1031
- if progress_obj:
1032
- def progress_callback(
1033
- processed_count: int,
1034
- total_count: int,
1035
- job_name: str,
1036
- job_percent: float,
1037
- current_job_progress: float,
1038
- ):
1039
- """Update progress as jobs execute."""
1040
- estimated_messages_processed = int((job_percent / 100) * total_count)
1041
- jobs_complete = int((job_percent / 100) * len(jobs_to_run))
1042
- progress_obj.update(
1043
- messages_processed=estimated_messages_processed,
1044
- messages_skipped=0,
1045
- current_job_name=job_name,
1046
- current_job_progress_percent=current_job_progress,
1047
- jobs_complete=jobs_complete,
1048
- jobs_total=len(jobs_to_run),
1049
- )
1050
- except Exception:
1051
- pass # Progress callback is optional
1061
+ if progress_updater is not None:
1062
+ def progress_callback(
1063
+ processed_count: int,
1064
+ total_count: int,
1065
+ job_name: str,
1066
+ job_percent: float,
1067
+ current_job_progress: float,
1068
+ ):
1069
+ estimated_messages_processed = int((job_percent / 100) * total_count) if total_count else 0
1070
+ jobs_complete = int((job_percent / 100) * len(jobs_to_run)) if jobs_to_run else 0
1071
+ progress_updater(
1072
+ {
1073
+ "status": "processing",
1074
+ "progress_percent": min(100.0, job_percent),
1075
+ "messages_processed": estimated_messages_processed,
1076
+ "messages_skipped": 0,
1077
+ "messages_total": total_count,
1078
+ "current_job_name": job_name,
1079
+ "current_job_progress_percent": current_job_progress,
1080
+ "jobs_complete": jobs_complete,
1081
+ "jobs_total": len(jobs_to_run),
1082
+ "jobs_progress_percent": (jobs_complete / len(jobs_to_run) * 100) if jobs_to_run else 0.0,
1083
+ }
1084
+ )
1085
+ else:
1086
+ try:
1087
+ from ..enrichment.progress import get_progress
1088
+ progress_obj = get_progress(source_id)
1089
+ if progress_obj:
1090
+ def progress_callback(
1091
+ processed_count: int,
1092
+ total_count: int,
1093
+ job_name: str,
1094
+ job_percent: float,
1095
+ current_job_progress: float,
1096
+ ):
1097
+ estimated_messages_processed = int((job_percent / 100) * total_count)
1098
+ jobs_complete = int((job_percent / 100) * len(jobs_to_run))
1099
+ progress_obj.update(
1100
+ messages_processed=estimated_messages_processed,
1101
+ messages_skipped=0,
1102
+ current_job_name=job_name,
1103
+ current_job_progress_percent=current_job_progress,
1104
+ jobs_complete=jobs_complete,
1105
+ jobs_total=len(jobs_to_run),
1106
+ )
1107
+ except Exception:
1108
+ pass
1052
1109
 
1110
+ if progress_updater is not None:
1111
+ progress_updater(
1112
+ {
1113
+ "status": "processing",
1114
+ "messages_total": len(unprocessed_messages),
1115
+ "jobs_total": len(jobs_to_run),
1116
+ }
1117
+ )
1118
+
1053
1119
  enrichment_result = await orchestrator.run_canonical(
1054
1120
  unprocessed_messages,
1055
1121
  job_names=jobs_to_run,
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import hashlib
4
+ import logging
4
5
 
5
6
  from fastapi import APIRouter, Depends
6
7
 
@@ -10,6 +11,8 @@ from ..engine.usage_observation import emit_usage_observation
10
11
  from ..rate_limit import rate_limit
11
12
  from ..services.container import Services, get_services
12
13
 
14
+ logger = logging.getLogger("topos.api.llm")
15
+
13
16
  router = APIRouter()
14
17
 
15
18
 
@@ -19,6 +22,12 @@ router = APIRouter()
19
22
  dependencies=[Depends(require_api_key), Depends(rate_limit)],
20
23
  )
21
24
  async def llm_generation(body: GenerationRequest):
25
+ logger.info(
26
+ "llm_generation request: provider=%r model=%r prompt_chars=%d",
27
+ body.provider,
28
+ body.model,
29
+ len(body.prompt or ""),
30
+ )
22
31
  services: Services = get_services()
23
32
  result = await services.llm.generate(body.model_dump())
24
33
  usage = result.get("usage") if isinstance(result, dict) else {}
@@ -45,6 +54,12 @@ async def llm_generation(body: GenerationRequest):
45
54
  dependencies=[Depends(require_api_key), Depends(rate_limit)],
46
55
  )
47
56
  async def llm_generation_alias(body: GenerationRequest):
57
+ logger.info(
58
+ "llm_generation request (alias): provider=%r model=%r prompt_chars=%d",
59
+ body.provider,
60
+ body.model,
61
+ len(body.prompt or ""),
62
+ )
48
63
  services: Services = get_services()
49
64
  result = await services.llm.generate(body.model_dump())
50
65
  usage = result.get("usage") if isinstance(result, dict) else {}
@@ -232,11 +232,13 @@ async def list_entities(
232
232
  # as an entity id.
233
233
  @router.get("/entities/graph")
234
234
  async def get_entity_graph(
235
- limit_nodes: int = Query(default=100, ge=1, le=500),
236
- limit_edges: int = Query(default=300, ge=1, le=1500),
235
+ limit_nodes: int = Query(default=100, ge=1, le=5000),
236
+ limit_edges: int = Query(default=300, ge=1, le=20000),
237
237
  min_weight: float = Query(default=0.0, ge=0.0),
238
238
  include_closed: bool = Query(default=False),
239
239
  as_of: Optional[str] = Query(default=None),
240
+ selection: str = Query(default="weight"),
241
+ offset: int = Query(default=0, ge=0),
240
242
  _api_key: str = Depends(require_api_key),
241
243
  ):
242
244
  """Entity-spine graph (decayed typed edges) in list_graph node/edge shape.
@@ -244,16 +246,25 @@ async def get_entity_graph(
244
246
  Each edge carries valid_from/valid_to/last_event_at. ``as_of`` (ISO date)
245
247
  returns the graph as it stood at that instant (temporal scrubber);
246
248
  ``include_closed`` adds ended edges to the present view.
249
+
250
+ ``selection=weight`` (default) ranks by weight for MCP/minimal slices;
251
+ ``selection=all`` ranks by recency for the owner knowledge-graph UI.
247
252
  """
253
+ import asyncio
254
+
248
255
  from ..features.entities.reads import entity_graph
249
256
 
250
- return entity_graph(
251
- _entities_conn(),
257
+ conn = _entities_conn()
258
+ return await asyncio.to_thread(
259
+ entity_graph,
260
+ conn,
252
261
  limit_nodes=limit_nodes,
253
262
  limit_edges=limit_edges,
254
263
  min_weight=min_weight,
255
264
  include_closed=include_closed,
256
265
  as_of=as_of,
266
+ selection=selection,
267
+ offset=offset,
257
268
  )
258
269
 
259
270
 
@@ -11,6 +11,7 @@ from ..ingestion.ingest_helpers import ingest_file_payload, ingest_ui_payload
11
11
  from ..api.enrichment import _process_enrichment_core
12
12
  from ..engine.usage_observation import emit_usage_observation
13
13
  from ..sources import install_service
14
+ from ..sources.definitions import with_source_capabilities
14
15
 
15
16
  router = APIRouter()
16
17
  logger = logging.getLogger("topos.api.source_install")
@@ -140,7 +141,7 @@ async def _list_sources_core(payload: Dict[str, Any]) -> Dict[str, Any]:
140
141
  source_def = rec.source_definition_json if isinstance(rec.source_definition_json, dict) else {}
141
142
  if not sid or sid in active_by_source or not source_def:
142
143
  continue
143
- active_by_source[sid] = source_def
144
+ active_by_source[sid] = with_source_capabilities(source_def)
144
145
  sources = list(active_by_source.values())
145
146
  return {"status": "ok", "sources": sources}
146
147
 
@@ -0,0 +1,86 @@
1
+ """Tool-RAG endpoints: sync the tool index, retrieve top-K tools for a query.
2
+
3
+ PLAN_AGENT_QUALITY WS-3 (M2). The chat orchestration (topos-react-app) pushes
4
+ the gateway's tool list here after ``tools/list`` (hash-deduped upsert → cheap
5
+ no-op when unchanged) and calls ``/v1/tools/retrieve`` per turn to build a
6
+ focused tool doc sized to the model instead of a flat 52-tool dump.
7
+
8
+ Handlers are sync ``def`` on purpose: the embedding path is blocking HF
9
+ inference, and FastAPI runs sync handlers in its threadpool.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import List, Optional
15
+
16
+ from fastapi import APIRouter, Depends, HTTPException
17
+ from pydantic import BaseModel, Field
18
+
19
+ from ..auth import require_api_key
20
+ from ..core.state import get_db_connection
21
+ from ..features.signal.tool_index import index_status, index_tools, retrieve_tools
22
+ from ..rate_limit import rate_limit
23
+
24
+ router = APIRouter()
25
+
26
+
27
+ class ToolSpecIn(BaseModel):
28
+ name: str
29
+ description: str = ""
30
+ connector_id: Optional[str] = None
31
+
32
+
33
+ class IndexToolsRequest(BaseModel):
34
+ tools: List[ToolSpecIn] = Field(default_factory=list, max_length=2000)
35
+ # Prune index rows absent from this payload (full-list syncs only).
36
+ prune_missing: bool = False
37
+
38
+
39
+ class RetrieveToolsRequest(BaseModel):
40
+ query: str
41
+ connector_scope: Optional[str] = None
42
+ k: int = 8
43
+
44
+
45
+ def _require_conn():
46
+ conn = get_db_connection()
47
+ if conn is None:
48
+ raise HTTPException(status_code=503, detail="Database unavailable")
49
+ return conn
50
+
51
+
52
+ @router.post(
53
+ "/v1/tools/index",
54
+ dependencies=[Depends(require_api_key), Depends(rate_limit)],
55
+ )
56
+ def tools_index(body: IndexToolsRequest):
57
+ conn = _require_conn()
58
+ specs = [spec.model_dump() for spec in body.tools if str(spec.name or "").strip()]
59
+ if not specs and not body.prune_missing:
60
+ raise HTTPException(status_code=422, detail="tools must be a non-empty list")
61
+ return index_tools(conn, specs, prune_missing=body.prune_missing)
62
+
63
+
64
+ @router.post(
65
+ "/v1/tools/retrieve",
66
+ dependencies=[Depends(require_api_key), Depends(rate_limit)],
67
+ )
68
+ def tools_retrieve(body: RetrieveToolsRequest):
69
+ if not str(body.query or "").strip():
70
+ raise HTTPException(status_code=422, detail="query is required")
71
+ conn = _require_conn()
72
+ return retrieve_tools(
73
+ conn,
74
+ body.query,
75
+ connector_scope=body.connector_scope,
76
+ k=body.k,
77
+ )
78
+
79
+
80
+ @router.get(
81
+ "/v1/tools/index/status",
82
+ dependencies=[Depends(require_api_key), Depends(rate_limit)],
83
+ )
84
+ def tools_index_status():
85
+ conn = _require_conn()
86
+ return index_status(conn)
@@ -45,10 +45,12 @@ from .api import (
45
45
  home_chat as home_chat_routes,
46
46
  privacy_disclose as privacy_disclose_routes,
47
47
  signal as signal_routes,
48
+ tool_index as tool_index_routes,
48
49
  upgrades as upgrades_routes,
49
50
  )
50
51
  from .config.settings import settings
51
52
  from .core.logging import align_uvicorn_loggers, configure_logging
53
+ from .extensions import load_extensions
52
54
  from .core import state
53
55
  from .core.handlers import handle_control_plane_request
54
56
  from .control_plane_client import ControlPlaneClient
@@ -65,6 +67,7 @@ from .sync import SyncClient
65
67
  from .sync_handlers import handle_sync_op
66
68
 
67
69
  configure_logging()
70
+ load_extensions()
68
71
  logger = logging.getLogger("topos.app")
69
72
 
70
73
  app = FastAPI(
@@ -128,10 +131,15 @@ app.include_router(privacy_disclose_routes.router)
128
131
  app.include_router(compute_remote_routes.router)
129
132
  app.include_router(engine_run_routes.router)
130
133
  app.include_router(data_commit_routes.router)
134
+ app.include_router(tool_index_routes.router)
131
135
 
132
136
 
133
137
  @app.on_event("startup")
134
138
  async def startup_event() -> None:
139
+ from .runtime_shutdown import clear_shutdown, install_shutdown_signal_hooks
140
+
141
+ clear_shutdown()
142
+ install_shutdown_signal_hooks()
135
143
  align_uvicorn_loggers()
136
144
  _log_runtime_banner()
137
145
  logger.info("CORS allowed origins: %s", settings.allowed_origins)
@@ -172,6 +180,20 @@ async def startup_event() -> None:
172
180
  _start_upgrades(_upgrade_conn)
173
181
  except Exception as e:
174
182
  logger.warning("Upgrade runner at startup failed (non-fatal): %s", e)
183
+ try:
184
+ from .core.state import get_db_connection as _get_conn_for_pipeline
185
+ from .pipeline.job_runner import recover_pipeline_jobs, start_pipeline_worker
186
+ from .features.entities.graph_refresh import reconcile_graph_on_startup
187
+
188
+ _pipeline_conn = state.db_conn if state.db_conn is not None else _get_conn_for_pipeline()
189
+ if _pipeline_conn is not None:
190
+ recovered = recover_pipeline_jobs(_pipeline_conn)
191
+ if recovered:
192
+ logger.info("Recovered stale pipeline jobs on startup: count=%s", recovered)
193
+ reconcile_graph_on_startup(_pipeline_conn)
194
+ start_pipeline_worker(_get_conn_for_pipeline)
195
+ except Exception as e:
196
+ logger.warning("Pipeline worker at startup failed (non-fatal): %s", e)
175
197
  try:
176
198
  from .sources import install_service
177
199
 
@@ -185,6 +207,16 @@ async def startup_event() -> None:
185
207
  )
186
208
  except Exception as e:
187
209
  logger.warning("Active source install rehydration at startup failed (non-fatal): %s", e)
210
+ if getattr(settings, "sanitization_prewarm_on_startup", True):
211
+ async def _prewarm_sanitization() -> None:
212
+ try:
213
+ from .sanitization.prewarm import prewarm_sanitization_models
214
+
215
+ await asyncio.to_thread(prewarm_sanitization_models)
216
+ except Exception as prewarm_exc: # noqa: BLE001
217
+ logger.warning("Sanitization prewarm at startup failed (non-fatal): %s", prewarm_exc)
218
+
219
+ asyncio.create_task(_prewarm_sanitization())
188
220
  if settings.topos_control_plane_url:
189
221
  if settings.hosted_pool_lease_enabled:
190
222
  try:
@@ -282,6 +314,11 @@ async def startup_event() -> None:
282
314
 
283
315
  @app.on_event("shutdown")
284
316
  async def shutdown_event() -> None:
317
+ from .runtime_shutdown import request_shutdown
318
+
319
+ # Wake cooperative workers (fact_llm / Ollama threads) before awaiting
320
+ # network teardown so Ctrl+C does not wait out a full enrichment batch.
321
+ request_shutdown("app_shutdown")
285
322
  await stop_runtime_update_monitor()
286
323
  if state.engine_presence_task:
287
324
  state.engine_presence_task.cancel()