Project

General

Profile

Actions

Feature #104

closed
RG RG

Frappe Telegram AI Chatbot - Prototype

Feature #104: Frappe Telegram AI Chatbot - Prototype

Added by Rajesh Gotur 22 days ago. Updated 22 days ago.

Start date:
09/25/2026
Due date:
% Done:

100%

Estimated time:
48:00 h
Spent time:

Description

AI Telegram Chatbot for Frappe / ERPNext

Build a secure, read-only AI assistant that allows users to ask natural-language questions about their Frappe / ERPNext data directly from Telegram while preserving the user's existing Frappe roles, DocType permissions, User Permissions and field-level restrictions.


1. Executive Summary

This story covers the implementation of the Frappe Telegram AI chatbot.

The application provides a Telegram interface over a Frappe / ERPNext system. Each Telegram user authenticates with their own Frappe account. The chatbot stores only the resulting Frappe session identifier in encrypted form and performs every Frappe lookup using that user's own session.

The AI does not receive the user's Frappe password or session ID. It receives only the Frappe data returned by tools that execute under the authenticated user's permissions.

The core workflow is:

Telegram User
     |
     | Frappe username + password
     v
Telegram Bot
     |
     | POST /api/method/login
     v
Frappe / ERPNext
     |
     | authenticated session (sid)
     v
Encrypted Session Store
     |
     v
Natural-language Question
     |
     v
AI Agent
     |
     | tool/function calls
     v
Read-only Frappe Tools
     |
     | user's own Frappe sid
     v
Frappe REST API
     |
     v
AI-generated Answer
     |
     v
Telegram

The chatbot is intentionally read-only. It can search, count, aggregate and open Frappe records, but it cannot create, modify, submit or delete records.


2. Jira Story Definition

User Story

As a Frappe / ERPNext user,

I want to authenticate with my Frappe account and ask natural-language questions about the Frappe data that I am permitted to access through Telegram,

so that I can quickly retrieve business information without opening the Frappe web interface and manually searching records.

Story Type

Feature

Primary Deliverable

A production-ready Telegram chatbot that:

  • authenticates users against Frappe;
  • preserves Frappe's existing access control;
  • translates natural-language questions into validated Frappe read operations;
  • uses an OpenAI-compatible AI model with tool/function calling;
  • returns concise answers in Telegram;
  • maintains limited conversation context for follow-up questions;
  • protects Frappe sessions and passwords;
  • prevents write operations.

3. Business Objective

The objective is to provide a conversational interface over existing Frappe / ERPNext data without creating a second permission system.

Instead of:

Open Frappe
    |
    v
Find DocType
    |
    v
Build filters
    |
    v
Search records
    |
    v
Calculate totals
    |
    v
Interpret result

the user can ask:

"Show my last 5 sales orders"

"How many open leads do we have?"

"Total unpaid sales invoices this month by customer"

"Show the details of SO-00045"

The AI determines which read-only Frappe tools are required, executes them through the user's Frappe session, and converts the returned data into a concise Telegram response.


4. Scope

4.1 In Scope

  • Telegram bot using aiogram.
  • Private-chat authentication flow.
  • Frappe username/password authentication.
  • Frappe session management.
  • Encrypted persistent session storage.
  • Automatic session revalidation.
  • Frappe role and readable DocType discovery.
  • Natural-language question handling.
  • OpenAI-compatible AI provider integration.
  • AI tool/function calling.
  • Dynamic Frappe DocType discovery.
  • DocType metadata inspection.
  • Field validation.
  • Read-only record searching.
  • Record counting.
  • Aggregation.
  • Full-record retrieval.
  • Filters and sorting.
  • Grouped aggregate queries.
  • Conversation memory.
  • Telegram message splitting.
  • Rate limiting.
  • Failed-login throttling.
  • Password message deletion.
  • Private-chat restriction.
  • Logout/session cleanup.
  • Configuration validation.
  • Service health checks.
  • Troubleshooting and operational diagnostics.

4.2 Out of Scope

The chatbot does not:

  • create Frappe records;
  • update Frappe records;
  • delete records;
  • submit documents;
  • cancel documents;
  • execute raw SQL;
  • bypass Frappe permissions;
  • maintain a separate application-level role/permission system;
  • send Frappe passwords to the AI provider;
  • send Frappe session IDs to the AI provider;
  • provide Telegram group-based business-data access;
  • support Frappe two-factor-authenticated accounts through this login flow.

5. Functional Requirements

# Requirement Description
1 Telegram interface Users interact with the application through Telegram
2 Frappe authentication Authenticate each user using their own Frappe account
3 Session persistence Persist the Frappe session securely for subsequent conversations
4 Permission inheritance Use Frappe as the authority for all data access
5 AI question understanding Interpret natural-language business questions
6 Tool selection Allow the AI to select appropriate read-only Frappe tools
7 Dynamic DocType discovery Find readable DocTypes when the AI is unsure of the exact name
8 Metadata discovery Inspect actual DocType fields before constructing queries
9 Record search Search/list records with filters, sorting and limits
10 Counting Count records matching user criteria
11 Aggregation Calculate sum, average, minimum, maximum or count
12 Record detail Retrieve a complete record by DocType and name
13 Query validation Reject invalid fields, filters, operators and aggregate arguments
14 Conversation context Maintain limited user-specific conversation memory
15 Session validation Re-check stored sessions periodically
16 Security controls Encrypt stored sessions and throttle authentication/requests
17 Telegram formatting Split long responses into Telegram-safe message sizes
18 Operational checks Validate configuration and external service connectivity
19 Read-only enforcement Prevent AI from performing write operations
20 Logout Close the Frappe session and remove local session data

