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,547 @@
|
|
|
1
|
+
"""MetaLearner - orchestrates cognitive performance tracking and self-improvement."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Callable, List, Optional, Dict, Any, TYPE_CHECKING
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
import time
|
|
9
|
+
|
|
10
|
+
from .types import GapSeverity
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from apsimo.vector.embedder import EmbeddingPipeline
|
|
14
|
+
from apsimo.vector.store import VectorStore
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class CycleResult:
|
|
19
|
+
"""Result of a complete cognition cycle."""
|
|
20
|
+
cpi: Optional["CognitivePerformanceIndex"]
|
|
21
|
+
gaps: List["Gap"]
|
|
22
|
+
adjustments: List["Adjustment"]
|
|
23
|
+
duration_ms: float
|
|
24
|
+
errors: List[str]
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def has_critical_gaps(self) -> bool:
|
|
28
|
+
return any(g.severity == GapSeverity.CRITICAL for g in self.gaps) if self.gaps else False
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class MetaLearnerConfig:
|
|
33
|
+
"""Configuration for MetaLearner behavior."""
|
|
34
|
+
metrics_lookback_days: int = 7
|
|
35
|
+
min_cpi_threshold: float = 50.0
|
|
36
|
+
max_adjustments_per_cycle: int = 3
|
|
37
|
+
persist_to_graph: bool = True
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
logger = __import__('logging').getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class MetaLearner:
|
|
44
|
+
"""Orchestrates cognitive performance tracking and self-improvement."""
|
|
45
|
+
|
|
46
|
+
def __init__(self, graph: "ColonyGraph", config: Optional[MetaLearnerConfig] = None):
|
|
47
|
+
self.graph = graph
|
|
48
|
+
self.config = config or MetaLearnerConfig()
|
|
49
|
+
|
|
50
|
+
# Sub-components (loaded lazily)
|
|
51
|
+
self._metrics_collector = None
|
|
52
|
+
self._performance_index = None
|
|
53
|
+
self._gap_detector = None
|
|
54
|
+
self._strategy_adjuster = None
|
|
55
|
+
|
|
56
|
+
# Optional FeedbackStore for consuming user corrections
|
|
57
|
+
self._feedback_store: Optional[Any] = None
|
|
58
|
+
|
|
59
|
+
# Vector store + embedder for cognition pattern matching (§6.2)
|
|
60
|
+
self._vector_store: Optional["VectorStore"] = None
|
|
61
|
+
self._embedder: Optional["EmbeddingPipeline"] = None
|
|
62
|
+
|
|
63
|
+
# Hooks for external metric recording
|
|
64
|
+
self._metric_hooks: List[Callable[..., None]] = []
|
|
65
|
+
|
|
66
|
+
# Counter incremented on each persistence failure for observability
|
|
67
|
+
self._persist_errors: int = 0
|
|
68
|
+
|
|
69
|
+
# Dedup / throttle state
|
|
70
|
+
self._last_persisted_cpi: Optional[float] = None # overall score of last persisted CPI
|
|
71
|
+
self._cycle_count: int = 0 # total run_cycle() calls; persist summary every 10th
|
|
72
|
+
self._open_gap_types: set = set() # gap_type values with an open Gap node in graph
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def is_fully_wired(self) -> bool:
|
|
76
|
+
"""Check if all sub-components are available."""
|
|
77
|
+
return all([
|
|
78
|
+
self._performance_index is not None,
|
|
79
|
+
self._gap_detector is not None,
|
|
80
|
+
self._strategy_adjuster is not None,
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def available_components(self) -> List[str]:
|
|
85
|
+
"""List which sub-components are available."""
|
|
86
|
+
components = []
|
|
87
|
+
if self._metrics_collector:
|
|
88
|
+
components.append("metrics_collector")
|
|
89
|
+
if self._performance_index:
|
|
90
|
+
components.append("performance_index")
|
|
91
|
+
if self._gap_detector:
|
|
92
|
+
components.append("gap_detector")
|
|
93
|
+
if self._strategy_adjuster:
|
|
94
|
+
components.append("strategy_adjuster")
|
|
95
|
+
return components
|
|
96
|
+
|
|
97
|
+
# Component setters for dependency injection
|
|
98
|
+
def set_metrics_collector(self, collector: "MetricsCollector") -> None:
|
|
99
|
+
self._metrics_collector = collector
|
|
100
|
+
|
|
101
|
+
def set_performance_index(self, computer: "PerformanceIndexComputer") -> None:
|
|
102
|
+
self._performance_index = computer
|
|
103
|
+
|
|
104
|
+
def set_gap_detector(self, detector: "GapDetector") -> None:
|
|
105
|
+
self._gap_detector = detector
|
|
106
|
+
|
|
107
|
+
def set_strategy_adjuster(self, adjuster: "StrategyAdjuster") -> None:
|
|
108
|
+
self._strategy_adjuster = adjuster
|
|
109
|
+
|
|
110
|
+
def set_feedback_store(self, store: Any) -> None:
|
|
111
|
+
"""Wire a FeedbackStore so MetaLearner consumes user corrections each cycle."""
|
|
112
|
+
self._feedback_store = store
|
|
113
|
+
|
|
114
|
+
def set_vector_store(self, store: "VectorStore", embedder: "EmbeddingPipeline") -> None:
|
|
115
|
+
"""Wire vector store + embedder for cognition pattern matching."""
|
|
116
|
+
self._vector_store = store
|
|
117
|
+
self._embedder = embedder
|
|
118
|
+
|
|
119
|
+
def register_metric_hook(self, hook: Callable[..., None]) -> None:
|
|
120
|
+
"""Register a callback to receive metrics."""
|
|
121
|
+
self._metric_hooks.append(hook)
|
|
122
|
+
|
|
123
|
+
async def record_metric(self, metric_type: str, value: float, domain: str = "general") -> None:
|
|
124
|
+
"""Record a metric value."""
|
|
125
|
+
if self._metrics_collector:
|
|
126
|
+
await self._metrics_collector.record(metric_type, value, domain)
|
|
127
|
+
|
|
128
|
+
# Also notify hooks
|
|
129
|
+
for hook in self._metric_hooks:
|
|
130
|
+
try:
|
|
131
|
+
hook(metric_type, value, domain)
|
|
132
|
+
except Exception as exc:
|
|
133
|
+
logger.warning(
|
|
134
|
+
"MetaLearner: metric hook %r raised (hook will be skipped): %s",
|
|
135
|
+
getattr(hook, "__name__", hook),
|
|
136
|
+
exc,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
async def evaluate(self) -> "CognitivePerformanceIndex":
|
|
140
|
+
"""Compute current Cognitive Performance Index."""
|
|
141
|
+
if not self._performance_index:
|
|
142
|
+
logger.warning("MetaLearner.evaluate: PerformanceIndexComputer not wired — CPI unavailable")
|
|
143
|
+
from apsimo.intelligence.cognition.performance_index import CognitivePerformanceIndex, CPIComponent
|
|
144
|
+
now = datetime.now(timezone.utc)
|
|
145
|
+
default_comp = CPIComponent(
|
|
146
|
+
name="unavailable", score=0.0, trend="unavailable",
|
|
147
|
+
metrics={"available": False, "deprecated": True},
|
|
148
|
+
available=False)
|
|
149
|
+
return CognitivePerformanceIndex(
|
|
150
|
+
retrieval=default_comp, prediction=default_comp,
|
|
151
|
+
goal_progress=default_comp, tool_efficiency=default_comp,
|
|
152
|
+
initiative=default_comp, response_quality=default_comp,
|
|
153
|
+
overall=0.0, computed_at=now, deprecated=True,
|
|
154
|
+
available_components=[],
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
cpi = await self._performance_index.compute(self._metrics_collector)
|
|
158
|
+
|
|
159
|
+
# Persist to graph
|
|
160
|
+
if self.config.persist_to_graph:
|
|
161
|
+
await self._persist_cpi(cpi)
|
|
162
|
+
|
|
163
|
+
return cpi
|
|
164
|
+
|
|
165
|
+
async def detect_gaps(self, cpi: Optional["CognitivePerformanceIndex"] = None) -> List["Gap"]:
|
|
166
|
+
"""Detect performance gaps from CPI."""
|
|
167
|
+
if not self._gap_detector:
|
|
168
|
+
raise RuntimeError("GapDetector not wired")
|
|
169
|
+
|
|
170
|
+
if cpi is None:
|
|
171
|
+
cpi = await self.evaluate()
|
|
172
|
+
|
|
173
|
+
gaps = self._gap_detector.detect(cpi)
|
|
174
|
+
|
|
175
|
+
# Sort by severity
|
|
176
|
+
severity_order = {GapSeverity.CRITICAL: 0, GapSeverity.WARNING: 1, GapSeverity.INFO: 2}
|
|
177
|
+
gaps.sort(key=lambda g: severity_order.get(g.severity, 99))
|
|
178
|
+
|
|
179
|
+
# Persist gaps to graph
|
|
180
|
+
if self.config.persist_to_graph:
|
|
181
|
+
for gap in gaps:
|
|
182
|
+
await self._persist_gap(gap)
|
|
183
|
+
|
|
184
|
+
return gaps
|
|
185
|
+
|
|
186
|
+
async def adjust_strategy(self, gap: "Gap") -> "Adjustment":
|
|
187
|
+
"""Generate and apply strategy adjustment for a gap."""
|
|
188
|
+
if not self._strategy_adjuster:
|
|
189
|
+
raise RuntimeError("StrategyAdjuster not wired")
|
|
190
|
+
|
|
191
|
+
adjustment = await self._strategy_adjuster.generate(gap)
|
|
192
|
+
|
|
193
|
+
# Apply the adjustment
|
|
194
|
+
await self._strategy_adjuster.apply(adjustment)
|
|
195
|
+
|
|
196
|
+
# Persist to graph — pass the source gap for relationship creation
|
|
197
|
+
if self.config.persist_to_graph:
|
|
198
|
+
await self._persist_adjustment(adjustment, gap)
|
|
199
|
+
|
|
200
|
+
return adjustment
|
|
201
|
+
|
|
202
|
+
async def run_cycle(self) -> CycleResult:
|
|
203
|
+
"""Execute full cognition cycle: evaluate → detect → adjust."""
|
|
204
|
+
self._cycle_count += 1
|
|
205
|
+
start_time = time.time()
|
|
206
|
+
cpi = None
|
|
207
|
+
gaps = []
|
|
208
|
+
adjustments = []
|
|
209
|
+
errors = []
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
# 1. Evaluate current performance
|
|
213
|
+
cpi = await self.evaluate()
|
|
214
|
+
except Exception as e:
|
|
215
|
+
msg = f"Evaluation failed: {e}"
|
|
216
|
+
logger.warning("MetaLearner.run_cycle: %s", msg)
|
|
217
|
+
errors.append(msg)
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
# 2. Detect gaps
|
|
221
|
+
if cpi:
|
|
222
|
+
gaps = await self.detect_gaps(cpi)
|
|
223
|
+
except Exception as e:
|
|
224
|
+
msg = f"Gap detection failed: {e}"
|
|
225
|
+
logger.warning("MetaLearner.run_cycle: %s", msg)
|
|
226
|
+
errors.append(msg)
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
# 2b. Process user corrections from FeedbackStore
|
|
230
|
+
if self._feedback_store is not None:
|
|
231
|
+
await self._process_feedback_corrections()
|
|
232
|
+
except Exception as e:
|
|
233
|
+
msg = f"Feedback processing failed: {e}"
|
|
234
|
+
logger.warning("MetaLearner.run_cycle: %s", msg)
|
|
235
|
+
errors.append(msg)
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
# 3. Adjust strategy for each gap (up to max)
|
|
239
|
+
if gaps and self._strategy_adjuster:
|
|
240
|
+
for gap in gaps[:self.config.max_adjustments_per_cycle]:
|
|
241
|
+
try:
|
|
242
|
+
adjustment = await self.adjust_strategy(gap)
|
|
243
|
+
adjustments.append(adjustment)
|
|
244
|
+
except Exception as e:
|
|
245
|
+
msg = f"Adjustment failed for {gap.gap_type}: {e}"
|
|
246
|
+
logger.warning("MetaLearner.run_cycle: %s", msg)
|
|
247
|
+
errors.append(msg)
|
|
248
|
+
except Exception as e:
|
|
249
|
+
msg = f"Strategy adjustment phase failed: {e}"
|
|
250
|
+
logger.warning("MetaLearner.run_cycle: %s", msg)
|
|
251
|
+
errors.append(msg)
|
|
252
|
+
|
|
253
|
+
# Persist cycle summary
|
|
254
|
+
if self.config.persist_to_graph:
|
|
255
|
+
await self._persist_cycle_summary(cpi, gaps, adjustments, errors)
|
|
256
|
+
|
|
257
|
+
# Store cycle in vector store for pattern matching (§6.2)
|
|
258
|
+
await self._store_cognition_vector(cpi, gaps, adjustments)
|
|
259
|
+
|
|
260
|
+
duration_ms = (time.time() - start_time) * 1000
|
|
261
|
+
return CycleResult(
|
|
262
|
+
cpi=cpi,
|
|
263
|
+
gaps=gaps,
|
|
264
|
+
adjustments=adjustments,
|
|
265
|
+
duration_ms=duration_ms,
|
|
266
|
+
errors=errors,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
async def _process_feedback_corrections(self) -> None:
|
|
270
|
+
"""Pull unapplied corrections from FeedbackStore and record as metrics."""
|
|
271
|
+
if self._feedback_store is None:
|
|
272
|
+
return
|
|
273
|
+
corrections = self._feedback_store.get_unapplied(limit=50)
|
|
274
|
+
if not corrections:
|
|
275
|
+
return
|
|
276
|
+
metric_map = {
|
|
277
|
+
"factual": ("factual_error_rate", 1.0),
|
|
278
|
+
"tone": ("tone_error_rate", 1.0),
|
|
279
|
+
"action": ("action_error_rate", 1.0),
|
|
280
|
+
"preference": ("preference_mismatch_rate", 1.0),
|
|
281
|
+
}
|
|
282
|
+
applied_ids = []
|
|
283
|
+
for correction in corrections:
|
|
284
|
+
metric_type, value = metric_map.get(
|
|
285
|
+
correction.correction_type, ("correction_rate", 1.0)
|
|
286
|
+
)
|
|
287
|
+
await self.record_metric(metric_type, value, domain="feedback")
|
|
288
|
+
applied_ids.append(correction.correction_id)
|
|
289
|
+
self._feedback_store.mark_applied(applied_ids)
|
|
290
|
+
|
|
291
|
+
async def _persist_cpi(self, cpi: "CognitivePerformanceIndex") -> None:
|
|
292
|
+
"""Persist CPI components as CognitiveMetric nodes (MERGE, only on >1.0 change)."""
|
|
293
|
+
overall = getattr(cpi, "overall", 0.0)
|
|
294
|
+
# Skip if change from last persisted value is ≤1.0 (avoids 53K identical nodes)
|
|
295
|
+
if self._last_persisted_cpi is not None and abs(overall - self._last_persisted_cpi) <= 1.0:
|
|
296
|
+
return
|
|
297
|
+
self._last_persisted_cpi = overall
|
|
298
|
+
try:
|
|
299
|
+
async with self.graph.driver.session(database=self.graph.database) as session:
|
|
300
|
+
today = datetime.now().strftime("%Y-%m-%d")
|
|
301
|
+
for component_name in ["retrieval", "prediction", "goal_progress", "tool_efficiency", "initiative", "response_quality"]:
|
|
302
|
+
component = getattr(cpi, component_name, None)
|
|
303
|
+
if component and getattr(component, "available", True):
|
|
304
|
+
await session.run("""
|
|
305
|
+
MERGE (m:CognitiveMetric {metric_type: $component_name, day: $day})
|
|
306
|
+
SET m.value = $score,
|
|
307
|
+
m.domain = 'cpi',
|
|
308
|
+
m.recorded_at = datetime()
|
|
309
|
+
""", component_name=component_name, day=today, score=component.score)
|
|
310
|
+
except Exception as exc:
|
|
311
|
+
self._persist_errors += 1
|
|
312
|
+
logger.warning("MetaLearner: failed to persist CPI to graph: %s", exc)
|
|
313
|
+
|
|
314
|
+
async def _persist_gap(self, gap: "Gap") -> None:
|
|
315
|
+
"""Persist gap to graph (MERGE on gap_type+status='open', skip if already open)."""
|
|
316
|
+
gap_type_val = gap.gap_type.value if hasattr(gap.gap_type, "value") else str(gap.gap_type)
|
|
317
|
+
# Skip if we already have an open node for this gap type in this session
|
|
318
|
+
if gap_type_val in self._open_gap_types:
|
|
319
|
+
return
|
|
320
|
+
try:
|
|
321
|
+
async with self.graph.driver.session(database=self.graph.database) as session:
|
|
322
|
+
# Check for existing open gap of same type before creating
|
|
323
|
+
result = await session.run(
|
|
324
|
+
"MATCH (g:Gap {gap_type: $gap_type, status: 'open'}) RETURN count(g) AS cnt",
|
|
325
|
+
gap_type=gap_type_val,
|
|
326
|
+
)
|
|
327
|
+
record = await result.single()
|
|
328
|
+
if record and record["cnt"] > 0:
|
|
329
|
+
self._open_gap_types.add(gap_type_val)
|
|
330
|
+
return
|
|
331
|
+
await session.run("""
|
|
332
|
+
MERGE (g:Gap {gap_type: $gap_type, status: 'open'})
|
|
333
|
+
ON CREATE SET
|
|
334
|
+
g.id = randomUUID(),
|
|
335
|
+
g.severity = $severity,
|
|
336
|
+
g.component = $component,
|
|
337
|
+
g.description = $description,
|
|
338
|
+
g.diagnosed_at = datetime()
|
|
339
|
+
ON MATCH SET
|
|
340
|
+
g.severity = $severity,
|
|
341
|
+
g.updated_at = datetime()
|
|
342
|
+
""", gap_type=gap_type_val, severity=gap.severity.value,
|
|
343
|
+
component=gap.component, description=gap.description)
|
|
344
|
+
self._open_gap_types.add(gap_type_val)
|
|
345
|
+
except Exception as exc:
|
|
346
|
+
self._persist_errors += 1
|
|
347
|
+
logger.warning(
|
|
348
|
+
"MetaLearner: failed to persist gap %r to graph: %s",
|
|
349
|
+
gap_type_val, exc,
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
async def _persist_adjustment(self, adjustment: "Adjustment", gap: Optional["Gap"] = None) -> None:
|
|
353
|
+
"""Persist adjustment to graph and link to its source gap."""
|
|
354
|
+
gap_type_val = None
|
|
355
|
+
if gap is not None:
|
|
356
|
+
gap_type_val = gap.gap_type.value if hasattr(gap.gap_type, "value") else str(gap.gap_type)
|
|
357
|
+
try:
|
|
358
|
+
async with self.graph.driver.session(database=self.graph.database) as session:
|
|
359
|
+
if gap_type_val:
|
|
360
|
+
# Only create adjustment + link if the gap has no resolver yet
|
|
361
|
+
await session.run("""
|
|
362
|
+
MATCH (g:Gap {gap_type: $gap_type, status: 'open'})
|
|
363
|
+
WHERE NOT exists((g)-[:RESOLVED_BY]->(:Adjustment))
|
|
364
|
+
CREATE (a:Adjustment {
|
|
365
|
+
id: randomUUID(),
|
|
366
|
+
adjustment_type: $adj_type,
|
|
367
|
+
hypothesis: $hypothesis,
|
|
368
|
+
status: 'applied',
|
|
369
|
+
applied_at: datetime()
|
|
370
|
+
})
|
|
371
|
+
CREATE (g)-[:RESOLVED_BY]->(a)
|
|
372
|
+
""", gap_type=gap_type_val, adj_type=adjustment.adjustment_type,
|
|
373
|
+
hypothesis=adjustment.hypothesis)
|
|
374
|
+
else:
|
|
375
|
+
await session.run("""
|
|
376
|
+
CREATE (a:Adjustment {
|
|
377
|
+
id: randomUUID(),
|
|
378
|
+
adjustment_type: $adj_type,
|
|
379
|
+
hypothesis: $hypothesis,
|
|
380
|
+
status: 'applied',
|
|
381
|
+
applied_at: datetime()
|
|
382
|
+
})
|
|
383
|
+
""", adj_type=adjustment.adjustment_type, hypothesis=adjustment.hypothesis)
|
|
384
|
+
except Exception as exc:
|
|
385
|
+
self._persist_errors += 1
|
|
386
|
+
logger.warning(
|
|
387
|
+
"MetaLearner: failed to persist adjustment %r to graph: %s",
|
|
388
|
+
adjustment.adjustment_type, exc,
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
async def _persist_cycle_summary(
|
|
392
|
+
self,
|
|
393
|
+
cpi: Optional["CognitivePerformanceIndex"],
|
|
394
|
+
gaps: List["Gap"],
|
|
395
|
+
adjustments: List["Adjustment"],
|
|
396
|
+
errors: List[str]
|
|
397
|
+
) -> None:
|
|
398
|
+
"""Persist cycle summary every 10th cycle to reduce graph churn."""
|
|
399
|
+
if self._cycle_count % 10 != 0:
|
|
400
|
+
return
|
|
401
|
+
try:
|
|
402
|
+
overall_score = cpi.overall if cpi else 0.0
|
|
403
|
+
gap_types = [
|
|
404
|
+
g.gap_type.value if hasattr(g.gap_type, "value") else str(g.gap_type)
|
|
405
|
+
for g in gaps
|
|
406
|
+
]
|
|
407
|
+
async with self.graph.driver.session(database=self.graph.database) as session:
|
|
408
|
+
result = await session.run("""
|
|
409
|
+
CREATE (c:CognitionCycle {
|
|
410
|
+
id: randomUUID(),
|
|
411
|
+
cycle_number: $cycle_num,
|
|
412
|
+
overall_cpi: $overall,
|
|
413
|
+
gap_count: $gap_count,
|
|
414
|
+
adjustment_count: $adj_count,
|
|
415
|
+
error_count: $error_count,
|
|
416
|
+
completed_at: datetime()
|
|
417
|
+
})
|
|
418
|
+
RETURN c.id AS cycle_id
|
|
419
|
+
""", cycle_num=self._cycle_count, overall=overall_score,
|
|
420
|
+
gap_count=len(gaps), adj_count=len(adjustments),
|
|
421
|
+
error_count=len(errors))
|
|
422
|
+
record = await result.single()
|
|
423
|
+
cycle_id = record["cycle_id"] if record else None
|
|
424
|
+
|
|
425
|
+
# Link to detected gaps
|
|
426
|
+
if cycle_id and gap_types:
|
|
427
|
+
for gap_type_val in gap_types:
|
|
428
|
+
await session.run("""
|
|
429
|
+
MATCH (c:CognitionCycle {id: $cycle_id})
|
|
430
|
+
MATCH (g:Gap {gap_type: $gap_type})
|
|
431
|
+
MERGE (c)-[:DETECTED]->(g)
|
|
432
|
+
""", cycle_id=cycle_id, gap_type=gap_type_val)
|
|
433
|
+
except Exception as exc:
|
|
434
|
+
self._persist_errors += 1
|
|
435
|
+
logger.warning("MetaLearner: failed to persist cycle summary to graph: %s", exc)
|
|
436
|
+
|
|
437
|
+
async def _cleanup_old_metrics(self) -> None:
|
|
438
|
+
"""Delete CognitiveMetric nodes older than 7 days (TTL cleanup)."""
|
|
439
|
+
try:
|
|
440
|
+
async with self.graph.driver.session(database=self.graph.database) as session:
|
|
441
|
+
result = await session.run("""
|
|
442
|
+
MATCH (m:CognitiveMetric)
|
|
443
|
+
WHERE m.recorded_at < datetime() - duration({days: 7})
|
|
444
|
+
WITH m LIMIT 1000
|
|
445
|
+
DETACH DELETE m
|
|
446
|
+
RETURN count(m) AS deleted
|
|
447
|
+
""")
|
|
448
|
+
record = await result.single()
|
|
449
|
+
deleted = record["deleted"] if record else 0
|
|
450
|
+
if deleted:
|
|
451
|
+
logger.info("MetaLearner TTL: deleted %d old CognitiveMetric nodes", deleted)
|
|
452
|
+
except Exception as exc:
|
|
453
|
+
logger.debug("MetaLearner TTL cleanup error (non-fatal): %s", exc)
|
|
454
|
+
|
|
455
|
+
# ------------------------------------------------------------------
|
|
456
|
+
# Cognition pattern matching via vector store (§6.2)
|
|
457
|
+
# ------------------------------------------------------------------
|
|
458
|
+
|
|
459
|
+
def _build_cycle_summary(
|
|
460
|
+
self,
|
|
461
|
+
cpi: Optional["CognitivePerformanceIndex"],
|
|
462
|
+
gaps: List["Gap"],
|
|
463
|
+
adjustments: List["Adjustment"],
|
|
464
|
+
) -> str:
|
|
465
|
+
"""Generate a text summary of a cognition cycle for embedding."""
|
|
466
|
+
parts = []
|
|
467
|
+
if cpi:
|
|
468
|
+
parts.append(f"CPI overall={getattr(cpi, 'overall', 0.0):.1f}")
|
|
469
|
+
if gaps:
|
|
470
|
+
gap_strs = [
|
|
471
|
+
f"{g.gap_type.value if hasattr(g.gap_type, 'value') else g.gap_type}({g.severity.value})"
|
|
472
|
+
for g in gaps
|
|
473
|
+
]
|
|
474
|
+
parts.append(f"Gaps: {', '.join(gap_strs)}")
|
|
475
|
+
if adjustments:
|
|
476
|
+
adj_strs = [a.adjustment_type for a in adjustments]
|
|
477
|
+
parts.append(f"Adjustments: {', '.join(adj_strs)}")
|
|
478
|
+
return "; ".join(parts) if parts else "Empty cognition cycle"
|
|
479
|
+
|
|
480
|
+
async def _store_cognition_vector(
|
|
481
|
+
self,
|
|
482
|
+
cpi: Optional["CognitivePerformanceIndex"],
|
|
483
|
+
gaps: List["Gap"],
|
|
484
|
+
adjustments: List["Adjustment"],
|
|
485
|
+
) -> None:
|
|
486
|
+
"""Embed and store a cognition cycle summary in the COGNITION collection."""
|
|
487
|
+
if self._vector_store is None or self._embedder is None:
|
|
488
|
+
return
|
|
489
|
+
try:
|
|
490
|
+
from apsimo.vector.collections import Collection
|
|
491
|
+
import uuid
|
|
492
|
+
|
|
493
|
+
summary = self._build_cycle_summary(cpi, gaps, adjustments)
|
|
494
|
+
vector = await self._embedder.embed(summary)
|
|
495
|
+
cycle_id = str(uuid.uuid4())
|
|
496
|
+
|
|
497
|
+
await self._vector_store.add(
|
|
498
|
+
collection=Collection.COGNITION,
|
|
499
|
+
id=cycle_id,
|
|
500
|
+
text=summary,
|
|
501
|
+
vector=vector,
|
|
502
|
+
metadata={
|
|
503
|
+
"cycle_id": cycle_id,
|
|
504
|
+
"cpi_score": getattr(cpi, "overall", 0.0) if cpi else 0.0,
|
|
505
|
+
"gaps": [
|
|
506
|
+
g.gap_type.value if hasattr(g.gap_type, "value") else str(g.gap_type)
|
|
507
|
+
for g in gaps
|
|
508
|
+
],
|
|
509
|
+
"adjustments": [a.adjustment_type for a in adjustments],
|
|
510
|
+
"cycle_at": time.time(),
|
|
511
|
+
},
|
|
512
|
+
)
|
|
513
|
+
except Exception as exc:
|
|
514
|
+
logger.warning("MetaLearner: failed to store cognition vector: %s", exc)
|
|
515
|
+
|
|
516
|
+
async def find_similar_cycles(self, limit: int = 5) -> List[Dict[str, Any]]:
|
|
517
|
+
"""Query the COGNITION collection for similar past cycles.
|
|
518
|
+
|
|
519
|
+
Called at the start of a new cycle to provide pattern context to
|
|
520
|
+
StrategyAdjuster. Returns empty list if vector store is not
|
|
521
|
+
configured.
|
|
522
|
+
"""
|
|
523
|
+
if self._vector_store is None or self._embedder is None:
|
|
524
|
+
return []
|
|
525
|
+
try:
|
|
526
|
+
from apsimo.vector.collections import Collection
|
|
527
|
+
|
|
528
|
+
# Use the most recent cycle summary as the query
|
|
529
|
+
count = await self._vector_store.count(Collection.COGNITION)
|
|
530
|
+
if count == 0:
|
|
531
|
+
return []
|
|
532
|
+
|
|
533
|
+
# Build a query from current state (lightweight — just embed a status string)
|
|
534
|
+
query_text = "recent cognition cycle performance gaps and adjustments"
|
|
535
|
+
query_vector = await self._embedder.embed(query_text)
|
|
536
|
+
results = await self._vector_store.search(
|
|
537
|
+
collection=Collection.COGNITION,
|
|
538
|
+
query_vector=query_vector,
|
|
539
|
+
limit=limit,
|
|
540
|
+
)
|
|
541
|
+
return [
|
|
542
|
+
{"text": r.text, "score": r.score, "metadata": r.metadata}
|
|
543
|
+
for r in results
|
|
544
|
+
]
|
|
545
|
+
except Exception as exc:
|
|
546
|
+
logger.warning("MetaLearner: failed to query similar cycles: %s", exc)
|
|
547
|
+
return []
|