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
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""Explicit valid-time and observation-time windows for memory recall."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from datetime import datetime, timedelta, timezone
|
|
6
|
+
import json
|
|
7
|
+
import re
|
|
8
|
+
from zoneinfo import ZoneInfo
|
|
9
|
+
|
|
10
|
+
UTC = timezone.utc
|
|
11
|
+
_MONTHS = {name.casefold(): i for i, name in enumerate(
|
|
12
|
+
("January", "February", "March", "April", "May", "June", "July", "August",
|
|
13
|
+
"September", "October", "November", "December"), 1)}
|
|
14
|
+
_DATE = r"\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}(?::\d{2})?(?:Z|[+-]\d{2}:\d{2}))?"
|
|
15
|
+
_MONTH_DATE = r"(?:" + "|".join(_MONTHS) + r")\s+\d{1,2},?\s+\d{4}"
|
|
16
|
+
_EVENT = re.compile(r"\b(footage|camera|observed|spotted|seen|saw|happened|recorded|arrived|visited)\b", re.I)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def utc_timestamp(value: str | None) -> datetime | None:
|
|
20
|
+
if not value:
|
|
21
|
+
return None
|
|
22
|
+
try:
|
|
23
|
+
result = datetime.fromisoformat(value.replace("Z", "+00:00"))
|
|
24
|
+
return result.astimezone(UTC) if result.tzinfo else None
|
|
25
|
+
except (TypeError, ValueError):
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def parse_source_date(expression: str, *, observed_at: str | None, timezone_name="UTC") -> str | None:
|
|
30
|
+
"""Resolve only explicit supported date text, anchored to source occurrence."""
|
|
31
|
+
zone = ZoneInfo(timezone_name)
|
|
32
|
+
value = expression.strip().casefold()
|
|
33
|
+
try:
|
|
34
|
+
if value in {"now", "today", "yesterday", "tomorrow"}:
|
|
35
|
+
observed = utc_timestamp(observed_at)
|
|
36
|
+
if observed is None:
|
|
37
|
+
return None
|
|
38
|
+
if value == "now":
|
|
39
|
+
return observed.isoformat()
|
|
40
|
+
local = observed.astimezone(zone).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
41
|
+
local += timedelta(days={"yesterday": -1, "today": 0, "tomorrow": 1}[value])
|
|
42
|
+
return local.astimezone(UTC).isoformat()
|
|
43
|
+
if re.fullmatch(_DATE, expression, re.I):
|
|
44
|
+
date = datetime.fromisoformat(expression.replace("Z", "+00:00"))
|
|
45
|
+
if date.tzinfo is None:
|
|
46
|
+
date = date.replace(tzinfo=zone)
|
|
47
|
+
return date.astimezone(UTC).isoformat()
|
|
48
|
+
match = re.fullmatch(r"([a-z]+)\s+(\d{1,2}),?\s+(\d{4})", value)
|
|
49
|
+
if match and match[1] in _MONTHS:
|
|
50
|
+
return datetime(int(match[3]), _MONTHS[match[1]], int(match[2]), tzinfo=zone).astimezone(UTC).isoformat()
|
|
51
|
+
except ValueError:
|
|
52
|
+
pass
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def source_event_time(expression: str | None, *, observed_at: str | None, timezone_name="UTC") -> dict:
|
|
57
|
+
"""Retain source-grounded event precision without inventing a point in time.
|
|
58
|
+
|
|
59
|
+
The caller verifies the expression against the quotation. An unresolved
|
|
60
|
+
optional event date is different from an unresolved state-validity condition.
|
|
61
|
+
The latter must still prevent certifying when a state holds.
|
|
62
|
+
"""
|
|
63
|
+
if expression is None:
|
|
64
|
+
return {"status": "unknown"}
|
|
65
|
+
result = {"expression": expression}
|
|
66
|
+
parsed = parse_source_date(expression, observed_at=observed_at, timezone_name=timezone_name)
|
|
67
|
+
if parsed:
|
|
68
|
+
if expression.casefold().strip() == "now" or (re.fullmatch(_DATE, expression, re.I) and "T" in expression.upper()):
|
|
69
|
+
return {**result, "status": "resolved", "precision": "instant", "at": parsed}
|
|
70
|
+
begin = utc_timestamp(parsed).astimezone(ZoneInfo(timezone_name))
|
|
71
|
+
return {**result, "status": "resolved", "precision": "calendar_day", "start": parsed,
|
|
72
|
+
"end_exclusive": (begin + timedelta(days=1)).astimezone(UTC).isoformat()}
|
|
73
|
+
# This relation refers to the message's occurrence, never its later import.
|
|
74
|
+
if re.fullmatch(r"before (?:sending )?(?:this|the current) message", expression.strip(), re.I):
|
|
75
|
+
observed = utc_timestamp(observed_at)
|
|
76
|
+
if observed:
|
|
77
|
+
return {**result, "status": "bounded", "before": observed.isoformat()}
|
|
78
|
+
return {**result, "status": "unresolved"}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass(frozen=True)
|
|
82
|
+
class MemoryTimeQuery:
|
|
83
|
+
mode: str = "current"
|
|
84
|
+
start: str | None = None
|
|
85
|
+
end: str | None = None
|
|
86
|
+
expression: str | None = None
|
|
87
|
+
|
|
88
|
+
def accepts_observation(self, occurred_at: str | None) -> bool:
|
|
89
|
+
if self.mode != "observed_range":
|
|
90
|
+
return True
|
|
91
|
+
stamp = utc_timestamp(occurred_at)
|
|
92
|
+
if stamp is None:
|
|
93
|
+
return False
|
|
94
|
+
return (not self.start or stamp >= utc_timestamp(self.start)) and (not self.end or stamp < utc_timestamp(self.end))
|
|
95
|
+
|
|
96
|
+
def accepts_claim(self, claim: dict) -> bool:
|
|
97
|
+
if claim.get("retracted_by"):
|
|
98
|
+
return False
|
|
99
|
+
if self.mode == "unresolved_time":
|
|
100
|
+
return False
|
|
101
|
+
if self.mode == "observed_range":
|
|
102
|
+
event = claim.get('event_time', {})
|
|
103
|
+
if event.get('status') == 'resolved' and event.get('precision') == 'calendar_day':
|
|
104
|
+
start, end = utc_timestamp(event.get('start')), utc_timestamp(event.get('end_exclusive'))
|
|
105
|
+
return bool(start and end
|
|
106
|
+
and (not self.end or start < utc_timestamp(self.end))
|
|
107
|
+
and (not self.start or end > utc_timestamp(self.start)))
|
|
108
|
+
return self.accepts_observation(claim.get("event_at"))
|
|
109
|
+
start, end = utc_timestamp(claim.get("valid_from")), utc_timestamp(claim.get("valid_to"))
|
|
110
|
+
query_start, query_end = utc_timestamp(self.start), utc_timestamp(self.end)
|
|
111
|
+
if self.mode == "valid_range":
|
|
112
|
+
# A historical assertion with no known validity start cannot be
|
|
113
|
+
# certified as true on an arbitrary earlier date.
|
|
114
|
+
if start is None:
|
|
115
|
+
return False
|
|
116
|
+
return (query_end is None or start < query_end) and (end is None or query_start < end)
|
|
117
|
+
if query_start:
|
|
118
|
+
return (start is None or start <= query_start) and (end is None or query_start < end)
|
|
119
|
+
return not claim.get("superseded_by")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _temporal_request_text(text: str) -> str:
|
|
123
|
+
"""Exclude delimited evidence, retaining a quoted date used as an operand.
|
|
124
|
+
|
|
125
|
+
This only selects text for temporal interpretation. Retrieval still uses
|
|
126
|
+
the original query, including every quoted word and structured field.
|
|
127
|
+
"""
|
|
128
|
+
text = re.sub(r"(?s)```.*?```|~~~.*?~~~", " ", text)
|
|
129
|
+
text = re.sub(r"(?m)^\s*>[^\n]*", " ", text)
|
|
130
|
+
decoder = json.JSONDecoder()
|
|
131
|
+
spans, through = [], 0
|
|
132
|
+
for match in re.finditer(r"[\[{]", text):
|
|
133
|
+
if match.start() < through:
|
|
134
|
+
continue
|
|
135
|
+
try:
|
|
136
|
+
value, end = decoder.raw_decode(text, match.start())
|
|
137
|
+
except ValueError:
|
|
138
|
+
continue
|
|
139
|
+
if isinstance(value, (dict, list)):
|
|
140
|
+
spans.append((match.start(), end))
|
|
141
|
+
through = end
|
|
142
|
+
for start, end in reversed(spans):
|
|
143
|
+
text = text[:start] + " " + text[end:]
|
|
144
|
+
|
|
145
|
+
def quoted(match):
|
|
146
|
+
value = match[0][1:-1].strip()
|
|
147
|
+
if (re.fullmatch(_DATE + "|" + _MONTH_DATE + "|today|yesterday|tomorrow", value, re.I)
|
|
148
|
+
or re.fullmatch(r"last\s+\d{1,3}\s+(?:hours?|days?)|"
|
|
149
|
+
r"(?:last|next|previous)\s+(?:week|month|year)|"
|
|
150
|
+
r"\d+\s+(?:weeks?|months?|years?)\s+ago", value, re.I)):
|
|
151
|
+
return value
|
|
152
|
+
return " "
|
|
153
|
+
|
|
154
|
+
return re.sub(r'''"(?:\\.|[^"\\])*"|“[^”]*”|(?<!\w)'(?:\\.|[^'\\])*'(?!\w)|`[^`\n]*`''', quoted, text)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def interpret_time_query(text: str, *, now: datetime, timezone_name="UTC") -> MemoryTimeQuery:
|
|
158
|
+
"""Calendar days differ from trailing windows and from source ingestion.
|
|
159
|
+
|
|
160
|
+
A date without a clock covers that local calendar day. If a fact changes
|
|
161
|
+
during the day, both intersecting validity intervals remain visible.
|
|
162
|
+
"""
|
|
163
|
+
zone = ZoneInfo(timezone_name)
|
|
164
|
+
text = _temporal_request_text(text[:4096])
|
|
165
|
+
mode = "observed_range" if _EVENT.search(text) else "valid_range"
|
|
166
|
+
duration = re.search(r"\blast\s+(\d{1,3})\s+(hours?|days?)\b", text, re.I)
|
|
167
|
+
if duration and mode == "observed_range":
|
|
168
|
+
delta = timedelta(hours=int(duration[1])) if duration[2].lower().startswith("hour") else timedelta(days=int(duration[1]))
|
|
169
|
+
return MemoryTimeQuery(mode, (now - delta).astimezone(UTC).isoformat(), now.astimezone(UTC).isoformat(), duration[0])
|
|
170
|
+
# Do not quietly turn unsupported ranges/relative dates into a current
|
|
171
|
+
# answer or select the first date in a multi-date question.
|
|
172
|
+
unsupported = re.search(
|
|
173
|
+
r"\b(before|after|between|until|through|last (?:week|month|year)|next (?:week|month|year)|"
|
|
174
|
+
r"previous (?:week|month|year)|\d+ (?:weeks?|months?|years?) ago)\b", text, re.I)
|
|
175
|
+
matches = list(re.finditer(_DATE + "|" + _MONTH_DATE + r"|\b(?:today|yesterday|tomorrow)\b", text, re.I))
|
|
176
|
+
if unsupported or len(matches) > 1:
|
|
177
|
+
return MemoryTimeQuery("unresolved_time", expression=text)
|
|
178
|
+
match = re.search(_DATE + "|" + _MONTH_DATE + r"|\b(?:today|yesterday|tomorrow)\b", text, re.I)
|
|
179
|
+
if match:
|
|
180
|
+
expression = match[0]
|
|
181
|
+
if (mode == "valid_range" and expression.lower() in {"today", "tomorrow"}
|
|
182
|
+
and not re.search(r"\b(as of|valid|effective|held|was|were)\b", text, re.I)):
|
|
183
|
+
# "What tea should I bring later today?" asks for a current
|
|
184
|
+
# preference; it does not assert that an undated preference has a
|
|
185
|
+
# certified historical validity interval.
|
|
186
|
+
return MemoryTimeQuery("current", now.astimezone(UTC).isoformat())
|
|
187
|
+
start = parse_source_date(expression, observed_at=now.isoformat(), timezone_name=timezone_name)
|
|
188
|
+
if start:
|
|
189
|
+
begin = utc_timestamp(start)
|
|
190
|
+
if "T" in expression:
|
|
191
|
+
end = (begin + timedelta(microseconds=1)).isoformat()
|
|
192
|
+
else:
|
|
193
|
+
end = (begin.astimezone(zone) + timedelta(days=1)).astimezone(UTC).isoformat()
|
|
194
|
+
if re.search(r"\bsince\s+" + re.escape(expression), text, re.I):
|
|
195
|
+
mode, end = "observed_range", now.astimezone(UTC).isoformat()
|
|
196
|
+
return MemoryTimeQuery(mode, start, end, expression)
|
|
197
|
+
return MemoryTimeQuery("current", now.astimezone(UTC).isoformat())
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def filter_unstructured(rows: list[dict], query: MemoryTimeQuery) -> list[dict]:
|
|
201
|
+
"""Observation questions cannot use write time as evidence of occurrence."""
|
|
202
|
+
if query.mode == "current":
|
|
203
|
+
return rows
|
|
204
|
+
if query.mode == "observed_range":
|
|
205
|
+
return [dict(row, validity_status="source_occurrence_only")
|
|
206
|
+
for row in rows if query.accepts_observation(row.get("occurred_at"))]
|
|
207
|
+
# Source quotations alone do not establish when the asserted fact held.
|
|
208
|
+
return [dict(row, validity_status="unknown") for row in rows]
|
apsimo/beliefs/store.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""BeliefStore -- conflict records, supersession audit, property snapshots."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
import sqlite3
|
|
8
|
+
import threading
|
|
9
|
+
import time
|
|
10
|
+
from typing import Any, Dict, List, Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BeliefStore:
|
|
14
|
+
def __init__(self, db_path: Optional[str] = None) -> None:
|
|
15
|
+
self._lock = threading.RLock()
|
|
16
|
+
self._conn = sqlite3.connect(str(db_path) if db_path else ":memory:",
|
|
17
|
+
check_same_thread=False)
|
|
18
|
+
self._conn.row_factory = sqlite3.Row
|
|
19
|
+
with self._lock:
|
|
20
|
+
self._conn.execute(
|
|
21
|
+
"""CREATE TABLE IF NOT EXISTS conflicts (
|
|
22
|
+
id TEXT PRIMARY KEY, scope TEXT, subject TEXT,
|
|
23
|
+
predicate TEXT, value_a TEXT, value_b TEXT,
|
|
24
|
+
meta_a TEXT, meta_b TEXT,
|
|
25
|
+
status TEXT DEFAULT 'open',
|
|
26
|
+
resolution TEXT, detected_at REAL, resolved_at REAL
|
|
27
|
+
)""")
|
|
28
|
+
self._conn.execute(
|
|
29
|
+
"""CREATE TABLE IF NOT EXISTS supersession_audit (
|
|
30
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
31
|
+
scope TEXT, subject TEXT, predicate TEXT,
|
|
32
|
+
old_value TEXT, new_value TEXT,
|
|
33
|
+
old_confidence REAL, new_confidence REAL,
|
|
34
|
+
reason TEXT, actor TEXT, created_at REAL
|
|
35
|
+
)""")
|
|
36
|
+
self._conn.execute(
|
|
37
|
+
"""CREATE TABLE IF NOT EXISTS property_snapshot (
|
|
38
|
+
entity_id TEXT, key TEXT, value TEXT, confidence REAL,
|
|
39
|
+
updated_at REAL, PRIMARY KEY (entity_id, key)
|
|
40
|
+
)""")
|
|
41
|
+
self._conn.commit()
|
|
42
|
+
|
|
43
|
+
# -- conflicts ---------------------------------------------------------
|
|
44
|
+
@staticmethod
|
|
45
|
+
def conflict_id(scope: str, subject: str, predicate: str,
|
|
46
|
+
value_a: str, value_b: str) -> str:
|
|
47
|
+
basis = "|".join(sorted([str(value_a), str(value_b)])
|
|
48
|
+
+ [scope, subject.lower(), predicate.lower()])
|
|
49
|
+
return "bc-" + hashlib.sha256(basis.encode()).hexdigest()[:12]
|
|
50
|
+
|
|
51
|
+
def record_conflict(self, scope: str, subject: str, predicate: str,
|
|
52
|
+
value_a: str, value_b: str,
|
|
53
|
+
meta_a: Optional[dict] = None,
|
|
54
|
+
meta_b: Optional[dict] = None,
|
|
55
|
+
status: str = "open") -> str:
|
|
56
|
+
cid = self.conflict_id(scope, subject, predicate, value_a, value_b)
|
|
57
|
+
with self._lock:
|
|
58
|
+
self._conn.execute(
|
|
59
|
+
"""INSERT INTO conflicts
|
|
60
|
+
(id, scope, subject, predicate, value_a, value_b,
|
|
61
|
+
meta_a, meta_b, status, detected_at)
|
|
62
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
63
|
+
ON CONFLICT(id) DO NOTHING""",
|
|
64
|
+
(cid, scope, subject[:200], predicate[:120],
|
|
65
|
+
str(value_a)[:300], str(value_b)[:300],
|
|
66
|
+
json.dumps(meta_a or {}), json.dumps(meta_b or {}),
|
|
67
|
+
status, time.time()))
|
|
68
|
+
self._conn.commit()
|
|
69
|
+
return cid
|
|
70
|
+
|
|
71
|
+
def resolve_conflict(self, conflict_id: str, resolution: str,
|
|
72
|
+
status: str = "resolved") -> None:
|
|
73
|
+
with self._lock:
|
|
74
|
+
self._conn.execute(
|
|
75
|
+
"UPDATE conflicts SET status=?, resolution=?, resolved_at=? "
|
|
76
|
+
"WHERE id=?",
|
|
77
|
+
(status, resolution[:400], time.time(), conflict_id))
|
|
78
|
+
self._conn.commit()
|
|
79
|
+
|
|
80
|
+
def conflicts(self, status: Optional[str] = None,
|
|
81
|
+
limit: int = 50) -> List[Dict[str, Any]]:
|
|
82
|
+
q = "SELECT * FROM conflicts"
|
|
83
|
+
params: List[Any] = []
|
|
84
|
+
if status:
|
|
85
|
+
q += " WHERE status=?"; params.append(status)
|
|
86
|
+
q += " ORDER BY detected_at DESC LIMIT ?"; params.append(limit)
|
|
87
|
+
with self._lock:
|
|
88
|
+
rows = self._conn.execute(q, params).fetchall()
|
|
89
|
+
return [dict(r) for r in rows]
|
|
90
|
+
|
|
91
|
+
# -- supersession audit ---------------------------------------------------
|
|
92
|
+
def record_supersession(self, scope: str, subject: str, predicate: str,
|
|
93
|
+
old_value: Any, new_value: Any,
|
|
94
|
+
old_confidence: float, new_confidence: float,
|
|
95
|
+
reason: str, actor: str = "belief_engine") -> None:
|
|
96
|
+
with self._lock:
|
|
97
|
+
self._conn.execute(
|
|
98
|
+
"""INSERT INTO supersession_audit
|
|
99
|
+
(scope, subject, predicate, old_value, new_value,
|
|
100
|
+
old_confidence, new_confidence, reason, actor, created_at)
|
|
101
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
|
102
|
+
(scope, subject[:200], predicate[:120], str(old_value)[:300],
|
|
103
|
+
str(new_value)[:300], old_confidence, new_confidence,
|
|
104
|
+
reason[:300], actor, time.time()))
|
|
105
|
+
self._conn.commit()
|
|
106
|
+
|
|
107
|
+
def supersessions(self, limit: int = 50) -> List[Dict[str, Any]]:
|
|
108
|
+
with self._lock:
|
|
109
|
+
rows = self._conn.execute(
|
|
110
|
+
"SELECT * FROM supersession_audit ORDER BY created_at DESC "
|
|
111
|
+
"LIMIT ?", (limit,)).fetchall()
|
|
112
|
+
return [dict(r) for r in rows]
|
|
113
|
+
|
|
114
|
+
# -- property snapshots (for change/supersession detection) ---------------
|
|
115
|
+
def snapshot_get(self, entity_id: str, key: str) -> Optional[Dict[str, Any]]:
|
|
116
|
+
with self._lock:
|
|
117
|
+
r = self._conn.execute(
|
|
118
|
+
"SELECT * FROM property_snapshot WHERE entity_id=? AND key=?",
|
|
119
|
+
(entity_id, key)).fetchone()
|
|
120
|
+
return dict(r) if r else None
|
|
121
|
+
|
|
122
|
+
def snapshot_put(self, entity_id: str, key: str, value: Any,
|
|
123
|
+
confidence: float) -> None:
|
|
124
|
+
with self._lock:
|
|
125
|
+
self._conn.execute(
|
|
126
|
+
"""INSERT INTO property_snapshot
|
|
127
|
+
(entity_id, key, value, confidence, updated_at)
|
|
128
|
+
VALUES (?, ?, ?, ?, ?)
|
|
129
|
+
ON CONFLICT(entity_id, key) DO UPDATE SET
|
|
130
|
+
value=?, confidence=?, updated_at=?""",
|
|
131
|
+
(entity_id, key, str(value)[:300], confidence, time.time(),
|
|
132
|
+
str(value)[:300], confidence, time.time()))
|
|
133
|
+
self._conn.commit()
|