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,12 @@
|
|
|
1
|
+
"""Proposals: well-formed findings/suggestions delivered to the owner via the
|
|
2
|
+
guarded (shadow-gated, boundary-checked, rate-limited) reach-out path."""
|
|
3
|
+
|
|
4
|
+
from apsimo.proposals.models import Proposal, ProposalStore
|
|
5
|
+
from apsimo.proposals.engine import (
|
|
6
|
+
build_from_thinker, build_from_research, proposal_to_payload,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"Proposal", "ProposalStore",
|
|
11
|
+
"build_from_thinker", "build_from_research", "proposal_to_payload",
|
|
12
|
+
]
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Turn self-directed thoughts and research findings into Proposals."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from typing import Any, Dict, Optional
|
|
8
|
+
|
|
9
|
+
from apsimo.proposals.models import Proposal
|
|
10
|
+
|
|
11
|
+
_THINK_PREFIX = re.compile(r"^\[self-directed thinking\]\s*", re.IGNORECASE)
|
|
12
|
+
|
|
13
|
+
# Ungrounded rationale text: empty, or a generic "worth doing" placeholder
|
|
14
|
+
# that carries no evidence of WHY the work helps. Proposals whose only
|
|
15
|
+
# justification is one of these do not ship (honest why_it_helps: item 4).
|
|
16
|
+
_UNGROUNDED = re.compile(
|
|
17
|
+
r"^(i think this work is worth doing( now)?\.?"
|
|
18
|
+
r"|worth doing( now)?\.?"
|
|
19
|
+
r"|advances your priorities\.?"
|
|
20
|
+
r"|moves a piece of your work forward\.?)$",
|
|
21
|
+
re.IGNORECASE,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _first_sentence(text: str, limit: int = 200) -> str:
|
|
26
|
+
text = (text or "").strip()
|
|
27
|
+
if not text:
|
|
28
|
+
return ""
|
|
29
|
+
m = re.search(r"[.!?](\s|$)", text)
|
|
30
|
+
sentence = text[: m.end()].strip() if m else text
|
|
31
|
+
return sentence[:limit].strip()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def build_from_thinker(initiative: Any) -> Optional[Proposal]:
|
|
35
|
+
"""Package one self-directed-thinking initiative as a Proposal.
|
|
36
|
+
|
|
37
|
+
Returns None (does NOT ship) when the initiative carries no grounded
|
|
38
|
+
reason: ``why_it_helps`` must come from the initiative's own evidence
|
|
39
|
+
(its rationale), never a per-type template. A thought whose rationale is
|
|
40
|
+
empty or a generic "worth doing" placeholder is not deliverable.
|
|
41
|
+
"""
|
|
42
|
+
title = (getattr(initiative, "description", "") or "").strip()
|
|
43
|
+
itype = getattr(initiative, "type", None)
|
|
44
|
+
itype = getattr(itype, "value", None) or str(itype or "research")
|
|
45
|
+
rationale = _THINK_PREFIX.sub("", getattr(initiative, "rationale", "") or "").strip()
|
|
46
|
+
|
|
47
|
+
# Grounding gate: a real, evidence-bearing rationale is required.
|
|
48
|
+
if not rationale or _UNGROUNDED.match(rationale):
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
conf = float(getattr(initiative, "priority", 0.6) or 0.6)
|
|
53
|
+
except (TypeError, ValueError):
|
|
54
|
+
conf = 0.6
|
|
55
|
+
return Proposal(
|
|
56
|
+
title=title[:100] or "(proposal)",
|
|
57
|
+
finding=rationale,
|
|
58
|
+
# Grounded in the initiative's own evidence, not a template.
|
|
59
|
+
why_it_helps=_first_sentence(rationale),
|
|
60
|
+
suggested_action=title,
|
|
61
|
+
citations=[],
|
|
62
|
+
source="thinker",
|
|
63
|
+
initiative_type=itype,
|
|
64
|
+
confidence=conf,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def build_from_research(goal: str, artifact_text: str, sources: list,
|
|
69
|
+
confidence: float = 0.7) -> Optional[Proposal]:
|
|
70
|
+
"""Package a research finding (with citations) as a Proposal.
|
|
71
|
+
|
|
72
|
+
Returns None (does NOT ship) without grounded evidence: a research
|
|
73
|
+
proposal needs an actual finding AND the question that motivated it (its
|
|
74
|
+
grounded ``why_it_helps``). An empty finding or a missing goal means there
|
|
75
|
+
is nothing honest to say about why it helps.
|
|
76
|
+
"""
|
|
77
|
+
finding = (artifact_text or "").strip()
|
|
78
|
+
goal = (goal or "").strip()
|
|
79
|
+
if not finding or not goal:
|
|
80
|
+
return None
|
|
81
|
+
cites = []
|
|
82
|
+
for s in (sources or [])[:6]:
|
|
83
|
+
if isinstance(s, dict):
|
|
84
|
+
cites.append({"title": s.get("title", ""), "url": s.get("url", "")})
|
|
85
|
+
else:
|
|
86
|
+
cites.append({"title": str(getattr(s, "title", "") or ""),
|
|
87
|
+
"url": str(getattr(s, "url", "") or "")})
|
|
88
|
+
return Proposal(
|
|
89
|
+
title=goal[:100],
|
|
90
|
+
finding=finding[:1200],
|
|
91
|
+
# Grounded in the actual question that prompted the research.
|
|
92
|
+
why_it_helps=f"answers a question you're working on: {goal}"[:200],
|
|
93
|
+
suggested_action="Review the finding and tell me if you want me to go deeper.",
|
|
94
|
+
citations=cites, source="research", initiative_type="research",
|
|
95
|
+
confidence=confidence,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def proposal_to_payload(p: Proposal) -> Dict[str, Any]:
|
|
100
|
+
"""Delivery payload for a Proposal (dedicated 'proposal' type)."""
|
|
101
|
+
return {
|
|
102
|
+
"id": p.id,
|
|
103
|
+
"type": "proposal",
|
|
104
|
+
"priority": p.confidence,
|
|
105
|
+
"title": p.title[:80],
|
|
106
|
+
"description": p.render(),
|
|
107
|
+
"rationale": p.finding,
|
|
108
|
+
"suggested_action": p.suggested_action,
|
|
109
|
+
"entity_id": None, # proposals target the owner
|
|
110
|
+
"entity_type": "proposal",
|
|
111
|
+
"channel_hint": "dm",
|
|
112
|
+
"context": {},
|
|
113
|
+
"generated_at": datetime.now(timezone.utc).isoformat(),
|
|
114
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Proposal artifact + store.
|
|
2
|
+
|
|
3
|
+
A Proposal is a well-formed thing Colony wants to put in front of the owner:
|
|
4
|
+
a finding (what it noticed / learned), why it helps him, a concrete suggested
|
|
5
|
+
action, and citations. It is a DEDICATED type, distinct from routine reach-out
|
|
6
|
+
initiatives, delivered through the same guarded (shadow-gated, boundary-checked,
|
|
7
|
+
rate-limited) path.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import sqlite3
|
|
14
|
+
import threading
|
|
15
|
+
import time
|
|
16
|
+
import uuid
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from typing import Any, Dict, List, Optional
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class Proposal:
|
|
23
|
+
title: str
|
|
24
|
+
finding: str = "" # what Colony noticed / learned
|
|
25
|
+
why_it_helps: str = "" # relevance to the owner
|
|
26
|
+
suggested_action: str = "" # concrete next step
|
|
27
|
+
citations: List[Dict[str, str]] = field(default_factory=list) # [{title,url}]
|
|
28
|
+
source: str = "thinker" # thinker | research | <initiative_id>
|
|
29
|
+
initiative_type: str = "research"
|
|
30
|
+
confidence: float = 0.6
|
|
31
|
+
status: str = "shadow" # shadow | delivered | dismissed | draft
|
|
32
|
+
id: str = field(default_factory=lambda: f"prop-{uuid.uuid4().hex[:12]}")
|
|
33
|
+
created_at: float = field(default_factory=time.time)
|
|
34
|
+
route_ref: str = ""
|
|
35
|
+
result_ref: str = ""
|
|
36
|
+
subject_person_id: str = ""
|
|
37
|
+
viewer_scope: str = "owner"
|
|
38
|
+
shareability: str = "owner_private"
|
|
39
|
+
scope_digest: str = ""
|
|
40
|
+
|
|
41
|
+
def render(self) -> str:
|
|
42
|
+
"""Owner-facing text handed to the composing agent."""
|
|
43
|
+
lines = [self.title.strip()]
|
|
44
|
+
finding = self.finding.strip()
|
|
45
|
+
why = self.why_it_helps.strip()
|
|
46
|
+
if finding:
|
|
47
|
+
lines.append(f"What I found: {finding}")
|
|
48
|
+
# Skip the why-line when it merely restates the finding (the grounded
|
|
49
|
+
# why is often the finding's lead sentence) — no honest information is
|
|
50
|
+
# lost and the message stays tight.
|
|
51
|
+
if why and not (finding and finding.startswith(why)):
|
|
52
|
+
lines.append(f"Why it helps you: {why}")
|
|
53
|
+
if self.suggested_action:
|
|
54
|
+
lines.append(f"Suggested next step: {self.suggested_action.strip()}")
|
|
55
|
+
if self.citations:
|
|
56
|
+
cites = "; ".join(
|
|
57
|
+
(c.get("title") or c.get("url") or "").strip()
|
|
58
|
+
for c in self.citations if (c.get("title") or c.get("url"))
|
|
59
|
+
)
|
|
60
|
+
if cites:
|
|
61
|
+
lines.append(f"Sources: {cites}")
|
|
62
|
+
return "\n".join(lines)
|
|
63
|
+
|
|
64
|
+
def to_row(self) -> Dict[str, Any]:
|
|
65
|
+
return {
|
|
66
|
+
"id": self.id, "title": self.title, "finding": self.finding,
|
|
67
|
+
"why_it_helps": self.why_it_helps, "suggested_action": self.suggested_action,
|
|
68
|
+
"citations": json.dumps(self.citations), "source": self.source,
|
|
69
|
+
"initiative_type": self.initiative_type, "confidence": self.confidence,
|
|
70
|
+
"status": self.status, "created_at": self.created_at,
|
|
71
|
+
"route_ref": self.route_ref, "result_ref": self.result_ref,
|
|
72
|
+
"subject_person_id": self.subject_person_id,
|
|
73
|
+
"viewer_scope": self.viewer_scope,
|
|
74
|
+
"shareability": self.shareability,
|
|
75
|
+
"scope_digest": self.scope_digest,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
def visible_to(
|
|
79
|
+
self,
|
|
80
|
+
*,
|
|
81
|
+
viewer_person_id: str,
|
|
82
|
+
owner_person_id: str,
|
|
83
|
+
audiences: set[str] | frozenset[str] = frozenset(),
|
|
84
|
+
) -> bool:
|
|
85
|
+
viewer = str(viewer_person_id or "").strip()
|
|
86
|
+
if not viewer:
|
|
87
|
+
return False
|
|
88
|
+
if viewer == str(owner_person_id or "").strip():
|
|
89
|
+
return True
|
|
90
|
+
if self.shareability == "public":
|
|
91
|
+
return "global" in audiences
|
|
92
|
+
if self.shareability == "shared":
|
|
93
|
+
return "shared" in audiences
|
|
94
|
+
if self.shareability == "subject_private":
|
|
95
|
+
return viewer == self.subject_person_id
|
|
96
|
+
return False
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def from_row(cls, r: Dict[str, Any]) -> "Proposal":
|
|
100
|
+
try:
|
|
101
|
+
cites = json.loads(r.get("citations") or "[]")
|
|
102
|
+
except Exception:
|
|
103
|
+
cites = []
|
|
104
|
+
return cls(
|
|
105
|
+
id=r["id"], title=r["title"], finding=r.get("finding", "") or "",
|
|
106
|
+
why_it_helps=r.get("why_it_helps", "") or "",
|
|
107
|
+
suggested_action=r.get("suggested_action", "") or "",
|
|
108
|
+
citations=cites, source=r.get("source", "thinker") or "thinker",
|
|
109
|
+
initiative_type=r.get("initiative_type", "research") or "research",
|
|
110
|
+
confidence=float(r.get("confidence", 0.6) or 0.6),
|
|
111
|
+
status=r.get("status", "shadow") or "shadow",
|
|
112
|
+
created_at=float(r.get("created_at") or time.time()),
|
|
113
|
+
route_ref=r.get("route_ref", "") or "",
|
|
114
|
+
result_ref=r.get("result_ref", "") or "",
|
|
115
|
+
subject_person_id=r.get("subject_person_id", "") or "",
|
|
116
|
+
viewer_scope=r.get("viewer_scope", "owner") or "owner",
|
|
117
|
+
shareability=r.get("shareability", "owner_private") or "owner_private",
|
|
118
|
+
scope_digest=r.get("scope_digest", "") or "",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class ProposalStore:
|
|
123
|
+
def __init__(self, db_path: Optional[str] = None) -> None:
|
|
124
|
+
self._lock = threading.RLock()
|
|
125
|
+
self._conn = sqlite3.connect(str(db_path) if db_path else ":memory:",
|
|
126
|
+
check_same_thread=False)
|
|
127
|
+
self._conn.row_factory = sqlite3.Row
|
|
128
|
+
with self._lock:
|
|
129
|
+
self._conn.execute(
|
|
130
|
+
"""CREATE TABLE IF NOT EXISTS proposals (
|
|
131
|
+
id TEXT PRIMARY KEY, title TEXT NOT NULL, finding TEXT,
|
|
132
|
+
why_it_helps TEXT, suggested_action TEXT, citations TEXT,
|
|
133
|
+
source TEXT, initiative_type TEXT, confidence REAL,
|
|
134
|
+
status TEXT, created_at REAL, route_ref TEXT,
|
|
135
|
+
result_ref TEXT, subject_person_id TEXT,
|
|
136
|
+
viewer_scope TEXT DEFAULT 'owner',
|
|
137
|
+
shareability TEXT DEFAULT 'owner_private', scope_digest TEXT
|
|
138
|
+
)""")
|
|
139
|
+
columns = {
|
|
140
|
+
row[1] for row in self._conn.execute(
|
|
141
|
+
"PRAGMA table_info(proposals)"
|
|
142
|
+
).fetchall()
|
|
143
|
+
}
|
|
144
|
+
for name, declaration in (
|
|
145
|
+
("route_ref", "TEXT"),
|
|
146
|
+
("result_ref", "TEXT"),
|
|
147
|
+
("subject_person_id", "TEXT"),
|
|
148
|
+
("viewer_scope", "TEXT DEFAULT 'owner'"),
|
|
149
|
+
("shareability", "TEXT DEFAULT 'owner_private'"),
|
|
150
|
+
("scope_digest", "TEXT"),
|
|
151
|
+
):
|
|
152
|
+
if name not in columns:
|
|
153
|
+
self._conn.execute(
|
|
154
|
+
f"ALTER TABLE proposals ADD COLUMN {name} {declaration}"
|
|
155
|
+
)
|
|
156
|
+
self._conn.commit()
|
|
157
|
+
|
|
158
|
+
def add(self, p: Proposal) -> Proposal:
|
|
159
|
+
row = p.to_row()
|
|
160
|
+
with self._lock:
|
|
161
|
+
cols = ", ".join(row); ph = ", ".join(["?"] * len(row))
|
|
162
|
+
self._conn.execute(
|
|
163
|
+
f"INSERT OR REPLACE INTO proposals ({cols}) VALUES ({ph})",
|
|
164
|
+
list(row.values()))
|
|
165
|
+
self._conn.commit()
|
|
166
|
+
return p
|
|
167
|
+
|
|
168
|
+
def add_if_absent(self, p: Proposal) -> bool:
|
|
169
|
+
"""Insert a stable proposal without overwriting operator state."""
|
|
170
|
+
|
|
171
|
+
row = p.to_row()
|
|
172
|
+
with self._lock:
|
|
173
|
+
cols = ", ".join(row)
|
|
174
|
+
ph = ", ".join(["?"] * len(row))
|
|
175
|
+
cursor = self._conn.execute(
|
|
176
|
+
f"INSERT OR IGNORE INTO proposals ({cols}) VALUES ({ph})",
|
|
177
|
+
list(row.values()),
|
|
178
|
+
)
|
|
179
|
+
self._conn.commit()
|
|
180
|
+
return cursor.rowcount == 1
|
|
181
|
+
|
|
182
|
+
def list(self, status: Optional[str] = None, limit: int = 50) -> List[Proposal]:
|
|
183
|
+
q = "SELECT * FROM proposals"
|
|
184
|
+
params: List[Any] = []
|
|
185
|
+
if status:
|
|
186
|
+
q += " WHERE status=?"; params.append(status)
|
|
187
|
+
q += " ORDER BY created_at DESC LIMIT ?"; params.append(limit)
|
|
188
|
+
with self._lock:
|
|
189
|
+
rows = self._conn.execute(q, params).fetchall()
|
|
190
|
+
return [Proposal.from_row(dict(r)) for r in rows]
|
|
191
|
+
|
|
192
|
+
def get(self, proposal_id: str) -> Optional[Proposal]:
|
|
193
|
+
with self._lock:
|
|
194
|
+
row = self._conn.execute(
|
|
195
|
+
"SELECT * FROM proposals WHERE id=?", (proposal_id,),
|
|
196
|
+
).fetchone()
|
|
197
|
+
return Proposal.from_row(dict(row)) if row is not None else None
|
|
198
|
+
|
|
199
|
+
def set_status(self, proposal_id: str, status: str) -> bool:
|
|
200
|
+
with self._lock:
|
|
201
|
+
cur = self._conn.execute(
|
|
202
|
+
"UPDATE proposals SET status=? WHERE id=?", (status, proposal_id))
|
|
203
|
+
self._conn.commit()
|
|
204
|
+
return cur.rowcount > 0
|
|
205
|
+
|
|
206
|
+
def count(self, status: Optional[str] = None) -> int:
|
|
207
|
+
return len(self.list(status=status, limit=100000))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Opt-in, finite qualification through existing model consumers."""
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Small neutral cases. A role completion is not native agent qualification."""
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from .records import CaseSpec
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def role_completion(inputs, context):
|
|
8
|
+
response = await context.router.complete(inputs['messages'], context={
|
|
9
|
+
'function_role': inputs['role'], 'allow_fallback': False,
|
|
10
|
+
'max_output_tokens': inputs.get('max_output_tokens', 512)})
|
|
11
|
+
return {'output': response.content, 'effects': {}}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def json_fields(observed, oracle):
|
|
15
|
+
"""Exact independently specified fields, not a model judging itself."""
|
|
16
|
+
output = observed.get('output')
|
|
17
|
+
if isinstance(output, str):
|
|
18
|
+
try:
|
|
19
|
+
output = json.loads(output)
|
|
20
|
+
except (ValueError, TypeError):
|
|
21
|
+
return {'output_is_json': False}
|
|
22
|
+
root = {**observed, 'output': output}
|
|
23
|
+
checks = {}
|
|
24
|
+
for item in oracle['fields']:
|
|
25
|
+
current = root
|
|
26
|
+
try:
|
|
27
|
+
for part in item['path']:
|
|
28
|
+
current = current[part]
|
|
29
|
+
except (KeyError, IndexError, TypeError):
|
|
30
|
+
checks[item['name']] = False
|
|
31
|
+
else:
|
|
32
|
+
checks[item['name']] = type(current) is type(item['equals']) and current == item['equals']
|
|
33
|
+
return checks
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
STANDARD = [
|
|
37
|
+
CaseSpec(id='chat.grounded-note', version='1', role='chat', boundary='role_completion',
|
|
38
|
+
consumer='role_completion', evaluator='json_fields',
|
|
39
|
+
inputs={'role': 'chat', 'messages': [
|
|
40
|
+
{'role': 'system', 'content': 'Answer from the supplied note only. Return a JSON object; use null for information absent from the note.'},
|
|
41
|
+
{'role': 'user', 'content': 'Note: The blue sample case is in drawer 4. The silver case was moved, but its new location is unknown. Where is each case? Use keys blue and silver.'}]},
|
|
42
|
+
oracle={'fields': [
|
|
43
|
+
{'name': 'known_location', 'path': ['output', 'blue'], 'equals': 'drawer 4'},
|
|
44
|
+
{'name': 'unknown_preserved', 'path': ['output', 'silver'], 'equals': None}]}),
|
|
45
|
+
CaseSpec(id='extraction.conditions', version='1', role='extraction', boundary='role_completion',
|
|
46
|
+
consumer='role_completion', evaluator='json_fields',
|
|
47
|
+
inputs={'role': 'extraction', 'messages': [
|
|
48
|
+
{'role': 'system', 'content': 'Extract only explicit information. Return JSON with keys item, location, valid_day, requires_wet_shelf (boolean), owner. Use null for absent information.'},
|
|
49
|
+
{'role': 'user', 'content': 'For tomorrow only, put the blue sample case in drawer 4 if the shelf is wet. Nobody has identified its owner.'}]},
|
|
50
|
+
oracle={'fields': [
|
|
51
|
+
{'name': 'item', 'path': ['output', 'item'], 'equals': 'blue sample case'},
|
|
52
|
+
{'name': 'location', 'path': ['output', 'location'], 'equals': 'drawer 4'},
|
|
53
|
+
{'name': 'time_condition', 'path': ['output', 'valid_day'], 'equals': 'tomorrow'},
|
|
54
|
+
{'name': 'wet_shelf_condition', 'path': ['output', 'requires_wet_shelf'], 'equals': True},
|
|
55
|
+
{'name': 'unknown_owner', 'path': ['output', 'owner'], 'equals': None}]}),
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
CONSUMERS = {'role_completion': role_completion}
|
|
59
|
+
EVALUATORS = {'json_fields': json_fields}
|
|
60
|
+
|
|
61
|
+
from .memory_cases import CASES as MEMORY_CASES, CONSUMERS as MEMORY_CONSUMERS, EVALUATORS as MEMORY_EVALUATORS
|
|
62
|
+
STANDARD.extend(MEMORY_CASES)
|
|
63
|
+
CONSUMERS.update(MEMORY_CONSUMERS)
|
|
64
|
+
EVALUATORS.update(MEMORY_EVALUATORS)
|
|
65
|
+
|
|
66
|
+
from .structured_cases import CASES as STRUCTURED_CASES
|
|
67
|
+
STANDARD.extend(STRUCTURED_CASES)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def select_cases(roles):
|
|
71
|
+
cases = [case for case in STANDARD if case.role in roles]
|
|
72
|
+
uncovered = set(roles) - {case.role for case in cases}
|
|
73
|
+
if uncovered:
|
|
74
|
+
raise ValueError('No installed standard cases for roles: ' + ', '.join(sorted(uncovered)))
|
|
75
|
+
return cases
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Opt-in CLI. Inspect/compare are offline; evaluate invokes selected consumers."""
|
|
2
|
+
import asyncio
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def add_parser(sub):
|
|
8
|
+
parser = sub.add_parser('models', help='Inspect and qualify model bindings without selecting a deployment')
|
|
9
|
+
commands = parser.add_subparsers(dest='models_command', required=True)
|
|
10
|
+
for command in ('inspect', 'evaluate'):
|
|
11
|
+
item = commands.add_parser(command)
|
|
12
|
+
item.add_argument('binding', help='Existing modelPool or named tier binding')
|
|
13
|
+
item.add_argument('--config', required=True, type=Path, help='Existing private host model configuration JSON')
|
|
14
|
+
if command == 'evaluate':
|
|
15
|
+
item.add_argument('--roles', default='chat,extraction')
|
|
16
|
+
item.add_argument('--suite', choices=['standard'], default='standard')
|
|
17
|
+
item.add_argument('--evidence-mode', choices=['actual_inference', 'controlled'], default='actual_inference',
|
|
18
|
+
help='Label controlled fixtures separately; neither label attests serving weights')
|
|
19
|
+
item.add_argument('--output', required=True, type=Path, help='New private result directory')
|
|
20
|
+
item.add_argument('--resume', action='store_true', help='Continue untouched cases; interrupted attempts are never rerun')
|
|
21
|
+
item = commands.add_parser('compare')
|
|
22
|
+
item.add_argument('incumbent', type=Path)
|
|
23
|
+
item.add_argument('candidate', type=Path)
|
|
24
|
+
item.add_argument('--json', action='store_true')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def run(args):
|
|
28
|
+
from .records import read, write_once, publish
|
|
29
|
+
from .report import compare, summarize, markdown
|
|
30
|
+
if args.models_command == 'compare':
|
|
31
|
+
report = compare(args.incumbent, args.candidate)
|
|
32
|
+
print(json.dumps(report, indent=2) if args.json else markdown(report))
|
|
33
|
+
return 0
|
|
34
|
+
from .runner import inspect_binding, router_for, evaluate
|
|
35
|
+
config = read(args.config)
|
|
36
|
+
recipe = inspect_binding(config, args.binding)
|
|
37
|
+
if args.models_command == 'inspect':
|
|
38
|
+
print(json.dumps(recipe, indent=2))
|
|
39
|
+
return 0
|
|
40
|
+
from .cases import select_cases, CONSUMERS, EVALUATORS
|
|
41
|
+
cases = select_cases([r.strip() for r in args.roles.split(',') if r.strip()])
|
|
42
|
+
asyncio.run(evaluate(args.output, recipe, cases, CONSUMERS, EVALUATORS,
|
|
43
|
+
lambda case: router_for(config, args.binding, [case]), resume=args.resume, evidence_mode=args.evidence_mode))
|
|
44
|
+
report = summarize(args.output)
|
|
45
|
+
# Reports are new immutable views. Earlier reports remain useful when a run resumes.
|
|
46
|
+
index = len(list(args.output.glob('report-*.json'))) + 1
|
|
47
|
+
write_once(args.output / f'report-{index:03d}.json', report)
|
|
48
|
+
text = markdown(report)
|
|
49
|
+
publish(args.output / f'report-{index:03d}.md', text.encode())
|
|
50
|
+
print(text)
|
|
51
|
+
return 0 if all(row['outcome'] == 'pass' for row in report['cases']) else 1
|