#!/usr/bin/env python3
"""
LangChain Form Generator Agent
===============================
This example shows a LangChain agent that generates AgentForms dynamically
from natural-language prompts — e.g. "Build me a job application form for
a restaurant" or "Create a checkout form for event tickets."
Pattern:
1. Human provides a prompt describing the desired form.
2. The LangChain LLM parses the prompt and defines the fields.
3. The agent calls the AgentForms SDK to create the form.
4. A shareable URL is returned to the human.
5. The agent optionally polls for submissions and summarises results.
Prerequisites:
pip install langchain langchain-openai agentforms requests
# Configure your LLM provider (e.g. OPENAI_API_KEY)
# Configure AgentForms:
# export AGENTFORMS_API_KEY='***'
"""
import os
import sys
import time
from typing import Optional
# ---------------------------------------------------------------------------
# AgentForms integration
# ---------------------------------------------------------------------------
try:
from agentforms import AgentForms, FieldDefinition
except ImportError:
print("ERROR: agentforms SDK not installed. Run: pip install agentforms")
sys.exit(1)
# ---------------------------------------------------------------------------
# LangChain tool definition
# ---------------------------------------------------------------------------
try:
from langchain.tools import tool
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
LANGCHAIN_AVAILABLE = True
except ImportError:
LANGCHAIN_AVAILABLE = False
# Fallback stubs so the file is readable even without langchain installed.
class _FakeTool:
def __init__(self, name, description, **kw):
self.name = name
self.description = description
def __call__(self, *a, **k):
return None
tool = _FakeTool
# ---------------------------------------------------------------------------
# AgentForms tool for LangChain
# ---------------------------------------------------------------------------
@tool
def create_agentform(
name: str,
fields: list,
metadata: Optional[dict] = None,
) -> str:
"""
Create an AgentForm and return its share URL.
Args:
name: Human-readable form name.
fields: List of dicts with keys:
- name (str): snake_case field id
- label (str): display label
- type (str): one of text, email, tel, textarea,
select, number, date, hidden
- required (bool): optional, default False
- options (list): optional, for select-type fields
- placeholder (str): optional hint text
- default (str): optional default value
Returns:
Short share URL the human can open in a browser.
"""
client = AgentForms(api_key=os.environ["AGENTFORMS_API_KEY"])
form = client.forms.create(name=name, fields=fields, metadata=metadata)
return form.share_url
@tool
def generate_agentform(prompt: str, form_name: Optional[str] = None) -> str:
"""
Use AgentForms' built-in AI to generate a form from a natural-language prompt.
Args:
prompt: e.g. "A feedback survey for a product launch event"
form_name: optional override for the AI-generated name
Returns:
Short share URL for the generated form.
"""
client = AgentForms(api_key=os.environ["AGENTFORMS_API_KEY"])
form = client.forms.generate(prompt=prompt, form_name=form_name)
return form.share_url
@tool
def poll_submissions(
form_url: str,
timeout_seconds: int = 60,
poll_interval: int = 10,
) -> str:
"""
Wait for submissions on a form and return them as a summary string.
Args:
form_url: The share URL returned by create_agentform.
timeout_seconds: How long to wait before giving up.
poll_interval: Seconds between API calls.
Returns:
Markdown summary of collected submissions.
"""
client = AgentForms(api_key=os.environ["AGENTFORMS_API_KEY"])
# Extract token from share URL: https://agentforms.io/abc123
token = form_url.rstrip("/").split("/")[-1]
deadline = time.time() + timeout_seconds
while time.time() < deadline:
result = client.submissions.list(form_token=token, limit=10)
submissions = result.get("submissions", [])
if submissions:
lines = [f"## Submissions collected ({len(submissions)})"]
for i, sub in enumerate(submissions, 1):
lines.append(f"\n### Submission {i} (id={sub.id})")
for key, value in sub.dynamic_data.items():
lines.append(f"- **{key}**: {value}")
return "\n".join(lines)
time.sleep(poll_interval)
return "No submissions received within the timeout window."
# ---------------------------------------------------------------------------
# Build the LangChain chain
# ---------------------------------------------------------------------------
def build_form_agent(temperature: float = 0.3):
"""
Assemble a LangChain chat chain that uses the AgentForms tools.
Returns:
A runnable chain (langchain Runnable) and the tools list.
"""
if not LANGCHAIN_AVAILABLE:
raise ImportError(
"LangChain is not installed. Run: pip install langchain langchain-openai"
)
llm = ChatOpenAI(model="gpt-4o", temperature=temperature)
tools = [generate_agentform, create_agentform, poll_submissions]
prompt = ChatPromptTemplate.from_messages([
("system", """You are a Form Builder Assistant. Your job is to help users
create data-collection forms by calling the AgentForms API.
Available tools:
- generate_agentform(prompt, form_name): AI-powered form generation from a
natural language prompt. Use this when the user's request is broad or open-ended.
- create_agentform(name, fields, metadata): Programmatic form creation when you
already know the exact fields. Build the fields list as dicts with:
name, label, type, required, options, placeholder, default.
Supported types: text, email, tel, textarea, select, number, date, hidden.
- poll_submissions(form_url, timeout_seconds, poll_interval): Wait for and
summarise form submissions.
Workflow:
1. Ask clarifying questions if the request is vague.
2. Call generate_agentform or create_agentform to build the form.
3. Share the returned URL with the user.
4. Optionally call poll_submissions to collect responses.
Always explain what form was created and which fields it contains.""",),
("human", "{input}"),
])
chain = prompt | llm | StrOutputParser()
return chain, tools
# ---------------------------------------------------------------------------
# Standalone demo (runs without LangChain if not installed)
# ---------------------------------------------------------------------------
def demo_direct_api():
"""
Minimal demo that uses the AgentForms SDK directly (no LangChain dependency).
This is useful for verifying the SDK integration works on its own.
"""
client = AgentForms(api_key=os.environ["AGENTFORMS_API_KEY"])
print("📝 Creating a form via the SDK directly...\n")
# Approach A: Programmatic creation
form1 = client.forms.create(
name="Quick Contact Form",
fields=[
{"name": "full_name", "label": "Full Name", "type": "text", "required": True},
{"name": "email", "label": "Email Address", "type": "email", "required": True},
{"name": "company", "label": "Company", "type": "text", "required": False},
{"name": "topic", "label": "Topic", "type": "select",
"options": ["Partnership", "Support", "Sales", "Other"], "required": True},
{"name": "message", "label": "Message", "type": "textarea",
"placeholder": "Tell us how we can help...", "required": False},
],
metadata={"source": "demo", "pattern": "langchain-form-agent"},
)
print(f"✅ Form created: {form1.name}")
print(f" Share URL: {form1.share_url}")
print(f" Public URL: {form1.public_url}")
print(f" Fields: {len(form1.fields)}\n")
for field in form1.fields:
req = "⚠️ " if field.required else " "
print(f" {req} [{field.type}] {field.label} ({field.name})")
print("\n" + "-" * 60 + "\n")
# Approach B: AI-powered generation (requires Starter+ tier)
try:
print("🤖 Generating a form with AI...\n")
form2 = client.forms.generate(
prompt="A food preference and allergy checklist for a corporate catering order",
form_name="Catering Preferences",
)
print(f"✅ AI-generated form: {form2.name}")
print(f" Share URL: {form2.share_url}")
print(f" Fields: {len(form2.fields)}\n")
for field in form2.fields:
req = "⚠️ " if field.required else " "
print(f" {req} [{field.type}] {field.label} ({field.name})")
except Exception as e:
print(f"⚠️ AI generation skipped (may require higher tier): {e}")
return form1, form2 if "form2" in dir() else None
# ---------------------------------------------------------------------------
# Full LangChain agent demo
# ---------------------------------------------------------------------------
def demo_langchain_agent():
"""
Interactive demo of the LangChain form agent.
If LangChain is installed, this builds the agent and runs a sample query.
"""
if not LANGCHAIN_AVAILABLE:
print("LangChain not installed — running direct SDK demo instead.")
print("Install with: pip install langchain langchain-openai\n")
demo_direct_api()
return
print("🔗 Building LangChain Form Agent...\n")
chain, tools = build_form_agent()
sample_prompt = (
"Create a registration form for a tech conference. "
"Include name, email, company, job title, "
"and a dropdown for which workshops they want to attend."
)
print(f"Prompt: {sample_prompt}\n")
result = chain.invoke({"input": sample_prompt})
print("Agent response:\n")
print(result)
print()
# Show available tools
print("Available tools:")
for t in tools:
print(f" - {t.name}: {t.description[:80]}...")
# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------
if __name__ == "__main__":
if "AGENTFORMS_API_KEY" not in os.environ:
print("Set the AGENTFORMS_API_KEY environment variable and try again.")
print(" export AGENTFORMS_API_KEY='***'")
sys.exit(1)
mode = sys.argv[1] if len(sys.argv) > 1 else "direct"
if mode == "langchain":
demo_langchain_agent()
else:
demo_direct_api()