@adminforth/agent

中文文档
3.5.2发布于 2026/11/03MITTypeScriptES Module近 30 天下载 3192

AI agent plugin for AdminForth with tool-based workflows and persistent chat sessions

原始使用文档
文档目录23 节
  1. Features
  2. How it works
  3. Architecture
  4. One turn, end to end
  5. Progressive tool & skill disclosure
  6. Requirements
  7. Installation
  8. Setup
  9. 1. Create the storage resources
  10. 2. Configure the plugin
  11. 3. Register in your AdminForth config
  12. Configuration reference
  13. sessionResource fields
  14. turnResource fields
  15. Tools & skills
  16. Human-in-the-loop approvals
  17. Voice
  18. External chat surfaces (e.g. Telegram)
  19. HTTP endpoints
  20. Contributing / tests
  21. About AdminForth
  22. Related links
  23. License

AdminForth Agent Plugin

License: MIT Build Status npm downloads npm version

Ask AI

Adds a native, tool-calling AI agent to your AdminForth application. The agent lives in a chat panel inside the admin UI, can inspect and mutate your resources through the tools of the AdminForth MCP server, streams its answers token-by-token, and keeps persistent chat sessions.

Full tutorial: AdminForth Agent Documentation

Features

  • Chat agent in the admin UI — a streaming chat surface injected into every page.
  • Tool calling over your resources — the agent reads and (optionally) mutates records through the @adminforth/mcp plugin, which runs AdminForth's own API handlers as the user, so your access rules, hooks and validation still apply.
  • Progressive tool & skill disclosure — the agent loads only the tools it needs, guided by Markdown skills you can extend.
  • Human-in-the-loop approvals — tools you mark as dangerous pause for explicit approve/reject from the user before running.
  • Mid-turn steering — send another instruction while the agent is still working; it is folded into the running turn before its next model call instead of waiting in line.
  • Message editing & branching — edit an earlier message to fork the conversation from that turn's checkpoint: later turns are dropped and the answer is regenerated.
  • Multiple modes — expose several models (e.g. Fast, Balanced, Smart Thinking) and let users switch between them.
  • Persistent sessions — conversations are stored in your database; an optional checkpointer persists full LangGraph state across turns.
  • Voice in and out — optional speech-to-text and text-to-speech via an audio adapter.
  • External chat surfaces — optionally serve the same agent through webhooks (e.g. Telegram) with OAuth identity mapping.

Built on LangChain / LangGraph.

How it works

