Skip to content

v1.0.0

Choose a tag to compare

@enriquephl enriquephl released this 03 Aug 09:56
· 129 commits to main since this release
v1.0.0
1440c2a

First stable release. The 0.x stability commitments in
docs/model-config.md
carry forward unchanged into 1.x.

⚠️ Breaking

Three config changes now refuse to boot. The last two were dead config that silently did nothing, so deleting the key is the whole migration. The first was live and needs a real port.

Config Was it doing anything? Fix
[defaults].ignore_providers / .provider_sort (#213) Yes — these fed OpenRouter routing on chat and vision requests Port to a body rule on the openrouter entry (below), then delete the old keys
[tasks.affinity_evaluation].filter_prompt (#214) No — never read Delete the key; the evaluator's prompt is engine-owned. Every shape counts as set, an explicit blank included
[tasks.<name>.tiers.*] on any task other than chat_companion / chat_output_filter (#217) No — could never be selected Move the settings to the task level, or delete the block

Migration for the first row:

[[providers.openrouter.body]]
params = { provider = { ignore = ["some-bad-provider"], sort = "price" } }
# optional: tasks = ["chat_companion", ...] to scope the rule

Wire-contract removals (#216), all consequences of the judge going seedless:

  • image.image_prompt is gone from the stream request — the composer decides what the picture shows from turn context, so a caller-supplied prompt has nowhere to go.
  • image_prompt is gone from the PDE judge's accepted verdict JSON. A custom [tasks.pde_decision].filter_prompt that still asks for it is writing a field nothing reads.
  • prompt_variant = "raw" is no longer a reserved escape that skipped composition. With no seed to draw verbatim there is nothing to skip to, so raw is now an ordinary variant name — it selects a variant only if you configured one under that literal key.

Two behaviour changes that do not block boot:

  • [tasks.chat_image_prompt_compose] is now required for image capability (#216). The server still boots without it, but the judge no longer writes image-prompt seeds, so judged image actions have no prompt source and degrade to text. One narrow exception: a client-forced turn (image.force = true) bypasses the capability gate and falls open to a generic persona-portrait prompt, logging a warning. Configure the block to keep real image turns.
  • Vision calls no longer send OpenRouter provider prefs (#213). The removed [defaults] keys also fed the chat_vision body; body rules are chat-only, so there is no replacement on that path.

Features

  • [[providers.<name>.body]] custom body params (#213) — opaque per-provider params merged into the chat/completions wire body, scopable per task. Replaces the removed [defaults] provider-routing prefs for chat requests.
  • First-person affinity evaluation (#214) — the evaluator now reads the turn in the character's own voice rather than as a third-person analyst, with explicit reason-text hygiene rules aimed at stopping a canned refusal from being rationalised into persistent persona state (the reason field is persisted and re-injected as [emotional_context], so it was a real feedback loop). Sent as a system + user pair. Scoring contract unchanged — same five deltas, same caps, same seven-key JSON. Ships alongside an always-on Chinese anti-refusal guard in the chat prompt prefix.
  • Seedless generate-mode image composer (#216) — the PDE judge stops writing image-prompt seeds; the composer generates the prompt from turn context instead. On reply_text_image it runs concurrently with the chat call, so the compose hop hides under it (reply_image has no chat call to overlap). A generic persona-portrait prompt remains the sanctioned fail-open when the composer produces no subject. The composer also emits a short caption, which every history-facing render now uses. The engine counts recent images for the judge instead of asking it to tally markers in the transcript.
  • Tier-block boot gate (#217) — [tasks.<name>.tiers.*] refuses to boot for any task outside chat_companion / chat_output_filter, the only two the engine ever resolves with a tier. Same dead-config failure class as #210, one level deeper in the config tree.
  • Compose-call audit trio (#211) — compose_variant / compose_model / compose_generation_id on chat_messages.metadata.image.
  • Voice relationship line (#209) — bond/chemistry tiers drive a single relationship line in the voice prompt, with a per-turn relationship_scope request field selecting which halves inject.

Docs

  • Full pre-1.0 documentation audit (#218) — every claim in the doc set checked against the source. 12 verified factual errors fixed across seven doc pairs, including three dead type citations stale since PR #42, a "no LLM call" claim invalidated by the opt-in PDE judge in #83, and a Chinese page that documented the exact opposite of the code after a fail-safe removal. Chinese-version content gaps closed (the entire Voice section, the world_director background path, the channel field). Every deferred finding cleared in the same PR.

Install

docker pull ghcr.io/etherfunlab/eros-engine:1.0.0
eros-engine-core  = "1.0"
eros-engine-store = "1.0"   # Postgres + pgvector layer
eros-engine-llm   = "1.0"   # OpenRouter + Voyage clients

Full changelog: v0.9.3...v1.0.0