Spaces:
Sleeping
Sleeping
File size: 12,823 Bytes
b484b4d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | """
Launch Desk β Function Tools
=============================
Four @function_tool decorated tools for the Launch Planner agent.
Each does simple but realistic logic without external API calls.
"""
from __future__ import annotations
import re
from agents import function_tool
# ---------------------------------------------------------------------------
# 1. extract_tasks
# ---------------------------------------------------------------------------
@function_tool
def extract_tasks(brief: str) -> list[dict]:
"""Parse a product brief and extract a list of launch tasks.
Each task includes a name, priority (high/medium/low), owner role,
and a relative deadline expressed as days before launch.
Args:
brief: Free-form product brief text.
Returns:
A list of task dicts: {task, priority, owner, deadline}
"""
if not brief or not brief.strip():
return [
{"task": "Define launch goals and metrics", "priority": "high",
"owner": "Product", "deadline": "T-30 days"},
]
text = brief.lower()
# Heuristic keyword β task mapping. We scan the brief for domain keywords
# and build a prioritised task list from whatever matches.
task_templates: list[dict] = [
{"keywords": ["api", "backend", "server", "database", "infra"],
"task": "Freeze code and tag release candidate",
"priority": "high", "owner": "Engineering", "deadline": "T-14 days"},
{"keywords": ["qa", "test", "bug", "regression", "testing"],
"task": "Complete QA regression and smoke testing",
"priority": "high", "owner": "QA", "deadline": "T-7 days"},
{"keywords": ["doc", "documentation", "guide", "readme", "manual"],
"task": "Write user-facing documentation and API guides",
"priority": "medium", "owner": "Technical Writing", "deadline": "T-10 days"},
{"keywords": ["market", "marketing", "campaign", "ad", "social", "blog", "press"],
"task": "Prepare marketing campaign assets and schedule posts",
"priority": "high", "owner": "Marketing", "deadline": "T-5 days"},
{"keywords": ["support", "customer", "help", "ticket", "oncall"],
"task": "Staff support team and prepare runbooks",
"priority": "medium", "owner": "Customer Success", "deadline": "T-3 days"},
{"keywords": ["security", "compliance", "audit", "gdpr", "soc"],
"task": "Complete security review and compliance sign-off",
"priority": "high", "owner": "Security", "deadline": "T-21 days"},
{"keywords": ["pricing", "billing", "plan", "tier", "subscription"],
"task": "Finalise pricing tiers and billing configuration",
"priority": "medium", "owner": "Finance", "deadline": "T-12 days"},
{"keywords": ["analytics", "tracking", "metric", "dashboard", "kpi"],
"task": "Set up analytics dashboards and success metrics",
"priority": "low", "owner": "Data", "deadline": "T-8 days"},
{"keywords": ["design", "ui", "ux", "figma", "mockup", "brand"],
"task": "Finalise UI polish and brand assets",
"priority": "medium", "owner": "Design", "deadline": "T-10 days"},
{"keywords": ["legal", "contract", "terms", "privacy", "policy"],
"task": "Review legal terms and privacy policy updates",
"priority": "medium", "owner": "Legal", "deadline": "T-15 days"},
]
tasks: list[dict] = []
for tmpl in task_templates:
if any(kw in text for kw in tmpl["keywords"]):
tasks.append({
"task": tmpl["task"],
"priority": tmpl["priority"],
"owner": tmpl["owner"],
"deadline": tmpl["deadline"],
})
# Always include goal definition as the first task
always = {
"task": "Define launch goals and success metrics",
"priority": "high",
"owner": "Product",
"deadline": "T-30 days",
}
if not any(t["task"] == always["task"] for t in tasks):
tasks.insert(0, always)
# Always include a launch-day verification task
launch_day = {
"task": "Launch-day verification and monitoring",
"priority": "high",
"owner": "Engineering",
"deadline": "Launch day (T-0)",
}
if not any(t["task"] == launch_day["task"] for t in tasks):
tasks.append(launch_day)
return tasks
# ---------------------------------------------------------------------------
# 2. check_readiness
# ---------------------------------------------------------------------------
@function_tool
def check_readiness(tasks: str, launch_date: str) -> dict:
"""Check launch readiness against a five-point rubric.
The rubric covers: code frozen, docs written, QA passed, marketing
ready, and support staffed. We look for evidence of each in the
provided task list text.
Args:
tasks: The extracted task list (as a string or JSON).
launch_date: Target launch date in YYYY-MM-DD format.
Returns:
{ready: bool, score: int (0-100), gaps: list[str]}
"""
text = (tasks or "").lower()
rubric = [
("code frozen", ["code", "freeze", "tag", "release candidate", "engineering"]),
("docs written", ["doc", "documentation", "guide", "readme", "writing"]),
("QA passed", ["qa", "test", "regression", "smoke", "bug"]),
("marketing ready", ["market", "campaign", "social", "ad", "press", "blog"]),
("support staffed", ["support", "customer", "runbook", "oncall", "help"]),
]
covered: list[str] = []
gaps: list[str] = []
for label, keywords in rubric:
if any(kw in text for kw in keywords):
covered.append(label)
else:
gaps.append(label)
score = int((len(covered) / len(rubric)) * 100)
ready = len(gaps) == 0 and score >= 100
# If launch date is missing we flag it as a gap too
if not launch_date or not launch_date.strip():
gaps.append("launch date not set")
score = max(0, score - 10)
return {
"ready": ready,
"score": score,
"gaps": gaps,
"covered": covered,
}
# ---------------------------------------------------------------------------
# 3. generate_checklist
# ---------------------------------------------------------------------------
@function_tool
def generate_checklist(tasks: str) -> list[dict]:
"""Generate per-owner checklists from a task list.
Parses the tasks string and groups items by owner, producing a
checklist for each owner with concrete action items.
Args:
tasks: The extracted task list (string or JSON).
Returns:
A list of {owner, items: [str]} dicts.
"""
# Try to parse as JSON list of dicts; fall back to line parsing
import json
task_items: list[dict] = []
stripped = (tasks or "").strip()
if stripped:
try:
parsed = json.loads(stripped)
if isinstance(parsed, list):
task_items = parsed
except (json.JSONDecodeError, TypeError):
# Fall back: split by newline, treat each line as a task
for line in stripped.splitlines():
line = line.strip().strip("-").strip()
if line:
task_items.append({"task": line, "owner": "General"})
# If nothing parsed, provide a default checklist
if not task_items:
task_items = [
{"task": "Define launch goals and metrics", "owner": "Product"},
{"task": "Freeze code and tag release candidate", "owner": "Engineering"},
{"task": "Complete QA regression testing", "owner": "QA"},
{"task": "Write documentation", "owner": "Technical Writing"},
{"task": "Prepare marketing campaign", "owner": "Marketing"},
{"task": "Staff support team", "owner": "Customer Success"},
]
# Group tasks by owner
by_owner: dict[str, list[str]] = {}
for t in task_items:
owner = t.get("owner", "General")
task_name = t.get("task", str(t))
by_owner.setdefault(owner, []).append(task_name)
# Build owner checklists with concrete action items
checklists: list[dict] = []
for owner, task_names in by_owner.items():
items: list[str] = []
for tn in task_names:
items.append(f"Confirm: {tn}")
items.append(f"Sign off: {tn}")
# Add a shared pre-launch check for every owner
items.append("Review final launch checklist with launch lead")
checklists.append({"owner": owner, "items": items})
# Ensure there is always a Launch Lead checklist
if not any(c["owner"] == "Launch Lead" for c in checklists):
checklists.append({
"owner": "Launch Lead",
"items": [
"Confirm all owners have signed off",
"Verify go/no-go criteria are met",
"Schedule launch-day standup",
"Monitor dashboards during launch window",
],
})
return checklists
# ---------------------------------------------------------------------------
# 4. draft_copy
# ---------------------------------------------------------------------------
@function_tool
def draft_copy(channel: str, product: str, audience: str) -> dict:
"""Draft marketing copy for a specific channel.
Generates a headline, body, and call-to-action tailored to the
channel, product, and audience.
Args:
channel: Marketing channel (e.g. "email", "twitter", "blog",
"linkedin", "landing_page").
product: Product name or short description.
audience: Target audience description.
Returns:
{headline: str, body: str, cta: str}
"""
ch = (channel or "").lower().strip()
prod = (product or "").strip() or "our new product"
aud = (audience or "").strip() or "your team"
# Channel-specific copy templates
if ch in ("twitter", "x", "tweet"):
headline = f"π {prod} is live β built for {aud}."
body = (
f"We just shipped {prod}, designed from the ground up for {aud}. "
"Faster, simpler, and ready for production today. "
"Check it out π"
)
cta = "Try it now β"
elif ch in ("email", "newsletter", "drip"):
headline = f"Introducing {prod} β now available for {aud}"
body = (
f"Hi there,\n\n"
f"We're excited to announce {prod}, purpose-built for {aud}. "
"This release brings a refined experience, improved performance, "
"and the features you've been asking for.\n\n"
"Here's what's new:\n"
" β’ Streamlined workflow that saves you time\n"
" β’ Built-in reliability for production use\n"
" β’ Thoughtful design choices throughout\n\n"
"We'd love your feedback as you try it out."
)
cta = "Get started today"
elif ch in ("blog", "blog post", "announcement"):
headline = f"{prod}: A new standard for {aud}"
body = (
f"Today we're launching {prod}, our most refined release yet. "
f"Built specifically for {aud}, it combines the features you need "
"with the reliability you expect.\n\n"
"In this post we'll walk through what's new, why we built it, "
"and how to get started in under five minutes."
)
cta = "Read the full announcement"
elif ch in ("linkedin", "li"):
headline = f"We just launched {prod} β here's why it matters for {aud}"
body = (
f"After months of iteration, {prod} is now generally available. "
f"We built it for {aud} who need a solution that's both powerful "
"and dependable. Here's what went into it and what it means for you."
)
cta = "Learn more"
elif ch in ("landing", "landing page", "landing_page", "homepage"):
headline = f"{prod} β purpose-built for {aud}"
body = (
f"{prod} gives {aud} the tools they need to move faster, "
"with the reliability required for real production workloads. "
"No noise, no bloat β just what matters."
)
cta = "Start building for free"
else:
# Generic fallback for unknown channels
headline = f"Introducing {prod}"
body = (
f"{prod} is now available. Designed for {aud}, it delivers "
"the features and reliability you need to succeed."
)
cta = "Learn more"
return {
"headline": headline,
"body": body,
"cta": cta,
"channel": ch or "general",
}
|