topos-node 1.2.7__tar.gz → 1.3.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-1.2.7/topos_node.egg-info → topos_node-1.3.0}/PKG-INFO +1 -1
- {topos_node-1.2.7 → topos_node-1.3.0}/pyproject.toml +8 -2
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/__version__.py +2 -2
- topos_node-1.3.0/topos/api/conversation_context.py +142 -0
- topos_node-1.3.0/topos/api/facts_llm_config.py +63 -0
- topos_node-1.3.0/topos/api/local_mcp.py +119 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/signal.py +47 -1
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/app.py +4 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/browser_activity_mapper.py +8 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/cli/commands.py +4 -0
- topos_node-1.3.0/topos/config/conversation_context_llm.py +106 -0
- topos_node-1.3.0/topos/config/facts_llm.py +128 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/config/settings.py +6 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/config.py +134 -0
- topos_node-1.3.0/topos/core/handlers/query.py +175 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/signal_features.py +62 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/generative_prompts.py +34 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/generative_response.py +4 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/ollama.py +138 -1
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/usage_observation.py +2 -1
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/catalog.py +13 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/__init__.py +3 -0
- topos_node-1.3.0/topos/enrichment/jobs/canonical/attention_triage_job.py +66 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/dimension_summary_job.py +13 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/fact_extraction_job.py +5 -1
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/orchestrator.py +14 -3
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/declared_mappings.py +55 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/facts/extract.py +12 -2
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/facts/llm_extract.py +15 -10
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/facts/reads.py +1 -0
- topos_node-1.3.0/topos/features/facts/verdicts.py +209 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/fit/evaluator.py +58 -4
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/fit/opportunity_types.json +9 -0
- topos_node-1.3.0/topos/features/signal/conversation_context.py +145 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/intentions.json +40 -9
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/time.json +16 -4
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/extraction/artifact_router.py +21 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/extraction/rule_extractors.py +28 -2
- topos_node-1.3.0/topos/features/signal/typed_stores/aggregates.py +347 -0
- topos_node-1.3.0/topos/features/signal/typed_stores/commitments.py +136 -0
- topos_node-1.3.0/topos/features/signal/typed_stores/rhythm.py +171 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/typed_stores/scope_materializer.py +6 -0
- topos_node-1.3.0/topos/features/triage/__init__.py +4 -0
- topos_node-1.3.0/topos/features/triage/badges.py +223 -0
- topos_node-1.3.0/topos/features/triage/daily.py +609 -0
- topos_node-1.3.0/topos/features/triage/dashboard.py +80 -0
- topos_node-1.3.0/topos/features/triage/instruments.py +216 -0
- topos_node-1.3.0/topos/features/triage/intents.py +102 -0
- topos_node-1.3.0/topos/features/triage/readiness.py +58 -0
- topos_node-1.3.0/topos/protocol/handled_message_types.json +194 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/retrieval.py +172 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/scope_registry.json +36 -5
- topos_node-1.3.0/topos/query/truth_facts.py +74 -0
- topos_node-1.3.0/topos/query/truth_prompts.py +131 -0
- topos_node-1.3.0/topos/query/verify.py +388 -0
- topos_node-1.3.0/topos/query/verify_modes.py +147 -0
- topos_node-1.3.0/topos/runtime_housekeeping.py +117 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/bundled_canonical_triples.py +24 -5
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/canonical_signal_defaults.py +1 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/install_service.py +55 -1
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/__init__.py +23 -0
- topos_node-1.3.0/topos/storage/db/migrations/attention_triage_v1.py +60 -0
- topos_node-1.3.0/topos/storage/db/migrations/attention_triage_v2.py +44 -0
- topos_node-1.3.0/topos/storage/db/migrations/conversation_context_v1.py +52 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/upgrades/manifests.json +36 -0
- {topos_node-1.2.7 → topos_node-1.3.0/topos_node.egg-info}/PKG-INFO +1 -1
- {topos_node-1.2.7 → topos_node-1.3.0}/topos_node.egg-info/SOURCES.txt +24 -0
- topos_node-1.2.7/topos/api/local_mcp.py +0 -46
- topos_node-1.2.7/topos/core/handlers/query.py +0 -86
- topos_node-1.2.7/topos/features/signal/typed_stores/aggregates.py +0 -108
- topos_node-1.2.7/topos/protocol/handled_message_types.json +0 -181
- {topos_node-1.2.7 → topos_node-1.3.0}/LICENSE +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/MANIFEST.in +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/README.md +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/setup.cfg +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/shared/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/shared/filtering.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/shared/schema_registry.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/tests/test_extensions.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/tests/test_llm_integrations_storage.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/tests/test_protocol_handled_types.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/duckdb_adapter.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/messenger_communities.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/messenger_graph.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/messenger_labels.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/profiles.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/query_engine.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/analytics/raw_queries.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/analytics.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/app_registry.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/backup.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/compute_remote.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/data_commit.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/data_explorer_table_prefs.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/database_explorer.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/db.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/device.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/engine_run.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/enrichment.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/enrichment_lab.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/filter_lab.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/health.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/home_chat.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/ingestion_api.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/ingestion_compat.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/ingestion_sources.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/intelligence_lifecycle.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/llm.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/messenger_analytics.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/privacy_disclose.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/query_api.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/runtime_bootstrap.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/sanitization_ollama_config.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/signal_extraction_config.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/source_install.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/source_scrub.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/sources.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/sources_overview.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/sync.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/tool_index.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/ui_config.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/uma_data.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/upgrades.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/usage.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/api/user_identity.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/auth.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/base.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/chatgpt_mapper.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/demo_mappers.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/documents_mapper.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/github_activity_mapper.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/google_calendar_mapper.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/grok_mapper.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/messenger_mapper.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/models.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/resolver.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/cli/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/cli/__main__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/config/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/config/sanitization_ollama.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/config/signal_extraction.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/config/uvicorn_logging.json +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/contacts/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/contacts/identity.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/control_plane_client.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/api_models.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/connection_resilience.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/device_helpers.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/errors.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/events.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/common.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/contacts_import.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/database_explorer.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/device.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/enrichment.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/enrichment_lab.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/filter_lab.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/home_chat.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/ingest.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/messages.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/messenger_analytics.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/registry.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/routines.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/sources.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/tool_index.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/handlers/uma.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/logging.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/metrics.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/routine_access.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/startup_banner.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/state.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/table_layers.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/core/types.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/data_explorer_row_delete.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/data_explorer_table_prefs.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/data_explorer_tables.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/canonical_writer.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/content_policy.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/field_registry.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/privacy_layer.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/disclosure/tier.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/base.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/huggingface.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/openai.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/openai_compatible.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/redpill.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/backends/stub.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/client.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/engine.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/intake.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/memory_utils.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/model_cache.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/pipeline_memory.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/queue_manager.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/registration.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/result_formatter.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/router.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/scoped_token.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/tasks.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/transport.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/usage_guard.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/engine/validator.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/derived_tables.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/job_writer.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/base.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/_batch_limits.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/_engine_runner.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/availability_scores_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/brief_fallback.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/embeddings_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/emo_27_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/entities_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/goal_extraction_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/pii_redaction_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/relationship_edges_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/sentiment_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/statistics_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/timeline_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/topic_clusters_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/topics_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/url_classification_core.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/url_classification_enrichment_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/canonical/url_classification_signal_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/raw/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/raw/language_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/model_overrides.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/models/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/models/manager.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/models/mvp_defaults.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/models/registry.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/models/versioning.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/processor.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/progress_bar.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/registry_contract.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/signal_derivation_config.json +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/source_overrides.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment/website_classifier.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/bundles.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/model_resolve.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/schema.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/service.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/enrichment_lab/worker.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/evals/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/evals/enrichment_eval.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/extensions.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/consolidation.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/dossier.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/edges.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/fact_materializer.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/graph_enrichers.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/graph_refresh.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/graph_search.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/linking.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/maintenance.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/reads.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/entities/resolver.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/facts/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/facts/store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/lifecycle/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/lifecycle/derived_scrub.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/lifecycle/exclusions.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/lifecycle/gc.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/provenance/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/provenance/posture.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/provenance/roles.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/brief_canonical_loader.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/brief_ontology.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/brief_renderer.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/brief_schemas.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/chunking.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/cluster_labels.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/data_health.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/brief_ontologies.json +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/profile.json +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/relationships.json +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/schema/dimension_definition.schema.json +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/definitions/work.json +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/dimension_briefs.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/dimension_definition_loader.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/dimension_profiles.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/dimension_registry.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/embed_context.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/extraction/artifact_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/graph_sanitize.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/hybrid_search.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/incremental_clustering.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/model_recommendations.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/query_embed_cache.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/schemas.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/service.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/signal_object_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/source_hydration.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/structured_signal.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/tool_index.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/topic_clustering.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/vector_codec.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/vector_math.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/signal/vector_settings.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/stats/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/stats/definitions.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/stats/engine.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/stats/fold.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/stats/insights.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/features/timeline_projection.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/bundles.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/schema.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/service.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/filter_lab/worker.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/home_chat/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/home_chat/schema.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/home_chat/store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/hosted_pool_lease.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/canonical_pipeline.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/checkpoints/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/inbox_crypto.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/inbox_drain.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/ingest_helpers.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/jobs.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/journal_location_fanout.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/journal_time_log_normalize.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/local_sync.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/log_preview.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/manager.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/base.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/browser_parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/calendar_parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/demo_file_parsers.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/documents_parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/github_activity_parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/google_calendar_parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/grok_parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/messenger_parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/parsers/voxterm_parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/progress.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/reprocess.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/base.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/calendar.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/chatgpt.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/contact_importers.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/grok.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/imessage_reader.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/signal_export_parser.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/sources/signal_reader.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/state_machine.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/triggers/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/triggers/file_trigger.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/usage_inbox_dedupe.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/validation/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/validation/base.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/validation/schema_registry.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/ingestion/validation/schema_validator.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/lineage/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/lineage/provenance.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/lineage/tracker.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/llm_integrations_storage.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/mcp_stdio_proxy.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/observability/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/observability/alerts.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/observability/metrics.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/observability/tracing.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/openai_client.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/audit.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/envelope.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/job_runner.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/job_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/stages.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/pipeline/stub_enqueue.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/projections/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/projections/vector_index/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/projections/vector_index/base.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/projections/vector_index/builders.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/projections/vector_index/health_checks.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/protocol/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/audit.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/ddr.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/disclosure.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/fingerprint.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/game_layer.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/grant_cache.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/inference.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/intent.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/manifest.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/manifest_validation.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/minimizer.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/negotiation.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/pipeline.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/planner.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/runtime.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/scope_registry_loader.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/session.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/session_utils.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/source_generation.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/turn_classifier.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/query/types.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/rate_limit.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/routines/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/routines/schema.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/routines/store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/runtime_shutdown.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/runtime_update.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sanitization/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sanitization/nsfw_classifier.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sanitization/ollama_transforms.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sanitization/prewarm.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sanitization/privacy_filter.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/scope_resolution.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/container.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/embeddings/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/embeddings/base.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/embeddings/local.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/embeddings/remote.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/interfaces.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/llm/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/llm/base.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/llm/openai.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/local.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/services/postgres.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/definitions.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/registry.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/runtime_install.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/scrub_attribution.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sources/scrub_service.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/startup_banner.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/factory.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/fakes.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/postgres/stores.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/protocols.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/sqlite/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/sqlite/stores.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/adapters/sqlite/vector_search.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/activity_tables.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/ai_chat/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/ai_chat/canonicalizer.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/ai_chat/mapper.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/ai_chat/model.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/ai_chat/tables.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/calendar_contacts_tables.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/canonical_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/conversations_tables.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/mapping_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/canonical/postgres.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/client.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/connection_tuning.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/activity_events_content_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/actor_role_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/calendar_events_scheduling_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/canonical_address_book_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/canonical_disclosure_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/canonical_nsfw_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/derivation_ledger_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/documents_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/entity_edges_validity_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/episodes_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/extraction_artifacts.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/journal_entries_duration_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/journal_entries_ends_at_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/journal_entries_people_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/journal_entries_place_name_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/journal_entries_starts_at_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/pipeline_jobs_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/remediation_person_model.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/scope_source_generation.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/signal_dimension_backfill_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/signal_dimension_harness.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/signal_objects.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/signal_objects_period_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/signal_objects_updated_by_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/vector_storage_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/vector_storage_v2.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/vector_storage_v3.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/vector_storage_v4.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_clusters_v2.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_entities_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_entity_review_v2.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_facts_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_lifecycle_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_phase0.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_phase1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_query_quality.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_stats_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/migrations/wiki_timeline_v1.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/paths.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/postgres.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/schema.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/storage_breakdown.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/db/write_gate.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/enrichment/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/normalized/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/normalized/normalized_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/oplog/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/oplog/decision.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/oplog/oplog_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/oplog/postgres.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/person/identity_resolver.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/projections/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/projections/index_ops_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/projections/vector_index_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/browser_flat_tables.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/file_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/raw_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/raw_tables_manager.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/raw/sqlite_raw_store.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/security/encryption.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/signal_identity.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/source_settings.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/storage/user_identity.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sync/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sync/client.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/sync_handlers.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/testing/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/testing/lifespan.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/uma_contact_enrichment.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/uma_filters.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/uma_resource_id.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/uma_rpt.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/upgrades/__init__.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/upgrades/runner.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/utils/base_object.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos/websocket_client.py +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos_node.egg-info/dependency_links.txt +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos_node.egg-info/entry_points.txt +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/topos_node.egg-info/requires.txt +0 -0
- {topos_node-1.2.7 → topos_node-1.3.0}/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.
|
|
7
|
+
version = "1.3.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"
|
|
@@ -84,6 +84,12 @@ where = ["."]
|
|
|
84
84
|
include = ["topos*", "shared*"]
|
|
85
85
|
|
|
86
86
|
[tool.pytest.ini_options]
|
|
87
|
+
# tmp_path hygiene: this suite's fixtures build whole node DBs (100s of MB per
|
|
88
|
+
# run). Keep only the last run's FAILED dirs — passed dirs are removed as tests
|
|
89
|
+
# finish, so tmp never accumulates across runs. Killed runs can still leave
|
|
90
|
+
# locked roots behind; topos.runtime_housekeeping sweeps those on node start.
|
|
91
|
+
tmp_path_retention_count = 1
|
|
92
|
+
tmp_path_retention_policy = "failed"
|
|
87
93
|
filterwarnings = [
|
|
88
94
|
"ignore::DeprecationWarning:pydantic.*",
|
|
89
95
|
"ignore:on_event is deprecated.*:DeprecationWarning:fastapi.*",
|
|
@@ -106,5 +112,5 @@ markers = [
|
|
|
106
112
|
"eval_nightly: statistical privacy eval (attacker advantage, minimality, latency); nightly",
|
|
107
113
|
"eval_release: release-tier privacy eval (negotiation A/B, Pareto); run per release",
|
|
108
114
|
]
|
|
109
|
-
pythonpath = ["tests/gap/p3/engine", "tests/gap/p4/engine", "tests/gap/qq/engine", "tests/acceptance/wiki_mvp"]
|
|
115
|
+
pythonpath = ["tests/gap/p3/engine", "tests/gap/p4/engine", "tests/gap/qq/engine", "tests/acceptance/wiki_mvp", "tests/evals/time_signal"]
|
|
110
116
|
testpaths = ["tests"]
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""Owner-set conversation context tag (work | personal).
|
|
2
|
+
|
|
3
|
+
Second labeling axis alongside source posture: posture says whose words the
|
|
4
|
+
content is; context_tag says which life domain the thread belongs to. Set at
|
|
5
|
+
the conversation level (the thread in `conversations`); every message in the
|
|
6
|
+
thread inherits it at read/derivation time. Owner-only; never inferred here.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from fastapi import APIRouter, Body, Depends, HTTPException
|
|
12
|
+
|
|
13
|
+
from ..auth import require_api_key
|
|
14
|
+
from ..core.state import get_db_connection
|
|
15
|
+
from ..storage.db.migrations.conversation_context_v1 import CONTEXT_TAG_VALUES
|
|
16
|
+
|
|
17
|
+
router = APIRouter()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _conversation_row(conn, conversation_id: str, dataset_id: str):
|
|
21
|
+
return conn.execute(
|
|
22
|
+
"SELECT conversation_id, dataset_id, context_tag, context_tag_source "
|
|
23
|
+
"FROM conversations WHERE conversation_id=? AND dataset_id=?",
|
|
24
|
+
(conversation_id, dataset_id),
|
|
25
|
+
).fetchone()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def read_conversation_context(conn, conversation_id: str, dataset_id: str) -> dict | None:
|
|
29
|
+
"""Context-tag payload for a conversation, or None when it is unknown.
|
|
30
|
+
|
|
31
|
+
Shared by the HTTP endpoint below and the WS handler
|
|
32
|
+
(core.handlers.config get_conversation_context) so both stay one source.
|
|
33
|
+
"""
|
|
34
|
+
row = _conversation_row(conn, conversation_id, dataset_id)
|
|
35
|
+
if row is None:
|
|
36
|
+
return None
|
|
37
|
+
return {
|
|
38
|
+
"status": "ok",
|
|
39
|
+
"conversation_id": row[0],
|
|
40
|
+
"dataset_id": row[1],
|
|
41
|
+
"context_tag": row[2],
|
|
42
|
+
"context_tag_source": row[3],
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def write_conversation_context(conn, conversation_id: str, dataset_id: str, raw_tag) -> dict:
|
|
47
|
+
"""Owner set/clear of the context tag.
|
|
48
|
+
|
|
49
|
+
Raises ValueError on an invalid tag, LookupError when the conversation is
|
|
50
|
+
unknown. Shared by the HTTP endpoint and the WS handler.
|
|
51
|
+
"""
|
|
52
|
+
tag = str(raw_tag).strip().lower() if raw_tag is not None else None
|
|
53
|
+
if tag is not None and tag not in CONTEXT_TAG_VALUES:
|
|
54
|
+
raise ValueError(f"context_tag must be one of {sorted(CONTEXT_TAG_VALUES)} or null")
|
|
55
|
+
if _conversation_row(conn, conversation_id, dataset_id) is None:
|
|
56
|
+
raise LookupError("Unknown conversation")
|
|
57
|
+
# Owner decisions always win: stamped 'owner' even when clearing, so the
|
|
58
|
+
# auto-classifier never refills a conversation the owner chose to untag.
|
|
59
|
+
conn.execute(
|
|
60
|
+
"UPDATE conversations SET context_tag=?, context_tag_source='owner', "
|
|
61
|
+
"updated_at=datetime('now') WHERE conversation_id=? AND dataset_id=?",
|
|
62
|
+
(tag, conversation_id, dataset_id),
|
|
63
|
+
)
|
|
64
|
+
conn.commit()
|
|
65
|
+
return {
|
|
66
|
+
"status": "ok",
|
|
67
|
+
"conversation_id": conversation_id,
|
|
68
|
+
"dataset_id": dataset_id,
|
|
69
|
+
"context_tag": tag,
|
|
70
|
+
"context_tag_source": "owner",
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@router.get(
|
|
75
|
+
"/conversations/{conversation_id}/context",
|
|
76
|
+
dependencies=[Depends(require_api_key)],
|
|
77
|
+
)
|
|
78
|
+
async def get_conversation_context(conversation_id: str, dataset_id: str) -> dict:
|
|
79
|
+
conn = get_db_connection()
|
|
80
|
+
if conn is None:
|
|
81
|
+
raise HTTPException(status_code=503, detail="Database not available")
|
|
82
|
+
data = read_conversation_context(conn, conversation_id, dataset_id)
|
|
83
|
+
if data is None:
|
|
84
|
+
raise HTTPException(status_code=404, detail="Unknown conversation")
|
|
85
|
+
return data
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@router.put(
|
|
89
|
+
"/conversations/{conversation_id}/context",
|
|
90
|
+
dependencies=[Depends(require_api_key)],
|
|
91
|
+
)
|
|
92
|
+
async def set_conversation_context(
|
|
93
|
+
conversation_id: str,
|
|
94
|
+
payload: dict = Body(default_factory=dict),
|
|
95
|
+
) -> dict:
|
|
96
|
+
dataset_id = str(payload.get("dataset_id") or "").strip()
|
|
97
|
+
if not dataset_id:
|
|
98
|
+
raise HTTPException(status_code=422, detail="dataset_id is required")
|
|
99
|
+
conn = get_db_connection()
|
|
100
|
+
if conn is None:
|
|
101
|
+
raise HTTPException(status_code=503, detail="Database not available")
|
|
102
|
+
try:
|
|
103
|
+
return write_conversation_context(conn, conversation_id, dataset_id, payload.get("context_tag"))
|
|
104
|
+
except ValueError as exc:
|
|
105
|
+
raise HTTPException(status_code=422, detail=str(exc)) from exc
|
|
106
|
+
except LookupError as exc:
|
|
107
|
+
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# --- classifier model config (settings surface) -----------------------------------
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@router.get("/conversation-context-llm-config", dependencies=[Depends(require_api_key)])
|
|
114
|
+
async def get_context_llm_config() -> dict:
|
|
115
|
+
from ..config.conversation_context_llm import effective_config_for_api
|
|
116
|
+
from ..config.settings import settings
|
|
117
|
+
|
|
118
|
+
conn = get_db_connection()
|
|
119
|
+
if conn is None:
|
|
120
|
+
raise HTTPException(status_code=503, detail="Database not available")
|
|
121
|
+
return {"status": "ok", **effective_config_for_api(settings, conn)}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@router.put("/conversation-context-llm-config", dependencies=[Depends(require_api_key)])
|
|
125
|
+
async def put_context_llm_config(payload: dict = Body(default=None)) -> dict:
|
|
126
|
+
from ..config.conversation_context_llm import (
|
|
127
|
+
ENGINE_CONFIG_KEY_CONVERSATION_CONTEXT_LLM_MODEL,
|
|
128
|
+
effective_config_for_api,
|
|
129
|
+
normalize_put_model,
|
|
130
|
+
)
|
|
131
|
+
from ..config.settings import settings
|
|
132
|
+
from ..core.state import set_engine_config_value
|
|
133
|
+
|
|
134
|
+
conn = get_db_connection()
|
|
135
|
+
if conn is None:
|
|
136
|
+
raise HTTPException(status_code=503, detail="Database not available")
|
|
137
|
+
try:
|
|
138
|
+
model = normalize_put_model(payload)
|
|
139
|
+
except ValueError as exc:
|
|
140
|
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
141
|
+
set_engine_config_value(conn, ENGINE_CONFIG_KEY_CONVERSATION_CONTEXT_LLM_MODEL, model)
|
|
142
|
+
return {"status": "ok", **effective_config_for_api(settings, conn)}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Read/update the owner-selected facts-LLM extraction model (engine_config)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from fastapi import APIRouter, Body, Depends, HTTPException
|
|
9
|
+
|
|
10
|
+
from ..auth import require_api_key
|
|
11
|
+
from ..config.facts_llm import (
|
|
12
|
+
ENGINE_CONFIG_KEY_FACTS_LLM_MODEL,
|
|
13
|
+
effective_config_for_api,
|
|
14
|
+
normalize_put_model,
|
|
15
|
+
)
|
|
16
|
+
from ..config.settings import settings
|
|
17
|
+
from ..core.state import get_db_connection, set_engine_config_value
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger("topos.api.facts_llm_config")
|
|
20
|
+
|
|
21
|
+
router = APIRouter(tags=["facts-llm"])
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@router.get("/v1/facts-llm-config", dependencies=[Depends(require_api_key)])
|
|
25
|
+
async def get_facts_llm_config() -> dict[str, Any]:
|
|
26
|
+
conn = get_db_connection()
|
|
27
|
+
if not conn:
|
|
28
|
+
raise HTTPException(status_code=503, detail="Database not available")
|
|
29
|
+
try:
|
|
30
|
+
return {"status": "ok", **effective_config_for_api(settings, conn)}
|
|
31
|
+
except Exception as exc: # noqa: BLE001
|
|
32
|
+
logger.warning("get_facts_llm_config failed: %s", exc)
|
|
33
|
+
raise HTTPException(status_code=500, detail="Failed to read config") from exc
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@router.put("/v1/facts-llm-config", dependencies=[Depends(require_api_key)])
|
|
37
|
+
async def put_facts_llm_config(body: dict[str, Any] = Body(default=None)) -> dict[str, Any]:
|
|
38
|
+
conn = get_db_connection()
|
|
39
|
+
if not conn:
|
|
40
|
+
raise HTTPException(status_code=503, detail="Database not available")
|
|
41
|
+
try:
|
|
42
|
+
model = normalize_put_model(body)
|
|
43
|
+
set_engine_config_value(conn, ENGINE_CONFIG_KEY_FACTS_LLM_MODEL, model)
|
|
44
|
+
return {"status": "ok", **effective_config_for_api(settings, conn)}
|
|
45
|
+
except ValueError as exc:
|
|
46
|
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
47
|
+
except Exception as exc: # noqa: BLE001
|
|
48
|
+
logger.warning("put_facts_llm_config failed: %s", exc)
|
|
49
|
+
raise HTTPException(status_code=500, detail="Failed to save config") from exc
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@router.delete("/v1/facts-llm-config", dependencies=[Depends(require_api_key)])
|
|
53
|
+
async def delete_facts_llm_model_override() -> dict[str, Any]:
|
|
54
|
+
"""Clear the device override; the effective model reverts to env defaults."""
|
|
55
|
+
conn = get_db_connection()
|
|
56
|
+
if not conn:
|
|
57
|
+
raise HTTPException(status_code=503, detail="Database not available")
|
|
58
|
+
try:
|
|
59
|
+
set_engine_config_value(conn, ENGINE_CONFIG_KEY_FACTS_LLM_MODEL, "")
|
|
60
|
+
return {"status": "ok", **effective_config_for_api(settings, conn)}
|
|
61
|
+
except Exception as exc: # noqa: BLE001
|
|
62
|
+
logger.warning("delete facts_llm model override failed: %s", exc)
|
|
63
|
+
raise HTTPException(status_code=500, detail="Failed to clear config") from exc
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Local API for MCP-style tools (no Control Plane). Same auth as engine; for same-device/offline use."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
from fastapi import APIRouter, Body, Depends
|
|
8
|
+
|
|
9
|
+
from ..auth import require_api_key
|
|
10
|
+
from ..core.handlers import handle_control_plane_request
|
|
11
|
+
|
|
12
|
+
router = APIRouter(prefix="/api/local", tags=["local-mcp"])
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _local_mcp_payload(extra: dict | None = None) -> dict:
|
|
16
|
+
"""Payload for local MCP requests; source=claude_desktop so engine counts per source."""
|
|
17
|
+
p = {"mcp_source": "claude_desktop"}
|
|
18
|
+
if extra:
|
|
19
|
+
p.update(extra)
|
|
20
|
+
return p
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@router.post("/list_database_tables")
|
|
24
|
+
async def local_list_database_tables(_: None = Depends(require_api_key)) -> dict: # noqa: B008
|
|
25
|
+
"""List tables (same as CP-forwarded tool). Requires Bearer TOPOS_KEY."""
|
|
26
|
+
msg = {"id": str(uuid.uuid4()), "type": "list_database_tables", "payload": _local_mcp_payload()}
|
|
27
|
+
out = await handle_control_plane_request(msg)
|
|
28
|
+
if out.get("status") == "error":
|
|
29
|
+
return {"status": "error", "error": out.get("error", "unknown")}
|
|
30
|
+
return out.get("payload", {})
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@router.post("/verify_claim")
|
|
34
|
+
async def local_verify_claim(
|
|
35
|
+
body: dict = Body(default_factory=dict),
|
|
36
|
+
_: None = Depends(require_api_key), # noqa: B008
|
|
37
|
+
) -> dict:
|
|
38
|
+
"""Same-device truth check (PLAN_TRUTHFULNESS_PLUGIN.md). Owner-key only;
|
|
39
|
+
mirrors the CP door: `app_id` is mandatory and `mode` is pinned to fun —
|
|
40
|
+
this route cannot reach a mode the registry doesn't ship. Body:
|
|
41
|
+
{"statement": "...", "app_id": "truth-mirror"}."""
|
|
42
|
+
statement = str(body.get("statement") or "").strip()
|
|
43
|
+
app_id = str(body.get("app_id") or "").strip()
|
|
44
|
+
if not statement or not app_id:
|
|
45
|
+
return {"status": "error", "error": "statement and app_id required"}
|
|
46
|
+
msg = {
|
|
47
|
+
"id": str(uuid.uuid4()),
|
|
48
|
+
"type": "verify_claim",
|
|
49
|
+
"payload": {"statement": statement, "mode": "fun", "caller_app_id": app_id},
|
|
50
|
+
}
|
|
51
|
+
out = await handle_control_plane_request(msg)
|
|
52
|
+
if out.get("status") == "error":
|
|
53
|
+
return {"status": "error", "error": out.get("error", "unknown")}
|
|
54
|
+
return out.get("payload", {})
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@router.post("/truth_prompts")
|
|
58
|
+
async def local_truth_prompts(
|
|
59
|
+
body: dict = Body(default_factory=dict),
|
|
60
|
+
_: None = Depends(require_api_key), # noqa: B008
|
|
61
|
+
) -> dict:
|
|
62
|
+
"""Same-device "ask me" prompt seeds (fun aperture; topics only, no
|
|
63
|
+
stances). Body: {"app_id": "truth-mirror", "limit": 5}."""
|
|
64
|
+
app_id = str(body.get("app_id") or "").strip()
|
|
65
|
+
if not app_id:
|
|
66
|
+
return {"status": "error", "error": "app_id required"}
|
|
67
|
+
msg = {
|
|
68
|
+
"id": str(uuid.uuid4()),
|
|
69
|
+
"type": "truth_prompts",
|
|
70
|
+
"payload": {"mode": "fun", "caller_app_id": app_id,
|
|
71
|
+
"limit": int(body.get("limit") or 5)},
|
|
72
|
+
}
|
|
73
|
+
out = await handle_control_plane_request(msg)
|
|
74
|
+
if out.get("status") == "error":
|
|
75
|
+
return {"status": "error", "error": out.get("error", "unknown")}
|
|
76
|
+
return out.get("payload", {})
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@router.post("/truth_seed_fact")
|
|
80
|
+
async def local_truth_seed_fact(
|
|
81
|
+
body: dict = Body(default_factory=dict),
|
|
82
|
+
_: None = Depends(require_api_key), # noqa: B008
|
|
83
|
+
) -> dict:
|
|
84
|
+
"""Owner adds a fun fact to their own sheet (refused outside the fun
|
|
85
|
+
aperture). Body: {"predicate": "favorite_food", "value": "tacos",
|
|
86
|
+
"app_id": "truth-mirror"}."""
|
|
87
|
+
app_id = str(body.get("app_id") or "").strip()
|
|
88
|
+
if not app_id:
|
|
89
|
+
return {"status": "error", "error": "app_id required"}
|
|
90
|
+
msg = {
|
|
91
|
+
"id": str(uuid.uuid4()),
|
|
92
|
+
"type": "truth_seed_fact",
|
|
93
|
+
"payload": {
|
|
94
|
+
"mode": "fun",
|
|
95
|
+
"caller_app_id": app_id,
|
|
96
|
+
"predicate": str(body.get("predicate") or ""),
|
|
97
|
+
"value": str(body.get("value") or ""),
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
out = await handle_control_plane_request(msg)
|
|
101
|
+
if out.get("status") == "error":
|
|
102
|
+
return {"status": "error", "error": out.get("error", "unknown")}
|
|
103
|
+
return out.get("payload", {})
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@router.post("/get_table_schema")
|
|
107
|
+
async def local_get_table_schema(
|
|
108
|
+
body: dict = Body(default_factory=dict),
|
|
109
|
+
_: None = Depends(require_api_key), # noqa: B008
|
|
110
|
+
) -> dict:
|
|
111
|
+
"""Get table schema (same as CP-forwarded tool). Body: {"table_name": "..."}. Requires Bearer TOPOS_KEY."""
|
|
112
|
+
table_name = (body.get("table_name") or "").strip()
|
|
113
|
+
if not table_name:
|
|
114
|
+
return {"status": "error", "error": "table_name required"}
|
|
115
|
+
msg = {"id": str(uuid.uuid4()), "type": "get_table_schema", "payload": _local_mcp_payload({"table_name": table_name})}
|
|
116
|
+
out = await handle_control_plane_request(msg)
|
|
117
|
+
if out.get("status") == "error":
|
|
118
|
+
return {"status": "error", "error": out.get("error", "unknown")}
|
|
119
|
+
return out.get("payload", {})
|
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import logging
|
|
6
6
|
from typing import Any, Dict, Optional
|
|
7
7
|
|
|
8
|
-
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
8
|
+
from fastapi import APIRouter, Body, Depends, HTTPException, Query
|
|
9
9
|
from pydantic import BaseModel, Field
|
|
10
10
|
|
|
11
11
|
from ..auth import require_api_key
|
|
@@ -480,6 +480,34 @@ async def list_facts(
|
|
|
480
480
|
)
|
|
481
481
|
|
|
482
482
|
|
|
483
|
+
@router.post("/facts/verdict")
|
|
484
|
+
async def post_fact_verdict(
|
|
485
|
+
object_id: str = Body(...),
|
|
486
|
+
action: str = Body(..., description="confirm | reject | edit"),
|
|
487
|
+
object_value: Optional[str] = Body(default=None),
|
|
488
|
+
asserted_by: Optional[str] = Body(default=None),
|
|
489
|
+
note: Optional[str] = Body(default=None),
|
|
490
|
+
_api_key: str = Depends(require_api_key),
|
|
491
|
+
):
|
|
492
|
+
"""Owner verdict on one fact: confirm (attest true), reject (close +
|
|
493
|
+
tombstone this value), or edit (correct the value and/or attribution)."""
|
|
494
|
+
from ..features.facts.verdicts import apply_fact_verdict
|
|
495
|
+
|
|
496
|
+
try:
|
|
497
|
+
return apply_fact_verdict(
|
|
498
|
+
_entities_conn(),
|
|
499
|
+
object_id=object_id,
|
|
500
|
+
action=action,
|
|
501
|
+
object_value=object_value,
|
|
502
|
+
asserted_by=asserted_by,
|
|
503
|
+
note=note,
|
|
504
|
+
)
|
|
505
|
+
except LookupError as exc:
|
|
506
|
+
raise HTTPException(status_code=404, detail=str(exc))
|
|
507
|
+
except ValueError as exc:
|
|
508
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
509
|
+
|
|
510
|
+
|
|
483
511
|
@router.get("/insights")
|
|
484
512
|
async def list_stat_insights(
|
|
485
513
|
dimension: Optional[str] = Query(default=None, max_length=40),
|
|
@@ -623,3 +651,21 @@ async def refresh_dimension_brief(
|
|
|
623
651
|
return await service.refresh_brief(dimension, limit=limit)
|
|
624
652
|
except ValueError as exc:
|
|
625
653
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
# --------------------------------------------------------------- attention triage
|
|
657
|
+
|
|
658
|
+
@router.get("/attention/dashboard")
|
|
659
|
+
async def attention_dashboard(
|
|
660
|
+
_api_key: str = Depends(require_api_key),
|
|
661
|
+
days: int = Query(14, ge=1, le=90),
|
|
662
|
+
include_titles: bool = Query(True),
|
|
663
|
+
):
|
|
664
|
+
"""Data spine for the /data/attention tab (PLAN_ATTENTION_ANALYTICS_EXECUTION WS5.1)."""
|
|
665
|
+
from ..core.state import get_db_connection
|
|
666
|
+
from ..features.triage.dashboard import attention_dashboard_data
|
|
667
|
+
|
|
668
|
+
conn = get_db_connection()
|
|
669
|
+
if conn is None:
|
|
670
|
+
raise HTTPException(status_code=503, detail="database unavailable")
|
|
671
|
+
return attention_dashboard_data(conn, days=days, include_titles=include_titles)
|
|
@@ -15,6 +15,7 @@ from .api import (
|
|
|
15
15
|
app_registry as app_registry_routes,
|
|
16
16
|
backup as backup_routes,
|
|
17
17
|
compute_remote as compute_remote_routes,
|
|
18
|
+
conversation_context as conversation_context_routes,
|
|
18
19
|
engine_run as engine_run_routes,
|
|
19
20
|
data_commit as data_commit_routes,
|
|
20
21
|
db as db_routes,
|
|
@@ -39,6 +40,7 @@ from .api import (
|
|
|
39
40
|
ui_config as ui_config_routes,
|
|
40
41
|
data_explorer_table_prefs as data_explorer_table_prefs_routes,
|
|
41
42
|
sanitization_ollama_config as sanitization_ollama_config_routes,
|
|
43
|
+
facts_llm_config as facts_llm_config_routes,
|
|
42
44
|
signal_extraction_config as signal_extraction_config_routes,
|
|
43
45
|
filter_lab as filter_lab_routes,
|
|
44
46
|
enrichment_lab as enrichment_lab_routes,
|
|
@@ -106,6 +108,7 @@ app.include_router(device_routes.router)
|
|
|
106
108
|
app.include_router(backup_routes.router)
|
|
107
109
|
app.include_router(analytics_routes.router)
|
|
108
110
|
app.include_router(sources_routes.router)
|
|
111
|
+
app.include_router(conversation_context_routes.router, prefix="/v1")
|
|
109
112
|
app.include_router(source_install_routes.router, prefix="/v1")
|
|
110
113
|
app.include_router(source_scrub_routes.router, prefix="/v1")
|
|
111
114
|
app.include_router(intelligence_lifecycle_routes.router, prefix="/v1")
|
|
@@ -123,6 +126,7 @@ app.include_router(ui_config_routes.router)
|
|
|
123
126
|
app.include_router(data_explorer_table_prefs_routes.router)
|
|
124
127
|
app.include_router(user_identity_routes.router)
|
|
125
128
|
app.include_router(sanitization_ollama_config_routes.router)
|
|
129
|
+
app.include_router(facts_llm_config_routes.router)
|
|
126
130
|
app.include_router(signal_extraction_config_routes.router)
|
|
127
131
|
app.include_router(filter_lab_routes.router)
|
|
128
132
|
app.include_router(enrichment_lab_routes.router)
|
{topos_node-1.2.7 → topos_node-1.3.0}/topos/canonicalization/mappers/browser_activity_mapper.py
RENAMED
|
@@ -24,6 +24,7 @@ from __future__ import annotations
|
|
|
24
24
|
import json
|
|
25
25
|
from dataclasses import dataclass
|
|
26
26
|
from typing import Any, Optional
|
|
27
|
+
from urllib.parse import urlparse
|
|
27
28
|
|
|
28
29
|
from ...ingestion.parsers.base import NormalizedRecord
|
|
29
30
|
from .base import CanonicalMapper, CanonicalRecord, MappingMetadata
|
|
@@ -77,6 +78,13 @@ class BrowserActivityCanonicalMapper(CanonicalMapper):
|
|
|
77
78
|
"schema": payload.get("schema") or payload.get("schema_id"),
|
|
78
79
|
}
|
|
79
80
|
hostname = payload.get("hostname")
|
|
81
|
+
if not hostname and payload.get("url"):
|
|
82
|
+
# BT6 (PLAN_ATTENTION_TRIAGE.md): some plugin batches send url
|
|
83
|
+
# without hostname; derive it so downstream vocab never goes empty.
|
|
84
|
+
try:
|
|
85
|
+
hostname = urlparse(str(payload.get("url"))).hostname
|
|
86
|
+
except ValueError:
|
|
87
|
+
hostname = None
|
|
80
88
|
if hostname:
|
|
81
89
|
metadata["hostname"] = hostname
|
|
82
90
|
|
|
@@ -230,6 +230,10 @@ def main(db_path, topos_key, set_topos_key, discover, port, host, skip_update_ch
|
|
|
230
230
|
os.environ["TOPOS_DATABASE_PATH"] = db_path
|
|
231
231
|
click.echo(f"Database path: {db_path}")
|
|
232
232
|
|
|
233
|
+
from topos.runtime_housekeeping import start_background_housekeeping
|
|
234
|
+
|
|
235
|
+
start_background_housekeeping()
|
|
236
|
+
|
|
233
237
|
_emit_startup_banner(host=host, port=port)
|
|
234
238
|
uvicorn.run(app, host=host, port=port, log_config=get_uvicorn_log_config())
|
|
235
239
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Conversation-context classifier model: env default + per-node device override.
|
|
2
|
+
|
|
3
|
+
The owner picks which local model auto-categorizes new conversations as
|
|
4
|
+
work/personal (features.signal.conversation_context). Resolution order, first
|
|
5
|
+
non-empty wins — same contract as facts_llm:
|
|
6
|
+
|
|
7
|
+
1. engine_config["conversation_context_llm_model"] — device override the UI
|
|
8
|
+
writes; takes effect on the next enrichment batch, no restart needed.
|
|
9
|
+
2. Settings.ollama_extraction_model — the ingest-time extraction tier.
|
|
10
|
+
3. Settings.ollama_query_model — the floor tier.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
import sqlite3
|
|
17
|
+
from typing import Any, Dict, Optional
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger("topos.config.conversation_context_llm")
|
|
20
|
+
|
|
21
|
+
ENGINE_CONFIG_KEY_CONVERSATION_CONTEXT_LLM_MODEL = "conversation_context_llm_model"
|
|
22
|
+
|
|
23
|
+
_MAX_MODEL_NAME_LEN = 200
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _read_engine_config_value(conn: Optional[sqlite3.Connection], key: str) -> Optional[str]:
|
|
27
|
+
if conn is None:
|
|
28
|
+
return None
|
|
29
|
+
try:
|
|
30
|
+
row = conn.execute("SELECT value FROM engine_config WHERE key = ?", (key,)).fetchone()
|
|
31
|
+
if not row:
|
|
32
|
+
return None
|
|
33
|
+
try:
|
|
34
|
+
return str(row["value"]) # sqlite3.Row
|
|
35
|
+
except (TypeError, IndexError, KeyError):
|
|
36
|
+
return str(row[0])
|
|
37
|
+
except Exception: # noqa: BLE001 — missing table/row on fresh DB is not fatal
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def device_context_llm_model(conn: Optional[sqlite3.Connection]) -> str:
|
|
42
|
+
raw = _read_engine_config_value(conn, ENGINE_CONFIG_KEY_CONVERSATION_CONTEXT_LLM_MODEL)
|
|
43
|
+
return str(raw or "").strip()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def resolve_context_llm_model(settings: Any, conn: Optional[sqlite3.Connection] = None) -> str:
|
|
47
|
+
override = device_context_llm_model(conn)
|
|
48
|
+
if override:
|
|
49
|
+
return override
|
|
50
|
+
for attr in ("ollama_extraction_model", "ollama_query_model"):
|
|
51
|
+
value = str(getattr(settings, attr, "") or "").strip()
|
|
52
|
+
if value:
|
|
53
|
+
return value
|
|
54
|
+
return ""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def normalize_put_model(payload: Any) -> str:
|
|
58
|
+
"""{"model": "<name>"} or bare string → stored value; empty clears."""
|
|
59
|
+
if payload is None:
|
|
60
|
+
return ""
|
|
61
|
+
if isinstance(payload, str):
|
|
62
|
+
model = payload
|
|
63
|
+
elif isinstance(payload, dict):
|
|
64
|
+
model = payload.get("model") or ""
|
|
65
|
+
else:
|
|
66
|
+
raise ValueError("body must be a JSON object with a 'model' string")
|
|
67
|
+
model = str(model).strip()
|
|
68
|
+
if len(model) > _MAX_MODEL_NAME_LEN:
|
|
69
|
+
raise ValueError(f"model name too long (max {_MAX_MODEL_NAME_LEN} chars)")
|
|
70
|
+
if model and any(ch in model for ch in " \t\n\r"):
|
|
71
|
+
raise ValueError("model name must not contain whitespace")
|
|
72
|
+
return model
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def effective_config_for_api(settings: Any, conn: Optional[sqlite3.Connection]) -> Dict[str, Any]:
|
|
76
|
+
"""Resolved classifier model + local model catalog for the settings picker."""
|
|
77
|
+
override = device_context_llm_model(conn)
|
|
78
|
+
effective = resolve_context_llm_model(settings, conn)
|
|
79
|
+
if override:
|
|
80
|
+
source = "device_override"
|
|
81
|
+
elif str(getattr(settings, "ollama_extraction_model", "") or "").strip():
|
|
82
|
+
source = "extraction_model_default"
|
|
83
|
+
else:
|
|
84
|
+
source = "query_model_fallback"
|
|
85
|
+
|
|
86
|
+
available = []
|
|
87
|
+
try:
|
|
88
|
+
from ..engine.backends.ollama import OllamaAdapter
|
|
89
|
+
|
|
90
|
+
adapter = OllamaAdapter()
|
|
91
|
+
for name in adapter.list_models():
|
|
92
|
+
available.append(
|
|
93
|
+
{
|
|
94
|
+
"name": name,
|
|
95
|
+
"supports_thinking": adapter.model_supports_thinking(name),
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
except Exception as exc: # noqa: BLE001 — catalog is a nicety, never a failure
|
|
99
|
+
logger.debug("context_llm available-model probe failed: %s", exc)
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
"model": effective,
|
|
103
|
+
"override": override or None,
|
|
104
|
+
"source": source,
|
|
105
|
+
"available_models": available,
|
|
106
|
+
}
|