v1.0.0
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 ruleWire-contract removals (#216), all consequences of the judge going seedless:
image.image_promptis 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_promptis gone from the PDE judge's accepted verdict JSON. A custom[tasks.pde_decision].filter_promptthat 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, sorawis 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
providerprefs (#213). The removed[defaults]keys also fed thechat_visionbody; 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
reasonfield 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_imageit runs concurrently with the chat call, so the compose hop hides under it (reply_imagehas 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 shortcaption, 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 outsidechat_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_idonchat_messages.metadata.image. - Voice relationship line (#209) — bond/chemistry tiers drive a single relationship line in the voice prompt, with a per-turn
relationship_scoperequest 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_directorbackground path, thechannelfield). Every deferred finding cleared in the same PR.
Install
docker pull ghcr.io/etherfunlab/eros-engine:1.0.0eros-engine-core = "1.0"
eros-engine-store = "1.0" # Postgres + pgvector layer
eros-engine-llm = "1.0" # OpenRouter + Voyage clientsFull changelog: v0.9.3...v1.0.0