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,252 @@
|
|
|
1
|
+
"""Self Reflector — evaluate own performance and identify improvements.
|
|
2
|
+
|
|
3
|
+
Analyzes:
|
|
4
|
+
- Response quality patterns
|
|
5
|
+
- Error patterns
|
|
6
|
+
- Improvement opportunities
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from typing import Any, Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
# Score thresholds for issue/improvement classification
|
|
18
|
+
_CRITICAL_THRESHOLD = 0.5
|
|
19
|
+
_WARN_THRESHOLD = 0.7
|
|
20
|
+
_GOOD_THRESHOLD = 0.85
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class Reflection:
|
|
25
|
+
"""A self-reflection on performance.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
id: Unique reflection identifier
|
|
29
|
+
area: What was reflected on ("response_quality", "tool_usage", "memory_recall")
|
|
30
|
+
score: Quality score (0-1)
|
|
31
|
+
issues: Problems identified during reflection
|
|
32
|
+
improvements: Suggested improvements
|
|
33
|
+
timestamp: When the reflection occurred
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
id: str
|
|
37
|
+
area: str
|
|
38
|
+
score: float
|
|
39
|
+
issues: List[str] = field(default_factory=list)
|
|
40
|
+
improvements: List[str] = field(default_factory=list)
|
|
41
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class SelfReflector:
|
|
45
|
+
"""Evaluate and improve own performance.
|
|
46
|
+
|
|
47
|
+
Performs self-reflection across different areas (response quality,
|
|
48
|
+
memory recall, tool usage) and tracks improvement opportunities.
|
|
49
|
+
Attempts to query ``metrics_collector`` for real performance data;
|
|
50
|
+
falls back to sensible defaults when metrics are unavailable.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
metrics_collector: Colony metrics collector for gathering performance data
|
|
54
|
+
event_bus: Colony event bus for emitting reflection events
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(self, metrics_collector: Any, event_bus: Any) -> None:
|
|
58
|
+
self.metrics = metrics_collector
|
|
59
|
+
self.events = event_bus
|
|
60
|
+
self._reflections: List[Reflection] = []
|
|
61
|
+
|
|
62
|
+
async def reflect(self, area: Optional[str] = None) -> Reflection:
|
|
63
|
+
"""Perform self-reflection on an area.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
area: Specific area to reflect on, or None for default (response_quality)
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Reflection with score, issues, and suggested improvements
|
|
70
|
+
"""
|
|
71
|
+
if area == "response_quality" or area is None:
|
|
72
|
+
reflection = await self._reflect_on_responses()
|
|
73
|
+
elif area == "memory_recall":
|
|
74
|
+
reflection = await self._reflect_on_memory()
|
|
75
|
+
elif area == "tool_usage":
|
|
76
|
+
reflection = await self._reflect_on_tool_usage()
|
|
77
|
+
else:
|
|
78
|
+
reflection = Reflection(
|
|
79
|
+
id=f"reflect-{area}-{datetime.now().isoformat()}",
|
|
80
|
+
area=area,
|
|
81
|
+
score=0.5,
|
|
82
|
+
issues=[f"No reflection handler for area: {area}"],
|
|
83
|
+
improvements=["Add dedicated reflection handler for this area"],
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
self._reflections.append(reflection)
|
|
87
|
+
logger.debug("Completed reflection on %s: score=%.2f", reflection.area, reflection.score)
|
|
88
|
+
return reflection
|
|
89
|
+
|
|
90
|
+
async def get_recent_reflections(self, limit: int = 10) -> List[Reflection]:
|
|
91
|
+
"""Get the most recent reflections.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
limit: Maximum number of reflections to return
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Most recent reflections, newest first
|
|
98
|
+
"""
|
|
99
|
+
return list(reversed(self._reflections[-limit:]))
|
|
100
|
+
|
|
101
|
+
async def get_area_trend(self, area: str) -> Dict[str, Any]:
|
|
102
|
+
"""Compute trend statistics for a specific reflection area.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
area: The reflection area to analyse
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Dict with 'count', 'avg_score', 'min_score', 'max_score', 'trend'
|
|
109
|
+
(positive = improving, negative = declining).
|
|
110
|
+
"""
|
|
111
|
+
area_reflections = [r for r in self._reflections if r.area == area]
|
|
112
|
+
if not area_reflections:
|
|
113
|
+
return {"count": 0, "avg_score": None, "min_score": None, "max_score": None, "trend": 0.0}
|
|
114
|
+
|
|
115
|
+
scores = [r.score for r in area_reflections]
|
|
116
|
+
trend = 0.0
|
|
117
|
+
if len(scores) >= 2:
|
|
118
|
+
trend = scores[-1] - scores[0]
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
"count": len(scores),
|
|
122
|
+
"avg_score": sum(scores) / len(scores),
|
|
123
|
+
"min_score": min(scores),
|
|
124
|
+
"max_score": max(scores),
|
|
125
|
+
"trend": trend,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async def _reflect_on_responses(self) -> Reflection:
|
|
129
|
+
"""Reflect on response quality using available metrics."""
|
|
130
|
+
score = 0.75
|
|
131
|
+
issues: List[str] = []
|
|
132
|
+
improvements: List[str] = []
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
if hasattr(self.metrics, "get_recent_stats"):
|
|
136
|
+
stats = await self.metrics.get_recent_stats()
|
|
137
|
+
if isinstance(stats, dict):
|
|
138
|
+
score = float(stats.get("response_quality", 0.75))
|
|
139
|
+
except Exception:
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
score = max(0.0, min(1.0, score))
|
|
143
|
+
|
|
144
|
+
if score < _CRITICAL_THRESHOLD:
|
|
145
|
+
issues.extend([
|
|
146
|
+
"Response quality significantly below threshold",
|
|
147
|
+
"High error rate detected in recent responses",
|
|
148
|
+
])
|
|
149
|
+
improvements.extend([
|
|
150
|
+
"Review response generation strategy immediately",
|
|
151
|
+
"Add output validation layer",
|
|
152
|
+
])
|
|
153
|
+
elif score < _WARN_THRESHOLD:
|
|
154
|
+
issues.append("Response quality below acceptable level")
|
|
155
|
+
improvements.append("Add brevity scoring to response evaluation")
|
|
156
|
+
elif score < _GOOD_THRESHOLD:
|
|
157
|
+
issues.append("Could be more concise in some responses")
|
|
158
|
+
improvements.append("Implement response length optimization")
|
|
159
|
+
else:
|
|
160
|
+
improvements.append("Maintain current quality standards")
|
|
161
|
+
|
|
162
|
+
return Reflection(
|
|
163
|
+
id=f"reflect-responses-{datetime.now().isoformat()}",
|
|
164
|
+
area="response_quality",
|
|
165
|
+
score=score,
|
|
166
|
+
issues=issues,
|
|
167
|
+
improvements=improvements,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
async def _reflect_on_memory(self) -> Reflection:
|
|
171
|
+
"""Reflect on memory recall accuracy."""
|
|
172
|
+
score = 0.8
|
|
173
|
+
issues: List[str] = []
|
|
174
|
+
improvements: List[str] = []
|
|
175
|
+
|
|
176
|
+
try:
|
|
177
|
+
if hasattr(self.metrics, "get_memory_stats"):
|
|
178
|
+
stats = await self.metrics.get_memory_stats()
|
|
179
|
+
if isinstance(stats, dict):
|
|
180
|
+
score = float(stats.get("recall_accuracy", 0.8))
|
|
181
|
+
except Exception:
|
|
182
|
+
pass
|
|
183
|
+
|
|
184
|
+
score = max(0.0, min(1.0, score))
|
|
185
|
+
|
|
186
|
+
if score < _CRITICAL_THRESHOLD:
|
|
187
|
+
issues.extend([
|
|
188
|
+
"Memory recall accuracy critically low",
|
|
189
|
+
"Significant number of false positives in recall",
|
|
190
|
+
])
|
|
191
|
+
improvements.extend([
|
|
192
|
+
"Rebuild memory index",
|
|
193
|
+
"Increase memory index refresh frequency",
|
|
194
|
+
])
|
|
195
|
+
elif score < _WARN_THRESHOLD:
|
|
196
|
+
issues.append("Some stale memories surfaced in recent recalls")
|
|
197
|
+
improvements.append("Increase recency weighting in recall scoring")
|
|
198
|
+
elif score < _GOOD_THRESHOLD:
|
|
199
|
+
issues.append("Occasional irrelevant memories retrieved")
|
|
200
|
+
improvements.append("Tune vector similarity threshold for recall")
|
|
201
|
+
else:
|
|
202
|
+
improvements.append("Consider expanding memory retention window")
|
|
203
|
+
|
|
204
|
+
return Reflection(
|
|
205
|
+
id=f"reflect-memory-{datetime.now().isoformat()}",
|
|
206
|
+
area="memory_recall",
|
|
207
|
+
score=score,
|
|
208
|
+
issues=issues,
|
|
209
|
+
improvements=improvements,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
async def _reflect_on_tool_usage(self) -> Reflection:
|
|
213
|
+
"""Reflect on tool usage effectiveness."""
|
|
214
|
+
score = 0.7
|
|
215
|
+
issues: List[str] = []
|
|
216
|
+
improvements: List[str] = []
|
|
217
|
+
|
|
218
|
+
try:
|
|
219
|
+
if hasattr(self.metrics, "get_tool_stats"):
|
|
220
|
+
stats = await self.metrics.get_tool_stats()
|
|
221
|
+
if isinstance(stats, dict):
|
|
222
|
+
score = float(stats.get("tool_success_rate", 0.7))
|
|
223
|
+
except Exception:
|
|
224
|
+
pass
|
|
225
|
+
|
|
226
|
+
score = max(0.0, min(1.0, score))
|
|
227
|
+
|
|
228
|
+
if score < _CRITICAL_THRESHOLD:
|
|
229
|
+
issues.extend([
|
|
230
|
+
"Significant tool failures detected",
|
|
231
|
+
"Wrong tools selected for task types",
|
|
232
|
+
])
|
|
233
|
+
improvements.extend([
|
|
234
|
+
"Review tool selection criteria",
|
|
235
|
+
"Consult ToolLearner preferences before every tool call",
|
|
236
|
+
])
|
|
237
|
+
elif score < _WARN_THRESHOLD:
|
|
238
|
+
issues.append("Some tools used for wrong task types")
|
|
239
|
+
improvements.append("Cross-reference tool learner preferences before selection")
|
|
240
|
+
elif score < _GOOD_THRESHOLD:
|
|
241
|
+
issues.append("Occasional suboptimal tool choices")
|
|
242
|
+
improvements.append("Expand tool preference learning dataset")
|
|
243
|
+
else:
|
|
244
|
+
improvements.append("Tool usage patterns are effective; continue monitoring")
|
|
245
|
+
|
|
246
|
+
return Reflection(
|
|
247
|
+
id=f"reflect-tools-{datetime.now().isoformat()}",
|
|
248
|
+
area="tool_usage",
|
|
249
|
+
score=score,
|
|
250
|
+
issues=issues,
|
|
251
|
+
improvements=improvements,
|
|
252
|
+
)
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Session Continuity — maintain context across conversation sessions.
|
|
2
|
+
|
|
3
|
+
Manages:
|
|
4
|
+
- Session handoff
|
|
5
|
+
- Context preservation
|
|
6
|
+
- Long-term memory bridging
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from datetime import datetime, timedelta
|
|
11
|
+
from typing import Any, Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class SessionContext:
|
|
20
|
+
"""Context carried across sessions.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
session_id: Unique session identifier
|
|
24
|
+
user_id: User this session belongs to
|
|
25
|
+
started_at: When the session began
|
|
26
|
+
last_activity: Most recent activity timestamp
|
|
27
|
+
topics: Topics discussed in this session
|
|
28
|
+
entities: Referenced entity IDs (people, projects, etc.)
|
|
29
|
+
pending_tasks: Tasks still in progress
|
|
30
|
+
metadata: Additional session-specific data
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
session_id: str
|
|
34
|
+
user_id: str
|
|
35
|
+
started_at: datetime = field(default_factory=datetime.now)
|
|
36
|
+
last_activity: datetime = field(default_factory=datetime.now)
|
|
37
|
+
topics: List[str] = field(default_factory=list)
|
|
38
|
+
entities: List[str] = field(default_factory=list)
|
|
39
|
+
pending_tasks: List[str] = field(default_factory=list)
|
|
40
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class SessionContinuity:
|
|
44
|
+
"""Maintain context across sessions.
|
|
45
|
+
|
|
46
|
+
Tracks active sessions per user, resumes existing sessions within
|
|
47
|
+
the timeout window, and preserves topics, entities, and pending
|
|
48
|
+
tasks across session boundaries.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
graph_client: Colony graph client for persistent session storage
|
|
52
|
+
event_bus: Colony event bus for session lifecycle events
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(self, graph_client: Any, event_bus: Any) -> None:
|
|
56
|
+
self.graph = graph_client
|
|
57
|
+
self.events = event_bus
|
|
58
|
+
self._active_sessions: Dict[str, SessionContext] = {}
|
|
59
|
+
self._session_timeout = timedelta(hours=24)
|
|
60
|
+
|
|
61
|
+
async def start_session(self, user_id: str) -> SessionContext:
|
|
62
|
+
"""Start a new session, potentially continuing from a previous one.
|
|
63
|
+
|
|
64
|
+
If an active session exists for the user within the timeout window,
|
|
65
|
+
it is resumed instead of creating a new one.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
user_id: The user starting or resuming a session
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Active or newly created SessionContext
|
|
72
|
+
"""
|
|
73
|
+
existing = await self._find_existing_session(user_id)
|
|
74
|
+
|
|
75
|
+
if existing:
|
|
76
|
+
existing.last_activity = datetime.now()
|
|
77
|
+
logger.debug("Resumed session %s for user %s", existing.session_id, user_id)
|
|
78
|
+
return existing
|
|
79
|
+
|
|
80
|
+
session_id = f"session-{user_id}-{datetime.now().isoformat()}"
|
|
81
|
+
context = SessionContext(
|
|
82
|
+
session_id=session_id,
|
|
83
|
+
user_id=user_id,
|
|
84
|
+
)
|
|
85
|
+
self._active_sessions[session_id] = context
|
|
86
|
+
|
|
87
|
+
logger.debug("Started new session %s for user %s", session_id, user_id)
|
|
88
|
+
return context
|
|
89
|
+
|
|
90
|
+
async def update_context(
|
|
91
|
+
self,
|
|
92
|
+
session_id: str,
|
|
93
|
+
topics: Optional[List[str]] = None,
|
|
94
|
+
entities: Optional[List[str]] = None,
|
|
95
|
+
pending_tasks: Optional[List[str]] = None,
|
|
96
|
+
) -> None:
|
|
97
|
+
"""Update session context with new information.
|
|
98
|
+
|
|
99
|
+
Deduplicates topics and entities. Appends pending tasks.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
session_id: Session to update
|
|
103
|
+
topics: New topics to add
|
|
104
|
+
entities: New entity IDs to add
|
|
105
|
+
pending_tasks: New pending tasks to add
|
|
106
|
+
"""
|
|
107
|
+
if session_id not in self._active_sessions:
|
|
108
|
+
logger.warning("Attempted to update unknown session %s", session_id)
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
ctx = self._active_sessions[session_id]
|
|
112
|
+
ctx.last_activity = datetime.now()
|
|
113
|
+
|
|
114
|
+
if topics:
|
|
115
|
+
ctx.topics.extend(t for t in topics if t not in ctx.topics)
|
|
116
|
+
if entities:
|
|
117
|
+
ctx.entities.extend(e for e in entities if e not in ctx.entities)
|
|
118
|
+
if pending_tasks:
|
|
119
|
+
ctx.pending_tasks.extend(pending_tasks)
|
|
120
|
+
|
|
121
|
+
async def end_session(self, session_id: str) -> Optional[SessionContext]:
|
|
122
|
+
"""Explicitly end a session.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
session_id: Session to end
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
The ended session context, or None if not found
|
|
129
|
+
"""
|
|
130
|
+
ctx = self._active_sessions.pop(session_id, None)
|
|
131
|
+
if ctx:
|
|
132
|
+
logger.debug("Ended session %s", session_id)
|
|
133
|
+
return ctx
|
|
134
|
+
|
|
135
|
+
async def get_active_session(self, user_id: str) -> Optional[SessionContext]:
|
|
136
|
+
"""Get the active session for a user, if any.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
user_id: User to look up
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Active session or None
|
|
143
|
+
"""
|
|
144
|
+
return await self._find_existing_session(user_id)
|
|
145
|
+
|
|
146
|
+
async def _find_existing_session(self, user_id: str) -> Optional[SessionContext]:
|
|
147
|
+
"""Find an existing active session within the timeout window."""
|
|
148
|
+
cutoff = datetime.now() - self._session_timeout
|
|
149
|
+
|
|
150
|
+
for ctx in self._active_sessions.values():
|
|
151
|
+
if ctx.user_id == user_id and ctx.last_activity > cutoff:
|
|
152
|
+
return ctx
|
|
153
|
+
|
|
154
|
+
return None
|