name: food-tracking description: >- Log food eaten, view daily intake, manage food journal entries. Triggers: "j'ai mangé / pris", "I ate / had", "log breakfast / lunch / dinner / snack", "log my [meal]", "petit-déj / déjeuner / dîner / collation", "ajoute à mon tracker", "add to my tracker", "enregistre / log this meal", "mets dans mon suivi", "onglet Suivi du Jour", "mon bilan / daily summary", "combien il me reste ?", "what did I eat", "qu'est-ce que j'ai mangé", "modifier / edit an entry", "supprimer / delete / remove an entry from my log". 3 scripts: log_food_entries (write), get_daily_summary (read), delete_food_entry (delete).
Food Tracking
Workflow décisionnel (ORDRE OBLIGATOIRE)
Avant tout appel a log_food_entries, suivre cet ordre :
Etape 1 — Detection FAVORI (priorite absolue)
Si la phrase contient l'un de ces signaux → APPELER get_user_favorites (skill meal-planning) AVANT toute chose :
- "ma recette / mon plat / mon bol / mon shake / mon petit-dej favori"
- "comme d'habitude / d'hab / comme l'autre jour / comme toujours"
- "mon X prefere / habituel"
- "ce que je prends d'habitude"
Si match → reutiliser ingredients du favori (deja decomposes, en grammes) avec log_food_entries. Si aucun match → demander a l'utilisateur OU passer a l'etape 2.
Etape 2 — Decomposition obligatoire (si pas un favori)
Tout plat compose DOIT etre eclate en ingredients individuels AVANT l'appel.
Mots-cles forcant la decomposition :
- "bol de…" → eclater (skyr + flocons + fruits + miel…)
- "plat de…" / "recette de…" / "menu" / "repas" → eclater
- "smoothie / shake" → eclater (banane + lait + flocons…)
- "salade de…" / "carbonara" / "ratatouille" → eclater
JAMAIS logger un plat compose comme 1 seul item. Le script rejette avec code: "DECOMPOSE_REQUIRED".
Etape 3 — Conversion unites → grammes (OBLIGATOIRE)
JAMAIS envoyer unit: "piece" / "portion" / "unite". Toujours convertir en grammes via cette table :
| Aliment | Poids/piece | Aliment | Poids/piece |
|---|---|---|---|
| Œuf | 60g | Steak hache | 150g |
| Banane | 120g | Escalope de poulet | 130g |
| Pomme | 180g | Escalope de dinde | 130g |
| Orange | 200g | Filet de poulet | 150g |
| Kiwi | 75g | Pave de saumon | 150g |
| Tomate | 150g | Yaourt (1 pot) | 125g |
| Avocat | 150g | Pot de fromage blanc | 100g |
| Oignon | 150g | Tranche de jambon | 30g |
| Carotte | 120g | Tranche de pain | 30g |
| Courgette | 200g | Muffin anglais | 57g |
Hors table : estimer en grammes via bon sens nutritionnel (150g pour viande/poisson moyen, ~120g pour fruit moyen). Le script a un fallback LLM si tu envoies quand meme 500ms) et imparfait — convertis toi-meme.unit: "piece", mais c'est lent (
Exemple complet (utilisateur dit "j'ai mange 2 steaks haches et 1 yaourt") :
run_skill_script("food-tracking", "log_food_entries", {
"items": [
{"name": "steak hache", "quantity": 300, "unit": "g"}, # 2 × 150g
{"name": "yaourt nature", "quantity": 125, "unit": "g"} # 1 × 125g
],
"meal_type": "dejeuner"
})
Scripts
| Script | Action |
|---|---|
log_food_entries |
Ecrire des aliments dans daily_food_log (INSERT ou UPDATE) |
get_daily_summary |
Lire le bilan du jour : macros consomme/restant + detail par repas (aliments, quantites, macros) |
delete_food_entry |
Supprimer une entree du journal (par entry_id ou par recherche food_name) |
Parametres log_food_entries
| Parametre | Type | Requis | Description |
|---|---|---|---|
items |
list | oui | Liste d'objets {name: str, quantity: float, unit: str}. Chaque item = 1 ingredient simple. Cle = name (pas food_name). |
log_date |
str | non | YYYY-MM-DD. Defaut = aujourd'hui. Cle = log_date (pas date). |
meal_type |
str | non | "petit-dejeuner" | "dejeuner" | "diner" | "collation". Defaut = "dejeuner". Au niveau racine, pas dans chaque item. |
entry_id |
str | non | ID d'une entree existante a modifier. Le premier item de items remplace l'aliment (recalcul macros via OFF). |
Parametres get_daily_summary
| Parametre | Type | Requis | Description |
|---|---|---|---|
log_date |
str | non | YYYY-MM-DD. Defaut = aujourd'hui. |
Parametres delete_food_entry
| Parametre | Type | Requis | Description |
|---|---|---|---|
entry_id |
str | non* | UUID de l'entree a supprimer (prefere). |
food_name |
str | non* | Nom de l'aliment a chercher (fuzzy). *Au moins un des deux requis. |
meal_type |
str | non | Filtre par repas (avec food_name). |
log_date |
str | non | YYYY-MM-DD. Defaut = aujourd'hui. |
Si food_name matche plusieurs entrees → retourne la liste (code: "AMBIGUOUS") pour que l'agent demande confirmation ou precise avec entry_id.
Regles complementaires
Echec de matching OFF : Si log_food_entries retourne skipped_items non vide, mentionner explicitement a l'utilisateur les aliments non enregistres et proposer de reformuler le nom (plus generique, ex. "pain complet" au lieu de "baguette aux graines bio Carrefour") ou de fournir les macros manuellement. Codes d'erreur possibles dans skipped_items[].reason :
no_match: aliment introuvable dans OFF ni estimable par LLMMISSING_QUANTITY_OR_UNIT: item sans quantite/uniteUNKNOWN_UNIT: unite non convertible en grammes (rappel : convertir engcote agent, voir Etape 3 du workflow)
Code retour DECOMPOSE_REQUIRED : Le script a detecte un plat compose en 1 seul item. Re-essayer avec les ingredients eclates (voir Etape 2 du workflow). Si l'utilisateur reference clairement un favori, appeler get_user_favorites d'abord (Etape 1).
Recette issue de la conversation : Quand l'utilisateur demande de logger une recette qu'on vient de generer, reprendre EXACTEMENT les ingredients et quantites de la recette. Ne pas reestimer — utiliser les donnees deja presentes dans la conversation. Determiner le meal_type selon le contexte.
Lecture du tracker : Quand l'utilisateur demande ce qu'il a mange ou veut voir son suivi, appeler get_daily_summary. La reponse inclut meals_detail avec chaque aliment (entry_id, nom, quantite, unite, macros) groupe par repas — utile pour repondre a "qu'est-ce que j'ai mange ce matin ?" ou reutiliser un repas dans un plan.
Suppression fiable (par entry_id) : Pour supprimer un aliment, l'identifier par son entry_id plutot que par son nom. Si tu n'as pas encore l'entry_id, appelle d'abord get_daily_summary (chaque item de meals_detail porte un entry_id), puis delete_food_entry avec cet entry_id. La recherche par food_name est un repli pratique mais fragile : elle echoue si l'aliment a ete decompose (ex. "supprime ma carbonara" alors que c'est stocke en spaghetti + lardons + oeuf) ou si le nom differe. En cas de code: "AMBIGUOUS", re-appeler avec l'entry_id choisi dans la liste matches.
Modification d'une entree existante : Pour corriger un aliment deja journalise — changer le type ("non, c'est des escalopes pas du poulet") OU la quantite ("plutot 250g") — utiliser log_food_entries avec entry_id (le premier item de items remplace l'aliment et recalcule les macros via OFF). Comme pour la suppression, si tu n'as pas l'entry_id, lis d'abord get_daily_summary pour retrouver l'entree concernee.
Contexte [SUIVI RAPIDE - date: X] (barre rapide de l'onglet "Suivi du Jour") : la requete arrive sans historique de conversation (ephemeral) et l'utilisateur ne voit que ta reponse courte (affichee en notification) + la mise a jour de la jauge. Donc :
- Determine l'intention (ajouter par defaut / supprimer / modifier) et agis sur la date X : passe
log_date: Xadelete_food_entry,log_food_entriesetget_daily_summary(ne pas retomber sur "aujourd'hui" si X est une date passee). - Pour une suppression ou une modification, tu n'as pas le contexte conversationnel : appelle d'abord
get_daily_summary(log_date=X)pour voir les aliments journalises ce jour-la, retrouve la bonne entree par sonentry_id, puis agis. - Reponds par une confirmation courte et explicite de ce qui a ete fait (ex. "Poulet remplace par 250g d'escalopes" / "Riz supprime"). Si l'entree visee est vraiment ambigue, pose une question breve (l'utilisateur la verra) plutot que de deviner.
Exemples
# Ingredients simples
run_skill_script("food-tracking", "log_food_entries", {
"items": [
{"name": "poulet grille", "quantity": 200, "unit": "g"},
{"name": "riz basmati", "quantity": 150, "unit": "g"}
],
"meal_type": "dejeuner"
})
# Recette complete depuis la conversation (reprendre les ingredients exacts)
run_skill_script("food-tracking", "log_food_entries", {
"items": [
{"name": "escalope de poulet", "quantity": 400, "unit": "g"},
{"name": "farine de ble noir", "quantity": 50, "unit": "g"},
{"name": "riz blanc", "quantity": 100, "unit": "g"},
{"name": "poivron rouge", "quantity": 100, "unit": "g"},
{"name": "oignon", "quantity": 60, "unit": "g"},
{"name": "tomate", "quantity": 80, "unit": "g"},
{"name": "creme fraiche allegee", "quantity": 60, "unit": "ml"},
{"name": "huile d'olive", "quantity": 8, "unit": "ml"}
],
"meal_type": "dejeuner"
})
# Modifier un aliment existant
run_skill_script("food-tracking", "log_food_entries", {
"entry_id": "uuid-de-l-entree",
"items": [{"name": "skyr", "quantity": 200, "unit": "g"}],
"meal_type": "petit-dejeuner"
})
# Ajouter un favori au tracker (2 etapes)
# Etape 1 : recuperer le favori et ses ingredients
run_skill_script("meal-planning", "get_user_favorites", {"name": "poulet grillé"})
# → retourne ingredients: [{"name": "poulet", "quantity": 200, "unit": "g"}, ...]
# Etape 2 : logger les ingredients individuels
run_skill_script("food-tracking", "log_food_entries", {
"items": [
{"name": "poulet", "quantity": 200, "unit": "g"},
{"name": "herbes de provence", "quantity": 5, "unit": "g"}
],
"meal_type": "dejeuner"
})
# Supprimer par nom (recherche fuzzy dans les entrees du jour)
run_skill_script("food-tracking", "delete_food_entry", {
"food_name": "riz basmati",
"meal_type": "dejeuner"
})
# Supprimer par entry_id (retourne par get_daily_summary dans meals_detail)
run_skill_script("food-tracking", "delete_food_entry", {
"entry_id": "uuid-de-l-entree"
})
# Bilan du jour
run_skill_script("food-tracking", "get_daily_summary", {})
# Bilan d'une date specifique
run_skill_script("food-tracking", "get_daily_summary", {"log_date": "2026-03-05"})