Redesign Advisor context around feedback history

Advisor context is now minimal and feedback-first:
- User feedback (current run, placed first when present)
- Current prompt
- User intent
- Previous encoded prompt (anchor for feedback — so 'he held her head'
  has a referent)
- Suggestions from memory (repair candidates, max 5)
- Past feedback history (last 10 entries, most recent first)

Removed from context: rating label, axis codes, plain-English axis
translation, encoded-vs-original prompt duplication, advisor-poisoning
note, previous advisor diagnostic, perfect example, V2 recommendations,
source image text note (image is fed directly to vision-capable models
via the existing tokenizer image= path)

New persistent store: global_state["advisor_feedback_history"] — up to
10 entries, each {feedback, rating, iteration}. Only populated when
feedback_prompt is non-empty. Updated at the end of each run so the
current run's feedback is available for future runs, not the current.

History format: "Rating: user's exact feedback text" e.g.
"1. Missing details: I asked for smoke but it didn't appear."
"2. Wrong action: he was supposed to hold her hand, not her head."

Removed dead helpers: _v2_find_perfect_example_for_intent,
_v2_build_v2_recommendations, _v2_axes_to_plain_english,
_AXIS_DESCRIPTIONS — none used by advisor context any more.

Cleaned up _v2_prompt_advisor and _v2_negative_prompt_advisor
signatures: removed rating_label, phrases, perfect_example,
v2_recommendations, has_image params; added feedback_history.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
digital-garbage
2026-05-15 19:08:00 +03:00
co-authored by Claude Sonnet 4.6
parent 8df4a5dad0
commit 462beda1a1
2 changed files with 62 additions and 137 deletions
+61 -132
View File
@@ -5828,6 +5828,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
"intent_preference_phrases": {},
"conditioning_deltas": {},
"active_repair_axes": [],
"advisor_feedback_history": [],
"vision_memory": {},
"loss_history": [],
},
@@ -5871,6 +5872,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
data["global"].setdefault("intent_preference_phrases", {})
data["global"].setdefault("conditioning_deltas", {})
data["global"].setdefault("active_repair_axes", [])
data["global"].setdefault("advisor_feedback_history", [])
data["global"].setdefault("vision_memory", {})
data["global"].setdefault("loss_history", [])
return data, "loaded"
@@ -8795,83 +8797,46 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
})
return serializable
def _v2_find_perfect_example_for_intent(self, global_state, intent_family_slot):
if not isinstance(intent_family_slot, dict):
def _v2_update_advisor_feedback_history(self, global_state, feedback_prompt, rating_label, iter_num, limit=10):
feedback = str(feedback_prompt or "").strip()
if not feedback:
return
history = list(global_state.setdefault("advisor_feedback_history", []))
history.append({
"feedback": feedback,
"rating": str(rating_label or "").strip(),
"iteration": int(iter_num),
})
global_state["advisor_feedback_history"] = history[-limit:]
def _v2_format_advisor_feedback_history(self, global_state, limit=10):
history = list(global_state.get("advisor_feedback_history", []))
if not history:
return ""
base = intent_family_slot.get("perfect_anchors", {}).get("base", {})
if isinstance(base, dict):
prompt = self._v2_prompt_key(base.get("positive_prompt", "") or base.get("encoded_prompt", ""))
if prompt:
return prompt
loved = intent_family_slot.get("loved_variants", {})
if isinstance(loved, dict) and loved:
best = max(
(e for e in loved.values() if isinstance(e, dict)),
key=lambda e: int(e.get("last_seen_iter", 0)),
default=None,
)
if best:
prompt = self._v2_prompt_key(best.get("positive_prompt", "") or best.get("encoded_prompt", ""))
if prompt:
return prompt
return ""
def _v2_build_v2_recommendations(self, axis_feedback, phrases, repair_candidates, global_state):
parts = []
missing = list(axis_feedback.get("missing_axes", [])) if isinstance(axis_feedback, dict) else []
wrong = list(axis_feedback.get("wrong_axes", [])) if isinstance(axis_feedback, dict) else []
if missing:
parts.append(f"Missing axes needing improvement: {', '.join(missing)}.")
if wrong:
parts.append(f"Wrong axes to avoid repeating: {', '.join(wrong)}.")
if repair_candidates:
texts = [str(c.get("text", "")) for c in repair_candidates[:6] if isinstance(c, dict) and c.get("text")]
if texts:
parts.append(f"Repair suggestions from memory: {', '.join(texts)}.")
return " ".join(parts) if parts else ""
_AXIS_DESCRIPTIONS = {
"details": "fine detail, textures, small motion, secondary elements",
"action": "main action, movement, motion direction",
"quality": "visual clarity, sharpness, image quality",
}
def _v2_axes_to_plain_english(self, missing_axes, wrong_axes):
missing = [self._AXIS_DESCRIPTIONS.get(a, a) for a in (missing_axes or [])]
wrong = [self._AXIS_DESCRIPTIONS.get(a, a) for a in (wrong_axes or [])]
parts = []
if missing:
parts.append(f"The previous output was missing: {'; '.join(missing)}.")
if wrong:
parts.append(f"The previous output had wrong: {'; '.join(wrong)}.")
return " ".join(parts)
recent = history[-limit:][::-1]
lines = []
for i, entry in enumerate(recent, 1):
feedback = str(entry.get("feedback", "")).strip()
if not feedback:
continue
rating = str(entry.get("rating", "")).strip()
entry_text = f"{rating}: {feedback}" if rating else feedback
lines.append(f"{i}. {entry_text}")
return "\n".join(lines)
def _v2_advisor_prompt(
self,
prompt,
intent_prompt,
rating_label,
axis_feedback,
phrases,
repair_candidates,
previous_run=None,
has_image=False,
mode="Full",
feedback_prompt="",
perfect_example="",
v2_recommendations="",
feedback_history="",
):
missing_axes = list(axis_feedback.get("missing_axes", [])) if isinstance(axis_feedback, dict) else []
wrong_axes = list(axis_feedback.get("wrong_axes", [])) if isinstance(axis_feedback, dict) else []
previous_run = previous_run if isinstance(previous_run, dict) else {}
previous_prompt = self._v2_prompt_key(previous_run.get("prompt", ""))
previous_encoded = self._v2_prompt_key(previous_run.get("encoded_prompt", ""))
# Only show encoded prompt when it actually differs from the prompt.
show_encoded = previous_encoded and previous_encoded != previous_prompt
prev_advisor = previous_run.get("advisor", {}) if isinstance(previous_run.get("advisor"), dict) else {}
advisor_poisoned = bool(prev_advisor.get("applied", False))
prev_advisor_diagnostic = self._v2_prompt_key(prev_advisor.get("diagnostic", ""))
has_feedback = bool(str(feedback_prompt or "").strip())
previous_run = previous_run if isinstance(previous_run, dict) else {}
previous_prompt = self._v2_prompt_key(previous_run.get("encoded_prompt", "") or previous_run.get("prompt", ""))
if mode == "Only prompt":
output_instructions = (
@@ -8892,41 +8857,24 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
user_lines = []
# Feedback is placed first so the model reads it before any other context.
if has_feedback:
user_lines.append(f"User feedback: {str(feedback_prompt).strip()}")
user_lines += [
f"Current prompt: {self._v2_prompt_key(prompt)}",
f"User intent: {self._v2_prompt_key(intent_prompt) or 'same as current prompt'}",
]
user_lines.append(f"Current prompt: {self._v2_prompt_key(prompt)}")
user_lines.append(f"User intent: {self._v2_prompt_key(intent_prompt) or 'same as current prompt'}")
if previous_prompt:
user_lines.append(f"Previous prompt (caused the rating): {previous_prompt}")
if show_encoded:
user_lines.append(f"Previous encoded prompt (after repair): {previous_encoded}")
user_lines.append(f"Previous prompt (what caused the feedback): {previous_prompt}")
user_lines.append(f"Rating: {rating_label}")
candidates = [
str(c.get("text", "")) for c in (repair_candidates or [])[:5]
if isinstance(c, dict) and str(c.get("text", "")).strip()
]
if candidates:
user_lines.append(f"Suggestions: {', '.join(candidates)}.")
if not has_feedback:
what_went_wrong = self._v2_axes_to_plain_english(missing_axes, wrong_axes)
if what_went_wrong:
user_lines.append(f"What went wrong: {what_went_wrong}")
candidates = [
str(c.get("text", "")) for c in (repair_candidates or [])[:5]
if isinstance(c, dict) and str(c.get("text", "")).strip()
]
if candidates:
user_lines.append(f"Consider adding: {', '.join(candidates)}.")
if perfect_example:
user_lines.append(f"A previously perfect prompt for this intent: {perfect_example}")
if has_image:
user_lines.append("Source image is available.")
if advisor_poisoned:
user_lines.append("Note: the previous prompt was advisor-generated — the rating above is for that output.")
if prev_advisor_diagnostic:
user_lines.append(f"Previous advisor note: {prev_advisor_diagnostic}")
if feedback_history:
user_lines.append(f"Past feedback (most recent first):\n{feedback_history}")
if has_feedback:
user_lines.append(
@@ -9027,9 +8975,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
mode,
current_prompt,
intent_prompt,
rating_label,
axis_feedback,
phrases,
repair_candidates,
previous_run=None,
intent_phrases=None,
@@ -9039,8 +8985,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
thinking=True,
encode_cache=None,
feedback_prompt="",
perfect_example="",
v2_recommendations="",
feedback_history="",
max_length=800,
rating_profile=None,
):
@@ -9051,7 +8996,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
return current_prompt, "Advisor: skipped; prompt empty.", "", False
rating_profile = rating_profile if isinstance(rating_profile, dict) else {}
is_perfect = rating_profile.get("key") == "like" or str(rating_label or "").lower() == "perfect"
is_perfect = rating_profile.get("key") == "like"
repair_signal = bool(axis_feedback.get("missing_axes") or axis_feedback.get("wrong_axes"))
has_feedback = bool(str(feedback_prompt or "").strip())
@@ -9066,16 +9011,11 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
advisor_prompt_text = self._v2_advisor_prompt(
current_prompt,
intent_prompt,
rating_label if not intent_changed else f"{rating_label} (note: intent changed from previous run)",
axis_feedback,
phrases,
repair_candidates,
previous_run=previous_run,
has_image=image is not None,
mode=mode,
feedback_prompt=feedback_prompt,
perfect_example=perfect_example,
v2_recommendations=v2_recommendations,
feedback_history=feedback_history,
)
raw, gen_status = self._v2_generate_advisor_text(
clip, advisor_prompt_text, seed=seed, image=image, thinking=thinking, max_length=max_length
@@ -9116,17 +9056,13 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
positive_prompt,
negative_prompt,
intent_prompt,
rating_label,
axis_feedback,
previous_run=None,
has_image=False,
feedback_prompt="",
feedback_history="",
):
missing_axes = list(axis_feedback.get("missing_axes", [])) if isinstance(axis_feedback, dict) else []
wrong_axes = list(axis_feedback.get("wrong_axes", [])) if isinstance(axis_feedback, dict) else []
previous_run = previous_run if isinstance(previous_run, dict) else {}
previous_prompt = self._v2_prompt_key(previous_run.get("prompt", ""))
has_feedback = bool(str(feedback_prompt or "").strip())
previous_run = previous_run if isinstance(previous_run, dict) else {}
previous_prompt = self._v2_prompt_key(previous_run.get("encoded_prompt", "") or previous_run.get("prompt", ""))
neg_rules = (
"Additional rules for negative prompt repair:\n"
"- Add only concise suppression tags for things that were wrong or harmful.\n"
@@ -9141,24 +9077,20 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
user_lines.append(f"User feedback: {str(feedback_prompt).strip()}")
user_lines += [
f"Current prompt: {self._v2_prompt_key(positive_prompt)}",
f"Current negative prompt: {self._v2_prompt_key(negative_prompt) or 'empty'}",
f"Current negative: {self._v2_prompt_key(negative_prompt) or 'empty'}",
f"User intent: {self._v2_prompt_key(intent_prompt) or 'same as current prompt'}",
f"Rating: {rating_label}",
]
if previous_prompt:
user_lines.append(f"Previous prompt (caused the rating): {previous_prompt}")
if not has_feedback:
what_went_wrong = self._v2_axes_to_plain_english(missing_axes, wrong_axes)
if what_went_wrong:
user_lines.append(f"What went wrong: {what_went_wrong}")
if has_image:
user_lines.append("Source image is available.")
user_lines.append(f"Previous prompt (what caused the feedback): {previous_prompt}")
if feedback_history:
user_lines.append(f"Past feedback (most recent first):\n{feedback_history}")
if has_feedback:
user_lines.append("Task: apply the user feedback to repair the negative prompt.")
user_lines.append("Task: apply the user feedback to the negative prompt.")
else:
user_lines.append("Task: repair the negative prompt to suppress what went wrong.")
return (
V2_PROMPT_ADVISOR_SYSTEM_PROMPT.strip() + "\n" + neg_rules
+ ("\n" + V2_PROMPT_ADVISOR_FEEDBACK_OVERRIDE.strip() if has_feedback else "")
+ "\n\n" + "\n".join(user_lines)
)
@@ -9198,7 +9130,6 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
positive_prompt,
negative_prompt,
intent_prompt,
rating_label,
rating_profile,
axis_feedback,
previous_run=None,
@@ -9209,6 +9140,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
image=None,
thinking=True,
feedback_prompt="",
feedback_history="",
max_length=800,
):
mode = self._v2_advisor_mode(mode)
@@ -9224,11 +9156,9 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
positive_prompt,
negative_prompt,
intent_prompt,
rating_label,
axis_feedback,
previous_run=previous_run,
has_image=image is not None,
feedback_prompt=feedback_prompt,
feedback_history=feedback_history,
)
raw, gen_status = self._v2_generate_advisor_text(
clip, advisor_prompt_text, seed=seed, image=image, thinking=thinking, max_length=max_length
@@ -10031,6 +9961,8 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
negative_advisor_status = "Negative advisor: off."
negative_advisor_diagnostic = ""
negative_advisor_applied = False
feedback_history = ""
advisor_rating_label = rating_label
if current_prompt_refusal:
prompt_to_encode = analysis_prompt
lucky_status = "Prompt refusal filter: enhancer refusal detected; current prompt will not be stored or learned."
@@ -10107,8 +10039,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
encoded_role = "current prompt"
if not current_prompt_refusal:
v2_recommendations = self._v2_build_v2_recommendations(repair_feedback, phrases, repair_candidates, global_state)
perfect_example = self._v2_find_perfect_example_for_intent(global_state, current_family_slot)
feedback_history = self._v2_format_advisor_feedback_history(global_state)
pre_advisor_prompt = prompt_to_encode
advisor_rating_label = rating_label if has_previous_run else "No previous output (first run or session reset)"
prompt_to_encode, advisor_status, advisor_diagnostic, advisor_applied = self._v2_prompt_advisor(
@@ -10116,9 +10047,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
advisor_mode,
prompt_to_encode,
intent_source_prompt,
advisor_rating_label,
repair_feedback,
phrases,
repair_candidates,
previous_run=previous_run,
intent_phrases=intent_phrases,
@@ -10128,8 +10057,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
thinking=advisor_thinking,
encode_cache=encode_cache,
feedback_prompt=feedback_prompt,
perfect_example=perfect_example,
v2_recommendations=v2_recommendations,
feedback_history=feedback_history,
max_length=self._V2_ADVISOR_MAX_TOKENS,
rating_profile=learning_profile,
)
@@ -10202,7 +10130,6 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
prompt_to_encode,
repaired_negative_prompt,
intent_source_prompt,
advisor_rating_label,
learning_profile,
repair_feedback,
previous_run=previous_run,
@@ -10213,6 +10140,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
image=source_image,
thinking=advisor_thinking,
feedback_prompt=feedback_prompt,
feedback_history=feedback_history,
max_length=self._V2_ADVISOR_MAX_TOKENS,
)
negative_conditioning = []
@@ -10359,6 +10287,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
"rating_label": "Unrated",
"iteration": int(global_state["total_iterations"]),
}
self._v2_update_advisor_feedback_history(global_state, feedback_prompt, advisor_rating_label, int(global_state.get("total_iterations", 0)))
state["global"] = global_state
self._v2_save_state(state, refinement_key)
+1 -5
View File
@@ -1476,9 +1476,7 @@ def test_refiner_v2_advisor_uses_explicit_system_prompt_previous_prompt_thinking
"Diagnostics",
"person smoking",
"person smoking",
"Missing details",
{"missing_axes": ["details"], "wrong_axes": []},
prompt_phrases(refiner, "person smoking"),
[],
previous_run={"prompt": "old prompt", "encoded_prompt": "old encoded prompt"},
image=image,
@@ -1492,9 +1490,7 @@ def test_refiner_v2_advisor_uses_explicit_system_prompt_previous_prompt_thinking
assert "diagnostics only" in status
assert diagnostic == "add clearer smoke motion."
assert "FunPack Refiner V2 Prompt Advisor" in advisor_prompt
assert "Previous prompt (caused the rating): old prompt" in advisor_prompt
assert "Previous encoded prompt (after repair): old encoded prompt" in advisor_prompt
assert "Source image is available" in advisor_prompt
assert "Previous prompt (what caused the feedback): old encoded prompt" in advisor_prompt
assert kwargs["image"] is image
assert kwargs["thinking"] is True
assert clip.generate_kwargs["seed"] == 123