Wolf AI Assistant User Guide

May 23, 2026 · View on GitHub

中文

Wolf AI Assistant User Guide

This guide is for administrators and end users who want to enable and use the AI assistant inside Wolf. For a feature overview, start with README-AI-AGENT-EN.md.

Table of contents


1. What the AI assistant can do

The Wolf AI assistant is a conversational RBAC console embedded in the Wolf Console. You can drive Wolf with natural language:

  • Query: "How many roles does oa-app have? What permissions does each role hold?"
  • Create: "Under pi-mono, create a viewer role and grant it every permission whose ID starts with read_."
  • Update: "Remove the delete_user permission from the admin role."
  • Delete: "Delete the legacy-app application." (destructive — the AI will ask for confirmation)
  • Audit: "Were there any 403 accesses in the past week?"
  • Bigger tasks: "I need three roles for the sales team — sales-leader / sales-staff / sales-readonly. Suggest permissions based on naming conventions, show me the plan first, and once I approve, create them."

The assistant invokes Wolf's existing Controllers directly, so actions go through exactly the same code path as manual Console actions — including auth checks, argument validation, audit logging, and cache invalidation.

2. Prerequisites

2.1 Database upgrade

The assistant introduces 3 new tables:

TablePurpose
ai_chat_sessionOne session (one row in the sidebar)
ai_chat_messageOne message (user / assistant / toolResult), stored as JSON
ai_user_memoryOne user memory extracted from past sessions, injected into the next session's System Prompt

Fresh install: use server/script/db-psql.sql (PostgreSQL) or server/script/db-mysql.sql (MySQL). They already include the new tables.

Upgrading from 0.6.x / 0.7.x: run the upgrade to 0.8.x section of the upgrade script:

# PostgreSQL
psql -U wolfroot -d wolf -f server/script/db-psql-upgrade.sql

# MySQL
mysql -uwolfroot -p wolf < server/script/db-mysql-upgrade.sql

The upgrade script is idempotent for earlier sections; if you only want the 0.8.x changes, open the file and run just the upgrade to 0.8.x block.

2.2 Install dependencies

The server adds two core packages to package.json:

@mariozechner/pi-agent-core
@mariozechner/pi-ai

Both are ESM-only, while Wolf-Server itself is CommonJS — they are loaded via dynamic import(). Requirement: Node.js >= 18.

Then:

cd server
pnpm install   # or npm install

If you build Docker images (bin/build-all.sh), dependencies are installed inside the image — no manual step needed.

3. Configure the AI model

3.1 Configuration reference

Everything lives under the ai section of server/conf/config.js, and every field can be overridden via environment variable:

ai: {
  provider:           process.env.AI_PROVIDER       || 'openai',
  model:              process.env.AI_MODEL          || 'deepseek-v4-flash',
  api:                process.env.AI_API            || 'openai-completions',
  apiKey:             process.env.AI_API_KEY        || '',
  baseUrl:            process.env.AI_BASE_URL       || '',
  maxTurns:           parseInt(process.env.AI_MAX_TURNS)       || 20,
  maxHistoryMessages: parseInt(process.env.AI_MAX_HISTORY)     || 100,
  thinkingLevel:      process.env.AI_THINKING_LEVEL || 'low',
}
FieldEnv varDefaultDescription
providerAI_PROVIDERopenaiopenai / anthropic / google / mistral / groq / xai / openrouter
modelAI_MODELdeepseek-v4-flashModel ID, e.g. deepseek-v4-flash, gpt-4o, claude-3-5-sonnet-20241022, gemini-1.5-pro, qwen3.5-plus
apiAI_APIopenai-completionsAPI protocol. If the model is in the pi-ai built-in registry it is auto-detected; otherwise this value is used as fallback. Common: openai-completions (all OpenAI-compatible gateways), openai-responses (OpenAI's new Responses API only), anthropic-messages, google-generative-ai
apiKeyAI_API_KEYemptyAPI key. If empty, falls back to provider-specific env vars (see 3.3)
baseUrlAI_BASE_URLemptyCustom API URL, for proxies / self-hosted / regional gateways. Must include the version path, e.g. https://api.deepseek.com/v1
maxTurnsAI_MAX_TURNS20Max agent rounds per user turn (loop guard)
maxHistoryMessagesAI_MAX_HISTORY100Number of recent messages injected into context. Excess is pruned while keeping related assistant follow-ups intact
thinkingLevelAI_THINKING_LEVELlowlow / medium / high. Only meaningful for thinking-capable models

⚠️ Do not switch api to openai-responses unless you are talking to OpenAI's official Responses endpoint. For dashscope, self-hosted vLLM, Ollama, or any other OpenAI-compatible gateway, keep it on openai-completions.

3.2 Provider examples

DeepSeek (recommended default):

export AI_PROVIDER=openai
export AI_MODEL=deepseek-v4-flash
export AI_BASE_URL=https://api.deepseek.com/v1
export AI_API_KEY=sk-...
# AI_API defaults to openai-completions

Anthropic Claude:

export AI_PROVIDER=anthropic
export AI_MODEL=claude-3-5-sonnet-20241022
export AI_API_KEY=sk-ant-...
export AI_API=anthropic-messages

Google Gemini:

export AI_PROVIDER=google
export AI_MODEL=gemini-1.5-pro
export AI_API_KEY=...
export AI_API=google-generative-ai

Alibaba DashScope (Qwen) — OpenAI-compatible mode:

export AI_PROVIDER=openai
export AI_MODEL=qwen-plus               # or qwen3.5-plus, qwen-max, ...
export AI_API=openai-completions
export AI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
export AI_API_KEY=sk-...

Self-hosted vLLM / Ollama / SGLang:

export AI_PROVIDER=openai
export AI_MODEL=qwen3.6-35b            # whatever name your service exposes
export AI_API=openai-completions
export AI_BASE_URL=http://10.0.0.10:8000/v1
export AI_API_KEY=any-string             # most local stacks accept any string

OpenRouter:

export AI_PROVIDER=openrouter
export AI_MODEL=anthropic/claude-3.5-sonnet
export AI_API_KEY=sk-or-...

3.3 API key resolution order

server/src/ai/ai-config.js resolves the API key in this order:

  1. wolfConfig.ai.apiKey (i.e. AI_API_KEY) — only when the requested provider equals the currently configured provider
  2. The provider-specific standard environment variable:
ProviderEnv var
openaiOPENAI_API_KEY
anthropicANTHROPIC_API_KEY
googleGEMINI_API_KEY
mistralMISTRAL_API_KEY
groqGROQ_API_KEY
xaiXAI_API_KEY
openrouterOPENROUTER_API_KEY

This dual scheme suits both deployments (one AI_API_KEY injected per container) and local dev (re-use whatever SDK env vars you already export).

3.4 No migration needed when you switch models

Swapping provider / model / baseUrl is hot-pluggable:

  • Stored messages are provider-agnostic plain text and structured payloads. Old sessions remain usable after you switch models.
  • Token usage stats (ai_chat_message.token_usage) are preserved as-is.
  • User memories are plain text and unaffected by model swaps.

4. Using it in the Console

4.1 Open the AI Assistant page

  1. Log into the Wolf Console (http://localhost:12188/ or your deployment URL).
  2. In the left-hand nav, click AI Assistant (中文: AI 助手; 日本語: AIアシスタント).
  3. You land on /ai/chat.
AI Assistant entry and welcome screen
Left nav AI Assistant entry; welcome hints and example prompts when no session is selected

If no API key is configured, sending a message yields a friendly error asking the administrator to check the model configuration (AI_API_KEY, model name, baseUrl). Everything else in the Console continues to work.

AI not configured
Error prompt when the AI model / API key is not configured

4.2 Session management

The Sessions panel on the left:

  • New: click "New", or just send a message in an empty state (a session is auto-created with a title taken from the first 20 characters of your message).
  • Switch: click any session to load its history.
  • Rename: via the action button; or let the AI summarize the conversation into a tighter title ("✨ Auto rename").
  • Delete: soft delete (status=0), which also removes the session's messages from the visible list.

Each session is bound to the logged-in user.

Session list
Multiple sessions in the sidebar; the selected session shows chat history on the right
Auto-generate session name
Hover the magic-wand icon to auto-generate a session title from the conversation

4.3 User memory

The "💾 Memory" entry at the bottom of the sidebar opens the memory panel. Memories are grouped into 4 categories:

CategoryMeaningExample
preferenceUser preferences"Prefers tables for query results" / "Always uses Chinese"
knowledgeKnown facts about the system"OA system appID is oa-app" / "admin role has permissions X, Y, Z"
decisionPast decisions"Decided to remove user A from role R"
patternOperation patterns"Frequently queries permission config for oa-app"

How it works:

  1. Automatic extraction: Every time you create a new session, the server asynchronously analyzes the previous session, calls the LLM to extract 0..N new memory entries, and marks outdated ones as deprecated.
  2. Manual editing: The panel lets you add / edit / delete memories directly.
  3. Injection: The next time the Agent starts, all status=1 memories are folded into the System Prompt, grouped by category.

Memory is strictly per-user; nothing is shared across users.

Memory panel with entries
Memory panel: entries grouped by category, with auto-extracted and manual sources
Empty memory panel
Empty state: "No memories yet. Start chatting and the AI will learn automatically."
Add a memory manually
Manually add a memory: pick a category and enter content

5. Tool catalog

Below are all 31 tools. Tools marked [super] are only exposed to super usersadmin users will not see them and the LLM cannot invoke them.

Application (6)

ToolPurposeNotes
list_applicationsList appsSupports key / page / limit
get_applicationApp detail
create_application [super]Create an appUnique id, optional OAuth2 secret
update_application [super]Update an appName / description
delete_application [super]Delete an appDestructive — wipes all RBAC data under the app
get_rbac_diagramRBAC relationship graph dataRenders well with Mermaid
RBAC relationship diagram
Example: user–role–permission relationship diagram for an application
RBAC auth flowchart
Example: RBAC authorization flow rendered as a Mermaid flowchart
Markdown table reply
Example: query results rendered as a Markdown table

User (5)

ToolPurposeNotes
list_usersList usersadmin users only see users under apps they manage
create_user [super]Create a userPassword can be auto-generated
update_user [super]Update a userIncludes the manager field to promote/demote
delete_user [super]Delete a userDestructive
reset_user_password [super]Reset passwordReturns the new random password

Role (4) / Permission (4) / Resource (4) / Category (4)

Each provides list_xxx / create_xxx / update_xxx / delete_xxx, with parameters mirroring the same forms in the Console. See server/src/ai/tools/*.js for exact schemas.

UserRole (3)

ToolPurposeNotes
get_user_rolesRoles + direct permissions a user has in an app
set_user_rolesSet roles / permissions for a user in an appOverwrites; passing an empty array clears
delete_user_rolesRemove the user's entire link to that app

AccessLog (1)

ToolPurposeNotes
query_access_logsQuery audit logPass appID="ai-agent" to see only AI-driven actions

6. Auditing AI activity

When the AI calls a Controller via InternalCaller, an access_log entry is recorded. Key fields:

FieldAI actionManual action
appID'ai-agent'Real app ID (e.g. wolf-console)
userID / usernameThe logged-in userSame
actionHTTP methodSame
resNameInternal path (e.g. /wolf/role)URL path
bodyTool argumentsRequest body

To see everything the AI has done: in the "Access Log" page choose Application = ai-agent, or simply ask the AI: "List all ai-agent actions in the last day."

Query AI access logs in chat
Ask the assistant to query appID=ai-agent access logs; tool calls and results appear inline

7. Authorization model

AspectBehaviour
Login required✅ Enforced by the token-check middleware
Who can use itAny user who can log into the Console (super / admin / regular)
What tools are exposedDetermined by the logged-in user's manager field. admin users never see super-only tools; the LLM cannot try to call them
Can the AI escalate privileges❌ No. super-only tools are filtered out at getAllTools() time
Can the AI bypass Controller checks❌ No. Every call passes through InternalCallerController.access()
Cross-user visibility❌ None. ai_chat_session.userID / ai_user_memory.userID enforce strict isolation

8. SSE event protocol (integration reference)

POST /wolf/ai-chat/chat returns Content-Type: text/event-stream. Each event is data: {json}\n\n.

Event types:

typeEmitted whenKey fields
session_createdA new session is auto-createdsessionId
agent_startThe Agent starts processing this user turn
message_startA new assistant / user / toolResult message starts streamingmessage
message_updateStreaming token incrementmessage, event
message_endA single message finishes streamingmessage
doneThe full Agent turn finishestokenUsage (input / output / cost)
errorAnything failserror (human-readable string)

The reference frontend implementation lives in console/src/api/ai-chat.ts (function chatStream, an AsyncGenerator over native fetch + ReadableStream).

9. HTTP API summary

All AI endpoints live under service = ai-chat (controller server/src/controllers/ai-chat.js):

MethodPathPurpose
POST/wolf/ai-chat/chatSSE streaming conversation (core endpoint)
GET/wolf/ai-chat/sessionsCurrent user's sessions
POST/wolf/ai-chat/createSessionCreate a session (and trigger memory extraction)
DELETE/wolf/ai-chat/deleteSessionSoft-delete a session
PUT/wolf/ai-chat/renameSessionRename a session
GET/wolf/ai-chat/messagesMessages of a session
POST/wolf/ai-chat/autoRenameSessionLet the AI summarize a session title
GET/wolf/ai-chat/memoriesCurrent user's memories
POST/wolf/ai-chat/memoryAdd a memory
PUT/wolf/ai-chat/memoryEdit a memory
DELETE/wolf/ai-chat/memoryDelete a memory

All requests require the standard Console x-rbac-token. Response shape is the regular Wolf envelope: { ok, reason?, errmsg?, data? }.

10. FAQ

Q1. Opening the AI page returns 503 / AI_NOT_CONFIGURED?

A: The server cannot find an API key, or the model call failed. Sending a message shows: "AI returned no content. Please ask an administrator to check the model configuration (model name, API key, baseUrl)." Check that:

  • AI_API_KEY is set and matches the configured AI_PROVIDER; OR
  • A provider-specific env var is set (OPENAI_API_KEY, ANTHROPIC_API_KEY, …).
  • Restart server after exporting the variable.

Q2. The AI just spins and never replies?

A: Common causes:

  • baseUrl is wrong (unreachable gateway).
  • model is not recognized by your provider (when using OpenAI-compatible gateways, pi-ai builds a fallback model object, but the gateway still has to accept the model name).
  • Your API key is not authorized for that model on the gateway.
  • Check the server logs (log4js); search for [AgentFactory] and [ai-chat].

Q3. The AI reply contains <think>...</think> text?

A: Some models (DeepSeek-R1, Qwen-thinking, …) emit explicit reasoning blocks. The server's sanitize-message.js strips them before forwarding to the frontend. If you still see them, the model output format may have changed — please file an issue.

Q4. How do I run the assistant in "read-only" mode?

A: Tools are filtered by the user's manager field. For read-only behaviour, temporarily set the user's manager field to null (regular user) — they can still query but cannot invoke write tools.

Q5. Results get truncated when they are too long?

A: maxHistoryMessages = 100 by default; older messages are pruned while keeping related context coherent. For very large single responses, ask the AI to narrow the query via key / page / limit.

Q6. Can concurrent users leak data into each other's sessions?

A: No. ai_chat_session.userID / ai_user_memory.userID enforce isolation. SSE streams are per-request; Agent instances are created per turn and discarded — there is no shared global state.

Q7. Can I swap models without losing history?

A: Yes. Messages and memories are plain text, provider-agnostic. Just change the env vars and restart.

Q8. How do I tell AI actions apart from Console actions in the audit log?

A: Look at the appID column. AI activity is always ai-agent. Manual Console activity uses the real target app ID (the Console itself is wolf-console, business apps use their own IDs).


Back to TOC