6. High-Level Architecture

flowchart TB
    U["Telegram User"]

    subgraph TG["Telegram"]
        BOT["Telegram Bot"]
    end

    subgraph APP["Frappe Telegram AI Application"]
        H["Bot Handlers"]
        AUTH["Authentication Service"]
        AGENT["AI Agent"]
        TOOLS["Read-only Frappe Tools"]
        SCHEMA["DocType Metadata + Query Validation"]
        AI["AI Provider Client"]
        STORE["Encrypted SQLite Session Store"]
        SEC["Security Controls"]
        CONFIG["Configuration / Runtime"]
    end

    subgraph FR["Frappe / ERPNext"]
        LOGIN["Frappe Login API"]
        META["DocType Metadata"]
        DATA["Frappe Data APIs"]
        PERM["Roles / User Permissions / Field Permissions"]
    end

    U --> BOT
    BOT --> H
    H --> AUTH
    H --> AGENT

    AUTH --> LOGIN
    AUTH --> STORE
    AUTH --> SEC

    AGENT --> AI
    AGENT --> TOOLS
    TOOLS --> SCHEMA
    TOOLS --> DATA

    DATA --> PERM
    META --> SCHEMA

    AI --> AGENT
    AGENT --> H
    H --> BOT
    BOT --> U

    CONFIG --> H
    CONFIG --> AUTH
    CONFIG --> AGENT
    CONFIG --> SEC

7. Authentication and Security Architecture

The security model deliberately avoids duplicating Frappe's permission system.

sequenceDiagram
    participant U as Telegram User
    participant B as Bot
    participant A as AuthService
    participant F as Frappe
    participant DB as SQLite Session Store

    U->>B: /login
    B->>U: Frappe username/email
    U->>B: Username
    B->>U: Frappe password
    U->>B: Password
    B->>B: Delete password message
    B->>A: username + password
    A->>F: POST /api/method/login
    F-->>A: sid + full name
    A->>F: get_logged_user(sid)
    F-->>A: authenticated Frappe user
    A->>F: session_boot(sid)
    F-->>A: roles + readable DocTypes
    A->>DB: Store encrypted sid
    A-->>B: Principal
    B-->>U: Logged in + roles

Security Rules

  1. Passwords are never stored.
  2. Password messages are deleted after reading when configured.
  3. Frappe session IDs are encrypted before persistent storage.
  4. The encryption key is supplied through configuration.
  5. Each Telegram user is mapped to their own Frappe session.
  6. Frappe calls are made using the requesting user's session.
  7. The HTTP client intentionally does not share a cookie jar between users.
  8. AI requests do not contain the password or Frappe session ID.
  9. Login attempts are throttled after repeated failures.
  10. Questions are rate-limited per Telegram user.
  11. Stored Frappe sessions are periodically revalidated.
  12. /logout closes the Frappe session and removes stored session data.

8. Permission Model

Principle

Frappe is the only authority for data access.

The chatbot does not define independent application roles such as:

Telegram Admin
Telegram Sales User
Telegram HR User

Instead:

Telegram User
     |
     v
Frappe Login
     |
     v
Frappe User
     |
     +--> Roles
     +--> DocType permissions
     +--> User Permissions
     +--> Owner rules
     +--> Field permission levels
     +--> Custom permission logic
     |
     v
Allowed Frappe Data

A Sales User therefore receives the data Frappe allows that user to access, while an HR user receives the data allowed to that HR user.

Profile Information

At login/revalidation, the application reads:

  • authenticated Frappe username;
  • full name;
  • Frappe roles;
  • readable DocTypes where available.

These values are used to guide the AI and provide early rejection when Frappe has already reported that a DocType is not readable.

The actual Frappe API call is still performed with the user's own session, so Frappe remains the enforcement layer.


9. AI Agent Workflow

flowchart TD
    Q["User Question"] --> S["Build AI Context"]
    S --> P["System Prompt"]
    P --> AI["AI Provider"]

    AI --> D{"Tool Calls Required?"}

    D -->|No| A["Final Answer"]
    D -->|Yes| T["Read-only Frappe Tool"]

    T --> V["Validate Arguments"]
    V --> M["Load / Check DocType Metadata"]
    M --> F["Frappe API using User sid"]
    F --> R["Tool Result"]

    R --> AI
    AI --> D

    A --> O["Telegram Response"]

The AI agent runs a bounded tool loop.

For each question:

  1. Build the system prompt.
  2. Include limited conversation history.
  3. Send the question and tool definitions to the AI provider.
  4. If the AI requests a tool, validate and execute it.
  5. Return the tool result to the AI.
  6. Continue until the AI produces an answer or the tool-round limit is reached.
  7. Return the final answer to Telegram.
  8. Save the question and answer in bounded conversation memory.

10. AI System Rules

The system prompt enforces the following behaviour:

  • Retrieve factual information through tools.
  • Never invent records, numbers, names or statuses.
  • Respect the user's Frappe permissions.
  • Do not work around permission errors.
  • Discover the DocType when the exact name is uncertain.
  • Inspect DocType fields before querying uncertain fields.
  • Prefer count/aggregate operations for count and total questions.
  • Treat submitted documents appropriately when business totals normally require submitted records.
  • Remain read-only.
  • Ask one short clarification when a question is ambiguous.
  • Answer in the same language as the user's question.
  • Keep Telegram responses concise.
  • Include document IDs so users can find the records in Frappe.

11. AI Provider Integration

The application uses an OpenAI-compatible chat-completions interface with tool/function calling.

Supported provider configurations in the project:

