Tâches : « rappelle-moi dans 20 minutes » sans cron, à l'heure du navigateur

Repris d'AJEAN 0.17.5.

- task_create accepte in_minutes (dans N minutes) ou at (« HH:MM », prochaine
  occurrence, ou « AAAA-MM-JJ HH:MM ») pour une tâche unique, calculée côté
  serveur : le modèle n'a plus à écrire un cron ni à jongler avec les
  fuseaux pour un simple rappel. Elle s'écrit « @once AAAA-MM-JJ HH:MM » et
  se désactive après son passage ; manquée pendant un arrêt, elle part au
  redémarrage.
- Le navigateur envoie son fuseau (Europe/Paris…) avec chaque message ; il
  est retenu et sert aux tâches que l'IA planifie. Le conteneur tourne en
  UTC : « à 17h » tombait deux heures à côté. La réponse de task_create
  nomme le fuseau utilisé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 5.5 committed 2026-10-02 23:25:04 +02:00
1 parent 8171899ac1
commit 2bbf0ba76d
8 files changed
+160 -12

No files matched your search

+4 -1
View File
@@ -683,6 +683,9 @@ function loadFullHistory(){
// (« déjà en cours ») = succès (c'est notre envoi qui est passé). On ne montre une
// erreur qu'après plusieurs échecs ET vérification que rien ne tourne — plus de
// « network error » alarmiste alors que l'IA répond quand même.
// Fuseau du navigateur, envoyé avec chaque message : le conteneur tourne en UTC,
// et « rappelle-moi à 17h » doit tomber à 17h ici (voir rememberUserTZ).
const USER_TZ=(()=>{ try{ return Intl.DateTimeFormat().resolvedOptions().timeZone||''; }catch(_){ return ''; } })();
async function send(){
// Garde-fou : le bouton est déjà désactivé, mais l'Entrée passe aussi par ici.
if(STATUS_SEEN && !MODEL_READY){ toast('le modèle n\'est pas encore prêt'); return; }
@@ -711,7 +714,7 @@ async function send(){
if(PENDING && !queuedAtSend) addMsgFiles(PENDING, attachSent());
for(let attempt=0; attempt<3; attempt++){
try{
const r=await jfetch('/api/chat/send',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:text,files:files,ctx_used:CTX_USED,cid})});
const r=await jfetch('/api/chat/send',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:text,files:files,ctx_used:CTX_USED,cid,tz:USER_TZ})});
if(r.ok) clearAttach();
// 409 = une tâche planifiée occupe le modèle : pas de file dans ce cas.
if(r.status===409){ let m='modèle occupé'; try{ m=(await r.json()).error||m; }catch(_){} fail(m); return; }