v1.0.1
Features
image.forceredefined + standalone/personaimage compose endpoint (#220) — breaking, see below.- New
POST /persona/{instance_id}/image/compose: standalone image-prompt composition for a persona instance. Not a chat turn — nothing is persisted, no affinity runs, no memory is written. It shares the chat path's[tasks.chat_image_prompt_compose]task, its five-slot payload, and itsfilter_promptcontract, so a deployment's custom composer prompt serves both callers unchanged. - The endpoint doubles as a composer test surface: the response carries
modelandgeneration_id, andstream: true(the default) passes the composer's raw output through verbatim, so an operator tuning afilter_promptcan see exactly what the model returned rather than the post-fallback result. The terminaldoneframe minus itstypediscriminator is byte-identical to thestream: falsebody. - New top-level
/persona/*namespace, authenticated by the same middleware and bounded by the same per-user in-flight cap (≤3) as chat and voice. - New
502status for the repo (AppError::Upstream), scoped to this endpoint, so a caller can tell "the provider failed my call" from "the engine broke". There is deliberately no portrait fallback here — the chat path's fail-open exists to keep a turn moving, and this endpoint has no turn to protect.
- New
Fixes
fix(core): correct the ghost threshold comment and lock the non-decay (#219)
Breaking changes
Three consumer-visible changes on the chat stream (POST /comp/chat/{session_id}/message/stream). The version number does not signal these — read this section before upgrading.
image.force = trueno longer produces a text reply. It is now alwaysreply_image(image only). Thereply_image/reply_text_imagesplit belongs to the PDE judge, which a consumer has already overridden by forcing.contentis required on forced turns. Theforce+image_onlyempty-content exemption is gone: the turn existed to produce an image while the composer's strongest input — the user's message — was blank by design.modeno longer does anything, and fails silently.ImageModeand themodefield are deleted. A leftover"mode": "text_image"key still deserializes and is ignored, so a consumer that keeps sending it silently gets an image-only turn instead of text + image. This is the one to check before upgrading — it does not error. The silent-ignore is deliberate (a clean break beats accumulating tombstone fields at this stage) and is pinned by a test so it cannot regress into a deserialization error.
Additionally, image.force now requires [tasks.chat_image_prompt_compose] to be configured and returns 422 pre-stream otherwise. Previously force was the one path that bypassed the image-capability gate, emitting an image_request whose prompt came from the style preset and persona appearance alone — a generic portrait that ignored whatever the user said.
Docs
api-reference/model-config/architecture(both languages) document the new endpoint, the newforcecontract, and the composer task's second consumer.- Corrected two stale
architectureclaims this work exposed: the auth middleware protects everything except/healthzand/docs(not "/comp/*only"), and it attaches to the merged sub-router rather than a path prefix — which is why the new/persona/*namespace needed no additional auth wiring. Theroutes/module listing was also incomplete and is now correct.
Full changelog: v1.0.0...v1.0.1