You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two-Phase Intent Recognition Architecture (Core of this release): Splits the original "single full skill list to LLM" into two phases, significantly reducing Token consumption
Phase 1 (Coarse Selection): Sends only one line of name + description per skill; LLM determines which skill categories are needed; pure small talk returns null directly, skipping Phase 2 for normal AI conversation
Phase 2 (Precise Selection): Sends full details (actions + hints) only for skills selected in Phase 1, completing action selection and parameter extraction; validates skill_name against whitelist, invalid names rejected
Quantified benefits:
Pre-refactor baseline (single-phase, per recognition): main rules ~26K + all skills full ~80K (incl. BukkitAPI 77 actions ~38K) ≈ 106K chars
Pure small talk: only Phase 1 (returns null, no Phase 2) ≈ 8K chars, ↓ ~92% vs baseline
Normal skill (1 built-in skill hit, median full size ~3.1K): Phase 1 + Phase 2 ≈ 38K chars, ↓ ~65%
Response speed: two-phase adds one ultra-lightweight Phase 1 call, but each recognition no longer carries the full skill list; net latency depends on model and network
Skill SPI Structured Response Architecture (new needInfo secondary confirmation): Skill response semantics upgraded from "message-string prefixes" to typed status
New SkillResult.needInfo(message) factory: the official contract for third-party Skills to implement "needs info / secondary confirmation" (missing-param prompts, large-transfer confirmation, etc.); the framework emits a [NEED_INFO] marker and intent recognition drives the confirmation flow
SkillResult adds a typed SkillStatus enum (SUCCESS/FAILURE/NEED_INFO) + getStatus(); a new normalization layer SkillResultFormatter uniformly tags output to the LLM as [SUCCESS]/[FAILURE]/[NEED_INFO] — Skills write plain text, eliminating the inconsistency and double-tagging caused by hand-written prefixes
SPI Jar adds the SkillStatus class (6th class)
Intent Recognition Prompt System Restructuring (Chinese/English synced): Added "Three Inviolable Rules" top-priority rule (default to multi-step when uncertain); single-intent/multi-step decision refactored to three-condition check (required param provided by user + completable in one action + no dependency on other actions' return values); arithmetic placeholders unified for amount/quantity/price/threshold; parameter missing enforced "query-then-act" (null required params prohibited); Phase 1 coarse-selection positioning strengthened (favor recall over precision)
LLM Thinking Mode Governance: Normal conversation path auto-disables thinking for models with thinking on by default (MiMo, DeepSeek V4+, GLM 4.5+, Kimi K2+, Qwen3, Grok 4, Doubao thinking, MiniMax-M3, etc.); admin reasoning path injects enable params per model family; adapted OpenAI o-series / Doubao thinking max_completion_tokens. Resolves thinking tokens sharing max_tokens budget with output tokens causing empty output in MC scenarios (small quota)
Placeholder Arithmetic Evaluation Utility (ArithmeticUtil): Evaluation logic extracted to a public utility class; application scope expanded from multi-step task scalar params (amount/quantity/price) to CUSTOM task threshold, supporting relative thresholds like "5 below current health" ({step_0.health}-5). Single binary operation only (+ - * /), pure regex, no injection risk
Startup Version Update Detection: Async GitHub latest release check, colored console box notification on new version, silent on failure
🔧 Improvements
Diagnostic Model Fallback Mechanism: When admin.yml has no reasoning model configured, auto-falls back to llm.yml base chat model (reuses url/key/model only, max_tokens/timeout still use diagnostic-specific values to avoid report truncation), lowering the barrier for health monitoring
Health Monitoring Unavailable Layered Diagnostics: Checks prerequisites one by one (model / guardian switch / Spark installed), gives precise hints; diagnostic report header adds a "Diagnostic Model" row marking the actual generation model
DB History Load Count Tuning: loadFromDB limit changed from maxHistory×2 to maxHistory (default 20), reducing redundant loading
AFK Task String Condition Value Display Optimization: EvaluationResult adds actualValueStr; string conditions (e.g., block types) display real values instead of 0/1 placeholders
LLM Empty Response Friendly Hint: Returns "AI temporarily unavailable" to the player when streaming response is empty instead of an empty message (also logs SSE chunk count and recent raw data for troubleshooting)
JSON Scenarios Disable max_tokens: Intent recognition, profile analysis, etc. no longer set max_tokens, preventing complex JSON truncation; GenericBukkitAPI description enhanced to improve Phase 1 classification accuracy
Concurrency & Thread Safety: ConversationManager history queue upgraded to ConcurrentLinkedDeque + auto trim (MAX_HISTORY_SIZE=100); AFKTaskManager atomic registration prevents overflow; ProfileManager.flushAllProfiles single-connection batch update prevents cascade failure
Code Cleanup & Observability: LLMProvider interface simplified, ThinkingModelCapable upgraded to functional interface; SkillIntentRecognizer exception catching with full stack trace; GreetingPromptBuilder event summary merge eliminates ~140 lines of duplication; unified history access; cleaned up redundant i18n wrappers and translation dead keys
Embedding Retrieval Optimization: chunk vector norm precomputed and cached, cosine similarity computation reduced by 2/3
reconcileOnlineProfiles Single-Connection Batch: aligned with flushAllProfiles pattern
Profile Analysis Prompt Temporal Optimization (Chinese/English synced): No longer extracts volatile transient data like balance, coordinates, and inventory counts; retains only long-term stable traits to avoid stale wrong info lingering in the profile; existing profiles are auto-cleaned on the next analysis
Built-in Skills fully migrated to structured output: MarketActionSkill / CMISkill / MarketQuerySkill / CommandSkill stripped hand-written [FAILURE]/[NEED_INFO] prefixes (~80 sites), uniformly tagged by the framework normalization layer; TaskExecutor multi-step internal skip status switched to a typed enum, removing the old Chinese-prefix sniffing (fixes a latent classification mismatch under English locale)
Secondary confirmation & prompt governance (Chinese/English synced): intent recognition prompts add a "confirmation-flow" rule (reads the concrete value from history when the player confirms a prior action); llm.yml system prompt uniformly documents marker semantics; messages_en.yml strips marker prefixes embedded in keys/values and fixes a duplicate key; Skill-SPI-Integration-Guide.md (zh+en) fully rewritten
🐛 Bug Fixes
Fixed BM25Scorer.countOccurrences infinite loop on empty keyword causing mvn test to hang forever
Fixed KnowledgeRetriever.splitByFixedSize off-by-one where content exactly at MAX_CHUNK_SIZE was split into an extra trailing chunk by the overlap rollback logic
Fixed ConversationPersistenceService.mergeLoadedHistory clearing itself when loadedHistory and playerHistory are the same object via clear(), causing history loss (triggered when a player sends a message for the second time or later with valid in-memory history, via /ai command or chat listener path)
Fixed thinking/reasoning models producing empty output in normal conversation (covered by thinking mode governance)
Fixed profile analysis JSON parsing occasional failure (auto-repair then re-parse), CUSTOM task condition_plan null NPE, shutdown flushAllProfiles connection exception cascade failure, ConversationManager non-thread-safe ArrayDeque concurrent data loss
Security & Stability Hardening: Fixed multiple stability and security boundary issues; added recent active player cache to strengthen data isolation
⚠️ Compatibility
Upgrading from v2.1.0
Stop server, replace JAR, start
MUST remove intent_prompts.yml / intent_prompts_en.yml: the two-phase architecture + prompt system restructuring changed this file's structure significantly (new phase1 section, full rewrite into 9 sections, new "Three Inviolable Rules", etc.). Old file contents override the code's built-in new defaults, so the two-phase architecture and this prompt refactor will not take effect — you must delete and restart to let the plugin regenerate it
Recommended (for full skill / model config optimization effects): the following config files are recommended to be deleted and regenerated (works without deletion, just missing some optimizations):
llm.yml (thinking mode governance notes + default model updates + skill-result marker semantics unified: added [SUCCESS]/[FAILURE]/[NEED_INFO]/[SKIPPED] four-marker fallback handling and multi-step failure semantics; old config overrides the new version) / admin.yml (diagnostic model fallback notes)
config.yml (new security.player_isolation.offline_cache section, recent active player cache)
database.yml (new h2.tcp section, H2 TCP Server access control; profile analysis prompt temporal optimization, old config overrides the built-in new version, update or delete to regenerate)
Except for the intent_prompts.yml in step 2, all other config entries have code-level default fallbacks — works without deleting them
Lower diagnostic feature barrier: when no admin.yml reasoning model is configured, health monitoring auto-falls back to llm.yml, usable without extra config (diagnostic quota still controlled by admin.yml, no conflict with normal conversation)
Skill SPI fully backward compatible: SkillResult changes are purely additive (success/failure/public constructor signatures unchanged); already-compiled third-party Jars need no recompilation and no changes — at runtime the server's new SkillResult provides and auto-fills status (the SPI Jar is compile-time only, not packaged into third-party plugins). Old Skills need no changes; to use new capabilities like needInfo, recompile against the 2.1.1+ SPI Jar