update_meal
Update an existing meal by adding saved or new foods, correcting calories/macros, or adjusting drinks. Finds the exact meal to change and preserves unrelated data.
Instructions
Update an existing meal. Use only when the current message explicitly changes, corrects, or adds to a meal already logged. Never infer an update from earlier chat history. A plain food statement ("coffee with milk") is a new entry: use log_meal, even if that meal type already exists today.
FIND THE MEAL: use id if known. Otherwise use date (YYYY-MM-DD, defaults to today) plus name and/or target_meal_type to narrow the existing row. target_meal_type finds the current type and is never written; meal_type sets a new type. If the match is not exactly one row, nothing changes. On multiple matches, ask the user which meal they mean; never select a candidate id yourself. Send only fields that change.
THREE MODES. Picking the wrong one corrupts the meal.
ADD SAVED FOOD -> add_recipe_name. "add my usual kombucha to breakfast", "add the protein shake I saved to lunch". Do NOT use log_meal for this, that logs a second, separate meal. Additive: the recipe's food text is appended to the meal's existing food_items and each of its macros is ADDED to the meal's current value for that field, so the result is both foods together with both foods' calories, not a replacement. Matched the same way as log_meal's recipe_name (case-insensitive exact title, then substring); no match or more than one substring match throws an error naming the candidates or the user's saved titles instead of guessing. If the matched recipe has no stored value for one of calories/protein_g/fat_g/carbs_g, this throws carrying the recipe's food text: estimate just the missing field(s) and call again with the same id (or date+name) and add_recipe_name plus those field(s) set explicitly. An explicit field passed alongside add_recipe_name takes the recipe's place for that one field and is still ADDED to the meal; it does not overwrite the meal's total the way it does without add_recipe_name.
ADD UNSAVED FOOD -> add_food_items. "add a banana to my breakfast", "I also had a small coffee", where the extra food is not one of the user's saved recipes. Pass the new food's own description plus calories/protein_g/fat_g/carbs_g estimated for JUST that new food, not the meal's new total and not the existing food's macros. All four are required whenever add_food_items is set (there is no recipe to fall back on): estimate them from the description, never ask the user. Additive exactly like add_recipe_name: add_food_items is appended to the existing food_items (unless food_items is ALSO passed explicitly, which replaces the description outright instead of appending) and each macro is ADDED to the meal's current value; alcohol_g is optional and adds nothing when omitted. add_food_items and add_recipe_name are mutually exclusive: never set both in the same call. Adding both a saved recipe and separate ad-hoc food means two update_meal calls, one per addition.
CORRECT A VALUE -> plain fields, both add_* unset. "that was 400 calories, not 600", "actually it was just eggs, no toast", "make it 500 calories": the meal's stored total needs to become a specific NEW number, not grow. Each of food_items/calories/protein_g/fat_g/carbs_g/alcohol_g you pass REPLACES the meal's current value for that field outright, so send the corrected TOTAL for that field, never an amount to add.
Reaching for mode 3 when the meal is GROWING is the exact bug this tool used to have: it silently REPLACES the whole meal with just the new food and throws away what was already logged.
If add-vs-correct intent is ambiguous, ask before updating.
DRINKS / HYDRATION WHEN UPDATING: a food update must not silently erase an already-linked hydration event. For changes unrelated to drinks, omit fluids and the existing hydration is preserved. When ADDING a drink with add_food_items/add_recipe_name, fluids contains only the newly added drink(s) and they are appended to the meal's hydration. When CORRECTING the meal's drinks with both add_* fields omitted, fluids is the complete corrected drink list and replaces the linked hydration only after replacement rows have been safely inserted. If the correction removes every drink, explicitly send fluids: [] and the linked hydration is deleted. Whenever a drink volume is known or reasonably inferable, include it.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Meal ID, if already known. Alternative to date + name/target_meal_type, see FIND THE MEAL above. | |
| date | No | Date the meal was logged. Format: YYYY-MM-DD. Used with name and/or target_meal_type to find the meal when id is omitted; defaults to today if id and date are both omitted. | |
| name | No | Substring of the food description (case-insensitive) to disambiguate multiple meals on the same date. Only used when id is omitted. | |
| fat_g | No | Updated fat in grams. Same REPLACE-vs-ADD rule as calories above, including required-with-add_food_items. | |
| fluids | No | Optional drinks consumed in this intake. Omit when no drink amount is known. Hydration is persisted only when the user enabled hydration tracking. | |
| carbs_g | No | Updated carbohydrates in grams. Same REPLACE-vs-ADD rule as calories above, including required-with-add_food_items. | |
| calories | No | Updated total calories (kcal). Optional, omit if not changing (or, with add_recipe_name, if the recipe already has a stored value). REPLACES the current value unless add_recipe_name or add_food_items is also set, in which case this is the AMOUNT BEING ADDED (the new food's own calories, not the meal's new total), added onto the meal's current value. Required whenever add_food_items is set, since there is no saved recipe to fall back on. | |
| alcohol_g | No | Updated alcohol in grams. Same REPLACE-vs-ADD rule as calories above, except this one stays optional even with add_recipe_name or add_food_items set: omitting it just adds nothing. | |
| meal_type | No | Updated meal type to WRITE onto the meal (e.g. reclassify a Snack as Dinner). Optional, omit if not changing. Never inferred from add_recipe_name. Distinct from target_meal_type above, which FINDS a meal by its current type and is never written. | |
| protein_g | No | Updated protein in grams. Same REPLACE-vs-ADD rule as calories above, including required-with-add_food_items. | |
| food_items | No | Updated food description. Optional, omit if not changing. With add_recipe_name and add_food_items both omitted, this REPLACES the current description outright. With either one present and this omitted, the new food's text (the recipe's stored food_items, or add_food_items itself) is appended instead. Passing this alongside add_recipe_name/add_food_items overrides the append with this exact text. | |
| add_food_items | No | Optional. Description of food to ADD to this meal that ISN'T a saved recipe, e.g. "a banana", "small coffee with cream" (see ADD FOOD THAT WASN'T SAVED above). Requires calories/protein_g/fat_g/carbs_g to be set to the estimated macros of just this new food -- never the meal's new total. Appends this text onto the meal's existing food_items and adds the macro fields onto the meal's current values; never use this to replace a meal outright (omit it and pass food_items/calories/etc. directly for that). Mutually exclusive with add_recipe_name -- never set both; if adding a saved recipe and separate ad-hoc food, make two calls. | |
| add_recipe_name | No | Optional. Name (or a close phrase) of one of the user's saved recipes to FOLD INTO this meal, e.g. "kombucha", "protein shake" (see FOLD IN A SAVED RECIPE above). Adds the recipe's food text and macros onto the meal's current values; never use this to replace a meal outright (omit it and pass food_items/calories/etc. directly for that). Distinct from log_meal's recipe_name, which SETS a new meal's fields instead of adding to one that already exists. Mutually exclusive with add_food_items -- never set both. | |
| target_meal_type | No | Which meal type to FIND on the date, e.g. Breakfast, to disambiguate multiple meals logged that day -- "update today's breakfast" is target_meal_type: "Breakfast". Case-insensitive, only used when id is omitted. This is NEVER written to the meal; it only narrows the search, exactly like name above. Distinct from meal_type below, which SETS the new type to write. If no meal of this type is logged on the date, the call throws naming the meal types that ARE logged that day and changes nothing -- it never falls back to whichever meal the date happens to match. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes | Human-readable result text returned by the tool. |