Fix avatar misgendering, returning caller overflow, false callbacks
- Avatar prefetch checks gender marker, re-fetches on mismatch - Returning callers need 2+ actual calls before re-eligible (was 1) - Promotion rate lowered 10% → 5% to prevent pool flooding - Callback injection skipped for returning callers (already have context) - Show history clarifies "you are NOT that caller" to prevent identity confusion Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+9
-6
@@ -6361,7 +6361,7 @@ class Session:
|
|||||||
if random.random() < reaction_chance and best_target:
|
if random.random() < reaction_chance and best_target:
|
||||||
reaction = self._build_specific_reaction(current_bg, best_target)
|
reaction = self._build_specific_reaction(current_bg, best_target)
|
||||||
if random.random() < 0.30:
|
if random.random() < 0.30:
|
||||||
lines.append(f"\nYOU HEARD {best_target.caller_name.upper()} EARLIER and you {reaction}. This is partly why you called — bring it up early and tie it into your story.")
|
lines.append(f"\nYOU HEARD {best_target.caller_name.upper()} EARLIER ON THE SHOW TONIGHT and you {reaction}. It reminded you of your own situation — bring it up early and tie it into your story. NOTE: You are NOT {best_target.caller_name} — you are a different caller who was listening.")
|
||||||
else:
|
else:
|
||||||
lines.append(f"\nYOU HEARD {best_target.caller_name.upper()} EARLIER and you {reaction}. Mention it if it comes up naturally, but your call is about YOUR thing.")
|
lines.append(f"\nYOU HEARD {best_target.caller_name.upper()} EARLIER and you {reaction}. Mention it if it comes up naturally, but your call is about YOUR thing.")
|
||||||
else:
|
else:
|
||||||
@@ -7928,16 +7928,19 @@ async def start_call(caller_key: str):
|
|||||||
audio_service.stop_caller_audio()
|
audio_service.stop_caller_audio()
|
||||||
session.start_call(caller_key)
|
session.start_call(caller_key)
|
||||||
|
|
||||||
# Check for callback opportunity — inject callback context into background
|
# Check for callback opportunity — only for non-returning callers
|
||||||
|
# Returning callers already have their own PREVIOUS CALLS context
|
||||||
|
base = CALLER_BASES[caller_key]
|
||||||
|
if not base.get("returning"):
|
||||||
callback = _maybe_generate_callback()
|
callback = _maybe_generate_callback()
|
||||||
if callback:
|
if callback:
|
||||||
existing_bg = session.caller_backgrounds.get(caller_key, "")
|
existing_bg = session.caller_backgrounds.get(caller_key, "")
|
||||||
callback_ctx = f"\n\nCALLBACK: You already called earlier tonight. {callback['callback_reason']}. Reference your earlier call naturally — you're a returning caller with an update."
|
callback_ctx = f"\n\nPREVIOUS CALLS:\n- (earlier tonight) {callback['original_summary']}\nYou're calling back with an update — {callback['callback_reason']}. Reference your earlier call naturally."
|
||||||
if isinstance(existing_bg, CallerBackground):
|
if isinstance(existing_bg, CallerBackground):
|
||||||
existing_bg.natural_description += callback_ctx
|
existing_bg.natural_description += callback_ctx
|
||||||
else:
|
else:
|
||||||
session.caller_backgrounds[caller_key] = existing_bg + callback_ctx
|
session.caller_backgrounds[caller_key] = existing_bg + callback_ctx
|
||||||
print(f"[Callback] Injected callback context for {CALLER_BASES[caller_key].get('name', caller_key)}")
|
print(f"[Callback] Injected callback context for {base.get('name', caller_key)}")
|
||||||
|
|
||||||
caller = session.caller # This generates the background if needed
|
caller = session.caller # This generates the background if needed
|
||||||
|
|
||||||
@@ -8115,8 +8118,8 @@ async def _summarize_ai_call(caller_key: str, caller_name: str, conversation: li
|
|||||||
if base.get("returning") and base.get("regular_id"):
|
if base.get("returning") and base.get("regular_id"):
|
||||||
# Update existing regular's call history
|
# Update existing regular's call history
|
||||||
regular_caller_service.update_after_call(base["regular_id"], summary)
|
regular_caller_service.update_after_call(base["regular_id"], summary)
|
||||||
elif len(conversation) >= 8 and random.random() < 0.10:
|
elif len(conversation) >= 8 and random.random() < 0.05:
|
||||||
# 10% chance to promote first-timer with 8+ messages
|
# 5% chance to promote first-timer with 8+ messages
|
||||||
bg = session.caller_backgrounds.get(caller_key, "")
|
bg = session.caller_backgrounds.get(caller_key, "")
|
||||||
caller_style = session.caller_styles.get(caller_key, "")
|
caller_style = session.caller_styles.get(caller_key, "")
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,15 @@ class AvatarService:
|
|||||||
for caller in callers:
|
for caller in callers:
|
||||||
name = caller.get("name", "")
|
name = caller.get("name", "")
|
||||||
gender = caller.get("gender", "male")
|
gender = caller.get("gender", "male")
|
||||||
if name and not (AVATAR_DIR / f"{name}.jpg").exists():
|
if not name:
|
||||||
|
continue
|
||||||
|
g = "female" if gender.lower().startswith("f") else "male"
|
||||||
|
path = AVATAR_DIR / f"{name}.jpg"
|
||||||
|
marker = AVATAR_DIR / f"{name}.gender"
|
||||||
|
# Always call get_or_fetch if: no file, no gender marker, or gender mismatch
|
||||||
|
if not path.exists() or not marker.exists() or marker.read_text().strip() != g:
|
||||||
|
if path.exists():
|
||||||
|
print(f"[Avatar] Gender mismatch for {name}: cached={marker.read_text().strip() if marker.exists() else '?'}, want={g} — re-fetching")
|
||||||
tasks.append(self.get_or_fetch(name, gender))
|
tasks.append(self.get_or_fetch(name, gender))
|
||||||
|
|
||||||
if not tasks:
|
if not tasks:
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class RegularCallerService:
|
|||||||
import random
|
import random
|
||||||
if not self._regulars:
|
if not self._regulars:
|
||||||
return []
|
return []
|
||||||
available = [r for r in self._regulars if len(r.get("call_history", [])) > 0]
|
available = [r for r in self._regulars if len(r.get("call_history", [])) > 1]
|
||||||
if not available:
|
if not available:
|
||||||
return []
|
return []
|
||||||
return random.sample(available, min(count, len(available)))
|
return random.sample(available, min(count, len(available)))
|
||||||
|
|||||||
Reference in New Issue
Block a user