The minor guard cut "adult woman, no children, no minors" and let
non-consent wording through. It now masks negated phrases (NegEx-style,
comparatives excluded, sexual words still read raw), adds a non-consent
line, knows minor words in nine more languages, and leaves adult body
words like "petite" alone. Ratings: chat-made items tagged #nsfw are
rated NSFW, chat and Organize no longer lower NSFW or drop #nsfw unasked,
chat search filters by rating, packs spell rating tags one way and flag
a prompt with two. A template draft asked for a youth negative gets one.
Bench critiques #30 and #38.
Fixes from the 9B manual bench: How many follows the request (panel and chat draft_options); drafts see existing tags and drop every-option, label and name tags plus unasked negatives; "half as likely" halves the current weight and wrong-way weights are refused; retag that adds keeps tags (chat add_tags, constraint tag warning); partial "every" edits are asked once more.
Settings › AI assistant › Advanced › Debug log (off by default) gives every AI request an X-WP-Debug id. The server records each model call it makes (prompt as sent, reply, thinking, tool calls, tokens, errors), keeps the last 30 in memory and writes one file per request to ai-debug/ in the data folder (newest 300). Images, embedding vectors and keys are left out. A Debug button in the top bar lists the requests with Copy debug (Markdown) and JSON. WP_AI_DEBUG=1 records every request, for evals.
- The chat's plan card fills the Describe step and waits, so images and settings can be set first.
- Recommended pack settings (no model call) with a Use recommended button on the Settings step.
- Pack 11: model-rolling slots, family-named fixed values, writing-style slots and Pony tags on non-Pony packs are dropped; quality rules join into one; strip_repeats keeps rules on $model_*.
- Pack 15: folded slots are never a self axis; rule words become options after a fill.
- Fixed values panel sends fewer library variables (12-19 s on the 9B, was up to 113 s).
Plan drafts gets When needed (auto, the new default): after the first
draft, one more is asked only when score_plan finds a serious problem
(a relation that named nothing, a review fix other than request words,
a stated rule with no relation, too few prompt slots), and the better
draft is kept. Request gaps also match -ves plurals (elves → elf).
A slot's content call asks its options grouped by one axis (group_axis:
the one a rule narrows on, else one the slot offers, else the first),
at least two per value when the count allows, so every value is covered
by the first call. compile_slot flattens the groups; fill calls stay flat.
Co-authored-by: Claude <noreply@anthropic.com>
The code lands a share, hold and shown subject itself; a missing rule goes back to the planner once; a cut-off plan is asked again shorter; draw relations are never constraint cells; rules written as text, $$ leads and unasked multi-picks between rules are fixed at compile; the check catches a $name printed as written.
Graph planner settings lines, an accepts-aware dead-end tidy, constraints on drawn lists before their drawers (checked on drawn picks), a repair loop that skips unchanged problems, slot calls with style examples, and a pack eval smoke set. 9B smoke run: 12/15 clean packs vs 6/15 on dev, 15/15 plans compile.
Panels send the thinking off switch on Auto with sized output limits and a thinking watchdog. They list only the variables a request is about. They name wildcard names that two items share, recheck Add for a second concept, stop looping text answers early and ask again for a variable the request names. New scripts/ai_panel_evals.py; the 9B goes from 31/36 to 35/36 checks at 2.4x the speed.
- The check nudge ends with the exact run_test call for the cards (nudge → run_test 90% → 97% on the 9B).
- The clash warning keeps a variable the user's message names, instead of "pick another name".
- A guided change ask whose step only repeated a look-up, before any card, gets one more step with that tool closed instead of a forced answer.
- The unknown-name check counts the user's bare word.
9B smoke: full s42 18/20 with 0 false claims, full s7 20/20, empty 18/20; s-rename-var t2 6/6.
Short tool list (Settings › AI assistant › Advanced, off by default): a small model in typed JSON steps gets one line per tool in its instructions, and each tool's arguments and example in the tail of the step that first offers it, once while visible. It is fixed per chat (meta tool_index), so the prompt prefix stays stable. The eval takes --lean.
9B A/B: content tied (55 vs 55 over three pairs) with about 14% fewer prompt tokens per step, so the switch stays off by default for now.
Also drop "{1$$@{…}}" around a lone ref, like the bare braces.
On the full library the 9B answered the tag-filter note with the same
Sky card, byte for byte, in three runs of three; the note sat beside
"don't propose these again" (smoke s-tag-filter). That line now stays
out of the note's tail. A card sent again (exactly, or with only its
category or tags changed) runs the request check on the cards as they
are and is told what they still lack, counting as the note when none
came yet; a card that drops a feature the one it replaces had is told
so; a duplicate option holding a ref says one is enough; a rewrite of
every option counted from 0 is read as 1 to k; and braces around a
lone ref are dropped instead of refused.
On an empty library the 9B read the item twice, wrote "I've proposed
adding negatives…" with no call, and met the claim nudge with the same
text again (smoke s-negatives, both builds). The step after the nudge
now offers only the change tools it had plus the test tools, and the
repeat-read refusal points at the next call.
The 9B spent 2-4 steps after its card on more_tools and opening the card
it had just proposed, and only got the request check's note once it
answered (smoke on #108); on the full library it answered on the last
step, which skipped the note (no step left for the fix). A step after
the cards that changes nothing now carries the note, the note gives
itself the fix step and the answer even past the step cap, and opening
its own card (which can't open until the answer ends) closes open for
the rest of the answer. The smoke set's s-where check also accepts the
switch's own label.
On an empty library the 9B met the request check's note with more_tools,
opened its own card twice and then claimed the fallback or the
@{Palette:warm} options it never proposed (13 of 20 smoke checks, 17 on
a full library). The step after the note now offers only the cards' own
tools and the ones that add what is missing (request_check.fix_tools),
and a reply that talks about a missing feature anyway says no card has
it yet (request_check.claimed; "no fallback is needed" doesn't count).
A repeated refusal that forces the answer no longer skips the note.
The chat eval's --empty runs every scenario on a migrated empty
library, a new user's first chat.
Settings › AI › Advanced › Sampling sets top_p, top_k, min_p and repeat/presence penalties per provider slot (empty keeps the server's default). They go only to local and OpenAI-compatible servers. The chat eval gains --seed for a fixed sampling seed per scenario and run.
The request check (engine/ai/request_check.py) nudges once when the answer's cards lack a constraint, only rule, fallback, negatives or tag-filtered ref the request names. A tool repeated MAX_LOOPS times leaves the grammar for the rest of the answer. Page tools come to a task only on page words, and option tags in a wildcard ask no longer load the list tools.
- Typed JSON step grammars name only real items: ids limited to what the edit guard allows, read/run_test/open to what exists, and the tools that usually come next join the shortlist; a server that refuses the enums gets the plain grammar.
- A question or chat gets the reading, page and docs tools but nothing that changes or drafts; a follow-up in a chat that already proposed cards counts as a task.
- The shortlist core is search, read, ask and more_tools; docs, react, variables and run_test join only when the message or the answer calls for them, so first steps offer about ten tools.
- Traces record the message kind; eval runs keep each run's library and card ops, and the smoke checks read compiled refs.
- Send small and medium models feature cards with the message that needs them, and offer the tools a card names.
- Suggest local models by name only.
- Optional Type out replies (off by default), JSON steps included; the Thinking box streams live and the drawer says when the model sends nothing.
- Let the chat change an item its own card made.
- Evals start from a fresh library; traces record step time, thinking tokens and timeouts.
Each answer stores what its steps offered the model and what it did, summed by scripts/ai_trace_report.py. scripts/ai_chat_evals.py --set smoke runs ten asks with content checks. A new test fails if a request stops starting with the one before.
Settings and the chat header read the model's thinking choices from a
10-minute cache, so a model reloaded with other options (an LM Studio
model.yaml that gained or lost its off switch) kept showing the old
list. The thinking route now asks the server fresh; chat steps keep
the cache.
The LM Studio levels recipe in AI > Setup now says both model.yaml
fields are needed: without the enable_thinking boolean LM Studio lists
only the levels and can't turn thinking off. A level only counts while
thinking is on, so LM Studio's own chat needs its Thinking switch on.
Each provider and model takes different thinking values: LM Studio's
Qwen 3.x take only off and on (and LM Studio never hands a level to the
chat template, so Qwen 3.8 always ran at its xhigh default), Claude,
OpenAI and OpenRouter models each have their own effort levels, and
some can't turn thinking off.
- wp_api/_ai_thinking.py asks the server what the chosen model takes
(LM Studio /api/v1/models, Claude's Models API, OpenRouter /models,
Ollama /api/show, llama.cpp's chat template), else goes by the model's
name, and fits the saved setting before it is sent: a level on an
on/off model is On, Off on a model that must think is its lowest
level, a missing level is the nearest one.
- A refused value is asked again without it and remembered for the
model; a 4xx about thinking no longer marks the server as refusing
streams.
- A reply cut off with nothing but thinking is asked once more with
thinking off, and the model stays off until Thinking changes.
- llama.cpp gets the level as the template's reasoning_effort.
- New choices On, Extra high and Max; POST /wp/api/ai/thinking; Settings
and the chat header list only the model's choices with a line saying
what it takes.
- A JSON-mode reply that writes the rest of its step into the message
("calls: []", "**calls**: []", '"calls": []}', the calls list itself)
no longer shows it: engine/ai/step_fields.py cleans new answers and
utils/chat-step-fields.ts cleans stored chats and live text, kept in step
by tests/fixtures/step-fields-corpus.json.
- Items picked from the @ menu show as chips in the box while typing
(ChatInputMarks overlays tinted pills on the textarea text), in the chat,
the Draft with AI panels and the Pack builder.
- A picked wildcard's note tells the model to write @{Name} in options,
and a new wildcard that leaves out a reference the user asked for gets a
warning back so the model fixes it in the same answer.
- @{...} references in a chat reply stay coloured text; chips are for cards.
- Each reply shows how long it took beside Copy (elapsed_ms, kept with the
chat; time paused on the user is left out). Reopened chats keep their
format and tool-use badges too.
- The chat's model menu reloads when the provider or server changes.
- Docs: Ask about this page is pinned to the top right of the page, and it
and the docs starters name the page, so a question sent after moving on
still asks about it. The pipeline diagram stacks when narrow (docs beside
an open chat) instead of running off the side.
- Docs: AI chat page.
Dynamic Prompts and PPP variables, template arguments and PPP if blocks become stacks: setter wildcards, derivations for defaults, constraints from conditions and a Combine that renders the line. Model checks (_is_sdxl, _is_pony, ...) become a stack that reads WP Model Info. PPP stn and Umi negatives go to the option negative; PPP LoRA commands become <lora:...> text.
Umi AI YAML packs keep their tags, tag queries become weighted filtered references and Yaml Tags.txt names the tag groups. Subfolders that repeat list names become one table wildcard per name; template copies that differ by one tag fold into one steered wildcard.
The review lists installed extensions' wildcard folders, has a Bundles mode (stacks only by default), tag group renames, stack details and sample rolls from the real engine. Lists a condition reads stay out of merges, and folder reads skip symlinked files.
Shorter release notes, SeedList help, small-model docs; _chat_turn split and pyright in CI; ESLint a11y ratchet and Modal focus trap; tags/models/Image Filter tests; AI LAN warning, web allow expiry, one thinking setting per answer on local models, recommended hints and Reset to recommended (16k context minimum, 32k recommended); Assembler Clear template clears the negative; Vue 3.5.44, SECURITY and Dependabot.
Applied cards become (request, call) examples for small and medium models; common asks carry short steps; later steps say what the answer did; act asks run with thinking off; small chats compact sooner; a one-call explain docs tool; Test connection tries a small-model tool step; a struggling local answer offers the cloud provider already set up, once per chat; Advanced "Choose the tool first" names the tool before filling its arguments.
A multi-item ask on a split JSON chat is planned once (plan_items) and made one item per step with code keeping count; each step's grammar offers a shortlist of the chat's tools (more_tools widens it); confusable tools carry use-when lines and a sample call in the prompt and native descriptions.
* fix(chat): fixes from the Sonnet probe
- An empty answer after a failed page step, or on the last step, gets one
more step in words only; if still empty, the reply says the page step
didn't work.
- A change call sent again unchanged in one answer is answered "already
proposed, go on" instead of being made again, so five asked are five made.
- Keys and $variables that the docs, the library and the chat never mention
are sent back once to check or drop.
- Prompt: steps to do are a checklist, a risk is a Warning.
- A stray pipe on a note under a table is dropped.
* fix(chat): a link asked for is written in the answer, not pointed at
Sonnet probe: "link the guide back to me" made the model highlight the
guide, which failed.
---------
Co-authored-by: Claude <noreply@anthropic.com>
An ask sent with open / read_page in one step runs and the page calls wait; a repeated read_page or an open of a card already on screen counts as a repeat; "Remove clothing words" trims inside a phrase instead of dropping the option.
Pack builder: Fix all and updates say why nothing went out while the web search card waits; page follow-up lines are not request words; Only rows narrow only the tag groups they rule on; answers are not request gaps; code-wired story beats skip the lookup lint; left-out rules read plainly and get Fix with AI; a rule overwriting a pick becomes an append; model labels read "For Illustrious"; roomier plan head.
Chat: same-name edits refused with the shown item named; search by category for organizing; empty edit answers carry a note; prompt syntax coloured inside cards; every chat format named in the prompt; pointer captions avoid each other; one shared working line.
Search: what an allowed search found shows as a card in the Pack builder and the Draft with AI panels; Use what fits sends all results for the model to keep what fits, ticking sends only those, None of these sends nothing.
The pack-sheet round on the graph planner: agree/only sources roll an
accepts axis, fallback counting and tight-rule tips, the draw relation,
picks and model families read off the request, Quality and Negative
slots wired as fixed values and the template negative, Plan drafts best
of three, Danbooru respelling, thinking-off retry for all-reasoning JSON
answers, Reuse what fits on a graph plan, negative-ish names out of the
order, numeric derive text as weights, fills for missing axis values,
one derivation rule per axis, multi-pick rules dropped, request gaps
asked once, overlaps filed on the borrowing pick, the chat claim / defer
nudges, the empty-retag re-ask, and the adult-pack safety pass on every
wired item (request refusal, young-person words, tags and keyed rules
dropped, "mature" out of every negative).
A new Planner setting, Pack graph (the default), has the model write a
small typed graph (slots, axes, relations, template order) and the code
compiles every constraint, derivation, fixed value and the template from
it. Run and settings needs are wired by the code (story beats, sweep axes,
per-family quality, caps, style, rating, one bundle), hand edits are
locked, the plan review stops looping (typed findings, code questions,
narrow per-item Change with AI calls), and the chat gets the 9B fixes
(Tool format Automatic picks JSON steps for small models, XML calls run,
frame tests take numbers, written-out calls still run).
One card per idea, run_test finds items however the model names them, small-model rule and constraint shapes are cleaned up, Draft with AI panels use integer-enum ids with a catch-all repair call, Pack builder Fix all no longer loops, and scripts/ai_chat_evals.py runs scripted chats against a real model.
wp_api/ai.py keeps settings, Test connection, the library index and route registration; handlers move unchanged into _ai_drafts, _ai_turn, _ai_context, _ai_chats, _ai_pack and _ai_common.
Small and medium models answer each step in two parts (act, then answer). Web and Danbooru tools load by group via more_tools, appended at the end of the list. Test connection shows the fixed prefix split into instructions, tools and library summary. open takes a docs page id. A highlight before read_page is refused at once.
Chat round (explain on selection, page starters, reactions, streamed notes, thinking), negatives on node fixed values and combines, Pack builder quality fixes from 31 real-model eval rounds, and small-model support (scoped tools, checked tool arguments on local servers, two-phase steps, fixed prefix shown in Test connection).
Derivation and fixed values modules roll on their own rng stream (seeds through their alternations can resolve differently). DOM widgets tear down when their node is removed (effect scope, cleanups, shared onConnectionsChange wrapper, seed state in WeakMaps, capped topbar rAF loop). /import/commit validates module and bundle child payloads. WP_Context and preview close their library connection; the node path migrates once. Pinned option missing warns. CLAUDE.md says which parts of the schema machine are wired; js budget 473 KB.
Node knowledge and canvas variables for every AI feature, local tag/LoRA/embedding lookup, read_result page reading (built in, Crawl4AI or Firecrawl), opt-in Danbooru lookup, dismissable web warnings and "don't ask before web calls". Pack builder reads run style, subject and LoRA inputs from the request into the plan (Runs as), settings keep only pack-wide preferences plus Model; plan review checks stories, LoRA inputs and the model setting; anchor finding fixed; Fix with AI / Explain buttons; docs figure descriptions.
Variables are coloured text with hover cards instead of green chips on every surface (canvas included); nested @ refs keep their chips, and $name in a wildcard option is plain text. The derivation any / is empty / has value switch has room and is hidden under NOT exists. Tags use the accent colour. The AI pointer caption has a gap. Every AI box completes @ items, $ variables, tags, LoRAs and embeddings, and picked items reach the model with the message.
- LM Studio gets reasoning_effort "none"; OpenAI-compatible panel requests send thinking off too
- every AI request shows a one-line working status (random sparkle mark, changing word mixed with the real phase, timer), also in the top bar
- Ask to fix only on fixable card warnings
- per-provider model suggestions; OpenRouter picks link to their page
- pack builder: Settings step (remembered), web search ask on top and blocking, image and change marks, context meter, branch labels, reopened decisions stay listed, growing own answer, numbered images, images resent only when needed, Start over button
A chat's instructions plus all 37 native tool declarations come to about 17k tokens, so a model loaded with 16k in LM Studio or llama.cpp refused the first question. New chats now pick the leanest level that fits the window the server reports, cap re-sent history and tool results to the room left, retry leaner when the server still counts too many tokens, and otherwise say how much context to load. Compaction and the meter now count the tool declarations too.
Plan v2 (multi-answer questions, decisions, settings, sections, reserved ids, 60 items), Extend with AI and Make sub-bundles in the bundle editor, reference images on every Draft with AI panel, and opt-in web search in the wildcard and text panels.
Phases 2 to 8 of the AI assistant overhaul plus fixes from real-model chats: one tool registry with native tool calls, server-kept chat logs with prompt caching, an FTS5 library index with opt-in meaning search, keys bound to their address and a guard on every AI route, page tools and opt-in web search, saved chats with streaming, Try again, a context meter and compaction, chat images, delete/category/tag permissions with Undo, constraint and test cards, card fixes and previews, questions with answers to click, the derivation NOT toggle (schema v10, community catalog 0021), request fixes for the newest Claude models, and OpenAI's Responses API. Review fixes: Try again clears the old turn's fixes and answers, category Undo removes only what it made, a failed delete rolls back in order, not_matches patterns are checked, busy chats refuse a second request, and chat search ignores stored JSON.
- Chat acts instead of asking "should I proceed?" (one nudge), and a plan_pack tool hands a pack to the Pack builder.
- Chat keeps the user's question after a search, refuses repeated calls and must answer on its last step (it used to greet and re-run one search until it ran out).
- Search ranks items over name, variable, tags, description and content, folds plurals and widens broad subjects.
- Replies render Markdown without v-html, item mentions become chips, prompt syntax is coloured like the editors, Tip/Warning lines become callouts.
- Settings > AI assistant uses the full width: provider buttons marked Local/Cloud, compact fields, side cards; context and unload presets; Test connection warns below 16k and long results wrap.
- Ollama gets num_ctx sized to each request (Settings: Most context to use);
Test connection warns when LM Studio or llama.cpp loaded too little context.
- Model size profiles (auto from the name): small models get a slim prompt,
smaller tool results and a lower temperature; history is fitted to budget.
- Chat: a plan field before calls, one retry on an unusable step, a check
nudge when module changes were proposed without a test run, proposed
creates get ids so later calls in the same answer can use them.
- Pack builder: reads the library's conventions, reuses library wildcards,
takes a sample prompt, style/model/anchor on the plan, a plan review
(rules + optional model review) with "Fix these in the plan", rules
ordered after what they read, consumer briefs for wildcards, retry with
the error, one repair rebuild, variety notes from the check run.
- Import / Export: "Tag and connect with AI" after a wildcard pack import.
- Suggested local models updated (heretic builds, Artemis v1.2).
- Docs, README, release notes and docs index updated.
- AI panels in the fixed values, combine and template editors (/wp/api/ai/text/draft)
- chat creates and edits fixed values, combines, templates, bundles, rules and constraints, and runs test stacks
- Test Runner bar: explain the run, fix its warnings, why an option never comes up
- shared authoring guide (syntax, which feature for which job, coherence) for chat and pack builder
- pack builder plans fixed values, vocabularies, per-use settings and inputs; evals score features
- docs, README and release notes updated
The chat can search and read the built-in docs (engine/ai/docs_index.json,
rendered from the docs pages by pnpm docs:index) and open a docs page or a
manager page. It can remove, rewrite, retag and re-weight a wildcard's
options. Each message carries what the page shows: the open editor's item
with its unsaved changes, a list's filters and selection, the Test Runner's
last run, the Pack builder's plan. A change to the item open in an editor
goes into that editor's draft instead of the saved row. Docs pages get an
Ask the assistant button that explains the page or the selected text.
The Pack builder page plans a whole pack from one description (wildcards,
derivations, combines, constraints, a template), builds each item in its
own request, runs the pack on the engine, rebuilds items the run flags,
and installs everything as one tagged collection plus a bundle with one
undo. scripts/ai_pack_evals.py scores packs against a real model.
Test Runner warnings now keep their detail as data instead of a repr.
A top bar AI button opens a chat drawer. POST /wp/api/ai/chat runs up to
six model steps: read tools (search, read, variables) run on the server,
change tools (create wildcard/derivation/constraint, add options or rules,
update info, open) are compiled and validated into proposal cards. Apply
saves through the stores, Undo restores, and later changes to the same
item build on earlier ones.
Library lists get an Organize with AI action in the selection bar. The model
reads each selected module or bundle with the library's categories and tags
and suggests a category, tags to add or remove and a Safe/NSFW rating, with
a reason. Only real changes are listed; each is a chip the user can turn off.
Apply creates new categories, saves the ticked changes and offers Undo.
Follow-ups refine the answer like the other AI panels.
Every AI panel now keeps the conversation. After an answer, the request box
takes a follow-up; Refine sends it with the earlier requests, the model's own
answers and what the user unticked, and the model returns a revised answer in
full. Try again re-asks, the arrows flip between kept answers, and Start over
drops the conversation. Follow-ups reuse the context the first request saw.
The routes take an optional history and return the model's raw answer; the
client replays it as real turns for Claude (tool calls), OpenAI-compatible
servers and Ollama.