🐛 Ne plus compter l'attente qui précède un message d'une autre session
Une entrée user arrivée après la fin d'un tour de l'agent (dernière réponse du fil principal avec stop_reason autre que tool_use) ouvre une nouvelle plage, même écrite par Claude Code (isMeta) : message ou avis d'une autre session, commande slash, renommage. Une entrée isMeta écrite pendant un tour, ou après la fin d'un tour de sous-agent, ne coupe rien. Ajoute le fichier VERSION (1.0.1), vérifié égal à la constante de l'outil. Refs #2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KT2yBsd7nPivLnrEtcvuhX
This commit is contained in:
@@ -31,9 +31,22 @@ def humain(t, texte):
|
||||
return {"type": "user", "timestamp": t, "message": {"role": "user", "content": texte}}
|
||||
|
||||
|
||||
def agent(t):
|
||||
def agent(t, fin=None):
|
||||
"""Réponse de l'agent ; fin = son stop_reason (end_turn : il rend la main)."""
|
||||
return {"type": "assistant", "timestamp": t, "message": {"role": "assistant",
|
||||
"content": [{"type": "text", "text": "…"}]}}
|
||||
"content": [{"type": "text", "text": "…"}], "stop_reason": fin}}
|
||||
|
||||
|
||||
def meta(t, texte):
|
||||
"""Entrée user écrite par Claude Code, pas par l'humain : message d'une
|
||||
autre session, avis, rappel système, sortie de hook."""
|
||||
return {"type": "user", "isMeta": True, "timestamp": t,
|
||||
"message": {"role": "user", "content": texte}}
|
||||
|
||||
|
||||
def resultat(t):
|
||||
return {"type": "user", "timestamp": t, "message": {"role": "user", "content": [
|
||||
{"type": "tool_result", "tool_use_id": "x", "content": "…"}]}}
|
||||
|
||||
|
||||
# Deux tours : A de 10:00 à 10:05 (300 s), B de 10:08 à 10:10 (120 s).
|
||||
@@ -46,7 +59,7 @@ TRANSCRIPT = [humain("2026-10-21T10:00:00Z", "A"), agent("2026-10-21T10:02:00Z")
|
||||
APPELS = []
|
||||
|
||||
|
||||
def lancer(ts, saisies, *options, jeton=True, refus=False):
|
||||
def lancer(ts, saisies, *options, jeton=True, refus=False, session=SESSION):
|
||||
"""Lance main() avec un Gitea qui renvoie `saisies` ; rend les lignes JSON.
|
||||
jeton=False n'ajoute pas --jeton ; refus=True attend que l'outil refuse,
|
||||
sans avoir appelé Gitea."""
|
||||
@@ -58,7 +71,7 @@ def lancer(ts, saisies, *options, jeton=True, refus=False):
|
||||
ts.gitea = gitea
|
||||
APPELS.clear()
|
||||
sys.argv = ["temps-session.py", "--depot", "organisation/depot", "--ticket", "1",
|
||||
"--session", SESSION, *(["--jeton", str(JETON)] if jeton else []), *options]
|
||||
"--session", session, *(["--jeton", str(JETON)] if jeton else []), *options]
|
||||
sortie = io.StringIO()
|
||||
erreur = io.StringIO()
|
||||
try:
|
||||
@@ -194,6 +207,49 @@ jeton = "autre.jeton"
|
||||
verifier(sortie.getvalue().strip() == "temps-session.py " + ts.VERSION,
|
||||
"--version affiche %r" % sortie.getvalue())
|
||||
|
||||
# 13. Le fichier VERSION et la constante de l'outil (qui se télécharge
|
||||
# seul) disent la même version.
|
||||
version = (DEPOT / "VERSION").read_text().strip() if (DEPOT / "VERSION").exists() else None
|
||||
verifier(version == ts.VERSION, "VERSION dit %r, l'outil %r" % (version, ts.VERSION))
|
||||
|
||||
# 14 à 17 : entrées user écrites par Claude Code (isMeta). Chaque cas a
|
||||
# sa session ; le tour A va de 10:00 à 10:05 (300 s).
|
||||
def cas(numero, entrees):
|
||||
session = "00000000-0000-0000-0000-0000000000%02d" % numero
|
||||
(projet / (session + ".jsonl")).write_text("".join(json.dumps(d) + "\n" for d in entrees))
|
||||
return [l["time"] for l in lancer(ts, [], "--config", str(config), session=session)]
|
||||
|
||||
tour_a = [humain("2026-10-21T10:00:00Z", "A"), agent("2026-10-21T10:05:00Z", "end_turn")]
|
||||
reprise = [agent("2026-10-21T10:26:00Z", "tool_use"), resultat("2026-10-21T10:26:30Z"),
|
||||
agent("2026-10-21T10:27:00Z", "end_turn")]
|
||||
|
||||
# 14. L'agent a rendu la main ; une autre session lui écrit 20 min plus
|
||||
# tard (sous --pause) et il reprend : l'attente n'est pas comptée,
|
||||
# restent A et la reprise (10:25 à 10:27), 420 s.
|
||||
temps = cas(14, tour_a + [meta("2026-10-21T10:25:00Z", "Another Claude session sent a message: "
|
||||
'<cross-session-message from="autre">…</cross-session-message>')] + reprise)
|
||||
verifier(temps == [420], "message d'une autre session après l'attente : %r au lieu de 420 s" % temps)
|
||||
|
||||
# 15. Même chose pour un avis d'inactivité d'une autre session.
|
||||
temps = cas(15, tour_a + [meta("2026-10-21T10:25:00Z", '[Cross-session idle notice] "autre" …')] + reprise)
|
||||
verifier(temps == [420], "avis d'une autre session après l'attente : %r au lieu de 420 s" % temps)
|
||||
|
||||
# 16. Une entrée isMeta écrite pendant un tour (rappel système, sortie de
|
||||
# hook) ne coupe pas la plage : 300 s, pas 240.
|
||||
temps = cas(16, [humain("2026-10-21T10:00:00Z", "A"), agent("2026-10-21T10:02:00Z", "tool_use"),
|
||||
meta("2026-10-21T10:03:00Z", "<system-reminder>…</system-reminder>"),
|
||||
resultat("2026-10-21T10:04:00Z"), agent("2026-10-21T10:05:00Z", "end_turn")])
|
||||
verifier(temps == [300], "entrée isMeta pendant un tour : %r au lieu de 300 s" % temps)
|
||||
|
||||
# 17. Un sous-agent qui finit son tour (isSidechain) ne rend pas la main
|
||||
# de l'agent principal : la plage n'est pas coupée non plus.
|
||||
fin_sous_agent = agent("2026-10-21T10:02:30Z", "end_turn")
|
||||
fin_sous_agent["isSidechain"] = True
|
||||
temps = cas(17, [humain("2026-10-21T10:00:00Z", "A"), agent("2026-10-21T10:02:00Z", "tool_use"),
|
||||
fin_sous_agent, meta("2026-10-21T10:03:00Z", "<system-reminder>…</system-reminder>"),
|
||||
resultat("2026-10-21T10:04:00Z"), agent("2026-10-21T10:05:00Z", "end_turn")])
|
||||
verifier(temps == [300], "fin de tour d'un sous-agent : %r au lieu de 300 s" % temps)
|
||||
|
||||
if echecs:
|
||||
print("%d échec(s) :" % len(echecs))
|
||||
for e in echecs:
|
||||
|
||||
Reference in New Issue
Block a user