chatflow-agent 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. chatflow_agent-0.1.0/.github/workflows/publish.yml +44 -0
  2. chatflow_agent-0.1.0/.github/workflows/test.yml +38 -0
  3. chatflow_agent-0.1.0/.gitignore +33 -0
  4. chatflow_agent-0.1.0/LICENSE +21 -0
  5. chatflow_agent-0.1.0/PKG-INFO +564 -0
  6. chatflow_agent-0.1.0/README.md +522 -0
  7. chatflow_agent-0.1.0/examples/cli_multiagent.py +52 -0
  8. chatflow_agent-0.1.0/examples/multi_provider_swarm.py +66 -0
  9. chatflow_agent-0.1.0/examples/telegram_triage.py +57 -0
  10. chatflow_agent-0.1.0/examples/whatsapp_service.py +64 -0
  11. chatflow_agent-0.1.0/pyproject.toml +92 -0
  12. chatflow_agent-0.1.0/src/chatflow_agent/__init__.py +57 -0
  13. chatflow_agent-0.1.0/src/chatflow_agent/channels/__init__.py +14 -0
  14. chatflow_agent-0.1.0/src/chatflow_agent/channels/base.py +58 -0
  15. chatflow_agent-0.1.0/src/chatflow_agent/channels/cli.py +62 -0
  16. chatflow_agent-0.1.0/src/chatflow_agent/channels/telegram.py +115 -0
  17. chatflow_agent-0.1.0/src/chatflow_agent/channels/whatsapp.py +213 -0
  18. chatflow_agent-0.1.0/src/chatflow_agent/core/__init__.py +18 -0
  19. chatflow_agent-0.1.0/src/chatflow_agent/core/agent.py +135 -0
  20. chatflow_agent-0.1.0/src/chatflow_agent/core/engine.py +5 -0
  21. chatflow_agent-0.1.0/src/chatflow_agent/core/engines/__init__.py +16 -0
  22. chatflow_agent-0.1.0/src/chatflow_agent/core/engines/anthropic.py +151 -0
  23. chatflow_agent-0.1.0/src/chatflow_agent/core/engines/base.py +44 -0
  24. chatflow_agent-0.1.0/src/chatflow_agent/core/engines/factory.py +75 -0
  25. chatflow_agent-0.1.0/src/chatflow_agent/core/engines/gemini.py +132 -0
  26. chatflow_agent-0.1.0/src/chatflow_agent/core/engines/openai_compatible.py +231 -0
  27. chatflow_agent-0.1.0/src/chatflow_agent/core/memory.py +107 -0
  28. chatflow_agent-0.1.0/src/chatflow_agent/core/runner.py +225 -0
  29. chatflow_agent-0.1.0/src/chatflow_agent/core/tools.py +152 -0
  30. chatflow_agent-0.1.0/src/chatflow_agent/exceptions.py +38 -0
  31. chatflow_agent-0.1.0/src/chatflow_agent/py.typed +1 -0
  32. chatflow_agent-0.1.0/src/chatflow_agent/types.py +65 -0
  33. chatflow_agent-0.1.0/tests/__init__.py +1 -0
  34. chatflow_agent-0.1.0/tests/test_agent.py +90 -0
  35. chatflow_agent-0.1.0/tests/test_cli_channel.py +65 -0
  36. chatflow_agent-0.1.0/tests/test_memory.py +94 -0
  37. chatflow_agent-0.1.0/tests/test_multi_engine.py +240 -0
  38. chatflow_agent-0.1.0/tests/test_resilience.py +191 -0
  39. chatflow_agent-0.1.0/tests/test_runner.py +143 -0
  40. chatflow_agent-0.1.0/tests/test_telegram.py +82 -0
  41. chatflow_agent-0.1.0/tests/test_tools.py +101 -0
  42. chatflow_agent-0.1.0/tests/test_types.py +102 -0
  43. chatflow_agent-0.1.0/tests/test_whatsapp.py +118 -0
