apsimo 1.3.0__py3-none-any.whl
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.
- apsimo/__init__.py +38 -0
- apsimo/__main__.py +6 -0
- apsimo/agent/__init__.py +6 -0
- apsimo/agent/client.py +276 -0
- apsimo/agent/models.py +46 -0
- apsimo/agents/__init__.py +20 -0
- apsimo/agents/models.py +264 -0
- apsimo/agents/store.py +861 -0
- apsimo/agents/websocket.py +522 -0
- apsimo/api/__init__.py +1 -0
- apsimo/api/auth_telemetry.py +287 -0
- apsimo/api/authority.py +1203 -0
- apsimo/api/contact_grants.py +347 -0
- apsimo/api/middleware.py +483 -0
- apsimo/api/routers/__init__.py +1 -0
- apsimo/api/routers/commitment_work.py +265 -0
- apsimo/api/routers/context_gate.py +123 -0
- apsimo/api/routers/executions.py +140 -0
- apsimo/api/routers/followup_plans.py +147 -0
- apsimo/api/routers/governed_actions.py +162 -0
- apsimo/api/routers/host.py +14473 -0
- apsimo/api/routers/initiative_work.py +115 -0
- apsimo/api/routers/mining.py +104 -0
- apsimo/api/routers/observations.py +110 -0
- apsimo/api/routers/social_state.py +225 -0
- apsimo/api/routers/task_queue.py +2715 -0
- apsimo/api/routers/temporal_followups.py +251 -0
- apsimo/api/routers/transport.py +110 -0
- apsimo/api/routers/transport_ingress_api.py +240 -0
- apsimo/api/schemas/__init__.py +1 -0
- apsimo/api/schemas/host.py +1949 -0
- apsimo/autonomy/cli.py +110 -0
- apsimo/autonomy/condition_worker.py +437 -0
- apsimo/autonomy/config.py +424 -0
- apsimo/autonomy/loop.py +4316 -0
- apsimo/autonomy/registry.py +339 -0
- apsimo/autonomy/scheduler.py +1822 -0
- apsimo/autonomy/synthesis.py +449 -0
- apsimo/backup.py +962 -0
- apsimo/beliefs/__init__.py +23 -0
- apsimo/beliefs/contradictions.py +109 -0
- apsimo/beliefs/decay.py +61 -0
- apsimo/beliefs/engine.py +479 -0
- apsimo/beliefs/models.py +67 -0
- apsimo/beliefs/promotion.py +41 -0
- apsimo/beliefs/resolve.py +58 -0
- apsimo/beliefs/source_claims.py +690 -0
- apsimo/beliefs/source_projection.py +883 -0
- apsimo/beliefs/source_time.py +208 -0
- apsimo/beliefs/store.py +133 -0
- apsimo/briefings/aggregators.py +824 -0
- apsimo/briefings/composer.py +420 -0
- apsimo/briefings/config.py +55 -0
- apsimo/briefings/delivery.py +439 -0
- apsimo/briefings/engagement.py +97 -0
- apsimo/briefings/engine.py +274 -0
- apsimo/briefings/enhancer.py +99 -0
- apsimo/briefings/models.py +183 -0
- apsimo/briefings/scheduler.py +382 -0
- apsimo/briefings/store.py +435 -0
- apsimo/chain/__init__.py +48 -0
- apsimo/chain/block.py +100 -0
- apsimo/chain/cli.py +704 -0
- apsimo/chain/genesis.py +443 -0
- apsimo/chain/identity.py +416 -0
- apsimo/chain/keys.py +1025 -0
- apsimo/chain/local_keys.py +187 -0
- apsimo/chain/manager.py +290 -0
- apsimo/chain/node.py +163 -0
- apsimo/chain/plugin_transactions.py +371 -0
- apsimo/chain/protocol.py +220 -0
- apsimo/chain/state_machine.py +676 -0
- apsimo/chain/storage.py +503 -0
- apsimo/chain/transactions.py +250 -0
- apsimo/chain/validation.py +397 -0
- apsimo/channels/__init__.py +1 -0
- apsimo/channels/manifest.py +31 -0
- apsimo/channels/migrations/001_channels_schema.sql +12 -0
- apsimo/channels/phone_gateways.py +42 -0
- apsimo/channels/presence.py +188 -0
- apsimo/channels/router.py +235 -0
- apsimo/channels/store.py +231 -0
- apsimo/cli.py +2688 -0
- apsimo/cognition/__init__.py +11 -0
- apsimo/cognition/charter.py +398 -0
- apsimo/cognition/drive_governance.py +3530 -0
- apsimo/cognition/evidence_pipeline.py +1627 -0
- apsimo/cognition/external_events.py +932 -0
- apsimo/cognition/goal_spine.py +3488 -0
- apsimo/cognition/introspection.py +214 -0
- apsimo/cognition/prompt.py +150 -0
- apsimo/cognition/runtime.py +108 -0
- apsimo/cognition/trigger.py +154 -0
- apsimo/commitments/__init__.py +18 -0
- apsimo/commitments/local_work.py +355 -0
- apsimo/commitments/store.py +1052 -0
- apsimo/commitments/work.py +91 -0
- apsimo/compat.py +53 -0
- apsimo/compression/__init__.py +467 -0
- apsimo/connectors/__init__.py +21 -0
- apsimo/connectors/base.py +152 -0
- apsimo/connectors/caldav_calendar.py +125 -0
- apsimo/connectors/fs_documents.py +85 -0
- apsimo/connectors/imap_email.py +138 -0
- apsimo/connectors/manager.py +218 -0
- apsimo/connectors/webhook_pull.py +88 -0
- apsimo/contacts/__init__.py +33 -0
- apsimo/contacts/comms.py +357 -0
- apsimo/contacts/config.py +79 -0
- apsimo/contacts/exporters/__init__.py +1 -0
- apsimo/contacts/exporters/vcard.py +71 -0
- apsimo/contacts/identity_links.py +251 -0
- apsimo/contacts/importer.py +280 -0
- apsimo/contacts/importers/__init__.py +1 -0
- apsimo/contacts/importers/batch.py +43 -0
- apsimo/contacts/importers/macos_contacts.py +101 -0
- apsimo/contacts/migrations/001_contacts_schema.sql +141 -0
- apsimo/contacts/migrations/002_trust_scopes.sql +36 -0
- apsimo/contacts/migrations/003_open_gateway_enum.sql +32 -0
- apsimo/contacts/migrations/004_contact_provision_operations.sql +18 -0
- apsimo/contacts/migrations/005_identity_links.sql +27 -0
- apsimo/contacts/models.py +308 -0
- apsimo/contacts/scoring.py +16 -0
- apsimo/contacts/store.py +1623 -0
- apsimo/contacts/transport_ingress.py +252 -0
- apsimo/contacts/world_bridge.py +314 -0
- apsimo/contextgate/__init__.py +69 -0
- apsimo/contextgate/chunker.py +169 -0
- apsimo/contextgate/estimate.py +54 -0
- apsimo/contextgate/gate.py +313 -0
- apsimo/contextgate/retrieve.py +115 -0
- apsimo/delivery/__init__.py +16 -0
- apsimo/delivery/bridge.py +1260 -0
- apsimo/delivery/channels.py +526 -0
- apsimo/delivery/classification.py +50 -0
- apsimo/delivery/rate_limiter.py +268 -0
- apsimo/delivery/reachout_policy.py +206 -0
- apsimo/directed/__init__.py +22 -0
- apsimo/directed/audit.py +167 -0
- apsimo/directed/intake.py +95 -0
- apsimo/directed/models.py +191 -0
- apsimo/directed/service.py +509 -0
- apsimo/directives/__init__.py +25 -0
- apsimo/directives/evidence.py +87 -0
- apsimo/directives/extractor.py +188 -0
- apsimo/directives/guard.py +364 -0
- apsimo/directives/models.py +206 -0
- apsimo/directives/service.py +372 -0
- apsimo/directives/store.py +167 -0
- apsimo/doctor.py +2173 -0
- apsimo/environment.py +43 -0
- apsimo/events/__init__.py +33 -0
- apsimo/events/broadcaster.py +98 -0
- apsimo/events/bus.py +217 -0
- apsimo/events/journal.py +863 -0
- apsimo/events/stream.py +131 -0
- apsimo/events/types.py +150 -0
- apsimo/execution_results.py +357 -0
- apsimo/feedback/__init__.py +5 -0
- apsimo/feedback/store.py +76 -0
- apsimo/feeds/__init__.py +19 -0
- apsimo/feeds/cli.py +84 -0
- apsimo/feeds/engine.py +437 -0
- apsimo/feeds/example-feed.yaml +77 -0
- apsimo/feeds/hermes_cron.py +126 -0
- apsimo/feeds/manager.py +235 -0
- apsimo/feeds/spec.py +250 -0
- apsimo/feeds/template.py +202 -0
- apsimo/gate/__init__.py +18 -0
- apsimo/gate/audit.py +61 -0
- apsimo/gate/communication_policy.py +166 -0
- apsimo/gate/config.py +72 -0
- apsimo/gate/context_provenance.py +170 -0
- apsimo/gate/env_risk.py +226 -0
- apsimo/gate/guard_audit.py +353 -0
- apsimo/gate/layers/__init__.py +1 -0
- apsimo/gate/layers/base.py +15 -0
- apsimo/gate/layers/l1_recipient.py +66 -0
- apsimo/gate/layers/l2_pii.py +134 -0
- apsimo/gate/layers/l3_cross_context.py +50 -0
- apsimo/gate/layers/l4_trust_tier.py +78 -0
- apsimo/gate/layers/l5_injection.py +199 -0
- apsimo/gate/layers/l6_review.py +86 -0
- apsimo/gate/layers/l7_delay.py +100 -0
- apsimo/gate/layers/tom2_epistemic.py +185 -0
- apsimo/gate/models.py +64 -0
- apsimo/gate/pending_dispatch.py +5 -0
- apsimo/gate/pipeline.py +206 -0
- apsimo/gate/rejection.py +259 -0
- apsimo/gate/response_guard.py +700 -0
- apsimo/gate/rulesets/injection_v1.yaml +51 -0
- apsimo/gate/surface_policy.py +189 -0
- apsimo/gate/taint.py +226 -0
- apsimo/genesis.json +9 -0
- apsimo/goals/__init__.py +100 -0
- apsimo/goals/config.py +38 -0
- apsimo/goals/decomposer.py +421 -0
- apsimo/goals/engine.py +617 -0
- apsimo/goals/inference.py +354 -0
- apsimo/goals/models.py +302 -0
- apsimo/goals/priority.py +270 -0
- apsimo/goals/queue_bridge.py +149 -0
- apsimo/goals/replan.py +450 -0
- apsimo/goals/schema.sql +89 -0
- apsimo/goals/store.py +692 -0
- apsimo/governed_actions.py +1708 -0
- apsimo/harness_integration/__init__.py +45 -0
- apsimo/harness_integration/context.py +41 -0
- apsimo/harness_integration/skills.py +231 -0
- apsimo/identity/__init__.py +26 -0
- apsimo/identity/participants.py +181 -0
- apsimo/identity/resolver.py +329 -0
- apsimo/identity_bootstrap/__init__.py +5 -0
- apsimo/identity_bootstrap/builder.py +208 -0
- apsimo/identity_bootstrap/corpus.py +443 -0
- apsimo/identity_bootstrap/models.py +54 -0
- apsimo/identity_bootstrap/runner.py +353 -0
- apsimo/identity_bootstrap/seeders/__init__.py +25 -0
- apsimo/identity_bootstrap/seeders/briefings.py +109 -0
- apsimo/identity_bootstrap/seeders/chain.py +57 -0
- apsimo/identity_bootstrap/seeders/goals.py +128 -0
- apsimo/identity_bootstrap/seeders/memory.py +191 -0
- apsimo/identity_bootstrap/seeders/neo4j_cognition.py +79 -0
- apsimo/identity_bootstrap/seeders/relationship.py +152 -0
- apsimo/identity_bootstrap/seeders/sessions.py +67 -0
- apsimo/identity_bootstrap/seeders/skills.py +92 -0
- apsimo/identity_bootstrap/seeders/task_queue.py +72 -0
- apsimo/identity_bootstrap/seeders/world_model.py +143 -0
- apsimo/identity_bootstrap/self_query.py +92 -0
- apsimo/identity_bootstrap/self_reflection.py +155 -0
- apsimo/identity_bootstrap/skill.py +37 -0
- apsimo/identity_bootstrap/verifier.py +436 -0
- apsimo/initiatives/__init__.py +20 -0
- apsimo/initiatives/action_registry.py +454 -0
- apsimo/initiatives/approval_authority.py +2105 -0
- apsimo/initiatives/approval_policy.py +123 -0
- apsimo/initiatives/assignment.py +263 -0
- apsimo/initiatives/backup_evidence.py +100 -0
- apsimo/initiatives/context_freshness.py +103 -0
- apsimo/initiatives/models.py +318 -0
- apsimo/initiatives/native_work.py +270 -0
- apsimo/initiatives/standing_approvals.py +232 -0
- apsimo/initiatives/store.py +1081 -0
- apsimo/initiatives/temporal_followup.py +410 -0
- apsimo/intelligence/__init__.py +1 -0
- apsimo/intelligence/cognition/__init__.py +24 -0
- apsimo/intelligence/cognition/gap_detector.py +148 -0
- apsimo/intelligence/cognition/metalearner.py +547 -0
- apsimo/intelligence/cognition/metrics_collector.py +217 -0
- apsimo/intelligence/cognition/performance_index.py +299 -0
- apsimo/intelligence/cognition/registry.py +192 -0
- apsimo/intelligence/cognition/strategy_adjuster.py +222 -0
- apsimo/intelligence/cognition/types.py +16 -0
- apsimo/intelligence/components/__init__.py +66 -0
- apsimo/intelligence/components/anomaly_detector.py +413 -0
- apsimo/intelligence/components/initiative_engine.py +2643 -0
- apsimo/intelligence/components/preference_learner.py +521 -0
- apsimo/intelligence/components/research_orchestrator.py +358 -0
- apsimo/intelligence/components/self_directed_thinker.py +221 -0
- apsimo/intelligence/components/self_reflector.py +252 -0
- apsimo/intelligence/components/session_continuity.py +154 -0
- apsimo/intelligence/components/task_planner.py +320 -0
- apsimo/intelligence/components/tool_learner.py +217 -0
- apsimo/intelligence/graph/__init__.py +79 -0
- apsimo/intelligence/graph/client.py +2483 -0
- apsimo/intelligence/graph/consolidator.py +405 -0
- apsimo/intelligence/graph/distiller.py +312 -0
- apsimo/intelligence/graph/migrations.py +129 -0
- apsimo/intelligence/graph/queries.py +248 -0
- apsimo/intelligence/graph/recall.py +281 -0
- apsimo/intelligence/graph/reconciler.py +144 -0
- apsimo/intelligence/graph/schema.py +337 -0
- apsimo/intelligence/graph/selection.py +252 -0
- apsimo/intelligence/learning/__init__.py +17 -0
- apsimo/intelligence/learning/continuous_learner.py +245 -0
- apsimo/intelligence/learning/feedback_store.py +321 -0
- apsimo/intelligence/mind_model/__init__.py +1 -0
- apsimo/intelligence/mind_model/graph_baseline.py +136 -0
- apsimo/intelligence/mind_model/signal_collector.py +361 -0
- apsimo/intelligence/relationships/__init__.py +11 -0
- apsimo/intelligence/relationships/profiler.py +389 -0
- apsimo/intelligence/relationships/scorer.py +560 -0
- apsimo/intelligence/relationships/signal_floor.py +66 -0
- apsimo/intelligence/relationships/trust_tiers.py +300 -0
- apsimo/intelligence/synthesis/__init__.py +40 -0
- apsimo/intelligence/synthesis/connection_discoverer.py +379 -0
- apsimo/intelligence/synthesis/cross_domain_analyzer.py +287 -0
- apsimo/intelligence/synthesis/insight_deliverer.py +171 -0
- apsimo/intelligence/synthesis/insight_store.py +79 -0
- apsimo/intelligence/synthesis/insight_validator.py +183 -0
- apsimo/intelligence/synthesis/novelty_scorer.py +267 -0
- apsimo/intelligence/turn_middleware/__init__.py +15 -0
- apsimo/intelligence/turn_middleware/memory_sync.py +119 -0
- apsimo/mcp/__init__.py +41 -0
- apsimo/mcp/__main__.py +6 -0
- apsimo/mcp/config.py +287 -0
- apsimo/mcp/server.py +501 -0
- apsimo/migrations.py +187 -0
- apsimo/mining/__init__.py +27 -0
- apsimo/mining/corpus.py +239 -0
- apsimo/mining/escalations.py +289 -0
- apsimo/mining/models.py +169 -0
- apsimo/mining/store.py +210 -0
- apsimo/models/__init__.py +30 -0
- apsimo/models/memory.py +80 -0
- apsimo/models/mesh.py +72 -0
- apsimo/models/person.py +104 -0
- apsimo/models/signal.py +108 -0
- apsimo/observations/__init__.py +15 -0
- apsimo/observations/store.py +277 -0
- apsimo/patterns/__init__.py +6 -0
- apsimo/patterns/extract.py +187 -0
- apsimo/patterns/store.py +227 -0
- apsimo/persona/__init__.py +1 -0
- apsimo/persona/engine.py +611 -0
- apsimo/persona/manifest.py +140 -0
- apsimo/projects/__init__.py +28 -0
- apsimo/projects/engine.py +1681 -0
- apsimo/projects/event_outbox.py +188 -0
- apsimo/projects/models.py +216 -0
- apsimo/projects/planner.py +181 -0
- apsimo/projects/store.py +1446 -0
- apsimo/proposals/__init__.py +12 -0
- apsimo/proposals/engine.py +114 -0
- apsimo/proposals/models.py +207 -0
- apsimo/qualification/__init__.py +1 -0
- apsimo/qualification/cases.py +75 -0
- apsimo/qualification/cli.py +51 -0
- apsimo/qualification/memory_cases.py +209 -0
- apsimo/qualification/records.py +92 -0
- apsimo/qualification/report.py +87 -0
- apsimo/qualification/runner.py +311 -0
- apsimo/qualification/structured_cases.py +131 -0
- apsimo/reasoning/__init__.py +13 -0
- apsimo/reasoning/executor.py +506 -0
- apsimo/reasoning/loop.py +373 -0
- apsimo/reasoning/native_tools/__init__.py +16 -0
- apsimo/reasoning/native_tools/calculate.py +141 -0
- apsimo/reasoning/native_tools/file_ops.py +150 -0
- apsimo/reasoning/native_tools/web_search.py +49 -0
- apsimo/reasoning/tool_policy.py +182 -0
- apsimo/redact/__init__.py +176 -0
- apsimo/repos/__init__.py +5 -0
- apsimo/repos/mirrors.py +204 -0
- apsimo/research/__init__.py +41 -0
- apsimo/research/artifact.py +482 -0
- apsimo/research/gatherer.py +387 -0
- apsimo/research/pipeline.py +513 -0
- apsimo/research/search/__init__.py +7 -0
- apsimo/research/search/base.py +41 -0
- apsimo/research/search/brave.py +59 -0
- apsimo/research/search/cache.py +51 -0
- apsimo/research/search/duckduckgo.py +103 -0
- apsimo/research/search/orchestrator.py +119 -0
- apsimo/research/search/serpapi.py +59 -0
- apsimo/research/search/tavily.py +59 -0
- apsimo/research/synthesizer.py +309 -0
- apsimo/router/__init__.py +30 -0
- apsimo/router/complexity_scorer.py +148 -0
- apsimo/router/endpoints.py +153 -0
- apsimo/router/fallback.py +58 -0
- apsimo/router/functions.py +243 -0
- apsimo/router/native_policy.py +52 -0
- apsimo/router/router.py +762 -0
- apsimo/router/self_learning.py +174 -0
- apsimo/router/tiers.py +677 -0
- apsimo/sandbox/__init__.py +21 -0
- apsimo/sandbox/backend.py +195 -0
- apsimo/sandbox/manager.py +173 -0
- apsimo/scope_bounds.py +7 -0
- apsimo/secrets/__init__.py +6 -0
- apsimo/secrets/backends/__init__.py +8 -0
- apsimo/secrets/backends/base.py +42 -0
- apsimo/secrets/backends/env.py +110 -0
- apsimo/secrets/backends/keyring.py +72 -0
- apsimo/secrets/backends/onepassword.py +232 -0
- apsimo/secrets/cli.py +191 -0
- apsimo/secrets/manager.py +160 -0
- apsimo/secrets/migration.py +101 -0
- apsimo/secrets/types.py +98 -0
- apsimo/seed.py +41 -0
- apsimo/self_model/__init__.py +37 -0
- apsimo/self_model/appraisals.py +673 -0
- apsimo/self_model/benchmark.py +1314 -0
- apsimo/self_model/brief.py +40 -0
- apsimo/self_model/event_concerns.py +1128 -0
- apsimo/self_model/execution_forecasts.py +353 -0
- apsimo/self_model/expectations.py +1595 -0
- apsimo/self_model/experiments.py +1150 -0
- apsimo/self_model/journal.py +148 -0
- apsimo/self_model/judgments.py +705 -0
- apsimo/self_model/native_outcomes.py +55 -0
- apsimo/self_model/params.py +220 -0
- apsimo/self_model/perspective.py +246 -0
- apsimo/self_model/reconcile.py +183 -0
- apsimo/self_model/reply_forecasts.py +381 -0
- apsimo/self_model/runtime_forecasts.py +296 -0
- apsimo/self_model/runtime_models.py +67 -0
- apsimo/self_model/settlement.py +207 -0
- apsimo/self_model/situation.py +1731 -0
- apsimo/self_model/store.py +883 -0
- apsimo/self_model/supervised.py +137 -0
- apsimo/self_model/thinker.py +99 -0
- apsimo/self_model/trust.py +388 -0
- apsimo/self_model/workspace.py +2388 -0
- apsimo/server.py +4197 -0
- apsimo/services/__init__.py +1 -0
- apsimo/services/agent_bridge.py +474 -0
- apsimo/services/initiative_executor.py +914 -0
- apsimo/services/instance.py +297 -0
- apsimo/sessions/__init__.py +22 -0
- apsimo/sessions/config.py +13 -0
- apsimo/sessions/context_loader.py +88 -0
- apsimo/sessions/federation_session.py +75 -0
- apsimo/sessions/isolated_session.py +98 -0
- apsimo/sessions/reports.py +84 -0
- apsimo/sessions/store.py +148 -0
- apsimo/setup.py +2818 -0
- apsimo/setup_hermes.py +879 -0
- apsimo/setup_local_work.py +218 -0
- apsimo/setup_native_goals.py +134 -0
- apsimo/setup_native_reviews.py +115 -0
- apsimo/skills/__init__.py +10 -0
- apsimo/skills/base.py +108 -0
- apsimo/skills/budget.py +28 -0
- apsimo/skills/executor.py +493 -0
- apsimo/skills/executors/__init__.py +1 -0
- apsimo/skills/executors/behavioral_correction.py +75 -0
- apsimo/skills/executors/capability_gap.py +38 -0
- apsimo/skills/executors/data_quality.py +163 -0
- apsimo/skills/executors/knowledge_acquisition.py +41 -0
- apsimo/skills/executors/operational_hygiene.py +185 -0
- apsimo/skills/executors/subsystem_health.py +169 -0
- apsimo/skills/hermes_export.py +431 -0
- apsimo/skills/index.py +123 -0
- apsimo/skills/learning/__init__.py +21 -0
- apsimo/skills/learning/novelty_detector.py +206 -0
- apsimo/skills/learning/pattern_extractor.py +199 -0
- apsimo/skills/learning/triggers.py +159 -0
- apsimo/skills/loader.py +246 -0
- apsimo/skills/migrations/002_progressive_loading.sql +6 -0
- apsimo/skills/migrations/backfill_triggers.py +20 -0
- apsimo/skills/models.py +202 -0
- apsimo/skills/packager.py +128 -0
- apsimo/skills/protocols.py +70 -0
- apsimo/skills/registry.py +191 -0
- apsimo/skills/runtime.py +58 -0
- apsimo/skills/sandbox_runner.py +229 -0
- apsimo/skills/scheduler.py +129 -0
- apsimo/skills/schema.py +79 -0
- apsimo/skills/security/__init__.py +12 -0
- apsimo/skills/security/guards.py +53 -0
- apsimo/skills/security/scanner.py +223 -0
- apsimo/skills_memory/__init__.py +26 -0
- apsimo/skills_memory/distill.py +159 -0
- apsimo/skills_memory/models.py +85 -0
- apsimo/skills_memory/retrieve.py +62 -0
- apsimo/skills_memory/store.py +172 -0
- apsimo/surprise/__init__.py +6 -0
- apsimo/surprise/accumulation.py +57 -0
- apsimo/surprise/scorer.py +102 -0
- apsimo/surprise/store.py +203 -0
- apsimo/task_queue/__init__.py +69 -0
- apsimo/task_queue/action_receipts.py +148 -0
- apsimo/task_queue/approval_relay_canary.py +108 -0
- apsimo/task_queue/config.py +85 -0
- apsimo/task_queue/contract.py +361 -0
- apsimo/task_queue/events.py +130 -0
- apsimo/task_queue/governor.py +1031 -0
- apsimo/task_queue/handlers/__init__.py +16 -0
- apsimo/task_queue/handlers/base.py +37 -0
- apsimo/task_queue/handlers/inference.py +640 -0
- apsimo/task_queue/handlers/monitoring.py +116 -0
- apsimo/task_queue/handlers/registry.py +75 -0
- apsimo/task_queue/handlers/subtask_handler.py +173 -0
- apsimo/task_queue/handlers/system_maintenance.py +147 -0
- apsimo/task_queue/mesh_integration.py +111 -0
- apsimo/task_queue/models.py +317 -0
- apsimo/task_queue/queue_manager.py +8286 -0
- apsimo/task_queue/routing.py +287 -0
- apsimo/task_queue/scheduler.py +252 -0
- apsimo/task_queue/schema.sql +197 -0
- apsimo/task_queue/work_control.py +342 -0
- apsimo/task_queue/worker.py +993 -0
- apsimo/telemetry.py +145 -0
- apsimo/tom/__init__.py +6 -0
- apsimo/tom/affect.py +387 -0
- apsimo/tom/approvals.py +171 -0
- apsimo/tom/arcs.py +896 -0
- apsimo/tom/asymmetry.py +131 -0
- apsimo/tom/eligibility.py +248 -0
- apsimo/tom/engagement.py +214 -0
- apsimo/tom/exposure.py +214 -0
- apsimo/tom/extractor.py +306 -0
- apsimo/tom/fact_adapters.py +144 -0
- apsimo/tom/facts.py +326 -0
- apsimo/tom/integration.py +592 -0
- apsimo/tom/leveled.py +118 -0
- apsimo/tom/levels.py +247 -0
- apsimo/tom/recipient_audit.py +995 -0
- apsimo/tom/recipient_simulator.py +593 -0
- apsimo/tom/source_lineage.py +93 -0
- apsimo/tom/tom2.py +277 -0
- apsimo/tom/visibility.py +559 -0
- apsimo/tom/visibility_store.py +414 -0
- apsimo/tools/__init__.py +0 -0
- apsimo/tools/definitions.py +740 -0
- apsimo/tools/handlers.py +943 -0
- apsimo/toolsmith/__init__.py +26 -0
- apsimo/toolsmith/authority.py +166 -0
- apsimo/toolsmith/engine.py +559 -0
- apsimo/toolsmith/integrity.py +100 -0
- apsimo/toolsmith/miner.py +145 -0
- apsimo/toolsmith/policy.py +110 -0
- apsimo/toolsmith/registry.py +635 -0
- apsimo/turns/__init__.py +17 -0
- apsimo/turns/audio.py +134 -0
- apsimo/turns/documents.py +235 -0
- apsimo/turns/executions.py +486 -0
- apsimo/turns/hermes_history.py +245 -0
- apsimo/turns/hermes_kanban.py +268 -0
- apsimo/turns/hermes_work.py +96 -0
- apsimo/turns/idempotency.py +752 -0
- apsimo/turns/local_work.py +115 -0
- apsimo/turns/media.py +581 -0
- apsimo/turns/reported_workers.py +196 -0
- apsimo/turns/source_annotations.py +283 -0
- apsimo/turns/source_attribution.py +154 -0
- apsimo/turns/source_read.py +351 -0
- apsimo/turns/source_vectors.py +263 -0
- apsimo/turns/video.py +210 -0
- apsimo/util/autonomy_preset.py +220 -0
- apsimo/util/instance.py +92 -0
- apsimo/util/model_output.py +25 -0
- apsimo/util/quiet_hours.py +27 -0
- apsimo/util/session_safety.py +37 -0
- apsimo/util/temporal.py +343 -0
- apsimo/vector/__init__.py +75 -0
- apsimo/vector/backfill.py +171 -0
- apsimo/vector/caption.py +114 -0
- apsimo/vector/collections.py +51 -0
- apsimo/vector/config.py +102 -0
- apsimo/vector/embedder.py +670 -0
- apsimo/vector/image_preprocess.py +406 -0
- apsimo/vector/image_store.py +296 -0
- apsimo/vector/indexes.py +162 -0
- apsimo/vector/migrate.py +334 -0
- apsimo/vector/multimodal_provider.py +417 -0
- apsimo/vector/multimodal_types.py +87 -0
- apsimo/vector/openai_provider.py +119 -0
- apsimo/vector/query.py +49 -0
- apsimo/vector/reranker.py +565 -0
- apsimo/vector/safety_image.py +159 -0
- apsimo/vector/scanner.py +197 -0
- apsimo/vector/setup.py +289 -0
- apsimo/vector/store.py +533 -0
- apsimo/vector/tiers.py +263 -0
- apsimo/work_orders.py +925 -0
- apsimo/workers/__init__.py +21 -0
- apsimo/workers/agent_bridge.py +640 -0
- apsimo/workers/colony_worker.py +382 -0
- apsimo/workers/queue_worker.py +441 -0
- apsimo/workers/skills_sync.py +152 -0
- apsimo/world_model/__init__.py +71 -0
- apsimo/world_model/causal_maintenance.py +131 -0
- apsimo/world_model/causal_policy.py +43 -0
- apsimo/world_model/causal_query.py +125 -0
- apsimo/world_model/confidence.py +54 -0
- apsimo/world_model/config.py +64 -0
- apsimo/world_model/constants.py +97 -0
- apsimo/world_model/entities.py +145 -0
- apsimo/world_model/expectation_resolvers.py +177 -0
- apsimo/world_model/extraction/__init__.py +7 -0
- apsimo/world_model/extraction/base.py +62 -0
- apsimo/world_model/extraction/conversation_extractor.py +262 -0
- apsimo/world_model/extraction/detector.py +74 -0
- apsimo/world_model/extraction/document_extractor.py +78 -0
- apsimo/world_model/extraction/formats/__init__.py +24 -0
- apsimo/world_model/extraction/formats/csv_fmt.py +68 -0
- apsimo/world_model/extraction/formats/html_fmt.py +72 -0
- apsimo/world_model/extraction/formats/json_fmt.py +68 -0
- apsimo/world_model/extraction/formats/pdf.py +43 -0
- apsimo/world_model/extraction/formats/text.py +27 -0
- apsimo/world_model/extraction/llm_extractor.py +164 -0
- apsimo/world_model/extraction/pipeline.py +73 -0
- apsimo/world_model/integrations/__init__.py +5 -0
- apsimo/world_model/integrations/mind_model_bridge.py +115 -0
- apsimo/world_model/integrations/social_intel_bridge.py +120 -0
- apsimo/world_model/jobs/__init__.py +4 -0
- apsimo/world_model/jobs/extraction_job.py +168 -0
- apsimo/world_model/llm_extract.py +572 -0
- apsimo/world_model/neo4j/__init__.py +5 -0
- apsimo/world_model/neo4j/backend.py +654 -0
- apsimo/world_model/observations.py +155 -0
- apsimo/world_model/populator.py +307 -0
- apsimo/world_model/postgres/__init__.py +1 -0
- apsimo/world_model/postgres/backend.py +683 -0
- apsimo/world_model/relationships.py +25 -0
- apsimo/world_model/resolution/__init__.py +13 -0
- apsimo/world_model/resolution/entity_resolver.py +232 -0
- apsimo/world_model/resolution/merge_audit.py +16 -0
- apsimo/world_model/resolution/merge_workflow.py +117 -0
- apsimo/world_model/source_reports.py +121 -0
- apsimo/world_model/sqlite/__init__.py +4 -0
- apsimo/world_model/sqlite/backend.py +855 -0
- apsimo/world_model/sqlite/schema.sql +132 -0
- apsimo/world_model/store.py +545 -0
- apsimo-1.3.0.dist-info/METADATA +78 -0
- apsimo-1.3.0.dist-info/RECORD +614 -0
- apsimo-1.3.0.dist-info/WHEEL +5 -0
- apsimo-1.3.0.dist-info/entry_points.txt +11 -0
- apsimo-1.3.0.dist-info/licenses/LICENSE +21 -0
- apsimo-1.3.0.dist-info/top_level.txt +2 -0
- colony_sidecar/__init__.py +4 -0
apsimo/tom/facts.py
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"""Shared Facts — what the agent believes each contact knows.
|
|
2
|
+
|
|
3
|
+
Tracks information asymmetry: which facts are shared with a contact,
|
|
4
|
+
which were told by them, and which the agent inferred they know.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import logging
|
|
11
|
+
import sqlite3
|
|
12
|
+
import uuid
|
|
13
|
+
from datetime import datetime, timezone
|
|
14
|
+
from typing import Any, Dict, List, Optional
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
from .source_lineage import SourceLinkedStore
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SharedFactsStore(SourceLinkedStore):
|
|
23
|
+
"""SQLite-backed shared facts store."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, db_path: str, *, source_ledger=None) -> None:
|
|
26
|
+
self._db_path = db_path
|
|
27
|
+
self._source_ledger = source_ledger
|
|
28
|
+
self._conn = sqlite3.connect(db_path)
|
|
29
|
+
self._conn.row_factory = sqlite3.Row
|
|
30
|
+
self._conn.execute("PRAGMA journal_mode=WAL")
|
|
31
|
+
self._conn.execute("PRAGMA foreign_keys=ON")
|
|
32
|
+
self._create_tables()
|
|
33
|
+
self._conn.create_function('source_fact_visible', 2, self._source_visible)
|
|
34
|
+
self._conn.create_function('source_fact_automatic', 2, self._automatic_visible)
|
|
35
|
+
|
|
36
|
+
def _create_tables(self) -> None:
|
|
37
|
+
self._conn.executescript("""
|
|
38
|
+
CREATE TABLE IF NOT EXISTS shared_facts (
|
|
39
|
+
id TEXT PRIMARY KEY,
|
|
40
|
+
contact_id TEXT NOT NULL,
|
|
41
|
+
fact TEXT NOT NULL,
|
|
42
|
+
source TEXT NOT NULL,
|
|
43
|
+
confidence REAL NOT NULL DEFAULT 0.8,
|
|
44
|
+
created_at TEXT NOT NULL,
|
|
45
|
+
expires_at TEXT,
|
|
46
|
+
metadata TEXT
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
CREATE INDEX IF NOT EXISTS idx_shared_facts_contact
|
|
50
|
+
ON shared_facts(contact_id);
|
|
51
|
+
CREATE INDEX IF NOT EXISTS idx_shared_facts_source
|
|
52
|
+
ON shared_facts(source);
|
|
53
|
+
""")
|
|
54
|
+
self._conn.commit()
|
|
55
|
+
if 'source_lineage_json' not in {row[1] for row in self._conn.execute('PRAGMA table_info(shared_facts)')}:
|
|
56
|
+
self._conn.execute('ALTER TABLE shared_facts ADD COLUMN source_lineage_json TEXT')
|
|
57
|
+
self._conn.commit()
|
|
58
|
+
|
|
59
|
+
def source_visible(self, record: dict) -> bool:
|
|
60
|
+
return self._source_visible(record['contact_id'], record.get('source_lineage'))
|
|
61
|
+
|
|
62
|
+
def automatic_view(self):
|
|
63
|
+
"""Current source-linked estimates only; explicit history stays intact."""
|
|
64
|
+
return AutomaticFactsView(self)
|
|
65
|
+
|
|
66
|
+
def _automatic_visible(self, contact_id, raw) -> bool:
|
|
67
|
+
if not raw:
|
|
68
|
+
return False
|
|
69
|
+
try:
|
|
70
|
+
lineage = json.loads(raw) if isinstance(raw, str) else raw
|
|
71
|
+
return bool(isinstance(lineage, dict) and lineage.get('message_hashes')
|
|
72
|
+
and self._source_visible(contact_id, lineage))
|
|
73
|
+
except (ValueError, KeyError, TypeError):
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
def purge_erased_sources(self, turn_ids: Optional[List[str]] = None) -> int:
|
|
77
|
+
"""Physical cleanup follows durable tombstones; unknown origins stay intact."""
|
|
78
|
+
count = 0
|
|
79
|
+
rows = self._conn.execute(
|
|
80
|
+
'SELECT id,source_lineage_json FROM shared_facts WHERE source_lineage_json IS NOT NULL'
|
|
81
|
+
).fetchall()
|
|
82
|
+
for row in rows:
|
|
83
|
+
lineage = json.loads(row['source_lineage_json'])
|
|
84
|
+
if turn_ids is not None and lineage['turn_id'] not in turn_ids:
|
|
85
|
+
continue
|
|
86
|
+
if self._ledger().is_projection_erased(lineage['turn_id']):
|
|
87
|
+
count += self._conn.execute('DELETE FROM shared_facts WHERE id=?', (row['id'],)).rowcount
|
|
88
|
+
self._conn.commit()
|
|
89
|
+
return count
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def _decode(row):
|
|
93
|
+
data = dict(row)
|
|
94
|
+
if data.get('metadata'):
|
|
95
|
+
try:
|
|
96
|
+
data['metadata'] = json.loads(data['metadata'])
|
|
97
|
+
except (ValueError, TypeError):
|
|
98
|
+
pass
|
|
99
|
+
raw = data.pop('source_lineage_json', None)
|
|
100
|
+
if raw:
|
|
101
|
+
data['source_lineage'] = json.loads(raw)
|
|
102
|
+
data['metadata'] = {
|
|
103
|
+
**(data.get('metadata') or {}),
|
|
104
|
+
'canonical_source': 'turn:' + data['source_lineage']['turn_id'],
|
|
105
|
+
}
|
|
106
|
+
return data
|
|
107
|
+
|
|
108
|
+
def create_fact(
|
|
109
|
+
self,
|
|
110
|
+
*,
|
|
111
|
+
contact_id: str,
|
|
112
|
+
fact: str,
|
|
113
|
+
source: str = "shared_context",
|
|
114
|
+
confidence: float = 0.8,
|
|
115
|
+
expires_at: Optional[str] = None,
|
|
116
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
117
|
+
source_lineage: Optional[Dict[str, Any]] = None,
|
|
118
|
+
) -> Dict[str, Any]:
|
|
119
|
+
"""Add a shared fact. Returns the created fact dict."""
|
|
120
|
+
confidence = max(0.0, min(1.0, confidence))
|
|
121
|
+
if source_lineage is not None and not self._source_visible(contact_id, source_lineage):
|
|
122
|
+
from apsimo.turns.idempotency import SourceErased
|
|
123
|
+
raise SourceErased('source_erased')
|
|
124
|
+
|
|
125
|
+
fact_id = str(uuid.uuid4())
|
|
126
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
127
|
+
meta_json = None
|
|
128
|
+
if metadata is not None:
|
|
129
|
+
meta_json = json.dumps(metadata)
|
|
130
|
+
|
|
131
|
+
self._conn.execute(
|
|
132
|
+
"""INSERT INTO shared_facts (id, contact_id, fact, source, confidence, created_at, expires_at, metadata,source_lineage_json)
|
|
133
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
|
134
|
+
(fact_id, contact_id, fact, source, confidence, now, expires_at, meta_json,
|
|
135
|
+
json.dumps(source_lineage) if source_lineage is not None else None),
|
|
136
|
+
)
|
|
137
|
+
self._conn.commit()
|
|
138
|
+
|
|
139
|
+
result = self.get_fact(fact_id)
|
|
140
|
+
if result is None:
|
|
141
|
+
self.purge_erased_sources()
|
|
142
|
+
from apsimo.turns.idempotency import SourceErased
|
|
143
|
+
raise SourceErased('source_erased')
|
|
144
|
+
return result
|
|
145
|
+
|
|
146
|
+
def get_fact(self, fact_id: str) -> Optional[Dict[str, Any]]:
|
|
147
|
+
row = self._conn.execute(
|
|
148
|
+
"SELECT * FROM shared_facts WHERE id = ? AND source_fact_visible(contact_id,source_lineage_json)", (fact_id,)
|
|
149
|
+
).fetchone()
|
|
150
|
+
if row is None:
|
|
151
|
+
return None
|
|
152
|
+
return self._decode(row)
|
|
153
|
+
|
|
154
|
+
def list_facts(
|
|
155
|
+
self,
|
|
156
|
+
*,
|
|
157
|
+
contact_id: Optional[str] = None,
|
|
158
|
+
source: Optional[str] = None,
|
|
159
|
+
min_confidence: float = 0.0,
|
|
160
|
+
limit: int = 50,
|
|
161
|
+
offset: int = 0,
|
|
162
|
+
source_linked_only: bool = False,
|
|
163
|
+
) -> Dict[str, Any]:
|
|
164
|
+
"""List shared facts with optional filters.
|
|
165
|
+
|
|
166
|
+
Returns {"facts": [...], "total": N, "limit": N, "offset": N}.
|
|
167
|
+
"""
|
|
168
|
+
clauses: List[str] = []
|
|
169
|
+
params: List[Any] = []
|
|
170
|
+
|
|
171
|
+
if contact_id is not None:
|
|
172
|
+
clauses.append("contact_id = ?")
|
|
173
|
+
params.append(contact_id)
|
|
174
|
+
if source is not None:
|
|
175
|
+
clauses.append("source = ?")
|
|
176
|
+
params.append(source)
|
|
177
|
+
if min_confidence > 0:
|
|
178
|
+
clauses.append("confidence >= ?")
|
|
179
|
+
params.append(min_confidence)
|
|
180
|
+
|
|
181
|
+
# Filter out expired facts.
|
|
182
|
+
clauses.append("(expires_at IS NULL OR expires_at > ?)")
|
|
183
|
+
if source_linked_only:
|
|
184
|
+
# Apply before the window so recent legacy noise cannot crowd out
|
|
185
|
+
# older supported estimates. Visibility still checks exact current
|
|
186
|
+
# contact, session and message hashes in the canonical ledger.
|
|
187
|
+
clauses.append('source_fact_automatic(contact_id,source_lineage_json)')
|
|
188
|
+
else:
|
|
189
|
+
clauses.append('source_fact_visible(contact_id,source_lineage_json)')
|
|
190
|
+
params.append(datetime.now(timezone.utc).isoformat())
|
|
191
|
+
|
|
192
|
+
where = f" WHERE {' AND '.join(clauses)}"
|
|
193
|
+
|
|
194
|
+
total_row = self._conn.execute(
|
|
195
|
+
f"SELECT COUNT(*) as cnt FROM shared_facts{where}", params
|
|
196
|
+
).fetchone()
|
|
197
|
+
total = total_row["cnt"] if total_row else 0
|
|
198
|
+
|
|
199
|
+
rows = self._conn.execute(
|
|
200
|
+
f"SELECT * FROM shared_facts{where} ORDER BY created_at DESC LIMIT ? OFFSET ?",
|
|
201
|
+
params + [limit, offset],
|
|
202
|
+
).fetchall()
|
|
203
|
+
|
|
204
|
+
facts = [self._decode(row) for row in rows]
|
|
205
|
+
|
|
206
|
+
return {"facts": facts, "total": total, "limit": limit, "offset": offset}
|
|
207
|
+
|
|
208
|
+
def update_fact(
|
|
209
|
+
self,
|
|
210
|
+
fact_id: str,
|
|
211
|
+
*,
|
|
212
|
+
confidence: Optional[float] = None,
|
|
213
|
+
expires_at: Optional[str] = None,
|
|
214
|
+
fact: Optional[str] = None,
|
|
215
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
216
|
+
) -> Optional[Dict[str, Any]]:
|
|
217
|
+
"""Update a shared fact. Returns updated fact or None if not found."""
|
|
218
|
+
existing = self.get_fact(fact_id)
|
|
219
|
+
if existing is None:
|
|
220
|
+
return None
|
|
221
|
+
|
|
222
|
+
updates: List[str] = []
|
|
223
|
+
params: List[Any] = []
|
|
224
|
+
|
|
225
|
+
if confidence is not None:
|
|
226
|
+
updates.append("confidence = ?")
|
|
227
|
+
params.append(max(0.0, min(1.0, confidence)))
|
|
228
|
+
if expires_at is not None:
|
|
229
|
+
updates.append("expires_at = ?")
|
|
230
|
+
params.append(expires_at)
|
|
231
|
+
if fact is not None:
|
|
232
|
+
updates.append("fact = ?")
|
|
233
|
+
params.append(fact)
|
|
234
|
+
if metadata is not None:
|
|
235
|
+
import json
|
|
236
|
+
updates.append("metadata = ?")
|
|
237
|
+
params.append(json.dumps(metadata))
|
|
238
|
+
|
|
239
|
+
if not updates:
|
|
240
|
+
return existing
|
|
241
|
+
|
|
242
|
+
params.append(fact_id)
|
|
243
|
+
self._conn.execute(
|
|
244
|
+
f"UPDATE shared_facts SET {', '.join(updates)} WHERE id = ?", params
|
|
245
|
+
)
|
|
246
|
+
self._conn.commit()
|
|
247
|
+
|
|
248
|
+
return self.get_fact(fact_id)
|
|
249
|
+
|
|
250
|
+
def delete_fact(self, fact_id: str) -> bool:
|
|
251
|
+
"""Delete a shared fact. Returns True if deleted."""
|
|
252
|
+
cursor = self._conn.execute("DELETE FROM shared_facts WHERE id = ?", (fact_id,))
|
|
253
|
+
self._conn.commit()
|
|
254
|
+
return cursor.rowcount > 0
|
|
255
|
+
|
|
256
|
+
def purge_expired(self) -> int:
|
|
257
|
+
"""Remove expired facts. Returns count purged."""
|
|
258
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
259
|
+
cursor = self._conn.execute(
|
|
260
|
+
"DELETE FROM shared_facts WHERE expires_at IS NOT NULL AND expires_at <= ?", (now,)
|
|
261
|
+
)
|
|
262
|
+
self._conn.commit()
|
|
263
|
+
return cursor.rowcount
|
|
264
|
+
|
|
265
|
+
def close(self) -> None:
|
|
266
|
+
self._conn.close()
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class AutomaticFactsView:
|
|
270
|
+
"""Existing read interface with canonical eligibility, never a new store."""
|
|
271
|
+
|
|
272
|
+
def __init__(self, store):
|
|
273
|
+
self._store = store
|
|
274
|
+
|
|
275
|
+
def get_fact(self, fact_id):
|
|
276
|
+
record = self._store.get_fact(fact_id)
|
|
277
|
+
if record is None or not self._store._automatic_visible(
|
|
278
|
+
record['contact_id'], record.get('source_lineage')):
|
|
279
|
+
return None
|
|
280
|
+
expires = record.get('expires_at')
|
|
281
|
+
if expires and expires <= datetime.now(timezone.utc).isoformat():
|
|
282
|
+
return None
|
|
283
|
+
return record
|
|
284
|
+
|
|
285
|
+
def list_facts(self, **kwargs):
|
|
286
|
+
return self._store.list_facts(**{**kwargs, 'source_linked_only': True})
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class InferenceFactsView(SourceLinkedStore):
|
|
290
|
+
"""ToM2 cannot reuse an old knowledge inference across a source correction.
|
|
291
|
+
|
|
292
|
+
Ordinary recall can bundle attributed corrections with the original. The
|
|
293
|
+
compact knowledge renderers cannot represent that packet, so omit the
|
|
294
|
+
inference while retaining its fact and correction for explicit inspection.
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
def __init__(self, view, ledger):
|
|
298
|
+
self._view, self._source_ledger = view, ledger
|
|
299
|
+
self._read = {}
|
|
300
|
+
|
|
301
|
+
def get_fact(self, fact_id):
|
|
302
|
+
from apsimo.turns.source_annotations import expand
|
|
303
|
+
try:
|
|
304
|
+
row = self._view.get_fact(fact_id)
|
|
305
|
+
lineage = (row or {}).get('source_lineage') or {}
|
|
306
|
+
# Projected views can cache authorized rows. Recheck canonical
|
|
307
|
+
# membership independently, including all hashes and source scope.
|
|
308
|
+
if not lineage.get('message_hashes') or not self._source_visible(row['contact_id'], lineage):
|
|
309
|
+
return None
|
|
310
|
+
source = lineage['turn_id']
|
|
311
|
+
packet = expand(self._ledger(), [{
|
|
312
|
+
'id': fact_id, 'content': row['fact'], 'source_turn_id': source,
|
|
313
|
+
'_source_message_hashes': {source: lineage['message_hashes']},
|
|
314
|
+
}], contact_id=row['contact_id'], session_id=lineage['session_id'])
|
|
315
|
+
if (len(packet) != 1 or packet[0].get('_annotation_ids')
|
|
316
|
+
or source not in {ref['source_id'] for ref in packet[0].get('_annotation_source_refs', [])}):
|
|
317
|
+
return None
|
|
318
|
+
self._read.setdefault(fact_id, row)
|
|
319
|
+
return row
|
|
320
|
+
except Exception:
|
|
321
|
+
logger.debug('ToM2 source correction check unavailable', exc_info=True)
|
|
322
|
+
return None
|
|
323
|
+
|
|
324
|
+
def current(self):
|
|
325
|
+
"""Recheck after other context producers may have awaited work."""
|
|
326
|
+
return all(self.get_fact(key) == row for key, row in list(self._read.items()))
|