Provider Supported
OpenRouter Yes
OpenAI Yes
Groq Yes
Google Gemini through OpenAI-compatible endpoint Yes
Ollama Yes
Custom OpenAI-compatible server Yes

The provider configuration contains:

ai:
  provider: "openrouter"
  api_key: ""
  model: "openai/gpt-4o-mini"
  base_url: ""
  temperature: 0.1
  max_tokens: 1200
  timeout_seconds: 90
  max_tool_rounds: 6

For Ollama, an API key is not required.

The selected model must support tool/function calling because the AI needs to request Frappe data through the defined tools.


12. Read-Only Frappe Toolset

The chatbot exposes five core AI tools.

12.1 list_doctypes

Purpose:

Find readable Frappe DocTypes when the AI is unsure of the exact DocType name.

Example:

Question:
"Show me open customer complaints"

Possible flow:
list_doctypes("complaint")
        |
        v
Identify matching DocType

The tool uses the readable DocType information reported by Frappe.


12.2 describe_doctype

Purpose:

Inspect the actual structure of a DocType before querying it.

Returns information such as:

  • DocType name;
  • title field;
  • submittable status;
  • single/non-single status;
  • default fields;
  • field names;
  • labels;
  • field types;
  • Link/Select options;
  • child tables.

This prevents the AI from blindly inventing field names.


12.3 search_records

Purpose:

Search/list records with:

  • fields;
  • filters;
  • sorting;
  • result limit.

Example:

search_records(
    doctype="Sales Order",
    fields=["name", "customer", "grand_total"],
    filters=[["status", "=", "To Deliver and Bill"]],
    order_by="modified desc",
    limit=5
)

The actual query is sent to Frappe using the user's session.


12.4 count_records

Purpose:

Return the number of records matching filters.

Useful for questions such as:

How many open leads do we have?

The AI can use:

count_records("Lead", ...)

instead of retrieving every lead.


12.5 aggregate_records

Purpose:

Perform:

  • sum;
  • avg;
  • min;
  • max;
  • count.

It can optionally group results by another field.

Example:

Total purchase this year by supplier

can be translated into an aggregate operation grouped by supplier.

Only valid numeric fields can be used for numeric aggregation.


12.6 get_record

Purpose:

Retrieve one complete Frappe record by DocType and name.

Example:

Show the details of SO-00045

becomes:

get_record(
    doctype="Sales Order",
    name="SO-00045"
)

Child tables are included where available, while internal/noise fields are cleaned before being passed back to the AI.


13. Query Validation Layer

The AI is not allowed to send arbitrary field or filter definitions directly to Frappe.

The validation layer checks the request against the actual DocType metadata.

flowchart LR
    A["AI Tool Arguments"] --> B["JSON Validation"]
    B --> C["DocType Validation"]
    C --> D["Field Validation"]
    D --> E["Filter Validation"]
    E --> F["Operator Validation"]
    F --> G["Sort Validation"]
    G --> H["Limit Validation"]
    H --> I["Frappe API"]

Field Validation

The application verifies that requested fields actually exist.

Unknown fields produce a query error rather than being sent to Frappe.

Filter Validation

Supported operators include:

=
!=
>
<
>=
<=
like
not like
in
not in
between
is
timespan

Time-span filters include values such as:

today
yesterday
tomorrow
this week
last week
next week
this month
last month
next month
this quarter
last quarter
next quarter
this year
last year
next year
last 6 months
next 6 months

Sort Validation

Sorting must use a valid field and:

<fieldname> asc

or:

<fieldname> desc

Aggregate Validation

Supported aggregate functions:

sum
avg
min
max
count

Numeric aggregation is limited to supported numeric Frappe field types such as:

Currency
Float
Int
Percent
Duration

Protected Field Types

The metadata layer excludes fields that should not be queried as ordinary values, including:

Section Break
Column Break
Tab Break
HTML
Button
Fold
Heading
Table
Table MultiSelect
Password
Image

Password fields are therefore not exposed to the AI as queryable fields.


14. Query Result Protection

The application limits the amount of data passed into the AI context.

Configuration includes:

limits:
  default_records: 20
  max_records: 100
  max_tool_result_chars: 12000
  conversation_memory: 10
  requests_per_minute: 20

Record Limit

A query has:

  • a default record limit;
  • a hard maximum record limit.

This prevents a natural-language request from unintentionally loading an excessive number of records.

Tool Result Size

If the serialized tool response exceeds the configured character limit:

  • record lists are reduced;
  • grouped results may be reduced;
  • large child tables are truncated;
  • the result is marked as truncated.

This keeps the AI context bounded.


15. Telegram User Experience

Private Chat Only

The chatbot intentionally operates in private Telegram chats.

The application does not process normal business questions from group chats.

Private Chat
    |
    +--> Login
    +--> Questions
    +--> Commands

Group usage receives the private-chat instruction instead.


16. Login Workflow

stateDiagram-v2
    [*] --> LoggedOut

    LoggedOut --> Username: /start or /login
    Username --> Password: username entered
    Password --> Authenticating: password entered

    Authenticating --> LoggedIn: Frappe accepts credentials
    Authenticating --> Username: Invalid login
    Authenticating --> LoggedOut: 2FA unsupported / unavailable

    LoggedIn --> LoggedOut: /logout
    LoggedIn --> Username: Session expires

    Username --> LoggedOut: /cancel
    Password --> LoggedOut: /cancel

Login Sequence

  1. User sends /start or /login.
  2. Bot asks for Frappe username/email.
  3. User enters username.
  4. Bot asks for password.
  5. User enters password.
  6. Password message is deleted when enabled.
  7. Frappe validates credentials.
  8. Frappe returns a session ID.
  9. The bot resolves the authenticated Frappe user.
  10. User roles/readable DocTypes are loaded.
  11. Session ID is encrypted and stored.
  12. User is informed that login succeeded.

