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

@kandiforge/kandi-agentic-forms

v0.1.1

Published

AI-powered conversational form filling — XML spec in, structured output files out

Readme

kandi-agentic-forms

AI-powered conversational form filling for React. An agent guides users toward a predefined end state via chat + MCP tools — producing structured output files when complete.

React Client (FormProvider + KandiAgenticFormContainer)
    │ SSE Stream + REST API
    ▼
Node.js Server SDK (@kandiforge/kandi-agentic-forms/server)
    │ createFormServer({ adapterConfig, sessionStore, verifyToken })
    ▼
Agent Adapter (Vercel AI SDK / Forge)
    │ streamText + tool calling + MCP servers
    ▼
LLM Provider (OpenAI / Anthropic)

Features

  • XML form specs — declarative <agentic-form> format defines what to collect, agent behavior, and output files
  • Agent adapter abstraction — swap between Vercel AI SDK and custom adapters
  • MCP server scoping — each form spec declares which MCP servers the agent can use
  • Structured tool calling — agent uses update_field, confirm_field, complete_form tools (not free-text parsing)
  • SSE streaming — real-time agent responses via Server-Sent Events
  • MUI container component — glassmorphism chat drawer + artifact timeline, ready to use
  • Headless components — render-prop pattern for custom UIs
  • Framework-agnostic server — mount on Express, Next.js, Vercel, Fastify, etc.
  • kandi-login auth — reuses existing JWT tokens (optional)

Install

npm install @kandiforge/kandi-agentic-forms

Peer Dependencies

Required:

npm install react react-dom

Server (pick your LLM provider):

npm install ai @ai-sdk/openai    # OpenAI
npm install ai @ai-sdk/anthropic  # Anthropic

MUI components (optional):

npm install @mui/material @emotion/react @emotion/styled

Auth (optional):

npm install @kandiforge/kandi-login

Quick Start

1. Define a Form Spec (XML)

<agentic-form name="project-setup" version="1.0">
  <agent>
    <tone>professional-friendly</tone>
    <system-prompt>
      You are a project setup assistant. Help the user configure
      their new project by collecting the required information.
    </system-prompt>
    <greeting>Hi! Let's set up your new project. What would you like to name it?</greeting>
    <error-recovery strategy="retry-with-hint" max-retries="3" />
    <capabilities>
      <allow-skip-optional>true</allow-skip-optional>
      <allow-go-back>true</allow-go-back>
    </capabilities>
  </agent>

  <sections>
    <section id="basics" label="Project Basics" order="1">
      <field id="name" type="text" required="true">
        <label>Project Name</label>
        <prompt>What would you like to name your project?</prompt>
        <validation>
          <pattern regex="^[a-z][a-z0-9-]*$" message="Must be lowercase with hyphens only" />
          <min-length>3</min-length>
          <max-length>50</max-length>
        </validation>
      </field>

      <field id="framework" type="select" required="true">
        <label>Framework</label>
        <options>
          <option value="nextjs">Next.js</option>
          <option value="remix">Remix</option>
          <option value="astro">Astro</option>
          <option value="vite">Vite + React</option>
        </options>
      </field>

      <field id="description" type="textarea" required="false">
        <label>Description</label>
        <hint>A brief description of your project (optional)</hint>
      </field>
    </section>

    <section id="deployment" label="Deployment" order="2">
      <field id="provider" type="select" required="true">
        <label>Deploy Target</label>
        <options>
          <option value="vercel">Vercel</option>
          <option value="aws">AWS</option>
          <option value="self-hosted">Self-hosted</option>
        </options>
      </field>

      <field id="domain" type="text" required="false">
        <label>Custom Domain</label>
        <condition>
          <when field="deployment.provider" not-equals="self-hosted" />
        </condition>
      </field>
    </section>
  </sections>

  <output>
    <manifest filename="manifest.json" />
    <raw-data filename="project-config.json" />
    <session-log filename="setup-log.json" />
  </output>
</agentic-form>

2. Server — Create Form Server

import { createFormServer } from '@kandiforge/kandi-agentic-forms/server';

