NexusAI 1.2.0
What's new
Feature release: a plugin API for text and JSON generation, events for other plugins, daily token quotas, keyword knowledge selection and Folia support. It also stops printing API keys placed in a provider URL. Everyone on 1.1.2 can update. The new keys are appended to config.yml automatically, and it stays at config-version: 2.
Upgrading
- Replace
NexusAI-1.1.2.jarwithNexusAI-1.2.0.jarand restart. Commands and placeholders are unchanged.NexusAIApi.API_VERSIONis now3. - You do not need to edit
config.yml, and do not changeconfig-version. On the first start, 18 missing keys are copied from the jar default:plugin-api.*,quotas.*andknowledge.select/knowledge.keywords.*. The log showsAdded missing config keys: …, and that start writes oneconfig.yml.bak(orconfig.yml.bak.<timestamp>). Values you already set and your comments stay. - The appended defaults keep 1.1.2 behaviour: quotas are off and reject nothing, and knowledge selection stays
full. providers.<id>.structured-output,model-queuedaily-token-limit, and the prompt keysknowledge-select/knowledge-keywordsare not inserted. Add them yourself when you want them.prompts.yml,pool.ymlandusage.ymlstay on version 1.token-usage.ymlis created by the first counted request.- To roll back: stop the server, put
NexusAI-1.1.2.jarback and start it. 1.1.2 ignores the new keys, soconfig.ymlcan stay as it is. To remove the new keys, restore theconfig.yml.bakwritten by 1.2.0.token-usage.ymlis not read by 1.1.2. Details are indocs/migration-1.2.0.md.
Keys in provider URLs
- Fix: a key in a provider URL is no longer printed. This covers query values such as
?key=…and userinfo such asuser:pass@. Affected places:/nai status, the startupbase-url:line,/nai testand reload errors, provider warnings, exception messages and FINE request logs. Every query value is shown as***, userinfo as***@, and scheme, host, port and path stay readable. - Secret-looking query values from your configured URLs are also masked wherever they appear, including in provider error bodies that echo the request, events and the last error. This means names such as
key,api_key,token,sig,x-goog-api-key, or a name ending inkey/token/secret. The userinfo password is masked the same way. Ordinary values such as Azureapi-versionor amodelid are left alone in replies. - The HTTP request still sends the real query string.
- 1.1.1 and 1.1.2 printed an unmasked
?key=value on the/nai statusBase URL line and in the startup log. If you put a key in a provider URL, check old logs and consider rotating that key.api-keyorapi-key-fileremains the recommended place for keys. actions.logandmoderation.logare now owner-only (0600) on POSIX, including a file that already had a looser mode.
Plugin API
NexusAIApi.generatereturns aGenerationResultwith the text, source, provider, model, token counts, finish reason, latency, and aNexusErrorKindwhen the model did not answer. The future completes on a NexusAI thread. Do not join it on the main thread or a region thread.NexusAIApi.generateJsontakes aJsonSchema, and a successful result has been checked locally against it. It usesresponse_formatwhen the provider accepts it.providers.<id>.structured-outputmay beauto(default),json-schema,json-objectorprompt. One invalid reply is retried once on the same row; a second one completes asINVALID_JSONwith the fallback text. Only validated JSON is cached.NexusAIApi.registerPromptregisters anamespace:idprompt that survives/nai reloadand is removed with its plugin. An admin entry with the same id inprompts.ymloverrides it.- New
config.ymlkeys:plugin-api.enabled,plugin-api.max-template-charsandplugin-api.max-var-chars.
Events
- New events for other plugins:
NexusPreGenerateEvent,NexusPostGenerateEvent,NexusGenerateFailEvent,NexusProviderErrorEvent,NexusActionEventandNexusModerationFlagEvent. - One real model call fires Pre, then any failed HTTP attempts, then exactly one of Post or Fail. A cache hit, an in-flight join and a pooled answer fire none of them.
- Cancelling Pre skips HTTP and reports
CANCELLED. CancellingNexusActionEventrefuses the action without spending its cooldown. The order is documented indocs/api.md.
Token quotas
- With
quotas.enabled: true, a request is sent only while each cap that applies is not yet reached. The caps are per server, per player (or the most generousnexusai.quota.<name>group), per API plugin, and permodel-queuerow (daily-token-limit). Tokens reserved for calls in flight count. One call in flight can finish above a cap. /nai usage [players|consumers|history],%ainexus_usage_*%and/nai statusshow today's tokens./nai talkshowstalk.quota, and the API reportsQUOTA_EXCEEDED. A local rejection does not pause a provider.- With quotas off, nothing new is rejected and the counters still update in
token-usage.yml.
Knowledge by keywords
knowledge.select: keywords(orknowledge-selecton a prompt) sends only the paragraphs that match the request instead of whole files. There is no vector search and no embeddings.knowledge.keywords.*sets the paragraph and file limits, the minimum matches,on-no-matchand the stop words.knowledge-keywordson a prompt adds words to the query./nai testprints which knowledge was attached.fullstays the default and keeps the 1.1.2 cache key.
Folia
- Folia is supported on 1.21.8, 1.21.11, 26.1.2 and 26.2, and
plugin.ymlsetsfolia-supported: true. This rests on a thread audit and a CI smoke test on each of these versions. Other Folia versions may work and are not tested. - When the placeholder thread does not own the player, the world name given to a context provider is empty.
Masking and dialogue memory
- More vendor keys are masked even when they are not configured: DeepSeek, OpenRouter, one-case Groq and lowercase Anthropic keys. A CamelCase token such as
sk-NexusAIPluginForMinecraft2026is left as written. - A failed save or load of a data file or log logs the exception class and a masked message at WARNING. The stack trace goes to FINE. A data folder whose name contains a key does not print that key.
- Fix: stopping the server while
dialogue-memory.ymlis still loading saves the characters that are only in memory. Stop now splices them into the file within a 5-second budget. The existing bytes stay unchanged, and the file is replaced atomically. If that is not possible in time, the file is left untouched and one warning says how many characters were not saved.
Known issues
- The player-input boundary and the reply filter reduce prompt-injection risk. They do not eliminate it.
- An HTTP 429 on one model pauses its whole provider. Put
fallback-modelon a different provider so/nai talkcan still answer. - A key under a secret-looking URL parameter that is shorter than 6 characters is still hidden in printed URLs. It is not masked when a provider echoes it in an error body. Use
api-keyorapi-key-filefor such keys. - With a very large
dialogue-memory.yml, stop can take up to its 5-second budget. - Live structured output was checked only with Groq. OpenRouter, OpenAI and Ollama use the same code path but were not checked against the live service.
Compatibility
- Paper and Purpur 1.20.6–26.2; Folia 1.21.8, 1.21.11, 26.1.2 and 26.2 only; Java 21 or newer
- PlaceholderAPI 2.11.6+ (soft-depend); on Folia 2.11.7+
- Tested with PlaceholderAPI 2.12.3 on Paper 1.20.6-151, 1.21.1-133, 1.21.4-232, 1.21.8-60 and 26.2-129/133, on Purpur 1.20.6-2233 and 26.2-2633, and on Folia 1.21.8-6, 1.21.11-14, 26.1.2-8 and 26.2-7 (Java 21 on 1.20.6–1.21.11, Java 25 on 26.1.2 and 26.2).
- Paper and Purpur 26.3, Spigot and CraftBukkit are not supported.
Download
NexusAI-1.2.0.jar, SHA-256 f7add005ffd3eec3716174a6a93ad07f7ff2a7b1f1458285e197e2b40aff10ee
Full history: CHANGELOG.md
This mod has no additional files

