Spaces:
Sleeping
Sleeping
| # salespath_env/server/task_bank.py | |
| """ | |
| Prospect profiles, organised by difficulty. | |
| Per arXiv:2408.10215 §3 ("Reward shaping cannot fix data scarcity"), | |
| the training distribution must be wide enough that the policy cannot | |
| overfit to a handful of memorised episodes. We expand to ~20 profiles | |
| per level and reserve the last 4 of each level as a held-out eval set. | |
| Public API | |
| ---------- | |
| sample_profile(difficulty, split="train", rng=None) | |
| Sample a profile for online training/eval. | |
| iter_eval_profiles(difficulty) | |
| Iterate over the held-out eval profiles. | |
| iter_train_profiles(difficulty) | |
| Iterate over the training profiles. | |
| """ | |
| from __future__ import annotations | |
| import random | |
| from dataclasses import dataclass | |
| from typing import Iterator, List, Optional | |
| class ProspectProfile: | |
| company_name: str | |
| company_size: str # small / medium / enterprise | |
| industry: str | |
| budget_signal: str # high / medium / low / unknown | |
| pain_points: List[str] | |
| decision_maker: bool | |
| # Hidden values — never exposed directly to the agent. | |
| true_budget: float # 0.0 → 1.0 | |
| close_threshold: float | |
| stall_probability: float | |
| # --------------------------------------------------------------------------- | |
| # LEVEL 1 — Easy | |
| # Budget known, decision maker present, close should succeed. | |
| # --------------------------------------------------------------------------- | |
| PROFILES_L1: List[ProspectProfile] = [ | |
| ProspectProfile("Meridian Retail", "medium", "retail", "high", ["manual inventory tracking", "slow reporting"], True, 0.80, 0.50, 0.0), | |
| ProspectProfile("Northline Foods", "small", "food distribution", "medium", ["supplier delays", "inventory mismatch"], True, 0.60, 0.50, 0.0), | |
| ProspectProfile("Crestline Auto", "medium", "automotive parts", "high", ["parts forecasting", "warehouse turnover"], True, 0.75, 0.50, 0.0), | |
| ProspectProfile("HarborGoods", "small", "consumer goods", "high", ["channel reporting", "stockout alerts"], True, 0.72, 0.50, 0.0), | |
| ProspectProfile("Ironclad Tools", "medium", "industrial supply", "high", ["catalog updates", "B2B quoting"], True, 0.78, 0.50, 0.0), | |
| ProspectProfile("Greenway Grocer", "medium", "grocery", "medium", ["expiration tracking", "cold-chain visibility"], True, 0.62, 0.50, 0.0), | |
| ProspectProfile("BlueRiver Pharma", "medium", "pharmacy retail", "high", ["compliance forms", "expiry alerts"], True, 0.70, 0.50, 0.0), | |
| ProspectProfile("Stride Apparel", "small", "apparel", "medium", ["sizing variants", "returns workflow"], True, 0.58, 0.50, 0.0), | |
| ProspectProfile("Summit Hardware", "medium", "hardware retail", "high", ["SKU bloat", "POS integration"], True, 0.74, 0.50, 0.0), | |
| ProspectProfile("Pinecrest Books", "small", "books", "medium", ["seasonal demand", "inventory shrinkage"], True, 0.55, 0.50, 0.0), | |
| ProspectProfile("Lakeside Resort", "medium", "hospitality", "high", ["guest preference data", "F&B inventory"], True, 0.68, 0.50, 0.0), | |
| ProspectProfile("Granite Coffee", "small", "F&B chain", "medium", ["multi-location SKU sync", "shrinkage"], True, 0.60, 0.50, 0.0), | |
| ProspectProfile("Horizon Outdoor", "medium", "sporting goods", "high", ["seasonal kitting", "regional demand"], True, 0.71, 0.50, 0.0), | |
| ProspectProfile("Cobalt Components","medium", "electronics dist.", "high", ["BOM management", "lead-time variance"], True, 0.77, 0.50, 0.0), | |
| ProspectProfile("Verdant Garden", "small", "garden centre", "medium", ["seasonal stock", "weather-driven demand"], True, 0.56, 0.50, 0.0), | |
| # ---- eval split (last 4) ----------------------------------------------- | |
| ProspectProfile("Falcon Sports", "medium", "sporting goods", "high", ["return rate spikes", "regional sizing"], True, 0.69, 0.50, 0.0), | |
| ProspectProfile("Maple & Co", "small", "specialty grocery", "medium", ["organic inventory", "seasonal sourcing"], True, 0.57, 0.50, 0.0), | |
| ProspectProfile("Skyline Pet", "medium", "pet supplies", "high", ["food expiration", "subscription kits"], True, 0.73, 0.50, 0.0), | |
| ProspectProfile("Helix Beauty", "small", "beauty retail", "medium", ["palette variants", "promo windows"], True, 0.61, 0.50, 0.0), | |
| ] | |
| # --------------------------------------------------------------------------- | |
| # LEVEL 2 — Medium | |
| # Budget hidden initially, one objection expected, demo required for close. | |
| # --------------------------------------------------------------------------- | |
| PROFILES_L2: List[ProspectProfile] = [ | |
| ProspectProfile("Apex Logistics", "enterprise", "logistics", "unknown", ["route optimization", "driver coordination", "fuel tracking"], True, 0.70, 0.50, 0.0), | |
| ProspectProfile("Vertex Supply", "medium", "manufacturing", "unknown", ["vendor visibility", "purchase delays"], True, 0.55, 0.50, 0.0), | |
| ProspectProfile("Polaris Freight", "enterprise", "freight", "unknown", ["dispatch SLA", "fleet maintenance"], True, 0.66, 0.50, 0.0), | |
| ProspectProfile("Cobra Builders", "medium", "construction", "unknown", ["project costing", "subcontractor coordination"], True, 0.60, 0.50, 0.0), | |
| ProspectProfile("Aegis Energy", "enterprise", "utilities", "unknown", ["asset uptime", "grid analytics"], True, 0.71, 0.50, 0.0), | |
| ProspectProfile("Crystal Foods", "medium", "food processing", "unknown", ["batch traceability", "regulatory reporting"], True, 0.58, 0.50, 0.0), | |
| ProspectProfile("Atlas Steel", "enterprise", "metals", "unknown", ["yield optimization", "downtime reduction"], True, 0.65, 0.50, 0.0), | |
| ProspectProfile("Quartz Mobility", "medium", "mobility tech", "unknown", ["fleet utilization", "telematics ingest"], True, 0.59, 0.50, 0.0), | |
| ProspectProfile("Beacon Insure", "enterprise", "insurance", "unknown", ["claims triage", "fraud signals"], True, 0.72, 0.50, 0.0), | |
| ProspectProfile("Tesseract Bio", "medium", "biotech", "unknown", ["lab inventory", "experiment tracking"], True, 0.62, 0.50, 0.0), | |
| ProspectProfile("Pivot Media", "enterprise", "media", "unknown", ["content rights", "campaign attribution"], True, 0.69, 0.50, 0.0), | |
| ProspectProfile("Solstice Travel", "medium", "travel", "unknown", ["booking variance", "supplier API churn"], True, 0.57, 0.50, 0.0), | |
| ProspectProfile("Anvil Robotics", "enterprise", "robotics", "unknown", ["fleet calibration", "OTA updates"], True, 0.74, 0.50, 0.0), | |
| ProspectProfile("Pacific Marine", "medium", "shipping", "unknown", ["port turnaround", "container visibility"], True, 0.61, 0.50, 0.0), | |
| ProspectProfile("Lumen Telecom", "enterprise", "telecom", "unknown", ["service incidents", "field tech routing"], True, 0.68, 0.50, 0.0), | |
| # ---- eval split -------------------------------------------------------- | |
| ProspectProfile("Onyx Logistics", "enterprise", "logistics", "unknown", ["last-mile delays", "warehouse handoffs"], True, 0.67, 0.50, 0.0), | |
| ProspectProfile("Sigma Industrial", "medium", "industrial", "unknown", ["MRO inventory", "supplier OTIF"], True, 0.56, 0.50, 0.0), | |
| ProspectProfile("Kepler Insurance", "enterprise", "insurance", "unknown", ["renewal forecasting", "policy ops"], True, 0.70, 0.50, 0.0), | |
| ProspectProfile("Mosaic Energy", "enterprise", "energy", "unknown", ["asset health", "predictive maintenance"], True, 0.66, 0.50, 0.0), | |
| ] | |
| # --------------------------------------------------------------------------- | |
| # LEVEL 3 — Hard | |
| # Budget hidden, two objections, possible stalling, decision maker may be absent. | |
| # --------------------------------------------------------------------------- | |
| PROFILES_L3: List[ProspectProfile] = [ | |
| ProspectProfile("Nova Financial", "enterprise", "finance", "unknown", ["compliance reporting", "audit trails", "data silos"], False, 0.60, 0.55, 0.30), | |
| ProspectProfile("Atlas Health", "enterprise", "healthcare", "unknown", ["patient workflow delays", "reporting compliance"], False, 0.65, 0.55, 0.25), | |
| ProspectProfile("Citadel Bank", "enterprise", "banking", "unknown", ["KYC automation", "fraud detection lag"], False, 0.62, 0.55, 0.30), | |
| ProspectProfile("Helios Hospitals", "enterprise", "healthcare", "unknown", ["EHR fragmentation", "billing reconciliation"], False, 0.58, 0.55, 0.30), | |
| ProspectProfile("Orion Asset Mgmt", "enterprise", "asset mgmt", "unknown", ["risk reporting", "ESG data ingestion"], False, 0.66, 0.55, 0.25), | |
| ProspectProfile("Sable Pharma", "enterprise", "pharma", "unknown", ["GxP traceability", "trial data integrity"], False, 0.61, 0.55, 0.30), | |
| ProspectProfile("Magellan Travel", "enterprise", "travel ops", "unknown", ["disruption response", "loyalty data"], False, 0.59, 0.55, 0.30), | |
| ProspectProfile("Crucible Defense", "enterprise", "defense", "unknown", ["clearance workflow", "supply chain audit"], False, 0.63, 0.55, 0.25), | |
| ProspectProfile("Seraphim Care", "enterprise", "elder care", "unknown", ["caregiver scheduling", "regulatory reporting"], False, 0.57, 0.55, 0.30), | |
| ProspectProfile("Polaris Reinsure", "enterprise", "reinsurance", "unknown", ["catastrophe modeling", "loss aggregation"], False, 0.64, 0.55, 0.30), | |
| ProspectProfile("Vanguard Edu", "enterprise", "education", "unknown", ["enrollment ops", "compliance audits"], False, 0.55, 0.55, 0.25), | |
| ProspectProfile("Aurora Telecom", "enterprise", "telecom", "unknown", ["spectrum analytics", "tower asset mgmt"], False, 0.60, 0.55, 0.30), | |
| ProspectProfile("Trident Marine", "enterprise", "marine", "unknown", ["fleet compliance", "fuel arbitrage"], False, 0.58, 0.55, 0.30), | |
| ProspectProfile("Granite Mining", "enterprise", "mining", "unknown", ["asset uptime", "ESG reporting"], False, 0.62, 0.55, 0.30), | |
| ProspectProfile("Echelon Health", "enterprise", "health-ins", "unknown", ["claims adjudication", "provider network"], False, 0.59, 0.55, 0.30), | |
| # ---- eval split -------------------------------------------------------- | |
| ProspectProfile("Castle Securities", "enterprise", "securities", "unknown", ["trade surveillance", "settlement breaks"], False, 0.61, 0.55, 0.30), | |
| ProspectProfile("Lighthouse Care", "enterprise", "elder care", "unknown", ["staffing variance", "incident reporting"], False, 0.56, 0.55, 0.25), | |
| ProspectProfile("Crown Reinsurance", "enterprise", "reinsurance", "unknown", ["catastrophe modeling", "treaty management"], False, 0.63, 0.55, 0.30), | |
| ProspectProfile("Apex Pharma", "enterprise", "pharma", "unknown", ["clinical-trial reporting", "supply chain audit"], False, 0.60, 0.55, 0.30), | |
| ] | |
| # --------------------------------------------------------------------------- | |
| # LEVEL 4 — Adversarial | |
| # Misleading "high" budget signal but actual budget < threshold, | |
| # OR decision maker absent. Correct action is DISQUALIFY. | |
| # --------------------------------------------------------------------------- | |
| PROFILES_L4: List[ProspectProfile] = [ | |
| ProspectProfile("Cipher Tech", "small", "technology", "high", ["security", "compliance"], False, 0.20, 0.50, 0.50), | |
| ProspectProfile("BluePeak Studio", "small", "creative agency", "high", ["project visibility", "client reporting"], False, 0.25, 0.50, 0.40), | |
| ProspectProfile("Nimbus Labs", "small", "research", "high", ["grant reporting", "experiment tracking"], False, 0.18, 0.50, 0.45), | |
| ProspectProfile("Halo Consulting", "small", "consulting", "high", ["billable utilization", "client deliverables"], False, 0.22, 0.50, 0.45), | |
| ProspectProfile("Spire Architects", "small", "architecture", "high", ["drawing revisions", "permit tracking"], False, 0.24, 0.50, 0.40), | |
| ProspectProfile("Quill Publishing", "small", "publishing", "high", ["royalty tracking", "rights management"], False, 0.17, 0.50, 0.50), | |
| ProspectProfile("Onyx Boutique", "small", "fashion boutique", "high", ["trend forecasting", "supplier mix"], False, 0.21, 0.50, 0.45), | |
| ProspectProfile("Topaz Cinema", "small", "indie film", "high", ["distribution rights", "festival logistics"], False, 0.19, 0.50, 0.50), | |
| ProspectProfile("Mariner Charter", "small", "yacht charter", "high", ["seasonal demand", "crew scheduling"], False, 0.23, 0.50, 0.45), | |
| ProspectProfile("Velvet Catering", "small", "catering", "high", ["event variance", "ingredient costing"], False, 0.16, 0.50, 0.50), | |
| ProspectProfile("Echo Photography", "small", "studio", "high", ["project pipelines", "asset licensing"], False, 0.20, 0.50, 0.45), | |
| ProspectProfile("Stellar Wellness", "small", "wellness", "high", ["membership churn", "class scheduling"], False, 0.22, 0.50, 0.45), | |
| ProspectProfile("Drift Digital", "small", "agency", "high", ["campaign attribution", "creative asset library"], False, 0.19, 0.50, 0.50), | |
| ProspectProfile("Ember Theater", "small", "performing arts", "high", ["production budgeting", "ticket allocation"], False, 0.18, 0.50, 0.45), | |
| ProspectProfile("Halcyon Crafts", "small", "artisan retail", "high", ["maker payouts", "fulfilment SLA"], False, 0.21, 0.50, 0.50), | |
| # ---- eval split -------------------------------------------------------- | |
| ProspectProfile("Onyx Tech", "small", "technology", "high", ["zero-trust rollout", "compliance"], False, 0.19, 0.50, 0.50), | |
| ProspectProfile("Haven Studio", "small", "creative agency", "high", ["client-asset versioning", "billing transparency"], False, 0.23, 0.50, 0.40), | |
| ProspectProfile("Beacon Indie", "small", "publishing", "high", ["distribution rights", "royalty splits"], False, 0.17, 0.50, 0.50), | |
| ProspectProfile("Kindled Catering", "small", "catering", "high", ["event variance", "menu engineering"], False, 0.22, 0.50, 0.45), | |
| ] | |
| # --------------------------------------------------------------------------- | |
| # Splits | |
| # --------------------------------------------------------------------------- | |
| # Last `_EVAL_SIZE` of each list is the held-out eval split. | |
| _EVAL_SIZE = 4 | |
| def _split(profiles: List[ProspectProfile]) -> tuple[list, list]: | |
| return profiles[:-_EVAL_SIZE], profiles[-_EVAL_SIZE:] | |
| _TRAIN_L1, _EVAL_L1 = _split(PROFILES_L1) | |
| _TRAIN_L2, _EVAL_L2 = _split(PROFILES_L2) | |
| _TRAIN_L3, _EVAL_L3 = _split(PROFILES_L3) | |
| _TRAIN_L4, _EVAL_L4 = _split(PROFILES_L4) | |
| TRAIN_PROFILES = {1: _TRAIN_L1, 2: _TRAIN_L2, 3: _TRAIN_L3, 4: _TRAIN_L4} | |
| EVAL_PROFILES = {1: _EVAL_L1, 2: _EVAL_L2, 3: _EVAL_L3, 4: _EVAL_L4} | |
| ALL_PROFILES = {1: PROFILES_L1, 2: PROFILES_L2, 3: PROFILES_L3, 4: PROFILES_L4} | |
| # --------------------------------------------------------------------------- | |
| # Public API | |
| # --------------------------------------------------------------------------- | |
| def sample_profile( | |
| difficulty: int, | |
| split: str = "train", | |
| rng: Optional[random.Random] = None, | |
| ) -> ProspectProfile: | |
| """ | |
| Sample one profile from the requested split. | |
| Parameters | |
| ---------- | |
| difficulty : int (1..4) | |
| split : "train" | "eval" | "all" | |
| rng : optional pre-seeded RNG for reproducibility | |
| """ | |
| if difficulty not in TRAIN_PROFILES: | |
| difficulty = 1 | |
| pool: List[ProspectProfile] | |
| if split == "eval": | |
| pool = EVAL_PROFILES[difficulty] | |
| elif split == "all": | |
| pool = ALL_PROFILES[difficulty] | |
| else: | |
| pool = TRAIN_PROFILES[difficulty] | |
| return (rng or random).choice(pool) | |
| def iter_train_profiles(difficulty: int) -> Iterator[ProspectProfile]: | |
| yield from TRAIN_PROFILES[difficulty] | |
| def iter_eval_profiles(difficulty: int) -> Iterator[ProspectProfile]: | |
| yield from EVAL_PROFILES[difficulty] | |