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.
- {topos_node-0.1.18 → topos_node-1.0.0}/PKG-INFO +23 -10
- {topos_node-0.1.18 → topos_node-1.0.0}/README.md +1 -1
- {topos_node-0.1.18 → topos_node-1.0.0}/pyproject.toml +31 -8
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/__version__.py +2 -2
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/enrichment.py +61 -101
- topos_node-1.0.0/topos/api/ingestion_api.py +66 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/ingestion_sources.py +5 -1
- topos_node-1.0.0/topos/api/privacy_disclose.py +85 -0
- topos_node-1.0.0/topos/api/signal.py +306 -0
- topos_node-1.0.0/topos/api/signal_extraction_config.py +63 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/source_install.py +1 -0
- topos_node-1.0.0/topos/api/source_scrub.py +71 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/app.py +23 -1
- topos_node-1.0.0/topos/canonicalization/mappers/__init__.py +44 -0
- topos_node-1.0.0/topos/canonicalization/mappers/browser_activity_mapper.py +31 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/mappers/chatgpt_mapper.py +3 -1
- topos_node-1.0.0/topos/canonicalization/mappers/demo_mappers.py +199 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/mappers/messenger_mapper.py +12 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/cli/commands.py +2 -1
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/config/settings.py +21 -0
- topos_node-1.0.0/topos/config/signal_extraction.py +167 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/api_models.py +2 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/handlers.py +881 -122
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/logging.py +33 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/state.py +6 -0
- topos_node-1.0.0/topos/data_explorer_row_delete.py +603 -0
- topos_node-1.0.0/topos/data_explorer_tables.py +26 -0
- topos_node-1.0.0/topos/disclosure/__init__.py +29 -0
- topos_node-1.0.0/topos/disclosure/canonical_writer.py +78 -0
- topos_node-1.0.0/topos/disclosure/content_policy.py +67 -0
- topos_node-1.0.0/topos/disclosure/field_registry.py +51 -0
- topos_node-1.0.0/topos/disclosure/privacy_layer.py +373 -0
- topos_node-1.0.0/topos/disclosure/tier.py +107 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/backends/__init__.py +30 -0
- topos_node-1.0.0/topos/engine/backends/generative_prompts.py +80 -0
- topos_node-1.0.0/topos/engine/backends/generative_response.py +103 -0
- topos_node-1.0.0/topos/engine/backends/huggingface.py +348 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/backends/ollama.py +60 -34
- topos_node-1.0.0/topos/engine/backends/openai.py +27 -0
- topos_node-1.0.0/topos/engine/backends/openai_compatible.py +85 -0
- topos_node-1.0.0/topos/engine/backends/redpill.py +45 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/engine.py +15 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/registration.py +18 -1
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/router.py +5 -1
- topos_node-1.0.0/topos/enrichment/derived_tables.py +523 -0
- topos_node-1.0.0/topos/enrichment/job_writer.py +356 -0
- topos_node-1.0.0/topos/enrichment/jobs/__init__.py +70 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/base.py +5 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/_batch_limits.py +15 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/_engine_runner.py +32 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/availability_scores_job.py +53 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/brief_fallback.py +354 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/dimension_summary_job.py +203 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/embeddings_job.py +142 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/canonical/emo_27_job.py +5 -3
- topos_node-1.0.0/topos/enrichment/jobs/canonical/entities_job.py +69 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/goal_extraction_job.py +120 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/pii_redaction_job.py +128 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/relationship_edges_job.py +53 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/sentiment_job.py +66 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/topic_clusters_job.py +84 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/topics_job.py +111 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/url_classification_core.py +113 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/url_classification_enrichment_job.py +72 -0
- topos_node-1.0.0/topos/enrichment/jobs/canonical/url_classification_signal_job.py +54 -0
- topos_node-1.0.0/topos/enrichment/models/mvp_defaults.py +51 -0
- topos_node-1.0.0/topos/enrichment/orchestrator.py +366 -0
- topos_node-1.0.0/topos/enrichment/registry_contract.py +51 -0
- topos_node-1.0.0/topos/features/fit/evaluator.py +139 -0
- topos_node-1.0.0/topos/features/signal/__init__.py +0 -0
- topos_node-1.0.0/topos/features/signal/brief_canonical_loader.py +117 -0
- topos_node-1.0.0/topos/features/signal/brief_ontology.py +112 -0
- topos_node-1.0.0/topos/features/signal/brief_renderer.py +51 -0
- topos_node-1.0.0/topos/features/signal/brief_schemas.py +114 -0
- topos_node-1.0.0/topos/features/signal/chunking.py +87 -0
- topos_node-1.0.0/topos/features/signal/data_health.py +77 -0
- topos_node-1.0.0/topos/features/signal/dimension_briefs.py +307 -0
- topos_node-1.0.0/topos/features/signal/dimension_definition_loader.py +111 -0
- topos_node-1.0.0/topos/features/signal/dimension_profiles.py +51 -0
- topos_node-1.0.0/topos/features/signal/dimension_registry.py +161 -0
- topos_node-1.0.0/topos/features/signal/extraction/artifact_router.py +143 -0
- topos_node-1.0.0/topos/features/signal/extraction/artifact_store.py +141 -0
- topos_node-1.0.0/topos/features/signal/extraction/rule_extractors.py +362 -0
- topos_node-1.0.0/topos/features/signal/graph_sanitize.py +61 -0
- topos_node-1.0.0/topos/features/signal/hybrid_search.py +106 -0
- topos_node-1.0.0/topos/features/signal/query_embed_cache.py +56 -0
- topos_node-1.0.0/topos/features/signal/schemas.py +11 -0
- topos_node-1.0.0/topos/features/signal/service.py +476 -0
- topos_node-1.0.0/topos/features/signal/signal_object_store.py +225 -0
- topos_node-1.0.0/topos/features/signal/source_hydration.py +132 -0
- topos_node-1.0.0/topos/features/signal/structured_signal.py +113 -0
- topos_node-1.0.0/topos/features/signal/topic_clustering.py +1247 -0
- topos_node-1.0.0/topos/features/signal/typed_stores/aggregates.py +108 -0
- topos_node-1.0.0/topos/features/signal/typed_stores/scope_materializer.py +372 -0
- topos_node-1.0.0/topos/features/signal/vector_codec.py +96 -0
- topos_node-1.0.0/topos/features/signal/vector_math.py +17 -0
- topos_node-1.0.0/topos/features/signal/vector_settings.py +46 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/worker.py +18 -9
- topos_node-1.0.0/topos/ingestion/canonical_pipeline.py +705 -0
- topos_node-1.0.0/topos/ingestion/inbox_crypto.py +53 -0
- topos_node-1.0.0/topos/ingestion/inbox_drain.py +87 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/ingest_helpers.py +219 -217
- topos_node-1.0.0/topos/ingestion/journal_location_fanout.py +44 -0
- topos_node-1.0.0/topos/ingestion/journal_time_log_normalize.py +142 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/manager.py +281 -208
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/__init__.py +33 -0
- topos_node-1.0.0/topos/ingestion/parsers/demo_file_parsers.py +313 -0
- topos_node-1.0.0/topos/ingestion/parsers/voxterm_parser.py +71 -0
- topos_node-1.0.0/topos/ingestion/reprocess.py +254 -0
- topos_node-1.0.0/topos/ingestion/usage_inbox_dedupe.py +87 -0
- topos_node-1.0.0/topos/pipeline/__init__.py +15 -0
- topos_node-1.0.0/topos/pipeline/audit.py +171 -0
- topos_node-1.0.0/topos/pipeline/envelope.py +90 -0
- topos_node-1.0.0/topos/pipeline/stages.py +16 -0
- topos_node-1.0.0/topos/pipeline/stub_enqueue.py +55 -0
- topos_node-1.0.0/topos/query/__init__.py +34 -0
- topos_node-1.0.0/topos/query/audit.py +45 -0
- topos_node-1.0.0/topos/query/disclosure.py +115 -0
- topos_node-1.0.0/topos/query/fingerprint.py +21 -0
- topos_node-1.0.0/topos/query/game_layer.py +175 -0
- topos_node-1.0.0/topos/query/inference.py +70 -0
- topos_node-1.0.0/topos/query/intent.py +18 -0
- topos_node-1.0.0/topos/query/manifest.py +45 -0
- topos_node-1.0.0/topos/query/manifest_validation.py +90 -0
- topos_node-1.0.0/topos/query/pipeline.py +364 -0
- topos_node-1.0.0/topos/query/retrieval.py +1077 -0
- topos_node-1.0.0/topos/query/runtime.py +24 -0
- topos_node-1.0.0/topos/query/scope_registry_loader.py +47 -0
- topos_node-1.0.0/topos/query/session.py +48 -0
- topos_node-1.0.0/topos/query/session_utils.py +30 -0
- topos_node-1.0.0/topos/query/source_generation.py +114 -0
- topos_node-1.0.0/topos/query/turn_classifier.py +76 -0
- topos_node-1.0.0/topos/query/types.py +79 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/sanitization/__init__.py +9 -1
- topos_node-1.0.0/topos/sanitization/nsfw_classifier.py +139 -0
- topos_node-1.0.0/topos/sanitization/privacy_filter.py +208 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/local.py +37 -0
- topos_node-1.0.0/topos/sources/bundled_canonical_triples.py +126 -0
- topos_node-1.0.0/topos/sources/canonical_signal_defaults.py +58 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/sources/definitions.py +9 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/sources/install_service.py +42 -55
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/sources/registry.py +244 -23
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/sources/runtime_install.py +61 -24
- topos_node-1.0.0/topos/sources/scrub_attribution.py +417 -0
- topos_node-1.0.0/topos/sources/scrub_service.py +518 -0
- topos_node-1.0.0/topos/storage/adapters/__init__.py +38 -0
- topos_node-1.0.0/topos/storage/adapters/factory.py +147 -0
- topos_node-1.0.0/topos/storage/adapters/fakes.py +333 -0
- topos_node-1.0.0/topos/storage/adapters/postgres/stores.py +122 -0
- topos_node-1.0.0/topos/storage/adapters/protocols.py +103 -0
- topos_node-1.0.0/topos/storage/adapters/sqlite/__init__.py +0 -0
- topos_node-1.0.0/topos/storage/adapters/sqlite/stores.py +985 -0
- topos_node-1.0.0/topos/storage/adapters/sqlite/vector_search.py +218 -0
- topos_node-1.0.0/topos/storage/canonical/activity_tables.py +27 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/ai_chat/canonicalizer.py +12 -3
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/ai_chat/tables.py +63 -65
- topos_node-1.0.0/topos/storage/canonical/calendar_contacts_tables.py +11 -0
- topos_node-1.0.0/topos/storage/canonical/canonical_store.py +464 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/conversations_tables.py +70 -35
- topos_node-1.0.0/topos/storage/canonical/mapping_store.py +90 -0
- topos_node-1.0.0/topos/storage/canonical/postgres.py +204 -0
- topos_node-1.0.0/topos/storage/db/migrations/__init__.py +172 -0
- topos_node-1.0.0/topos/storage/db/migrations/canonical_disclosure_v1.py +62 -0
- topos_node-1.0.0/topos/storage/db/migrations/canonical_nsfw_v1.py +55 -0
- topos_node-1.0.0/topos/storage/db/migrations/extraction_artifacts.py +48 -0
- topos_node-1.0.0/topos/storage/db/migrations/journal_entries_duration_v1.py +28 -0
- topos_node-1.0.0/topos/storage/db/migrations/journal_entries_ends_at_v1.py +45 -0
- topos_node-1.0.0/topos/storage/db/migrations/journal_entries_people_v1.py +32 -0
- topos_node-1.0.0/topos/storage/db/migrations/journal_entries_place_name_v1.py +32 -0
- topos_node-1.0.0/topos/storage/db/migrations/journal_entries_starts_at_v1.py +40 -0
- topos_node-1.0.0/topos/storage/db/migrations/remediation_person_model.py +49 -0
- topos_node-1.0.0/topos/storage/db/migrations/scope_source_generation.py +39 -0
- topos_node-1.0.0/topos/storage/db/migrations/signal_dimension_harness.py +96 -0
- topos_node-1.0.0/topos/storage/db/migrations/signal_objects.py +53 -0
- topos_node-1.0.0/topos/storage/db/migrations/signal_objects_updated_by_v1.py +30 -0
- topos_node-1.0.0/topos/storage/db/migrations/vector_storage_v1.py +91 -0
- topos_node-1.0.0/topos/storage/db/migrations/vector_storage_v2.py +98 -0
- topos_node-1.0.0/topos/storage/db/migrations/vector_storage_v3.py +86 -0
- topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_phase0.py +288 -0
- topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_phase1.py +149 -0
- topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +57 -0
- topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +75 -0
- topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +73 -0
- topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_query_quality.py +93 -0
- topos_node-1.0.0/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +37 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/paths.py +53 -0
- topos_node-1.0.0/topos/storage/db/storage_breakdown.py +261 -0
- topos_node-1.0.0/topos/storage/person/identity_resolver.py +108 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/uma_filters.py +66 -34
- {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/PKG-INFO +23 -10
- {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/SOURCES.txt +137 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/requires.txt +22 -7
- topos_node-0.1.18/topos/api/ingestion_api.py +0 -37
- topos_node-0.1.18/topos/canonicalization/mappers/__init__.py +0 -22
- topos_node-0.1.18/topos/engine/backends/huggingface.py +0 -151
- topos_node-0.1.18/topos/enrichment/derived_tables.py +0 -214
- topos_node-0.1.18/topos/enrichment/jobs/__init__.py +0 -30
- topos_node-0.1.18/topos/enrichment/jobs/canonical/embeddings_job.py +0 -27
- topos_node-0.1.18/topos/enrichment/jobs/canonical/entities_job.py +0 -27
- topos_node-0.1.18/topos/enrichment/jobs/canonical/sentiment_job.py +0 -27
- topos_node-0.1.18/topos/enrichment/jobs/canonical/topics_job.py +0 -27
- topos_node-0.1.18/topos/enrichment/orchestrator.py +0 -177
- topos_node-0.1.18/topos/storage/canonical/canonical_store.py +0 -24
- topos_node-0.1.18/topos/storage/canonical/mapping_store.py +0 -30
- topos_node-0.1.18/topos/storage/canonical/postgres.py +0 -10
- topos_node-0.1.18/topos/storage/db/migrations/__init__.py +0 -1
- {topos_node-0.1.18 → topos_node-1.0.0}/LICENSE +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/setup.cfg +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/shared/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/shared/filtering.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/shared/schema_registry.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/tests/test_llm_integrations_storage.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/duckdb_adapter.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/messenger_communities.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/messenger_graph.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/messenger_labels.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/profiles.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/query_engine.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/analytics/raw_queries.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/analytics.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/app_registry.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/backup.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/compute_remote.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/data_commit.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/data_explorer_table_prefs.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/database_explorer.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/db.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/device.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/filter_lab.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/health.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/home_chat.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/ingestion_compat.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/llm.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/local_mcp.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/messenger_analytics.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/query_api.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/runtime_bootstrap.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/sanitization_ollama_config.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/sources.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/sources_overview.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/sync.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/ui_config.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/uma_data.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/usage.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/api/user_identity.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/auth.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/mappers/base.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/mappers/grok_mapper.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/models.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/canonicalization/resolver.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/cli/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/cli/__main__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/config/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/config/sanitization_ollama.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/contacts/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/contacts/identity.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/control_plane_client.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/connection_resilience.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/device_helpers.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/errors.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/events.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/metrics.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/routine_access.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/startup_banner.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/table_layers.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/core/types.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/data_explorer_table_prefs.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/backends/base.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/backends/stub.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/intake.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/queue_manager.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/result_formatter.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/scoped_token.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/tasks.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/transport.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/usage_guard.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/usage_observation.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/engine/validator.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/canonical/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/raw/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/raw/language_job.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/models/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/models/manager.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/models/registry.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/models/versioning.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/processor.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/progress_bar.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/enrichment/website_classifier.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/bundles.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/schema.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/service.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/filter_lab/store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/home_chat/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/home_chat/schema.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/home_chat/store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/hosted_pool_lease.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/checkpoints/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/jobs.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/local_sync.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/log_preview.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parser.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/base.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/browser_parser.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/calendar_parser.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/grok_parser.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/parsers/messenger_parser.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/progress.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/base.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/calendar.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/chatgpt.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/contact_importers.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/grok.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/imessage_reader.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/signal_export_parser.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/sources/signal_reader.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/state_machine.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/triggers/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/triggers/file_trigger.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/validation/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/validation/base.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/validation/schema_registry.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/ingestion/validation/schema_validator.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/lineage/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/lineage/provenance.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/lineage/tracker.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/llm_integrations_storage.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/mcp_stdio_proxy.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/observability/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/observability/alerts.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/observability/metrics.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/observability/tracing.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/openai_client.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/projections/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/projections/vector_index/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/projections/vector_index/base.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/projections/vector_index/builders.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/projections/vector_index/health_checks.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/rate_limit.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/routines/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/routines/schema.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/routines/store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/runtime_update.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/sanitization/ollama_transforms.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/scope_resolution.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/container.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/embeddings/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/embeddings/base.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/embeddings/local.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/embeddings/remote.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/interfaces.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/llm/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/llm/base.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/llm/openai.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/services/postgres.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/sources/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/startup_banner.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/ai_chat/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/ai_chat/mapper.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/canonical/ai_chat/model.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/client.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/postgres.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/db/schema.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/enrichment/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/normalized/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/normalized/normalized_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/oplog/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/oplog/decision.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/oplog/oplog_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/oplog/postgres.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/projections/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/projections/index_ops_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/projections/vector_index_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/browser_flat_tables.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/file_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/raw_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/raw_tables_manager.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/raw/sqlite_raw_store.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/security/encryption.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/signal_identity.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/source_settings.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/storage/user_identity.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/sync/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/sync/client.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/sync_handlers.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/testing/__init__.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/testing/lifespan.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/uma_contact_enrichment.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/uma_resource_id.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/uma_rpt.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/utils/base_object.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos/websocket_client.py +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/dependency_links.txt +0 -0
- {topos_node-0.1.18 → topos_node-1.0.0}/topos_node.egg-info/entry_points.txt +0 -0
- {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.
|
|
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:
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "topos-node"
|
|
7
|
-
version = "0.
|
|
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"]
|
|
@@ -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
|
|
89
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
106
|
-
|
|
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
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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:
|
|
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}
|