update_meal
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.
A meal imported from Cronometer, Fitbit, Apple Health, or Health Connect can't be edited here; the call refuses and names where to edit it instead. Relay that to the user rather than retrying.
FIND THE MEAL: call directly, no preliminary list for an ID or additive totals. Use id if known (it is in list_meals output and in the chat history's saved-records note after a log). 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: add_saved: add_recipe_name appends recipe food and ADDS its macros to current totals. Match: case-insensitive exact title, then substring; relay no-match/ambiguous errors. Stored recipe macros, including 0, are authoritative; explicit macros replace the recipe's contribution only for a correction or changed food/quantity. Missing recipe macros: estimate only the missing fields from returned food text and retry with the same selector and add_recipe_name. add_unsaved: add_food_items plus the four core macros (calories/protein_g/fat_g/carbs_g) for ONLY the new food; estimate those core values, never ask for them. Text appends; core macros ADD to current totals. alcohol_g: optional, omitted adds nothing. add_both: set add_recipe_name and add_food_items; ordinary core macro fields describe ONLY the unsaved addition. Recipe contributes its stored core macros. correct: both add_* unset; supplied fields REPLACE stored values. Send corrected totals, omit unchanged fields. Changed food_items: the four core macros for the WHOLE corrected meal; list_meals only if needed stored values are unavailable this turn. Additions and explicit value corrections need no pre-read. food_items: when supplied, replaces the description even in add modes. SATURATED FAT / FIBER: expanded nutrients, never required for an update. The estimator or a saved recipe's nutrient panel can fill omitted values, and core-macro updates work without them. 0 is a real value only when known, never a placeholder. ambiguous_add_vs_correct: ask before updating.
ESTIMATE: estimate (same format as log_meal's ESTIMATE section) supplies the nutrient estimate for whatever food this call changes -- the add_unsaved/add_both addition's own food, or, for a mode-3 food_items replacement, the WHOLE corrected meal. Omit to let the server estimate instead; never required.
MOVE TO A DIFFERENT DATE -> move_to_date. "move Tuesday's lunch to Wednesday": date/name/target_meal_type only SELECT which meal to update; they never move it. Set move_to_date to actually change the stored date, keeping the same id.
REMOVE ONE ADDED COMPONENT -> remove_item_name. Only works for a food previously recorded on THIS meal (add_recipe_name, add_food_items, or log_meal's own estimated items). If the meal has no such recorded item, this throws telling you to use mode 3 with corrected totals instead. An estimated item (log_meal's own food, no add_recipe_name/add_food_items involved) carries a name and gram estimate but no recorded calorie/macro split for that one item, so a precise subtraction isn't possible: this throws asking you to also send calories/protein_g/fat_g/carbs_g (the meal's corrected TOTALS after removing it) in the SAME call, which performs the removal and applies those totals together, in that order -- do this rather than a separate correcting call. Removing an item re-estimates the meal's nutrient panel from what remains (its updated food text and items), rather than leaving a stale estimate for food that's gone -- pass estimate here too to supply that re-estimate yourself instead of letting the server do it.
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. Drinks only; exclude food moisture.
CAFFEINE / DRINKS WHEN UPDATING: keep the two sidecars explicit in the same update_meal call. fluids is the hydration side and caffeine is the caffeine side; when a drink change affects both, send both. Omit either one when that side is unchanged so existing linked data is preserved. When ADDING caffeinated food/drink with add_food_items/add_recipe_name, caffeine contains only the new dose(s) and they are appended. When CORRECTING the meal's caffeine with both add_* fields omitted, caffeine is the complete corrected dose list and replaces linked caffeine only after replacement rows have been safely inserted. If the correction removes every caffeine dose, explicitly send caffeine: []. Each retained/new dose needs caffeine_mg and may optionally include source_type; its date follows the meal date.
SAVE AS RECIPE: when the user asks to save an already-logged meal as a reusable recipe, set save_as_recipe=true. This may be the only requested action: identify the real meal with id or the normal selectors and do not invent a food or macro edit. A follow-up like "save that as a recipe" after a successful log should use the known meal id plus save_as_recipe=true. Do not tell the user recipes cannot be saved from chat.
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. This only SELECTS which meal to update -- see move_to_date below to actually change a meal's stored date. | |
| 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 | Fat (g). See THREE MODES. | |
| fluids | No | Optional drinks consumed in this intake, including liquid ingredients in shakes or smoothies. Omit when no drink amount is known. Hydration is persisted only when the user enabled hydration tracking. | |
| carbs_g | No | Carbohydrates (g). See THREE MODES. | |
| fiber_g | No | Optional expanded nutrient: dietary fiber (g). | |
| caffeine | No | Optional caffeine doses in this intake. Keep each dose simple: caffeine amount is required and type is optional. The dose date follows the intake/meal date. If the user gave exact milligrams, preserve them exactly; otherwise estimate from the described food or drink. | |
| calories | No | Calories (kcal) never kJ | |
| estimate | No | The compact 3-line nutrient estimate for the food this call adds or the WHOLE corrected meal on a food_items replacement. See ESTIMATE above for the format. Omit to have the server estimate instead -- never blocks the write either way. A block whose parts exceed their whole (saturated fat over fat, fiber over carbs) is discarded and re-estimated. NUTRIENT ID DICTIONARY (id=name, unit is the name's suffix; ug=mcg). Every id means exactly this nutrient, never guess the order: 1=fiber_g 2=sugar_g 3=saturated_fat_g 4=monounsaturated_fat_g 5=polyunsaturated_fat_g 6=trans_fat_g 7=cholesterol_mg 8=sodium_mg 9=potassium_mg 10=calcium_mg 11=iron_mg 12=magnesium_mg 13=phosphorus_mg 14=zinc_mg 15=copper_mg 16=manganese_mg 17=selenium_ug 18=chloride_mg 19=chromium_ug 20=iodine_ug 21=molybdenum_ug 22=vitamin_a_ug 23=vitamin_c_mg 24=vitamin_d_ug 25=vitamin_e_mg 26=vitamin_k_ug 27=thiamin_b1_mg 28=riboflavin_b2_mg 29=niacin_b3_mg 30=pantothenic_acid_b5_mg 31=vitamin_b6_mg 32=biotin_b7_ug 33=folate_b9_ug 34=folic_acid_ug 35=vitamin_b12_ug 36=choline_mg 37=omega3_g 38=omega6_g 39=caffeine_mg 40=water_g 41=starch_g 42=added_sugar_g 43=total_unsaturated_fat_g 44=fluoride_mg | |
| alcohol_g | No | Alcohol (g). See THREE MODES. | |
| meal_type | No | Updated meal type to WRITE onto the meal (e.g. reclassify a Snack as Dinner), only when the user asks to change the type. A "For my breakfast:"-style label at the start of the message is the pill the user had open, not a request to change it. 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 | Protein (g). See THREE MODES. | |
| food_items | No | Replacement food description; omit to preserve or append. See THREE MODES. | |
| move_to_date | No | Move this meal to a different date. Format: YYYY-MM-DD. Distinct from date above, which only finds the meal; this is what actually changes it, keeping the same id. Optional, omit if not moving the meal. | |
| add_food_items | No | Unsaved food description to add; omit unless adding unsaved food. See THREE MODES. | |
| recipe_fiber_g | No | Optional recipe-component fiber (g) for add_both. | |
| save_as_recipe | No | True only when the user explicitly asks to save this meal as a reusable recipe. The recipe is copied from the final persisted meal. On update_meal, this can be the only requested action; use the real meal id or normal selectors and do not invent an edit. | |
| add_recipe_name | No | Saved recipe name or close phrase to add; omit unless adding saved food. See THREE MODES. | |
| saturated_fat_g | No | Optional expanded nutrient: saturated fat (g). | |
| remove_item_name | No | Name or substring of a previously-recorded item to remove from this meal (see REMOVE ONE ADDED COMPONENT above). Normally exclusive of every other field below -- only id/date/name/target_meal_type may accompany it, to select the meal, plus optionally estimate for the remaining meal -- EXCEPT when the tool has already refused this exact removal asking for corrected totals: then also send calories/protein_g/fat_g/carbs_g together with remove_item_name in the retry. | |
| 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. | |
| recipe_saturated_fat_g | No | Optional recipe-component saturated fat (g) for add_both. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes | Human-readable result text returned by the tool. |