npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@adminforth/agent

v2.7.5

Published

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

Readme

AdminForth Agent Plugin

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 safe API-based tools, 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 AdminForth's own API layer, so your access rules 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.
  • 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, builds the system prompt (including the list of your resources and available skills), streams the model's output back over SSE, and persists the prompt/response to your turn resource. Tools are executed through AdminForth's API endpoints; conversation memory is kept per session (thread_id = sessionId).

Requirements

Installation

npm install @adminforth/agent @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.

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.

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: 'turns', type: AdminForthDataTypes.INTEGER },
    { name: 'asker_id', type: AdminForthDataTypes.STRING },
    { name: 'created_at', type: AdminForthDataTypes.DATETIME, fillOnCreate: () => new Date().toISOString() },
  ],
};

export default sessionsResource;
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: add a `debug` TEXT column and map it via turnResource.debugField
    // to store per-turn debug traces.
  ],
};

export default turnsResource;

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 },
  ],
};

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',
      turnsField: 'turns',
      askerIdField: 'asker_id',
      createdAtField: 'created_at',
    },
    turnResource: {
      resourceId: 'turns',
      idField: 'id',
      sessionIdField: 'session_id',
      createdAtField: 'created_at',
      promptField: 'prompt',
      responseField: 'response',
    },

    // 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

| Option | Type | Required | Description | | --- | --- | --- | --- | | modes | { name: string; completionAdapter }[] | ✅ | Selectable models. The first entry is the default mode. Each mode has its own completion adapter. | | sessionResource | ISessionResource | ✅ | Field mapping for the sessions resource (see below). | | turnResource | ITurnResource | ✅ | Field mapping for the turns resource. | | maxTokens | number | — | Max generation tokens per model call. Default 1000. | | systemPrompt | string | — | 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. | | stickByDefault | boolean | — | Whether the chat panel is docked (sticky) by default. Default false. | | checkpointResource | ICheckpointResource | — | Field mapping enabling the persistent LangGraph checkpointer. Falls back to in-memory MemorySaver when omitted. | | audioAdapter | AudioAdapter | — | Enables voice input/output (speech-to-text and text-to-speech). | | chatSurfaceAdapters | ChatSurfaceAdapter[] | — | External chat surfaces (e.g. Telegram) served via webhooks. | | chatExternalIdentityResource | object | — | Maps external chat identities (provider + external user id) to admin users. Required for chat surfaces. |

sessionResource fields

resourceId, idField, titleField, turnsField, askerIdField, createdAtField.

turnResource fields

resourceId, idField, sessionIdField, createdAtField, promptField, responseField, and optional debugField (when set, per-turn debug traces are written to it).

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

Tools & skills

The agent works through API-based tools generated from your AdminForth resources (reading records, inspecting schema, and — through skills — creating/updating/deleting records and running actions). Tools run via AdminForth's own API layer, so per-resource permissions and validation are enforced.

To keep the model focused, tools are disclosed progressively:

  • get_resource is always available (to inspect resource structure).
  • The agent reads a skill (a SKILL.md file) to learn which tools a task needs, then loads those tool schemas on demand.

Built-in skills cover fetching data, analytics/charts, and mutating data. You can add your own skills by placing a SKILL.md (with name and description frontmatter) in a skills/<skill-name>/ directory under your custom components dir; plugin-provided skill directories are also discovered.

Human-in-the-loop approvals

Tools whose definition marks them dangerous (agent.isDangerous === true) 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). Approval state is currently held per process instance.

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 & path | Purpose | | --- | --- | | POST /agent/response | Send a message; streams the answer over SSE. | | POST /agent/approval | Approve/reject a pending human-in-the-loop tool call. | | POST /agent/speech-response | Multipart audio upload; streams transcript + answer (+ audio). | | POST /agent/get-placeholder-messages | Placeholder prompts for the chat textarea. | | POST /agent/get-sessions | List chat sessions. | | POST /agent/get-session-info | Fetch a session's turns. | | POST /agent/create-session | Create a new session. | | POST /agent/delete-session | Delete a session and its turns. | | POST /agent/add-system-message-to-turns | Append a system message turn. | | POST /agent/surface/<name>/webhook | Inbound webhook for an external chat surface. |

The /agent/response and /agent/approval streams use the Vercel AI UI message stream format (x-vercel-ai-ui-message-stream: v1); the frontend consumes them directly.

Contributing / tests

This package is developed inside the AdminForth monorepo. Unit and characterization tests for the plugin live in tests/jest_tests/ (adminforth_agent_*.test.ts) and run with:

cd tests/jest_tests
pnpm install
pnpm test

About AdminForth

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

Related links

License

MIT