topos-node 1.0.7__tar.gz → 1.0.8__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-1.0.7 → topos_node-1.0.8}/PKG-INFO +1 -1
- {topos_node-1.0.7 → topos_node-1.0.8}/pyproject.toml +10 -1
- topos_node-1.0.8/tests/test_protocol_handled_types.py +70 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/__version__.py +2 -2
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/ingestion_sources.py +9 -8
- topos_node-1.0.8/topos/api/intelligence_lifecycle.py +98 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/signal.py +182 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/source_install.py +11 -2
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/app.py +2 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/config/settings.py +4 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/control_plane_client.py +8 -0
- topos_node-1.0.8/topos/core/handlers/__init__.py +178 -0
- topos_node-1.0.8/topos/core/handlers/common.py +162 -0
- topos_node-1.0.8/topos/core/handlers/config.py +346 -0
- topos_node-1.0.8/topos/core/handlers/contacts_import.py +287 -0
- topos_node-1.0.8/topos/core/handlers/database_explorer.py +1686 -0
- topos_node-1.0.8/topos/core/handlers/device.py +327 -0
- topos_node-1.0.8/topos/core/handlers/enrichment.py +465 -0
- topos_node-1.0.8/topos/core/handlers/filter_lab.py +230 -0
- topos_node-1.0.8/topos/core/handlers/home_chat.py +91 -0
- topos_node-1.0.8/topos/core/handlers/ingest.py +526 -0
- topos_node-1.0.8/topos/core/handlers/messages.py +1106 -0
- topos_node-1.0.8/topos/core/handlers/messenger_analytics.py +471 -0
- topos_node-1.0.8/topos/core/handlers/query.py +64 -0
- topos_node-1.0.8/topos/core/handlers/registry.py +21 -0
- topos_node-1.0.8/topos/core/handlers/routines.py +298 -0
- topos_node-1.0.8/topos/core/handlers/signal_features.py +628 -0
- topos_node-1.0.8/topos/core/handlers/sources.py +457 -0
- topos_node-1.0.8/topos/core/handlers/uma.py +753 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/logging.py +2 -3
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/disclosure/field_registry.py +11 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/disclosure/tier.py +44 -12
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/backends/huggingface.py +147 -4
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/model_cache.py +3 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/__init__.py +12 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/embeddings_job.py +20 -9
- topos_node-1.0.8/topos/enrichment/jobs/canonical/entities_job.py +205 -0
- topos_node-1.0.8/topos/enrichment/jobs/canonical/fact_extraction_job.py +46 -0
- topos_node-1.0.8/topos/enrichment/jobs/canonical/statistics_job.py +116 -0
- topos_node-1.0.8/topos/enrichment/jobs/canonical/timeline_job.py +67 -0
- topos_node-1.0.8/topos/enrichment/jobs/canonical/topic_clusters_job.py +195 -0
- topos_node-1.0.8/topos/features/entities/__init__.py +1 -0
- topos_node-1.0.8/topos/features/entities/consolidation.py +349 -0
- topos_node-1.0.8/topos/features/entities/dossier.py +164 -0
- topos_node-1.0.8/topos/features/entities/edges.py +180 -0
- topos_node-1.0.8/topos/features/entities/linking.py +144 -0
- topos_node-1.0.8/topos/features/entities/reads.py +142 -0
- topos_node-1.0.8/topos/features/entities/resolver.py +486 -0
- topos_node-1.0.8/topos/features/facts/__init__.py +1 -0
- topos_node-1.0.8/topos/features/facts/extract.py +204 -0
- topos_node-1.0.8/topos/features/facts/reads.py +236 -0
- topos_node-1.0.8/topos/features/facts/store.py +346 -0
- topos_node-1.0.8/topos/features/lifecycle/__init__.py +1 -0
- topos_node-1.0.8/topos/features/lifecycle/derived_scrub.py +428 -0
- topos_node-1.0.8/topos/features/lifecycle/exclusions.py +239 -0
- topos_node-1.0.8/topos/features/signal/embed_context.py +110 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/hybrid_search.py +2 -1
- topos_node-1.0.8/topos/features/signal/incremental_clustering.py +304 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/service.py +65 -12
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/topic_clustering.py +90 -25
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/vector_settings.py +37 -0
- topos_node-1.0.8/topos/features/stats/__init__.py +1 -0
- topos_node-1.0.8/topos/features/stats/definitions.py +227 -0
- topos_node-1.0.8/topos/features/stats/engine.py +280 -0
- topos_node-1.0.8/topos/features/stats/fold.py +226 -0
- topos_node-1.0.8/topos/features/stats/insights.py +119 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/ingest_helpers.py +6 -4
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/manager.py +4 -2
- topos_node-1.0.8/topos/query/ddr.py +135 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/disclosure.py +64 -1
- topos_node-1.0.8/topos/query/fingerprint.py +35 -0
- topos_node-1.0.8/topos/query/grant_cache.py +159 -0
- topos_node-1.0.8/topos/query/minimizer.py +315 -0
- topos_node-1.0.8/topos/query/negotiation.py +384 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/pipeline.py +150 -3
- topos_node-1.0.8/topos/query/planner.py +175 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/retrieval.py +400 -88
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/session.py +3 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/turn_classifier.py +6 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sources/canonical_signal_defaults.py +3 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sources/definitions.py +76 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sources/install_service.py +8 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sources/registry.py +16 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sources/runtime_install.py +2 -1
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sources/scrub_service.py +48 -0
- topos_node-1.0.8/topos/storage/adapters/sqlite/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/adapters/sqlite/stores.py +8 -8
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/adapters/sqlite/vector_search.py +49 -27
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/__init__.py +32 -0
- topos_node-1.0.8/topos/storage/db/migrations/vector_storage_v4.py +147 -0
- topos_node-1.0.8/topos/storage/db/migrations/wiki_clusters_v2.py +44 -0
- topos_node-1.0.8/topos/storage/db/migrations/wiki_entities_v1.py +99 -0
- topos_node-1.0.8/topos/storage/db/migrations/wiki_entity_review_v2.py +38 -0
- topos_node-1.0.8/topos/storage/db/migrations/wiki_facts_v1.py +41 -0
- topos_node-1.0.8/topos/storage/db/migrations/wiki_lifecycle_v1.py +41 -0
- topos_node-1.0.8/topos/storage/db/migrations/wiki_stats_v1.py +66 -0
- topos_node-1.0.8/topos/storage/db/migrations/wiki_timeline_v1.py +39 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos_node.egg-info/PKG-INFO +1 -1
- {topos_node-1.0.7 → topos_node-1.0.8}/topos_node.egg-info/SOURCES.txt +58 -1
- topos_node-1.0.7/topos/core/handlers.py +0 -6941
- topos_node-1.0.7/topos/enrichment/jobs/canonical/entities_job.py +0 -69
- topos_node-1.0.7/topos/enrichment/jobs/canonical/topic_clusters_job.py +0 -84
- topos_node-1.0.7/topos/query/fingerprint.py +0 -21
- {topos_node-1.0.7 → topos_node-1.0.8}/LICENSE +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/README.md +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/setup.cfg +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/shared/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/shared/filtering.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/shared/schema_registry.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/tests/test_llm_integrations_storage.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/analytics/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/analytics/duckdb_adapter.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/analytics/messenger_communities.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/analytics/messenger_graph.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/analytics/messenger_labels.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/analytics/profiles.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/analytics/query_engine.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/analytics/raw_queries.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/analytics.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/app_registry.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/backup.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/compute_remote.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/data_commit.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/data_explorer_table_prefs.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/database_explorer.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/db.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/device.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/engine_run.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/enrichment.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/filter_lab.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/health.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/home_chat.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/ingestion_api.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/ingestion_compat.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/llm.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/local_mcp.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/messenger_analytics.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/privacy_disclose.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/query_api.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/runtime_bootstrap.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/sanitization_ollama_config.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/signal_extraction_config.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/source_scrub.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/sources.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/sources_overview.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/sync.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/ui_config.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/uma_data.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/usage.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/api/user_identity.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/auth.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/canonicalization/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/canonicalization/mappers/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/canonicalization/mappers/base.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/canonicalization/mappers/browser_activity_mapper.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/canonicalization/mappers/chatgpt_mapper.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/canonicalization/mappers/demo_mappers.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/canonicalization/mappers/grok_mapper.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/canonicalization/mappers/messenger_mapper.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/canonicalization/models.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/canonicalization/resolver.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/cli/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/cli/__main__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/cli/commands.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/config/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/config/sanitization_ollama.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/config/signal_extraction.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/contacts/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/contacts/identity.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/api_models.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/connection_resilience.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/device_helpers.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/errors.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/events.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/metrics.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/routine_access.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/startup_banner.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/state.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/table_layers.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/core/types.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/data_explorer_row_delete.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/data_explorer_table_prefs.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/data_explorer_tables.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/disclosure/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/disclosure/canonical_writer.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/disclosure/content_policy.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/disclosure/privacy_layer.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/backends/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/backends/base.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/backends/generative_prompts.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/backends/generative_response.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/backends/ollama.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/backends/openai.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/backends/openai_compatible.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/backends/redpill.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/backends/stub.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/client.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/engine.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/intake.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/memory_utils.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/pipeline_memory.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/queue_manager.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/registration.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/result_formatter.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/router.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/scoped_token.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/tasks.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/transport.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/usage_guard.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/usage_observation.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/engine/validator.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/derived_tables.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/job_writer.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/base.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/_batch_limits.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/_engine_runner.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/availability_scores_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/brief_fallback.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/dimension_summary_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/emo_27_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/goal_extraction_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/pii_redaction_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/relationship_edges_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/sentiment_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/topics_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/url_classification_core.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/url_classification_enrichment_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/canonical/url_classification_signal_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/raw/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/raw/language_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/models/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/models/manager.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/models/mvp_defaults.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/models/registry.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/models/versioning.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/orchestrator.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/processor.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/progress_bar.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/registry_contract.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/enrichment/website_classifier.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/fit/evaluator.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/brief_canonical_loader.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/brief_ontology.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/brief_renderer.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/brief_schemas.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/chunking.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/data_health.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/dimension_briefs.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/dimension_definition_loader.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/dimension_profiles.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/dimension_registry.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/extraction/artifact_router.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/extraction/artifact_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/extraction/rule_extractors.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/graph_sanitize.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/query_embed_cache.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/schemas.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/signal_object_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/source_hydration.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/structured_signal.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/typed_stores/aggregates.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/typed_stores/scope_materializer.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/vector_codec.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/features/signal/vector_math.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/filter_lab/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/filter_lab/bundles.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/filter_lab/schema.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/filter_lab/service.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/filter_lab/store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/filter_lab/worker.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/home_chat/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/home_chat/schema.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/home_chat/store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/hosted_pool_lease.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/canonical_pipeline.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/checkpoints/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/inbox_crypto.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/inbox_drain.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/jobs.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/journal_location_fanout.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/journal_time_log_normalize.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/local_sync.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/log_preview.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parser.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parsers/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parsers/base.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parsers/browser_parser.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parsers/calendar_parser.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parsers/demo_file_parsers.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parsers/grok_parser.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parsers/messenger_parser.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/parsers/voxterm_parser.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/progress.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/reprocess.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/sources/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/sources/base.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/sources/calendar.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/sources/chatgpt.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/sources/contact_importers.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/sources/grok.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/sources/imessage_reader.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/sources/signal_export_parser.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/sources/signal_reader.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/state_machine.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/triggers/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/triggers/file_trigger.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/usage_inbox_dedupe.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/validation/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/validation/base.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/validation/schema_registry.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/ingestion/validation/schema_validator.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/lineage/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/lineage/provenance.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/lineage/tracker.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/llm_integrations_storage.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/mcp_stdio_proxy.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/observability/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/observability/alerts.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/observability/metrics.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/observability/tracing.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/openai_client.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/pipeline/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/pipeline/audit.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/pipeline/envelope.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/pipeline/stages.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/pipeline/stub_enqueue.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/projections/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/projections/vector_index/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/projections/vector_index/base.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/projections/vector_index/builders.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/projections/vector_index/health_checks.py +0 -0
- {topos_node-1.0.7/topos/storage/adapters/sqlite → topos_node-1.0.8/topos/protocol}/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/audit.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/game_layer.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/inference.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/intent.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/manifest.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/manifest_validation.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/runtime.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/scope_registry_loader.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/session_utils.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/source_generation.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/query/types.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/rate_limit.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/routines/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/routines/schema.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/routines/store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/runtime_update.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sanitization/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sanitization/nsfw_classifier.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sanitization/ollama_transforms.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sanitization/privacy_filter.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/scope_resolution.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/container.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/embeddings/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/embeddings/base.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/embeddings/local.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/embeddings/remote.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/interfaces.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/llm/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/llm/base.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/llm/openai.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/local.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/services/postgres.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sources/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sources/bundled_canonical_triples.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sources/scrub_attribution.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/startup_banner.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/adapters/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/adapters/factory.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/adapters/fakes.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/adapters/postgres/stores.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/adapters/protocols.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/activity_tables.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/ai_chat/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/ai_chat/canonicalizer.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/ai_chat/mapper.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/ai_chat/model.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/ai_chat/tables.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/calendar_contacts_tables.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/canonical_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/conversations_tables.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/mapping_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/canonical/postgres.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/client.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/canonical_disclosure_v1.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/canonical_nsfw_v1.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/extraction_artifacts.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/journal_entries_duration_v1.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/journal_entries_ends_at_v1.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/journal_entries_people_v1.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/journal_entries_place_name_v1.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/journal_entries_starts_at_v1.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/remediation_person_model.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/scope_source_generation.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/signal_dimension_harness.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/signal_objects.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/signal_objects_updated_by_v1.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/vector_storage_v1.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/vector_storage_v2.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/vector_storage_v3.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/wiki_mvp_phase0.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/wiki_mvp_phase1.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/wiki_mvp_query_quality.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/paths.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/postgres.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/schema.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/db/storage_breakdown.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/enrichment/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/normalized/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/normalized/normalized_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/oplog/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/oplog/decision.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/oplog/oplog_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/oplog/postgres.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/person/identity_resolver.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/projections/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/projections/index_ops_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/projections/vector_index_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/raw/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/raw/browser_flat_tables.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/raw/file_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/raw/raw_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/raw/raw_tables_manager.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/raw/sqlite_raw_store.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/security/encryption.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/signal_identity.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/source_settings.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/storage/user_identity.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sync/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sync/client.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/sync_handlers.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/testing/__init__.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/testing/lifespan.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/uma_contact_enrichment.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/uma_filters.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/uma_resource_id.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/uma_rpt.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/utils/base_object.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos/websocket_client.py +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos_node.egg-info/dependency_links.txt +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos_node.egg-info/entry_points.txt +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos_node.egg-info/requires.txt +0 -0
- {topos_node-1.0.7 → topos_node-1.0.8}/topos_node.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "topos-node"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.8"
|
|
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"
|
|
@@ -89,6 +89,15 @@ markers = [
|
|
|
89
89
|
"public: public-safe test lane for OSS CI",
|
|
90
90
|
"private: internal architecture or fixtures; excluded from public CI",
|
|
91
91
|
"e2e: end-to-end tests (live Keycloak + Control Plane; require config and running CP)",
|
|
92
|
+
"live: requires a running local engine (localhost:9000) and a real TOPOS_KEY; excluded from deterministic lanes",
|
|
93
|
+
"release_pressure: iteration-4 live pressure smoke; run explicitly before releases",
|
|
94
|
+
"p0: priority marker on release pressure tests",
|
|
95
|
+
"retrieval_eval: dense-intelligence retrieval eval (loads local embedding model; run explicitly)",
|
|
96
|
+
"adversarial: scope-break / access-control adversarial test (privacy enforcement)",
|
|
97
|
+
"uar: unauthorized-access-rate probe (privacy claim #1); tier-1 CI gate, must find zero leaks",
|
|
98
|
+
"cer: canary-extraction-rate probe (privacy claim #2); tier-1 CI gate",
|
|
99
|
+
"eval_nightly: statistical privacy eval (attacker advantage, minimality, latency); nightly",
|
|
100
|
+
"eval_release: release-tier privacy eval (negotiation A/B, Pareto); run per release",
|
|
92
101
|
]
|
|
93
102
|
pythonpath = ["tests/gap/p3/engine", "tests/gap/p4/engine", "tests/gap/qq/engine", "tests/acceptance/wiki_mvp"]
|
|
94
103
|
testpaths = ["tests"]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Guards for the handled-message-types protocol snapshot.
|
|
2
|
+
|
|
3
|
+
The snapshot (topos/protocol/handled_message_types.json) is the machine-readable
|
|
4
|
+
list of control-plane message types this engine dispatches. Two invariants:
|
|
5
|
+
|
|
6
|
+
1. Freshness — the committed snapshot equals the runtime HANDLERS registry.
|
|
7
|
+
Adding or removing an @handles registration requires regenerating it:
|
|
8
|
+
uv run python scripts/dump_handled_types.py > topos/protocol/handled_message_types.json
|
|
9
|
+
|
|
10
|
+
2. Static parity — the set of string literals in @handles(...) decorators equals
|
|
11
|
+
the runtime registry, so no handler is registered dynamically in a way that
|
|
12
|
+
static consumers of the snapshot (or this repo's source) would miss.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import ast
|
|
17
|
+
import json
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
21
|
+
SNAPSHOT = REPO_ROOT / "topos" / "protocol" / "handled_message_types.json"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _runtime_handled() -> set[str]:
|
|
25
|
+
from topos.core.handlers import HANDLERS
|
|
26
|
+
|
|
27
|
+
return set(HANDLERS)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _static_handled() -> set[str]:
|
|
31
|
+
found: set[str] = set()
|
|
32
|
+
for py in sorted((REPO_ROOT / "topos").rglob("*.py")):
|
|
33
|
+
if "__pycache__" in py.parts:
|
|
34
|
+
continue
|
|
35
|
+
try:
|
|
36
|
+
tree = ast.parse(py.read_text(encoding="utf-8"))
|
|
37
|
+
except SyntaxError:
|
|
38
|
+
continue
|
|
39
|
+
for node in ast.walk(tree):
|
|
40
|
+
if isinstance(node, ast.Call) and getattr(node.func, "id", "") == "handles":
|
|
41
|
+
for arg in node.args:
|
|
42
|
+
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
|
|
43
|
+
found.add(arg.value)
|
|
44
|
+
return found
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_snapshot_matches_runtime_registry():
|
|
48
|
+
snapshot = set(json.loads(SNAPSHOT.read_text(encoding="utf-8"))["handled_message_types"])
|
|
49
|
+
runtime = _runtime_handled()
|
|
50
|
+
missing = sorted(runtime - snapshot)
|
|
51
|
+
stale = sorted(snapshot - runtime)
|
|
52
|
+
assert not missing and not stale, (
|
|
53
|
+
"topos/protocol/handled_message_types.json is stale "
|
|
54
|
+
f"(missing={missing}, stale={stale}). Regenerate with: "
|
|
55
|
+
"uv run python scripts/dump_handled_types.py > topos/protocol/handled_message_types.json"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_static_handles_literals_match_runtime_registry():
|
|
60
|
+
runtime = _runtime_handled()
|
|
61
|
+
static = _static_handled()
|
|
62
|
+
dynamic_only = sorted(runtime - static)
|
|
63
|
+
unregistered = sorted(static - runtime)
|
|
64
|
+
assert not dynamic_only, (
|
|
65
|
+
"Handlers registered without a literal @handles(...) decorator; static "
|
|
66
|
+
f"consumers of the registry cannot see them: {dynamic_only}"
|
|
67
|
+
)
|
|
68
|
+
assert not unregistered, (
|
|
69
|
+
f"@handles(...) literals that never reach the runtime registry: {unregistered}"
|
|
70
|
+
)
|
|
@@ -12,6 +12,7 @@ from ..auth import require_api_key
|
|
|
12
12
|
from ..core.state import get_db_connection
|
|
13
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
|
+
from ..sources.definitions import DELIVERY_LOCAL_SYNC, accepts_app_ingest, is_file_delivery
|
|
15
16
|
from ..sources.registry import REGISTRY
|
|
16
17
|
from ..storage.signal_identity import get_signal_identity, put_signal_identity
|
|
17
18
|
from ..storage.source_settings import get_source_settings, put_source_settings, update_sync_result
|
|
@@ -55,7 +56,7 @@ async def ingest_source(
|
|
|
55
56
|
if not source:
|
|
56
57
|
return {"status": "error", "error": "unknown source_id"}
|
|
57
58
|
|
|
58
|
-
if source
|
|
59
|
+
if is_file_delivery(source):
|
|
59
60
|
file = None
|
|
60
61
|
if request.headers.get("content-type", "").startswith("multipart/"):
|
|
61
62
|
form = await request.form()
|
|
@@ -108,7 +109,7 @@ async def ingest_source(
|
|
|
108
109
|
file_format=resolve_file_format(source_definition=source),
|
|
109
110
|
)
|
|
110
111
|
|
|
111
|
-
if source
|
|
112
|
+
if accepts_app_ingest(source):
|
|
112
113
|
if payload is None:
|
|
113
114
|
try:
|
|
114
115
|
payload = await request.json()
|
|
@@ -123,7 +124,7 @@ async def ingest_source(
|
|
|
123
124
|
source_id=source_id, # Pass source_id to enable direct processing
|
|
124
125
|
)
|
|
125
126
|
|
|
126
|
-
if source.
|
|
127
|
+
if source.delivery == DELIVERY_LOCAL_SYNC:
|
|
127
128
|
# iMessage, Signal: ingestion is via sync endpoint (POST /sources/{source_id}/sync), not file/body upload
|
|
128
129
|
return {
|
|
129
130
|
"status": "error",
|
|
@@ -161,7 +162,7 @@ async def put_source_settings_endpoint(
|
|
|
161
162
|
source = REGISTRY.get(source_id)
|
|
162
163
|
if not source:
|
|
163
164
|
return {"status": "error", "error": "unknown source_id"}
|
|
164
|
-
if source.
|
|
165
|
+
if source.delivery != DELIVERY_LOCAL_SYNC:
|
|
165
166
|
return {"status": "error", "error": "settings only apply to local_sync sources"}
|
|
166
167
|
dataset_id = dataset_id or (body.get("dataset_id") if body else None)
|
|
167
168
|
if not dataset_id:
|
|
@@ -186,7 +187,7 @@ async def sync_source(
|
|
|
186
187
|
source = REGISTRY.get(source_id)
|
|
187
188
|
if not source:
|
|
188
189
|
return {"status": "error", "error": "unknown source_id"}
|
|
189
|
-
if source.
|
|
190
|
+
if source.delivery != DELIVERY_LOCAL_SYNC:
|
|
190
191
|
return {"status": "error", "error": "sync endpoint only applies to local_sync sources"}
|
|
191
192
|
|
|
192
193
|
if not dataset_id:
|
|
@@ -315,7 +316,7 @@ async def get_source_contacts(
|
|
|
315
316
|
source = REGISTRY.get(source_id)
|
|
316
317
|
if not source:
|
|
317
318
|
return {"status": "error", "error": "unknown source_id"}
|
|
318
|
-
if source.
|
|
319
|
+
if source.delivery != DELIVERY_LOCAL_SYNC:
|
|
319
320
|
return {"status": "error", "error": "contacts only apply to local_sync sources"}
|
|
320
321
|
if not dataset_id:
|
|
321
322
|
return {"status": "error", "error": "dataset_id required"}
|
|
@@ -368,7 +369,7 @@ async def put_source_contact(
|
|
|
368
369
|
source = REGISTRY.get(source_id)
|
|
369
370
|
if not source:
|
|
370
371
|
return {"status": "error", "error": "unknown source_id"}
|
|
371
|
-
if source.
|
|
372
|
+
if source.delivery != DELIVERY_LOCAL_SYNC:
|
|
372
373
|
return {"status": "error", "error": "contacts only apply to local_sync sources"}
|
|
373
374
|
if not dataset_id:
|
|
374
375
|
return {"status": "error", "error": "dataset_id required"}
|
|
@@ -395,7 +396,7 @@ async def auto_resolve_source_contacts(
|
|
|
395
396
|
source = REGISTRY.get(source_id)
|
|
396
397
|
if not source:
|
|
397
398
|
return {"status": "error", "error": "unknown source_id"}
|
|
398
|
-
if source.
|
|
399
|
+
if source.delivery != DELIVERY_LOCAL_SYNC:
|
|
399
400
|
return {"status": "error", "error": "contacts only apply to local_sync sources"}
|
|
400
401
|
if not dataset_id:
|
|
401
402
|
return {"status": "error", "error": "dataset_id required"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Owner data-control API: exclude artifacts from derived intelligence.
|
|
2
|
+
|
|
3
|
+
These endpoints are the "remove things I don't want included" surface:
|
|
4
|
+
GET /intelligence/exclusions — list tombstones
|
|
5
|
+
POST /intelligence/exclusions/fact — soft-close + tombstone a fact
|
|
6
|
+
POST /intelligence/exclusions/entity — stop tracking an entity
|
|
7
|
+
POST /intelligence/exclusions/stat — suppress a stat insight
|
|
8
|
+
POST /intelligence/exclusions/record — purge one record's derived traces
|
|
9
|
+
DELETE /intelligence/exclusions — lift a tombstone (re-inclusion
|
|
10
|
+
happens on the next enrichment)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any, Dict, Optional
|
|
16
|
+
|
|
17
|
+
from fastapi import APIRouter, Body, Depends, HTTPException
|
|
18
|
+
|
|
19
|
+
from ..auth import require_api_key
|
|
20
|
+
from ..core.state import get_db_connection
|
|
21
|
+
|
|
22
|
+
router = APIRouter(tags=["intelligence-lifecycle"])
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _store():
|
|
26
|
+
conn = get_db_connection()
|
|
27
|
+
if conn is None:
|
|
28
|
+
raise HTTPException(status_code=503, detail="Database not available")
|
|
29
|
+
from ..features.lifecycle.exclusions import ExclusionStore
|
|
30
|
+
|
|
31
|
+
return ExclusionStore(conn)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@router.get("/intelligence/exclusions", dependencies=[Depends(require_api_key)])
|
|
35
|
+
async def list_exclusions(artifact_type: Optional[str] = None) -> Dict[str, Any]:
|
|
36
|
+
items = _store().list(artifact_type=artifact_type)
|
|
37
|
+
return {"items": items, "total": len(items)}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@router.post("/intelligence/exclusions/fact", dependencies=[Depends(require_api_key)])
|
|
41
|
+
async def exclude_fact(
|
|
42
|
+
subject_entity_id: str = Body(...),
|
|
43
|
+
predicate: str = Body(...),
|
|
44
|
+
object_value: Optional[str] = Body(None),
|
|
45
|
+
note: Optional[str] = Body(None),
|
|
46
|
+
) -> Dict[str, Any]:
|
|
47
|
+
try:
|
|
48
|
+
return _store().exclude_fact(
|
|
49
|
+
subject_entity_id=subject_entity_id,
|
|
50
|
+
predicate=predicate,
|
|
51
|
+
object_value=object_value,
|
|
52
|
+
note=note,
|
|
53
|
+
)
|
|
54
|
+
except ValueError as exc:
|
|
55
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@router.post("/intelligence/exclusions/entity", dependencies=[Depends(require_api_key)])
|
|
59
|
+
async def exclude_entity(
|
|
60
|
+
entity_ref: str = Body(..., description="entity_id or name"),
|
|
61
|
+
note: Optional[str] = Body(None),
|
|
62
|
+
) -> Dict[str, Any]:
|
|
63
|
+
try:
|
|
64
|
+
return _store().exclude_entity(entity_ref=entity_ref, note=note)
|
|
65
|
+
except ValueError as exc:
|
|
66
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@router.post("/intelligence/exclusions/stat", dependencies=[Depends(require_api_key)])
|
|
70
|
+
async def exclude_stat_insight(
|
|
71
|
+
stat_id: str = Body(...),
|
|
72
|
+
group_key: str = Body(""),
|
|
73
|
+
note: Optional[str] = Body(None),
|
|
74
|
+
) -> Dict[str, Any]:
|
|
75
|
+
try:
|
|
76
|
+
return _store().exclude_stat_insight(stat_id=stat_id, group_key=group_key, note=note)
|
|
77
|
+
except ValueError as exc:
|
|
78
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@router.post("/intelligence/exclusions/record", dependencies=[Depends(require_api_key)])
|
|
82
|
+
async def exclude_record(
|
|
83
|
+
record_id: str = Body(...),
|
|
84
|
+
note: Optional[str] = Body(None),
|
|
85
|
+
) -> Dict[str, Any]:
|
|
86
|
+
try:
|
|
87
|
+
return _store().exclude_record(record_id=record_id, note=note)
|
|
88
|
+
except ValueError as exc:
|
|
89
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@router.delete("/intelligence/exclusions", dependencies=[Depends(require_api_key)])
|
|
93
|
+
async def remove_exclusion(
|
|
94
|
+
artifact_type: str = Body(...),
|
|
95
|
+
artifact_key: str = Body(...),
|
|
96
|
+
) -> Dict[str, Any]:
|
|
97
|
+
removed = _store().remove_exclusion(artifact_type, artifact_key)
|
|
98
|
+
return {"removed": removed}
|
|
@@ -197,6 +197,188 @@ async def evaluate_fit(body: FitEvaluateBody, _api_key: str = Depends(require_ap
|
|
|
197
197
|
raise HTTPException(status_code=503, detail=str(exc)) from exc
|
|
198
198
|
|
|
199
199
|
|
|
200
|
+
def _entities_conn():
|
|
201
|
+
from ..core.state import get_db_connection
|
|
202
|
+
|
|
203
|
+
conn = get_db_connection()
|
|
204
|
+
if conn is None:
|
|
205
|
+
raise HTTPException(status_code=503, detail="database_unavailable")
|
|
206
|
+
return conn
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@router.get("/entities")
|
|
210
|
+
async def list_entities(
|
|
211
|
+
q: Optional[str] = Query(default=None, max_length=200),
|
|
212
|
+
entity_type: Optional[str] = Query(default=None, max_length=40),
|
|
213
|
+
contacts_only: bool = Query(default=False),
|
|
214
|
+
limit: int = Query(default=50, ge=1, le=200),
|
|
215
|
+
offset: int = Query(default=0, ge=0),
|
|
216
|
+
_api_key: str = Depends(require_api_key),
|
|
217
|
+
):
|
|
218
|
+
"""Resolved entity registry (entity spine), sorted by mention count."""
|
|
219
|
+
from ..features.entities.reads import list_entities as _list
|
|
220
|
+
|
|
221
|
+
return _list(
|
|
222
|
+
_entities_conn(),
|
|
223
|
+
q=q,
|
|
224
|
+
entity_type=entity_type,
|
|
225
|
+
contacts_only=contacts_only,
|
|
226
|
+
limit=limit,
|
|
227
|
+
offset=offset,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# NB: must be declared before /entities/{entity_id} so "graph" isn't captured
|
|
232
|
+
# as an entity id.
|
|
233
|
+
@router.get("/entities/graph")
|
|
234
|
+
async def get_entity_graph(
|
|
235
|
+
limit_nodes: int = Query(default=100, ge=1, le=500),
|
|
236
|
+
limit_edges: int = Query(default=300, ge=1, le=1500),
|
|
237
|
+
min_weight: float = Query(default=0.0, ge=0.0),
|
|
238
|
+
_api_key: str = Depends(require_api_key),
|
|
239
|
+
):
|
|
240
|
+
"""Entity-spine graph (decayed typed edges) in list_graph node/edge shape."""
|
|
241
|
+
from ..features.entities.reads import entity_graph
|
|
242
|
+
|
|
243
|
+
return entity_graph(
|
|
244
|
+
_entities_conn(),
|
|
245
|
+
limit_nodes=limit_nodes,
|
|
246
|
+
limit_edges=limit_edges,
|
|
247
|
+
min_weight=min_weight,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
@router.get("/entities/{entity_id}")
|
|
252
|
+
async def get_entity(
|
|
253
|
+
entity_id: str,
|
|
254
|
+
_api_key: str = Depends(require_api_key),
|
|
255
|
+
):
|
|
256
|
+
"""Entity detail: aliases, connections, recent mentions, dossier (owner view)."""
|
|
257
|
+
from ..features.entities.reads import get_entity_detail
|
|
258
|
+
|
|
259
|
+
detail = get_entity_detail(_entities_conn(), entity_id)
|
|
260
|
+
if detail is None:
|
|
261
|
+
raise HTTPException(status_code=404, detail=f"entity not found: {entity_id}")
|
|
262
|
+
return detail
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@router.get("/entity-review")
|
|
266
|
+
async def list_entity_review(
|
|
267
|
+
status: str = Query(default="pending", max_length=20),
|
|
268
|
+
limit: int = Query(default=100, ge=1, le=500),
|
|
269
|
+
_api_key: str = Depends(require_api_key),
|
|
270
|
+
):
|
|
271
|
+
"""Pending entity merge candidates (owner curation queue)."""
|
|
272
|
+
from ..features.entities.consolidation import list_review
|
|
273
|
+
|
|
274
|
+
items = list_review(_entities_conn(), status=status, limit=limit)
|
|
275
|
+
return {"items": items, "total": len(items)}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
@router.post("/entity-review/sweep")
|
|
279
|
+
async def run_entity_review_sweep(_api_key: str = Depends(require_api_key)):
|
|
280
|
+
"""Run the consolidation sweep now; returns proposal counts."""
|
|
281
|
+
from ..features.entities.consolidation import propose_merges
|
|
282
|
+
|
|
283
|
+
return propose_merges(_entities_conn())
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
@router.post("/entity-review/{review_id}/approve")
|
|
287
|
+
async def approve_entity_review(review_id: str, _api_key: str = Depends(require_api_key)):
|
|
288
|
+
from ..features.entities.consolidation import resolve_review
|
|
289
|
+
|
|
290
|
+
try:
|
|
291
|
+
return resolve_review(_entities_conn(), review_id, action="approve")
|
|
292
|
+
except LookupError as exc:
|
|
293
|
+
raise HTTPException(status_code=404, detail=str(exc))
|
|
294
|
+
except ValueError as exc:
|
|
295
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@router.post("/entity-review/{review_id}/dismiss")
|
|
299
|
+
async def dismiss_entity_review(review_id: str, _api_key: str = Depends(require_api_key)):
|
|
300
|
+
from ..features.entities.consolidation import resolve_review
|
|
301
|
+
|
|
302
|
+
try:
|
|
303
|
+
return resolve_review(_entities_conn(), review_id, action="dismiss")
|
|
304
|
+
except LookupError as exc:
|
|
305
|
+
raise HTTPException(status_code=404, detail=str(exc))
|
|
306
|
+
except ValueError as exc:
|
|
307
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
@router.post("/entities/{entity_id}/exclude")
|
|
311
|
+
async def exclude_entity_from_intelligence(
|
|
312
|
+
entity_id: str,
|
|
313
|
+
_api_key: str = Depends(require_api_key),
|
|
314
|
+
):
|
|
315
|
+
"""Owner exclusion: stop tracking this entity (tombstoned, reversible)."""
|
|
316
|
+
from ..features.lifecycle.exclusions import ExclusionStore
|
|
317
|
+
|
|
318
|
+
try:
|
|
319
|
+
return ExclusionStore(_entities_conn()).exclude_entity(entity_ref=entity_id)
|
|
320
|
+
except ValueError as exc:
|
|
321
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
@router.get("/facts")
|
|
325
|
+
async def list_facts(
|
|
326
|
+
predicate: Optional[str] = Query(default=None, max_length=80),
|
|
327
|
+
dimension: Optional[str] = Query(default=None, max_length=40),
|
|
328
|
+
include_closed: bool = Query(default=False),
|
|
329
|
+
limit: int = Query(default=100, ge=1, le=500),
|
|
330
|
+
offset: int = Query(default=0, ge=0),
|
|
331
|
+
_api_key: str = Depends(require_api_key),
|
|
332
|
+
):
|
|
333
|
+
"""Atomic owner facts with temporal validity (belief history via include_closed)."""
|
|
334
|
+
from ..features.facts.reads import list_facts as _list
|
|
335
|
+
|
|
336
|
+
return _list(
|
|
337
|
+
_entities_conn(),
|
|
338
|
+
predicate=predicate,
|
|
339
|
+
dimension=dimension,
|
|
340
|
+
include_closed=include_closed,
|
|
341
|
+
limit=limit,
|
|
342
|
+
offset=offset,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
@router.get("/insights")
|
|
347
|
+
async def list_stat_insights(
|
|
348
|
+
dimension: Optional[str] = Query(default=None, max_length=40),
|
|
349
|
+
limit: int = Query(default=200, ge=1, le=500),
|
|
350
|
+
_api_key: str = Depends(require_api_key),
|
|
351
|
+
):
|
|
352
|
+
"""Promoted statistical insights (owner-only rhythms, session stats, trends)."""
|
|
353
|
+
from ..features.facts.reads import list_stat_insights as _list
|
|
354
|
+
|
|
355
|
+
return _list(_entities_conn(), dimension=dimension, limit=limit)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@router.get("/timeline")
|
|
359
|
+
async def list_timeline(
|
|
360
|
+
canonical_table: Optional[str] = Query(default=None, max_length=60),
|
|
361
|
+
source_id: Optional[str] = Query(default=None, max_length=120),
|
|
362
|
+
date_from: Optional[str] = Query(default=None, max_length=32),
|
|
363
|
+
date_to: Optional[str] = Query(default=None, max_length=32),
|
|
364
|
+
limit: int = Query(default=100, ge=1, le=500),
|
|
365
|
+
offset: int = Query(default=0, ge=0),
|
|
366
|
+
_api_key: str = Depends(require_api_key),
|
|
367
|
+
):
|
|
368
|
+
"""Unified temporal projection across canonical tables (newest first)."""
|
|
369
|
+
from ..features.facts.reads import list_timeline as _list
|
|
370
|
+
|
|
371
|
+
return _list(
|
|
372
|
+
_entities_conn(),
|
|
373
|
+
canonical_table=canonical_table,
|
|
374
|
+
source_id=source_id,
|
|
375
|
+
date_from=date_from,
|
|
376
|
+
date_to=date_to,
|
|
377
|
+
limit=limit,
|
|
378
|
+
offset=offset,
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
|
|
200
382
|
@router.get("/definitions")
|
|
201
383
|
async def list_signal_definitions(_api_key: str = Depends(require_api_key)):
|
|
202
384
|
service = get_signal_service()
|
|
@@ -183,12 +183,21 @@ async def _test_ingestion_core(payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
183
183
|
if not source_def:
|
|
184
184
|
raise LookupError(f"No active install found for source_id={source_id}")
|
|
185
185
|
|
|
186
|
+
from ..sources.definitions import (
|
|
187
|
+
DELIVERY_CLIENT_PUSH,
|
|
188
|
+
DELIVERY_OWNER_UI,
|
|
189
|
+
DELIVERY_OWNER_UPLOAD,
|
|
190
|
+
derive_delivery,
|
|
191
|
+
)
|
|
192
|
+
|
|
186
193
|
source_type = str(source_def.get("source_type") or "file")
|
|
194
|
+
# Installed definitions serialized before the delivery rollout lack the field.
|
|
195
|
+
delivery = str(source_def.get("delivery") or "").strip() or derive_delivery(source_type, source_id)
|
|
187
196
|
schema_id = str(source_def.get("schema_id") or source_def.get("parser_id") or "").strip()
|
|
188
197
|
if not schema_id:
|
|
189
198
|
raise ValueError("Installed source definition is missing schema_id/parser_id")
|
|
190
199
|
|
|
191
|
-
if
|
|
200
|
+
if delivery == DELIVERY_OWNER_UPLOAD:
|
|
192
201
|
file_path = str(payload.get("sample_file_path") or "").strip()
|
|
193
202
|
if not file_path:
|
|
194
203
|
raise ValueError("sample_file_path is required for file source tests")
|
|
@@ -198,7 +207,7 @@ async def _test_ingestion_core(payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
198
207
|
file_path=file_path,
|
|
199
208
|
source_id=source_id,
|
|
200
209
|
)
|
|
201
|
-
elif
|
|
210
|
+
elif delivery in (DELIVERY_CLIENT_PUSH, DELIVERY_OWNER_UI):
|
|
202
211
|
sample_payload = payload.get("sample_payload")
|
|
203
212
|
if not isinstance(sample_payload, dict):
|
|
204
213
|
raise ValueError("sample_payload object is required for ui_stream source tests")
|
|
@@ -24,6 +24,7 @@ from .api import (
|
|
|
24
24
|
ingestion_compat as ingestion_compat_routes,
|
|
25
25
|
ingestion_api as ingestion_routes,
|
|
26
26
|
ingestion_sources as ingestion_sources_routes,
|
|
27
|
+
intelligence_lifecycle as intelligence_lifecycle_routes,
|
|
27
28
|
local_mcp as local_mcp_routes,
|
|
28
29
|
llm as llm_routes,
|
|
29
30
|
messenger_analytics as messenger_analytics_routes,
|
|
@@ -101,6 +102,7 @@ app.include_router(analytics_routes.router)
|
|
|
101
102
|
app.include_router(sources_routes.router)
|
|
102
103
|
app.include_router(source_install_routes.router, prefix="/v1")
|
|
103
104
|
app.include_router(source_scrub_routes.router, prefix="/v1")
|
|
105
|
+
app.include_router(intelligence_lifecycle_routes.router, prefix="/v1")
|
|
104
106
|
app.include_router(app_registry_routes.router)
|
|
105
107
|
app.include_router(ingestion_compat_routes.router)
|
|
106
108
|
app.include_router(enrichment_routes.router, prefix="/v1")
|
|
@@ -100,6 +100,10 @@ class Settings(BaseSettings):
|
|
|
100
100
|
engine_ollama_base_url: str = Field("http://localhost:11434", env="ENGINE_OLLAMA_BASE_URL")
|
|
101
101
|
ollama_query_model: str = Field("llama3.2:latest", env="TOPOS_OLLAMA_QUERY_MODEL")
|
|
102
102
|
engine_default_provider: str = Field("huggingface", env="ENGINE_DEFAULT_PROVIDER")
|
|
103
|
+
# §D minimizer runs on EVERY grantee query, so it uses a small/fast local model. The judge
|
|
104
|
+
# only runs in nightly privacy evals (F.4/CER semantic scoring), so it can be larger/slower.
|
|
105
|
+
disclosure_minimizer_model: str = Field("llama3.2:latest", env="TOPOS_DISCLOSURE_MINIMIZER_MODEL")
|
|
106
|
+
privacy_judge_model: str = Field("qwen3.5:9b-mlx", env="TOPOS_PRIVACY_JUDGE_MODEL")
|
|
103
107
|
|
|
104
108
|
engine_max_resident_models: int = Field(3, env="ENGINE_MAX_RESIDENT_MODELS")
|
|
105
109
|
engine_model_idle_ttl_sec: int = Field(0, env="ENGINE_MODEL_IDLE_TTL_SEC")
|
|
@@ -319,6 +319,14 @@ class ControlPlaneClient:
|
|
|
319
319
|
return False
|
|
320
320
|
|
|
321
321
|
async def _handle_message(self, ws, data: Dict[str, Any]) -> None:
|
|
322
|
+
msg_type = str(data.get("type") or "").strip().lower()
|
|
323
|
+
if msg_type == "ping":
|
|
324
|
+
pong: Dict[str, Any] = {"type": "pong"}
|
|
325
|
+
ping_id = data.get("id")
|
|
326
|
+
if ping_id is not None:
|
|
327
|
+
pong["id"] = ping_id
|
|
328
|
+
await self._send_ws_json(ws, pong)
|
|
329
|
+
return
|
|
322
330
|
try:
|
|
323
331
|
resp = await self.handler(data)
|
|
324
332
|
except Exception as exc: # noqa: BLE001
|