Conversational AI Agents¶
The agents/ directory contains four AI agents that drive the corporate profile onboarding flow. They are instantiated synchronously inside HTTP request handlers (in routes/routes.js) — not as background jobs — and collaborate to gather user info, research a company online, and produce a finalized profile draft.
For asynchronous AI workers that operate on the job queue, see User-Specific AI Jobs.
Overview¶
| Agent | File | Model | Role |
|---|---|---|---|
ConversationAgent |
agents/conversationAgent.js |
Gemini 2.5 Flash | Orchestrates the onboarding dialog; tracks state |
InputParserAgent |
agents/inputParserAgent.js |
Gemini 2.5 Flash | Extracts structured fields from free-text replies |
ResearchAgent |
agents/researchAgent.js |
Gemini 2.5 Flash + Google Search tool | Web-researches the company and drafts a 9-section profile |
ProfileAgent |
agents/profileAgent.js |
Gemini 2.5 Flash | Refines the research draft into a final profile, handles approval |
All four use the @google/generative-ai SDK with the GEMINI_API_KEY env var (see Configuration Reference).
Onboarding Flow¶
The four agents are not invoked as a strict sequential pipeline. They are instantiated per-session and called conditionally, based on the conversation's state machine. The diagram below shows the typical happy-path order; the actual orchestration in routes/routes.js is closer to "session-managed conditional flow" than a fixed pipeline.
┌──────────────┐
│ Client / UI │
└──────┬───────┘
│ POST onboarding messages
▼
┌────────────────────────────────────────────────────────────┐
│ routes/routes.js (per-session agent instances) │
│ │
│ ConversationAgent ──► InputParserAgent (sub-agent) │
│ │ │
│ ├── once enough info collected ──► ResearchAgent │
│ │ │ │
│ │ ▼ │
│ │ Google Search │
│ │ │ │
│ │ ◄── 9-section research draft ────┘ │
│ │ │
│ └──► ProfileAgent ──► finalized profile JSON │
└────────────────────────────────────────────────────────────┘
Each session keeps its own agent instances; nothing is persisted to memory beyond the lifetime of the request chain. State is stored in the database once the user approves the profile.
ConversationAgent¶
File: agents/conversationAgent.js
Role: Multi-turn dialog manager. Greets the user, collects personal details (first/last name, email, phone) and company details (name, website, city, country), then triggers research.
Public methods¶
| Method | Inputs | Returns |
|---|---|---|
handle_input(update_type, value, session_state) |
Form-style field updates | { message, extracted_field, user_info } |
process_user_input(user_input, session_state) |
Free-form text reply | { message, extracted_fields, ...flags } |
State¶
The agent maintains:
- conversation_history — array of {role, content} for prompt context
- user_info — accumulated field values
- Flags: first_name_set, details_confirmed, profile_rejected, waiting_for_profile_decision
System prompt (summary)¶
A friendly corporate-profile assistant. Greets by name, acknowledges form completions, asks for missing fields, confirms profile creation readiness, and suggests edits when the user rejects. Responses stay 50–100 words; emojis (😄, 🚀, 🌟) are used sparingly.
Sub-agent¶
ConversationAgent instantiates one InputParserAgent internally and uses it whenever it processes free-text input. After the profile is confirmed, the parser is disabled to prevent further field extraction.
InputParserAgent¶
File: agents/inputParserAgent.js
Role: A pure JSON extractor. Given a chunk of natural-language input, returns whichever of the eight onboarding fields it can identify.
Public methods¶
| Method | Inputs | Returns |
|---|---|---|
parse_input(user_input) |
Raw user text | { extracted_info: {...}, website_not_ready: boolean } |
Extracted fields¶
first_name, last_name, phone_number, email_id, company_name, company_website, city, country.
Notes¶
- Returns an empty object if nothing is detected — never invents values.
- Detects "no website" / "site not ready" phrases and sets
website_not_ready: true. - Has a
disabledflag toggled byConversationAgentonce the profile is confirmed.
ResearchAgent¶
File: agents/researchAgent.js
Role: Generates a draft corporate profile by web-searching the company. Uses Gemini 2.5 Flash with the googleSearch: {} built-in tool — no separate scraping pipeline.
Public methods¶
| Method | Inputs | Returns |
|---|---|---|
research_company(company_name, company_website, location, streamCallback?) |
Company metadata; optional stream callback | Plain-text profile (9 numbered sections) |
Output format¶
Numbered sections: 1. Company Overview 2. Market Positioning 3. Products & Services 4. Leadership Team 5. Awards & Recognition 6. Recent News 7. Contact Information 8. Online Presence 9. Notable Customers / Partners
Missing fields are rendered as Unknown.
Streaming¶
If streamCallback is provided, the agent emits incremental events:
- research_chunk — partial text as it streams in
- research_complete — final string
- research_error — on failure (a fallback string is also returned)
Streaming is consumed via Server-Sent Events (SSE) — the calling route handler in routes/routes.js writes incremental events directly to the HTTP response with res.write('data: ...\n\n'). The previous version of this doc claimed Socket.IO; that was incorrect. Socket.IO references in routes/routes.js are commented out (lines 38–39).
ProfileAgent¶
File: agents/profileAgent.js
Role: Polishes the research output into the final, user-approved profile. Also processes the user's yes/no approval response.
Public methods¶
| Method | Inputs | Returns |
|---|---|---|
create_profile(user_info, research_data, generate_detailed, streamCallback?) |
Collected fields + research text | Final profile text |
handle_approval(user_response, first_name, company_name) |
"yes" / "no" / free text | { status: "completed" \| "pending", profile? } |
Output format¶
Maintains the same 9-section format as ResearchAgent, but with user-provided details merged in, formatting normalized, and tone consistent with the user's onboarding chat.
Streaming¶
Like ResearchAgent, optional callback events: profile_chunk, profile_complete.
Integration with Routes¶
routes/routes.js is the only caller. It instantiates a fresh set of agents per onboarding session and chains them:
const ConversationAgent = require('../agents/conversationAgent');
const ResearchAgent = require('../agents/researchAgent');
const ProfileAgent = require('../agents/profileAgent');
// InputParserAgent is created internally by ConversationAgent.
const conv = new ConversationAgent(initialUserInfo);
const research = new ResearchAgent();
const profile = new ProfileAgent();
The route handler holds these instances in memory for the duration of the conversation. There is no shared agent pool — closing the session releases them.
Operational Notes¶
- Stateless across sessions — agent state lives in the request handler. Restarting the server drops all in-flight conversations.
- No retry logic — if Gemini returns an error mid-conversation, the route returns a fallback response and the user is asked to try again.
- No content moderation — outputs are not filtered for PII or unsafe content beyond what Gemini's own safety settings provide.
- Cost — each completed onboarding makes 5–15 Gemini calls (parser + conversation turns + research + profile). Monitor under
GEMINI_API_KEYusage in GCP. - Streaming — when streaming is enabled, output goes to the HTTP response via Server-Sent Events (
res.write), not Socket.IO. See the streaming notes onResearchAgentandProfileAgentabove.
Related¶
- User-Specific AI Jobs — async AI workers that run after onboarding completes (brand positioning, objectives, recommended subjects).
- RAG Pipeline — once a profile is saved, RAG corpora are built per account and used for content generation.
- Integration Inventory — full Gemini / Vertex AI configuration.