fix: plan compact persiste et recharge a l'identique (stabilite entre sessions)
This commit is contained in:
+85
-21
@@ -228,6 +228,9 @@ class Project:
|
|||||||
"nom": self.name,
|
"nom": self.name,
|
||||||
"cree_le": datetime.now().isoformat(timespec="seconds"),
|
"cree_le": datetime.now().isoformat(timespec="seconds"),
|
||||||
"dernier_markdown": "",
|
"dernier_markdown": "",
|
||||||
|
"dernier_plan_compact": "",
|
||||||
|
"plan_modifie_le": "", # horodatage dernière modif du plan
|
||||||
|
"formalise_le": "", # horodatage dernière formalisation
|
||||||
"dernier_yaml": "",
|
"dernier_yaml": "",
|
||||||
"dernier_pptx": "",
|
"dernier_pptx": "",
|
||||||
"nb_sessions": 0,
|
"nb_sessions": 0,
|
||||||
@@ -239,10 +242,34 @@ class Project:
|
|||||||
self.state_file.write_text(
|
self.state_file.write_text(
|
||||||
json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8")
|
json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||||
|
|
||||||
def has_state(self) -> bool:
|
def save_plan_compact(self, plan: str):
|
||||||
"""Vrai si le projet a déjà produit au moins un narratif formalisé."""
|
"""Sauvegarde continue du plan compact (source de vérité de la structure)."""
|
||||||
|
state = self.load_state()
|
||||||
|
state["dernier_plan_compact"] = plan
|
||||||
|
state["plan_modifie_le"] = datetime.now().isoformat(timespec="seconds")
|
||||||
|
self.save_state(state)
|
||||||
|
|
||||||
|
def mark_formalised(self, markdown: str):
|
||||||
|
"""Enregistre le Markdown formalisé + l'horodatage de formalisation."""
|
||||||
|
state = self.load_state()
|
||||||
|
state["dernier_markdown"] = markdown
|
||||||
|
state["formalise_le"] = datetime.now().isoformat(timespec="seconds")
|
||||||
|
self.save_state(state)
|
||||||
|
|
||||||
|
def plan_diverge(self) -> bool:
|
||||||
|
"""Vrai si le plan compact a été modifié APRÈS la dernière formalisation."""
|
||||||
st = self.load_state()
|
st = self.load_state()
|
||||||
return bool(st.get("dernier_markdown"))
|
pm, fm = st.get("plan_modifie_le", ""), st.get("formalise_le", "")
|
||||||
|
if not pm:
|
||||||
|
return False
|
||||||
|
if not fm:
|
||||||
|
return bool(st.get("dernier_plan_compact"))
|
||||||
|
return pm > fm
|
||||||
|
|
||||||
|
def has_state(self) -> bool:
|
||||||
|
"""Vrai si le projet a déjà un plan compact OU un narratif formalisé."""
|
||||||
|
st = self.load_state()
|
||||||
|
return bool(st.get("dernier_plan_compact") or st.get("dernier_markdown"))
|
||||||
|
|
||||||
# ── Journal de décisions (Solution D) ───────────────────────────────────
|
# ── Journal de décisions (Solution D) ───────────────────────────────────
|
||||||
def log(self, entry: str):
|
def log(self, entry: str):
|
||||||
@@ -531,34 +558,60 @@ class AgentSession:
|
|||||||
|
|
||||||
def reprime_narrator(session: AgentSession, proj: Project) -> None:
|
def reprime_narrator(session: AgentSession, proj: Project) -> None:
|
||||||
"""
|
"""
|
||||||
Réamorce une session Narrator neuve avec le contexte d'un projet
|
Réamorce une session Narrator avec le contexte d'un projet déjà travaillé.
|
||||||
déjà travaillé : dernier Markdown formalisé + journal des décisions.
|
|
||||||
(Solution C — on ne restaure pas la conversation exacte, on réinforme.)
|
Priorité au PLAN COMPACT persisté (source de vérité) : on le RECHARGE
|
||||||
|
à l'identique et on le réinjecte comme état de départ — l'agent ne
|
||||||
|
réinvente rien. Repli sur la reconstruction depuis le Markdown
|
||||||
|
uniquement si aucun plan compact n'a été sauvegardé (projets antérieurs
|
||||||
|
à la persistance du plan).
|
||||||
"""
|
"""
|
||||||
state = proj.load_state()
|
state = proj.load_state()
|
||||||
|
plan = state.get("dernier_plan_compact", "")
|
||||||
last_md = state.get("dernier_markdown", "")
|
last_md = state.get("dernier_markdown", "")
|
||||||
|
summary = proj.journal_summary()
|
||||||
|
|
||||||
|
if plan:
|
||||||
|
# RECHARGEMENT EXACT — pas de régénération
|
||||||
|
reprime = (
|
||||||
|
"Nous reprenons un projet de présentation déjà travaillé. "
|
||||||
|
"Voici le PLAN COMPACT EXACT sur lequel nous nous étions arrêtés. "
|
||||||
|
"C'est l'état de référence : tu le conserves tel quel et tu "
|
||||||
|
"travailles dessus. Ne le reformule pas, ne le réinvente pas, "
|
||||||
|
"ne renumérotes que si je te demande une modification de flux.\n\n"
|
||||||
|
"=== PLAN COMPACT ACTUEL ===\n\n"
|
||||||
|
f"{plan}\n\n"
|
||||||
|
)
|
||||||
|
if summary:
|
||||||
|
reprime += f"=== JOURNAL DES DÉCISIONS ===\n\n{summary}\n\n"
|
||||||
|
reprime += (
|
||||||
|
"Confirme en réaffichant ce plan compact À L'IDENTIQUE, puis "
|
||||||
|
"attends mes instructions (modes f: flux / d: deep dive). "
|
||||||
|
"N'ajoute aucun commentaire."
|
||||||
|
)
|
||||||
|
info("Réamorçage — plan compact rechargé à l'identique.")
|
||||||
|
out = session.start(reprime)
|
||||||
|
display_narrator(out)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Repli : pas de plan compact persisté → reconstruction depuis le Markdown
|
||||||
if not last_md:
|
if not last_md:
|
||||||
return
|
return
|
||||||
summary = proj.journal_summary()
|
|
||||||
reprime = (
|
reprime = (
|
||||||
"Nous reprenons un projet de présentation déjà travaillé. "
|
"Nous reprenons un projet déjà travaillé, mais seul le narratif "
|
||||||
"Voici l'état actuel pour te remettre en contexte.\n\n"
|
"formalisé est disponible (pas de plan compact sauvegardé).\n\n"
|
||||||
"=== DERNIER NARRATIF FORMALISÉ (état actuel du deck) ===\n\n"
|
"=== DERNIER NARRATIF FORMALISÉ ===\n\n"
|
||||||
f"{last_md}\n\n"
|
f"{last_md}\n\n"
|
||||||
)
|
)
|
||||||
if summary:
|
if summary:
|
||||||
reprime += (
|
reprime += f"=== JOURNAL DES DÉCISIONS ===\n\n{summary}\n\n"
|
||||||
"=== JOURNAL DES DÉCISIONS (historique du projet) ===\n\n"
|
|
||||||
f"{summary}\n\n"
|
|
||||||
)
|
|
||||||
reprime += (
|
reprime += (
|
||||||
"Reconstruis à partir de ce narratif le PLAN COMPACT de la présentation "
|
"Reconstruis le PLAN COMPACT à partir de ce narratif (chapitres, "
|
||||||
"(format hiérarchique : chapitres, slides numérotées en continu, tags "
|
"slides numérotées en continu, tags core/OPT-XXX et audience). "
|
||||||
"core/OPT-XXX et audience). Affiche uniquement ce plan compact, sans "
|
"Affiche uniquement ce plan compact. On repartira de lui (modes f:/d:)."
|
||||||
"autre commentaire. On repartira de ce plan pour la révision, avec les "
|
|
||||||
"mêmes modes f: (flux) et d: (deep dive)."
|
|
||||||
)
|
)
|
||||||
info("Réamorçage du Narrator — reconstruction du plan compact...")
|
warn("Aucun plan compact sauvegardé — reconstruction depuis le narratif "
|
||||||
|
"(peut différer légèrement).")
|
||||||
out = session.start(reprime)
|
out = session.start(reprime)
|
||||||
display_narrator(out)
|
display_narrator(out)
|
||||||
|
|
||||||
@@ -585,12 +638,20 @@ def run_narrator(session: AgentSession, proj: Project) -> Optional[str]:
|
|||||||
print("\n Documents présents dans inputs/ — /lire pour les injecter.")
|
print("\n Documents présents dans inputs/ — /lire pour les injecter.")
|
||||||
|
|
||||||
loaded_docs: set = set()
|
loaded_docs: set = set()
|
||||||
last_plan: str = "" # dernier plan compact (mode flux)
|
# Précharge le plan compact persisté (reprise) — source de vérité exacte
|
||||||
|
last_plan: str = proj.load_state().get("dernier_plan_compact", "")
|
||||||
last_response: str = "" # dernière réponse quelconque
|
last_response: str = "" # dernière réponse quelconque
|
||||||
formalized_md: Optional[str] = None
|
formalized_md: Optional[str] = None
|
||||||
pending_context: str = ""
|
pending_context: str = ""
|
||||||
mode: Optional[str] = None # MODE_FLUX / MODE_DEEP / None
|
mode: Optional[str] = None # MODE_FLUX / MODE_DEEP / None
|
||||||
|
|
||||||
|
if last_plan and not session.started:
|
||||||
|
info("Plan compact rechargé depuis la session précédente :")
|
||||||
|
print("\n" + textwrap.indent(last_plan, " "))
|
||||||
|
if proj.plan_diverge():
|
||||||
|
warn("Le plan a été modifié après la dernière formalisation — "
|
||||||
|
"pense à /formalise avant de générer.")
|
||||||
|
|
||||||
def send_with_mode(msg: str, current_mode: Optional[str]) -> str:
|
def send_with_mode(msg: str, current_mode: Optional[str]) -> str:
|
||||||
"""Préfixe le message d'une consigne de mode pour l'agent."""
|
"""Préfixe le message d'une consigne de mode pour l'agent."""
|
||||||
if current_mode == MODE_FLUX:
|
if current_mode == MODE_FLUX:
|
||||||
@@ -646,6 +707,7 @@ def run_narrator(session: AgentSession, proj: Project) -> Optional[str]:
|
|||||||
last_response = session.send(send_with_mode(pasted, mode))
|
last_response = session.send(send_with_mode(pasted, mode))
|
||||||
if mode == MODE_FLUX or mode is None:
|
if mode == MODE_FLUX or mode is None:
|
||||||
last_plan = last_response
|
last_plan = last_response
|
||||||
|
proj.save_plan_compact(last_plan)
|
||||||
display_narrator(last_response)
|
display_narrator(last_response)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -666,6 +728,7 @@ def run_narrator(session: AgentSession, proj: Project) -> Optional[str]:
|
|||||||
"en développant le contenu de chaque slide. Inclus les "
|
"en développant le contenu de chaque slide. Inclus les "
|
||||||
"slides tiroir en les marquant [OPT-XXX].")
|
"slides tiroir en les marquant [OPT-XXX].")
|
||||||
formalized_md = last_response
|
formalized_md = last_response
|
||||||
|
proj.mark_formalised(formalized_md)
|
||||||
display_narrator(last_response)
|
display_narrator(last_response)
|
||||||
ok("Formalisé. /valider pour passer au Designer, ou continue à ajuster.")
|
ok("Formalisé. /valider pour passer au Designer, ou continue à ajuster.")
|
||||||
continue
|
continue
|
||||||
@@ -716,6 +779,7 @@ def run_narrator(session: AgentSession, proj: Project) -> Optional[str]:
|
|||||||
# Mémoriser le plan si on est en flux (ou tout premier plan)
|
# Mémoriser le plan si on est en flux (ou tout premier plan)
|
||||||
if mode == MODE_FLUX or (mode is None and not last_plan):
|
if mode == MODE_FLUX or (mode is None and not last_plan):
|
||||||
last_plan = last_response
|
last_plan = last_response
|
||||||
|
proj.save_plan_compact(last_plan)
|
||||||
|
|
||||||
display_narrator(last_response)
|
display_narrator(last_response)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user