17. Session Management

Persistent sessions are stored in:

data/sessions.db

The database contains a mapping between:

Telegram User ID
        |
        v
Frappe User
        |
        v
Encrypted Frappe sid

The password is never stored.

The session store records:

  • Telegram user ID;
  • Telegram username;
  • Frappe user;
  • full name;
  • encrypted session ID;
  • creation timestamp;
  • last checked timestamp.

Session Revalidation

The configured default is:

security:
  session_check_minutes: 5

The application re-checks the session with Frappe periodically.

If the session has ended because:

  • the Frappe session expired;
  • the user logged out;
  • the user was disabled;
  • the session became invalid;

the local session is removed and the user is asked to log in again.


18. Logout Workflow

When the user sends:

/logout

the application:

  1. Clears conversation memory.
  2. Removes the local session.
  3. Attempts to close the Frappe session.
  4. Confirms that the user is logged out.

No Frappe password remains in storage.


19. Conversation Memory

The agent maintains limited per-user conversation memory.

Configured default:

conversation_memory: 10

Memory is maintained per Telegram user and is reset by:

/new

It is also cleared when:

/logout

or when the application restarts.

This allows follow-up questions while preventing unlimited conversation history from growing the AI context.

Example:

User:
Show my last 5 sales orders

Bot:
SO-001...
SO-002...

User:
Which customer is the largest one?

Bot:
...

The second question can use the bounded prior conversation context.


20. Telegram Response Handling

Telegram allows messages up to approximately 4096 characters.

The implementation uses a safer internal limit of:

4000 characters

Long AI answers are split at:

  1. line breaks where possible;
  2. spaces where necessary;
  3. hard boundaries only as a final fallback.

This avoids failed Telegram sends caused by oversized messages.

The system prompt also instructs the AI to keep responses short and Telegram-friendly.


21. Commands

The chatbot exposes:

Command Purpose
/start Start the bot / begin login
/login Log in or switch Frappe account
/logout Close the Frappe session and log out
/me Show Frappe user, name, roles and readable DocType information
/new Start a new conversation and clear previous question/answer memory
/cancel Cancel the current login flow
/help Show usage instructions

22. Error Handling

The application defines explicit error categories.

Error Behaviour
Invalid credentials User is asked to retry
Too many failed logins Temporary login lock
2FA account Bot reports that this login flow does not support it
Frappe unavailable User receives a service-unavailable message
Session expired Local session is cleared and login is requested
Permission denied User is informed that their Frappe role does not allow the requested access
DocType not found AI receives a controlled error and can correct its approach
Invalid query AI receives validation feedback
AI timeout User receives a concise AI-service error
AI API key rejected Configuration/API-key error is reported
AI rate limit User is asked to retry later
Telegram conflict Another polling instance must be stopped
Non-text message Bot asks the user to send a text question

23. Login Security Controls

Failed Login Throttling

The application tracks failed Frappe logins per Telegram user.

Default:

max_login_attempts: 5
lockout_minutes: 15

Once the configured threshold is reached, further login attempts are temporarily blocked.

This is an additional application-level protection; Frappe can also enforce its own account-security policies.


24. Request Rate Limiting

Questions are limited per Telegram user.

Default:

requests_per_minute: 20

The limiter uses a sliding one-minute window.

If the user exceeds the limit:

You are sending questions too quickly.
Please wait a moment.

No AI/Frappe query is performed for the rejected request.


25. Frappe REST Integration

The Frappe client supports the following operations.

Frappe Operation Purpose
/api/method/login Authenticate user
/api/method/logout End user session
/api/method/frappe.auth.get_logged_user Verify session owner
/api/method/frappe.sessions.get Retrieve roles/readable DocTypes
/api/method/frappe.desk.form.load.getdoctype Retrieve DocType metadata
/api/method/frappe.client.get_list Search/list records
/api/method/frappe.client.get_count Count records
/api/resource/{doctype}/{name} Retrieve a specific record
/api/method/ping Service health check

The Frappe client uses explicit session headers:

Cookie: sid=<user session>

The HTTP client does not retain a shared cookie jar.

This prevents sessions from different Telegram users from being accidentally mixed.


26. Frappe Error Mapping

The application maps Frappe responses into controlled application errors.

Examples:

401 / SessionExpired
        -> SessionInvalid

403 / PermissionError
        -> PermissionDenied

404 / DoesNotExistError
        -> NotFound

400 / 409 / 417 / 422
        -> InvalidRequest

5xx
        -> FrappeUnavailable

This allows the Telegram layer and AI agent to distinguish:

  • authentication problems;
  • permission problems;
  • invalid queries;
  • missing records;
  • server/network problems.

27. Runtime Architecture

flowchart TB
    MAIN["main.py"]

    CHECK["python main.py check"]
    RUN["python main.py"]
    KEY["python main.py genkey"]

    MAIN --> CHECK
    MAIN --> RUN
    MAIN --> KEY

    RUN --> SETTINGS["Settings"]
    SETTINGS --> APP["Application.build()"]

    APP --> FR["FrappeClient"]
    APP --> AI["AIProvider"]
    APP --> STORE["SessionStore"]
    APP --> AUTH["AuthService"]
    APP --> TOOLS["FrappeTools"]
    APP --> AGENT["Agent"]
    APP --> HANDLERS["BotHandlers"]

    HANDLERS --> AGENT
    HANDLERS --> AUTH
    AGENT --> TOOLS
    AGENT --> AI
    AUTH --> FR
    TOOLS --> FR
    STORE --> DB["SQLite"]

