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,274 @@
|
|
|
1
|
+
"""BriefingEngine — top-level coordinator for the Colony Briefing System."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from typing import Any, List, Optional
|
|
8
|
+
|
|
9
|
+
from apsimo.briefings.composer import BriefingComposer
|
|
10
|
+
from apsimo.briefings.config import BriefingConfig
|
|
11
|
+
from apsimo.briefings.delivery import BriefingDeliveryEngine
|
|
12
|
+
from apsimo.briefings.engagement import SectionEngagementTracker
|
|
13
|
+
from apsimo.briefings.enhancer import BriefingLMEnhancer
|
|
14
|
+
from apsimo.briefings.models import (
|
|
15
|
+
Briefing,
|
|
16
|
+
BriefingCompletionSignal,
|
|
17
|
+
BriefingStatus,
|
|
18
|
+
BriefingType,
|
|
19
|
+
SectionEngagementRecord,
|
|
20
|
+
)
|
|
21
|
+
from apsimo.briefings.store import BriefingStore
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BriefingEngine:
|
|
25
|
+
"""Top-level coordinator for generating, delivering, and tracking briefings."""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
config: Optional[BriefingConfig] = None,
|
|
30
|
+
store: Optional[BriefingStore] = None,
|
|
31
|
+
delivery: Optional[BriefingDeliveryEngine] = None,
|
|
32
|
+
enhancer: Optional[BriefingLMEnhancer] = None,
|
|
33
|
+
delivery_bridge: Optional[Any] = None, # ProactiveDeliveryBridge
|
|
34
|
+
relationship_aggregator: Optional[Any] = None,
|
|
35
|
+
calendar_aggregator: Optional[Any] = None,
|
|
36
|
+
goal_aggregator: Optional[Any] = None,
|
|
37
|
+
anomaly_aggregator: Optional[Any] = None,
|
|
38
|
+
mind_model_aggregator: Optional[Any] = None,
|
|
39
|
+
synthesis_aggregator: Optional[Any] = None,
|
|
40
|
+
) -> None:
|
|
41
|
+
self._config = config or BriefingConfig()
|
|
42
|
+
self._store = store or BriefingStore(db_path=":memory:")
|
|
43
|
+
self._delivery = delivery or BriefingDeliveryEngine(gateways=[], default_gateway="api")
|
|
44
|
+
self._enhancer = enhancer or BriefingLMEnhancer(enabled=False)
|
|
45
|
+
self._delivery_bridge = delivery_bridge
|
|
46
|
+
# Aggregators default to stubs inside the composer; the real ones must
|
|
47
|
+
# be passed through or every briefing data section is permanently empty.
|
|
48
|
+
self._composer = BriefingComposer(
|
|
49
|
+
relationship_aggregator=relationship_aggregator,
|
|
50
|
+
calendar_aggregator=calendar_aggregator,
|
|
51
|
+
goal_aggregator=goal_aggregator,
|
|
52
|
+
anomaly_aggregator=anomaly_aggregator,
|
|
53
|
+
mind_model_aggregator=mind_model_aggregator,
|
|
54
|
+
synthesis_aggregator=synthesis_aggregator,
|
|
55
|
+
suppressed_sections=self._config.suppressed_sections,
|
|
56
|
+
)
|
|
57
|
+
self._engagement = SectionEngagementTracker(store=self._store)
|
|
58
|
+
self._scheduler = None
|
|
59
|
+
|
|
60
|
+
# Register the WhatsApp gateway if a delivery bridge is available.
|
|
61
|
+
if delivery_bridge is not None:
|
|
62
|
+
from apsimo.briefings.delivery import WhatsAppBriefingGateway
|
|
63
|
+
self._delivery.register(WhatsAppBriefingGateway(delivery_bridge=delivery_bridge))
|
|
64
|
+
|
|
65
|
+
# ------------------------------------------------------------------
|
|
66
|
+
# Generation & Delivery
|
|
67
|
+
# ------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
def generate_and_deliver(self, briefing_type: BriefingType) -> Briefing:
|
|
70
|
+
"""Generate a briefing of the given type, persist it, and deliver it.
|
|
71
|
+
|
|
72
|
+
Raises ValueError for BriefingType.TACTICAL (use fire_tactical() instead).
|
|
73
|
+
Engagement history is used to re-order sections by prior engagement score.
|
|
74
|
+
If LM enhancement is enabled, the briefing is polished before delivery.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
The saved Briefing object after delivery attempt. The returned
|
|
78
|
+
Briefing.status reflects the delivery outcome (DELIVERED or PENDING).
|
|
79
|
+
"""
|
|
80
|
+
if briefing_type == BriefingType.TACTICAL:
|
|
81
|
+
raise ValueError("Use fire_tactical() for tactical briefings")
|
|
82
|
+
|
|
83
|
+
now = datetime.now(timezone.utc)
|
|
84
|
+
scores = self._engagement.get_section_scores()
|
|
85
|
+
|
|
86
|
+
if briefing_type == BriefingType.DAILY:
|
|
87
|
+
cfg = self._config.daily
|
|
88
|
+
briefing = self._composer.build_daily_briefing(
|
|
89
|
+
date=now.strftime("%Y-%m-%d"),
|
|
90
|
+
tz=cfg.timezone,
|
|
91
|
+
max_sections=cfg.max_sections,
|
|
92
|
+
section_order=cfg.section_order,
|
|
93
|
+
engagement_history=scores,
|
|
94
|
+
)
|
|
95
|
+
else: # WEEKLY
|
|
96
|
+
cfg = self._config.weekly
|
|
97
|
+
from datetime import timedelta
|
|
98
|
+
week_start = now - timedelta(days=now.weekday())
|
|
99
|
+
briefing = self._composer.build_weekly_briefing(
|
|
100
|
+
period_start=week_start,
|
|
101
|
+
period_end=now,
|
|
102
|
+
engagement_history=scores,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
if self._config.lm_enhancement_enabled:
|
|
106
|
+
briefing = self._enhancer.enhance_briefing(briefing)
|
|
107
|
+
|
|
108
|
+
# Resolve home channel gateway before persisting (Fix 8 point 1).
|
|
109
|
+
if not briefing.gateway:
|
|
110
|
+
briefing.gateway = self._resolve_home_channel()
|
|
111
|
+
|
|
112
|
+
# draft → saved
|
|
113
|
+
self._store.save(briefing)
|
|
114
|
+
# draft → queued
|
|
115
|
+
self._store.mark_queued(briefing.briefing_id)
|
|
116
|
+
# queued → delivering
|
|
117
|
+
self._store.mark_delivering(briefing.briefing_id)
|
|
118
|
+
result = self._delivery.deliver(briefing)
|
|
119
|
+
if result.success:
|
|
120
|
+
# delivering → delivered
|
|
121
|
+
self._store.mark_delivered(briefing.briefing_id, result.gateway)
|
|
122
|
+
briefing = self._store.get(briefing.briefing_id)
|
|
123
|
+
return briefing
|
|
124
|
+
|
|
125
|
+
def fire_tactical(
|
|
126
|
+
self,
|
|
127
|
+
trigger: str,
|
|
128
|
+
severity: str,
|
|
129
|
+
summary: str,
|
|
130
|
+
details: str,
|
|
131
|
+
suggested_actions: Optional[List[str]] = None,
|
|
132
|
+
) -> Optional[Briefing]:
|
|
133
|
+
"""Fire a tactical (event-driven) briefing if the tactical channel is enabled.
|
|
134
|
+
|
|
135
|
+
Returns None when tactical briefings are disabled in config, so callers
|
|
136
|
+
must handle the None case. When enabled, saves and delivers immediately
|
|
137
|
+
without engagement scoring.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
The delivered Briefing, or None if tactical is disabled.
|
|
141
|
+
"""
|
|
142
|
+
if not self._config.tactical.enabled:
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
briefing = self._composer.build_tactical_briefing(
|
|
146
|
+
trigger=trigger,
|
|
147
|
+
severity=severity,
|
|
148
|
+
summary=summary,
|
|
149
|
+
details=details,
|
|
150
|
+
suggested_actions=suggested_actions,
|
|
151
|
+
)
|
|
152
|
+
if not briefing.gateway:
|
|
153
|
+
briefing.gateway = self._resolve_home_channel()
|
|
154
|
+
self._store.save(briefing)
|
|
155
|
+
self._store.mark_queued(briefing.briefing_id)
|
|
156
|
+
self._store.mark_delivering(briefing.briefing_id)
|
|
157
|
+
result = self._delivery.deliver(briefing)
|
|
158
|
+
if result.success:
|
|
159
|
+
self._store.mark_delivered(briefing.briefing_id, result.gateway)
|
|
160
|
+
briefing = self._store.get(briefing.briefing_id)
|
|
161
|
+
return briefing
|
|
162
|
+
|
|
163
|
+
# ------------------------------------------------------------------
|
|
164
|
+
# Pending delivery (Fix 8 point 3 — pick up stalled drafts)
|
|
165
|
+
# ------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
def deliver_pending(self) -> int:
|
|
168
|
+
"""Attempt delivery of any DRAFT or QUEUED briefings.
|
|
169
|
+
|
|
170
|
+
Transitions each briefing through the state machine:
|
|
171
|
+
draft/queued → delivering → delivered (or back to queued on failure).
|
|
172
|
+
|
|
173
|
+
Returns the number of briefings successfully delivered.
|
|
174
|
+
"""
|
|
175
|
+
count = 0
|
|
176
|
+
for status in (BriefingStatus.DRAFT, BriefingStatus.QUEUED):
|
|
177
|
+
for briefing in self._store.list_by_status(status):
|
|
178
|
+
if not briefing.gateway:
|
|
179
|
+
briefing.gateway = self._resolve_home_channel()
|
|
180
|
+
# Persist the resolved gateway so the delivery engine uses it.
|
|
181
|
+
self._store.save(briefing)
|
|
182
|
+
self._store.mark_delivering(briefing.briefing_id)
|
|
183
|
+
result = self._delivery.deliver(briefing)
|
|
184
|
+
if result.success:
|
|
185
|
+
self._store.mark_delivered(briefing.briefing_id, result.gateway)
|
|
186
|
+
count += 1
|
|
187
|
+
import logging as _logging
|
|
188
|
+
_logging.getLogger(__name__).info(
|
|
189
|
+
"deliver_pending: delivered briefing %s via %s",
|
|
190
|
+
briefing.briefing_id,
|
|
191
|
+
result.gateway,
|
|
192
|
+
)
|
|
193
|
+
else:
|
|
194
|
+
# Revert to queued so the scheduler retries next cycle.
|
|
195
|
+
self._store.mark_queued(briefing.briefing_id)
|
|
196
|
+
import logging as _logging
|
|
197
|
+
_logging.getLogger(__name__).warning(
|
|
198
|
+
"deliver_pending: failed to deliver briefing %s: %s",
|
|
199
|
+
briefing.briefing_id,
|
|
200
|
+
result.error,
|
|
201
|
+
)
|
|
202
|
+
return count
|
|
203
|
+
|
|
204
|
+
def _resolve_home_channel(self) -> str:
|
|
205
|
+
"""Return the home channel platform from delivery_bridge or env vars."""
|
|
206
|
+
if self._delivery_bridge is not None:
|
|
207
|
+
home = self._delivery_bridge.resolve_home_channel()
|
|
208
|
+
if home:
|
|
209
|
+
return home["platform"]
|
|
210
|
+
for platform in ("whatsapp", "telegram", "discord", "slack", "signal"):
|
|
211
|
+
if os.environ.get(f"{platform.upper()}_HOME_CHANNEL"):
|
|
212
|
+
return platform
|
|
213
|
+
return "api"
|
|
214
|
+
|
|
215
|
+
# ------------------------------------------------------------------
|
|
216
|
+
# Query
|
|
217
|
+
# ------------------------------------------------------------------
|
|
218
|
+
|
|
219
|
+
def get_pending(self) -> List[Briefing]:
|
|
220
|
+
return self._store.list_by_status(BriefingStatus.DRAFT)
|
|
221
|
+
|
|
222
|
+
def get_recent(self, limit: int = 10) -> List[Briefing]:
|
|
223
|
+
return self._store.list_recent(limit=limit)
|
|
224
|
+
|
|
225
|
+
# ------------------------------------------------------------------
|
|
226
|
+
# Engagement
|
|
227
|
+
# ------------------------------------------------------------------
|
|
228
|
+
|
|
229
|
+
def record_engagement(self, briefing_id: str, section_name: str, signal: str) -> None:
|
|
230
|
+
record = SectionEngagementRecord(
|
|
231
|
+
section_name=section_name,
|
|
232
|
+
briefing_id=briefing_id,
|
|
233
|
+
signal=signal,
|
|
234
|
+
recorded_at=datetime.now(timezone.utc),
|
|
235
|
+
)
|
|
236
|
+
self._engagement.record(record)
|
|
237
|
+
if signal == "read":
|
|
238
|
+
self._store.mark_read(briefing_id)
|
|
239
|
+
|
|
240
|
+
def get_suppression_candidates(self, **kwargs) -> List[str]:
|
|
241
|
+
return self._engagement.get_suppression_candidates(**kwargs)
|
|
242
|
+
|
|
243
|
+
def suppress_section(self, section: str, reason: str = "") -> None:
|
|
244
|
+
if section not in self._config.suppressed_sections:
|
|
245
|
+
self._config.suppressed_sections.append(section)
|
|
246
|
+
|
|
247
|
+
def emit_completion_signal(self, briefing: Briefing) -> BriefingCompletionSignal:
|
|
248
|
+
scores = self._engagement.get_section_scores()
|
|
249
|
+
active = briefing.active_sections()
|
|
250
|
+
engaged = [s.name for s in active if scores.get(s.name, 0.5) > 0.5]
|
|
251
|
+
return BriefingCompletionSignal(
|
|
252
|
+
briefing_id=briefing.briefing_id,
|
|
253
|
+
briefing_type=briefing.briefing_type,
|
|
254
|
+
sections=[s.name for s in active],
|
|
255
|
+
engaged_sections=engaged,
|
|
256
|
+
delivered_at=datetime.now(timezone.utc),
|
|
257
|
+
total_anomalies=0,
|
|
258
|
+
active_goals=0,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# ------------------------------------------------------------------
|
|
262
|
+
# Lifecycle
|
|
263
|
+
# ------------------------------------------------------------------
|
|
264
|
+
|
|
265
|
+
def attach_scheduler(self, scheduler) -> None:
|
|
266
|
+
self._scheduler = scheduler
|
|
267
|
+
|
|
268
|
+
def start(self) -> None:
|
|
269
|
+
if self._scheduler is not None:
|
|
270
|
+
self._scheduler.start()
|
|
271
|
+
|
|
272
|
+
def stop(self) -> None:
|
|
273
|
+
if self._scheduler is not None:
|
|
274
|
+
self._scheduler.stop()
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Colony Briefing System — LLM Enhancement Pass.
|
|
2
|
+
|
|
3
|
+
Generates natural-language narratives for briefing sections.
|
|
4
|
+
Falls back gracefully when no LLM client is provided or when
|
|
5
|
+
the LLM call fails.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
from typing import Any, Dict, Optional, Protocol, runtime_checkable
|
|
13
|
+
|
|
14
|
+
from .models import Briefing, BriefingSection
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
from apsimo.cognition.charter import build_system_prompt as _charter_prompt
|
|
19
|
+
|
|
20
|
+
_SYSTEM_PROMPT = _charter_prompt("narrator")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@runtime_checkable
|
|
24
|
+
class LLMClientProtocol(Protocol):
|
|
25
|
+
"""Minimal interface expected from an LLM client."""
|
|
26
|
+
|
|
27
|
+
def complete(self, system: str, prompt: str, max_tokens: int) -> str: ...
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BriefingLMEnhancer:
|
|
31
|
+
"""Generate natural-language narratives for briefing sections."""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
llm_client: Optional[LLMClientProtocol] = None,
|
|
36
|
+
enabled: bool = True,
|
|
37
|
+
) -> None:
|
|
38
|
+
self._client = llm_client
|
|
39
|
+
self._enabled = enabled
|
|
40
|
+
self._tokens_used = 0
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def tokens_used(self) -> int:
|
|
44
|
+
return self._tokens_used
|
|
45
|
+
|
|
46
|
+
def enhance_section(
|
|
47
|
+
self,
|
|
48
|
+
section_name: str,
|
|
49
|
+
structured_content: Dict[str, Any],
|
|
50
|
+
max_tokens: int = 150,
|
|
51
|
+
) -> str:
|
|
52
|
+
"""Generate a natural-language narrative for a single section.
|
|
53
|
+
|
|
54
|
+
Returns an empty string if LLM is disabled, unavailable, or if
|
|
55
|
+
the content has no notable information.
|
|
56
|
+
"""
|
|
57
|
+
if not self._enabled or self._client is None:
|
|
58
|
+
return ""
|
|
59
|
+
|
|
60
|
+
if not structured_content:
|
|
61
|
+
return ""
|
|
62
|
+
|
|
63
|
+
prompt = (
|
|
64
|
+
f"Section: {section_name}\n"
|
|
65
|
+
f"Data: {json.dumps(structured_content, default=str)}\n\n"
|
|
66
|
+
"Write a 1–3 sentence briefing summary for this section. "
|
|
67
|
+
"Be concise and actionable. Do not repeat the raw data literally."
|
|
68
|
+
)
|
|
69
|
+
try:
|
|
70
|
+
narrative = self._client.complete(_SYSTEM_PROMPT, prompt, max_tokens)
|
|
71
|
+
self._tokens_used += max_tokens # conservative accounting
|
|
72
|
+
return narrative.strip()
|
|
73
|
+
except Exception as exc:
|
|
74
|
+
logger.warning("LLM enhancement failed for section '%s': %s", section_name, exc)
|
|
75
|
+
return ""
|
|
76
|
+
|
|
77
|
+
def enhance_briefing(
|
|
78
|
+
self,
|
|
79
|
+
briefing: Briefing,
|
|
80
|
+
max_tokens_per_section: int = 150,
|
|
81
|
+
) -> Briefing:
|
|
82
|
+
"""Run the LLM enhancement pass on all active sections.
|
|
83
|
+
|
|
84
|
+
Modifies section.narrative in-place. Returns the updated briefing.
|
|
85
|
+
Falls back to structured-only content on any LLM failure.
|
|
86
|
+
"""
|
|
87
|
+
if not self._enabled or self._client is None:
|
|
88
|
+
return briefing
|
|
89
|
+
|
|
90
|
+
for section in briefing.active_sections():
|
|
91
|
+
if section.suppressed:
|
|
92
|
+
continue
|
|
93
|
+
section.narrative = self.enhance_section(
|
|
94
|
+
section.name,
|
|
95
|
+
section.content,
|
|
96
|
+
max_tokens=max_tokens_per_section,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return briefing
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Colony Briefing System — data models.
|
|
2
|
+
|
|
3
|
+
Defines the core Briefing, BriefingSection, and briefing content types
|
|
4
|
+
used throughout the briefing pipeline.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import uuid
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from typing import Any, Dict, List, Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BriefingType(str, Enum):
|
|
17
|
+
DAILY = "daily"
|
|
18
|
+
TACTICAL = "tactical"
|
|
19
|
+
WEEKLY = "weekly"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BriefingStatus(str, Enum):
|
|
23
|
+
DRAFT = "draft"
|
|
24
|
+
QUEUED = "queued"
|
|
25
|
+
DELIVERING = "delivering"
|
|
26
|
+
DELIVERED = "delivered"
|
|
27
|
+
READ = "read"
|
|
28
|
+
ARCHIVED = "archived"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class BriefingPriority(str, Enum):
|
|
32
|
+
LOW = "low"
|
|
33
|
+
NORMAL = "normal"
|
|
34
|
+
HIGH = "high"
|
|
35
|
+
URGENT = "urgent"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class BriefingSection:
|
|
40
|
+
"""A single named content block within a briefing."""
|
|
41
|
+
|
|
42
|
+
section_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
|
43
|
+
name: str = ""
|
|
44
|
+
content: Dict[str, Any] = field(default_factory=dict)
|
|
45
|
+
narrative: str = ""
|
|
46
|
+
priority: int = 50
|
|
47
|
+
suppressed: bool = False
|
|
48
|
+
engagement: Optional[str] = None # "read" | "dismissed" | "acted"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class Briefing:
|
|
53
|
+
"""A delivered summary document."""
|
|
54
|
+
|
|
55
|
+
briefing_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
|
56
|
+
briefing_type: BriefingType = BriefingType.DAILY
|
|
57
|
+
status: BriefingStatus = BriefingStatus.DRAFT
|
|
58
|
+
sections: List[BriefingSection] = field(default_factory=list)
|
|
59
|
+
priority: BriefingPriority = BriefingPriority.NORMAL
|
|
60
|
+
triggered_by: Optional[str] = None
|
|
61
|
+
gateway: Optional[str] = None
|
|
62
|
+
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
|
63
|
+
delivered_at: Optional[datetime] = None
|
|
64
|
+
read_at: Optional[datetime] = None
|
|
65
|
+
|
|
66
|
+
def is_delivered(self) -> bool:
|
|
67
|
+
return self.status in {BriefingStatus.DELIVERED, BriefingStatus.READ}
|
|
68
|
+
|
|
69
|
+
def active_sections(self) -> List[BriefingSection]:
|
|
70
|
+
return [s for s in self.sections if not s.suppressed]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
# Content types
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass
|
|
79
|
+
class CalendarEvent:
|
|
80
|
+
time: str # HH:MM local time
|
|
81
|
+
title: str
|
|
82
|
+
participants: List[str]
|
|
83
|
+
prep_needed: bool = False
|
|
84
|
+
location: Optional[str] = None
|
|
85
|
+
duration_minutes: int = 30
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@dataclass
|
|
89
|
+
class DailyBriefingContent:
|
|
90
|
+
date: str # ISO-8601 date
|
|
91
|
+
calendar: List[CalendarEvent]
|
|
92
|
+
tasks: Dict[str, Any] # overdue, due_today, blocked, highlights
|
|
93
|
+
relationships: Dict[str, Any] # changes list
|
|
94
|
+
health: Optional[Dict[str, Any]] = None
|
|
95
|
+
anomalies: Optional[Dict[str, Any]] = None
|
|
96
|
+
initiatives: Optional[Dict[str, Any]] = None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class TacticalBriefingContent:
|
|
101
|
+
trigger: str
|
|
102
|
+
severity: str # "critical" | "warning" | "info"
|
|
103
|
+
summary: str
|
|
104
|
+
details: str
|
|
105
|
+
suggested_actions: List[str] = field(default_factory=list)
|
|
106
|
+
related_entities: List[str] = field(default_factory=list)
|
|
107
|
+
requires_response: bool = False
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@dataclass
|
|
111
|
+
class WeeklyBriefingContent:
|
|
112
|
+
period_start: str # ISO-8601 date
|
|
113
|
+
period_end: str # ISO-8601 date
|
|
114
|
+
task_completion_rate: float # 0.0–1.0
|
|
115
|
+
relationship_health: Dict[str, Any] # improved, declined, neglected
|
|
116
|
+
top_achievements: List[str]
|
|
117
|
+
areas_of_focus: List[str]
|
|
118
|
+
emerging_patterns: List[str]
|
|
119
|
+
upcoming_week: Dict[str, Any]
|
|
120
|
+
system_health: Dict[str, Any] # uptime, errors, backup_status
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
# Intelligence integration models
|
|
125
|
+
# ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclass
|
|
129
|
+
class BriefingCompletionSignal:
|
|
130
|
+
"""Signal emitted to the synthesis engine after briefing delivery."""
|
|
131
|
+
|
|
132
|
+
briefing_id: str
|
|
133
|
+
briefing_type: BriefingType
|
|
134
|
+
sections: List[str]
|
|
135
|
+
engaged_sections: List[str]
|
|
136
|
+
delivered_at: datetime
|
|
137
|
+
total_anomalies: int
|
|
138
|
+
active_goals: int
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@dataclass
|
|
142
|
+
class BriefingTelemetryEvent:
|
|
143
|
+
"""Telemetry for MetaLearner briefing performance tracking."""
|
|
144
|
+
|
|
145
|
+
briefing_id: str
|
|
146
|
+
briefing_type: BriefingType
|
|
147
|
+
time_to_generate_ms: float
|
|
148
|
+
time_to_deliver_ms: float
|
|
149
|
+
lm_tokens_used: int
|
|
150
|
+
section_count: int
|
|
151
|
+
engagement_score: float
|
|
152
|
+
gateway: str
|
|
153
|
+
delivered_at: datetime
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# ---------------------------------------------------------------------------
|
|
157
|
+
# Engagement
|
|
158
|
+
# ---------------------------------------------------------------------------
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@dataclass
|
|
162
|
+
class SectionEngagementRecord:
|
|
163
|
+
"""Record of user engagement with a briefing section."""
|
|
164
|
+
|
|
165
|
+
section_name: str
|
|
166
|
+
briefing_id: str
|
|
167
|
+
signal: str # "read" | "dismissed" | "acted" | "shared"
|
|
168
|
+
recorded_at: datetime
|
|
169
|
+
context: Optional[str] = None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# ---------------------------------------------------------------------------
|
|
173
|
+
# Schedule
|
|
174
|
+
# ---------------------------------------------------------------------------
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@dataclass
|
|
178
|
+
class ScheduleEntry:
|
|
179
|
+
"""Persisted schedule state for daily/weekly briefings."""
|
|
180
|
+
|
|
181
|
+
type: str # "daily" | "weekly"
|
|
182
|
+
last_run: Optional[datetime] = None
|
|
183
|
+
next_run: Optional[datetime] = None
|