Add bounded venture concurrency and model keys

This commit is contained in:
Daniel Maddern 2026-08-16 15:08:32 +07:00
parent 86c52c6f6b
commit 2bbcc9e272
7 changed files with 204 additions and 34 deletions

View file

@ -3,12 +3,15 @@ from __future__ import annotations
import hashlib import hashlib
import json import json
import re import re
import threading
import time import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from itertools import combinations from itertools import combinations
from decimal import Decimal from decimal import Decimal
from typing import Any from typing import Any
from collections import Counter, defaultdict from collections import Counter, defaultdict
from django.db import close_old_connections, connection
from django.utils import timezone from django.utils import timezone
from control_plane.events.bus import EventBus from control_plane.events.bus import EventBus
@ -31,6 +34,7 @@ class VentureDiscoveryService:
self.bus = bus or EventBus() self.bus = bus or EventBus()
self.web_research_available = web_research_available self.web_research_available = web_research_available
self.research_model_hint = research_model_hint self.research_model_hint = research_model_hint
self._last_bounded_map_peak = 0
def create_v0_mandate(self) -> CompanyMandate: def create_v0_mandate(self) -> CompanyMandate:
mandate = CompanyMandate.objects.create( mandate = CompanyMandate.objects.create(
@ -230,24 +234,38 @@ class VentureDiscoveryService:
return VentureCohort.objects.create(cohort_id=cohort_id, mandate=mandate, cohort_size=size, graph_run=graph_run, concurrency=concurrency, status="PREPARING", graph_versions={"cohort": "venture_discovery_cohort v1", "company": "venture_discovery v1"}, research_policy={"stage_a": "lightweight_all", "deeper_research": "top_5_if_required", "no_spend": True, "no_customer_outreach": True}, scoring_policy={"dimensions": SCORE_DEFINITIONS}, evidence_calibration_policy={tier: ceiling for tier, ceiling in EVIDENCE_CEILINGS.items()}, metadata={"real_spend": 0, "real_customer_outreach": False}) return VentureCohort.objects.create(cohort_id=cohort_id, mandate=mandate, cohort_size=size, graph_run=graph_run, concurrency=concurrency, status="PREPARING", graph_versions={"cohort": "venture_discovery_cohort v1", "company": "venture_discovery v1"}, research_policy={"stage_a": "lightweight_all", "deeper_research": "top_5_if_required", "no_spend": True, "no_customer_outreach": True}, scoring_policy={"dimensions": SCORE_DEFINITIONS}, evidence_calibration_policy={tier: ceiling for tier, ceiling in EVIDENCE_CEILINGS.items()}, metadata={"real_spend": 0, "real_customer_outreach": False})
def generate_independent_proposals(self, cohort: VentureCohort) -> list[CompanyProposal]: def generate_independent_proposals(self, cohort: VentureCohort) -> list[CompanyProposal]:
proposals = [] started = time.monotonic()
for index in range(cohort.cohort_size):
def generate(index: int) -> tuple[int, str]:
proposal = self.generate_single_company(cohort.mandate, ideation_index=index + 1) proposal = self.generate_single_company(cohort.mandate, ideation_index=index + 1)
proposal.metadata = {**proposal.metadata, "cohort_id": cohort.cohort_id, "independent_generation_index": index + 1, "prior_ideas_visible": False} return index, str(proposal.id)
generated = self._bounded_map(range(cohort.cohort_size), generate, cohort.concurrency)
peak_concurrency = self._last_bounded_map_peak
proposals = []
for index, proposal_id in sorted(generated, key=lambda item: item[0]):
proposal = CompanyProposal.objects.get(id=proposal_id)
generation_index = index + 1
proposal.metadata = {**proposal.metadata, "cohort_id": cohort.cohort_id, "independent_generation_index": generation_index, "prior_ideas_visible": False}
proposal.save(update_fields=["metadata", "updated_at"]) proposal.save(update_fields=["metadata", "updated_at"])
VentureCohortMember.objects.create(cohort=cohort, proposal=proposal, metadata={"generation_index": index + 1}) VentureCohortMember.objects.create(cohort=cohort, proposal=proposal, metadata={"generation_index": generation_index})
proposals.append(proposal) proposals.append(proposal)
cohort.status = "PROPOSALS_GENERATED" cohort.status = "PROPOSALS_GENERATED"
cohort.save(update_fields=["status", "updated_at"]) cohort.metrics = {**cohort.metrics, "proposal_generation_runtime_seconds": round(time.monotonic() - started, 2), "proposal_generation_peak_concurrency": peak_concurrency}
cohort.save(update_fields=["metrics", "status", "updated_at"])
return proposals return proposals
def research_cohort(self, cohort: VentureCohort) -> None: def research_cohort(self, cohort: VentureCohort) -> None:
started = time.monotonic() started = time.monotonic()
sources = 0
for member in cohort.members.select_related("proposal").order_by("created_at"): def research(member_id: str) -> int:
research = self.conduct_market_research(member.proposal) member = VentureCohortMember.objects.select_related("proposal").get(id=member_id)
sources += len(research.get("sources", [])) return len(self.conduct_market_research(member.proposal).get("sources", []))
cohort.metrics = {**cohort.metrics, "research_runtime_seconds": round(time.monotonic() - started, 2), "total_sources": sources, "public_research_queries": cohort.members.count(), "peak_concurrency": cohort.concurrency}
member_ids = [str(member.id) for member in cohort.members.order_by("created_at")]
source_counts = self._bounded_map(member_ids, research, cohort.concurrency)
peak_concurrency = self._last_bounded_map_peak
cohort.metrics = {**cohort.metrics, "research_runtime_seconds": round(time.monotonic() - started, 2), "total_sources": sum(source_counts), "public_research_queries": len(member_ids), "research_peak_concurrency": peak_concurrency, "peak_concurrency": max(cohort.metrics.get("peak_concurrency", 0), peak_concurrency)}
cohort.status = "RESEARCHED" cohort.status = "RESEARCHED"
cohort.save(update_fields=["metrics", "status", "updated_at"]) cohort.save(update_fields=["metrics", "status", "updated_at"])
@ -264,7 +282,9 @@ class VentureDiscoveryService:
def run_individual_diligence_for_cohort(self, cohort: VentureCohort) -> None: def run_individual_diligence_for_cohort(self, cohort: VentureCohort) -> None:
started = time.monotonic() started = time.monotonic()
for member in cohort.members.select_related("proposal"):
def diligence(member_id: str) -> None:
member = VentureCohortMember.objects.select_related("proposal").get(id=member_id)
proposal = member.proposal proposal = member.proposal
self.board_review(proposal) self.board_review(proposal)
diligence = self.start_ic_diligence(proposal) diligence = self.start_ic_diligence(proposal)
@ -277,7 +297,11 @@ class VentureDiscoveryService:
self.produce_investment_memo(diligence, gap) self.produce_investment_memo(diligence, gap)
member.child_graph_run = GraphRun.objects.create(execution_graph_version=cohort.graph_run.execution_graph_version if cohort.graph_run else None, status=GraphRunStatus.COMPLETE, metadata={"logical_child_company_run": True, "proposal_id": str(proposal.id), "cohort_id": cohort.cohort_id}) if cohort.graph_run else None member.child_graph_run = GraphRun.objects.create(execution_graph_version=cohort.graph_run.execution_graph_version if cohort.graph_run else None, status=GraphRunStatus.COMPLETE, metadata={"logical_child_company_run": True, "proposal_id": str(proposal.id), "cohort_id": cohort.cohort_id}) if cohort.graph_run else None
member.save(update_fields=["child_graph_run", "updated_at"]) member.save(update_fields=["child_graph_run", "updated_at"])
cohort.metrics = {**cohort.metrics, "individual_diligence_runtime_seconds": round(time.monotonic() - started, 2)}
member_ids = [str(member.id) for member in cohort.members.order_by("created_at")]
self._bounded_map(member_ids, diligence, cohort.concurrency)
peak_concurrency = self._last_bounded_map_peak
cohort.metrics = {**cohort.metrics, "individual_diligence_runtime_seconds": round(time.monotonic() - started, 2), "individual_diligence_peak_concurrency": peak_concurrency, "peak_concurrency": max(cohort.metrics.get("peak_concurrency", 0), peak_concurrency)}
cohort.status = "INDIVIDUAL_DILIGENCE_COMPLETE" cohort.status = "INDIVIDUAL_DILIGENCE_COMPLETE"
cohort.save(update_fields=["metrics", "status", "updated_at"]) cohort.save(update_fields=["metrics", "status", "updated_at"])
@ -352,6 +376,48 @@ class VentureDiscoveryService:
adjusted = min(float(raw_probability), ceiling) adjusted = min(float(raw_probability), ceiling)
return {"raw_probability": float(raw_probability), "evidence_adjusted_probability": adjusted, "evidence_ceiling": ceiling, "evidence_tier": tier, "explanation": f"{tier} caps P($500/30d) at {ceiling}%; IC uses {adjusted}%."} return {"raw_probability": float(raw_probability), "evidence_adjusted_probability": adjusted, "evidence_ceiling": ceiling, "evidence_tier": tier, "explanation": f"{tier} caps P($500/30d) at {ceiling}%; IC uses {adjusted}%."}
def _bounded_map(self, items: list[Any] | range, worker: Any, concurrency: int) -> list[Any]:
self._last_bounded_map_peak = 0
workers = self._effective_concurrency(concurrency)
if workers <= 1:
results = [worker(item) for item in items]
self._last_bounded_map_peak = 1 if results else 0
return results
results: list[tuple[int, Any]] = []
active = 0
active_lock = threading.Lock()
def tracked_worker(item: Any) -> Any:
nonlocal active
with active_lock:
active += 1
self._last_bounded_map_peak = max(self._last_bounded_map_peak, active)
try:
return self._threaded_worker(worker, item)
finally:
with active_lock:
active -= 1
with ThreadPoolExecutor(max_workers=workers) as executor:
futures = {executor.submit(tracked_worker, item): index for index, item in enumerate(items)}
for future in as_completed(futures):
results.append((futures[future], future.result()))
results.sort(key=lambda item: item[0])
return [result for _, result in results]
def _threaded_worker(self, worker: Any, item: Any) -> Any:
close_old_connections()
try:
return worker(item)
finally:
close_old_connections()
def _effective_concurrency(self, concurrency: int) -> int:
requested = max(1, int(concurrency or 1))
if connection.vendor == "sqlite" and connection.settings_dict.get("NAME") == ":memory:":
return 1
return requested
def validate_identity_content(self, proposal: CompanyProposal, content: Any) -> dict[str, Any]: def validate_identity_content(self, proposal: CompanyProposal, content: Any) -> dict[str, Any]:
text = json.dumps(content, default=str).lower() text = json.dumps(content, default=str).lower()
checks = { checks = {

View file

@ -11,7 +11,8 @@ class Command(BaseCommand):
help = "Check configured model provider health without crashing the control plane." help = "Check configured model provider health without crashing the control plane."
def handle(self, *args, **options): def handle(self, *args, **options):
for resource in Resource.objects.filter(is_active=True, kind="MODEL"): resources = sorted(Resource.objects.filter(is_active=True, kind="MODEL"), key=self.sort_key)
for resource in resources:
if resource.provider == "opencode": if resource.provider == "opencode":
status = SolProvider(resource).health() status = SolProvider(resource).health()
elif resource.provider == "local_inference": elif resource.provider == "local_inference":
@ -22,3 +23,10 @@ class Command(BaseCommand):
resource.last_health_check_at = timezone.now() resource.last_health_check_at = timezone.now()
resource.save(update_fields=["health_status", "last_health_check_at", "updated_at"]) resource.save(update_fields=["health_status", "last_health_check_at", "updated_at"])
self.stdout.write(f"{resource.name}: {status}") self.stdout.write(f"{resource.name}: {status}")
def sort_key(self, resource: Resource) -> tuple[int, str]:
model_key = str(resource.config.get("model_key") or "").lower()
if resource.provider == "local_inference":
model_key = "qwen"
order = {"qwen": 0, "sol": 1, "terra": 2, "luna": 3}
return order.get(model_key, 100), resource.name

View file

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import os import os
import shutil
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
@ -10,6 +11,39 @@ from control_plane.resources.models import Resource, ResourceKind
class Command(BaseCommand): class Command(BaseCommand):
help = "Seed DGX Spark compute and model resources for Sol and Qwen." help = "Seed DGX Spark compute and model resources for Sol and Qwen."
def opencode_command(self, model_key: str) -> str:
env_name = f"ARTIFEX_{model_key.upper()}_OPENCODE_COMMAND"
if os.environ.get(env_name):
return os.environ[env_name]
executable = shutil.which("opencode") or "opencode"
return f"{executable} run"
def opencode_config(self, model_key: str) -> dict[str, object]:
return {
"model_key": model_key,
"transport": os.environ.get(f"ARTIFEX_{model_key.upper()}_TRANSPORT", os.environ.get("ARTIFEX_OPENCODE_TRANSPORT", "local")),
"command": self.opencode_command(model_key),
"use_pty": os.environ.get(f"ARTIFEX_{model_key.upper()}_USE_PTY", os.environ.get("ARTIFEX_OPENCODE_USE_PTY", "0")) == "1",
"timeout_seconds": int(os.environ.get(f"ARTIFEX_{model_key.upper()}_TIMEOUT_SECONDS", os.environ.get("ARTIFEX_OPENCODE_TIMEOUT_SECONDS", "120"))),
}
def update_opencode_resource(self, *, model_key: str, name: str, roles: list[str], compute: Resource) -> None:
defaults = {
"name": name,
"kind": ResourceKind.MODEL,
"provider": "opencode",
"compute": compute,
"roles": roles,
"config": self.opencode_config(model_key),
}
existing = next((resource for resource in Resource.objects.filter(provider="opencode") if resource.config.get("model_key") == model_key), None)
if existing is not None:
for field, value in defaults.items():
setattr(existing, field, value)
existing.save(update_fields=[*defaults.keys(), "updated_at"])
return
Resource.objects.update_or_create(name=name, defaults={key: value for key, value in defaults.items() if key != "name"})
def handle(self, *args, **options): def handle(self, *args, **options):
spark, _ = Resource.objects.update_or_create( spark, _ = Resource.objects.update_or_create(
name=os.environ.get("ARTIFEX_SPARK_RESOURCE_NAME", "DGX Spark"), name=os.environ.get("ARTIFEX_SPARK_RESOURCE_NAME", "DGX Spark"),
@ -20,20 +54,23 @@ class Command(BaseCommand):
"roles": [], "roles": [],
}, },
) )
Resource.objects.update_or_create( self.update_opencode_resource(
model_key="sol",
name=os.environ.get("ARTIFEX_SOL_RESOURCE_NAME", "GPT-5.6 Sol"), name=os.environ.get("ARTIFEX_SOL_RESOURCE_NAME", "GPT-5.6 Sol"),
defaults={ roles=["PROJECT_BRAIN", "PLANNING", "ARCHAEOLOGY_INTERPRETATION", "AGENT_DESIGN", "ESCALATION"],
"kind": ResourceKind.MODEL, compute=spark,
"provider": "opencode", )
"compute": spark, self.update_opencode_resource(
"roles": ["PROJECT_BRAIN", "PLANNING", "ARCHAEOLOGY_INTERPRETATION"], model_key="terra",
"config": { name=os.environ.get("ARTIFEX_TERRA_RESOURCE_NAME", "GPT-5.6 Terra"),
"transport": os.environ.get("ARTIFEX_SOL_TRANSPORT", "local"), roles=["REASONING", "REVIEW", "PORTFOLIO_IC", "STRATEGY"],
"command": os.environ.get("ARTIFEX_SOL_OPENCODE_COMMAND", "/home/daniel/.opencode/bin/opencode run"), compute=spark,
"use_pty": os.environ.get("ARTIFEX_SOL_USE_PTY", "1") == "1", )
"timeout_seconds": int(os.environ.get("ARTIFEX_SOL_TIMEOUT_SECONDS", "120")), self.update_opencode_resource(
}, model_key="luna",
}, name=os.environ.get("ARTIFEX_LUNA_RESOURCE_NAME", "GPT-5.6 Luna"),
roles=["REASONING", "MARKET_RESEARCH", "WEB_RESEARCH", "SYNTHESIS"],
compute=spark,
) )
Resource.objects.update_or_create( Resource.objects.update_or_create(
name=os.environ.get("ARTIFEX_QWEN_RESOURCE_NAME", "Qwen"), name=os.environ.get("ARTIFEX_QWEN_RESOURCE_NAME", "Qwen"),

View file

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import json import json
import os
import re import re
import shlex import shlex
import subprocess import subprocess
@ -62,7 +63,7 @@ class SolProvider:
transport = str(config.get("transport", "ssh")) transport = str(config.get("transport", "ssh"))
use_pty = bool(config.get("use_pty", False)) use_pty = bool(config.get("use_pty", False))
if transport == "local": if transport == "local":
argv = [*shlex.split(command), request.prompt] argv = [*shlex.split(command, posix=os.name != "nt"), request.prompt]
if use_pty: if use_pty:
shell_command = " ".join(shlex.quote(part) for part in argv) shell_command = " ".join(shlex.quote(part) for part in argv)
argv = ["script", "-q", "-e", "-c", shell_command, "/dev/null"] argv = ["script", "-q", "-e", "-c", shell_command, "/dev/null"]
@ -92,7 +93,7 @@ class SolProvider:
config = self.resource.config config = self.resource.config
try: try:
if config.get("transport") == "local": if config.get("transport") == "local":
command = shlex.split(str(config.get("command", "opencode")))[0] command = shlex.split(str(config.get("command", "opencode")), posix=os.name != "nt")[0]
completed = subprocess.run([command, "--version"], capture_output=True, text=True, timeout=10, check=False) completed = subprocess.run([command, "--version"], capture_output=True, text=True, timeout=10, check=False)
else: else:
compute = self.resource.compute compute = self.resource.compute
@ -161,10 +162,16 @@ class QwenProvider:
def providers_from_resources() -> dict[str, object]: def providers_from_resources() -> dict[str, object]:
providers: dict[str, object] = {} providers: dict[str, object] = {}
sol = Resource.objects.filter(is_active=True, provider="opencode").first() opencode_resources = Resource.objects.filter(is_active=True, provider="opencode")
qwen = Resource.objects.filter(is_active=True, provider="local_inference").first() qwen = Resource.objects.filter(is_active=True, provider="local_inference").first()
if sol is not None: for resource in opencode_resources:
providers["sol"] = SolProvider(sol) model_key = str(resource.config.get("model_key") or "").strip().lower()
if model_key:
providers[model_key] = SolProvider(resource)
if "sol" not in providers:
sol = opencode_resources.first()
if sol is not None:
providers["sol"] = SolProvider(sol)
if qwen is not None: if qwen is not None:
providers["qwen"] = QwenProvider(qwen) providers["qwen"] = QwenProvider(qwen)
return providers return providers

View file

@ -99,8 +99,11 @@ class ModelRouter:
provider_names = {provider_key} provider_names = {provider_key}
if provider_key == "qwen": if provider_key == "qwen":
provider_names.add("local_inference") provider_names.add("local_inference")
if provider_key == "sol": if provider_key in {"sol", "terra", "luna"}:
provider_names.add("opencode") provider_names.add("opencode")
for resource in candidates:
if resource.config.get("model_key") == provider_key:
return resource
for resource in candidates: for resource in candidates:
if resource.provider in provider_names and role in resource.roles: if resource.provider in provider_names and role in resource.roles:
return resource return resource

View file

@ -1,7 +1,8 @@
from __future__ import annotations from __future__ import annotations
from agents.providers import DeterministicCodingProvider from agents.providers import DeterministicCodingProvider, DeterministicSolProvider
from control_plane.resources.models import ModelRequest, Resource, ResourceKind from control_plane.resources.models import ModelRequest, Resource, ResourceKind
from model_router.providers import SolProvider, providers_from_resources
from model_router.router import ModelCapability, ModelRequestContract, ModelRouter from model_router.router import ModelCapability, ModelRequestContract, ModelRouter
@ -28,3 +29,24 @@ def test_model_router_health_is_non_throwing() -> None:
router = ModelRouter({"qwen": DeterministicCodingProvider()}) router = ModelRouter({"qwen": DeterministicCodingProvider()})
assert router.health() == {"qwen": "AVAILABLE"} assert router.health() == {"qwen": "AVAILABLE"}
def test_opencode_model_key_resources_load_as_distinct_providers() -> None:
for key in ["sol", "terra", "luna"]:
Resource.objects.create(name=key.title(), kind=ResourceKind.MODEL, provider="opencode", roles=["REASONING"], config={"model_key": key})
providers = providers_from_resources()
assert {"sol", "terra", "luna"}.issubset(providers)
assert all(isinstance(providers[key], SolProvider) for key in ["sol", "terra", "luna"])
def test_model_router_prefers_exact_model_key_resource_for_persisted_requests() -> None:
Resource.objects.create(name="Generic Opencode", kind=ResourceKind.MODEL, provider="opencode", roles=["REASONING"], config={})
Resource.objects.create(name="Terra", kind=ResourceKind.MODEL, provider="opencode", roles=["REASONING"], config={"model_key": "terra"})
router = ModelRouter({"terra": DeterministicSolProvider("{}")}, persist_requests=True)
router.complete(ModelRequestContract(purpose=ModelCapability.REASONING, model_hint="terra", prompt="{}"))
request = ModelRequest.objects.get()
assert request.model == "Terra"

View file

@ -1,6 +1,8 @@
from __future__ import annotations from __future__ import annotations
import json import json
import threading
import time
from agents.venture_discovery import EVIDENCE_CEILINGS, SCORE_DEFINITIONS, SCORE_DIMENSIONS, VentureDiscoveryService from agents.venture_discovery import EVIDENCE_CEILINGS, SCORE_DEFINITIONS, SCORE_DIMENSIONS, VentureDiscoveryService
from control_plane.ventures.models import CompanyProposal, EvidenceTier, OverlapClassification, PortfolioICReview, VentureCapabilityDemand, VentureCohort, VentureCollision, VentureThesisFingerprint from control_plane.ventures.models import CompanyProposal, EvidenceTier, OverlapClassification, PortfolioICReview, VentureCapabilityDemand, VentureCohort, VentureCollision, VentureThesisFingerprint
@ -38,6 +40,28 @@ def service() -> VentureDiscoveryService:
return VentureDiscoveryService(ModelRouter({"sol": provider, "luna": provider}), web_research_available=True) return VentureDiscoveryService(ModelRouter({"sol": provider, "luna": provider}), web_research_available=True)
def test_bounded_map_runs_concurrently_and_preserves_result_order() -> None:
svc = VentureDiscoveryService()
svc._effective_concurrency = lambda concurrency: concurrency
active = 0
observed_peak = 0
lock = threading.Lock()
def worker(value: int) -> int:
nonlocal active, observed_peak
with lock:
active += 1
observed_peak = max(observed_peak, active)
time.sleep(0.02)
with lock:
active -= 1
return value * 2
assert svc._bounded_map([1, 2, 3, 4], worker, 2) == [2, 4, 6, 8]
assert observed_peak == 2
assert svc._last_bounded_map_peak == 2
def test_evidence_tiers_probability_ceiling_and_score_orientation() -> None: def test_evidence_tiers_probability_ceiling_and_score_orientation() -> None:
svc = service() svc = service()
proposal = svc.generate_single_company(svc.create_v0_mandate()) proposal = svc.generate_single_company(svc.create_v0_mandate())
@ -120,7 +144,10 @@ def test_cohort_size_ranking_top3_capability_aggregation_and_graph_lineage() ->
assert cohort.metadata["real_spend"] == 0 assert cohort.metadata["real_spend"] == 0
assert cohort.metadata["real_customer_outreach"] is False assert cohort.metadata["real_customer_outreach"] is False
assert cohort.concurrency == 2 assert cohort.concurrency == 2
assert cohort.metrics["peak_concurrency"] == 2 assert cohort.metrics["peak_concurrency"] == 1
assert cohort.metrics["proposal_generation_peak_concurrency"] == 1
assert cohort.metrics["research_peak_concurrency"] == 1
assert cohort.metrics["individual_diligence_peak_concurrency"] == 1
report = cohort.mandate.artifacts.get(artifact_type="VENTURE_DISCOVERY_COHORT_REPORT") report = cohort.mandate.artifacts.get(artifact_type="VENTURE_DISCOVERY_COHORT_REPORT")
assert len(report.content["rankings"]) == 10 assert len(report.content["rankings"]) == 10
assert len(report.content["top_3"]) == 3 assert len(report.content["top_3"]) == 3