# retoor <retoor@molodetz.nl>
import json
import logging
import random
import re
import time
from typing import Any , Optional
import httpx
from devplacepy import stealth
from devplacepy . services . bot . config import (
GIST_LANGUAGES ,
GIST_MIN_LINES ,
PERSONA_GIST_FLAVOR ,
PERSONA_LANGUAGES ,
SEARCH_TERMS ,
TRIVIAL_GIST_TERMS ,
)
from devplacepy . services . bot . handles import MAX_HANDLE_LEN , sanitize_handle
HANDLE_CANDIDATE_TARGET = 8
logger = logging . getLogger ( __name__ )
class LLMClient :
def __init__ (
self ,
api_key : str ,
api_url : str ,
model : str ,
input_cost_per_1m : float ,
output_cost_per_1m : float ,
gist_min_lines : int = GIST_MIN_LINES ,
) :
if not api_key :
raise RuntimeError ( " LLM API key not set " )
self . api_key = api_key
self . api_url = api_url
self . model = model
self . input_cost_per_1m = input_cost_per_1m
self . output_cost_per_1m = output_cost_per_1m
self . gist_min_lines = max ( 1 , gist_min_lines )
self . total_cost = 0.0
self . total_calls = 0
self . total_in_tokens = 0
self . total_out_tokens = 0
def _raw_call ( self , system : str , prompt : str , temperature : float = 0.7 ) - > str :
for attempt in range ( 3 ) :
try :
payload = {
" model " : self . model ,
" messages " : [
{ " role " : " system " , " content " : system } ,
{ " role " : " user " , " content " : prompt } ,
] ,
" temperature " : temperature ,
}
logger . info (
" LLM >>> model= %s system= %s prompt= %s " ,
self . model ,
json . dumps ( system [ : 500 ] ) ,
json . dumps ( prompt [ : 500 ] ) ,
)
with stealth . stealth_sync_client ( timeout = 30 ) as client :
resp = client . post (
self . api_url ,
json = payload ,
headers = { " Authorization " : f " Bearer { self . api_key } " } ,
)
raw = resp . content
logger . info ( " LLM <<< %s " , raw [ : 2000 ] . decode ( errors = " replace " ) )
result = resp . json ( )
usage = result . get ( " usage " , { } )
in_tokens = usage . get ( " prompt_tokens " , 0 )
out_tokens = usage . get ( " completion_tokens " , 0 )
cost = ( in_tokens * self . input_cost_per_1m / 1_000_000 ) + (
out_tokens * self . output_cost_per_1m / 1_000_000
)
self . total_cost + = cost
self . total_calls + = 1
self . total_in_tokens + = in_tokens
self . total_out_tokens + = out_tokens
return result [ " choices " ] [ 0 ] [ " message " ] [ " content " ]
except (
httpx . HTTPError ,
json . JSONDecodeError ,
KeyError ,
) as e :
logger . warning ( " LLM call attempt %d /3 failed: %s " , attempt + 1 , e )
if attempt == 2 :
raise
time . sleep ( 2 * * attempt )
return " "
def _call ( self , system : str , prompt : str , temperature : float = 0.7 ) - > str :
return self . clean ( self . _raw_call ( system , prompt , temperature ) )
@staticmethod
def clean ( text : str , preserve_md : bool = False ) - > str :
if not preserve_md :
text = re . sub ( r " \ * \ *|__| \ *|_ " , " " , text )
text = text . replace ( " — " , " - " ) . replace ( " – " , " - " )
text = text . replace ( " ‘ " , " ' " ) . replace ( " ’ " , " ' " )
text = text . replace ( " “ " , ' " ' ) . replace ( " ” " , ' " ' )
text = re . sub ( r " \ s { 2,} " , " " , text )
return text . strip ( )
@staticmethod
def strip_md ( text : str ) - > str :
return LLMClient . clean ( text ) [ : 200 ]
@staticmethod
def strip_label ( text : str ) - > str :
labels = (
" post title " ,
" project name " ,
" snippet name " ,
" title " ,
" name " ,
" concept " ,
" snippet " ,
" headline " ,
" gist " ,
" issue " ,
)
result = ( text or " " ) . strip ( ) . strip ( ' " ' ) . strip ( " ' " ) . strip ( )
changed = True
while changed :
changed = False
lowered = result . lower ( )
for label in labels :
if lowered . startswith ( label + " : " ) :
result = result [ len ( label ) + 1 : ] . strip ( ) . strip ( ' " ' ) . strip ( " ' " )
changed = True
break
for sep in ( " concept: " , " description: " , " desc: " , " idea: " ) :
idx = result . lower ( ) . find ( sep )
if idx > 0 :
result = result [ : idx ] . strip ( )
return result . strip ( ) . strip ( ' " ' ) . strip ( " ' " ) . strip ( )
@staticmethod
def strip_code_fences ( text : str ) - > str :
text = text . strip ( )
if text . startswith ( " ``` " ) :
lines = text . split ( " \n " )
if lines and lines [ 0 ] . lstrip ( ) . startswith ( " ``` " ) :
lines = lines [ 1 : ]
if lines and lines [ - 1 ] . strip ( ) . startswith ( " ``` " ) :
lines = lines [ : - 1 ]
text = " \n " . join ( lines )
return text . strip ( )
def generate_post (
self ,
title : str ,
desc : str ,
persona : str = " " ,
category : str = " " ,
recent_titles : Optional [ list [ str ] ] = None ,
) - > str :
persona_extras = {
" enthusiastic_junior " : " Be excited. Use **bold** for emphasis. Short excited sentences. End with a question sometimes. " ,
" grumpy_senior " : " Be slightly cynical but helpful. Short blunt sentences. No fluff. Call out bad practices. " ,
" hobbyist_maker " : " Be casual and friendly. Mention side projects and tinkering. Use *italics* for tools/libraries. " ,
" academic_type " : " Be precise and structured. Use *italics* for terminology. Well thought out arguments. " ,
" storyteller " : " Use **bold** for key points. Write anecdotal, narrative style. Longer flowing sentences. " ,
" rebel " : " Be informal. Skip punctuation sometimes. Use slang. Type like you ' re in a hurry. " ,
" mentor " : " Be helpful and explanatory. Use **bold** for key takeaways. Include practical advice. " ,
" minimalist " : " One paragraph. Short blunt declarative sentences. No markdown. No fluff. " ,
}
category_extras = {
" devlog " : " Write it as a personal devlog entry - share your learning process and insights about this topic. " ,
" showcase " : " Write it as a showcase - express genuine excitement about what makes this impressive. " ,
" question " : " Write it as a discussion starter - ask thoughtful questions, invite others to share perspectives. " ,
" rant " : " Write it as an opinionated rant - strong viewpoint, passionate criticism, but keep it substantive. " ,
" fun " : " Write it lighthearted and playful, but stay tied to the actual tech topic. Humor about the technology itself, not off-topic jokes or lyrics. " ,
" random " : " Be natural and conversational - share your thoughts like any casual discussion. " ,
}
persona_extra = (
f " { persona_extras . get ( persona , ' Be casual. No markdown. ' ) } "
if persona
else " Be casual. No markdown. "
)
category_extra = f " { category_extras . get ( category , ' ' ) } " if category else " "
distinct_rule = " "
if recent_titles :
recent = " ; " . join ( t for t in recent_titles [ - 6 : ] if t )
if recent :
distinct_rule = (
f " You already posted about: { recent [ : 600 ] } . Take a completely "
" different angle from those and do not repeat their framing, "
" examples, or opinions. "
)
preserve = persona in (
" enthusiastic_junior " ,
" hobbyist_maker " ,
" academic_type " ,
" storyteller " ,
" mentor " ,
)
text = self . _call (
f " You are a dev writing a social media post reacting to tech news. Write 2-4 short paragraphs. "
f " { persona_extra } { category_extra } Do not summarize the article; assume the reader already saw it. "
f " Add your own value: a concrete opinion, an implication, a personal experience, or a pointed question. "
f " Reference a specific detail rather than restating the headline. No em dashes. Under 300 words. "
f " { distinct_rule } " ,
f " News: { title } \n \n { desc [ : 800 ] } " ,
)
return self . clean ( text , preserve_md = preserve )
def generate_post_title (
self , headline : str , persona : str = " " , category : str = " "
) - > str :
style = {
" enthusiastic_junior " : " Sound excited and curious. " ,
" grumpy_senior " : " Sound blunt and a little skeptical. " ,
" hobbyist_maker " : " Sound casual and hands-on. " ,
" academic_type " : " Sound precise and measured. " ,
" minimalist " : " Keep it plain and very short. " ,
" storyteller " : " Hint at a story or an angle. " ,
" rebel " : " Sound provocative or contrarian. " ,
" mentor " : " Sound thoughtful and constructive. " ,
} . get ( persona , " " )
title = self . strip_label (
self . clean (
self . _call (
" You are a developer writing the title of a community forum post reacting to tech news. "
" Write a natural, human title of 3 to 8 words in your own voice. "
" Do not copy or paraphrase the full headline and do not restate every detail. "
" No trailing punctuation unless it is a genuine question. No quotes. No label prefix. "
f " No em dashes. { style } " ,
f " Headline: { headline } \n Your post title: " ,
temperature = 0.8 ,
)
)
)
return title [ : 120 ]
def select_reaction ( self , content_snippet : str , persona : str = " " ) - > str :
from devplacepy . constants import REACTION_EMOJI
flavor = {
" enthusiastic_junior " : " You react readily and warmly. " ,
" grumpy_senior " : " You react rarely, only to genuinely notable content. " ,
" hobbyist_maker " : " You react to anything hands-on, clever, or fun. " ,
" academic_type " : " You react only to substantive, rigorous content. " ,
" minimalist " : " You react very sparingly. " ,
" storyteller " : " You react to anything with a human angle. " ,
" rebel " : " You react to bold or contrarian takes. " ,
" mentor " : " You react supportively to effort and learning. " ,
} . get ( persona , " " )
options = " " . join ( REACTION_EMOJI )
verdict = self . _call (
" You are a developer browsing a community feed. Decide whether a post deserves an "
" emoji reaction and which single emoji best fits its content and sentiment. "
f " { flavor } Reply with EXACTLY one of these emojis: { options } "
" or the word NONE if the content is mundane or would not move you to react. "
" Output only the emoji or NONE, nothing else. " ,
f " Post: \n { content_snippet [ : 1200 ] } " ,
temperature = 0.4 ,
)
text = verdict or " "
for emoji in REACTION_EMOJI :
if emoji in text or emoji . replace ( " \ufe0f " , " " ) in text :
return emoji
return " "
@staticmethod
def pick_comment_style ( ) - > str :
return random . choices (
[ " standard " , " oneliner " , " question " ] ,
weights = [ 55 , 23 , 22 ] ,
k = 1 ,
) [ 0 ]
@staticmethod
def is_short_comment_style ( style : str ) - > bool :
return style in ( " oneliner " , " question " )
def generate_comment (
self ,
post_snippet : str ,
persona : str = " " ,
mention_target : str = " " ,
parent_context : str = " " ,
style : str = " " ,
existing_comments : str = " " ,
) - > str :
extras = {
" enthusiastic_junior " : " Be excited. Use **bold** for agreement. Short replies. " ,
" grumpy_senior " : " Be blunt and short. No markdown. One sarcastic remark or actual advice. " ,
" rebel " : " Super casual. Skip caps sometimes. Short. " ,
" mentor " : " Be helpful. Use **bold** for key point. " ,
" storyteller " : " Share a quick related story. Use *italics* for emphasis. " ,
" minimalist " : " Shortest possible reply. One sentence max. " ,
}
extra = (
f " { extras . get ( persona , ' Be casual. No markdown. ' ) } "
if persona
else " Be casual. No markdown. "
)
preserve = persona in ( " enthusiastic_junior " , " mentor " , " storyteller " )
if style == " oneliner " :
length_rule = (
" Write ONE short casual line, under 12 words, like a quick reply "
" you would type without thinking too hard. Lowercase is fine, "
" contractions are fine, no markdown. "
)
preserve = False
elif style == " question " :
length_rule = (
" Write a SINGLE pointed question about a specific detail in the post. "
" One sentence. No preamble. "
)
else :
length_rule = f " Write 1-3 short sentences. { extra } "
mention_rule = " "
if mention_target :
mention_rule = (
f " Address @ { mention_target } naturally in the first sentence "
f " (weave the @ { mention_target } mention inline, do not append it at the end). "
)
ctx = " "
if parent_context :
ctx = f " \n \n Replying to this comment: \n { parent_context [ : 800 ] } "
others = " "
distinct_rule = " "
if existing_comments :
others = (
" \n \n Comments already posted by others on this thread: \n "
f " { existing_comments [ : 1600 ] } "
)
distinct_rule = (
" Other people already commented (listed below). Contribute a point "
" none of them made: a different angle on the topic, a caveat they "
" missed, or respectful disagreement with one of them by name. Do not "
" repeat any opinion, framing, example, or question already raised. "
)
system = (
f " You are a dev replying to a post. { length_rule } { mention_rule } "
" No em dashes. Reference a specific detail from the post. "
" Do not open with or rely on generic filler like ' great point ' , ' I agree ' , ' nice ' , "
" ' thanks for sharing ' , or ' interesting ' . Add something real: a concrete experience, "
" a caveat, a counterexample, respectful disagreement, or a pointed question. "
f " Never just paraphrase or agree blandly. { distinct_rule } "
)
reply = self . clean (
self . _call ( system , f " Post: \n { post_snippet [ : 1500 ] } { ctx } { others } " ) . strip ( ) ,
preserve_md = preserve ,
)
return reply [ : 2000 ]
@staticmethod
def _overlap_ratio ( text : str , context : str ) - > float :
def tokens ( s : str ) - > list [ str ] :
return [ w for w in re . findall ( r " [a-z0-9]+ " , s . lower ( ) ) if len ( w ) > 3 ]
candidate = tokens ( text )
source = set ( tokens ( context ) )
if not candidate or not source :
return 0.0
hits = sum ( 1 for w in candidate if w in source )
return hits / len ( candidate )
def quality_check (
self , kind : str , text : str , context : str = " " , style : str = " " , siblings : str = " "
) - > tuple [ bool , str ] :
from devplacepy . services . bot . config import (
MIN_COMMENT_LEN ,
MIN_SHORT_COMMENT_LEN ,
MIN_POST_LEN ,
RESTATEMENT_OVERLAP_THRESHOLD ,
SIBLING_OVERLAP_THRESHOLD ,
GENERIC_COMMENT_PHRASES ,
)
stripped = self . clean ( text or " " ) . strip ( )
if kind == " comment " :
min_len = (
MIN_SHORT_COMMENT_LEN
if self . is_short_comment_style ( style )
else MIN_COMMENT_LEN
)
else :
min_len = MIN_POST_LEN
if len ( stripped ) < min_len :
return False , f " too short ( { len ( stripped ) } < { min_len } ) "
lowered = stripped . lower ( )
if kind == " comment " :
for phrase in GENERIC_COMMENT_PHRASES :
if phrase in lowered :
return False , f " generic phrase ' { phrase } ' "
if (
context
and self . _overlap_ratio ( stripped , context ) > RESTATEMENT_OVERLAP_THRESHOLD
) :
return False , " restates the source "
if (
siblings
and self . _overlap_ratio ( stripped , siblings ) > SIBLING_OVERLAP_THRESHOLD
) :
return False , " echoes another comment "
verdict = self . _call (
" You are a strict content quality reviewer for a developer community. "
" Reject text that is generic, low-effort, pure filler, or merely summarizes its "
" source without adding an opinion, experience, or insight. "
" Reply with exactly PASS or ' FAIL: <short reason> ' . " ,
f " Type: { kind } \n Text: \n { stripped [ : 1200 ] } " ,
temperature = 0.0 ,
)
if verdict . strip ( ) . upper ( ) . startswith ( " PASS " ) :
return True , " ok "
return False , verdict . strip ( ) [ : 120 ] or " judge rejected "
@staticmethod
def _parse_json ( text : str ) - > dict :
text = LLMClient . strip_code_fences ( text or " " ) . strip ( )
start = text . find ( " { " )
end = text . rfind ( " } " )
if start > = 0 and end > start :
text = text [ start : end + 1 ]
parsed = json . loads ( text )
if not isinstance ( parsed , dict ) :
raise ValueError ( " expected a JSON object " )
return parsed
@staticmethod
def _clamp01 ( value : Any , default : float ) - > float :
try :
return max ( 0.0 , min ( 1.0 , float ( value ) ) )
except ( TypeError , ValueError ) :
return default
@staticmethod
def _as_int ( value : Any , default : int ) - > int :
try :
return int ( value )
except ( TypeError , ValueError ) :
return default
@staticmethod
def _as_terms ( value : Any ) - > list [ str ] :
if isinstance ( value , list ) :
return [ str ( item ) . strip ( ) for item in value if str ( item ) . strip ( ) ] [ : 8 ]
if isinstance ( value , str ) and value . strip ( ) :
return [ part . strip ( ) for part in value . split ( " , " ) if part . strip ( ) ] [ : 8 ]
return [ ]
def _normalize_identity ( self , data : dict , archetype : str ) - > dict :
interests = self . _as_terms ( data . get ( " interests " ) ) or list (
SEARCH_TERMS . get ( archetype , [ ] )
)
return {
" archetype " : archetype ,
" name " : str ( data . get ( " name " , " " ) ) . strip ( ) [ : 60 ] ,
" backstory " : str ( data . get ( " backstory " , " " ) ) . strip ( ) [ : 300 ] ,
" interests " : interests ,
" dislikes " : self . _as_terms ( data . get ( " dislikes " ) ) ,
" temperament " : str ( data . get ( " temperament " , " " ) ) . strip ( ) [ : 120 ] ,
" verbosity " : self . _clamp01 ( data . get ( " verbosity " ) , 0.5 ) ,
" contrarianness " : self . _clamp01 ( data . get ( " contrarianness " ) , 0.3 ) ,
" generosity " : self . _clamp01 ( data . get ( " generosity " ) , 0.5 ) ,
" curiosity " : self . _clamp01 ( data . get ( " curiosity " ) , 0.5 ) ,
" rhythm " : str ( data . get ( " rhythm " , " " ) ) . strip ( ) [ : 120 ] ,
}
def generate_identity ( self , archetype : str ) - > dict :
interests = " , " . join ( SEARCH_TERMS . get ( archetype , [ ] ) )
system = (
" You invent a unique, believable individual developer for a social coding "
" platform, seeded from a broad archetype but distinct from anyone else who "
" shares it. Return ONLY a JSON object, no prose and no markdown fences, with "
" these keys: name (a short handle-like display name), backstory (one concrete "
" sentence), interests (array of 4 to 6 short topics), dislikes (array of 2 to 4 "
" short topics), temperament (a few words), verbosity (number 0.0 to 1.0), "
" contrarianness (number 0.0 to 1.0), generosity (number 0.0 to 1.0), curiosity "
" (number 0.0 to 1.0), rhythm (a few words on when and how they show up). Make it "
" specific and memorable, never generic. No em dashes. "
)
prompt = (
f " Archetype: { archetype } \n "
f " Typical interests for this archetype: { interests } \n "
" Create the persona JSON: "
)
data = self . _parse_json ( self . _raw_call ( system , prompt , temperature = 0.9 ) )
return self . _normalize_identity ( data , archetype )
def generate_handle_candidates ( self , archetype : str ) - > list [ str ] :
interests = " , " . join ( SEARCH_TERMS . get ( archetype , [ ] ) )
system = (
" You invent online handles for a developer signing up to a programmer "
" community in the style of devRant or Hacker News. The handles read like a "
" real nerd picked them, never like a person ' s full name. Lean on programming "
" and hacker culture: tech nouns (null, kernel, segfault, daemon), occasional "
" leetspeak (c0d3r, h4x), an adjective plus noun, a creature, or a short word "
f " with a number. Lowercase mostly, { MAX_HANDLE_LEN } characters or fewer, only "
" letters, digits, underscores and hyphens, no spaces and no dots. Return ONLY "
f ' a JSON object {{ " handles " : [ " ... " , " ... " ] }} with { HANDLE_CANDIDATE_TARGET } '
" distinct handles, no prose, no markdown fences. No em dashes. "
)
prompt = (
f " Archetype: { archetype } \n "
f " Their interests: { interests } \n "
" Create the handles JSON: "
)
try :
data = self . _parse_json (
self . _raw_call ( system , prompt , temperature = 1.0 )
)
except ( ValueError , json . JSONDecodeError ) as exc :
logger . warning ( " Handle candidate generation failed: %s " , exc )
return [ ]
handles : list [ str ] = [ ]
for raw in data . get ( " handles " , [ ] ) :
handle = sanitize_handle ( raw )
if handle and handle . lower ( ) not in { h . lower ( ) for h in handles } :
handles . append ( handle )
return handles
@staticmethod
def _identity_card ( identity : dict ) - > str :
lines = [
f " name: { identity . get ( ' name ' , ' ' ) } " ,
f " archetype: { identity . get ( ' archetype ' , ' ' ) } " ,
f " backstory: { identity . get ( ' backstory ' , ' ' ) } " ,
f " interests: { ' , ' . join ( identity . get ( ' interests ' , [ ] ) ) } " ,
f " dislikes: { ' , ' . join ( identity . get ( ' dislikes ' , [ ] ) ) } " ,
f " temperament: { identity . get ( ' temperament ' , ' ' ) } " ,
f " verbosity: { identity . get ( ' verbosity ' , 0.5 ) } " ,
f " contrarianness: { identity . get ( ' contrarianness ' , 0.3 ) } " ,
f " generosity: { identity . get ( ' generosity ' , 0.5 ) } " ,
f " curiosity: { identity . get ( ' curiosity ' , 0.5 ) } " ,
f " rhythm: { identity . get ( ' rhythm ' , ' ' ) } " ,
]
return " \n " . join ( lines )
def _decision_system ( self , identity : dict ) - > str :
return (
" You are role-playing a single developer on a social coding platform. Stay in "
" character at all times. \n \n "
" IDENTITY \n "
f " { self . _identity_card ( identity ) } \n \n "
" HOW TO DECIDE \n "
" - Choose the actions that THIS person, with these interests and this "
" temperament, would take on the page described. Behaviour must follow the "
" identity, not chance. \n "
" - A generous person votes and reacts readily; a contrarian one comments to push "
" back; a terse, low-verbosity one acts rarely and briefly; a curious one explores "
" and navigates. Let the numbers and interests drive the plan. \n "
" - Only choose actions whose name appears in the MENU. Never invent an action or "
" a target. \n "
" - Order the plan the way this person would actually act, and include only what "
" they would genuinely do (an empty plan is fine if nothing here interests them). \n "
" - energy is how engaged this person is right now, 0.0 (barely present) to 1.0 "
" (highly active), following their rhythm. \n "
" - stop_after is roughly how many more actions this whole visit warrants before "
" they would naturally drift away. \n "
" - Output ONLY the JSON object below. No prose, no markdown fences. \n \n "
" OUTPUT SCHEMA \n "
' { " plan " :[ { " action " : " <menu action> " , " target " : " <id or empty> " , '
' " rationale " : " <short> " }], " energy " :<0.0-1.0>, " stop_after " :<integer>} '
)
@staticmethod
def _decision_prompt ( page_state : dict , menu : list [ dict ] , history : list [ str ] ) - > str :
menu_lines = " \n " . join ( f " - { item [ ' action ' ] } : { item [ ' desc ' ] } " for item in menu )
recent = " ; " . join ( history [ - 8 : ] ) if history else " nothing yet this visit "
unread = page_state . get ( " unread_notifications " , 0 )
unread_line = (
f " \n UNREAD NOTIFICATIONS: { unread } (someone may have mentioned or replied to you) "
if unread
else " "
)
return (
f " PAGE: { page_state . get ( ' page ' , ' unknown ' ) } \n "
f " VISIBLE: { page_state . get ( ' visible ' , ' ' ) } { unread_line } \n "
f " MENU: \n { menu_lines } \n "
f " RECENT (this visit): { recent } "
)
@staticmethod
def _filter_plan ( plan : Any , allowed : set ) - > list [ dict ] :
if not isinstance ( plan , list ) :
return [ ]
result = [ ]
for entry in plan :
if not isinstance ( entry , dict ) :
continue
action = str ( entry . get ( " action " , " " ) ) . strip ( )
if action not in allowed :
continue
result . append (
{
" action " : action ,
" target " : str ( entry . get ( " target " , " " ) ) . strip ( ) [ : 120 ] ,
" rationale " : str ( entry . get ( " rationale " , " " ) ) . strip ( ) [ : 200 ] ,
}
)
return result [ : 12 ]
def decide (
self ,
identity : dict ,
page_state : dict ,
menu : list [ dict ] ,
history : list [ str ] ,
temperature : float = 0.4 ,
) - > dict :
allowed = { item [ " action " ] for item in menu }
system = self . _decision_system ( identity )
base = self . _decision_prompt ( page_state , menu , history )
result = { " plan " : [ ] , " energy " : 0.5 , " stop_after " : 0 }
for attempt in range ( 2 ) :
prompt = base
if attempt :
prompt + = " \n \n Return ONLY valid JSON matching the schema. No prose. "
try :
data = self . _parse_json ( self . _raw_call ( system , prompt , temperature ) )
except ( ValueError , KeyError , json . JSONDecodeError ) :
continue
result = {
" plan " : self . _filter_plan ( data . get ( " plan " ) , allowed ) ,
" energy " : self . _clamp01 ( data . get ( " energy " ) , 0.5 ) ,
" stop_after " : self . _as_int ( data . get ( " stop_after " ) , 0 ) ,
}
if result [ " plan " ] :
break
return result
def generate_issue ( self , topic : str ) - > tuple [ str , str ] :
text = self . _call (
" Write an issue report. One line title. Then 2-3 sentences describing what happened and what should have happened. Like a real dev reporting an issue. No em dashes. " ,
f " Issue: { topic } " ,
)
lines = text . strip ( ) . split ( " \n " )
title = lines [ 0 ] . strip ( ) . lstrip ( " # " ) . strip ( ) [ : 120 ] or f " Issue report: { topic } "
desc = " " . join (
line . lstrip ( " -* " ) . strip ( ) for line in lines [ 1 : ] if line . strip ( )
)
return title , desc [ : 2000 ] or text [ : 500 ]
def generate_bio ( self ) - > str :
return self . _call (
" Write a short bio for a developer profile. 1-2 sentences. What they work on, what they like. Sound human. No em dashes. " ,
" Bio: " ,
)
def generate_profile_fields ( self , handle : str ) - > tuple [ str , str , str ] :
location = self . clean (
self . _call (
" Name one plausible city and country for a developer. Reply with ONLY ' City, Country ' . No extra words. " ,
" Location: " ,
temperature = 0.9 ,
)
) [ : 80 ]
slug = re . sub ( r " [^a-z0-9_-] " , " " , handle . lower ( ) ) or " dev "
git_link = f " https://github.com/ { slug } "
website = f " https:// { slug } .dev "
return location , git_link , website
def generate_dm ( self , persona : str = " " , context : str = " " ) - > str :
extra = {
" enthusiastic_junior " : " Be friendly and excited. " ,
" grumpy_senior " : " Be blunt but not rude. " ,
" rebel " : " Be super casual. " ,
" mentor " : " Be warm and encouraging. " ,
" storyteller " : " Open with a small hook. " ,
" minimalist " : " One short sentence. " ,
} . get ( persona , " Be casual and friendly. " )
ctx = f " \n \n Earlier message: \n { context [ : 400 ] } " if context else " "
return self . clean (
self . _call (
f " Write one short, friendly direct message to another developer. 1-2 sentences. { extra } No em dashes. " ,
f " Write a DM to start or continue a chat. { ctx } " ,
)
) [ : 500 ]
def generate_project_title ( self , persona : str = " " ) - > str :
return self . strip_label (
self . clean (
self . _call (
" Invent a short, catchy project name. 2 to 4 words. A tool, game, or app. "
" Output only the name. No label, no colon, no description, no quotes. No em dashes. " ,
" Project name: " ,
temperature = 0.9 ,
)
)
) [ : 80 ]
def generate_project_desc ( self , title : str , persona : str = " " ) - > str :
flavor = {
" grumpy_senior " : " Keep it dry and matter of fact. " ,
" academic_type " : " Be precise about the approach and trade-offs. " ,
" minimalist " : " Two short sentences, no filler. " ,
" rebel " : " Be bold about why the usual approach is wrong. " ,
" storyteller " : " Open with the motivation behind it. " ,
} . get ( persona , " " )
shape = random . choice (
[
" Write one terse sentence. Just what it is. No tech stack. " ,
" Write two sentences: what it does and the main tech behind it. " ,
" Write 2 to 3 sentences including the tech stack and a trade-off you made. " ,
" Write a short blurb, under 25 words, plain and understated. " ,
]
)
return self . clean (
self . _call (
f " You are a developer describing your own project. { shape } { flavor } No em dashes. " ,
f " Project: { title } " ,
)
) [ : 5000 ]
def generate_gist ( self , persona : str = " " ) - > tuple [ str , str , str , str ] :
languages = PERSONA_LANGUAGES . get ( persona ) or GIST_LANGUAGES
language = random . choice ( languages )
flavor = PERSONA_GIST_FLAVOR . get ( persona , " a genuinely useful utility " )
code = self . strip_code_fences (
self . _call (
f " Write a short, correct, self-contained { language } snippet of 8 to 20 lines. "
f " It should be { flavor } . Make it non-trivial and genuinely useful: no hello world, "
" no bare language-feature demo, no textbook 101 example, no trivial one-liner, "
" no basic getter or setter. Output ONLY raw code. No markdown fences. No commentary. " ,
f " Language: { language } . Write the snippet: " ,
temperature = 0.7 ,
)
) [ : 4000 ]
title = self . strip_label (
self . clean (
self . _call (
" Name this code snippet in 2 to 5 words, like a developer titling a gist. "
" No quotes. No markdown. No label prefix. No em dashes. " ,
f " Language: { language } \n Code: \n { code [ : 1200 ] } \n Title: " ,
temperature = 0.7 ,
)
)
) [ : 120 ]
description = self . clean (
self . _call (
" Write a one-sentence description of what this snippet does and when it is handy. No em dashes. " ,
f " Title: { title } \n Language: { language } \n Code: \n { code [ : 1200 ] } " ,
)
) [ : 400 ]
return title , description , language , code
def gist_quality_check (
self , title : str , code : str , language : str
) - > tuple [ bool , str ] :
lowered = ( title or " " ) . lower ( )
for term in TRIVIAL_GIST_TERMS :
if term in lowered :
return False , f " trivial topic ' { term } ' "
lines = [ ln for ln in ( code or " " ) . splitlines ( ) if ln . strip ( ) ]
if len ( lines ) < self . gist_min_lines :
return False , f " too few lines ( { len ( lines ) } < { self . gist_min_lines } ) "
verdict = self . _call (
" You are a strict reviewer for a developer community ' s shared code snippets. "
" Reject snippets that are textbook 101 material, trivial one-liners, hello world, "
" a bare language-feature demo, or something every developer already knows by heart. "
" Accept only snippets an experienced developer would find non-obvious or worth bookmarking. "
" Reply with exactly PASS or ' FAIL: <short reason> ' . " ,
f " Language: { language } \n Title: { title } \n Code: \n { code [ : 1500 ] } " ,
temperature = 0.0 ,
)
if verdict . strip ( ) . upper ( ) . startswith ( " PASS " ) :
return True , " ok "
return False , verdict . strip ( ) [ : 120 ] or " judge rejected "