const forms = createFormServer({
  adapterConfig: {
    provider: 'anthropic',
    apiKey: process.env.ANTHROPIC_API_KEY!,
    model: 'claude-sonnet-4-20250514',
    maxSteps: 10,
  },
  sessionStore: mySessionStore, // implement SessionStoreAdapter
  verifyToken: async (token) => {
    // validate JWT from kandi-login, or your own auth
    return { sub: 'user-123' };
  },
});

3. Server — Mount Routes

Next.js App Router:

// app/api/forms/sessions/route.ts
import { forms } from '@/lib/form-server';

export async function POST(req: Request) {
  const body = await req.json();
  const res = createFormResponse();
  await forms.handleCreateSession(
    { method: 'POST', query: {}, headers: Object.fromEntries(req.headers), body },
    res,
  );
  return res.toNextResponse();
}

Express:

app.post('/forms/sessions', forms.handleCreateSession);
app.get('/forms/sessions/stream', forms.handleStream);
app.post('/forms/sessions/message', forms.handleSendMessage);
app.get('/forms/sessions', forms.handleGetSession);
app.post('/forms/sessions/complete', forms.handleComplete);
app.delete('/forms/sessions', forms.handleDeleteSession);
app.get('/forms/sessions/files', forms.handleGetFiles);
app.get('/forms/sessions/files/download', forms.handleDownloadFile);
app.post('/forms/specs/validate', forms.handleValidateSpec);

4. Client — MUI Container (Recommended)

import { FormProvider } from '@kandiforge/kandi-agentic-forms/react';
import { KandiAgenticFormContainer } from '@kandiforge/kandi-agentic-forms/react/mui';
import { useAuth } from '@kandiforge/kandi-login/react';

function App() {
  const { getToken } = useAuth();

  return (
    <FormProvider
      config={{
        formServerUrl: '/api/forms',
        getToken,
      }}
      onSessionComplete={(files) => console.log('Done!', files)}
    >
      <KandiAgenticFormContainer
        height="600px"
        drawerWidth={380}
        onStop={() => console.log('Agent interrupted')}
      />
    </FormProvider>
  );
}

5. Client — Start a Session

import { useAgenticForm } from '@kandiforge/kandi-agentic-forms/react';

function StartButton({ specXml }: { specXml: string }) {
  const { startSession, isLoading } = useAgenticForm();

  return (
    <button onClick={() => startSession(specXml)} disabled={isLoading}>
      Start Form
    </button>
  );
}

6. Client — Headless (Custom UI)

import { HeadlessFormChat } from '@kandiforge/kandi-agentic-forms/react/headless';

<HeadlessFormChat>
  {({ messages, sendMessage, progress, isConnected, spec }) => (
    <div>
      <progress value={progress} max={1} />
      {messages.map(msg => (
        <div key={msg.id} className={msg.role}>
          {msg.content}
        </div>
      ))}
      <input onKeyDown={e => {
        if (e.key === 'Enter') sendMessage(e.currentTarget.value);
      }} />
    </div>
  )}
</HeadlessFormChat>

Entry Points

| Import Path | Purpose | |---|---| | kandi-agentic-forms | Core + React exports | | @kandiforge/kandi-agentic-forms/core | Types, spec parser, validator, FormSession | | @kandiforge/kandi-agentic-forms/react | FormProvider, useAgenticForm, useFormStream | | @kandiforge/kandi-agentic-forms/react/headless | HeadlessFormChat (render-prop, zero styling) | | @kandiforge/kandi-agentic-forms/react/mui | KandiAgenticFormContainer + styled components | | @kandiforge/kandi-agentic-forms/server | createFormServer, VercelAdapter, SessionManager |

SessionStoreAdapter

Implement this interface to connect the form server to your database:

interface SessionStoreAdapter {
  createSession(userId: string, spec: AgenticFormSpec): Promise<string>;
  getSession(sessionId: string): Promise<AgenticFormSession | null>;
  getSpec(sessionId: string): Promise<AgenticFormSpec | null>;
  updateSession(sessionId: string, patch: Partial<AgenticFormSession>): Promise<void>;
  deleteSession(sessionId: string): Promise<void>;
  listUserSessions(userId: string): Promise<AgenticFormSession[]>;
  storeOutputFiles?(sessionId: string, manifest: AgenticFormManifest, files: Map<string, Buffer>): Promise<void>;
  getOutputFile?(sessionId: string, fileId: string): Promise<{ data: Buffer; filename: string; mimeType: string } | null>;
}

