topos-node 0.1.18__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. {topos_node-0.1.18 → topos_node-1.0.0}/PKG-INFO +23 -10
  2. {topos_node-0.1.18 → topos_node-1.0.0}/README.md +1 -1
  3. {topos_node-0.1.18 → topos_node-1.0.0}/pyproject.toml +31 -8
  4. {topos_node-0.1.18 → topos_node-1.0.0}/topos/__version__.py +2 -2
  5. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/enrichment.py +61 -101
  6. topos_node-1.0.0/topos/api/ingestion_api.py +66 -0
  7. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/ingestion_sources.py +5 -1
  8. topos_node-1.0.0/topos/api/privacy_disclose.py +85 -0
  9. topos_node-1.0.0/topos/api/signal.py +306 -0
  10. topos_node-1.0.0/topos/api/signal_extraction_config.py +63 -0
  11. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/source_install.py +1 -0
  12. topos_node-1.0.0/topos/api/source_scrub.py +71 -0
  13. {topos_node-0.1.18 → topos_node-1.0.0}/topos/app.py +23 -1
  14. topos_node-1.0.0/topos/canonicalization/mappers/__init__.py +44 -0
  15. topos_node-1.0.0/topos/canonicalization/mappers/browser_activity_mapper.py +31 -0
  16. {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/mappers/chatgpt_mapper.py +3 -1
  17. topos_node-1.0.0/topos/canonicalization/mappers/demo_mappers.py +199 -0
  18. {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/mappers/messenger_mapper.py +12 -0
  19. {topos_node-0.1.18 → topos_node-1.0.0}/topos/cli/commands.py +2 -1
  20. {topos_node-0.1.18 → topos_node-1.0.0}/topos/config/settings.py +21 -0
  21. topos_node-1.0.0/topos/config/signal_extraction.py +167 -0
  22. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/api_models.py +2 -0
  23. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/handlers.py +881 -122
  24. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/logging.py +33 -0
  25. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/state.py +6 -0
  26. topos_node-1.0.0/topos/data_explorer_row_delete.py +603 -0
  27. topos_node-1.0.0/topos/data_explorer_tables.py +26 -0
  28. topos_node-1.0.0/topos/disclosure/__init__.py +29 -0
  29. topos_node-1.0.0/topos/disclosure/canonical_writer.py +78 -0
  30. topos_node-1.0.0/topos/disclosure/content_policy.py +67 -0
  31. topos_node-1.0.0/topos/disclosure/field_registry.py +51 -0
  32. topos_node-1.0.0/topos/disclosure/privacy_layer.py +373 -0
  33. topos_node-1.0.0/topos/disclosure/tier.py +107 -0
  34. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/backends/__init__.py +30 -0
  35. topos_node-1.0.0/topos/engine/backends/generative_prompts.py +80 -0
  36. topos_node-1.0.0/topos/engine/backends/generative_response.py +103 -0
  37. topos_node-1.0.0/topos/engine/backends/huggingface.py +348 -0
  38. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/backends/ollama.py +60 -34
  39. topos_node-1.0.0/topos/engine/backends/openai.py +27 -0
  40. topos_node-1.0.0/topos/engine/backends/openai_compatible.py +85 -0
  41. topos_node-1.0.0/topos/engine/backends/redpill.py +45 -0
  42. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/engine.py +15 -0
  43. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/registration.py +18 -1
  44. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/router.py +5 -1
  45. topos_node-1.0.0/topos/enrichment/derived_tables.py +523 -0
  46. topos_node-1.0.0/topos/enrichment/job_writer.py +356 -0
  47. topos_node-1.0.0/topos/enrichment/jobs/__init__.py +70 -0
  48. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/base.py +5 -0
  49. topos_node-1.0.0/topos/enrichment/jobs/canonical/_batch_limits.py +15 -0
  50. topos_node-1.0.0/topos/enrichment/jobs/canonical/_engine_runner.py +32 -0
  51. topos_node-1.0.0/topos/enrichment/jobs/canonical/availability_scores_job.py +53 -0
  52. topos_node-1.0.0/topos/enrichment/jobs/canonical/brief_fallback.py +354 -0
  53. topos_node-1.0.0/topos/enrichment/jobs/canonical/dimension_summary_job.py +203 -0
  54. topos_node-1.0.0/topos/enrichment/jobs/canonical/embeddings_job.py +142 -0
  55. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/canonical/emo_27_job.py +5 -3
  56. topos_node-1.0.0/topos/enrichment/jobs/canonical/entities_job.py +69 -0
  57. topos_node-1.0.0/topos/enrichment/jobs/canonical/goal_extraction_job.py +120 -0
  58. topos_node-1.0.0/topos/enrichment/jobs/canonical/pii_redaction_job.py +128 -0
  59. topos_node-1.0.0/topos/enrichment/jobs/canonical/relationship_edges_job.py +53 -0
  60. topos_node-1.0.0/topos/enrichment/jobs/canonical/sentiment_job.py +66 -0
  61. topos_node-1.0.0/topos/enrichment/jobs/canonical/topic_clusters_job.py +84 -0
  62. topos_node-1.0.0/topos/enrichment/jobs/canonical/topics_job.py +111 -0
  63. topos_node-1.0.0/topos/enrichment/jobs/canonical/url_classification_core.py +113 -0
  64. topos_node-1.0.0/topos/enrichment/jobs/canonical/url_classification_enrichment_job.py +72 -0
  65. topos_node-1.0.0/topos/enrichment/jobs/canonical/url_classification_signal_job.py +54 -0
  66. topos_node-1.0.0/topos/enrichment/models/mvp_defaults.py +51 -0
  67. topos_node-1.0.0/topos/enrichment/orchestrator.py +366 -0
  68. topos_node-1.0.0/topos/enrichment/registry_contract.py +51 -0
  69. topos_node-1.0.0/topos/features/fit/evaluator.py +139 -0
  70. topos_node-1.0.0/topos/features/signal/__init__.py +0 -0
  71. topos_node-1.0.0/topos/features/signal/brief_canonical_loader.py +117 -0
  72. topos_node-1.0.0/topos/features/signal/brief_ontology.py +112 -0
  73. topos_node-1.0.0/topos/features/signal/brief_renderer.py +51 -0
  74. topos_node-1.0.0/topos/features/signal/brief_schemas.py +114 -0
  75. topos_node-1.0.0/topos/features/signal/chunking.py +87 -0
  76. topos_node-1.0.0/topos/features/signal/data_health.py +77 -0
  77. topos_node-1.0.0/topos/features/signal/dimension_briefs.py +307 -0
  78. topos_node-1.0.0/topos/features/signal/dimension_definition_loader.py +111 -0
  79. topos_node-1.0.0/topos/features/signal/dimension_profiles.py +51 -0
  80. topos_node-1.0.0/topos/features/signal/dimension_registry.py +161 -0
  81. topos_node-1.0.0/topos/features/signal/extraction/artifact_router.py +143 -0
  82. topos_node-1.0.0/topos/features/signal/extraction/artifact_store.py +141 -0
  83. topos_node-1.0.0/topos/features/signal/extraction/rule_extractors.py +362 -0
  84. topos_node-1.0.0/topos/features/signal/graph_sanitize.py +61 -0
  85. topos_node-1.0.0/topos/features/signal/hybrid_search.py +106 -0
  86. topos_node-1.0.0/topos/features/signal/query_embed_cache.py +56 -0
  87. topos_node-1.0.0/topos/features/signal/schemas.py +11 -0
  88. topos_node-1.0.0/topos/features/signal/service.py +476 -0
  89. topos_node-1.0.0/topos/features/signal/signal_object_store.py +225 -0
  90. topos_node-1.0.0/topos/features/signal/source_hydration.py +132 -0
  91. topos_node-1.0.0/topos/features/signal/structured_signal.py +113 -0
  92. topos_node-1.0.0/topos/features/signal/topic_clustering.py +1247 -0
  93. topos_node-1.0.0/topos/features/signal/typed_stores/aggregates.py +108 -0
  94. topos_node-1.0.0/topos/features/signal/typed_stores/scope_materializer.py +372 -0
  95. topos_node-1.0.0/topos/features/signal/vector_codec.py +96 -0
  96. topos_node-1.0.0/topos/features/signal/vector_math.py +17 -0
  97. topos_node-1.0.0/topos/features/signal/vector_settings.py +46 -0
  98. {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/worker.py +18 -9
  99. topos_node-1.0.0/topos/ingestion/canonical_pipeline.py +705 -0
  100. topos_node-1.0.0/topos/ingestion/inbox_crypto.py +53 -0
  101. topos_node-1.0.0/topos/ingestion/inbox_drain.py +87 -0
  102. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/ingest_helpers.py +219 -217
  103. topos_node-1.0.0/topos/ingestion/journal_location_fanout.py +44 -0
  104. topos_node-1.0.0/topos/ingestion/journal_time_log_normalize.py +142 -0
  105. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/manager.py +281 -208
  106. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/__init__.py +33 -0
  107. topos_node-1.0.0/topos/ingestion/parsers/demo_file_parsers.py +313 -0
  108. topos_node-1.0.0/topos/ingestion/parsers/voxterm_parser.py +71 -0
  109. topos_node-1.0.0/topos/ingestion/reprocess.py +254 -0
  110. topos_node-1.0.0/topos/ingestion/usage_inbox_dedupe.py +87 -0
  111. topos_node-1.0.0/topos/pipeline/__init__.py +15 -0
  112. topos_node-1.0.0/topos/pipeline/audit.py +171 -0
  113. topos_node-1.0.0/topos/pipeline/envelope.py +90 -0
  114. topos_node-1.0.0/topos/pipeline/stages.py +16 -0
  115. topos_node-1.0.0/topos/pipeline/stub_enqueue.py +55 -0
  116. topos_node-1.0.0/topos/query/__init__.py +34 -0
  117. topos_node-1.0.0/topos/query/audit.py +45 -0
  118. topos_node-1.0.0/topos/query/disclosure.py +115 -0
  119. topos_node-1.0.0/topos/query/fingerprint.py +21 -0
  120. topos_node-1.0.0/topos/query/game_layer.py +175 -0
  121. topos_node-1.0.0/topos/query/inference.py +70 -0
  122. topos_node-1.0.0/topos/query/intent.py +18 -0
  123. topos_node-1.0.0/topos/query/manifest.py +45 -0
  124. topos_node-1.0.0/topos/query/manifest_validation.py +90 -0
  125. topos_node-1.0.0/topos/query/pipeline.py +364 -0
  126. topos_node-1.0.0/topos/query/retrieval.py +1077 -0
  127. topos_node-1.0.0/topos/query/runtime.py +24 -0
  128. topos_node-1.0.0/topos/query/scope_registry_loader.py +47 -0
  129. topos_node-1.0.0/topos/query/session.py +48 -0
  130. topos_node-1.0.0/topos/query/session_utils.py +30 -0
  131. topos_node-1.0.0/topos/query/source_generation.py +114 -0
  132. topos_node-1.0.0/topos/query/turn_classifier.py +76 -0
  133. topos_node-1.0.0/topos/query/types.py +79 -0
  134. {topos_node-0.1.18 → topos_node-1.0.0}/topos/sanitization/__init__.py +9 -1
  135. topos_node-1.0.0/topos/sanitization/nsfw_classifier.py +139 -0
  136. topos_node-1.0.0/topos/sanitization/privacy_filter.py +208 -0
  137. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/local.py +37 -0
  138. topos_node-1.0.0/topos/sources/bundled_canonical_triples.py +126 -0
  139. topos_node-1.0.0/topos/sources/canonical_signal_defaults.py +58 -0
  140. {topos_node-0.1.18 → topos_node-1.0.0}/topos/sources/definitions.py +9 -0
  141. {topos_node-0.1.18 → topos_node-1.0.0}/topos/sources/install_service.py +42 -55
  142. {topos_node-0.1.18 → topos_node-1.0.0}/topos/sources/registry.py +244 -23
  143. {topos_node-0.1.18 → topos_node-1.0.0}/topos/sources/runtime_install.py +61 -24
  144. topos_node-1.0.0/topos/sources/scrub_attribution.py +417 -0
  145. topos_node-1.0.0/topos/sources/scrub_service.py +518 -0
  146. topos_node-1.0.0/topos/storage/adapters/__init__.py +38 -0
  147. topos_node-1.0.0/topos/storage/adapters/factory.py +147 -0
  148. topos_node-1.0.0/topos/storage/adapters/fakes.py +333 -0
  149. topos_node-1.0.0/topos/storage/adapters/postgres/stores.py +122 -0
  150. topos_node-1.0.0/topos/storage/adapters/protocols.py +103 -0
  151. topos_node-1.0.0/topos/storage/adapters/sqlite/__init__.py +0 -0
  152. topos_node-1.0.0/topos/storage/adapters/sqlite/stores.py +985 -0
  153. topos_node-1.0.0/topos/storage/adapters/sqlite/vector_search.py +218 -0
  154. topos_node-1.0.0/topos/storage/canonical/activity_tables.py +27 -0
  155. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/ai_chat/canonicalizer.py +12 -3
  156. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/ai_chat/tables.py +63 -65
  157. topos_node-1.0.0/topos/storage/canonical/calendar_contacts_tables.py +11 -0
  158. topos_node-1.0.0/topos/storage/canonical/canonical_store.py +464 -0
  159. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/conversations_tables.py +70 -35
  160. topos_node-1.0.0/topos/storage/canonical/mapping_store.py +90 -0
  161. topos_node-1.0.0/topos/storage/canonical/postgres.py +204 -0
  162. topos_node-1.0.0/topos/storage/db/migrations/__init__.py +172 -0
  163. topos_node-1.0.0/topos/storage/db/migrations/canonical_disclosure_v1.py +62 -0
  164. topos_node-1.0.0/topos/storage/db/migrations/canonical_nsfw_v1.py +55 -0
  165. topos_node-1.0.0/topos/storage/db/migrations/extraction_artifacts.py +48 -0
  166. topos_node-1.0.0/topos/storage/db/migrations/journal_entries_duration_v1.py +28 -0
  167. topos_node-1.0.0/topos/storage/db/migrations/journal_entries_ends_at_v1.py +45 -0
  168. topos_node-1.0.0/topos/storage/db/migrations/journal_entries_people_v1.py +32 -0
  169. topos_node-1.0.0/topos/storage/db/migrations/journal_entries_place_name_v1.py +32 -0
  170. topos_node-1.0.0/topos/storage/db/migrations/journal_entries_starts_at_v1.py +40 -0
  171. topos_node-1.0.0/topos/storage/db/migrations/remediation_person_model.py +49 -0
  172. topos_node-1.0.0/topos/storage/db/migrations/scope_source_generation.py +39 -0
  173. topos_node-1.0.0/topos/storage/db/migrations/signal_dimension_harness.py +96 -0
  174. topos_node-1.0.0/topos/storage/db/migrations/signal_objects.py +53 -0
  175. topos_node-1.0.0/topos/storage/db/migrations/signal_objects_updated_by_v1.py +30 -0
  176. topos_node-1.0.0/topos/storage/db/migrations/vector_storage_v1.py +91 -0
  177. topos_node-1.0.0/topos/storage/db/migrations/vector_storage_v2.py +98 -0
  178. topos_node-1.0.0/topos/storage/db/migrations/vector_storage_v3.py +86 -0
  179. topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_phase0.py +288 -0
  180. topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_phase1.py +149 -0
  181. topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +57 -0
  182. topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +75 -0
  183. topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +73 -0
  184. topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_query_quality.py +93 -0
  185. topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +37 -0
  186. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/paths.py +53 -0
  187. topos_node-1.0.0/topos/storage/db/storage_breakdown.py +261 -0
  188. topos_node-1.0.0/topos/storage/person/identity_resolver.py +108 -0
  189. {topos_node-0.1.18 → topos_node-1.0.0}/topos/uma_filters.py +66 -34
  190. {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/PKG-INFO +23 -10
  191. {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/SOURCES.txt +137 -0
  192. {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/requires.txt +22 -7
  193. topos_node-0.1.18/topos/api/ingestion_api.py +0 -37
  194. topos_node-0.1.18/topos/canonicalization/mappers/__init__.py +0 -22
  195. topos_node-0.1.18/topos/engine/backends/huggingface.py +0 -151
  196. topos_node-0.1.18/topos/enrichment/derived_tables.py +0 -214
  197. topos_node-0.1.18/topos/enrichment/jobs/__init__.py +0 -30
  198. topos_node-0.1.18/topos/enrichment/jobs/canonical/embeddings_job.py +0 -27
  199. topos_node-0.1.18/topos/enrichment/jobs/canonical/entities_job.py +0 -27
  200. topos_node-0.1.18/topos/enrichment/jobs/canonical/sentiment_job.py +0 -27
  201. topos_node-0.1.18/topos/enrichment/jobs/canonical/topics_job.py +0 -27
  202. topos_node-0.1.18/topos/enrichment/orchestrator.py +0 -177
  203. topos_node-0.1.18/topos/storage/canonical/canonical_store.py +0 -24
  204. topos_node-0.1.18/topos/storage/canonical/mapping_store.py +0 -30
  205. topos_node-0.1.18/topos/storage/canonical/postgres.py +0 -10
  206. topos_node-0.1.18/topos/storage/db/migrations/__init__.py +0 -1
  207. {topos_node-0.1.18 → topos_node-1.0.0}/LICENSE +0 -0
  208. {topos_node-0.1.18 → topos_node-1.0.0}/setup.cfg +0 -0
  209. {topos_node-0.1.18 → topos_node-1.0.0}/shared/__init__.py +0 -0
  210. {topos_node-0.1.18 → topos_node-1.0.0}/shared/filtering.py +0 -0
  211. {topos_node-0.1.18 → topos_node-1.0.0}/shared/schema_registry.py +0 -0
  212. {topos_node-0.1.18 → topos_node-1.0.0}/tests/test_llm_integrations_storage.py +0 -0
  213. {topos_node-0.1.18 → topos_node-1.0.0}/topos/__init__.py +0 -0
  214. {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/__init__.py +0 -0
  215. {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/duckdb_adapter.py +0 -0
  216. {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/messenger_communities.py +0 -0
  217. {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/messenger_graph.py +0 -0
  218. {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/messenger_labels.py +0 -0
  219. {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/profiles.py +0 -0
  220. {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/query_engine.py +0 -0
  221. {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/raw_queries.py +0 -0
  222. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/__init__.py +0 -0
  223. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/analytics.py +0 -0
  224. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/app_registry.py +0 -0
  225. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/backup.py +0 -0
  226. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/compute_remote.py +0 -0
  227. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/data_commit.py +0 -0
  228. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/data_explorer_table_prefs.py +0 -0
  229. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/database_explorer.py +0 -0
  230. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/db.py +0 -0
  231. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/device.py +0 -0
  232. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/filter_lab.py +0 -0
  233. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/health.py +0 -0
  234. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/home_chat.py +0 -0
  235. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/ingestion_compat.py +0 -0
  236. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/llm.py +0 -0
  237. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/local_mcp.py +0 -0
  238. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/messenger_analytics.py +0 -0
  239. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/query_api.py +0 -0
  240. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/runtime_bootstrap.py +0 -0
  241. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/sanitization_ollama_config.py +0 -0
  242. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/sources.py +0 -0
  243. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/sources_overview.py +0 -0
  244. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/sync.py +0 -0
  245. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/ui_config.py +0 -0
  246. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/uma_data.py +0 -0
  247. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/usage.py +0 -0
  248. {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/user_identity.py +0 -0
  249. {topos_node-0.1.18 → topos_node-1.0.0}/topos/auth.py +0 -0
  250. {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/__init__.py +0 -0
  251. {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/mappers/base.py +0 -0
  252. {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/mappers/grok_mapper.py +0 -0
  253. {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/models.py +0 -0
  254. {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/resolver.py +0 -0
  255. {topos_node-0.1.18 → topos_node-1.0.0}/topos/cli/__init__.py +0 -0
  256. {topos_node-0.1.18 → topos_node-1.0.0}/topos/cli/__main__.py +0 -0
  257. {topos_node-0.1.18 → topos_node-1.0.0}/topos/config/__init__.py +0 -0
  258. {topos_node-0.1.18 → topos_node-1.0.0}/topos/config/sanitization_ollama.py +0 -0
  259. {topos_node-0.1.18 → topos_node-1.0.0}/topos/contacts/__init__.py +0 -0
  260. {topos_node-0.1.18 → topos_node-1.0.0}/topos/contacts/identity.py +0 -0
  261. {topos_node-0.1.18 → topos_node-1.0.0}/topos/control_plane_client.py +0 -0
  262. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/__init__.py +0 -0
  263. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/connection_resilience.py +0 -0
  264. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/device_helpers.py +0 -0
  265. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/errors.py +0 -0
  266. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/events.py +0 -0
  267. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/metrics.py +0 -0
  268. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/routine_access.py +0 -0
  269. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/startup_banner.py +0 -0
  270. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/table_layers.py +0 -0
  271. {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/types.py +0 -0
  272. {topos_node-0.1.18 → topos_node-1.0.0}/topos/data_explorer_table_prefs.py +0 -0
  273. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/__init__.py +0 -0
  274. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/backends/base.py +0 -0
  275. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/backends/stub.py +0 -0
  276. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/intake.py +0 -0
  277. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/queue_manager.py +0 -0
  278. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/result_formatter.py +0 -0
  279. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/scoped_token.py +0 -0
  280. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/tasks.py +0 -0
  281. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/transport.py +0 -0
  282. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/usage_guard.py +0 -0
  283. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/usage_observation.py +0 -0
  284. {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/validator.py +0 -0
  285. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/__init__.py +0 -0
  286. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/canonical/__init__.py +0 -0
  287. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/raw/__init__.py +0 -0
  288. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
  289. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/raw/language_job.py +0 -0
  290. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
  291. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
  292. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/models/__init__.py +0 -0
  293. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/models/manager.py +0 -0
  294. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/models/registry.py +0 -0
  295. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/models/versioning.py +0 -0
  296. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/processor.py +0 -0
  297. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/progress_bar.py +0 -0
  298. {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/website_classifier.py +0 -0
  299. {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/__init__.py +0 -0
  300. {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/bundles.py +0 -0
  301. {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/schema.py +0 -0
  302. {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/service.py +0 -0
  303. {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/store.py +0 -0
  304. {topos_node-0.1.18 → topos_node-1.0.0}/topos/home_chat/__init__.py +0 -0
  305. {topos_node-0.1.18 → topos_node-1.0.0}/topos/home_chat/schema.py +0 -0
  306. {topos_node-0.1.18 → topos_node-1.0.0}/topos/home_chat/store.py +0 -0
  307. {topos_node-0.1.18 → topos_node-1.0.0}/topos/hosted_pool_lease.py +0 -0
  308. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/__init__.py +0 -0
  309. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/checkpoints/__init__.py +0 -0
  310. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
  311. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
  312. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/jobs.py +0 -0
  313. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/local_sync.py +0 -0
  314. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/log_preview.py +0 -0
  315. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parser.py +0 -0
  316. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/base.py +0 -0
  317. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/browser_parser.py +0 -0
  318. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/calendar_parser.py +0 -0
  319. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
  320. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
  321. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/grok_parser.py +0 -0
  322. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/messenger_parser.py +0 -0
  323. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/progress.py +0 -0
  324. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/__init__.py +0 -0
  325. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/base.py +0 -0
  326. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/calendar.py +0 -0
  327. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/chatgpt.py +0 -0
  328. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/contact_importers.py +0 -0
  329. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/grok.py +0 -0
  330. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/imessage_reader.py +0 -0
  331. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/signal_export_parser.py +0 -0
  332. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/signal_reader.py +0 -0
  333. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/state_machine.py +0 -0
  334. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/triggers/__init__.py +0 -0
  335. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/triggers/file_trigger.py +0 -0
  336. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
  337. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/validation/__init__.py +0 -0
  338. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/validation/base.py +0 -0
  339. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/validation/schema_registry.py +0 -0
  340. {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/validation/schema_validator.py +0 -0
  341. {topos_node-0.1.18 → topos_node-1.0.0}/topos/lineage/__init__.py +0 -0
  342. {topos_node-0.1.18 → topos_node-1.0.0}/topos/lineage/provenance.py +0 -0
  343. {topos_node-0.1.18 → topos_node-1.0.0}/topos/lineage/tracker.py +0 -0
  344. {topos_node-0.1.18 → topos_node-1.0.0}/topos/llm_integrations_storage.py +0 -0
  345. {topos_node-0.1.18 → topos_node-1.0.0}/topos/mcp_stdio_proxy.py +0 -0
  346. {topos_node-0.1.18 → topos_node-1.0.0}/topos/observability/__init__.py +0 -0
  347. {topos_node-0.1.18 → topos_node-1.0.0}/topos/observability/alerts.py +0 -0
  348. {topos_node-0.1.18 → topos_node-1.0.0}/topos/observability/metrics.py +0 -0
  349. {topos_node-0.1.18 → topos_node-1.0.0}/topos/observability/tracing.py +0 -0
  350. {topos_node-0.1.18 → topos_node-1.0.0}/topos/openai_client.py +0 -0
  351. {topos_node-0.1.18 → topos_node-1.0.0}/topos/projections/__init__.py +0 -0
  352. {topos_node-0.1.18 → topos_node-1.0.0}/topos/projections/vector_index/__init__.py +0 -0
  353. {topos_node-0.1.18 → topos_node-1.0.0}/topos/projections/vector_index/base.py +0 -0
  354. {topos_node-0.1.18 → topos_node-1.0.0}/topos/projections/vector_index/builders.py +0 -0
  355. {topos_node-0.1.18 → topos_node-1.0.0}/topos/projections/vector_index/health_checks.py +0 -0
  356. {topos_node-0.1.18 → topos_node-1.0.0}/topos/rate_limit.py +0 -0
  357. {topos_node-0.1.18 → topos_node-1.0.0}/topos/routines/__init__.py +0 -0
  358. {topos_node-0.1.18 → topos_node-1.0.0}/topos/routines/schema.py +0 -0
  359. {topos_node-0.1.18 → topos_node-1.0.0}/topos/routines/store.py +0 -0
  360. {topos_node-0.1.18 → topos_node-1.0.0}/topos/runtime_update.py +0 -0
  361. {topos_node-0.1.18 → topos_node-1.0.0}/topos/sanitization/ollama_transforms.py +0 -0
  362. {topos_node-0.1.18 → topos_node-1.0.0}/topos/scope_resolution.py +0 -0
  363. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/__init__.py +0 -0
  364. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/container.py +0 -0
  365. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/embeddings/__init__.py +0 -0
  366. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/embeddings/base.py +0 -0
  367. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/embeddings/local.py +0 -0
  368. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/embeddings/remote.py +0 -0
  369. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/interfaces.py +0 -0
  370. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/llm/__init__.py +0 -0
  371. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/llm/base.py +0 -0
  372. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/llm/openai.py +0 -0
  373. {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/postgres.py +0 -0
  374. {topos_node-0.1.18 → topos_node-1.0.0}/topos/sources/__init__.py +0 -0
  375. {topos_node-0.1.18 → topos_node-1.0.0}/topos/startup_banner.py +0 -0
  376. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/__init__.py +0 -0
  377. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/__init__.py +0 -0
  378. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/ai_chat/__init__.py +0 -0
  379. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/ai_chat/mapper.py +0 -0
  380. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/ai_chat/model.py +0 -0
  381. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/__init__.py +0 -0
  382. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/client.py +0 -0
  383. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
  384. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/postgres.py +0 -0
  385. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/schema.py +0 -0
  386. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/enrichment/__init__.py +0 -0
  387. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
  388. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
  389. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/normalized/__init__.py +0 -0
  390. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/normalized/normalized_store.py +0 -0
  391. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/oplog/__init__.py +0 -0
  392. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/oplog/decision.py +0 -0
  393. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/oplog/oplog_store.py +0 -0
  394. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/oplog/postgres.py +0 -0
  395. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/projections/__init__.py +0 -0
  396. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/projections/index_ops_store.py +0 -0
  397. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/projections/vector_index_store.py +0 -0
  398. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/__init__.py +0 -0
  399. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/browser_flat_tables.py +0 -0
  400. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/file_store.py +0 -0
  401. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/raw_store.py +0 -0
  402. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/raw_tables_manager.py +0 -0
  403. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/sqlite_raw_store.py +0 -0
  404. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/security/encryption.py +0 -0
  405. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/signal_identity.py +0 -0
  406. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/source_settings.py +0 -0
  407. {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/user_identity.py +0 -0
  408. {topos_node-0.1.18 → topos_node-1.0.0}/topos/sync/__init__.py +0 -0
  409. {topos_node-0.1.18 → topos_node-1.0.0}/topos/sync/client.py +0 -0
  410. {topos_node-0.1.18 → topos_node-1.0.0}/topos/sync_handlers.py +0 -0
  411. {topos_node-0.1.18 → topos_node-1.0.0}/topos/testing/__init__.py +0 -0
  412. {topos_node-0.1.18 → topos_node-1.0.0}/topos/testing/lifespan.py +0 -0
  413. {topos_node-0.1.18 → topos_node-1.0.0}/topos/uma_contact_enrichment.py +0 -0
  414. {topos_node-0.1.18 → topos_node-1.0.0}/topos/uma_resource_id.py +0 -0
  415. {topos_node-0.1.18 → topos_node-1.0.0}/topos/uma_rpt.py +0 -0
  416. {topos_node-0.1.18 → topos_node-1.0.0}/topos/utils/base_object.py +0 -0
  417. {topos_node-0.1.18 → topos_node-1.0.0}/topos/websocket_client.py +0 -0
  418. {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/dependency_links.txt +0 -0
  419. {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/entry_points.txt +0 -0
  420. {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: topos-node
3
- Version: 0.1.18
3
+ Version: 1.0.0
4
4
  Summary: Topos personal AI engine (FastAPI): local data, sync, control plane WebSocket client
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://topos.dialogues.ai
@@ -22,17 +22,30 @@ Requires-Dist: packaging<26.2,>=26.1
22
22
  Requires-Dist: mcp~=1.27.0
23
23
  Requires-Dist: google-cloud-storage~=3.10.1
24
24
  Requires-Dist: google-cloud-run~=0.16.0
25
- Requires-Dist: networkx<3.7,>=3.2.1
26
- Requires-Dist: transformers~=5.10.2
27
- Requires-Dist: huggingface-hub~=1.18.0
28
- Requires-Dist: tqdm~=4.67.3
29
- Requires-Dist: hf-xet~=1.5.1
30
- Requires-Dist: torch<3,>=2.8.0
31
- Requires-Dist: python-louvain<0.17,>=0.16
32
25
  Requires-Dist: asgi-lifespan~=2.1.0
26
+ Provides-Extra: database
27
+ Requires-Dist: psycopg[binary]~=3.3.3; extra == "database"
33
28
  Provides-Extra: engine
34
29
  Requires-Dist: duckdb~=1.5.2; extra == "engine"
35
- Requires-Dist: psycopg[binary]~=3.3.3; extra == "engine"
30
+ Requires-Dist: torch<3,>=2.8.0; extra == "engine"
31
+ Requires-Dist: transformers~=5.10.2; extra == "engine"
32
+ Requires-Dist: huggingface-hub~=1.18.0; extra == "engine"
33
+ Requires-Dist: tqdm~=4.67.3; extra == "engine"
34
+ Requires-Dist: hf-xet~=1.5.1; extra == "engine"
35
+ Requires-Dist: sentence-transformers~=5.6.0; extra == "engine"
36
+ Requires-Dist: networkx<3.7,>=3.2.1; extra == "engine"
37
+ Requires-Dist: python-louvain<0.17,>=0.16; extra == "engine"
38
+ Provides-Extra: local
39
+ Requires-Dist: psycopg[binary]~=3.3.3; extra == "local"
40
+ Requires-Dist: duckdb~=1.5.2; extra == "local"
41
+ Requires-Dist: torch<3,>=2.8.0; extra == "local"
42
+ Requires-Dist: transformers~=5.10.2; extra == "local"
43
+ Requires-Dist: huggingface-hub~=1.18.0; extra == "local"
44
+ Requires-Dist: tqdm~=4.67.3; extra == "local"
45
+ Requires-Dist: hf-xet~=1.5.1; extra == "local"
46
+ Requires-Dist: sentence-transformers~=5.6.0; extra == "local"
47
+ Requires-Dist: networkx<3.7,>=3.2.1; extra == "local"
48
+ Requires-Dist: python-louvain<0.17,>=0.16; extra == "local"
36
49
  Provides-Extra: signal
37
50
  Requires-Dist: pysqlcipher3~=1.2.0; extra == "signal"
38
51
  Provides-Extra: dev
@@ -109,7 +122,7 @@ The `shared/` package in this repo is part of the node runtime contract. It cont
109
122
  ### 1) Install
110
123
 
111
124
  ```bash
112
- uv tool install topos-node
125
+ uv tool install 'topos-node[local]'
113
126
  ```
114
127
 
115
128
  ### 2) Configure
@@ -66,7 +66,7 @@ The `shared/` package in this repo is part of the node runtime contract. It cont
66
66
  ### 1) Install
67
67
 
68
68
  ```bash
69
- uv tool install topos-node
69
+ uv tool install 'topos-node[local]'
70
70
  ```
71
71
 
72
72
  ### 2) Configure
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "topos-node"
7
- version = "0.1.18"
7
+ version = "1.0.0"
8
8
  description = "Topos personal AI engine (FastAPI): local data, sync, control plane WebSocket client"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -24,13 +24,6 @@ dependencies = [
24
24
  "mcp~=1.27.0",
25
25
  "google-cloud-storage~=3.10.1",
26
26
  "google-cloud-run~=0.16.0",
27
- "networkx>=3.2.1,<3.7",
28
- "transformers~=5.10.2",
29
- "huggingface-hub~=1.18.0",
30
- "tqdm~=4.67.3",
31
- "hf-xet~=1.5.1",
32
- "torch>=2.8.0,<3",
33
- "python-louvain>=0.16,<0.17",
34
27
  "asgi-lifespan~=2.1.0",
35
28
  ]
36
29
 
@@ -39,9 +32,34 @@ Homepage = "https://topos.dialogues.ai"
39
32
  Source = "https://dialogues.ai"
40
33
 
41
34
  [project.optional-dependencies]
35
+ # Lean database / sync plane (hosted topos-database Cloud Run image).
36
+ database = [
37
+ "psycopg[binary]~=3.3.3",
38
+ ]
39
+ # ML + enrichment runtime (hosted topos-engine Cloud Run image).
42
40
  engine = [
43
41
  "duckdb~=1.5.2",
42
+ "torch>=2.8.0,<3",
43
+ "transformers~=5.10.2",
44
+ "huggingface-hub~=1.18.0",
45
+ "tqdm~=4.67.3",
46
+ "hf-xet~=1.5.1",
47
+ "sentence-transformers~=5.6.0",
48
+ "networkx>=3.2.1,<3.7",
49
+ "python-louvain>=0.16,<0.17",
50
+ ]
51
+ # Colocated local node (database + engine on one device). Default for PyPI / uv tool install.
52
+ local = [
44
53
  "psycopg[binary]~=3.3.3",
54
+ "duckdb~=1.5.2",
55
+ "torch>=2.8.0,<3",
56
+ "transformers~=5.10.2",
57
+ "huggingface-hub~=1.18.0",
58
+ "tqdm~=4.67.3",
59
+ "hf-xet~=1.5.1",
60
+ "sentence-transformers~=5.6.0",
61
+ "networkx>=3.2.1,<3.7",
62
+ "python-louvain>=0.16,<0.17",
45
63
  ]
46
64
  signal = [
47
65
  "pysqlcipher3~=1.2.0",
@@ -65,8 +83,13 @@ filterwarnings = [
65
83
  "ignore:on_event is deprecated.*:DeprecationWarning:fastapi.*",
66
84
  ]
67
85
  markers = [
86
+ "gap: gap verification test (sprint pack); must pass after sprint lands",
87
+ "qq_eval: live query quality/latency eval against owner database",
88
+ "acceptance: Wiki MVP acceptance test (AT-1 through AT-8)",
89
+ "hosted_parity: hosted vs local parity (staging/nightly)",
68
90
  "public: public-safe test lane for OSS CI",
69
91
  "private: internal architecture or fixtures; excluded from public CI",
70
92
  "e2e: end-to-end tests (live Keycloak + Control Plane; require config and running CP)",
71
93
  ]
94
+ pythonpath = ["tests/gap/p3/engine", "tests/gap/p4/engine", "tests/gap/qq/engine", "tests/acceptance/wiki_mvp"]
72
95
  testpaths = ["tests"]
@@ -1,6 +1,6 @@
1
1
  """Topos Control Plane Version Information."""
2
2
 
3
- __version__ = "0.1.18"
4
- __version_info__ = (0, 1, 18)
3
+ __version__ = "1.0.0"
4
+ __version_info__ = (1, 0, 0)
5
5
 
6
6
  __all__ = ["__version__", "__version_info__"]
@@ -85,36 +85,25 @@ async def _backfill_browser_visits_url_classification(
85
85
  only_missing: bool = True,
86
86
  limit: Optional[int] = None,
87
87
  ) -> Dict[str, Any]:
88
- """Backfill URL classification for normalized browser visits raw table rows."""
89
- from ..engine import Engine, build_url_classification_task
90
- from ..storage.raw.browser_flat_tables import (
91
- ensure_browser_url_classification_table,
92
- write_browser_url_classification,
93
- )
94
- from ..enrichment.progress_bar import ProgressBar
95
- from ..storage.raw.raw_tables_manager import RawTablesManager
88
+ """Backfill Interests signal facts from canonical activity_events (not raw tables)."""
89
+ import uuid
96
90
 
97
- source_table = "raw_chat_messages_browservisits"
91
+ from ..ingestion.canonical_pipeline import (
92
+ activity_payload_to_signal_record,
93
+ run_post_canonical_pipeline,
94
+ )
95
+ from ..sources.registry import BROWSER_VISITS
98
96
 
99
97
  logger.info(
100
- "[PIPELINE:ENRICHMENT] Source backfill start: source=browser_visits enrichment=url_classification only_missing=%s limit=%s",
98
+ "[PIPELINE:SIGNAL_DERIVE] Browser visits backfill from activity_events only_missing=%s limit=%s",
101
99
  only_missing,
102
100
  limit,
103
101
  )
104
102
 
105
- # Ensure/migrate the raw browser visits table to normalized-column schema first.
106
- RawTablesManager(db_conn).ensure_raw_table(source_table)
107
-
108
- # If source table does not exist yet, return an empty success result.
109
- source_exists = db_conn.execute(
110
- "SELECT name FROM sqlite_master WHERE type='table' AND name=?",
111
- (source_table,),
103
+ table_exists = db_conn.execute(
104
+ "SELECT name FROM sqlite_master WHERE type='table' AND name='activity_events'"
112
105
  ).fetchone()
113
- if not source_exists:
114
- logger.info(
115
- "[PIPELINE:ENRICHMENT] Source backfill complete: source table missing (%s)",
116
- source_table,
117
- )
106
+ if not table_exists:
118
107
  return {
119
108
  "rows_scanned": 0,
120
109
  "rows_processed": 0,
@@ -123,100 +112,71 @@ async def _backfill_browser_visits_url_classification(
123
112
  "errors": [],
124
113
  }
125
114
 
126
- ensure_browser_url_classification_table(db_conn)
127
-
128
- params: List[Any] = []
115
+ params: List[Any] = ["browser_visits"]
116
+ query = """
117
+ SELECT event_id, activity_type, url, title, occurred_at, source_id
118
+ FROM activity_events
119
+ WHERE source_id=?
120
+ """
129
121
  if only_missing:
130
- query = """
131
- SELECT
132
- (COALESCE(v.url, '') || '_' || COALESCE(v.visited_at, '')) AS derived_record_id,
133
- v.dataset_id,
134
- v.url,
135
- v.title
136
- FROM raw_chat_messages_browservisits v
137
- LEFT JOIN browser_url_classification c
138
- ON c.source_table = 'browser_visits'
139
- AND c.record_id = (COALESCE(v.url, '') || '_' || COALESCE(v.visited_at, ''))
140
- WHERE c.record_id IS NULL
141
- ORDER BY v.visited_at ASC
142
- """
143
- else:
144
- query = """
145
- SELECT
146
- (COALESCE(v.url, '') || '_' || COALESCE(v.visited_at, '')) AS derived_record_id,
147
- v.dataset_id,
148
- v.url,
149
- v.title
150
- FROM raw_chat_messages_browservisits v
151
- ORDER BY v.visited_at ASC
122
+ query += """
123
+ AND event_id NOT IN (
124
+ SELECT record_id FROM signal_facts
125
+ WHERE source_id='browser_visits' AND dimension='interests'
126
+ )
152
127
  """
128
+ query += " ORDER BY occurred_at ASC"
153
129
  if isinstance(limit, int) and limit > 0:
154
130
  query += " LIMIT ?"
155
131
  params.append(limit)
156
132
 
157
133
  rows = db_conn.execute(query, tuple(params)).fetchall()
134
+ canonical_records = [
135
+ activity_payload_to_signal_record(
136
+ {
137
+ "event_id": row[0],
138
+ "activity_type": row[1],
139
+ "url": row[2],
140
+ "title": row[3],
141
+ "occurred_at": row[4],
142
+ "source_id": row[5],
143
+ },
144
+ source_id="browser_visits",
145
+ )
146
+ for row in rows
147
+ if isinstance(row[2], str) and row[2].strip()
148
+ ]
149
+
150
+ skipped = max(len(rows) - len(canonical_records), 0)
151
+ if not canonical_records:
152
+ return {
153
+ "rows_scanned": len(rows),
154
+ "rows_processed": 0,
155
+ "rows_skipped": skipped + len(rows),
156
+ "rows_failed": 0,
157
+ "errors": [],
158
+ }
158
159
 
159
- processed = 0
160
- skipped = 0
161
- failed = 0
162
- errors: List[Dict[str, Any]] = []
163
-
164
- if rows:
165
- with ProgressBar(total=len(rows), desc="url_classification backfill") as pbar:
166
- for row in rows:
167
- record_id = row[0]
168
- dataset_id = row[1]
169
- url = row[2]
170
- title = row[3]
171
- if not isinstance(url, str) or not url.strip():
172
- skipped += 1
173
- pbar.update(1)
174
- continue
175
-
176
- try:
177
- task = build_url_classification_task(
178
- task_id=f"backfill_url_{record_id}",
179
- url=url,
180
- title=title,
181
- source_id="browser_visits",
182
- record_ids=[record_id],
183
- )
184
- engine = Engine()
185
- result = await asyncio.to_thread(engine.run, task)
186
- if result.status != "completed":
187
- failed += 1
188
- errors.append({"record_id": record_id, "error": result.error or result.status})
189
- continue
190
- out = result.output
191
- write_browser_url_classification(
192
- db_conn,
193
- source_table="browser_visits",
194
- record_id=record_id,
195
- dataset_id=dataset_id,
196
- url=url,
197
- title=title,
198
- category=out.get("category"),
199
- confidence=out.get("confidence"),
200
- model_name=out.get("model"),
201
- ensure_table=False,
202
- log_write=False, # Avoid per-row log spam during bulk backfill
203
- )
204
- processed += 1
205
- except Exception as exc: # noqa: BLE001
206
- failed += 1
207
- errors.append({"record_id": record_id, "error": str(exc)})
208
- finally:
209
- pbar.update(1)
160
+ pipeline_outcome = await run_post_canonical_pipeline(
161
+ source_def=BROWSER_VISITS,
162
+ canonical_records=canonical_records,
163
+ sync_batch_id=f"backfill_browser_visits_{uuid.uuid4().hex[:12]}",
164
+ run_enrichment=False,
165
+ job_names=["url_classification"],
166
+ )
167
+ derive_result = pipeline_outcome.get("signal_derivation") or {}
168
+ processed = sum((derive_result.get("records_created") or {}).values())
169
+ failed = len(derive_result.get("errors") or [])
210
170
 
211
171
  summary = {
212
172
  "rows_scanned": len(rows),
213
- "rows_processed": processed,
173
+ "rows_processed": int(processed),
214
174
  "rows_skipped": skipped,
215
175
  "rows_failed": failed,
216
- "errors": errors[:100],
176
+ "errors": (derive_result.get("errors") or [])[:100],
217
177
  }
218
178
  logger.info(
219
- "[PIPELINE:ENRICHMENT] Source backfill complete: source=browser_visits enrichment=url_classification scanned=%d processed=%d skipped=%d failed=%d",
179
+ "[PIPELINE:SIGNAL_DERIVE] Browser visits backfill complete: scanned=%d processed=%d skipped=%d failed=%d",
220
180
  summary["rows_scanned"],
221
181
  summary["rows_processed"],
222
182
  summary["rows_skipped"],
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ from fastapi import APIRouter, Body, Depends, HTTPException, Request
4
+
5
+ from ..auth import require_api_key
6
+ from ..ingestion.reprocess import reprocess_source
7
+ from .ingestion_sources import ingest_source
8
+
9
+ router = APIRouter()
10
+
11
+
12
+ @router.post("/ingestion/start")
13
+ async def start_ingestion() -> dict:
14
+ return {"status": "stub"}
15
+
16
+
17
+ @router.post("/ingestion/progress")
18
+ async def report_progress() -> dict:
19
+ return {"status": "stub"}
20
+
21
+
22
+ @router.post("/ingestion/reprocess", dependencies=[Depends(require_api_key)])
23
+ async def ingestion_reprocess(payload: dict = Body(default_factory=dict)) -> dict:
24
+ try:
25
+ return await reprocess_source(
26
+ source_id=str(payload["source_id"]),
27
+ dataset_id=str(payload["dataset_id"]),
28
+ from_stage=payload.get("from_stage") or "raw",
29
+ sync_batch_id=payload.get("sync_batch_id"),
30
+ force=bool(payload.get("force", False)),
31
+ )
32
+ except KeyError as exc:
33
+ raise HTTPException(status_code=400, detail=f"Missing field: {exc}") from exc
34
+ except ValueError as exc:
35
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
36
+
37
+
38
+ @router.get("/ingestion/audit", dependencies=[Depends(require_api_key)])
39
+ async def get_ingestion_audit(sync_batch_id: str) -> dict:
40
+ from ..core.state import get_db_connection
41
+ from ..pipeline.audit import SQLiteIngestAuditStore
42
+
43
+ conn = get_db_connection()
44
+ if not conn:
45
+ raise HTTPException(status_code=503, detail="Database unavailable")
46
+ store = SQLiteIngestAuditStore(conn)
47
+ return {"sync_batch_id": sync_batch_id, "stages": store.query_by_batch(sync_batch_id)}
48
+
49
+
50
+ @router.post("/ingestion/upload", dependencies=[Depends(require_api_key)])
51
+ async def upload_ingestion_file(request: Request) -> dict:
52
+ return await ingest_source("chatgpt_file_ingestion", request)
53
+
54
+
55
+ @router.post("/ingestion/upload-local-path", dependencies=[Depends(require_api_key)])
56
+ async def upload_ingestion_local_path(
57
+ request: Request, payload: dict = Body(default_factory=dict)
58
+ ) -> dict:
59
+ dataset_id = payload.get("dataset_id")
60
+ file_path = payload.get("file_path")
61
+ return await ingest_source(
62
+ "chatgpt_file_ingestion",
63
+ request,
64
+ dataset_id=dataset_id,
65
+ file_path=file_path,
66
+ )
@@ -10,7 +10,7 @@ from fastapi import APIRouter, Body, Depends, Query, Request # noqa: F401 Body
10
10
 
11
11
  from ..auth import require_api_key
12
12
  from ..core.state import get_db_connection
13
- from ..ingestion.ingest_helpers import ingest_file_payload, ingest_ui_payload
13
+ from ..ingestion.ingest_helpers import ingest_file_payload, ingest_ui_payload, resolve_file_format
14
14
  from ..ingestion.local_sync import run_imessage_sync, run_signal_sync, run_signal_upload
15
15
  from ..sources.registry import REGISTRY
16
16
  from ..storage.signal_identity import get_signal_identity, put_signal_identity
@@ -86,6 +86,8 @@ async def ingest_source(
86
86
  dataset_id=dataset_id,
87
87
  schema_id=source.schema_id,
88
88
  file_path=file_path,
89
+ source_id=source_id,
90
+ file_format=resolve_file_format(source_definition=source, file_path=file_path),
89
91
  )
90
92
  payload_bytes = await file.read()
91
93
  guard = await submit_usage_guard_check(
@@ -102,6 +104,8 @@ async def ingest_source(
102
104
  dataset_id=dataset_id,
103
105
  schema_id=source.schema_id,
104
106
  file_bytes=payload_bytes,
107
+ source_id=source_id,
108
+ file_format=resolve_file_format(source_definition=source),
105
109
  )
106
110
 
107
111
  if source.source_type == "ui_stream":
@@ -0,0 +1,85 @@
1
+ """Platform Privacy Layer: batch PII disclosure via Topos Engine."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from typing import Any, List, Optional
7
+
8
+ from fastapi import APIRouter, Body, Depends, HTTPException
9
+ from pydantic import BaseModel, Field
10
+
11
+ from ..auth import require_api_key
12
+ from ..sanitization.privacy_filter import PRIVACY_DISCLOSE_MAX_BATCH, redact_privacy_batch
13
+ from ..sanitization.nsfw_classifier import NSFW_CLASSIFY_MAX_BATCH, classify_nsfw_batch
14
+
15
+ logger = logging.getLogger("topos.api.privacy_disclose")
16
+
17
+ router = APIRouter(tags=["privacy"])
18
+
19
+
20
+ class PrivacyDiscloseItem(BaseModel):
21
+ id: str = ""
22
+ text: str = ""
23
+ transform_id: Optional[str] = None
24
+
25
+
26
+ class PrivacyDiscloseRequest(BaseModel):
27
+ items: List[PrivacyDiscloseItem] = Field(default_factory=list)
28
+ transform_id: str = "pii_redaction"
29
+
30
+
31
+ @router.post("/v1/privacy/disclose", dependencies=[Depends(require_api_key)])
32
+ async def post_privacy_disclose(body: PrivacyDiscloseRequest = Body(...)) -> dict[str, Any]:
33
+ if not body.items:
34
+ raise HTTPException(status_code=400, detail="items required")
35
+ if len(body.items) > PRIVACY_DISCLOSE_MAX_BATCH:
36
+ raise HTTPException(
37
+ status_code=413,
38
+ detail=f"batch exceeds limit of {PRIVACY_DISCLOSE_MAX_BATCH}",
39
+ )
40
+ payload_items = [
41
+ {
42
+ "id": item.id,
43
+ "text": item.text,
44
+ "transform_id": item.transform_id or body.transform_id,
45
+ }
46
+ for item in body.items
47
+ ]
48
+ try:
49
+ result = redact_privacy_batch(payload_items, transform_id=body.transform_id)
50
+ except Exception as exc: # noqa: BLE001
51
+ logger.warning("post_privacy_disclose failed: %s", exc)
52
+ raise HTTPException(status_code=500, detail="privacy disclose failed") from exc
53
+ status = str(result.get("status") or "ok")
54
+ if status == "unavailable":
55
+ raise HTTPException(status_code=503, detail=str(result.get("error") or "privacy filter unavailable"))
56
+ if status == "too_large":
57
+ raise HTTPException(status_code=413, detail=str(result.get("error") or "batch too large"))
58
+ return {"status": "ok", **result}
59
+
60
+
61
+ class NsfwClassifyRequest(BaseModel):
62
+ items: List[PrivacyDiscloseItem] = Field(default_factory=list)
63
+
64
+
65
+ @router.post("/v1/privacy/nsfw-classify", dependencies=[Depends(require_api_key)])
66
+ async def post_nsfw_classify(body: NsfwClassifyRequest = Body(...)) -> dict[str, Any]:
67
+ if not body.items:
68
+ raise HTTPException(status_code=400, detail="items required")
69
+ if len(body.items) > NSFW_CLASSIFY_MAX_BATCH:
70
+ raise HTTPException(
71
+ status_code=413,
72
+ detail=f"batch exceeds limit of {NSFW_CLASSIFY_MAX_BATCH}",
73
+ )
74
+ payload_items = [{"id": item.id, "text": item.text} for item in body.items]
75
+ try:
76
+ result = classify_nsfw_batch(payload_items)
77
+ except Exception as exc: # noqa: BLE001
78
+ logger.warning("post_nsfw_classify failed: %s", exc)
79
+ raise HTTPException(status_code=500, detail="nsfw classify failed") from exc
80
+ status = str(result.get("status") or "ok")
81
+ if status == "disabled":
82
+ return {"status": "ok", **result}
83
+ if status == "too_large":
84
+ raise HTTPException(status_code=413, detail=str(result.get("error") or "batch too large"))
85
+ return {"status": "ok", **result}