This commit is contained in:
Mikan
2026-06-21 04:11:38 +03:00
parent bd85e186dc
commit 4dee4fb0a8
19 changed files with 1423 additions and 115 deletions

View File

@@ -4,6 +4,46 @@ All notable changes to AI-RPG are documented here.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.2.0] — 2026-06-21
This release fixes critical bugs that prevented world creation, world editing, and LLM tool-calling with local models (gemma, qwen, etc.).
### Backend — Critical fixes
- **Prompt templates**: fixed `KeyError: 'scene_text, delta_time'` that crashed world_builder during intro scene generation. The prompts contained literal `{scene_text, delta_time}` braces which `str.format()` interpreted as format fields. Rewrote `orchestrator_phase2` and `intro_scene` prompts to describe the tool arguments in prose instead of using brace notation. All 11 prompt templates now format correctly (verified with a test).
- **LLM tool-call parsing for local models**: many local models (gemma4, qwen, etc.) don't use the OpenAI function-calling format — they emit tool calls as text like `call:calc{"expression": "2+2"}` or `<tool_call>calc{...}</tool_call>`. Added `_parse_text_tool_calls()` to `app/core/llm.py` that detects these patterns and converts them to OpenAI-format `tool_calls`. The LLM client now automatically parses text-based tool calls when the model doesn't return them in the standard format. This fixes the issue where `request_tools` was `[]` (empty) in logs even though tools were sent — actually tools WERE sent, but the model returned calls as text and they were ignored.
- **Test endpoints — ascii codec error**: `POST /api/admin/test/llm-tools` failed with `'ascii' codec can't encode character '\u2026'` when the client sent a masked api_key (containing `…`) back as a query parameter. Added `_is_masked()` and `_resolve()` helpers that detect masked values (`…` or `****`) and fall back to the raw DB value. All 4 test endpoints (test/llm, test/llm-tools, test/embeddings, test/embeddings/probe-dimension) now use these helpers.
- **Test LLM tools — better prompt**: the test now sends a system message "You must use the calc tool" and a user message "You MUST call the calc tool with expression '2+2'" to encourage tool use. Also increased timeout from 15s to 30s. The response now includes `raw_response` (the full LLM message) for debugging.
- **World editor — `'str' object has no attribute 'get'`**: the world_editor crashed when tool_calls contained string entries instead of dicts (some models return non-standard formats). Added type normalization: each tool_call is checked with `isinstance(tc, dict)`, strings are parsed as JSON, non-dicts are skipped. Also handles cases where `function` is not a dict.
- **World editor — propose_changes now waits for user**: previously `propose_changes` was auto-accepted (simplified). Now the editor emits `change_proposed` and WAITS for the user to accept/reject via `POST /api/sessions/worlds/{id}/apply` or `/discard`. Implemented using `asyncio.Future` stored in `_pending_changes` dict keyed by world_id. 120s timeout.
- **World editor — ask_user now waits for answer**: similarly, `ask_user` now waits for `POST /api/sessions/worlds/{id}/answer` body `{text: "..."}`. 120s timeout.
- **World editor — apply_diff improved**: now supports paths `world.name`, `world.description`, `schemas` (full replace), and `environment.<field>` (via apply_patch). Previously only `environment.*` paths worked.
- **World editor — better empty-state handling**: when world has no schemas/entities/environment, the prompt now shows "(no schemas yet)", "(no entities yet)", and "(empty — world has no environment yet. Use env_update to add player, current_location, plot_rails.)" instead of empty strings, so the LLM understands the context.
### Backend — New endpoints
- `POST /api/sessions/worlds/{id}/apply` — accept proposed changes (resolves the pending Future)
- `POST /api/sessions/worlds/{id}/discard` — reject proposed changes
- `POST /api/sessions/worlds/{id}/answer` body `{text: "..."}` — answer a clarification
- `POST /api/worlds/{id}/generate-intro``{stream_url}` — re-generate intro scene for draft worlds
- `GET /api/sessions/worlds/{id}/intro/stream` (SSE) — runs the intro_scene stage, sets world.status to "ready" on success. Emits `step`, `intro_scene_complete`, `done` events.
### Frontend — Critical fixes (10 files changed, 1 new)
- **World Editor — Accept/Reject buttons**: `change_proposed` events now show a card with the diff (color-coded: green=add, red=remove, yellow=replace) and two buttons. Accept → `POST /apply`, Reject → `POST /discard`. After decision, the card collapses to a status line.
- **World Editor — Answer input**: `clarification` events show a card with either free-text input + Send button, or clickable option buttons (if `options` provided). Submit → `POST /answer`.
- **World Edit Page — Generate Intro Scene**: new `IntroSceneGenerator` component. If `world.status === 'draft'`, shows a "Generate Intro Scene" button. Clicking it opens the SSE stream, shows progress, displays the generated scene, and on `done` refreshes the world (status → "ready") + shows toast "World is ready!".
- **Settings panel — autocomplete="off"**: all inputs now have `autoComplete="off"`. API key fields use `type="text"` (browsers won't save them as passwords). Added a hidden decoy password input to absorb the password manager's attention.
- **Username/email autocomplete**: verified `LoginPage` uses `autoComplete="username"` for the login field, `RegisterPage` uses `autoComplete="email"` for email and `autoComplete="username"` for username.
- **Test LLM Tools — raw response display**: when `has_tool_calls=false`, shows a warning + collapsible `<details>` with the raw LLM response so the user can see what the model returned.
- **World Builder — Retry button**: on error, shows a "Retry" button that re-subscribes to the builder stream. Also fixed a stale-closure bug where `done`/`error` events didn't close the active SSE controller (used `useRef` to track the current controller).
- **World Card — draft state**: draft worlds show a "Continue setup" button (links to edit page) and a "Draft" badge. No "Play" button for drafts.
- **Play page — better not-ready toast**: "This world is not ready yet. Generate the intro scene first."
### Verification
- Backend: 68 unit tests pass, 50 routes.
- Frontend: `tsc --noEmit` → 0 errors. `npm run build` → success (368 KB JS / 23 KB CSS, ~112 KB gzipped).
## [1.1.0] — 2026-06-21
This is a major bugfix release addressing 20+ issues found during user testing.