For each user message the plugin creates a turn, opens an in-process connection to the @adminforth/mcp server as the user, builds the system prompt (the MCP server instructions with its skills, followed by the agent's own rules), streams the model's output back over SSE, and persists the prompt/response to your turn resource. Every tool call is an MCP tools/call on that connection; conversation memory is kept per session (thread_id = sessionId).

Architecture

The plugin is layered so that the provider-specific parts (LangChain/LangGraph, the completion adapter, the checkpointer) sit behind ports and never leak into the turn logic:

LayerDirectoryDepends on
Domain — prompt building, event vocabulary, buffersdomain/adminforth types only
Application — the turn use case + portsapplication/domain
LLM runtime — LangChain/LangGraph behind LlmPortllm/application, domain, tools
Tools — MCP connection, progressive disclosuretools/@adminforth/mcp
Persistence — sessions, turns, checkpointspersistence/AdminForth resources
Transport — HTTP endpoints, SSE, external surfacestransport/application
Frontend — Vue 3 + Pinia chat surfacecustom/HTTP + SSE contract
flowchart TB
    UI["Admin UI - custom/<br/>Vue 3 + Pinia chat surface"]
    TR["transport/<br/>HTTP endpoints, SSE, external surfaces"]
    APP["application/<br/>RunTurnUseCase + LlmPort"]
    DOM["domain/<br/>prompt building, steer buffer,<br/>events, language detection"]
    LLMS["llm/<br/>LangGraph agent, middleware chain, models"]
    TLS["tools/<br/>MCP connection,<br/>progressive disclosure"]
    PRS["persistence/<br/>sessions, turns, checkpoints"]

    MCPS(["@adminforth/mcp<br/>tools, skills, 2FA confirmation"])
    AF[("AdminForth core<br/>resources, API layer, auth")]
    MODEL(["Completion adapter<br/>OpenAI / Anthropic / Gemini"])
    ADPT(["Audio and chat surface adapters<br/>STT / TTS, Telegram"])

    UI <-->|"POST + SSE"| TR
    TR <--> ADPT
    TR --> APP
    TR -->|"session CRUD"| PRS
    APP --> DOM
    APP --> PRS
    APP -->|"LlmPort"| LLMS
    LLMS --> MODEL
    LLMS --> TLS
    LLMS -->|"checkpointer"| PRS
    TLS -->|"in-process MCP"| MCPS
    MCPS --> AF
    PRS --> AF

Every arrow into AdminForth core goes through its ordinary resource/API layer, so your access rules, hooks and validation apply to the agent exactly as they do to a human admin. The agent has exactly the permissions of the user it runs for: the MCP readOnly option applies to MCP clients only.

One turn, end to end

sequenceDiagram
    autonumber
    actor U as User
    participant UI as Chat UI (useAgentChat)
    participant EP as POST /agent/response
    participant UC as RunTurnUseCase
    participant DB as sessions and turns
    participant LLM as LangGraphLlm + AgentRuntime
    participant M as Model (completion adapter)
    participant T as MCP tool (@adminforth/mcp)

    U->>UI: type a message
    UI->>EP: message, sessionId, mode, timeZone, currentPage
    EP->>UC: handleTurn
    UC->>DB: assert session ownership
    UC->>DB: create turn, response = not_finished
    UC-->>UI: data-turn-persisted with turnId
    UC->>M: detect user language (small side call)
    UC->>LLM: streamTurn with system prompt, messages, context

    loop agent loop, recursionLimit 100
        LLM->>LLM: steer middleware drains SteerBuffer
        LLM->>M: model call with currently enabled tools
        M-->>LLM: reasoning and text deltas
        LLM-->>UI: reasoning-delta and text-delta frames
        M-->>LLM: tool call
        alt tool has destructiveHint (agent.requiresHumanApproval)
            LLM-->>UI: data-interrupt, generation pauses
            U->>UI: approve or reject
            UI->>EP: POST /agent/approval
            EP->>UC: resume the interrupted graph
        else safe tool
            LLM->>T: tools/call on the in-process MCP connection
            T-->>LLM: YAML result
            LLM-->>UI: data-tool-call start and end
        end
    end

    LLM-->>UC: stream ends
    UC->>LLM: getLatestCheckpointId, the fork point for edits
    UC->>DB: save response, debug trace, checkpointId
    UC-->>UI: data-response then finish

Two side channels run on top of that flow:

  • Steering — POST /agent/steer buffers a message in the in-process SteerBuffer; the beforeModel steer middleware folds it in as a user message before the next model call and emits data-steer-applied on the turn's already-open stream.
  • Editing / branching — POST /agent/edit forks from the previous turn's stored checkpoint id, truncates the later turns, and regenerates. Requires both checkpointResource and turnResource.checkpointIdField.

Progressive tool & skill disclosure

flowchart LR
    A["Turn starts"] --> B["Exposed tools: MCP get_resources_list,<br/>get_resource, fetch_skill, wait_for_confirmation,<br/>and get_user_location, navigate_user, fetch_tool_schema"]
    B --> C{"Needs more than<br/>reading schema?"}
    C -- no --> D["Answer with the base tools"]
    C -- yes --> E["MCP fetch_skill returns<br/>the matching skill"]
    E --> F["fetch_tool_schema loads one<br/>MCP tool by name"]
    F --> G["McpToolsMiddleware sees the<br/>status 200 tool message and adds that<br/>tool to the next model call"]
    G --> H{"destructiveHint?"}
    H -- yes --> I["humanInTheLoopMiddleware interrupt,<br/>approve or reject in the UI"]
    H -- no --> J["tools/call on the MCP server"]
    I -- approved --> J

Requirements

Installation

pnpm add @adminforth/agent @adminforth/mcp @adminforth/completion-adapter-openai-responses

Setup

Setup has three parts: (1) create the storage resources, (2) configure the plugin, and (3) register both in your AdminForth config. Add the MCP plugin to the same globalPlugins. If only the agent uses it, new AdminForthMcpPlugin({ internalOnly: true }) needs no auth secret table and no adminPanelOrigin; to connect other MCP clients too, set it up as its documentation describes.

1. Create the storage resources

The plugin does not create tables for you — you expose ordinary AdminForth resources and tell the plugin which fields to use. The field names are up to you; the mapping in the plugin options connects them.

Sessions resource (required)
import { AdminForthDataTypes, type AdminForthResourceInput } from 'adminforth';
import { randomUUID } from 'crypto';

const sessionsResource: AdminForthResourceInput = {
  dataSource: 'maindb',
  table: 'sessions',
  resourceId: 'sessions',
  label: 'Sessions',
  columns: [
    { name: 'id', primaryKey: true, type: AdminForthDataTypes.STRING, fillOnCreate: () => randomUUID() },
    { name: 'title', type: AdminForthDataTypes.STRING },
    { name: 'asker_id', type: AdminForthDataTypes.STRING },
    { name: 'created_at', type: AdminForthDataTypes.DATETIME, fillOnCreate: () => new Date().toISOString() },
  ],
  // Agent-internal data: closed to admin users and MCP clients, the agent works with it directly.
  options: {
    allowedActions: { list: false, show: false, create: false, edit: false, delete: false },
  },
};

export default sessionsResource;
Turns resource (required)
import { AdminForthDataTypes, type AdminForthResourceInput } from 'adminforth';
import { randomUUID } from 'crypto';

const turnsResource: AdminForthResourceInput = {
  dataSource: 'maindb',
  table: 'turns',
  resourceId: 'turns',
  label: 'Turns',
  columns: [
    { name: 'id', primaryKey: true, type: AdminForthDataTypes.STRING, fillOnCreate: () => randomUUID() },
    { name: 'session_id', type: AdminForthDataTypes.STRING },
    { name: 'created_at', type: AdminForthDataTypes.DATETIME, fillOnCreate: () => new Date().toISOString() },
    { name: 'prompt', type: AdminForthDataTypes.TEXT },
    { name: 'response', type: AdminForthDataTypes.TEXT },
    // Optional: map via turnResource.checkpointIdField. Stores each turn's tip
    // checkpoint id — required for message editing / branching.
    { name: 'checkpoint_id', type: AdminForthDataTypes.STRING },
    // Optional: add a `debug` TEXT column and map it via turnResource.debugField
    // to store per-turn debug traces.
  ],
  // Agent-internal data: closed to admin users and MCP clients, the agent works with it directly.
  options: {
    allowedActions: { list: false, show: false, create: false, edit: false, delete: false },
  },
};

export default turnsResource;
Checkpoints resource (optional — enables persistent memory)

Without this resource the agent uses an in-memory checkpointer (MemorySaver), which is lost on restart and not shared across instances. For production, add a checkpoint resource. Rows accumulate over time, so pairing it with an auto-cleanup plugin is recommended.

import { AdminForthDataTypes, type AdminForthResourceInput } from 'adminforth';

const checkpointsResource: AdminForthResourceInput = {
  dataSource: 'maindb',
  table: 'agent_checkpoints',
  resourceId: 'agent_checkpoints',
  label: 'Agent Checkpoints',
  columns: [
    { name: 'id', primaryKey: true, type: AdminForthDataTypes.STRING },
    { name: 'thread_id', type: AdminForthDataTypes.STRING },
    { name: 'checkpoint_namespace', type: AdminForthDataTypes.STRING },
    { name: 'checkpoint_id', type: AdminForthDataTypes.STRING },
    { name: 'parent_checkpoint_id', type: AdminForthDataTypes.STRING },
    { name: 'row_kind', type: AdminForthDataTypes.STRING },
    { name: 'task_id', type: AdminForthDataTypes.STRING },
    { name: 'sequence', type: AdminForthDataTypes.INTEGER },
    { name: 'created_at', type: AdminForthDataTypes.DATETIME },
    { name: 'checkpoint_payload', type: AdminForthDataTypes.TEXT },
    { name: 'metadata_payload', type: AdminForthDataTypes.TEXT },
    { name: 'writes_payload', type: AdminForthDataTypes.TEXT },
    { name: 'schema_version', type: AdminForthDataTypes.INTEGER },
  ],
  // Agent-internal data: closed to admin users and MCP clients, the agent works with it directly.
  options: {
    allowedActions: { list: false, show: false, create: false, edit: false, delete: false },
  },
};

export default checkpointsResource;

2. Configure the plugin

// globalPlugins.ts
import AdminForthAgent from '@adminforth/agent';
import CompletionAdapterOpenAIResponses from '@adminforth/completion-adapter-openai-responses';

// Reasoning effort is configured on the completion adapter, not on the plugin.
const createCompletionAdapter = (model: string, effort: 'low' | 'medium' | 'high') =>
  new CompletionAdapterOpenAIResponses({
    openAiApiKey: process.env.OPENAI_API_KEY as string,
    model,
    extraRequestBodyParameters: { reasoning: { effort } },
  });

export const globalPlugins = [
  new AdminForthAgent({
    // The first mode is the default. Users can switch modes in the chat UI.
    modes: [
      { name: 'Balanced', completionAdapter: createCompletionAdapter('gpt-5.4-mini', 'medium') },
      { name: 'Fast', completionAdapter: createCompletionAdapter('gpt-5.4-mini', 'low') },
      { name: 'Smart Thinking', completionAdapter: createCompletionAdapter('gpt-5.4', 'high') },
    ],
    maxTokens: 10000,

    sessionResource: {
      resourceId: 'sessions',
      idField: 'id',
      titleField: 'title',
      askerIdField: 'asker_id',
      createdAtField: 'created_at',
    },
    turnResource: {
      resourceId: 'turns',
      idField: 'id',
      sessionIdField: 'session_id',
      createdAtField: 'created_at',
      promptField: 'prompt',
      responseField: 'response',
      // Enables message editing / branching (together with checkpointResource below).
      checkpointIdField: 'checkpoint_id',
    },

    // Optional but recommended in production:
    checkpointResource: {
      resourceId: 'agent_checkpoints',
      idField: 'id',
      threadIdField: 'thread_id',
      checkpointNamespaceField: 'checkpoint_namespace',
      checkpointIdField: 'checkpoint_id',
      parentCheckpointIdField: 'parent_checkpoint_id',
      rowKindField: 'row_kind',
      taskIdField: 'task_id',
      sequenceField: 'sequence',
      createdAtField: 'created_at',
      checkpointPayloadField: 'checkpoint_payload',
      metadataPayloadField: 'metadata_payload',
      writesPayloadField: 'writes_payload',
      schemaVersionField: 'schema_version',
    },
  }),
];

3. Register in your AdminForth config

import sessionsResource from './resources/agent_resources/sessions.js';
import turnsResource from './resources/agent_resources/turns.js';
import checkpointsResource from './resources/agent_resources/checkpoints.js';
import { globalPlugins } from './globalPlugins.js';

const admin = new AdminForth({
  // ...
  resources: [
    sessionsResource,
    turnsResource,
    checkpointsResource, // only if you configured checkpointResource
    // ...your other resources
  ],
  globalPlugins,
});

That's it — a chat panel now appears in the admin UI.

Configuration reference

OptionTypeRequiredDescription
modes{ name: string; completionAdapter }[]✅Selectable models. The first entry is the default mode. Each mode has its own completion adapter.
sessionResourceISessionResource✅Field mapping for the sessions resource (see below).
turnResourceITurnResource✅Field mapping for the turns resource.
maxTokensnumber—Max generation tokens per model call. Default 1000.
systemPromptstring—Extra text appended to the built-in agent system prompt.
placeholderMessages({ adminUser, headers }) => string[] | Promise<string[]>—Example prompts preloaded into the chat textarea. Resolved once when the chat UI loads.
stickByDefaultboolean—Whether the chat panel is docked (sticky) by default. Default false.
checkpointResourceICheckpointResource—Field mapping enabling the persistent LangGraph checkpointer. Falls back to in-memory MemorySaver when omitted.
audioAdapterAudioAdapter—Enables voice input/output (speech-to-text and text-to-speech).
chatSurfaceAdaptersChatSurfaceAdapter[]—External chat surfaces (e.g. Telegram) served via webhooks.
chatExternalIdentityResourceobject—Maps external chat identities (provider + external user id) to admin users. Required for chat surfaces.

sessionResource fields

resourceId, idField, titleField, askerIdField, createdAtField.

turnsField is deprecated and ignored — session turns are looked up through turnResource.sessionIdField. It still type-checks for backward compatibility and will be removed in a future major version.

turnResource fields

resourceId, idField, sessionIdField, createdAtField, promptField, responseField, plus two optional ones:

FieldEffect
debugFieldPer-turn debug traces are written to this column.
checkpointIdFieldEach successful turn's tip checkpoint id is stored, which is what message editing / branching forks from. Editing needs this and checkpointResource; without both, the chat UI hides the edit action and POST /agent/edit rejects the request.

Reasoning effort is set on the completion adapter (e.g. extraRequestBodyParameters: { reasoning: { effort } }), not on the plugin.

Tools & skills

The agent has no tools of its own for your data: it is an MCP client of the @adminforth/mcp server, connected in process for each turn as the user who sends the message. The MCP server runs AdminForth's API handlers, so per-resource permissions, hooks and validation are enforced, and it shows only the resources the user may list or show.

To keep the model focused, tools are disclosed progressively:

  • Always available: the MCP tools get_resources_list, get_resource, fetch_skill and, with two-factor authentication set up, wait_for_confirmation; and the agent's own get_user_location, navigate_user and fetch_tool_schema.
  • Every other MCP tool is named, with the first sentence of its description, in the description of fetch_tool_schema, the way MCP clients that load tool schemas on demand list them. The agent loads a tool with fetch_tool_schema before its first call, and a skill loaded with fetch_skill tells it which tools a task needs.

Skills come from the MCP server: its built-in fetch-data, analyze-data and mutate-data, plus every skills/<skill-name>/SKILL.md in your custom components dir and in other plugins. The agent's own system prompt adds the rules of this chat and the guide for Vega-Lite charts.

Datetimes in get_resource_data results come in the user's time zone, which the chat UI sends with every message.

Human-in-the-loop approvals

Tools whose endpoint sets agent.requiresHumanApproval, which the MCP server marks with destructiveHint, trigger an approval interrupt: generation pauses and the UI shows an approve/reject prompt. The client resolves it via POST /agent/approval, and the run resumes (or, on reject, the model is told the action was declined).

The prompt names the resource and columns by their labels and lists every value the tool would write; for update_record each field shows its current value next to the new one. Values of masked and backendOnly columns are never shown.

Where the pending approval lives depends on your setup: with checkpointResource configured the LangGraph checkpoint is authoritative, so a resume survives a restart and works across instances; with the in-memory fallback the state is held per process instance.

Actions that need a two-factor verification run after the user confirms them on the MCP confirmation page of the admin panel: the agent shows the link and waits with wait_for_confirmation.

Voice

Provide an audioAdapter (e.g. @adminforth/audio-adapter-openai) to enable the microphone button. Audio is transcribed to text, answered by the agent, and (optionally) synthesized back to speech and streamed to the client. Client-side voice activity detection is loaded automatically.

External chat surfaces (e.g. Telegram)

Pass chatSurfaceAdapters (e.g. @adminforth/chat-surface-adapter-telegram) to expose the agent over a webhook at POST /agent/surface/<adapter-name>/webhook. Incoming users are resolved to admin users through chatExternalIdentityResource (pairs nicely with an OAuth adapter such as @adminforth/oauth-adapter-telegram), and unauthorized accounts are rejected.

HTTP endpoints

All routes are registered under your AdminForth API base path.

Method & pathPurpose
POST /agent/responseSend a message; streams the answer over SSE.
POST /agent/editEdit a previous message: forks from its turn's checkpoint, truncates later turns, regenerates.
POST /agent/approvalApprove/reject a pending human-in-the-loop tool call.
POST /agent/steerBuffer a mid-turn instruction; folded into the running turn before the next model call.
POST /agent/speech-responseMultipart audio upload; streams transcript + answer (+ audio).
POST /agent/get-placeholder-messagesPlaceholder prompts for the chat textarea.
POST /agent/get-sessionsList chat sessions.
POST /agent/get-session-infoFetch a session's turns.
POST /agent/create-sessionCreate a new session.
POST /agent/delete-sessionDelete a session and its turns.
POST /agent/add-system-message-to-turnsAppend a system message turn.
POST /agent/append-steer-to-turnPersist a steer into the running turn's stored prompt.
POST /agent/surface/<name>/webhookInbound webhook for an external chat surface.

The /agent/response, /agent/edit and /agent/approval streams use the Vercel AI UI message stream format (x-vercel-ai-ui-message-stream: v1); the frontend consumes them directly. /agent/speech-response uses the plugin's own bare event names instead.

Contributing / tests

This package is developed inside the AdminForth monorepo. The plugin carries its own self-contained Jest suite in tests/ — run it from the plugin root:

pnpm install
pnpm test

A couple of integration-level agent tests (adminforth_agent_*.test.ts) still live in the monorepo's tests/jest_tests/ and run from that directory.

About AdminForth

AdminForth is an open-source, agent-first admin framework for building robust admin panels and back-office applications faster.

License

MIT

版本与发布记录

@adminforth/agent 共发布 238 个版本,首次发布于 2026/04/20;过去 12 个月发布了 238 个版本。

版本发布日期距今
3.5.2latest2026/11/034 天前
3.5.12026/11/034 天前
3.5.02026/10/308 天前
3.4.02026/10/309 天前
3.3.02026/10/2315 天前
3.2.02026/10/2117 天前

关于 @adminforth/agent 的常见问题

@adminforth/agent 是什么?

AI agent plugin for AdminForth with tool-based workflows and persistent chat sessions

如何安装 @adminforth/agent?

在项目目录运行 npm install @adminforth/agent,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:adminforth(^4.21.0)、@adminforth/mcp(^3.2.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@adminforth/agent 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@adminforth/agent 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@adminforth/agent 可以商用吗?

@adminforth/agent 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@adminforth/agent 的下载量有多少?

根据 npm 官方下载统计,@adminforth/agent 在 2026/10/05 – 2026/11/03 这 30 天内被下载 3,192 次,日均约 106 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@adminforth/agent 还在维护吗?

最新版本 3.5.2 发布于 2026/11/03(4 天前);至今共发布 238 个版本,其中过去 12 个月发布了 238 个;首次发布于 2026/04/20。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。