- Thread tools are bound server-side to the chat's own thread. The model
used to pass contact_id, so practice mode could read any conversation it
named; a model-supplied contact_id is now only checked, never trusted, and
the prompts no longer hand it one.
- Practice chats need no persona. They're stored under PRACTICE_PERSONA_ID
and run with an inert stand-in, so deleting or editing personas can't hide
or break them. persona_id is optional on create for as_contact.
- The per-thread list filters in SQL (list_persona_chats_for_contact, served
by idx_persona_chat_anchor_contact) instead of decoding every transcript.
- fetch_mms_image checks the content type and a 20 MB cap before reading
the body, so a video attachment isn't downloaded in full.
- get_photos_near_time unions tags over every path sharing the content, per
the multi-library model.
- look_at_photo only opens indexed photos, so an excluded folder can't be
read by guessing a path.
- One date parser: get_photos_near_time uses date_info::parse_center.
- Practice prompt source rewrapped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A local insight's transcript carries the photo itself, so continuing on hybrid
was refused. Each hybrid turn now has the local vision model describe the
photo (cached per image), sends the description in its place, and puts the
photo back before saving, so the stored chat and later local turns keep it.
If the local description fails, the turn fails. The stored model id is only
reused on the same backend, so a llama-swap slot isn't sent to OpenRouter.
Checked end to end against a recording fake OpenRouter on all three
continuation endpoints: no image data left, the stored transcript kept the
photo, and switching back to local saw the photo again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing in the client stopped it: a message carrying images became image_url
parts and went out. Photos stayed local only because callers routed around it.
messages_to_openai, which every OpenRouter request passes through, now refuses
any image (IMAGES_STAY_LOCAL), and describe_image always errors; hybrid mode
describes photos with the local model. A caller bug now fails the turn instead
of uploading a photo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Small local models get weekdays, "how long ago" and day counts between dates
wrong, confidently. Persona chats anchored on old SMS threads ask exactly
those questions. date_info answers them exactly, in the owner's display zone:
- no args: now (replaces get_current_datetime)
- date: its weekday and how long ago / until
- date + other_date: the gap in days, weeks and years/months/days, plus
hours when both carry times
- date + add_days: the date N days after (or before)
Checked live on gemma4-26b-A4B and gemma4-31: each date question took one
date_info call and came back correct.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
describe_photo describes the file chat's photo. Persona chats have no photo,
so a vision-capable model was offered a tool that could only answer "No image
available". Persona chats now build their catalog with the vision gate off;
the thread tools still cover looking at images there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An anchored conversation now has a mode. 'about' is the existing behaviour (a
persona talks with the user about the thread). 'as_contact' has the model play
the contact so the user can rehearse the conversation: its own prompt (stay in
the contact's voice, don't invent facts, coach on 'out of character'), no
persona prompt, and only the thread tools — no memory, library, calendar or
other-thread access, and no knowledge writes.
The shared persona/file-chat loop now refuses tool calls that weren't in the
turn's catalog, so the gates hold even when a model names a tool it wasn't
offered.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Persona conversations can now be anchored on a message in an SMS thread.
Creating one snapshots the thread up to that message (via SMS-API) into the
row; every turn appends it to the persona prompt with guidance to talk like a
text thread rather than write an insight.
Anchored turns get four tools: get_thread_messages (page the thread),
look_at_message_image (local vision on an MMS photo), get_photos_near_time
(library photos with tags and people) and look_at_photo (local vision on a
library photo). The conversation list filters by contact_id.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>