The runtime builds the application dependencies and starts the aiogram polling dispatcher.


28. Configuration

The project uses:

config/config.yaml

A clean template is supplied as:

config/config.example.yaml

Main configuration areas:

app:
telegram:
frappe:
ai:
security:
limits:

Application

app:
  name: "Frappe AI Assistant"
  log_level: "INFO"
  data_dir: "data"

Telegram

telegram:
  bot_token: ""

The token is created through Telegram's BotFather.

Frappe

frappe:
  url: ""
  verify_ssl: true
  timeout_seconds: 30

Default API paths target Frappe v14/v15.

AI

ai:
  provider: "openrouter"
  api_key: ""
  model: "openai/gpt-4o-mini"
  base_url: ""
  temperature: 0.1
  max_tokens: 1200
  timeout_seconds: 90
  max_tool_rounds: 6

Security

security:
  encryption_key: ""
  session_check_minutes: 5
  max_login_attempts: 5
  lockout_minutes: 15
  delete_password_messages: true

Limits

limits:
  default_records: 20
  max_records: 100
  max_tool_result_chars: 12000
  conversation_memory: 10
  requests_per_minute: 20

29. Configuration Validation

The project provides:

python main.py check

The check validates required settings and then tests:

Configuration
      |
      +--> Frappe
      |
      +--> Telegram token
      |
      +--> AI service

Successful validation results in:

Ready to start: python main.py

If a configuration item is invalid, the check identifies the relevant setting.


30. Encryption Key Generation

A Fernet-compatible key is required for encrypted session storage.

Generate it with:

python main.py genkey

The generated value is placed in:

security:
  encryption_key: "..."

Changing this key invalidates the application's ability to decrypt existing stored sessions, causing users to log in again.


31. Installation

The project requires:

Python 3.10+

Create a virtual environment:

python -m venv .venv

Windows:

.\.venv\Scripts\Activate.ps1

Linux/macOS:

source .venv/bin/activate

Install dependencies:

pip install -r requirements.txt

Dependencies include:

aiogram
httpx
pydantic
PyYAML
cryptography

32. Startup Flow

flowchart TD
    A["Clone / copy project"] --> B["Create virtual environment"]
    B --> C["Activate .venv"]
    C --> D["pip install -r requirements.txt"]
    D --> E["Create config/config.yaml"]
    E --> F["Generate encryption key"]
    F --> G["python main.py check"]
    G --> H{"All checks pass?"}
    H -->|No| I["Fix configuration / connectivity"]
    I --> G
    H -->|Yes| J["python main.py"]
    J --> K["Telegram long polling"]

The bot uses Telegram long polling, so the supplied implementation does not require a public webhook URL.


33. Production Deployment

The project recommends running the bot under a process manager such as:

systemd
Supervisor
Docker

Production requirements include:

  • protect config/config.yaml;
  • keep API keys outside source control;
  • restrict file permissions on configuration;
  • protect the encryption key;
  • use HTTPS for the Frappe site where applicable;
  • ensure only one polling instance uses the Telegram bot token;
  • monitor application logs;
  • ensure the bot process can reach Frappe and the selected AI provider.

The application is designed to run as a long-lived bot process.


34. Project Structure

frappe_telegram_ai/
│
├── main.py
│
├── config/
│   ├── config.yaml
│   └── config.example.yaml
│
├── app/
│   ├── core/
│   │   ├── config.py
│   │   └── logging.py
│   │
│   ├── frappe/
│   │   ├── client.py
│   │   └── errors.py
│   │
│   ├── auth/
│   │   ├── principal.py
│   │   └── service.py
│   │
│   ├── storage/
│   │   └── sessions.py
│   │
│   ├── security/
│   │   ├── crypto.py
│   │   └── limits.py
│   │
│   ├── ai/
│   │   └── provider.py
│   │
│   ├── agent/
│   │   ├── agent.py
│   │   ├── schema.py
│   │   └── tools.py
│   │
│   ├── bot/
│   │   ├── handlers.py
│   │   └── texts.py
│   │
│   └── runtime.py
│
└── docs/
    ├── ACCESS_CONTROL.md
    └── TROUBLESHOOTING.md

35. Module Responsibilities

Module Responsibility
main.py Start, configuration check and encryption-key generation
core/config.py YAML configuration loading and validation
core/logging.py Application logging
frappe/client.py Frappe REST communication
frappe/errors.py Frappe-specific error types
auth/service.py Login, logout, session restoration and revalidation
auth/principal.py Authenticated Frappe user context
storage/sessions.py Persistent encrypted session mapping
security/crypto.py Fernet encryption/decryption
security/limits.py Login throttling and request rate limiting
ai/provider.py OpenAI-compatible AI client and tool-call parsing
agent/agent.py AI system prompt, tool loop and conversation memory
agent/schema.py DocType metadata and query validation
agent/tools.py Read-only Frappe tool implementation
bot/handlers.py Telegram commands, login flow and question handling
bot/texts.py User-facing Telegram messages
runtime.py Dependency wiring and bot startup

36. Detailed Data Flow

Question → Answer

┌───────────────────────┐
│ Telegram User         │
│ "How many open leads?"│
└───────────┬───────────┘
            │
            v
┌───────────────────────┐
│ Bot Handler           │
│ - session check       │
│ - rate limit          │
└───────────┬───────────┘
            │
            v
┌───────────────────────┐
│ Agent                 │
│ - system prompt       │
│ - conversation memory │
│ - user context        │
└───────────┬───────────┘
            │
            v
