mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-21 12:12:22 +02:00
76 lines
3.5 KiB
Python
76 lines
3.5 KiB
Python
"""Turn the local scan + app picks into a personalized greeting and starters.
|
|
|
|
One cheap aux call on whatever lane the user just connected; every failure path
|
|
returns the static fallback so the reveal can never be an error card.
|
|
"""
|
|
|
|
import json
|
|
import re
|
|
from typing import List, Optional
|
|
|
|
from typeguard import typechecked
|
|
|
|
from backend.apps.agents.core.aux_llm import aux_max_tokens_for, safe_resp_text
|
|
from backend.apps.onboarding.models import PrepRequest, PrepResponse
|
|
from backend.apps.settings.models import AppSettings, PersonalizedStarter
|
|
|
|
FALLBACK_STARTERS: List[PersonalizedStarter] = [
|
|
PersonalizedStarter(title="Clean up Downloads", prompt="Sort my Downloads folder into tidy subfolders. Show me the plan before moving anything."),
|
|
PersonalizedStarter(title="Research something", prompt="Research the best noise-cancelling headphones under $300 and give me a comparison table."),
|
|
PersonalizedStarter(title="Build a tiny app", prompt="Build me a simple habit tracker app I can use right now."),
|
|
PersonalizedStarter(title="Plan a trip", prompt="Plan a 3-day weekend trip itinerary and turn it into a printable page."),
|
|
]
|
|
|
|
P_SYSTEM = (
|
|
"You write first-run starter tasks for OpenSwarm, a desktop AI agent platform that can "
|
|
"organize local files, browse the web in a real browser, build small apps, and run agents in parallel. "
|
|
"Given facts about the user's machine and the apps they picked, respond with STRICT JSON only: "
|
|
'{"greeting": string, "starters": [{"title": string, "prompt": string}]}. '
|
|
"Exactly 4 starters. Each title is 2-5 words. Each prompt is a concrete, safe, immediately runnable task "
|
|
"referencing the user's real folders, file counts, or picked apps when possible; never invent facts, never "
|
|
"propose deleting anything without review. The greeting is one warm sentence that names 2-3 specific things "
|
|
"found on the machine. No markdown, no commentary, JSON only."
|
|
)
|
|
|
|
|
|
@typechecked
|
|
def parse_prep(text: str) -> Optional[PrepResponse]:
|
|
match = re.search(r"\{.*\}", text, re.DOTALL)
|
|
if not match:
|
|
return None
|
|
try:
|
|
data = json.loads(match.group(0))
|
|
starters = [
|
|
PersonalizedStarter(title=str(s.get("title", "")).strip(), prompt=str(s.get("prompt", "")).strip())
|
|
for s in data.get("starters", [])
|
|
if isinstance(s, dict) and str(s.get("title", "")).strip() and str(s.get("prompt", "")).strip()
|
|
]
|
|
if not starters:
|
|
return None
|
|
return PrepResponse(greeting=str(data.get("greeting", "")).strip(), starters=starters[:4])
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
@typechecked
|
|
async def build_prep(settings: AppSettings, request: PrepRequest) -> PrepResponse:
|
|
facts = request.model_dump()
|
|
try:
|
|
from backend.apps.agents.providers.registry import resolve_aux_model
|
|
from backend.apps.settings.credentials import get_anthropic_client_for_model
|
|
|
|
aux_model, _ = await resolve_aux_model(settings, preferred_tier="haiku")
|
|
client = get_anthropic_client_for_model(settings, aux_model)
|
|
resp = await client.messages.create(
|
|
model=aux_model,
|
|
max_tokens=aux_max_tokens_for(aux_model, base=700),
|
|
system=P_SYSTEM,
|
|
messages=[{"role": "user", "content": json.dumps(facts)}],
|
|
)
|
|
parsed = parse_prep(safe_resp_text(resp))
|
|
if parsed is not None:
|
|
return parsed
|
|
except Exception:
|
|
pass
|
|
return PrepResponse(greeting="", starters=list(FALLBACK_STARTERS))
|