topos-node 1.3.36__tar.gz → 1.3.38__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 (758) hide show
  1. {topos_node-1.3.36/topos_node.egg-info → topos_node-1.3.38}/PKG-INFO +1 -1
  2. {topos_node-1.3.36 → topos_node-1.3.38}/pyproject.toml +1 -1
  3. {topos_node-1.3.36 → topos_node-1.3.38}/topos/__version__.py +2 -2
  4. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/ingestion_sources.py +18 -6
  5. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/signal.py +36 -16
  6. {topos_node-1.3.36 → topos_node-1.3.38}/topos/cli/tray.py +39 -4
  7. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/signal_features.py +4 -1
  8. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/sources.py +12 -5
  9. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/backends/ollama.py +9 -0
  10. topos_node-1.3.38/topos/engine/ollama_runtime.py +142 -0
  11. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/reads.py +123 -0
  12. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/local_sync.py +66 -23
  13. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/sources/imessage_reader.py +96 -10
  14. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/llm/openai.py +13 -0
  15. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/pipeline_jobs_v1.py +34 -1
  16. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/source_settings.py +56 -22
  17. {topos_node-1.3.36 → topos_node-1.3.38}/topos/upgrades/manifests.json +18 -0
  18. {topos_node-1.3.36 → topos_node-1.3.38/topos_node.egg-info}/PKG-INFO +1 -1
  19. {topos_node-1.3.36 → topos_node-1.3.38}/topos_node.egg-info/SOURCES.txt +1 -0
  20. {topos_node-1.3.36 → topos_node-1.3.38}/LICENSE +0 -0
  21. {topos_node-1.3.36 → topos_node-1.3.38}/MANIFEST.in +0 -0
  22. {topos_node-1.3.36 → topos_node-1.3.38}/README.md +0 -0
  23. {topos_node-1.3.36 → topos_node-1.3.38}/setup.cfg +0 -0
  24. {topos_node-1.3.36 → topos_node-1.3.38}/shared/__init__.py +0 -0
  25. {topos_node-1.3.36 → topos_node-1.3.38}/shared/filtering.py +0 -0
  26. {topos_node-1.3.36 → topos_node-1.3.38}/shared/schema_registry.py +0 -0
  27. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_active_database_binding.py +0 -0
  28. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_active_ingestion_binding.py +0 -0
  29. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_extensions.py +0 -0
  30. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_gate_leg_hermeticity.py +0 -0
  31. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_llm_integrations_storage.py +0 -0
  32. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_local_gate_composition.py +0 -0
  33. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_owner_database_hermeticity.py +0 -0
  34. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_prewarm_first_run.py +0 -0
  35. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_profile_hygiene.py +0 -0
  36. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_profiles.py +0 -0
  37. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_protocol_handled_types.py +0 -0
  38. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_query_field_contract.py +0 -0
  39. {topos_node-1.3.36 → topos_node-1.3.38}/tests/test_system_computer_name.py +0 -0
  40. {topos_node-1.3.36 → topos_node-1.3.38}/topos/__init__.py +0 -0
  41. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/__init__.py +0 -0
  42. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/dataset_resolution.py +0 -0
  43. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/duckdb_adapter.py +0 -0
  44. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/luck_surface.py +0 -0
  45. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/messenger_communities.py +0 -0
  46. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/messenger_directed.py +0 -0
  47. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/messenger_graph.py +0 -0
  48. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/messenger_labels.py +0 -0
  49. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/person_graph.py +0 -0
  50. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/person_overlay.py +0 -0
  51. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/profiles.py +0 -0
  52. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/query_engine.py +0 -0
  53. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/raw_queries.py +0 -0
  54. {topos_node-1.3.36 → topos_node-1.3.38}/topos/analytics/relationship_reads.py +0 -0
  55. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/__init__.py +0 -0
  56. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/analytics.py +0 -0
  57. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/app_registry.py +0 -0
  58. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/backup.py +0 -0
  59. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/community_naming_config.py +0 -0
  60. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/compute_remote.py +0 -0
  61. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/connected_apps.py +0 -0
  62. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/conversation_context.py +0 -0
  63. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/data_commit.py +0 -0
  64. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/data_explorer_table_prefs.py +0 -0
  65. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/database_explorer.py +0 -0
  66. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/db.py +0 -0
  67. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/device.py +0 -0
  68. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/disk_space_config.py +0 -0
  69. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/engine_run.py +0 -0
  70. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/enrichment.py +0 -0
  71. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/enrichment_lab.py +0 -0
  72. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/facts_llm_config.py +0 -0
  73. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/filter_lab.py +0 -0
  74. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/health.py +0 -0
  75. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/home_chat.py +0 -0
  76. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/ingestion_api.py +0 -0
  77. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/ingestion_compat.py +0 -0
  78. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/intelligence_lifecycle.py +0 -0
  79. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/llm.py +0 -0
  80. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/local_mcp.py +0 -0
  81. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/messenger_analytics.py +0 -0
  82. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/privacy_disclose.py +0 -0
  83. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/query_api.py +0 -0
  84. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/runtime_bootstrap.py +0 -0
  85. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/sanitization_ollama_config.py +0 -0
  86. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/shell.py +0 -0
  87. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/signal_extraction_config.py +0 -0
  88. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/source_install.py +0 -0
  89. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/source_scrub.py +0 -0
  90. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/sources.py +0 -0
  91. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/sources_overview.py +0 -0
  92. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/sync.py +0 -0
  93. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/tool_index.py +0 -0
  94. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/ui_config.py +0 -0
  95. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/uma_data.py +0 -0
  96. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/upgrades.py +0 -0
  97. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/usage.py +0 -0
  98. {topos_node-1.3.36 → topos_node-1.3.38}/topos/api/user_identity.py +0 -0
  99. {topos_node-1.3.36 → topos_node-1.3.38}/topos/app.py +0 -0
  100. {topos_node-1.3.36 → topos_node-1.3.38}/topos/auth.py +0 -0
  101. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/__init__.py +0 -0
  102. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/declared_field_map.py +0 -0
  103. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/mappers/__init__.py +0 -0
  104. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/mappers/base.py +0 -0
  105. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/mappers/browser_activity_mapper.py +0 -0
  106. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/mappers/chatgpt_mapper.py +0 -0
  107. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/mappers/demo_mappers.py +0 -0
  108. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/mappers/documents_mapper.py +0 -0
  109. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/mappers/github_activity_mapper.py +0 -0
  110. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/mappers/google_calendar_mapper.py +0 -0
  111. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/mappers/grok_mapper.py +0 -0
  112. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/mappers/messenger_mapper.py +0 -0
  113. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/models.py +0 -0
  114. {topos_node-1.3.36 → topos_node-1.3.38}/topos/canonicalization/resolver.py +0 -0
  115. {topos_node-1.3.36 → topos_node-1.3.38}/topos/cli/__init__.py +0 -0
  116. {topos_node-1.3.36 → topos_node-1.3.38}/topos/cli/__main__.py +0 -0
  117. {topos_node-1.3.36 → topos_node-1.3.38}/topos/cli/assets/topos_blk_rounded.png +0 -0
  118. {topos_node-1.3.36 → topos_node-1.3.38}/topos/cli/assets/topos_white.png +0 -0
  119. {topos_node-1.3.36 → topos_node-1.3.38}/topos/cli/commands.py +0 -0
  120. {topos_node-1.3.36 → topos_node-1.3.38}/topos/cli/profile_cmd.py +0 -0
  121. {topos_node-1.3.36 → topos_node-1.3.38}/topos/cli/reprocess_cmd.py +0 -0
  122. {topos_node-1.3.36 → topos_node-1.3.38}/topos/cli/setup_models_cmd.py +0 -0
  123. {topos_node-1.3.36 → topos_node-1.3.38}/topos/config/__init__.py +0 -0
  124. {topos_node-1.3.36 → topos_node-1.3.38}/topos/config/conversation_context_llm.py +0 -0
  125. {topos_node-1.3.36 → topos_node-1.3.38}/topos/config/facts_llm.py +0 -0
  126. {topos_node-1.3.36 → topos_node-1.3.38}/topos/config/local_model_builds.py +0 -0
  127. {topos_node-1.3.36 → topos_node-1.3.38}/topos/config/model_packs.py +0 -0
  128. {topos_node-1.3.36 → topos_node-1.3.38}/topos/config/node_function_providers.py +0 -0
  129. {topos_node-1.3.36 → topos_node-1.3.38}/topos/config/sanitization_ollama.py +0 -0
  130. {topos_node-1.3.36 → topos_node-1.3.38}/topos/config/settings.py +0 -0
  131. {topos_node-1.3.36 → topos_node-1.3.38}/topos/config/signal_extraction.py +0 -0
  132. {topos_node-1.3.36 → topos_node-1.3.38}/topos/config/uvicorn_logging.json +0 -0
  133. {topos_node-1.3.36 → topos_node-1.3.38}/topos/contacts/__init__.py +0 -0
  134. {topos_node-1.3.36 → topos_node-1.3.38}/topos/contacts/identity.py +0 -0
  135. {topos_node-1.3.36 → topos_node-1.3.38}/topos/control_plane_client.py +0 -0
  136. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/__init__.py +0 -0
  137. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/api_models.py +0 -0
  138. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/connection_resilience.py +0 -0
  139. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/db_health.py +0 -0
  140. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/device_helpers.py +0 -0
  141. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/errors.py +0 -0
  142. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/events.py +0 -0
  143. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/__init__.py +0 -0
  144. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/common.py +0 -0
  145. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/complexity.py +0 -0
  146. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/config.py +0 -0
  147. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/contacts_import.py +0 -0
  148. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/database_explorer.py +0 -0
  149. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/derivation.py +0 -0
  150. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/device.py +0 -0
  151. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/enrichment.py +0 -0
  152. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/enrichment_lab.py +0 -0
  153. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/filter_lab.py +0 -0
  154. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/graph_query.py +0 -0
  155. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/home_chat.py +0 -0
  156. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/ingest.py +0 -0
  157. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/mcp_client_elevations.py +0 -0
  158. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/mcp_clients.py +0 -0
  159. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/messages.py +0 -0
  160. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/messenger_analytics.py +0 -0
  161. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/query.py +0 -0
  162. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/registry.py +0 -0
  163. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/routines.py +0 -0
  164. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/timeline_daily.py +0 -0
  165. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/tool_index.py +0 -0
  166. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/handlers/uma.py +0 -0
  167. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/logging.py +0 -0
  168. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/metrics.py +0 -0
  169. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/routine_access.py +0 -0
  170. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/startup_banner.py +0 -0
  171. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/state.py +0 -0
  172. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/table_layers.py +0 -0
  173. {topos_node-1.3.36 → topos_node-1.3.38}/topos/core/types.py +0 -0
  174. {topos_node-1.3.36 → topos_node-1.3.38}/topos/data_explorer_row_delete.py +0 -0
  175. {topos_node-1.3.36 → topos_node-1.3.38}/topos/data_explorer_table_prefs.py +0 -0
  176. {topos_node-1.3.36 → topos_node-1.3.38}/topos/data_explorer_tables.py +0 -0
  177. {topos_node-1.3.36 → topos_node-1.3.38}/topos/disclosure/__init__.py +0 -0
  178. {topos_node-1.3.36 → topos_node-1.3.38}/topos/disclosure/canonical_writer.py +0 -0
  179. {topos_node-1.3.36 → topos_node-1.3.38}/topos/disclosure/content_policy.py +0 -0
  180. {topos_node-1.3.36 → topos_node-1.3.38}/topos/disclosure/field_registry.py +0 -0
  181. {topos_node-1.3.36 → topos_node-1.3.38}/topos/disclosure/privacy_layer.py +0 -0
  182. {topos_node-1.3.36 → topos_node-1.3.38}/topos/disclosure/tier.py +0 -0
  183. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/__init__.py +0 -0
  184. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/backends/__init__.py +0 -0
  185. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/backends/base.py +0 -0
  186. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/backends/generative_prompts.py +0 -0
  187. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/backends/generative_response.py +0 -0
  188. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/backends/huggingface.py +0 -0
  189. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/backends/openai.py +0 -0
  190. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/backends/openai_compatible.py +0 -0
  191. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/backends/redpill.py +0 -0
  192. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/backends/stub.py +0 -0
  193. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/client.py +0 -0
  194. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/disk_space.py +0 -0
  195. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/engine.py +0 -0
  196. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/hosted_llm_wallet.py +0 -0
  197. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/intake.py +0 -0
  198. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/memory_utils.py +0 -0
  199. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/model_cache.py +0 -0
  200. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/model_manager.py +0 -0
  201. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/ollama_install.py +0 -0
  202. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/ollama_pull.py +0 -0
  203. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/ollama_setup_guidance.py +0 -0
  204. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/pipeline_memory.py +0 -0
  205. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/queue_manager.py +0 -0
  206. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/registration.py +0 -0
  207. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/result_formatter.py +0 -0
  208. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/router.py +0 -0
  209. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/scoped_token.py +0 -0
  210. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/tasks.py +0 -0
  211. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/torch_runtime.py +0 -0
  212. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/transport.py +0 -0
  213. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/usage_guard.py +0 -0
  214. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/usage_observation.py +0 -0
  215. {topos_node-1.3.36 → topos_node-1.3.38}/topos/engine/validator.py +0 -0
  216. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/__init__.py +0 -0
  217. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/catalog.py +0 -0
  218. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/derivation_recovery.py +0 -0
  219. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/derived_tables.py +0 -0
  220. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/job_readiness.py +0 -0
  221. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/job_writer.py +0 -0
  222. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/__init__.py +0 -0
  223. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/base.py +0 -0
  224. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/__init__.py +0 -0
  225. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/_batch_limits.py +0 -0
  226. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/_engine_runner.py +0 -0
  227. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/attention_triage_job.py +0 -0
  228. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/availability_scores_job.py +0 -0
  229. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/brief_fallback.py +0 -0
  230. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/complexity_snapshot_job.py +0 -0
  231. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/derivation_job.py +0 -0
  232. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/derived_object_embeddings_job.py +0 -0
  233. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/dimension_summary_job.py +0 -0
  234. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/embeddings_job.py +0 -0
  235. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/emo_27_job.py +0 -0
  236. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/entities_job.py +0 -0
  237. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/fact_extraction_job.py +0 -0
  238. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/goal_extraction_job.py +0 -0
  239. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/pii_redaction_job.py +0 -0
  240. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/relationship_edges_job.py +0 -0
  241. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/sentiment_job.py +0 -0
  242. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/statistics_job.py +0 -0
  243. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/timeline_job.py +0 -0
  244. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/topic_clusters_job.py +0 -0
  245. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/canonical/topics_job.py +0 -0
  246. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/raw/__init__.py +0 -0
  247. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
  248. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/raw/language_job.py +0 -0
  249. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
  250. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
  251. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/model_overrides.py +0 -0
  252. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/models/__init__.py +0 -0
  253. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/models/manager.py +0 -0
  254. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/models/mvp_defaults.py +0 -0
  255. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/models/registry.py +0 -0
  256. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/models/versioning.py +0 -0
  257. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/orchestrator.py +0 -0
  258. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/pipeline_activity.py +0 -0
  259. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/processor.py +0 -0
  260. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/progress_bar.py +0 -0
  261. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/record_progress.py +0 -0
  262. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/registry_contract.py +0 -0
  263. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/signal_derivation_config.json +0 -0
  264. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment/source_overrides.py +0 -0
  265. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment_lab/__init__.py +0 -0
  266. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment_lab/bundles.py +0 -0
  267. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment_lab/model_resolve.py +0 -0
  268. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment_lab/schema.py +0 -0
  269. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment_lab/service.py +0 -0
  270. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment_lab/store.py +0 -0
  271. {topos_node-1.3.36 → topos_node-1.3.38}/topos/enrichment_lab/worker.py +0 -0
  272. {topos_node-1.3.36 → topos_node-1.3.38}/topos/evals/__init__.py +0 -0
  273. {topos_node-1.3.36 → topos_node-1.3.38}/topos/evals/enrichment_eval.py +0 -0
  274. {topos_node-1.3.36 → topos_node-1.3.38}/topos/extensions.py +0 -0
  275. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/__init__.py +0 -0
  276. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/canonical.py +0 -0
  277. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/engine.py +0 -0
  278. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/entropy.py +0 -0
  279. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/focus.py +0 -0
  280. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/graph_metrics.py +0 -0
  281. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/influence.py +0 -0
  282. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/projection.py +0 -0
  283. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/snapshots.py +0 -0
  284. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/store.py +0 -0
  285. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/topic_merge.py +0 -0
  286. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/topics.py +0 -0
  287. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/topics_daily.py +0 -0
  288. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/complexity/volatility.py +0 -0
  289. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/__init__.py +0 -0
  290. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/_scales.yaml +0 -0
  291. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/admin.legal.yaml +0 -0
  292. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/aspirations.goals.yaml +0 -0
  293. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/behavior.habits.yaml +0 -0
  294. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/behavior.preferences.yaml +0 -0
  295. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/beliefs.civic.yaml +0 -0
  296. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/beliefs.spiritual.yaml +0 -0
  297. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/communication.style.yaml +0 -0
  298. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/community.membership.yaml +0 -0
  299. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/craft.tooling.yaml +0 -0
  300. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/expertise.knowledge.yaml +0 -0
  301. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/finances.economics.yaml +0 -0
  302. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/health.lifestyle.yaml +0 -0
  303. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/health.mental.yaml +0 -0
  304. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/health.physical.yaml +0 -0
  305. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/household.pets.yaml +0 -0
  306. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/identity.core.yaml +0 -0
  307. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/interests.taste.yaml +0 -0
  308. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/life.events.yaml +0 -0
  309. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/narrative.self.yaml +0 -0
  310. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/net.capability.yaml +0 -0
  311. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/obligations.commitments.yaml +0 -0
  312. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/personality.traits.yaml +0 -0
  313. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/places.mobility.yaml +0 -0
  314. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/possessions.assets.yaml +0 -0
  315. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/relationships.social.yaml +0 -0
  316. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/values.motivation.yaml +0 -0
  317. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/vocab/dispositions.yaml +0 -0
  318. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/vocab/expertise.yaml +0 -0
  319. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/vocab/habits.yaml +0 -0
  320. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/vocab/interests.yaml +0 -0
  321. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/vocab/preferences.yaml +0 -0
  322. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/vocab/stances.yaml +0 -0
  323. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/vocab/tools.yaml +0 -0
  324. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/vocab/values.yaml +0 -0
  325. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/bundled_packs/work.career.yaml +0 -0
  326. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/candidates.py +0 -0
  327. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/guard.py +0 -0
  328. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/kernels.py +0 -0
  329. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/net_subject_policy.py +0 -0
  330. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/packs.py +0 -0
  331. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/person_bridge.py +0 -0
  332. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/prefilter.py +0 -0
  333. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/registry.py +0 -0
  334. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/report_card.py +0 -0
  335. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/router.py +0 -0
  336. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/social_bench.py +0 -0
  337. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/social_kernels.py +0 -0
  338. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/surfaces.py +0 -0
  339. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/synthesize.py +0 -0
  340. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/template.py +0 -0
  341. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/verify.py +0 -0
  342. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/derivation/writer.py +0 -0
  343. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/__init__.py +0 -0
  344. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/affinity.py +0 -0
  345. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/affinity_owner.py +0 -0
  346. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/affinity_quality.py +0 -0
  347. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/community_names.py +0 -0
  348. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/community_naming.py +0 -0
  349. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/consolidation.py +0 -0
  350. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/context_vectors.py +0 -0
  351. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/cypher.py +0 -0
  352. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/declared_mappings.py +0 -0
  353. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/dossier.py +0 -0
  354. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/edges.py +0 -0
  355. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/fact_materializer.py +0 -0
  356. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/graph_enrichers.py +0 -0
  357. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/graph_refresh.py +0 -0
  358. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/graph_search.py +0 -0
  359. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/linking.py +0 -0
  360. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/maintenance.py +0 -0
  361. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/owner.py +0 -0
  362. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/rebuild_subprocess.py +0 -0
  363. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/resolver.py +0 -0
  364. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/entities/structured_fields.py +0 -0
  365. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/facts/__init__.py +0 -0
  366. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/facts/extract.py +0 -0
  367. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/facts/llm_extract.py +0 -0
  368. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/facts/reads.py +0 -0
  369. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/facts/store.py +0 -0
  370. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/facts/verdicts.py +0 -0
  371. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/fit/evaluator.py +0 -0
  372. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/fit/opportunity_types.json +0 -0
  373. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/lifecycle/__init__.py +0 -0
  374. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/lifecycle/blackhole.py +0 -0
  375. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/lifecycle/blackhole_guard.py +0 -0
  376. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/lifecycle/blackhole_llm.py +0 -0
  377. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/lifecycle/blackhole_rebuild.py +0 -0
  378. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/lifecycle/derived_scrub.py +0 -0
  379. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/lifecycle/exclusions.py +0 -0
  380. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/lifecycle/gc.py +0 -0
  381. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/provenance/__init__.py +0 -0
  382. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/provenance/posture.py +0 -0
  383. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/provenance/roles.py +0 -0
  384. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/__init__.py +0 -0
  385. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/brief_canonical_loader.py +0 -0
  386. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/brief_ontology.py +0 -0
  387. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/brief_renderer.py +0 -0
  388. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/brief_schemas.py +0 -0
  389. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/chunking.py +0 -0
  390. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/cluster_labels.py +0 -0
  391. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/conversation_context.py +0 -0
  392. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/data_health.py +0 -0
  393. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/brief_ontologies.json +0 -0
  394. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/intentions.json +0 -0
  395. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/interests.json +0 -0
  396. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/memory.json +0 -0
  397. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/places.json +0 -0
  398. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/profile.json +0 -0
  399. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/relationships.json +0 -0
  400. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/resources.json +0 -0
  401. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/schema/dimension_definition.schema.json +0 -0
  402. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/time.json +0 -0
  403. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/wellbeing.json +0 -0
  404. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/definitions/work.json +0 -0
  405. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/derived_index.py +0 -0
  406. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/derived_spec.py +0 -0
  407. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/dimension_briefs.py +0 -0
  408. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/dimension_definition_loader.py +0 -0
  409. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/dimension_profiles.py +0 -0
  410. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/dimension_registry.py +0 -0
  411. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/embed_context.py +0 -0
  412. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/extraction/artifact_router.py +0 -0
  413. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/extraction/artifact_store.py +0 -0
  414. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/extraction/rule_extractors.py +0 -0
  415. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/graph_sanitize.py +0 -0
  416. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/hybrid_search.py +0 -0
  417. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/incremental_clustering.py +0 -0
  418. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/model_recommendations.py +0 -0
  419. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/query_embed_cache.py +0 -0
  420. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/schemas.py +0 -0
  421. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/service.py +0 -0
  422. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/signal_object_store.py +0 -0
  423. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/source_hydration.py +0 -0
  424. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/structured_signal.py +0 -0
  425. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/tool_index.py +0 -0
  426. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/topic_clustering.py +0 -0
  427. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/typed_stores/aggregates.py +0 -0
  428. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/typed_stores/commitments.py +0 -0
  429. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/typed_stores/rhythm.py +0 -0
  430. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/typed_stores/scope_materializer.py +0 -0
  431. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/vector_codec.py +0 -0
  432. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/vector_math.py +0 -0
  433. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/signal/vector_settings.py +0 -0
  434. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/stats/__init__.py +0 -0
  435. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/stats/definitions.py +0 -0
  436. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/stats/engine.py +0 -0
  437. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/stats/fold.py +0 -0
  438. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/stats/insights.py +0 -0
  439. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/timeline_projection.py +0 -0
  440. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/timeline_rollup.py +0 -0
  441. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/triage/__init__.py +0 -0
  442. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/triage/badges.py +0 -0
  443. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/triage/daily.py +0 -0
  444. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/triage/dashboard.py +0 -0
  445. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/triage/instruments.py +0 -0
  446. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/triage/intents.py +0 -0
  447. {topos_node-1.3.36 → topos_node-1.3.38}/topos/features/triage/readiness.py +0 -0
  448. {topos_node-1.3.36 → topos_node-1.3.38}/topos/filter_lab/__init__.py +0 -0
  449. {topos_node-1.3.36 → topos_node-1.3.38}/topos/filter_lab/bundles.py +0 -0
  450. {topos_node-1.3.36 → topos_node-1.3.38}/topos/filter_lab/schema.py +0 -0
  451. {topos_node-1.3.36 → topos_node-1.3.38}/topos/filter_lab/service.py +0 -0
  452. {topos_node-1.3.36 → topos_node-1.3.38}/topos/filter_lab/store.py +0 -0
  453. {topos_node-1.3.36 → topos_node-1.3.38}/topos/filter_lab/worker.py +0 -0
  454. {topos_node-1.3.36 → topos_node-1.3.38}/topos/home_chat/__init__.py +0 -0
  455. {topos_node-1.3.36 → topos_node-1.3.38}/topos/home_chat/schema.py +0 -0
  456. {topos_node-1.3.36 → topos_node-1.3.38}/topos/home_chat/store.py +0 -0
  457. {topos_node-1.3.36 → topos_node-1.3.38}/topos/hosted_pool_lease.py +0 -0
  458. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/__init__.py +0 -0
  459. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/canonical_pipeline.py +0 -0
  460. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/checkpoints/__init__.py +0 -0
  461. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
  462. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
  463. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/inbox_crypto.py +0 -0
  464. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/inbox_drain.py +0 -0
  465. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/ingest_helpers.py +0 -0
  466. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/jobs.py +0 -0
  467. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/journal_location_fanout.py +0 -0
  468. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/journal_time_log_normalize.py +0 -0
  469. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/log_preview.py +0 -0
  470. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/manager.py +0 -0
  471. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parser.py +0 -0
  472. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/__init__.py +0 -0
  473. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/base.py +0 -0
  474. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/browser_parser.py +0 -0
  475. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/calendar_parser.py +0 -0
  476. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
  477. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
  478. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/demo_file_parsers.py +0 -0
  479. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/documents_parser.py +0 -0
  480. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/github_activity_parser.py +0 -0
  481. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/google_calendar_parser.py +0 -0
  482. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/grok_parser.py +0 -0
  483. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/messenger_parser.py +0 -0
  484. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/parsers/voxterm_parser.py +0 -0
  485. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/progress.py +0 -0
  486. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/reprocess.py +0 -0
  487. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/sources/__init__.py +0 -0
  488. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/sources/base.py +0 -0
  489. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/sources/calendar.py +0 -0
  490. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/sources/chatgpt.py +0 -0
  491. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/sources/contact_importers.py +0 -0
  492. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/sources/grok.py +0 -0
  493. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/sources/signal_export_parser.py +0 -0
  494. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/sources/signal_reader.py +0 -0
  495. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/state_machine.py +0 -0
  496. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/triggers/__init__.py +0 -0
  497. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/triggers/file_trigger.py +0 -0
  498. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
  499. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/usage_inbox_dedupe.py +0 -0
  500. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/validation/__init__.py +0 -0
  501. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/validation/base.py +0 -0
  502. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/validation/schema_registry.py +0 -0
  503. {topos_node-1.3.36 → topos_node-1.3.38}/topos/ingestion/validation/schema_validator.py +0 -0
  504. {topos_node-1.3.36 → topos_node-1.3.38}/topos/lineage/__init__.py +0 -0
  505. {topos_node-1.3.36 → topos_node-1.3.38}/topos/lineage/provenance.py +0 -0
  506. {topos_node-1.3.36 → topos_node-1.3.38}/topos/lineage/tracker.py +0 -0
  507. {topos_node-1.3.36 → topos_node-1.3.38}/topos/llm_integrations_storage.py +0 -0
  508. {topos_node-1.3.36 → topos_node-1.3.38}/topos/mcp_clients.py +0 -0
  509. {topos_node-1.3.36 → topos_node-1.3.38}/topos/mcp_stdio_proxy.py +0 -0
  510. {topos_node-1.3.36 → topos_node-1.3.38}/topos/observability/__init__.py +0 -0
  511. {topos_node-1.3.36 → topos_node-1.3.38}/topos/observability/alerts.py +0 -0
  512. {topos_node-1.3.36 → topos_node-1.3.38}/topos/observability/metrics.py +0 -0
  513. {topos_node-1.3.36 → topos_node-1.3.38}/topos/observability/tracing.py +0 -0
  514. {topos_node-1.3.36 → topos_node-1.3.38}/topos/openai_client.py +0 -0
  515. {topos_node-1.3.36 → topos_node-1.3.38}/topos/owner_key.py +0 -0
  516. {topos_node-1.3.36 → topos_node-1.3.38}/topos/pipeline/__init__.py +0 -0
  517. {topos_node-1.3.36 → topos_node-1.3.38}/topos/pipeline/audit.py +0 -0
  518. {topos_node-1.3.36 → topos_node-1.3.38}/topos/pipeline/envelope.py +0 -0
  519. {topos_node-1.3.36 → topos_node-1.3.38}/topos/pipeline/job_runner.py +0 -0
  520. {topos_node-1.3.36 → topos_node-1.3.38}/topos/pipeline/job_store.py +0 -0
  521. {topos_node-1.3.36 → topos_node-1.3.38}/topos/pipeline/stages.py +0 -0
  522. {topos_node-1.3.36 → topos_node-1.3.38}/topos/pipeline/stub_enqueue.py +0 -0
  523. {topos_node-1.3.36 → topos_node-1.3.38}/topos/principal.py +0 -0
  524. {topos_node-1.3.36 → topos_node-1.3.38}/topos/profiles.py +0 -0
  525. {topos_node-1.3.36 → topos_node-1.3.38}/topos/projections/__init__.py +0 -0
  526. {topos_node-1.3.36 → topos_node-1.3.38}/topos/projections/vector_index/__init__.py +0 -0
  527. {topos_node-1.3.36 → topos_node-1.3.38}/topos/projections/vector_index/base.py +0 -0
  528. {topos_node-1.3.36 → topos_node-1.3.38}/topos/projections/vector_index/builders.py +0 -0
  529. {topos_node-1.3.36 → topos_node-1.3.38}/topos/projections/vector_index/health_checks.py +0 -0
  530. {topos_node-1.3.36 → topos_node-1.3.38}/topos/protocol/__init__.py +0 -0
  531. {topos_node-1.3.36 → topos_node-1.3.38}/topos/protocol/handled_message_types.json +0 -0
  532. {topos_node-1.3.36 → topos_node-1.3.38}/topos/protocol/narrowing_vocabulary.json +0 -0
  533. {topos_node-1.3.36 → topos_node-1.3.38}/topos/protocol/query_field_contract.json +0 -0
  534. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/__init__.py +0 -0
  535. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/audit.py +0 -0
  536. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/closeness.py +0 -0
  537. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/cohort_resolvers.py +0 -0
  538. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/collaborators.py +0 -0
  539. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/ddr.py +0 -0
  540. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/disclosure.py +0 -0
  541. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/entity_window.py +0 -0
  542. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/exclusion.py +0 -0
  543. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/facts_direct.py +0 -0
  544. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/fingerprint.py +0 -0
  545. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/game_layer.py +0 -0
  546. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/grant_cache.py +0 -0
  547. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/inference.py +0 -0
  548. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/intent.py +0 -0
  549. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/manifest.py +0 -0
  550. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/manifest_validation.py +0 -0
  551. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/minimizer.py +0 -0
  552. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/narrowing.py +0 -0
  553. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/negotiation.py +0 -0
  554. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/packet_resolution.py +0 -0
  555. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/pipeline.py +0 -0
  556. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/planner.py +0 -0
  557. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/retrieval.py +0 -0
  558. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/runtime.py +0 -0
  559. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/scope_arbiter.py +0 -0
  560. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/scope_classifier.py +0 -0
  561. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/scope_head.py +0 -0
  562. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/scope_registry.json +0 -0
  563. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/scope_registry_loader.py +0 -0
  564. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/scope_shadow.py +0 -0
  565. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/session.py +0 -0
  566. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/session_utils.py +0 -0
  567. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/source_generation.py +0 -0
  568. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/truth_facts.py +0 -0
  569. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/truth_prompts.py +0 -0
  570. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/turn_classifier.py +0 -0
  571. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/types.py +0 -0
  572. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/verify.py +0 -0
  573. {topos_node-1.3.36 → topos_node-1.3.38}/topos/query/verify_modes.py +0 -0
  574. {topos_node-1.3.36 → topos_node-1.3.38}/topos/rate_limit.py +0 -0
  575. {topos_node-1.3.36 → topos_node-1.3.38}/topos/relay_stamp.py +0 -0
  576. {topos_node-1.3.36 → topos_node-1.3.38}/topos/routines/__init__.py +0 -0
  577. {topos_node-1.3.36 → topos_node-1.3.38}/topos/routines/schema.py +0 -0
  578. {topos_node-1.3.36 → topos_node-1.3.38}/topos/routines/store.py +0 -0
  579. {topos_node-1.3.36 → topos_node-1.3.38}/topos/runtime_housekeeping.py +0 -0
  580. {topos_node-1.3.36 → topos_node-1.3.38}/topos/runtime_shutdown.py +0 -0
  581. {topos_node-1.3.36 → topos_node-1.3.38}/topos/runtime_update.py +0 -0
  582. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sanitization/__init__.py +0 -0
  583. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sanitization/nsfw_classifier.py +0 -0
  584. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sanitization/ollama_transforms.py +0 -0
  585. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sanitization/prewarm.py +0 -0
  586. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sanitization/privacy_filter.py +0 -0
  587. {topos_node-1.3.36 → topos_node-1.3.38}/topos/scope_resolution.py +0 -0
  588. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/__init__.py +0 -0
  589. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/container.py +0 -0
  590. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/embeddings/__init__.py +0 -0
  591. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/embeddings/base.py +0 -0
  592. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/embeddings/local.py +0 -0
  593. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/embeddings/remote.py +0 -0
  594. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/interfaces.py +0 -0
  595. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/llm/__init__.py +0 -0
  596. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/llm/base.py +0 -0
  597. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/local.py +0 -0
  598. {topos_node-1.3.36 → topos_node-1.3.38}/topos/services/postgres.py +0 -0
  599. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sources/__init__.py +0 -0
  600. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sources/bundled_canonical_triples.py +0 -0
  601. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sources/canonical_signal_defaults.py +0 -0
  602. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sources/declared_field_map_spec.py +0 -0
  603. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sources/definitions.py +0 -0
  604. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sources/install_service.py +0 -0
  605. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sources/registry.py +0 -0
  606. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sources/runtime_install.py +0 -0
  607. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sources/scrub_attribution.py +0 -0
  608. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sources/scrub_service.py +0 -0
  609. {topos_node-1.3.36 → topos_node-1.3.38}/topos/startup_banner.py +0 -0
  610. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/__init__.py +0 -0
  611. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/adapters/__init__.py +0 -0
  612. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/adapters/factory.py +0 -0
  613. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/adapters/fakes.py +0 -0
  614. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/adapters/postgres/stores.py +0 -0
  615. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/adapters/protocols.py +0 -0
  616. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/adapters/sqlite/__init__.py +0 -0
  617. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/adapters/sqlite/stores.py +0 -0
  618. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/adapters/sqlite/vector_search.py +0 -0
  619. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/__init__.py +0 -0
  620. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/activity_tables.py +0 -0
  621. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/ai_chat/__init__.py +0 -0
  622. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/ai_chat/canonicalizer.py +0 -0
  623. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/ai_chat/mapper.py +0 -0
  624. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/ai_chat/model.py +0 -0
  625. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/ai_chat/tables.py +0 -0
  626. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/calendar_contacts_tables.py +0 -0
  627. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/canonical_store.py +0 -0
  628. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/conversations_tables.py +0 -0
  629. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/journal_repair.py +0 -0
  630. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/mapping_store.py +0 -0
  631. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/canonical/postgres.py +0 -0
  632. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/__init__.py +0 -0
  633. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/client.py +0 -0
  634. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/connection_tuning.py +0 -0
  635. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/__init__.py +0 -0
  636. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/activity_events_content_v1.py +0 -0
  637. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/actor_role_v1.py +0 -0
  638. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/affinity_pair_labels_v1.py +0 -0
  639. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/attention_triage_v1.py +0 -0
  640. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/attention_triage_v2.py +0 -0
  641. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/backup.py +0 -0
  642. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/backup_custody.py +0 -0
  643. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/calendar_events_scheduling_v1.py +0 -0
  644. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/canonical_address_book_v1.py +0 -0
  645. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/canonical_disclosure_v1.py +0 -0
  646. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/canonical_nsfw_v1.py +0 -0
  647. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/community_names_v1.py +0 -0
  648. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/complexity_v1.py +0 -0
  649. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/conflict_provenance_v1.py +0 -0
  650. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/conversation_context_v1.py +0 -0
  651. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/derivation_factory_v1.py +0 -0
  652. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/derivation_ledger_v1.py +0 -0
  653. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/derivation_provenance_v1.py +0 -0
  654. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/derived_row_identity_v1.py +0 -0
  655. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/documents_v1.py +0 -0
  656. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/enrichment_record_progress_v1.py +0 -0
  657. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/enrichment_spec_version_v1.py +0 -0
  658. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/entity_affinity_v1.py +0 -0
  659. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/entity_blackhole_v1.py +0 -0
  660. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/entity_context_vectors_v1.py +0 -0
  661. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/entity_context_vectors_v2.py +0 -0
  662. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/entity_edges_validity_v1.py +0 -0
  663. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/entity_mentions_authored_v1.py +0 -0
  664. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/entity_review_candidate_bar_v1.py +0 -0
  665. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/entity_review_dedup_v1.py +0 -0
  666. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/entity_review_provenance_v1.py +0 -0
  667. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/episodes_v1.py +0 -0
  668. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/extraction_artifacts.py +0 -0
  669. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/fact_dimension_by_entity_type_v1.py +0 -0
  670. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/journal_entries_duration_v1.py +0 -0
  671. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/journal_entries_ends_at_v1.py +0 -0
  672. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/journal_entries_people_v1.py +0 -0
  673. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/journal_entries_place_name_v1.py +0 -0
  674. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/journal_entries_starts_at_v1.py +0 -0
  675. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/journal_origin_dimension_v1.py +0 -0
  676. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/mention_table_stamp_backfill_v1.py +0 -0
  677. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/message_emotions_role_backfill_v1.py +0 -0
  678. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/message_emotions_role_v1.py +0 -0
  679. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/net_subject_policy_v1.py +0 -0
  680. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/pack_registry_v1.py +0 -0
  681. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/query_artifacts_duration_ms_v1.py +0 -0
  682. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/registry.py +0 -0
  683. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/registry_checksums.json +0 -0
  684. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/remediation_person_model.py +0 -0
  685. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/retire_url_classification_v1.py +0 -0
  686. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/scope_source_generation.py +0 -0
  687. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/signal_dimension_backfill_v1.py +0 -0
  688. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/signal_dimension_harness.py +0 -0
  689. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/signal_objects.py +0 -0
  690. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/signal_objects_period_v1.py +0 -0
  691. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/signal_objects_updated_by_v1.py +0 -0
  692. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/signal_summaries_drop_v1.py +0 -0
  693. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
  694. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/vector_storage_v1.py +0 -0
  695. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/vector_storage_v2.py +0 -0
  696. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/vector_storage_v3.py +0 -0
  697. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/vector_storage_v4.py +0 -0
  698. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_clusters_v2.py +0 -0
  699. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_entities_v1.py +0 -0
  700. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_entity_review_v2.py +0 -0
  701. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_facts_v1.py +0 -0
  702. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_lifecycle_v1.py +0 -0
  703. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_mvp_phase0.py +0 -0
  704. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_mvp_phase1.py +0 -0
  705. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +0 -0
  706. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +0 -0
  707. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +0 -0
  708. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_mvp_query_quality.py +0 -0
  709. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +0 -0
  710. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_stats_v1.py +0 -0
  711. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/migrations/wiki_timeline_v1.py +0 -0
  712. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/paths.py +0 -0
  713. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/postgres.py +0 -0
  714. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/schema.py +0 -0
  715. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/schema_probe.py +0 -0
  716. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/storage_breakdown.py +0 -0
  717. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/db/write_gate.py +0 -0
  718. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/derived_row_identity.py +0 -0
  719. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/enrichment/__init__.py +0 -0
  720. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
  721. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
  722. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/normalized/__init__.py +0 -0
  723. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/normalized/normalized_store.py +0 -0
  724. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/oplog/__init__.py +0 -0
  725. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/oplog/decision.py +0 -0
  726. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/oplog/oplog_store.py +0 -0
  727. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/oplog/postgres.py +0 -0
  728. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/person/identity_resolver.py +0 -0
  729. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/projections/__init__.py +0 -0
  730. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/projections/index_ops_store.py +0 -0
  731. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/projections/vector_index_store.py +0 -0
  732. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/raw/__init__.py +0 -0
  733. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/raw/browser_flat_tables.py +0 -0
  734. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/raw/file_store.py +0 -0
  735. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/raw/raw_store.py +0 -0
  736. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/raw/raw_tables_manager.py +0 -0
  737. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/raw/sqlite_raw_store.py +0 -0
  738. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/security/encryption.py +0 -0
  739. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/signal_identity.py +0 -0
  740. {topos_node-1.3.36 → topos_node-1.3.38}/topos/storage/user_identity.py +0 -0
  741. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sync/__init__.py +0 -0
  742. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sync/client.py +0 -0
  743. {topos_node-1.3.36 → topos_node-1.3.38}/topos/sync_handlers.py +0 -0
  744. {topos_node-1.3.36 → topos_node-1.3.38}/topos/testing/__init__.py +0 -0
  745. {topos_node-1.3.36 → topos_node-1.3.38}/topos/testing/lifespan.py +0 -0
  746. {topos_node-1.3.36 → topos_node-1.3.38}/topos/uds.py +0 -0
  747. {topos_node-1.3.36 → topos_node-1.3.38}/topos/uma_contact_enrichment.py +0 -0
  748. {topos_node-1.3.36 → topos_node-1.3.38}/topos/uma_filters.py +0 -0
  749. {topos_node-1.3.36 → topos_node-1.3.38}/topos/uma_resource_id.py +0 -0
  750. {topos_node-1.3.36 → topos_node-1.3.38}/topos/uma_rpt.py +0 -0
  751. {topos_node-1.3.36 → topos_node-1.3.38}/topos/upgrades/__init__.py +0 -0
  752. {topos_node-1.3.36 → topos_node-1.3.38}/topos/upgrades/runner.py +0 -0
  753. {topos_node-1.3.36 → topos_node-1.3.38}/topos/utils/base_object.py +0 -0
  754. {topos_node-1.3.36 → topos_node-1.3.38}/topos/websocket_client.py +0 -0
  755. {topos_node-1.3.36 → topos_node-1.3.38}/topos_node.egg-info/dependency_links.txt +0 -0
  756. {topos_node-1.3.36 → topos_node-1.3.38}/topos_node.egg-info/entry_points.txt +0 -0
  757. {topos_node-1.3.36 → topos_node-1.3.38}/topos_node.egg-info/requires.txt +0 -0
  758. {topos_node-1.3.36 → topos_node-1.3.38}/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.3.36