┌───────────────────────┐
│ AI Provider            │
│ decides tool call     │
└───────────┬───────────┘
            │
            v
┌───────────────────────┐
│ count_records         │
│ doctype = Lead        │
│ filters = ...         │
└───────────┬───────────┘
            │
            v
┌───────────────────────┐
│ Query Validation      │
│ valid DocType/fields  │
└───────────┬───────────┘
            │
            v
┌───────────────────────┐
│ Frappe REST API       │
│ user's sid            │
└───────────┬───────────┘
            │
            v
┌───────────────────────┐
│ Count Result          │
└───────────┬───────────┘
            │
            v
┌───────────────────────┐
│ AI Final Answer       │
└───────────┬───────────┘
            │
            v
┌───────────────────────┐
│ Telegram              │
│ concise response      │
└───────────────────────┘

37. Example Query Workflows

Example A — Recent Sales Orders

User:
Show my last 5 sales orders

Expected agent reasoning path:

Question
  |
  v
Sales Order DocType
  |
  v
search_records
  |
  +--> order by modified desc
  +--> limit 5
  |
  v
Frappe
  |
  v
Records
  |
  v
AI concise answer

Example B — Count Open Leads

User:
How many open leads do we have?

Preferred operation:

count_records

rather than loading every Lead record.


Example C — Total Unpaid Sales Invoices

User:
Total unpaid sales invoices this month

The agent can:

  1. identify the Sales Invoice DocType;
  2. inspect its fields if required;
  3. construct validated filters;
  4. aggregate the appropriate numeric field;
  5. return the total.

Example D — Grouped Total

User:
Total purchase this year by supplier

The agent can use:

aggregate_records
    function = sum
    field = appropriate numeric field
    group_by = supplier
    filters = current-year criteria

The query is validated against actual DocType metadata before reaching Frappe.


Example E — Record Detail

User:
Show the details of SO-00045

The agent can use:

get_record
    doctype = Sales Order
    name = SO-00045

The resulting document and relevant child-table information are cleaned before being returned to the AI.


38. Read-Only Enforcement

The system has multiple layers supporting read-only behaviour.

Layer 1 — AI Instruction

The system prompt explicitly states that the assistant can only read data.

Layer 2 — Tool Surface

Only read-oriented tools are exposed:

list_doctypes
describe_doctype
search_records
count_records
aggregate_records
get_record

There are no create/update/delete tools.

Layer 3 — Frappe Client

The data methods implemented by the client are read-only.

Result

A request such as:

Create a new customer

should receive a response explaining that the assistant is read-only rather than executing a write operation.


39. Data Privacy Boundary

flowchart LR
    P["Frappe Password"] --> F["Frappe Login"]
    F --> S["Frappe sid"]

    S --> E["Encrypted Local Storage"]

    S -. never sent .-> AI["AI Provider"]
    P -. never sent .-> AI

    FDATA["Frappe Data Allowed to User"] --> AI
    AI --> ANS["Answer"]

The AI provider receives:

  • the conversation context;
  • the system instructions;
  • tool results returned by the user's permitted Frappe queries.

The AI provider does not receive:

  • the Frappe password;
  • the Frappe session ID.

40. Access-Control Decision Flow

flowchart TD
    A["User asks about DocType"] --> B{"Logged in?"}
    B -->|No| C["Request Frappe login"]
    B -->|Yes| D{"DocType known?"}

    D -->|No| E["list_doctypes"]
    E --> F["Identify valid DocType"]

    D -->|Yes| F

    F --> G{"Frappe says user can read it?"}
    G -->|No| H["Return permission denied"]
    G -->|Yes| I["Load DocType metadata"]

    I --> J["Validate fields / filters"]
    J --> K{"Valid query?"}

    K -->|No| L["Return controlled query error to AI"]
    K -->|Yes| M["Call Frappe with user's sid"]

    M --> N["Permission enforcement by Frappe"]
    N --> O["Tool result"]
    O --> P["AI answer"]

41. Edge Cases

Invalid Login

The user is asked to retry and the failure contributes to the login throttle.

Too Many Login Attempts

The Telegram user is temporarily locked from attempting another login.

Two-Factor Authentication

The current implementation reports that the Frappe account uses two-factor authentication and cannot use this login flow.

Expired Session

The stored session is removed and the user is asked to authenticate again.

Changed Frappe Roles

Roles and readable DocTypes are refreshed during periodic session checks.

Permission Denied

The agent does not attempt to bypass the permission. It reports the restriction.

Unknown DocType

The AI can use list_doctypes.

Unknown Field

The AI can use describe_doctype.

Invalid Field

The query validator rejects it before the request is sent.

Large Result

The result is reduced to the configured context size and marked as truncated where applicable.

Long Telegram Answer

The answer is split into Telegram-sized messages.

Too Many Questions

The per-user rate limiter rejects the request temporarily.

Frappe Unavailable

The bot returns a controlled Frappe connectivity message.

AI Unavailable

The bot returns a controlled AI-service message.

Bot Running Twice

Telegram polling can conflict when two instances use the same bot token. Only one polling instance should run.


42. Logging

The project supports:

DEBUG
INFO
WARNING
ERROR

The logging system is designed not to write:

  • Frappe passwords;
  • Frappe session IDs.

Operational failures are logged with controlled information useful for diagnosis.

For troubleshooting:

app:
  log_level: "DEBUG"

can be used when more detail is required.


43. Health / Readiness Check

The command:

python main.py check

performs three external checks after configuration validation:

1. Frappe
   |
   +--> /api/method/ping

2. Telegram
   |
   +--> bot.get_me()

3. AI
   |
   +--> chat completion test