Server Handlers

| Handler | Method | Description | |---|---|---| | handleCreateSession | POST | Create session from XML spec | | handleStream | GET | SSE stream for session events | | handleSendMessage | POST | Send user message to agent | | handleGetSession | GET | Get session state | | handleComplete | POST | Trigger output generation | | handleDeleteSession | DELETE | Cancel/delete session | | handleGetFiles | GET | List output files | | handleDownloadFile | GET | Download an output file | | handleValidateSpec | POST | Validate XML spec |

Form Tools

The agent automatically has access to these tools during a session:

| Tool | Description | |---|---| | update_field | Set a field value with validation | | confirm_field | Mark field as user-confirmed | | get_progress | Return completion status per section | | skip_field | Skip an optional field | | request_file_upload | Signal client for file upload UI | | complete_form | Finalize the session |

XML Spec Reference

Root Element

<agentic-form name="form-name" version="1.0">

Agent Configuration

<agent>
  <tone>professional-friendly</tone>
  <system-prompt>Custom instructions for the agent</system-prompt>
  <greeting>Opening message to the user</greeting>
  <completion-message>Thanks, {{fields.basics.name}}!</completion-message>
  <error-recovery strategy="retry-with-hint" max-retries="3" />
  <confirmations>
    <confirm before="submit">Please confirm all details are correct.</confirm>
  </confirmations>
  <capabilities>
    <allow-skip-optional>true</allow-skip-optional>
    <allow-go-back>true</allow-go-back>
    <allow-save-progress>false</allow-save-progress>
  </capabilities>
</agent>

Field Types

text · textarea · number · date · datetime · select · multi-select · checkbox · file · signature · repeatable

Conditional Fields

<field id="domain" type="text" required="false">
  <label>Custom Domain</label>
  <condition>
    <when field="deployment.provider" not-equals="self-hosted" />
  </condition>
</field>

MCP Servers (per-form)

<mcp-servers>
  <mcp-server id="validator" transport="stdio">
    <name>Config Validator</name>
    <endpoint>npx</endpoint>
    <args><arg>my-validator</arg></args>
    <allowed-tools>
      <tool>validate_config</tool>
      <tool>check_dependencies</tool>
    </allowed-tools>
  </mcp-server>
</mcp-servers>

Output Files

<output>
  <manifest filename="manifest.json" />
  <raw-data filename="form-data.json" />
  <session-log filename="session-log.json" />
  <rendered-file id="summary" format="html">
    <template ref="templates/summary.hbs" />
    <filename>{{fields.basics.name}}-summary.html</filename>
  </rendered-file>
</output>

Output Files (kandi-agentic-form-files)

When a session completes, these files are generated:

  • manifest.json — file list with SHA-256 hashes, session metadata, form spec hash
  • form-data.json — collected values organized by section
  • session-log.json — timestamped event log (field_collected, field_skipped, confirmations)
  • Rendered files — from templates (PDF, CSV, HTML) referenced in the spec

MUI Container Components

Import from @kandiforge/kandi-agentic-forms/react/mui:

| Component | Description | |---|---| | KandiAgenticFormContainer | Main container — artifact timeline + collapsible chat drawer | | ChatPanel | Glassmorphism chat drawer with auto-scroll + connection indicator | | ChatInput | Text input with send + stop (interrupt) buttons | | MessageBubble | Role-based chat message styling | | ArtifactTimeline | Scrollable timeline of artifacts produced by the agent | | ArtifactCard | Expandable card for files, milestones, field updates | | ProgressBar | Section-aware progress with color transitions | | FieldStatusChip | Status badge (pending/collected/confirmed/error) | | useArtifacts | Hook that derives artifact timeline from session state |

Environment Variables

# LLM Provider (server-side only — never expose to client)
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...

# JWT (if using kandi-login)
JWT_SECRET=your-secret-min-32-chars

License

MIT — KandiForge