3
+ Version: 1.3.38
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.3.36"
7
+ version = "1.3.38"
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"
@@ -1,6 +1,6 @@
1
1
  """Topos Control Plane Version Information."""
2
2
 
3
- __version__ = "1.3.36"
4
- __version_info__ = (1, 3, 36)
3
+ __version__ = "1.3.38"
4
+ __version_info__ = (1, 3, 38)
5
5
 
6
6
  __all__ = ["__version__", "__version_info__"]
@@ -158,7 +158,7 @@ async def put_source_settings_endpoint(
158
158
  dataset_id: Optional[str] = Query(default=None),
159
159
  body: Optional[dict] = Body(default=None),
160
160
  ):
161
- """Set source settings (e.g. enabled). Valid for local_sync sources (imessage, signal)."""
161
+ """Set source settings (e.g. enabled, exclude_spam). Valid for local_sync sources (imessage, signal)."""
162
162
  source = REGISTRY.get(source_id)
163
163
  if not source:
164
164
  return {"status": "error", "error": "unknown source_id"}
@@ -167,14 +167,26 @@ async def put_source_settings_endpoint(
167
167
  dataset_id = dataset_id or (body.get("dataset_id") if body else None)
168
168
  if not dataset_id:
169
169
  return {"status": "error", "error": "dataset_id required"}
170
- enabled = body.get("enabled") if body else None
171
- if enabled is None:
172
- return {"status": "error", "error": "enabled required in body"}
170
+ body = body or {}
171
+ enabled = body.get("enabled")
172
+ posture_provided = "posture" in body
173
+ exclude_spam_provided = "exclude_spam" in body
174
+ if enabled is None and not posture_provided and not exclude_spam_provided:
175
+ return {"status": "error", "error": "enabled, posture, or exclude_spam required in body"}
173
176
  conn = get_db_connection()
174
177
  if not conn:
175
178
  return {"status": "error", "error": "Database not available"}
176
- put_source_settings(conn, dataset_id, source_id, enabled=enabled)
177
- return {"status": "ok", "dataset_id": dataset_id, "source_id": source_id, "enabled": bool(enabled)}
179
+ put_kwargs: dict = {"enabled": enabled}
180
+ if posture_provided:
181
+ put_kwargs["posture"] = body.get("posture")
182
+ if exclude_spam_provided:
183
+ put_kwargs["exclude_spam"] = bool(body.get("exclude_spam"))
184
+ try:
185
+ put_source_settings(conn, dataset_id, source_id, **put_kwargs)
186
+ except ValueError as exc:
187
+ return {"status": "error", "error": str(exc)}
188
+ settings = get_source_settings(conn, dataset_id, source_id) or {}
189
+ return {"status": "ok", "dataset_id": dataset_id, "source_id": source_id, **settings}
178
190
 
179
191
 
180
192
  @router.post("/sources/{source_id}/sync", dependencies=[Depends(require_api_key)])
@@ -682,28 +682,37 @@ async def blackhole_entity(
682
682
  """
683
683
  import asyncio
684
684
 
685
+ from ..core.state import close_thread_db_connection
685
686
  from ..features.lifecycle.blackhole import BlackholeStore
686
687
  from ..features.lifecycle.blackhole_rebuild import rebuild_for_blackhole
687
688
 
688
- conn = _entities_conn()
689
+ _entities_conn() # fail fast with 503 before spawning the worker
690
+ processing_tier = body.processing_tier
691
+ note = body.note
692
+
693
+ def _blackhole():
694
+ try:
695
+ conn = _entities_conn()
696
+ result = BlackholeStore(conn).blackhole_entity(
697
+ entity_ref=entity_id,
698
+ processing_tier=processing_tier,
699
+ note=note,
700
+ )
701
+ # D4: the notification above was raised first, so the owner already
702
+ # knows the hide is incomplete; now do the rebuild that makes it
703
+ # true. Same worker / same connection — do not hop back to the loop
704
+ # with a write-gate hold still possible.
705
+ if not result.get("already_blackholed"):
706
+ result["rebuild"] = rebuild_for_blackhole(conn, entity_id).as_dict()
707
+ return result
708
+ finally:
709
+ close_thread_db_connection()
710
+
689
711
  try:
690
- result = BlackholeStore(conn).blackhole_entity(
691
- entity_ref=entity_id,
692
- processing_tier=body.processing_tier,
693
- note=body.note,
694
- )
712
+ return await asyncio.to_thread(_blackhole)
695
713
  except ValueError as exc:
696
714
  raise HTTPException(status_code=400, detail=str(exc))
697
715
 
698
- # D4: the notification above was raised first, so the owner already knows the
699
- # hide is incomplete; now do the rebuild that makes it true. Non-owners are
700
- # withheld the prose artifacts for the duration, so this running late is safe
701
- # while it running silently would not be.
702
- if not result.get("already_blackholed"):
703
- result["rebuild"] = await asyncio.to_thread(rebuild_for_blackhole, conn, entity_id)
704
- result["rebuild"] = result["rebuild"].as_dict()
705
- return result
706
-
707
716
 
708
717
  @router.delete("/entities/{entity_id}/blackhole")
709
718
  async def unblackhole_entity(
@@ -711,9 +720,20 @@ async def unblackhole_entity(
711
720
  _api_key: str = Depends(require_api_key),
712
721
  ):
713
722
  """Lift a black hole. Existing grants are not restored — normal permissions resume."""
723
+ import asyncio
724
+
725
+ from ..core.state import close_thread_db_connection
714
726
  from ..features.lifecycle.blackhole import BlackholeStore
715
727
 
716
- return BlackholeStore(_entities_conn()).unblackhole_entity(entity_ref=entity_id)
728
+ _entities_conn() # fail fast with 503 before spawning the worker
729
+
730
+ def _unblackhole():
731
+ try:
732
+ return BlackholeStore(_entities_conn()).unblackhole_entity(entity_ref=entity_id)
733
+ finally:
734
+ close_thread_db_connection()
735
+
736
+ return await asyncio.to_thread(_unblackhole)
717
737
 
718
738
 
719
739
  @router.get("/blackholes")
@@ -2,8 +2,9 @@
2
2
 
3
3
  Port of the original open-source topos-cli ``menu_bar_app`` (pystray + PIL):
4
4
  the Topos glyph with a status dot composited in the corner — yellow while
5
- starting, green while the node answers ``/healthcheck``, red while it does
6
- not, orange when a newer topos-node is published on PyPI. The menu offers
5
+ starting, green while the node answers ``/healthcheck``, red only after
6
+ repeated misses (a single late probe is a busy node, not a dead one),
7
+ orange when a newer topos-node is published on PyPI. The menu offers
7
8
  API docs, the hosted Topos app, a one-click update when one is available,
8
9
  and Quit.
9
10
 
@@ -33,10 +34,36 @@ STATUS_COLORS = {
33
34
  }
34
35
 
35
36
  HEALTH_POLL_SECONDS = 5.0
37
+ #: Must sit above ``probe_db_health``'s 2s budget. A 3s client deadline raced
38
+ #: the probe under ingest load and painted the tray red for a live node.
39
+ HEALTH_TIMEOUT_SECONDS = 10.0
40
+ #: One missed probe is a stalled event loop, not a down node. Two in a row
41
+ #: is enough to go red; a single success clears the count (same shape as
42
+ #: the web app's ``HEALTH_FAILURE_THRESHOLD``).
43
+ HEALTH_FAILURE_THRESHOLD = 2
36
44
  TOPOS_APP_URL = "https://topos.dialogues.ai"
37
45
  TOPOS_DOCS_URL = "https://topos.dialogues.ai/docs/welcome"
38
46
 
39
47
 
48
+ def resolve_tray_health_status(
49
+ *,
50
+ probe_ok: bool,
51
+ consecutive_failures: int,
52
+ current_status: str,
53
+ failure_threshold: int = HEALTH_FAILURE_THRESHOLD,
54
+ ) -> tuple[str, int]:
55
+ """Map one ``/healthcheck`` result to (next_status, next_failure_count).
56
+
57
+ A single timeout must not flip a green (or still-starting) icon to red.
58
+ """
59
+ if probe_ok:
60
+ return "healthy", 0
61
+ failures = consecutive_failures + 1
62
+ if failures >= failure_threshold:
63
+ return "down", failures
64
+ return current_status, failures
65
+
66
+
40
67
  def tray_available() -> bool:
41
68
  try:
42
69
  import pystray # noqa: F401
@@ -214,16 +241,24 @@ class ToposTray:
214
241
  def _poll_health(self) -> None:
215
242
  import httpx
216
243
 
244
+ consecutive_failures = 0
217
245
  while self._icon is not None and self._icon.visible:
218
246
  try:
219
247
  # 401/403 = health auth enabled; the node answered, so it's up.
220
- healthy = httpx.get(self.health_url, timeout=3.0).status_code in (200, 401, 403)
248
+ healthy = httpx.get(
249
+ self.health_url, timeout=HEALTH_TIMEOUT_SECONDS
250
+ ).status_code in (200, 401, 403)
221
251
  except Exception:
222
252
  healthy = False
223
253
  if healthy:
224
254
  self._fetch_shell_status()
225
255
  self._maybe_fetch_topos_name()
226
- self._set_status("healthy" if healthy else "down")
256
+ next_status, consecutive_failures = resolve_tray_health_status(
257
+ probe_ok=healthy,
258
+ consecutive_failures=consecutive_failures,
259
+ current_status=self.status,
260
+ )
261
+ self._set_status(next_status)
227
262
  time.sleep(HEALTH_POLL_SECONDS)
228
263
 
229
264
  def _fetch_shell_status(self) -> None:
@@ -1031,7 +1031,10 @@ async def handle_signal_unblackhole_entity(message: Dict[str, Any]) -> Optional[
1031
1031
  try:
1032
1032
  from ...features.lifecycle.blackhole import BlackholeStore
1033
1033
 
1034
- result = BlackholeStore(hub.get_db_connection()).unblackhole_entity(entity_ref=entity_id)
1034
+ def _unblackhole(conn):
1035
+ return BlackholeStore(conn).unblackhole_entity(entity_ref=entity_id)
1036
+
1037
+ result = await run_db_write(_unblackhole)
1035
1038
  return {"id": req_id, "status": "ok", "payload": result}
1036
1039
  except Exception as exc: # noqa: BLE001
1037
1040
  return {"id": req_id, "status": "error", "error": str(exc)}
@@ -198,6 +198,8 @@ async def handle_put_source_settings(message: Dict[str, Any]) -> Optional[Dict[s
198
198
  # present in the body — absent means "leave unchanged".
199
199
  posture_provided = "posture" in payload
200
200
  posture = payload.get("posture")
201
+ exclude_spam_provided = "exclude_spam" in payload
202
+ exclude_spam = payload.get("exclude_spam")
201
203
  if not source_id or not dataset_id:
202
204
  return {"id": req_id, "status": "error", "error": "source_id and dataset_id required"}
203
205
  source = REGISTRY.get(source_id)
@@ -208,16 +210,20 @@ async def handle_put_source_settings(message: Dict[str, Any]) -> Optional[Dict[s
208
210
  # enabled toggle is being set.
209
211
  if enabled is not None and getattr(source, "source_type", None) != "local_sync":
210
212
  return {"id": req_id, "status": "error", "error": "enabled only applies to local_sync sources"}
211
- if enabled is None and not posture_provided:
212
- return {"id": req_id, "status": "error", "error": "enabled or posture required in body"}
213
+ if exclude_spam_provided and getattr(source, "source_type", None) != "local_sync":
214
+ return {"id": req_id, "status": "error", "error": "exclude_spam only applies to local_sync sources"}
215
+ if enabled is None and not posture_provided and not exclude_spam_provided:
216
+ return {"id": req_id, "status": "error", "error": "enabled, posture, or exclude_spam required in body"}
213
217
  conn = hub.get_db_connection()
214
218
  if not conn:
215
219
  return {"id": req_id, "status": "error", "error": "Database not available"}
216
220
  try:
221
+ put_kwargs: Dict[str, Any] = {"enabled": enabled}
217
222
  if posture_provided:
218
- put_source_settings(conn, dataset_id, source_id, enabled=enabled, posture=posture)
219
- else:
220
- put_source_settings(conn, dataset_id, source_id, enabled=enabled)
223
+ put_kwargs["posture"] = posture
224
+ if exclude_spam_provided:
225
+ put_kwargs["exclude_spam"] = bool(exclude_spam)
226
+ put_source_settings(conn, dataset_id, source_id, **put_kwargs)
221
227
  except ValueError as exc:
222
228
  return {"id": req_id, "status": "error", "error": str(exc)}
223
229
  # Echo the effective settings back (posture reflects what was persisted /
@@ -229,6 +235,7 @@ async def handle_put_source_settings(message: Dict[str, Any]) -> Optional[Dict[s
229
235
  else:
230
236
  result_payload["enabled"] = bool(settings_data.get("enabled", True))
231
237
  result_payload["posture"] = settings_data.get("posture")
238
+ result_payload["exclude_spam"] = bool(settings_data.get("exclude_spam", True))
232
239
  return {"id": req_id, "status": "ok", "payload": result_payload}
233
240
 
234
241
  @handles("get_source_contacts")
@@ -110,6 +110,12 @@ class OllamaAdapter:
110
110
  except Exception:
111
111
  return False
112
112
 
113
+ def _ensure_server(self) -> None:
114
+ """Start a local Ollama if this request needs one and :11434 is down."""
115
+ from ..ollama_runtime import ensure_running
116
+
117
+ ensure_running(base_url=self._base_url)
118
+
113
119
  def model_supports_thinking(self, model: str) -> bool:
114
120
  """True when /api/show lists the 'thinking' capability for ``model``.
115
121
 
@@ -172,6 +178,7 @@ class OllamaAdapter:
172
178
  curated table — Ollama has no size for a tag that is not on disk
173
179
  (PLAN_LOCAL_MODEL_QUICKSTART D4).
174
180
  """
181
+ self._ensure_server()
175
182
  req = urllib.request.Request(f"{self._base_url}/api/tags", method="GET")
176
183
  try:
177
184
  with urllib.request.urlopen(req, timeout=10) as resp:
@@ -211,6 +218,7 @@ class OllamaAdapter:
211
218
  show the download to a human. A callback that raises must not abort a
212
219
  multi-gigabyte transfer that is otherwise healthy.
213
220
  """
221
+ self._ensure_server()
214
222
  body = {"model": model_name, "stream": stream}
215
223
  req = urllib.request.Request(
216
224
  f"{self._base_url}/api/pull",
@@ -361,6 +369,7 @@ class OllamaAdapter:
361
369
  # rejected think=false before keep thinking but get a wider output
362
370
  # budget so the CoT cannot starve the answer (Ollama returns thinking
363
371
  # in a separate field, so 'response' stays clean either way).
372
+ self._ensure_server()
364
373
  requested_think = think
365
374
  think = self.resolve_think(model, think)
366
375
  if (
@@ -0,0 +1,142 @@
1
+ """Start a local Ollama server when a request needs it and :11434 is down.
2
+
3
+ Reachability is already probed everywhere; nothing on the product path used
4
+ to spawn the server. Install opens Ollama.app after a one-click install —
5
+ this module does the same (or ``ollama serve``) at request time, only for a
6
+ localhost base URL, and only once under a process lock.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import logging
12
+ import shutil
13
+ import subprocess
14
+ import threading
15
+ import time
16
+ from typing import Callable, Optional
17
+ from urllib.parse import urlparse
18
+
19
+ logger = logging.getLogger("topos.engine.ollama_runtime")
20
+
21
+ _LOCAL_HOSTS = frozenset({"localhost", "127.0.0.1", "::1"})
22
+ _WAIT_SEC = 20.0
23
+ _POLL_INTERVAL = 0.5
24
+
25
+ _LOCK = threading.Lock()
26
+
27
+
28
+ def _default_base_url() -> str:
29
+ try:
30
+ from ..config.settings import settings
31
+
32
+ return str(getattr(settings, "engine_ollama_base_url", None) or "http://localhost:11434").rstrip("/")
33
+ except Exception:
34
+ return "http://localhost:11434"
35
+
36
+
37
+ def is_local_base_url(url: str) -> bool:
38
+ raw = str(url or "").strip()
39
+ if not raw:
40
+ return False
41
+ parsed = urlparse(raw if "://" in raw else f"http://{raw}")
42
+ host = (parsed.hostname or "").lower()
43
+ return host in _LOCAL_HOSTS
44
+
45
+
46
+ def default_is_reachable(base_url: str) -> bool:
47
+ from .backends.ollama import OllamaAdapter
48
+
49
+ return bool(OllamaAdapter(base_url=base_url).is_reachable())
50
+
51
+
52
+ def default_app_present() -> bool:
53
+ from .ollama_install import default_app_present as _app_present
54
+
55
+ return bool(_app_present())
56
+
57
+
58
+ def default_open_app() -> None:
59
+ from .ollama_install import default_open_app as _open_app
60
+
61
+ _open_app()
62
+
63
+
64
+ def default_cli_present() -> bool:
65
+ return shutil.which("ollama") is not None
66
+
67
+
68
+ def default_spawn_serve() -> None:
69
+ subprocess.Popen(
70
+ ["ollama", "serve"],
71
+ stdout=subprocess.DEVNULL,
72
+ stderr=subprocess.DEVNULL,
73
+ start_new_session=True,
74
+ )
75
+
76
+
77
+ def ensure_running(
78
+ *,
79
+ base_url: Optional[str] = None,
80
+ is_reachable: Optional[Callable[[], bool]] = None,
81
+ is_local: Optional[Callable[[str], bool]] = None,
82
+ app_present: Optional[Callable[[], bool]] = None,
83
+ open_app: Optional[Callable[[], None]] = None,
84
+ cli_present: Optional[Callable[[], bool]] = None,
85
+ spawn_serve: Optional[Callable[[], None]] = None,
86
+ sleep: Optional[Callable[[float], None]] = None,
87
+ wait_sec: float = _WAIT_SEC,
88
+ poll_interval: float = _POLL_INTERVAL,
89
+ ) -> bool:
90
+ """Bring a local Ollama up if a request needs it.
91
+
92
+ Returns True when the server answers ``/api/tags`` (already up, or up
93
+ after we launched). Returns False when the URL is remote, nothing is
94
+ installed, or the wait timed out — callers then hit the existing 502 /
95
+ deferred path.
96
+ """
97
+ url = (base_url if base_url is not None else _default_base_url()).rstrip("/")
98
+ local_check = is_local if is_local is not None else is_local_base_url
99
+ if not local_check(url):
100
+ return False
101
+
102
+ reachable = is_reachable if is_reachable is not None else (lambda: default_is_reachable(url))
103
+ if reachable():
104
+ return True
105
+
106
+ with _LOCK:
107
+ if reachable():
108
+ return True
109
+
110
+ launched = False
111
+ present = app_present if app_present is not None else default_app_present
112
+ if present():
113
+ try:
114
+ (open_app if open_app is not None else default_open_app)()
115
+ launched = True
116
+ logger.info("opened Ollama.app; waiting for %s", url)
117
+ except Exception as exc: # noqa: BLE001 — launch is best-effort
118
+ logger.warning("failed to open Ollama.app: %s", exc)
119
+
120
+ if not launched:
121
+ has_cli = cli_present if cli_present is not None else default_cli_present
122
+ if has_cli():
123
+ try:
124
+ (spawn_serve if spawn_serve is not None else default_spawn_serve)()
125
+ launched = True
126
+ logger.info("spawned `ollama serve`; waiting for %s", url)
127
+ except Exception as exc: # noqa: BLE001
128
+ logger.warning("failed to spawn ollama serve: %s", exc)
129
+
130
+ if not launched:
131
+ logger.info("ollama is down and nothing on this machine can start it")
132
+ return False
133
+
134
+ sleeper = sleep if sleep is not None else time.sleep
135
+ deadline = time.monotonic() + float(wait_sec)
136
+ interval = max(0.0, float(poll_interval))
137
+ while time.monotonic() < deadline:
138
+ if reachable():
139
+ return True
140
+ sleeper(interval)
141
+ logger.warning("ollama did not become reachable at %s within %.1fs", url, wait_sec)
142
+ return False
@@ -106,6 +106,123 @@ def list_entities(
106
106
  }
107
107
 
108
108
 
109
+ def entity_card_aggregates(
110
+ conn: sqlite3.Connection,
111
+ entity_id: str,
112
+ *,
113
+ guard: BlackholeGuard,
114
+ ) -> Dict[str, Any]:
115
+ """Full-population counts a type-specific entity card reads.
116
+
117
+ Separate from ``recent_mentions`` because they answer a different question.
118
+ ``recent_mentions`` is a SAMPLE — twenty rows, newest first — and a card that
119
+ derived "83% of this came from browsing" by counting a sample would be
120
+ stating a measurement it had not made. Every count here is over the whole
121
+ mention set.
122
+
123
+ Two aggregates, because the card designs turn on two distinctions the spine
124
+ already records and nothing has ever read:
125
+
126
+ ``mention_sources``
127
+ Mentions grouped by canonical table, with the owner-authored share. This
128
+ is what separates an organization the owner *writes about* from one whose
129
+ name appeared in a page title, a place they have *been* (``location_events``)
130
+ from one they only ever talked about, and a project they *work on*
131
+ (``activity_events``) from one they have only planned. The whole judgement
132
+ line of six of the ten cards rests on it.
133
+
134
+ ``neighbor_counts``
135
+ Edges grouped by ``(edge_type, direction, neighbour type)``. The card needs
136
+ "6 people around this" and "14 goals point at it", and ``connections`` is
137
+ capped at twelve rows ordered by weight — a cap is the right answer for a
138
+ list and the wrong one for a count.
139
+
140
+ Direction is kept because it is load-bearing for at least one type: a
141
+ conversation's ``participates_in`` (inbound, someone was there) and its
142
+ ``mentions`` (outbound, someone was named) are different claims about a
143
+ person, and a card that merged them would say a person who was discussed was
144
+ in the room.
145
+ """
146
+ eid = str(entity_id)
147
+
148
+ # A record that names a protected entity is withheld whole, so its mentions
149
+ # of THIS entity cannot be counted either — otherwise the total silently
150
+ # disagrees with the records the reader is allowed to open, and the size of
151
+ # the disagreement is a signal about what was hidden. Inert for the owner UI,
152
+ # where `sees_everything` short-circuits `blocked_record_ids` to an empty set.
153
+ blocked_records = guard.blocked_record_ids()
154
+
155
+ mention_rows = conn.execute(
156
+ """
157
+ SELECT record_id, COALESCE(canonical_table, ''), COALESCE(authored_by_owner, 0)
158
+ FROM entity_mentions WHERE entity_id = ?
159
+ """,
160
+ (eid,),
161
+ ).fetchall()
162
+
163
+ by_table: Dict[str, Dict[str, int]] = {}
164
+ for record_id, table, authored in mention_rows:
165
+ if blocked_records and str(record_id) in blocked_records:
166
+ continue
167
+ # An unattributed mention is its own fact — bucketed under "" rather than
168
+ # dropped, so the card's percentages are over the same denominator as its
169
+ # total and cannot quietly exceed 100%.
170
+ slot = by_table.setdefault(str(table), {"count": 0, "owner_authored": 0})
171
+ slot["count"] += 1
172
+ if int(authored or 0) == 1:
173
+ slot["owner_authored"] += 1
174
+
175
+ mention_sources = sorted(
176
+ (
177
+ {"table": table, "count": v["count"], "owner_authored": v["owner_authored"]}
178
+ for table, v in by_table.items()
179
+ ),
180
+ key=lambda r: (-int(r["count"]), str(r["table"])),
181
+ )
182
+
183
+ # Counted in Python rather than pushed into a GROUP BY so the guard applies
184
+ # per neighbour: a protected entity must not be counted, and a SQL count
185
+ # would include it while the neighbour LIST beside it does not.
186
+ edge_rows = conn.execute(
187
+ """
188
+ SELECT e.src_entity_id, e.dst_entity_id, e.edge_type,
189
+ COALESCE(s.entity_type, ''), COALESCE(t.entity_type, ''),
190
+ s.canonical_name, t.canonical_name
191
+ FROM entity_edges e
192
+ LEFT JOIN entities s ON s.entity_id = e.src_entity_id
193
+ LEFT JOIN entities t ON t.entity_id = e.dst_entity_id
194
+ WHERE (e.src_entity_id = ? OR e.dst_entity_id = ?) AND e.valid_to IS NULL
195
+ """,
196
+ (eid, eid),
197
+ ).fetchall()
198
+
199
+ tally: Dict[tuple, int] = {}
200
+ for src, dst, edge_type, src_type, dst_type, src_name, dst_name in edge_rows:
201
+ outbound = str(src) == eid
202
+ other_id = dst if outbound else src
203
+ other_type = dst_type if outbound else src_type
204
+ other_name = dst_name if outbound else src_name
205
+ if guard.blocks_entity_id(other_id) or guard.blocks_name(other_name):
206
+ continue
207
+ key = (str(edge_type), "out" if outbound else "in", str(other_type))
208
+ tally[key] = tally.get(key, 0) + 1
209
+
210
+ neighbor_counts = sorted(
211
+ (
212
+ {
213
+ "edge_type": edge_type,
214
+ "direction": direction,
215
+ "entity_type": other_type,
216
+ "count": count,
217
+ }
218
+ for (edge_type, direction, other_type), count in tally.items()
219
+ ),
220
+ key=lambda r: (-int(r["count"]), str(r["edge_type"]), str(r["entity_type"])),
221
+ )
222
+
223
+ return {"mention_sources": mention_sources, "neighbor_counts": neighbor_counts}
224
+
225
+
109
226
  def get_entity_detail(
110
227
  conn: sqlite3.Connection,
111
228
  entity_id: str,
@@ -175,6 +292,12 @@ def get_entity_detail(
175
292
  entity["affinity_connections"] = guard.filter_rows(
176
293
  affinity, id_keys=id_keys, name_keys=name_keys
177
294
  )
295
+ # Full-population counts for the type-specific cards. Attached to every
296
+ # entity rather than branching on type here: the card layer decides what a
297
+ # place does with `location_events` and what an org does with the
298
+ # owner-authored share, and a read that guessed for it would have to be
299
+ # changed every time a card learns a new question.
300
+ entity.update(entity_card_aggregates(conn, str(entity_id), guard=guard))
178
301
  dossier = load_dossier_for_entity(conn, str(entity_id))
179
302
  if isinstance(dossier, dict) and not guard.sees_everything:
180
303
  dossier = dict(dossier)