This provides a single pre-start verification path.


44. Acceptance Criteria

# Acceptance Criteria
AC-01 A user can start the bot in a private Telegram chat
AC-02 The bot requests Frappe username/email
AC-03 The bot requests Frappe password
AC-04 The password message is deleted when configured
AC-05 Invalid Frappe credentials do not create a stored session
AC-06 Successful login creates an encrypted session mapping
AC-07 The user can use natural-language questions after login
AC-08 The AI can select read-only Frappe tools
AC-09 Tool arguments are validated against actual DocType metadata
AC-10 Unknown fields are rejected before querying Frappe
AC-11 The user's own Frappe session is used for every data lookup
AC-12 Frappe permissions determine the accessible data
AC-13 The AI cannot create, update, submit or delete records
AC-14 Count questions can use count_records
AC-15 Total/grouping questions can use aggregate_records
AC-16 Individual documents can be retrieved using get_record
AC-17 Session validity is periodically rechecked
AC-18 Expired sessions require the user to log in again
AC-19 /logout closes the Frappe session and clears local session state
AC-20 /new clears conversation memory
AC-21 Excessive requests are rate limited
AC-22 Repeated failed logins are throttled
AC-23 Long responses are split safely for Telegram
AC-24 python main.py check validates configuration and services
AC-25 The application can start using python main.py
AC-26 Group-chat business questions are rejected in favour of private chat
AC-27 AI provider failures are returned as controlled user-facing errors
AC-28 Frappe connectivity failures are returned as controlled user-facing errors

45. Testing Checklist

Installation

  • Python 3.10+ available.
  • Virtual environment created.
  • Dependencies installed.
  • config/config.yaml created.
  • Encryption key generated.

Configuration

  • Telegram bot token configured.
  • Frappe URL configured.
  • AI provider configured.
  • AI model supports tool calling.
  • AI API key configured where required.
  • Encryption key configured.
  • Limits reviewed.

Connectivity

  • python main.py check succeeds.
  • Frappe ping succeeds.
  • Telegram token is valid.
  • AI service returns a test response.

Authentication

  • /start works.
  • Username prompt works.
  • Password prompt works.
  • Password message deletion works.
  • Valid login works.
  • Invalid login is rejected.
  • Login throttling works.
  • /logout works.
  • /me shows the correct user and roles.
  • Session expiry causes re-login.

AI Queries

  • Simple list query.
  • Filtered query.
  • Count query.
  • Aggregate query.
  • Grouped aggregate.
  • Record detail query.
  • Follow-up question using memory.
  • Unknown DocType handling.
  • Unknown field handling.
  • Invalid filter handling.
  • Permission-denied handling.
  • Read-only write request rejection.

Telegram

  • Long answer splitting.
  • Text-only behaviour.
  • Private-chat restriction.
  • Rate limiting.
  • /help.
  • /new.
  • /cancel.

46. Troubleshooting Matrix

Problem Resolution
config/config.yaml needs attention Fill the settings identified by python main.py check
Cannot reach Frappe Verify frappe.url and network access
Self-signed local Frappe certificate Use frappe.verify_ssl: false only where appropriate
Invalid Frappe login Verify username/password and Frappe account status
Too many failed logins Wait for configured lockout period
2FA message Use an account supported by the current login flow
Bot repeatedly requests login Check Frappe session expiry, account status and encryption key
Permission denied Correct the Frappe user's role/permission in Frappe
AI rejects API key Check ai.api_key and provider
AI answers without querying Use a model/provider supporting tool/function calling
Telegram conflict Stop the other bot instance using the same token
Bot does not answer in group Use a private Telegram chat

47. Security Responsibilities

Frappe

Responsible for:

  • authentication;
  • role permissions;
  • DocType permissions;
  • User Permissions;
  • ownership rules;
  • field-level permissions;
  • custom permission logic;
  • session validity.

Application

Responsible for:

  • encrypted session storage;
  • login throttling;
  • request rate limiting;
  • password-message deletion;
  • tool argument validation;
  • result-size limits;
  • conversation-memory limits;
  • read-only tool exposure;
  • private-chat restriction.

AI Provider

Responsible only for:

  • understanding the natural-language request;
  • selecting tools;
  • interpreting returned data;
  • generating the final natural-language answer.

The AI provider is not an authorization layer.


48. Important Design Decisions

48.1 Frappe Remains the Source of Truth

No duplicate permission configuration is maintained in YAML.

Frappe Roles
     |
     v
Frappe Permissions
     |
     v
Frappe API
     |
     v
Telegram AI

48.2 Per-User Sessions

Each Telegram user receives their own Frappe session.

The client does not maintain a shared cookie jar.

48.3 Read-Only by Design

The chatbot intentionally exposes only read-oriented operations.

This reduces the impact of incorrect AI interpretation and keeps the first version focused on information retrieval.

48.4 Metadata Before Query

When field information is uncertain:

DocType
  |
  v
describe_doctype
  |
  v
validate field
  |
  v
query

This is preferable to allowing the AI to invent Frappe field names.

48.5 Bounded AI Tool Loop

The number of tool-call rounds is configurable.

Default:

6 rounds

If the budget is exhausted, the agent requests a final response using the information already gathered.

48.6 Bounded Context

Both tool-result size and conversation memory are limited.

This controls:

  • AI context size;
  • response latency;
  • unnecessary data transfer;
  • token consumption.

49. Current Implementation Status

Implementation status: Implemented in the supplied frappe_telegram_ai project.

