Skip to content

v1.0.1

Choose a tag to compare

@enriquephl enriquephl released this 04 Aug 07:06
· 124 commits to main since this release
v1.0.1
5cda5e3

Features

  • image.force redefined + standalone /persona image 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 its filter_prompt contract, so a deployment's custom composer prompt serves both callers unchanged.
    • The endpoint doubles as a composer test surface: the response carries model and generation_id, and stream: true (the default) passes the composer's raw output through verbatim, so an operator tuning a filter_prompt can see exactly what the model returned rather than the post-fallback result. The terminal done frame minus its type discriminator is byte-identical to the stream: false body.
    • 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 502 status 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.

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.

  1. image.force = true no longer produces a text reply. It is now always reply_image (image only). The reply_image / reply_text_image split belongs to the PDE judge, which a consumer has already overridden by forcing.
  2. content is required on forced turns. The force + image_only empty-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.
  3. mode no longer does anything, and fails silently. ImageMode and the mode field 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 new force contract, and the composer task's second consumer.
  • Corrected two stale architecture claims this work exposed: the auth middleware protects everything except /healthz and /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. The routes/ module listing was also incomplete and is now correct.

Full changelog: v1.0.0...v1.0.1