@@ -0,0 +1,44 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ push:
7
+ tags:
8
+ - "v*"
9
+
10
+ jobs:
11
+ build-and-publish:
12
+ name: Build and publish to PyPI
13
+ runs-on: ubuntu-latest
14
+ environment:
15
+ name: pypi
16
+ url: https://pypi.org/p/chatflow-agent
17
+ permissions:
18
+ id-token: write # Mandatory for PyPI Trusted Publishing (OIDC)
19
+ contents: read
20
+
21
+ steps:
22
+ - name: Checkout repository
23
+ uses: actions/checkout@v4
24
+
25
+ - name: Set up Python
26
+ uses: actions/setup-python@v5
27
+ with:
28
+ python-version: "3.11"
29
+
30
+ - name: Install build tooling
31
+ run: |
32
+ python -m pip install --upgrade pip
33
+ pip install build twine
34
+
35
+ - name: Build sdist and wheel
36
+ run: python -m build
37
+
38
+ - name: Validate distribution artifacts
39
+ run: twine check dist/*
40
+
41
+ - name: Publish package distributions to PyPI
42
+ uses: pypa/gh-action-pypi-publish@release/v1
43
+ with:
44
+ packages-dir: dist/
@@ -0,0 +1,38 @@
1
+ name: Test and Lint
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ name: Test on Python ${{ matrix.python-version }} (${{ matrix.os }})
12
+ runs-on: ${{ matrix.os }}
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ os: [ubuntu-latest, windows-latest]
17
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
18
+
19
+ steps:
20
+ - name: Checkout code
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Set up Python ${{ matrix.python-version }}
24
+ uses: actions/setup-python@v5
25
+ with:
26
+ python-version: ${{ matrix.python-version }}
27
+ cache: "pip"
28
+
29
+ - name: Install dependencies
30
+ run: |
31
+ python -m pip install --upgrade pip
32
+ pip install -e .[all,dev]
33
+
34
+ - name: Run Ruff Lint Check
35
+ run: ruff check .
36
+
37
+ - name: Run Pytest Suite
38
+ run: pytest -v
@@ -0,0 +1,33 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+ .installed.cfg
11
+ *.egg
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ ENV/
17
+
18
+ # Testing and linting
19
+ .pytest_cache/
20
+ .ruff_cache/
21
+ .mypy_cache/
22
+ .coverage
23
+ htmlcov/
24
+
25
+ # IDE files
26
+ .vscode/
27
+ .idea/
28
+ *.swp
29
+ *.swo
30
+
31
+ # Environment variables
32
+ .env
33
+ .env.*
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gustavo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,564 @@
1
+ Metadata-Version: 2.5
2
+ Name: chatflow-agent
3
+ Version: 0.1.0
4
+ Summary: Lightweight, async multi-agent framework with native handoffs for Gemini, Gemma, Grok, OpenAI & Claude.
5
+ Author-email: Gustavo <developer@example.com>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Keywords: ai,claude,gemini,gemma,grok,handoff,llm,multi-agent,openai,swarm,telegram,webhook,whatsapp
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Communications :: Chat
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: google-genai>=0.1.1
22
+ Requires-Dist: httpx>=0.27.0
23
+ Requires-Dist: pydantic>=2.6.0
24
+ Provides-Extra: all
25
+ Requires-Dist: fastapi>=0.110.0; extra == 'all'
26
+ Requires-Dist: python-telegram-bot>=21.0; extra == 'all'
27
+ Requires-Dist: uvicorn>=0.29.0; extra == 'all'
28
+ Provides-Extra: dev
29
+ Requires-Dist: mypy>=1.9.0; extra == 'dev'
30
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
31
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
33
+ Provides-Extra: telegram
34
+ Requires-Dist: python-telegram-bot>=21.0; extra == 'telegram'
35
+ Provides-Extra: webhook
36
+ Requires-Dist: fastapi>=0.110.0; extra == 'webhook'
37
+ Requires-Dist: uvicorn>=0.29.0; extra == 'webhook'
38
+ Provides-Extra: whatsapp
39
+ Requires-Dist: fastapi>=0.110.0; extra == 'whatsapp'
40
+ Requires-Dist: uvicorn>=0.29.0; extra == 'whatsapp'
41
+ Description-Content-Type: text/markdown
42
+
43
+ # chatflow-agent
44
+
45
+ [![PyPI version](https://img.shields.io/pypi/v/chatflow-agent.svg)](https://pypi.org/project/chatflow-agent/)
46
+ [![Python versions](https://img.shields.io/pypi/pyversions/chatflow-agent.svg)](https://pypi.org/project/chatflow-agent/)
47
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
48
+
49
+ > **Lightweight, async multi-agent framework with native handoffs for real-world channels.**
50
+ > Supports **Google Gemini**, **Google Gemma (Local)**, **xAI Grok**, **OpenAI (GPT-4o)**, and **Anthropic Claude**.
51
+ > Connect autonomous swarms directly to **WhatsApp**, **Telegram**, **Webhooks**, and **CLI**.
52
+ >
53
+ > *Framework multiagente asíncrono y liviano con transferencias nativas (handoffs) para canales reales.*
54
+ > *Compatible con **Google Gemini**, **Google Gemma (Local)**, **xAI Grok**, **OpenAI** y **Anthropic Claude**.*
55
+ > *Conecta equipos de agentes autónomos a **WhatsApp**, **Telegram**, **Webhooks** y **Terminal**.*
56
+
57
+ ---
58
+
59
+ ## English Documentation
60
+
61
+ ### Table of Contents
62
+ 1. [Overview & Architecture](#overview--architecture)
63
+ 2. [API Keys & Configuration](#api-keys--configuration)
64
+ 3. [Installation](#installation)
65
+ 4. [Step-by-Step Quickstarts](#step-by-step-quickstarts)
66
+ - [A. Cloud LLM (Gemini / OpenAI / Claude)](#a-cloud-llm-quickstart)
67
+ - [B. 100% Free Local LLM (Google Gemma via Ollama)](#b-local-offline-quickstart-google-gemma)
68
+ - [C. Multi-Agent Swarm with Handoffs](#c-multi-agent-swarm-with-handoffs)
69
+ 5. [Channel Connectors](#channel-connectors)
70
+ - [WhatsApp (Meta Cloud API)](#whatsapp-channel-meta-cloud-api)
71
+ - [Telegram Bot](#telegram-channel)
72
+ - [Interactive Terminal (CLI)](#interactive-terminal-cli)
73
+ 6. [Session Memory & Persistence](#session-memory--persistence)
74
+ 7. [Guía Completa en Español](#guía-completa-en-español)
75
+
76
+ ---
77
+
78
+ ### Overview & Architecture
79
+
80
+ `chatflow-agent` is designed for developers who want the multi-agent power of OpenAI Swarm without being locked into a single provider, combined with turnkey connectors for messaging platforms like **WhatsApp** and **Telegram**.
81
+
82
+ ```
83
+ [ WhatsApp / Telegram / Webhook / CLI ]
84
+ │
85
+ ▼
86
+ ┌───────────────────┐
87
+ │ Runner │ ◄─── Session Memory (per-user history)
88
+ └─────────┬─────────┘
89
+ │
90
+ ┌─────────┴─────────┐
91
+ ▼ ▼
92
+ ┌──────────────┐ ┌──────────────┐
93
+ │ Triage Agent │───►│ Spec. Agent │ (Autonomous Peer Handoff)
94
+ │ (Gemini/Grok)│ │ (Local Gemma)│
95
+ └──────────────┘ └──────────────┘
96
+ │ │
97
+ ▼ ▼
98
+ [@agent.tool] [@agent.tool]
99
+ ```
100
+
101
+ ---
102
+
103
+ ### API Keys & Configuration
104
+
105
+ You can provide API keys using any of the following 3 methods:
106
+
107
+ #### 1. Direct in Python Code (Easiest)
108
+ Pass your API key directly when instantiating the `Runner` or `Agent`:
109
+ ```python
110
+ # Pass to Runner (used by all agents with that provider)
111
+ runner = Runner(starting_agent=my_agent, api_key="AIzaSyYourGeminiKey")
112
+
113
+ # Or pass directly to a specific Agent:
114
+ grok_agent = Agent(
115
+ name="GrokSpecialist",
116
+ provider="grok",
117
+ api_key="xai-your-key-here",
118
+ instructions="..."
119
+ )
120
+ ```
121
+
122
+ #### 2. Using a `.env` File
123
+ Create a `.env` file in your project root:
124
+ ```env
125
+ # Google Gemini (Get free key at https://aistudio.google.com/)
126
+ GEMINI_API_KEY="AIzaSy..."
127
+
128
+ # OpenAI (https://platform.openai.com/api-keys)
129
+ OPENAI_API_KEY="sk-..."
130
+
131
+ # xAI Grok (https://console.x.ai/)
132
+ XAI_API_KEY="xai-..."
133
+
134
+ # Anthropic Claude (https://console.anthropic.com/)
135
+ ANTHROPIC_API_KEY="sk-ant-..."
136
+ ```
137
+ Then in your script:
138
+ ```python
139
+ from dotenv import load_dotenv
140
+ load_dotenv()
141
+ ```
142
+
143
+ #### 3. Via Terminal Environment Variables
144
+ * **Windows (PowerShell):**
145
+ ```powershell
146
+ $env:GEMINI_API_KEY="AIzaSy..."
147
+ ```
148
+ * **Linux / macOS (Bash/Zsh):**
149
+ ```bash
150
+ export GEMINI_API_KEY="AIzaSy..."
151
+ ```
152
+
153
+ #### Provider Credential Reference Table
154
+
155
+ | Provider | Where to get Key | Environment Variable | In-Code Parameter | Free Tier Available? |
156
+ | :--- | :--- | :--- | :--- | :--- |
157
+ | **Google Gemini** | [Google AI Studio](https://aistudio.google.com/app/apikey) | `GEMINI_API_KEY` | `api_key="..."` | **Yes (Generous free tier)** |
158
+ | **Google Gemma (Local)** | [Ollama](https://ollama.com) | *None needed* | `provider="ollama"` | **100% Free & Offline** |
159
+ | **xAI Grok** | [xAI Console](https://console.x.ai/) | `XAI_API_KEY` | `api_key="..."` | Pay-as-you-go |
160
+ | **OpenAI** | [OpenAI Platform](https://platform.openai.com/) | `OPENAI_API_KEY` | `api_key="..."` | Pay-as-you-go |
161
+ | **Anthropic Claude** | [Anthropic Console](https://console.anthropic.com/) | `ANTHROPIC_API_KEY` | `api_key="..."` | Pay-as-you-go |
162
+
163
+ ---
164
+
165
+ ### Installation
166
+
167
+ Install only what you need:
168
+
169
+ ```bash
170
+ # Core framework (Gemini, Gemma, Grok, OpenAI, Claude, CLI)
171
+ pip install chatflow-agent
172
+
173
+ # With WhatsApp Webhook connector (FastAPI + Uvicorn)
174
+ pip install "chatflow-agent[whatsapp]"
175
+
176
+ # With Telegram Bot connector (python-telegram-bot)
177
+ pip install "chatflow-agent[telegram]"
178
+
179
+ # Complete bundle (All channels & dev tools)
180
+ pip install "chatflow-agent[all]"
181
+ ```
182
+
183
+ ---
184
+
185
+ ### Step-by-Step Quickstarts
186
+
187
+ #### A. Cloud LLM Quickstart
188
+
189
+ Save as `bot.py` and run with `python bot.py`:
190
+
191
+ ```python
192
+ import asyncio
193
+ from chatflow_agent import Agent, Runner
194
+
195
+ # Define your agent
196
+ support_agent = Agent(
197
+ name="SupportBot",
198
+ model="gemini-2.5-flash", # Or provider="openai", model="gpt-4o-mini"
199
+ instructions="You are a helpful customer support agent for a retail store.",
200
+ )
201
+
202
+ # Register business tools using Python decorators and type hints
203
+ @support_agent.tool
204
+ def get_order_status(order_id: str) -> dict:
205
+ """Look up shipping and tracking status for an order."""
206
+ return {
207
+ "order_id": order_id,
208
+ "status": "Out for delivery",
209
+ "carrier": "FedEx",
210
+ "eta": "Today before 6:00 PM",
211
+ }
212
+
213
+ async def main():
214
+ # Pass api_key directly or set GEMINI_API_KEY in environment/.env
215
+ runner = Runner(starting_agent=support_agent)
216
+
217
+ response = await runner.run_async(
218
+ session_id="user_session_101",
219
+ user_message="Hi, can you check the status of my order #FDX-8821?",
220
+ )
221
+ print(f"[{response.active_agent_name}]: {response.content}")
222
+
223
+ if __name__ == "__main__":
224
+ asyncio.run(main())
225
+ ```
226
+
227
+ ---
228
+
229
+ #### B. Local Offline Quickstart (Google Gemma)
230
+
231
+ Run 100% locally on your machine with **zero API costs** and **total privacy** using [Ollama](https://ollama.com):
232
+
233
+ 1. Start Ollama with Gemma: `ollama run gemma2:9b`
234
+ 2. Run this script:
235
+
236
+ ```python
237
+ import asyncio
238
+ from chatflow_agent import Agent, Runner
239
+
240
+ # Connects to http://localhost:11434/v1 with no API key required
241
+ local_agent = Agent(
242
+ name="LocalAnalyst",
243
+ provider="ollama",
244
+ model="gemma2:9b",
245
+ instructions="You analyze confidential financial reports locally.",
246
+ )
247
+
248
+ @local_agent.tool
249
+ def calculate_vat(subtotal: float, rate_percentage: float = 21.0) -> dict:
250
+ """Calculate VAT tax and total amount."""
251
+ vat = subtotal * (rate_percentage / 100.0)
252
+ return {"subtotal": subtotal, "vat": round(vat, 2), "total": round(subtotal + vat, 2)}
253
+
254
+ async def main():
255
+ runner = Runner(starting_agent=local_agent)
256
+ response = await runner.run_async(
257
+ session_id="local_user",
258
+ user_message="Calculate VAT for a $450 invoice.",
259
+ )
260
+ print(f"[{response.active_agent_name}]: {response.content}")
261
+
262
+ if __name__ == "__main__":
263
+ asyncio.run(main())
264
+ ```
265
+
266
+ ---
267
+
268
+ #### C. Multi-Agent Swarm with Handoffs
269
+
270
+ Agents can autonomously delegate tasks to specialists:
271
+
272
+ ```python
273
+ import asyncio
274
+ from chatflow_agent import Agent, Runner
275
+
276
+ # 1. Specialist: Technical Support
277
+ tech_agent = Agent(
278
+ name="TechSupport",
279
+ model="gemini-2.5-flash",
280
+ instructions="You diagnose hardware and software issues.",
281
+ )
282
+
283
+ @tech_agent.tool
284
+ def run_diagnostics(device_id: str) -> str:
285
+ """Checks device telemetry."""
286
+ return f"Device {device_id}: All sensors nominal. Firmware v2.1 up to date."
287
+
288
+ # 2. Specialist: Billing & Invoices
289
+ billing_agent = Agent(
290
+ name="Billing",
291
+ model="gemini-2.5-flash",
292
+ instructions="You handle invoices, subscriptions, and refund requests.",
293
+ )
294
+
295
+ # 3. Receptionist (Frontline) with handoffs to specialists
296
+ concierge = Agent(
297
+ name="Reception",
298
+ model="gemini-2.5-flash",
299
+ instructions="Greet customers and transfer to TechSupport or Billing as required.",
300
+ handoffs=[tech_agent, billing_agent], # Swarm handoff capability
301
+ )
302
+
303
+ async def main():
304
+ runner = Runner(starting_agent=concierge)
305
+
306
+ # The model detects it is a technical query and hands off to TechSupport automatically
307
+ resp = await runner.run_async(
308
+ session_id="client_77",
309
+ user_message="My device DEV-42 is blinking red. Can you run diagnostics?",
310
+ )
311
+ print(f"Active Agent: {resp.active_agent_name}") # Output: TechSupport
312
+ print(f"Response: {resp.content}")
313
+
314
+ if __name__ == "__main__":
315
+ asyncio.run(main())
316
+ ```
317
+
318
+ ---
319
+
320
+ ### Channel Connectors
321
+
322
+ #### WhatsApp Channel (Meta Cloud API)
323
+
324
+ Run a production webhook server compatible with Meta WhatsApp Business Cloud API:
325
+
326
+ ```python
327
+ from chatflow_agent import Agent, Runner
328
+ from chatflow_agent.channels import WhatsAppChannel
329
+
330
+ agent = Agent(name="WhatsAppConcierge", instructions="Answer customer inquiries.")
331
+ runner = Runner(starting_agent=agent)
332
+
333
+ channel = WhatsAppChannel(
334
+ verify_token="my_custom_webhook_secret", # Verification token configured in Meta App
335
+ access_token="EAA...", # Meta Permanent/System User Token
336
+ phone_number_id="109876543210987", # WhatsApp Phone Number ID from Meta Dashboard
337
+ fallback_message="We are experiencing a temporary delay. Please try again shortly.",
338
+ unsupported_media_message="Currently I can only process text messages.",
339
+ )
340
+ channel.attach(runner)
341
+
342
+ if __name__ == "__main__":
343
+ # Exposes GET /webhook (verification handshake) and POST /webhook (incoming messages)
344
+ channel.run(host="0.0.0.0", port=8000)
345
+ ```
346
+
347
+ > **Testing locally?** Use a tunnel like [ngrok](https://ngrok.com) (`ngrok http 8000`) or Cloudflare Tunnels to provide Meta with a public HTTPS URL (`https://your-domain.ngrok-free.app/webhook`).
348
+
349
+ ---
350
+
351
+ #### Telegram Channel
352
+
353
+ ```python
354
+ from chatflow_agent import Agent, Runner
355
+ from chatflow_agent.channels import TelegramChannel
356
+
357
+ agent = Agent(name="TelegramBot", instructions="You assist Telegram users.")
358
+ runner = Runner(starting_agent=agent)
359
+
360
+ channel = TelegramChannel(
361
+ token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11", # From @BotFather
362
+ fallback_message="Sorry, a temporary issue occurred. Please retry in a few moments.",
363
+ )
364
+ channel.attach(runner)
365
+
366
+ if __name__ == "__main__":
367
+ # Runs async polling; automatically handles /start, /reset, and typing indicators
368
+ channel.run()
369
+ ```
370
+
371
+ ---
372
+
373
+ #### Interactive Terminal (CLI)
374
+
375
+ Test swarms in your terminal with colored chat output:
376
+
377
+ ```python
378
+ from chatflow_agent import Agent, Runner
379
+ from chatflow_agent.channels import CLIChannel
380
+
381
+ agent = Agent(name="TerminalAssistant", instructions="Answer user questions concisely.")
382
+ runner = Runner(starting_agent=agent)
383
+
384
+ channel = CLIChannel(session_id="dev_test")
385
+ channel.attach(runner)
386
+ channel.run()
387
+ ```
388
+
389
+ ---
390
+
391
+ ### Production Resilience & Concurrency
392
+
393
+ ChatFlow includes built-in safeguards engineered specifically for real-world messaging traffic:
394
+
395
+ * **Per-Session Concurrency Lock (`asyncio.Lock`):** When a user sends multiple messages in rapid succession (e.g., three WhatsApp voice transcriptions or quick texts in 2 seconds), an async lock guarantees FIFO execution. Turns are processed in strict sequential order, preventing race conditions, overlapping tool executions, or corrupted conversation histories.
396
+ * **Meta Anti-500 Error Shield:** Meta's webhook infrastructure retries delivery aggressively if your endpoint returns HTTP 500. `WhatsAppChannel` catches any upstream LLM outages or rate limits, returns **HTTP 200** to Meta to prevent retry storms, dispatches the configured `fallback_message` to the user, and logs clean diagnostic details.
397
+ * **Unsupported Media Handling:** Audio voice notes, photos, and PDF files are safely intercepted with `unsupported_media_message` without throwing unhandled exceptions or disrupting ongoing chat sessions.
398
+
399
+ ---
400
+
401
+ ### Session Memory & Persistence
402
+
403
+ Every conversation turn is tracked by `SessionContext`:
404
+ * **Sliding Window Pruning:** Prevents LLM context overflow by keeping the last `max_messages` (default: 50).
405
+ * **Active Agent State:** If a handoff occurs (e.g., from `Reception` to `Billing`), subsequent messages from that user automatically continue talking to `Billing`.
406
+ * **Resetting:** Call `session.clear()` or send `/reset` on Telegram to start fresh.
407
+
408
+ ---
409
+
410
+ ## Guía Completa en Español
411
+
412
+ ### Configuración de API Keys (Claves de Acceso)
413
+
414
+ Puedes configurar tus credenciales de cualquiera de estas **3 formas**:
415
+
416
+ #### Opción 1: Directo en tu Código Python (La más fácil)
417
+ Pasa tu clave directamente al instanciar el `Runner` o el `Agent`:
418
+ ```python
419
+ # Pasándola al Runner (la usan todos los agentes de ese proveedor):
420
+ runner = Runner(starting_agent=mi_agente, api_key="AIzaSyTuClaveDeGemini")
421
+
422
+ # O a un agente específico:
423
+ agente_grok = Agent(
424
+ name="Grok",
425
+ provider="grok",
426
+ api_key="xai-tu-clave-aqui",
427
+ instructions="..."
428
+ )
429
+ ```
430
+
431
+ #### Opción 2: Usando un Archivo `.env` (Recomendado en Producción)
432
+ Crea un archivo `.env` en la raíz de tu proyecto:
433
+ ```env
434
+ # Google Gemini (Obtén tu clave gratis en https://aistudio.google.com/)
435
+ GEMINI_API_KEY="AIzaSy..."
436
+
437
+ # OpenAI (https://platform.openai.com/api-keys)
438
+ OPENAI_API_KEY="sk-..."
439
+
440
+ # xAI Grok (https://console.x.ai/)
441
+ XAI_API_KEY="xai-..."
442
+
443
+ # Anthropic Claude (https://console.anthropic.com/)
444
+ ANTHROPIC_API_KEY="sk-ant-..."
445
+ ```
446
+ Y en tu código Python:
447
+ ```python
448
+ from dotenv import load_dotenv
449
+ load_dotenv()
450
+ ```
451
+
452
+ #### Opción 3: Variables de Entorno en la Terminal
453
+ * **En Windows PowerShell:**
454
+ ```powershell
455
+ $env:GEMINI_API_KEY="AIzaSy..."
456
+ ```
457
+ * **En Linux o macOS:**
458
+ ```bash
459
+ export GEMINI_API_KEY="AIzaSy..."
460
+ ```
461
+
462
+ ---
463
+
464
+ ### Tabla Comparativa de Proveedores y Claves
465
+
466
+ | Proveedor | Dónde obtener la clave | Variable de Entorno | Parámetro en Python | ¿Capa Gratuita? |
467
+ | :--- | :--- | :--- | :--- | :--- |
468
+ | **Google Gemini** | [Google AI Studio](https://aistudio.google.com/app/apikey) | `GEMINI_API_KEY` | `api_key="..."` | **Sí (Muy generosa)** |
469
+ | **Google Gemma (Local)** | [Ollama](https://ollama.com) | *No requiere clave* | `provider="ollama"` | **100% Gratis y Offline** |
470
+ | **xAI Grok** | [xAI Console](https://console.x.ai/) | `XAI_API_KEY` | `api_key="..."` | Pago por uso |
471
+ | **OpenAI** | [OpenAI Platform](https://platform.openai.com/) | `OPENAI_API_KEY` | `api_key="..."` | Pago por uso |
472
+ | **Anthropic Claude** | [Anthropic Console](https://console.anthropic.com/) | `ANTHROPIC_API_KEY` | `api_key="..."` | Pago por uso |
473
+
474
+ ---
475
+
476
+ ### Ejemplo Rápido: De 0 a Funcionando en 2 Minutos
477
+
478
+ Crea un archivo `mi_asistente.py`:
479
+
480
+ ```python
481
+ import asyncio
482
+ from chatflow_agent import Agent, Runner
483
+
484
+ # 1. Definir el agente con sus herramientas
485
+ soporte = Agent(
486
+ name="SoporteClientes",
487
+ model="gemini-2.5-flash",
488
+ instructions="Eres un asistente cordial de atención al cliente.",
489
+ )
490
+
491
+ @soporte.tool
492
+ def consultar_stock(articulo: str) -> dict:
493
+ """Consulta la disponibilidad y precio de un artículo en inventario."""
494
+ catalogo = {
495
+ "laptop": {"stock": 5, "precio": "$1,200"},
496
+ "teclado": {"stock": 18, "precio": "$45"},
497
+ "mouse": {"stock": 30, "precio": "$25"},
498
+ }
499
+ return catalogo.get(articulo.lower(), {"stock": 0, "precio": "No disponible"})
500
+
501
+ # 2. Ejecutar la conversación
502
+ async def main():
503
+ # Puedes pasar tu api_key aquí directamente si no usas variables de terminal:
504
+ # runner = Runner(starting_agent=soporte, api_key="AIzaSy...")
505
+ runner = Runner(starting_agent=soporte)
506
+
507
+ respuesta = await runner.run_async(
508
+ session_id="cliente_whatsapp_1",
509
+ user_message="Hola, ¿tienen stock de la laptop y a cuánto está?",
510
+ )
511
+ print(f"[{respuesta.active_agent_name}]: {respuesta.content}")
512
+
513
+ if __name__ == "__main__":
514
+ asyncio.run(main())
515
+ ```
516
+
517
+ Para ejecutar:
518
+ ```bash
519
+ python mi_asistente.py
520
+ ```
521
+
522
+ ---
523
+
524
+ ### Ejemplo: Servidor de WhatsApp en Producción
525
+
526
+ Crea `servicio_whatsapp.py`:
527
+
528
+ ```python
529
+ from chatflow_agent import Agent, Runner
530
+ from chatflow_agent.channels import WhatsAppChannel
531
+
532
+ agente_ventas = Agent(
533
+ name="VentasWhatsApp",
534
+ model="gemini-2.5-flash",
535
+ instructions="Ayudas a los clientes a cotizar y realizar compras.",
536
+ )
537
+
538
+ runner = Runner(starting_agent=agente_ventas)
539
+
540
+ # Conector oficial para Meta Cloud API con resiliencia de produccion
541
+ servidor_whatsapp = WhatsAppChannel(
542
+ verify_token="tu_token_verificacion_meta", # Configurado en Meta Developers
543
+ access_token="EAA...", # Token de acceso de Meta
544
+ phone_number_id="102938475610293", # ID del numero de WhatsApp Business
545
+ fallback_message="Disculpa, estamos experimentando una demora temporal. Por favor intenta en unos momentos.",
546
+ unsupported_media_message="Por el momento solo puedo procesar mensajes de texto.",
547
+ )
548
+ servidor_whatsapp.attach(runner)
549
+
550
+ if __name__ == "__main__":
551
+ # Levanta el webhook en http://localhost:8000/webhook
552
+ servidor_whatsapp.run(host="0.0.0.0", port=8000)
553
+ ```
554
+
555
+ ### Resiliencia y Concurrencia en Produccion
556
+
557
+ * **Candado de Concurrencia (`asyncio.Lock`):** Si un cliente envia 3 mensajes seguidos en WhatsApp o Telegram, se encolan y procesan en estricto orden FIFO por usuario. Nunca se mezclan turnos ni se corrompe el historial.
558
+ * **Escudo Anti-500 en WhatsApp:** Si la IA tiene una microcaida o se agota la cuota del proveedor, el webhook responde **HTTP 200** a Meta (evitando bombardeos de reintentos) y le envia al usuario un mensaje de contingencia amigable (`fallback_message`).
559
+ * **Filtro de Mensajes Multimedia:** Audios, fotos y documentos son interceptados con un aviso claro (`unsupported_media_message`) sin interrumpir la sesion.
560
+
561
+ ---
562
+
563
+ ## License
564
+ Distributed under the **MIT License**.