The supplied project contains the complete application structure for:

  • Telegram bot handling;
  • Frappe authentication;
  • encrypted sessions;
  • role-aware access;
  • AI tool calling;
  • read-only Frappe querying;
  • DocType metadata validation;
  • conversation memory;
  • security limits;
  • configuration validation;
  • startup and health checks;
  • troubleshooting documentation.

This story describes the implementation present in the supplied project. It does not claim that every acceptance-test checkbox has been freshly executed unless a separate test report records that execution.


50. Known Limitations

  1. The current bot supports a read-only Frappe workflow.
  2. Frappe two-factor-authenticated accounts are not supported by the current Telegram login flow.
  3. Business-data interaction is intentionally restricted to private Telegram chats.
  4. The selected AI model must support tool/function calling.
  5. AI-provider availability and rate limits remain external dependencies.
  6. The bot uses Telegram long polling, so only one active polling instance should use the same bot token.
  7. Changing security.encryption_key makes existing encrypted sessions unreadable and requires users to log in again.
  8. Conversation memory is intentionally bounded and is cleared by /new, /logout, or application restart.
  9. Large tool results are intentionally truncated to stay within configured AI context limits.
  10. The bot does not provide write operations such as creating or modifying Frappe documents.

51. Future Extension Possibilities

The current architecture provides a controlled foundation for additional capabilities, subject to explicit security and permission requirements.

Potential future areas include:

Current
  |
  +--> Read-only Frappe AI
        |
        +--> More read-only business tools
        +--> Better domain-specific query guidance
        +--> Additional reporting capabilities
        +--> More Frappe/ERPNext DocType intelligence

Any future write capability would require a separate security design and should not be assumed from the current read-only implementation.


52. Final End-to-End Flow

┌───────────────────────────────┐
│        Telegram User          │
└───────────────┬───────────────┘
                │
                │ /start
                v
┌───────────────────────────────┐
│      Telegram Bot Handler     │
│                               │
│  Username → Password          │
│  Password message deleted     │
└───────────────┬───────────────┘
                │
                v
┌───────────────────────────────┐
│       Authentication Service  │
└───────────────┬───────────────┘
                │
                │ Frappe Login
                v
┌───────────────────────────────┐
│        Frappe / ERPNext       │
│                               │
│ Credentials + Roles + Access  │
└───────────────┬───────────────┘
                │
                │ sid
                v
┌───────────────────────────────┐
│   Encrypted Session Storage   │
└───────────────┬───────────────┘
                │
                │ User Question
                v
┌───────────────────────────────┐
│          AI Agent             │
│                               │
│ Understand → Select Tool      │
└───────────────┬───────────────┘
                │
                v
┌───────────────────────────────┐
│   Query Validation / Metadata │
└───────────────┬───────────────┘
                │
                v
┌───────────────────────────────┐
│     Read-only Frappe Tools    │
│                               │
│ Search / Count / Aggregate    │
│ Get Record / Describe / List  │
└───────────────┬───────────────┘
                │
                │ User's own sid
                v
┌───────────────────────────────┐
│        Frappe REST API        │
│                               │
│ Frappe permissions enforced   │
└───────────────┬───────────────┘
                │
                v
┌───────────────────────────────┐
│         Tool Result           │
└───────────────┬───────────────┘
                │
                v
┌───────────────────────────────┐
│          AI Agent             │
│      Natural-language answer  │
└───────────────┬───────────────┘
                │
                v
┌───────────────────────────────┐
│        Telegram Response      │
└───────────────────────────────┘

53. Jira Definition of Done

The story is considered complete when:

  • Telegram bot starts successfully.
  • Configuration validation passes.
  • Frappe connectivity is verified.
  • Telegram token is verified.
  • AI provider connectivity is verified.
  • User can authenticate using Frappe credentials.
  • Passwords are not persisted.
  • Frappe sessions are encrypted at rest.
  • Frappe sessions are periodically revalidated.
  • Frappe roles/permissions control accessible data.
  • Natural-language questions can invoke the read-only toolset.
  • Tool arguments are validated against actual Frappe metadata.
  • Search/count/aggregate/get-record workflows operate correctly.
  • AI cannot perform write operations.
  • Conversation memory works within configured limits.
  • Rate limiting is active.
  • Login throttling is active.
  • Long Telegram responses are split safely.
  • Logout clears the application session.
  • Private-chat restriction works.
  • Error handling provides controlled user-facing messages.
  • Production configuration is protected from source control.
  • Only one Telegram polling instance is deployed per bot token.

54. Reference Commands

Install

python -m venv .venv

Activate — Windows

.\.venv\Scripts\Activate.ps1

Activate — Linux/macOS

source .venv/bin/activate

Install Dependencies

pip install -r requirements.txt

Generate Encryption Key

python main.py genkey

Validate Configuration and Services

python main.py check

Start Bot

python main.py

55. Source Project Reference

Project:
frappe_telegram_ai

Main entry point:
main.py

Configuration:
config/config.yaml
config/config.example.yaml

Runtime:
app/runtime.py

Telegram:
app/bot/

AI:
app/ai/
app/agent/

Frappe:
app/frappe/

Authentication:
app/auth/

Security:
app/security/

Persistent sessions:
app/storage/

Documentation:
docs/ACCESS_CONTROL.md
docs/TROUBLESHOOTING.md

The story is based on the implementation and documentation supplied in the frappe_telegram_ai project. It intentionally distinguishes implemented behaviour from future possibilities and does not introduce write capabilities that are not present in the supplied code.


Files

README.md (4.53 KB) README.md Rajesh Gotur, 09/30/2026 01:15 PM

RG Updated by Rajesh Gotur 22 days ago Actions #1

  • Status changed from New to Closed
Actions

Also available in: PDF Atom