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,131 @@
|
|
|
1
|
+
"""Causal-edge maintenance primitives (H2.3): contradiction + staleness.
|
|
2
|
+
|
|
3
|
+
Two fabrication controls for the causal layer, consumed by the
|
|
4
|
+
BeliefEngine's periodic run:
|
|
5
|
+
|
|
6
|
+
1. CONTRADICTION: a positive causal claim (WM_CAUSES / WM_ENABLES) and a
|
|
7
|
+
negative one (WM_BLOCKS / WM_INHIBITS) between the SAME ordered entity
|
|
8
|
+
pair cannot both be right. Opposing pairs become conflict rows + review
|
|
9
|
+
initiatives and are NEVER auto-resolved — not at any trust stage, not in
|
|
10
|
+
live mode. Recency/confidence ordering is how belief conflicts are
|
|
11
|
+
settled, but a causal claim is a model of the world, and silently picking
|
|
12
|
+
a winner would let one confidently-worded fabrication erase a true edge.
|
|
13
|
+
A human (or an explicitly owner-approved flow) closes these.
|
|
14
|
+
|
|
15
|
+
2. STALENESS: a causal edge that has gone COLONY_CAUSAL_TTL_DAYS (default
|
|
16
|
+
120) without support (creation or corroboration) loses 0.05 confidence
|
|
17
|
+
per maintenance run, floored at 0.2 — never deleted. Staleness is judged
|
|
18
|
+
by the ``last_support_at`` property (stamped by the extractor on create/
|
|
19
|
+
corroborate) so that the decay write itself cannot reset the clock.
|
|
20
|
+
|
|
21
|
+
This module is pure computation + read-only store access; every WRITE stays
|
|
22
|
+
in the BeliefEngine where it is mode-gated (live/supervised) and journaled.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import logging
|
|
28
|
+
import os
|
|
29
|
+
from datetime import datetime, timezone
|
|
30
|
+
from typing import Any, Dict, List, Tuple
|
|
31
|
+
|
|
32
|
+
from apsimo.world_model.constants import CAUSAL_RELATIONSHIP_TYPES
|
|
33
|
+
|
|
34
|
+
logger = logging.getLogger(__name__)
|
|
35
|
+
|
|
36
|
+
POSITIVE_CAUSAL = frozenset({"WM_CAUSES", "WM_ENABLES"})
|
|
37
|
+
NEGATIVE_CAUSAL = frozenset({"WM_BLOCKS", "WM_INHIBITS"})
|
|
38
|
+
|
|
39
|
+
CAUSAL_DECAY_STEP = 0.05
|
|
40
|
+
CAUSAL_DECAY_FLOOR = 0.2
|
|
41
|
+
|
|
42
|
+
# The property the extractor stamps on every create/corroborate; the decay
|
|
43
|
+
# clock reads it (falling back to updated_at/created_at for pre-existing
|
|
44
|
+
# edges) and deliberately never advances it on a decay write.
|
|
45
|
+
LAST_SUPPORT_PROP = "last_support_at"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def causal_ttl_days() -> float:
|
|
49
|
+
"""COLONY_CAUSAL_TTL_DAYS (default 120): days without support before a
|
|
50
|
+
causal edge starts decaying."""
|
|
51
|
+
try:
|
|
52
|
+
v = float(os.environ.get("COLONY_CAUSAL_TTL_DAYS", "120"))
|
|
53
|
+
return v if v > 0 else 120.0
|
|
54
|
+
except (TypeError, ValueError):
|
|
55
|
+
return 120.0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
async def load_causal_edges(store: Any, limit_per_type: int = 500) -> List[Any]:
|
|
59
|
+
"""All causal edges, via explicitly-typed queries (the only sanctioned
|
|
60
|
+
read path — causal edges are excluded from generic reads by policy)."""
|
|
61
|
+
out: List[Any] = []
|
|
62
|
+
for rel_type in sorted(CAUSAL_RELATIONSHIP_TYPES):
|
|
63
|
+
try:
|
|
64
|
+
rels = await store.query_relationships(
|
|
65
|
+
relationship_type=rel_type, min_confidence=0.0,
|
|
66
|
+
limit=limit_per_type)
|
|
67
|
+
except Exception:
|
|
68
|
+
logger.debug("causal edge load failed for %s", rel_type,
|
|
69
|
+
exc_info=True)
|
|
70
|
+
continue
|
|
71
|
+
out.extend(rels or [])
|
|
72
|
+
return out
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def opposing_pairs(edges: List[Any]) -> List[Tuple[Any, Any]]:
|
|
76
|
+
"""(positive_edge, negative_edge) pairs over the same ordered
|
|
77
|
+
(source_id, target_id) — the causal contradictions. Inactive edges
|
|
78
|
+
(valid_to set) are ignored: a closed edge no longer claims anything."""
|
|
79
|
+
by_pair: Dict[Tuple[str, str], Dict[str, List[Any]]] = {}
|
|
80
|
+
for e in edges:
|
|
81
|
+
if getattr(e, "valid_to", None) is not None:
|
|
82
|
+
continue
|
|
83
|
+
rel = str(getattr(e, "relationship_type", "") or "").upper()
|
|
84
|
+
if rel in POSITIVE_CAUSAL:
|
|
85
|
+
polarity = "pos"
|
|
86
|
+
elif rel in NEGATIVE_CAUSAL:
|
|
87
|
+
polarity = "neg"
|
|
88
|
+
else:
|
|
89
|
+
continue
|
|
90
|
+
key = (str(e.source_id), str(e.target_id))
|
|
91
|
+
by_pair.setdefault(key, {"pos": [], "neg": []})[polarity].append(e)
|
|
92
|
+
pairs: List[Tuple[Any, Any]] = []
|
|
93
|
+
for buckets in by_pair.values():
|
|
94
|
+
for pos in buckets["pos"]:
|
|
95
|
+
for neg in buckets["neg"]:
|
|
96
|
+
pairs.append((pos, neg))
|
|
97
|
+
return pairs
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def support_timestamp(edge: Any) -> str:
|
|
101
|
+
"""The edge's last-support timestamp (ISO8601), preferring the
|
|
102
|
+
extractor-stamped property over store bookkeeping columns."""
|
|
103
|
+
props = getattr(edge, "properties", None) or {}
|
|
104
|
+
return str(props.get(LAST_SUPPORT_PROP)
|
|
105
|
+
or getattr(edge, "updated_at", None)
|
|
106
|
+
or getattr(edge, "created_at", None) or "")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def support_age_days(edge: Any, now: datetime) -> float:
|
|
110
|
+
"""Days since the edge was last supported; 0.0 when unparseable (an
|
|
111
|
+
edge we cannot date is never treated as stale — fail toward keeping)."""
|
|
112
|
+
raw = support_timestamp(edge)
|
|
113
|
+
if not raw:
|
|
114
|
+
return 0.0
|
|
115
|
+
try:
|
|
116
|
+
ts = datetime.fromisoformat(raw.replace("Z", "+00:00"))
|
|
117
|
+
if ts.tzinfo is None:
|
|
118
|
+
ts = ts.replace(tzinfo=timezone.utc)
|
|
119
|
+
return max(0.0, (now - ts).total_seconds() / 86400.0)
|
|
120
|
+
except Exception:
|
|
121
|
+
return 0.0
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def stale_causal_edges(edges: List[Any], now: datetime = None) -> List[Any]:
|
|
125
|
+
"""Causal edges past the TTL that still have confidence to lose."""
|
|
126
|
+
now = now or datetime.now(timezone.utc)
|
|
127
|
+
ttl = causal_ttl_days()
|
|
128
|
+
return [e for e in edges
|
|
129
|
+
if getattr(e, "valid_to", None) is None
|
|
130
|
+
and float(getattr(e, "confidence", 0.0) or 0.0) > CAUSAL_DECAY_FLOOR
|
|
131
|
+
and support_age_days(e, now) > ttl]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Causal-edge policy: causal edges are QUERY-ONLY unless explicitly unlocked.
|
|
2
|
+
|
|
3
|
+
THE INVARIANT
|
|
4
|
+
A causal edge (WM_CAUSES / WM_ENABLES / WM_BLOCKS / WM_INHIBITS, see
|
|
5
|
+
``CAUSAL_RELATIONSHIP_TYPES``) may be stored, corroborated, decayed and
|
|
6
|
+
read back to answer "why" / "what happens if" questions — but it must
|
|
7
|
+
NEVER, on its own, cause Colony to take or schedule an action. An
|
|
8
|
+
inferred "A causes B" is a belief about the world, not an instruction;
|
|
9
|
+
acting on a fabricated or stale causal edge is exactly the failure mode
|
|
10
|
+
this module exists to prevent.
|
|
11
|
+
|
|
12
|
+
Every consumer that reads causal edges and could turn them into behavior
|
|
13
|
+
(planners, initiative generators, directed actions) MUST gate that path on
|
|
14
|
+
``causal_edges_actionable()``. The flag COLONY_CAUSAL_ACT defaults to off,
|
|
15
|
+
so the invariant holds by default; flipping it is an explicit owner
|
|
16
|
+
decision, revertible via env alone.
|
|
17
|
+
|
|
18
|
+
This module is intentionally tiny and dependency-free so any layer can
|
|
19
|
+
import it without cycles.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import os
|
|
25
|
+
|
|
26
|
+
from apsimo.world_model.constants import CAUSAL_RELATIONSHIP_TYPES
|
|
27
|
+
|
|
28
|
+
__all__ = ["CAUSAL_RELATIONSHIP_TYPES", "causal_edges_actionable", "is_causal"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def causal_edges_actionable() -> bool:
|
|
32
|
+
"""May causal edges influence ACTIONS (not just answers)? Default no.
|
|
33
|
+
|
|
34
|
+
COLONY_CAUSAL_ACT=1 is the only unlock; anything else (unset, 0, junk)
|
|
35
|
+
keeps causal edges query-only.
|
|
36
|
+
"""
|
|
37
|
+
return os.environ.get("COLONY_CAUSAL_ACT", "0").strip().lower() in (
|
|
38
|
+
"1", "true", "yes", "on")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def is_causal(rel_type: str) -> bool:
|
|
42
|
+
"""True when ``rel_type`` is one of the causal relationship types."""
|
|
43
|
+
return str(rel_type or "").strip().upper() in CAUSAL_RELATIONSHIP_TYPES
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""Read-only causal-chain query — the sanctioned way to READ causal edges.
|
|
2
|
+
|
|
3
|
+
Causal edges are query-only by policy (world_model/causal_policy.py) and are
|
|
4
|
+
excluded from every generic graph read path: the ONLY surfaces that return
|
|
5
|
+
them are the /world/causal/* endpoints (built on this module) and
|
|
6
|
+
explicitly-typed relationship queries. This module answers "why" / "what
|
|
7
|
+
happens if" questions by walking causal edges alone; it never writes and
|
|
8
|
+
never feeds an action path.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
from typing import Any, Dict, List
|
|
15
|
+
|
|
16
|
+
from apsimo.world_model.constants import CAUSAL_RELATIONSHIP_TYPES
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
_DIRECTIONS = ("downstream", "upstream", "both")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _edge_dict(rel: Any) -> Dict[str, Any]:
|
|
24
|
+
props = getattr(rel, "properties", None) or {}
|
|
25
|
+
return {
|
|
26
|
+
"id": rel.id,
|
|
27
|
+
"source_id": rel.source_id,
|
|
28
|
+
"target_id": rel.target_id,
|
|
29
|
+
"relationship_type": rel.relationship_type,
|
|
30
|
+
"confidence": rel.confidence,
|
|
31
|
+
"is_active": bool(getattr(rel, "is_active", rel.valid_to is None)),
|
|
32
|
+
"evidence": props.get("evidence"),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
async def causal_chain(
|
|
37
|
+
store: Any,
|
|
38
|
+
entity_id: str,
|
|
39
|
+
direction: str = "downstream",
|
|
40
|
+
max_hops: int = 3,
|
|
41
|
+
min_confidence: float = 0.0,
|
|
42
|
+
max_edges: int = 100,
|
|
43
|
+
) -> Dict[str, Any]:
|
|
44
|
+
"""BFS over causal edges only (explicitly typed queries, so the generic
|
|
45
|
+
read-path exclusion does not apply here — by construction).
|
|
46
|
+
|
|
47
|
+
direction: downstream = effects of entity_id; upstream = its causes;
|
|
48
|
+
both = the full causal neighborhood.
|
|
49
|
+
"""
|
|
50
|
+
if direction not in _DIRECTIONS:
|
|
51
|
+
direction = "downstream"
|
|
52
|
+
max_hops = max(1, min(int(max_hops), 5))
|
|
53
|
+
|
|
54
|
+
edges: Dict[str, Dict[str, Any]] = {}
|
|
55
|
+
visited: Dict[str, int] = {entity_id: 0}
|
|
56
|
+
frontier = [entity_id]
|
|
57
|
+
truncated = False
|
|
58
|
+
|
|
59
|
+
for hop in range(max_hops):
|
|
60
|
+
next_frontier: List[str] = []
|
|
61
|
+
for eid in frontier:
|
|
62
|
+
for rel_type in sorted(CAUSAL_RELATIONSHIP_TYPES):
|
|
63
|
+
queries = []
|
|
64
|
+
if direction in ("downstream", "both"):
|
|
65
|
+
queries.append({"source_id": eid})
|
|
66
|
+
if direction in ("upstream", "both"):
|
|
67
|
+
queries.append({"target_id": eid})
|
|
68
|
+
for q in queries:
|
|
69
|
+
rels = await store.query_relationships(
|
|
70
|
+
relationship_type=rel_type,
|
|
71
|
+
min_confidence=min_confidence, limit=50, **q)
|
|
72
|
+
for rel in rels:
|
|
73
|
+
if rel.id in edges:
|
|
74
|
+
continue
|
|
75
|
+
if len(edges) >= max_edges:
|
|
76
|
+
truncated = True
|
|
77
|
+
break
|
|
78
|
+
edges[rel.id] = _edge_dict(rel)
|
|
79
|
+
other = (rel.target_id if rel.source_id == eid
|
|
80
|
+
else rel.source_id)
|
|
81
|
+
if other not in visited:
|
|
82
|
+
visited[other] = hop + 1
|
|
83
|
+
next_frontier.append(other)
|
|
84
|
+
if truncated:
|
|
85
|
+
break
|
|
86
|
+
if truncated:
|
|
87
|
+
break
|
|
88
|
+
if truncated:
|
|
89
|
+
break
|
|
90
|
+
if truncated or not next_frontier:
|
|
91
|
+
break
|
|
92
|
+
frontier = next_frontier
|
|
93
|
+
|
|
94
|
+
nodes: Dict[str, Dict[str, Any]] = {}
|
|
95
|
+
for eid in visited:
|
|
96
|
+
try:
|
|
97
|
+
ent = await store.get_entity(eid, min_confidence=0.0)
|
|
98
|
+
except Exception:
|
|
99
|
+
ent = None
|
|
100
|
+
if ent is not None:
|
|
101
|
+
nodes[eid] = {"name": ent.name, "entity_type": ent.entity_type,
|
|
102
|
+
"hops": visited[eid]}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
"entity_id": entity_id,
|
|
106
|
+
"direction": direction,
|
|
107
|
+
"max_hops": max_hops,
|
|
108
|
+
"edges": list(edges.values()),
|
|
109
|
+
"nodes": nodes,
|
|
110
|
+
"truncated": truncated,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
async def causal_edges(store: Any, min_confidence: float = 0.0,
|
|
115
|
+
limit: int = 100) -> List[Dict[str, Any]]:
|
|
116
|
+
"""Flat list of causal edges (explicitly typed queries per causal type)."""
|
|
117
|
+
out: List[Dict[str, Any]] = []
|
|
118
|
+
for rel_type in sorted(CAUSAL_RELATIONSHIP_TYPES):
|
|
119
|
+
rels = await store.query_relationships(
|
|
120
|
+
relationship_type=rel_type, min_confidence=min_confidence,
|
|
121
|
+
limit=limit)
|
|
122
|
+
out.extend(_edge_dict(r) for r in rels)
|
|
123
|
+
if len(out) >= limit:
|
|
124
|
+
break
|
|
125
|
+
return out[:limit]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Confidence scoring for World Model entities and properties."""
|
|
2
|
+
|
|
3
|
+
# Confidence initialization rules (entity-level)
|
|
4
|
+
CONFIDENCE_BY_SOURCE = {
|
|
5
|
+
"structured_import": 0.95, # calendar sync, contact import — highly reliable
|
|
6
|
+
"document_extraction": 0.70, # named entity from PDF, email body
|
|
7
|
+
"conversation_ner": 0.55, # NER from message text
|
|
8
|
+
"inferred": 0.30, # deduced from context, not explicitly stated
|
|
9
|
+
"unverified_mention": 0.20, # single passing mention
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
# Confidence boost per corroborating observation
|
|
13
|
+
CORROBORATION_BOOST = 0.05
|
|
14
|
+
|
|
15
|
+
# Confidence ceiling
|
|
16
|
+
MAX_CONFIDENCE = 0.98
|
|
17
|
+
|
|
18
|
+
# Minimum confidence for an entity to appear in query results by default
|
|
19
|
+
DEFAULT_CONFIDENCE_THRESHOLD = 0.30
|
|
20
|
+
|
|
21
|
+
# Minimum confidence for storage
|
|
22
|
+
MIN_CONFIDENCE_FOR_STORAGE = 0.20
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def compute_property_confidence(
|
|
26
|
+
extraction_source: str,
|
|
27
|
+
corroboration_count: int = 0,
|
|
28
|
+
) -> float:
|
|
29
|
+
"""Compute property-level confidence from source and corroboration.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
extraction_source: Source type key from CONFIDENCE_BY_SOURCE.
|
|
33
|
+
corroboration_count: Number of additional observations corroborating this value.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Confidence in [0.0, MAX_CONFIDENCE].
|
|
37
|
+
"""
|
|
38
|
+
base = CONFIDENCE_BY_SOURCE.get(extraction_source, 0.30)
|
|
39
|
+
boosted = base + corroboration_count * CORROBORATION_BOOST
|
|
40
|
+
return min(boosted, MAX_CONFIDENCE)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def boost_confidence(current: float, amount: float = CORROBORATION_BOOST) -> float:
|
|
44
|
+
"""Boost confidence by amount, capped at MAX_CONFIDENCE."""
|
|
45
|
+
return min(current + amount, MAX_CONFIDENCE)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def apply_extraction_adjustments(base_confidence: float, adjustments: list[float]) -> float:
|
|
49
|
+
"""Apply a list of signed confidence adjustments to a base value.
|
|
50
|
+
|
|
51
|
+
Clamps result to [0.0, MAX_CONFIDENCE].
|
|
52
|
+
"""
|
|
53
|
+
result = base_confidence + sum(adjustments)
|
|
54
|
+
return max(0.0, min(result, MAX_CONFIDENCE))
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""World Model configuration dataclass."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _default_sqlite_path() -> str:
|
|
9
|
+
"""State-dir-anchored default (env-overridable via
|
|
10
|
+
WORLD_MODEL_SQLITE_PATH). A bare cwd-relative filename made the store
|
|
11
|
+
land wherever the process happened to start (a git checkout, on the
|
|
12
|
+
reference deployment), which is fragile across restarts and updates."""
|
|
13
|
+
explicit = os.environ.get("WORLD_MODEL_SQLITE_PATH", "").strip()
|
|
14
|
+
if explicit:
|
|
15
|
+
return explicit
|
|
16
|
+
state_dir = os.environ.get("COLONY_STATE_DIR", "").strip()
|
|
17
|
+
if state_dir:
|
|
18
|
+
return os.path.join(state_dir, "colony_world_model.db")
|
|
19
|
+
return "colony_world_model.db"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class WorldModelConfig:
|
|
24
|
+
# ── Feature flags ──────────────────────────────────────────────────
|
|
25
|
+
enabled: bool = True
|
|
26
|
+
auto_extract_conversations: bool = True
|
|
27
|
+
auto_extract_documents: bool = True
|
|
28
|
+
structured_import_enabled: bool = True
|
|
29
|
+
entity_resolution_enabled: bool = True
|
|
30
|
+
|
|
31
|
+
# ── Backend ────────────────────────────────────────────────────────
|
|
32
|
+
# SQLite supports canonical typed observations. Alternate backends retain
|
|
33
|
+
# only the legacy entity/relationship graph, not observation parity.
|
|
34
|
+
backend: str = "sqlite" # "sqlite" | "neo4j" | "postgres"
|
|
35
|
+
neo4j_uri: str = "bolt://localhost:7687"
|
|
36
|
+
neo4j_database: str = "neo4j"
|
|
37
|
+
sqlite_path: str = field(default_factory=_default_sqlite_path)
|
|
38
|
+
|
|
39
|
+
# ── Confidence thresholds ──────────────────────────────────────────
|
|
40
|
+
min_confidence_for_storage: float = 0.20
|
|
41
|
+
min_confidence_for_query: float = 0.30
|
|
42
|
+
auto_merge_confidence_threshold: float = 0.85
|
|
43
|
+
propose_merge_confidence_threshold: float = 0.70
|
|
44
|
+
|
|
45
|
+
# ── Resolution ─────────────────────────────────────────────────────
|
|
46
|
+
string_similarity_auto_merge: float = 0.92
|
|
47
|
+
string_similarity_propose: float = 0.75
|
|
48
|
+
|
|
49
|
+
# ── Extraction ─────────────────────────────────────────────────────
|
|
50
|
+
max_extraction_ms: int = 50 # per-message budget
|
|
51
|
+
min_message_length_for_extraction: int = 20
|
|
52
|
+
extraction_spacy_model: str = "en_core_web_sm"
|
|
53
|
+
|
|
54
|
+
# ── Graph traversal ────────────────────────────────────────────────
|
|
55
|
+
max_graph_hops: int = 5
|
|
56
|
+
default_graph_hops: int = 2
|
|
57
|
+
max_traversal_nodes: int = 200
|
|
58
|
+
|
|
59
|
+
# ── Retention ─────────────────────────────────────────────────────
|
|
60
|
+
low_confidence_entity_ttl_days: int = 90
|
|
61
|
+
merge_proposal_expiry_days: int = 30
|
|
62
|
+
|
|
63
|
+
# ── Briefing limits ────────────────────────────────────────────────
|
|
64
|
+
max_world_model_briefing_items_per_day: int = 3
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""World Model constants: entity types, relationship types, external ID keys."""
|
|
2
|
+
|
|
3
|
+
# ── Entity Types ──────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
ENTITY_TYPES = frozenset({
|
|
6
|
+
"person",
|
|
7
|
+
"company",
|
|
8
|
+
"project",
|
|
9
|
+
"product",
|
|
10
|
+
"location",
|
|
11
|
+
"event",
|
|
12
|
+
"concept",
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
# ── Relationship Types (WM_ prefixed for Neo4j namespace safety) ──────────────
|
|
16
|
+
|
|
17
|
+
RELATIONSHIP_TYPES = frozenset({
|
|
18
|
+
"WM_WORKS_AT",
|
|
19
|
+
"WM_FOUNDED",
|
|
20
|
+
"WM_OWNS",
|
|
21
|
+
"WM_INVESTED_IN",
|
|
22
|
+
"WM_ADVISES",
|
|
23
|
+
"WM_MANAGES",
|
|
24
|
+
"WM_REPORTS_TO",
|
|
25
|
+
"WM_KNOWS",
|
|
26
|
+
"WM_INTRODUCED_BY", # provenance: who introduced this person to the agent's graph
|
|
27
|
+
"WM_PARTNER_OF",
|
|
28
|
+
"WM_ACQUIRED",
|
|
29
|
+
"WM_PART_OF",
|
|
30
|
+
"WM_LOCATED_IN",
|
|
31
|
+
"WM_MEMBER_OF",
|
|
32
|
+
"WM_ATTENDED",
|
|
33
|
+
"WM_ORGANIZED",
|
|
34
|
+
"WM_PRODUCED",
|
|
35
|
+
"WM_USES",
|
|
36
|
+
"WM_RELATED_TO",
|
|
37
|
+
"WM_TAGGED_WITH",
|
|
38
|
+
"WM_MENTIONS",
|
|
39
|
+
"WM_PREDECESSOR_OF",
|
|
40
|
+
"WM_SUCCESSOR_OF",
|
|
41
|
+
"WM_DEPENDS_ON",
|
|
42
|
+
# Causal vocabulary (query-only; see world_model/causal_policy.py)
|
|
43
|
+
"WM_CAUSES",
|
|
44
|
+
"WM_ENABLES",
|
|
45
|
+
"WM_BLOCKS",
|
|
46
|
+
"WM_INHIBITS",
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
# ── Causal Relationship Types ─────────────────────────────────────────────────
|
|
50
|
+
# The causal subset of RELATIONSHIP_TYPES. Causal edges are QUERY-ONLY by
|
|
51
|
+
# policy: they may inform answers to "why"/"what happens if" questions but
|
|
52
|
+
# must never trigger actions unless world_model.causal_policy explicitly
|
|
53
|
+
# says otherwise (COLONY_CAUSAL_ACT, default off).
|
|
54
|
+
|
|
55
|
+
CAUSAL_RELATIONSHIP_TYPES = frozenset({
|
|
56
|
+
"WM_CAUSES", # A brings about B
|
|
57
|
+
"WM_ENABLES", # A makes B possible (necessary-ish precondition)
|
|
58
|
+
"WM_BLOCKS", # A prevents B outright
|
|
59
|
+
"WM_INHIBITS", # A makes B less likely / weaker
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
# ── External ID Keys ──────────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
EXTERNAL_ID_KEYS = {
|
|
65
|
+
# People
|
|
66
|
+
"linkedin": "LinkedIn profile URL or ID",
|
|
67
|
+
"email": "Primary email address",
|
|
68
|
+
"phone": "E.164 phone number",
|
|
69
|
+
"twitter": "Twitter/X handle",
|
|
70
|
+
|
|
71
|
+
# Companies
|
|
72
|
+
"crunchbase": "Crunchbase organization slug",
|
|
73
|
+
"linkedin_company": "LinkedIn company ID",
|
|
74
|
+
"ticker": "Stock ticker symbol",
|
|
75
|
+
"domain": "Primary web domain",
|
|
76
|
+
"lei": "Legal Entity Identifier (ISO 17442)",
|
|
77
|
+
|
|
78
|
+
# Events
|
|
79
|
+
"calendar_uid": "iCal UID from calendar source",
|
|
80
|
+
"eventbrite": "Eventbrite event ID",
|
|
81
|
+
|
|
82
|
+
# Products
|
|
83
|
+
"app_store_id": "Apple App Store bundle ID",
|
|
84
|
+
"play_store_id": "Google Play package name",
|
|
85
|
+
|
|
86
|
+
# Locations
|
|
87
|
+
"geonames_id": "GeoNames feature ID",
|
|
88
|
+
"osm_id": "OpenStreetMap node/way/relation ID",
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# ── ID Prefixes ───────────────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
ENTITY_ID_PREFIX = "we" # world entity
|
|
94
|
+
RELATIONSHIP_ID_PREFIX = "wr" # world relationship
|
|
95
|
+
OBSERVATION_ID_PREFIX = "wo" # world observation
|
|
96
|
+
MERGE_PROPOSAL_ID_PREFIX = "mp" # merge proposal
|
|
97
|
+
MERGE_AUDIT_ID_PREFIX = "ma" # merge audit record
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""World Model entity dataclasses.
|
|
2
|
+
|
|
3
|
+
Seven entity types form Colony's world model:
|
|
4
|
+
Person, Company, Project, Product, Location, Event, Concept
|
|
5
|
+
|
|
6
|
+
All share BaseEntity fields. Each adds domain-specific properties.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import Any, Dict, List, Optional, Union
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class BaseEntity:
|
|
16
|
+
"""Common properties for all world model entities."""
|
|
17
|
+
id: str # we-<timestamp>-<random7>
|
|
18
|
+
name: str # canonical display name
|
|
19
|
+
entity_type: str # EntityType literal
|
|
20
|
+
aliases: List[str] = field(default_factory=list)
|
|
21
|
+
external_ids: Dict[str, str] = field(default_factory=dict)
|
|
22
|
+
confidence: float = 0.5 # 0.0–1.0 overall entity confidence
|
|
23
|
+
properties: Dict[str, Any] = field(default_factory=dict)
|
|
24
|
+
first_seen: Optional[datetime] = None
|
|
25
|
+
last_seen: Optional[datetime] = None
|
|
26
|
+
created_at: Optional[datetime] = None
|
|
27
|
+
updated_at: Optional[datetime] = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class PersonEntity(BaseEntity):
|
|
32
|
+
"""A person Colony has encountered or knows about."""
|
|
33
|
+
entity_type: str = "person"
|
|
34
|
+
email: Optional[str] = None
|
|
35
|
+
phone: Optional[str] = None
|
|
36
|
+
title: Optional[str] = None # "CTO", "Engineer"
|
|
37
|
+
bio_summary: Optional[str] = None
|
|
38
|
+
linkedin_url: Optional[str] = None
|
|
39
|
+
twitter_handle: Optional[str] = None
|
|
40
|
+
location_id: Optional[str] = None # FK to LocationEntity
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class CompanyEntity(BaseEntity):
|
|
45
|
+
"""An organization of any kind."""
|
|
46
|
+
entity_type: str = "company"
|
|
47
|
+
domain: Optional[str] = None # "acme.com"
|
|
48
|
+
industry: Optional[str] = None # "SaaS", "Healthcare"
|
|
49
|
+
size_range: Optional[str] = None # "1-10", "11-50", "51-200", "201-1000", "1000+"
|
|
50
|
+
founded_year: Optional[int] = None
|
|
51
|
+
headquarters_id: Optional[str] = None # FK to LocationEntity
|
|
52
|
+
linkedin_url: Optional[str] = None
|
|
53
|
+
crunchbase_url: Optional[str] = None
|
|
54
|
+
ticker: Optional[str] = None # "AAPL", "GOOG"
|
|
55
|
+
description: Optional[str] = None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class ProjectEntity(BaseEntity):
|
|
60
|
+
"""A bounded initiative with participants and a goal."""
|
|
61
|
+
entity_type: str = "project"
|
|
62
|
+
description: Optional[str] = None
|
|
63
|
+
status: Optional[str] = None # "active", "completed", "paused", "cancelled"
|
|
64
|
+
start_date: Optional[str] = None # ISO8601
|
|
65
|
+
end_date: Optional[str] = None # ISO8601; None = ongoing
|
|
66
|
+
owner_id: Optional[str] = None # FK to PersonEntity
|
|
67
|
+
company_id: Optional[str] = None # FK to CompanyEntity
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class ProductEntity(BaseEntity):
|
|
72
|
+
"""A product, service, or software artifact."""
|
|
73
|
+
entity_type: str = "product"
|
|
74
|
+
category: Optional[str] = None # "SaaS", "hardware", "API"
|
|
75
|
+
version: Optional[str] = None
|
|
76
|
+
url: Optional[str] = None
|
|
77
|
+
company_id: Optional[str] = None # FK to CompanyEntity
|
|
78
|
+
description: Optional[str] = None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass
|
|
82
|
+
class LocationEntity(BaseEntity):
|
|
83
|
+
"""A geographic or virtual place."""
|
|
84
|
+
entity_type: str = "location"
|
|
85
|
+
location_type: Optional[str] = None # "city", "country", "office", "virtual"
|
|
86
|
+
city: Optional[str] = None
|
|
87
|
+
country: Optional[str] = None
|
|
88
|
+
latitude: Optional[float] = None
|
|
89
|
+
longitude: Optional[float] = None
|
|
90
|
+
timezone: Optional[str] = None # "America/Los_Angeles"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass
|
|
94
|
+
class EventEntity(BaseEntity):
|
|
95
|
+
"""A time-bounded occurrence."""
|
|
96
|
+
entity_type: str = "event"
|
|
97
|
+
event_type: Optional[str] = None # "meeting", "conference", "deadline", "launch"
|
|
98
|
+
start_time: Optional[str] = None # ISO8601
|
|
99
|
+
end_time: Optional[str] = None # ISO8601
|
|
100
|
+
location_id: Optional[str] = None
|
|
101
|
+
organizer_id: Optional[str] = None # FK to PersonEntity or CompanyEntity
|
|
102
|
+
url: Optional[str] = None
|
|
103
|
+
description: Optional[str] = None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@dataclass
|
|
107
|
+
class ConceptEntity(BaseEntity):
|
|
108
|
+
"""An abstract topic, technology, or category."""
|
|
109
|
+
entity_type: str = "concept"
|
|
110
|
+
concept_type: Optional[str] = None # "technology", "methodology", "regulation", "topic"
|
|
111
|
+
description: Optional[str] = None
|
|
112
|
+
parent_concept_id: Optional[str] = None # for hierarchical concepts
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# Type union for all entity types
|
|
116
|
+
EntityType = (
|
|
117
|
+
Union[PersonEntity, CompanyEntity, ProjectEntity,
|
|
118
|
+
ProductEntity, LocationEntity, EventEntity, ConceptEntity]
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Map from entity_type string to dataclass
|
|
122
|
+
ENTITY_CLASS_MAP: Dict[str, type] = {
|
|
123
|
+
"person": PersonEntity,
|
|
124
|
+
"company": CompanyEntity,
|
|
125
|
+
"project": ProjectEntity,
|
|
126
|
+
"product": ProductEntity,
|
|
127
|
+
"location": LocationEntity,
|
|
128
|
+
"event": EventEntity,
|
|
129
|
+
"concept": ConceptEntity,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def entity_from_dict(data: Dict[str, Any]) -> BaseEntity:
|
|
134
|
+
"""Reconstruct an entity from a flat dict (e.g., from SQLite row).
|
|
135
|
+
|
|
136
|
+
Maps 'entity_type' to the appropriate subclass and constructs it.
|
|
137
|
+
Unknown types fall back to BaseEntity.
|
|
138
|
+
"""
|
|
139
|
+
entity_type = data.get("entity_type", "")
|
|
140
|
+
cls = ENTITY_CLASS_MAP.get(entity_type, BaseEntity)
|
|
141
|
+
# Filter data keys to only those accepted by the dataclass
|
|
142
|
+
import dataclasses
|
|
143
|
+
valid_fields = {f.name for f in dataclasses.fields(cls)}
|
|
144
|
+
filtered = {k: v for k, v in data.items() if k in valid_fields}
|
|
145
|
+
return cls(**filtered)
|