TeLLMgramBot 3.13.1__tar.gz → 3.13.3__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.
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/PKG-INFO +11 -10
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/README.md +10 -9
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/TeLLMgramBot.py +12 -15
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/initialize.py +77 -84
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/tools.py +4 -4
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot.egg-info/PKG-INFO +11 -10
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/setup.py +1 -1
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/LICENSE +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/__init__.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/archive.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/conversation.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/database.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/message_handlers.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/models.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/providers/__init__.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/providers/anthropic_provider.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/providers/base.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/providers/factory.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/providers/openai_provider.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/utils.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot/web_utils.py +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot.egg-info/SOURCES.txt +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot.egg-info/dependency_links.txt +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot.egg-info/requires.txt +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/TeLLMgramBot.egg-info/top_level.txt +0 -0
- {tellmgrambot-3.13.1 → tellmgrambot-3.13.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: TeLLMgramBot
|
|
3
|
-
Version: 3.13.
|
|
3
|
+
Version: 3.13.3
|
|
4
4
|
Summary: LLM-powered Telegram bot (OpenAI + Anthropic)
|
|
5
5
|
Home-page: https://github.com/Digital-Heresy/TeLLMgramBot
|
|
6
6
|
Author: Digital Heresy
|
|
@@ -82,11 +82,11 @@ TeLLMgramBot creates the following directories:
|
|
|
82
82
|
- `test_personality.prmpt` - Sample bot personality (multi-provider, can be renamed)
|
|
83
83
|
- `url_analysis.prmpt` - URL summarization prompt template
|
|
84
84
|
- A system appendix is automatically appended to every persona at runtime, teaching the LLM about cross-chat memory and search behavior. User messages include speaker annotations with chat context and timestamps so the LLM always knows who is speaking, in which chat, and when.
|
|
85
|
-
- **`logs`** - Bot instance logs (one per startup, named after the bot's Telegram username or `
|
|
86
|
-
- Logs include anonymized Telegram IDs for privacy. Console shows INFO-level TeLLMgramBot messages only, prefixed with an `[identity label]` (the bot's Telegram username by default, or `
|
|
85
|
+
- **`logs`** - Bot instance logs (one per startup, named after the bot's Telegram username or `instance_name` config, e.g. `my_bot_2026-03-29_10-30-45.log`)
|
|
86
|
+
- Logs include anonymized Telegram IDs for privacy. Console shows INFO-level TeLLMgramBot messages only, prefixed with an `[identity label]` (the bot's Telegram username by default, or `instance_name` when configured).
|
|
87
87
|
- Bot keeps the 10 most recent logs per bot instance, automatically pruning older ones.
|
|
88
88
|
- Pass `-v` or `--verbose` on startup for DEBUG-level logging.
|
|
89
|
-
- **`data`** - SQLite database (default `conversations.db`, customizable via `
|
|
89
|
+
- **`data`** - SQLite database (default `conversations.db`, customizable via `instance_name` config) storing all messages, users, and chats
|
|
90
90
|
- Users manage their data via `/forget` and `/private` commands.
|
|
91
91
|
|
|
92
92
|
### Environment Variables for Paths
|
|
@@ -102,13 +102,13 @@ Override default directory locations by setting these environment variables (use
|
|
|
102
102
|
If unset, all paths default to subdirectories of the execution directory (the directory containing your entry-point script).
|
|
103
103
|
|
|
104
104
|
## API Keys
|
|
105
|
-
TeLLMgramBot supports four API keys,
|
|
105
|
+
TeLLMgramBot supports four API keys. OpenAI, Anthropic, and VirusTotal keys load from environment variables or `.key` files. The Telegram key loads from `telegram_api_key` in `config.yaml` or its env var (no `.key` file):
|
|
106
106
|
|
|
107
|
-
| Key | Env Var | File | When required |
|
|
108
|
-
|
|
107
|
+
| Key | Env Var | File/Config | When required |
|
|
108
|
+
|-----|---------|-------------|---------------|
|
|
109
109
|
| [OpenAI](https://platform.openai.com/api-keys) | `TELLMGRAMBOT_OPENAI_API_KEY` | `openai.key` | For `gpt-*` models |
|
|
110
110
|
| [Anthropic](https://console.anthropic.com/settings/keys) | `TELLMGRAMBOT_ANTHROPIC_API_KEY` | `anthropic.key` | For `claude-*` models |
|
|
111
|
-
| [Telegram](https://t.me/BotFather) | `TELLMGRAMBOT_TELEGRAM_API_KEY` | `
|
|
111
|
+
| [Telegram](https://t.me/BotFather) | `TELLMGRAMBOT_TELEGRAM_API_KEY` | `telegram_api_key` in config.yaml | Always required |
|
|
112
112
|
| [VirusTotal](https://www.virustotal.com/gui/my-apikey) | `TELLMGRAMBOT_VIRUSTOTAL_API_KEY` | `virustotal.key` | For URL analysis |
|
|
113
113
|
|
|
114
114
|
Missing provider keys (OpenAI or Anthropic) disable chat and URL analysis but allow the bot to start. Missing VirusTotal disables URL analysis. Telegram key is required - the bot will not start without it.
|
|
@@ -151,12 +151,13 @@ When the bot is triggered in a group and about to respond (not deferring to anot
|
|
|
151
151
|
- `bot_owner`: Telegram username(s) with admin access (required, no `@`). Accepts a single string or a YAML list of usernames.
|
|
152
152
|
- `chat_model`: LLM model for conversation (e.g. `gpt-4o-mini` or `claude-sonnet-4-6`)
|
|
153
153
|
- `url_model`: LLM model for URL analysis (e.g. `gpt-4o` or `claude-haiku-4-5`)
|
|
154
|
+
- `telegram_api_key`: Telegram bot API key (required). Lookup order: TELLMGRAMBOT_TELEGRAM_API_KEY env var -> config field.
|
|
154
155
|
- `bot_nickname` / `bot_initials`: Names the bot responds to in groups
|
|
155
|
-
- `
|
|
156
|
-
- `log_name`: Optional label used for the console prefix and log filename (e.g. `MyBot` produces `[MyBot] INFO: ...` on the console and `MyBot_{timestamp}.log`); omit to use the bot's Telegram username. Useful for multi-platform deployments sharing the same config.
|
|
156
|
+
- `instance_name`: Optional label for console prefix, log filename, and database name (e.g. `MyBot` produces `[MyBot] INFO: ...` on console, `MyBot_{timestamp}.log` logs, and `MyBot.db` database); omit to use bot's Telegram username for logging and `conversations.db` for database. Use distinct names when running multiple bot instances in the same directory.
|
|
157
157
|
- `token_limit`: Max tokens (optional; defaults to model's maximum)
|
|
158
158
|
- `search_limit`: Max search results (optional; defaults to 30)
|
|
159
159
|
- `archive_days`: Days before messages are eligible for archival (optional; default 60, minimum 1). Older messages are distilled into daily summaries, then progressively compressed into monthly digests. Once archived their respective raw messages do not return to the LLM context any more, only when searching messages.
|
|
160
|
+
- `allow_local_webhooks`: Set to `true` to permit webhook/MCP URLs targeting loopback or link-local addresses (optional; default `false`). Useful when tools like Home Assistant run on the same host.
|
|
160
161
|
- `tools`: Optional list of webhook and MCP tool definitions (admin-only, private chat only). See [docs/tools.md](docs/tools.md) for schema and examples.
|
|
161
162
|
4. **Disable group privacy mode in BotFather:**
|
|
162
163
|
```
|
|
@@ -50,11 +50,11 @@ TeLLMgramBot creates the following directories:
|
|
|
50
50
|
- `test_personality.prmpt` - Sample bot personality (multi-provider, can be renamed)
|
|
51
51
|
- `url_analysis.prmpt` - URL summarization prompt template
|
|
52
52
|
- A system appendix is automatically appended to every persona at runtime, teaching the LLM about cross-chat memory and search behavior. User messages include speaker annotations with chat context and timestamps so the LLM always knows who is speaking, in which chat, and when.
|
|
53
|
-
- **`logs`** - Bot instance logs (one per startup, named after the bot's Telegram username or `
|
|
54
|
-
- Logs include anonymized Telegram IDs for privacy. Console shows INFO-level TeLLMgramBot messages only, prefixed with an `[identity label]` (the bot's Telegram username by default, or `
|
|
53
|
+
- **`logs`** - Bot instance logs (one per startup, named after the bot's Telegram username or `instance_name` config, e.g. `my_bot_2026-03-29_10-30-45.log`)
|
|
54
|
+
- Logs include anonymized Telegram IDs for privacy. Console shows INFO-level TeLLMgramBot messages only, prefixed with an `[identity label]` (the bot's Telegram username by default, or `instance_name` when configured).
|
|
55
55
|
- Bot keeps the 10 most recent logs per bot instance, automatically pruning older ones.
|
|
56
56
|
- Pass `-v` or `--verbose` on startup for DEBUG-level logging.
|
|
57
|
-
- **`data`** - SQLite database (default `conversations.db`, customizable via `
|
|
57
|
+
- **`data`** - SQLite database (default `conversations.db`, customizable via `instance_name` config) storing all messages, users, and chats
|
|
58
58
|
- Users manage their data via `/forget` and `/private` commands.
|
|
59
59
|
|
|
60
60
|
### Environment Variables for Paths
|
|
@@ -70,13 +70,13 @@ Override default directory locations by setting these environment variables (use
|
|
|
70
70
|
If unset, all paths default to subdirectories of the execution directory (the directory containing your entry-point script).
|
|
71
71
|
|
|
72
72
|
## API Keys
|
|
73
|
-
TeLLMgramBot supports four API keys,
|
|
73
|
+
TeLLMgramBot supports four API keys. OpenAI, Anthropic, and VirusTotal keys load from environment variables or `.key` files. The Telegram key loads from `telegram_api_key` in `config.yaml` or its env var (no `.key` file):
|
|
74
74
|
|
|
75
|
-
| Key | Env Var | File | When required |
|
|
76
|
-
|
|
75
|
+
| Key | Env Var | File/Config | When required |
|
|
76
|
+
|-----|---------|-------------|---------------|
|
|
77
77
|
| [OpenAI](https://platform.openai.com/api-keys) | `TELLMGRAMBOT_OPENAI_API_KEY` | `openai.key` | For `gpt-*` models |
|
|
78
78
|
| [Anthropic](https://console.anthropic.com/settings/keys) | `TELLMGRAMBOT_ANTHROPIC_API_KEY` | `anthropic.key` | For `claude-*` models |
|
|
79
|
-
| [Telegram](https://t.me/BotFather) | `TELLMGRAMBOT_TELEGRAM_API_KEY` | `
|
|
79
|
+
| [Telegram](https://t.me/BotFather) | `TELLMGRAMBOT_TELEGRAM_API_KEY` | `telegram_api_key` in config.yaml | Always required |
|
|
80
80
|
| [VirusTotal](https://www.virustotal.com/gui/my-apikey) | `TELLMGRAMBOT_VIRUSTOTAL_API_KEY` | `virustotal.key` | For URL analysis |
|
|
81
81
|
|
|
82
82
|
Missing provider keys (OpenAI or Anthropic) disable chat and URL analysis but allow the bot to start. Missing VirusTotal disables URL analysis. Telegram key is required - the bot will not start without it.
|
|
@@ -119,12 +119,13 @@ When the bot is triggered in a group and about to respond (not deferring to anot
|
|
|
119
119
|
- `bot_owner`: Telegram username(s) with admin access (required, no `@`). Accepts a single string or a YAML list of usernames.
|
|
120
120
|
- `chat_model`: LLM model for conversation (e.g. `gpt-4o-mini` or `claude-sonnet-4-6`)
|
|
121
121
|
- `url_model`: LLM model for URL analysis (e.g. `gpt-4o` or `claude-haiku-4-5`)
|
|
122
|
+
- `telegram_api_key`: Telegram bot API key (required). Lookup order: TELLMGRAMBOT_TELEGRAM_API_KEY env var -> config field.
|
|
122
123
|
- `bot_nickname` / `bot_initials`: Names the bot responds to in groups
|
|
123
|
-
- `
|
|
124
|
-
- `log_name`: Optional label used for the console prefix and log filename (e.g. `MyBot` produces `[MyBot] INFO: ...` on the console and `MyBot_{timestamp}.log`); omit to use the bot's Telegram username. Useful for multi-platform deployments sharing the same config.
|
|
124
|
+
- `instance_name`: Optional label for console prefix, log filename, and database name (e.g. `MyBot` produces `[MyBot] INFO: ...` on console, `MyBot_{timestamp}.log` logs, and `MyBot.db` database); omit to use bot's Telegram username for logging and `conversations.db` for database. Use distinct names when running multiple bot instances in the same directory.
|
|
125
125
|
- `token_limit`: Max tokens (optional; defaults to model's maximum)
|
|
126
126
|
- `search_limit`: Max search results (optional; defaults to 30)
|
|
127
127
|
- `archive_days`: Days before messages are eligible for archival (optional; default 60, minimum 1). Older messages are distilled into daily summaries, then progressively compressed into monthly digests. Once archived their respective raw messages do not return to the LLM context any more, only when searching messages.
|
|
128
|
+
- `allow_local_webhooks`: Set to `true` to permit webhook/MCP URLs targeting loopback or link-local addresses (optional; default `false`). Useful when tools like Home Assistant run on the same host.
|
|
128
129
|
- `tools`: Optional list of webhook and MCP tool definitions (admin-only, private chat only). See [docs/tools.md](docs/tools.md) for schema and examples.
|
|
129
130
|
4. **Disable group privacy mode in BotFather:**
|
|
130
131
|
```
|
|
@@ -103,7 +103,7 @@ class TelegramBot:
|
|
|
103
103
|
self.telegram['username'] = bot.username
|
|
104
104
|
self.telegram['first_name'] = bot.first_name
|
|
105
105
|
self.telegram['last_name'] = bot.last_name
|
|
106
|
-
bind_log_identity(bot.username, self.
|
|
106
|
+
bind_log_identity(bot.username, self._instance_name)
|
|
107
107
|
except Exception as e:
|
|
108
108
|
# Fail fast if the bot's identity cannot be fetched to avoid
|
|
109
109
|
# continuing with an uninitialized self.telegram['username'].
|
|
@@ -183,7 +183,7 @@ class TelegramBot:
|
|
|
183
183
|
List all registered tools available to this bot instance (admin-only, private chat only).
|
|
184
184
|
|
|
185
185
|
Shows name and description for every tool the bot exposes, including the built-in
|
|
186
|
-
search_messages tool and any webhook tools defined in config.
|
|
186
|
+
search_messages tool and any webhook tools defined in bot config. Restricted to
|
|
187
187
|
bot_owner in a private chat; any other caller receives a generic denial.
|
|
188
188
|
|
|
189
189
|
Args:
|
|
@@ -964,7 +964,7 @@ class TelegramBot:
|
|
|
964
964
|
archive_days = INIT_BOT_CONFIG['archive_days'],
|
|
965
965
|
persona_prompt = INIT_BOT_CONFIG['persona_prompt'],
|
|
966
966
|
key_status: ApiKeyStatus | None = None,
|
|
967
|
-
|
|
967
|
+
instance_name: str | None = None,
|
|
968
968
|
webhook_schemas: list | None = None,
|
|
969
969
|
webhook_defs: dict | None = None,
|
|
970
970
|
):
|
|
@@ -983,8 +983,8 @@ class TelegramBot:
|
|
|
983
983
|
persona_temp: LLM temperature (0.0-2.0). If None, defaults to 1.0.
|
|
984
984
|
persona_prompt: System prompt defining the bot's behavior and personality.
|
|
985
985
|
key_status: ApiKeyStatus object indicating available features. If None, calls init_structure().
|
|
986
|
-
|
|
987
|
-
|
|
986
|
+
instance_name: Optional label for console prefix and log file name (from bot config `instance_name`).
|
|
987
|
+
Defaults to the bot's Telegram username when not set.
|
|
988
988
|
archive_days: Days before messages are eligible for Tier 1 archival (default: 60).
|
|
989
989
|
Must be an integer >= 1; invalid values log a warning and fall back to 60.
|
|
990
990
|
Tier 2 compression triggers at archive_days * 2.
|
|
@@ -1001,7 +1001,7 @@ class TelegramBot:
|
|
|
1001
1001
|
"""
|
|
1002
1002
|
# Starting to initialize, not online yet
|
|
1003
1003
|
self._online = False
|
|
1004
|
-
self.
|
|
1004
|
+
self._instance_name = instance_name
|
|
1005
1005
|
|
|
1006
1006
|
# Bootstrap structure and logging; init_logging() is a no-op if init_structure already ran it.
|
|
1007
1007
|
self.key_status = key_status if key_status is not None else init_structure()[0]
|
|
@@ -1104,18 +1104,15 @@ class TelegramBot:
|
|
|
1104
1104
|
Side Effects:
|
|
1105
1105
|
- Calls init_structure() which creates directories, config/prompt files, and checks API keys.
|
|
1106
1106
|
- Calls discover_mcp_tools() if any 'mcp_server:' entries are in config (gracefully degrades if called from async context).
|
|
1107
|
-
-
|
|
1108
|
-
- Log identity/file label is taken from config
|
|
1107
|
+
- May log warnings (for missing config values, empty prompt, or skipped MCP discovery), but does not print a startup API key status summary.
|
|
1108
|
+
- Log identity/file label is taken from bot config `instance_name` when set; otherwise defaults to the bot's Telegram username once _tele_info() resolves.
|
|
1109
1109
|
"""
|
|
1110
1110
|
# Bootstrap directories, logging, config, prompt (with appendix), and API keys in one call.
|
|
1111
1111
|
key_status, config, prompt = init_structure(config_file, prompt_file)
|
|
1112
1112
|
|
|
1113
|
-
# Build the webhook tool registry from the optional 'tools:' block in config.
|
|
1114
|
-
allow_local = config
|
|
1115
|
-
webhook_schemas, webhook_defs = build_tool_registry(
|
|
1116
|
-
config.get('tools') or [],
|
|
1117
|
-
allow_local=allow_local,
|
|
1118
|
-
)
|
|
1113
|
+
# Build the webhook tool registry from the optional 'tools:' block in bot config.
|
|
1114
|
+
allow_local = config['allow_local_webhooks'] or False
|
|
1115
|
+
webhook_schemas, webhook_defs = build_tool_registry(config.get('tools') or [], allow_local)
|
|
1119
1116
|
|
|
1120
1117
|
# Discover MCP tools from any 'mcp_server:' entries in the tools config.
|
|
1121
1118
|
mcp_entries = [
|
|
@@ -1148,7 +1145,7 @@ class TelegramBot:
|
|
|
1148
1145
|
archive_days = config['archive_days'],
|
|
1149
1146
|
persona_prompt = prompt,
|
|
1150
1147
|
key_status = key_status,
|
|
1151
|
-
|
|
1148
|
+
instance_name = config['instance_name'],
|
|
1152
1149
|
webhook_schemas = webhook_schemas,
|
|
1153
1150
|
webhook_defs = webhook_defs,
|
|
1154
1151
|
)
|
|
@@ -96,28 +96,31 @@ class ApiKeyStatus:
|
|
|
96
96
|
disabled_reasons: dict = field(default_factory=dict)
|
|
97
97
|
|
|
98
98
|
|
|
99
|
+
_TELEGRAM_KEY_RE = re.compile(r'^\d+:[A-Za-z0-9_-]+$')
|
|
100
|
+
|
|
99
101
|
INIT_BOT_CONFIG = {
|
|
100
102
|
'bot_owner': '<YOUR USERNAME>',
|
|
101
103
|
'bot_nickname': 'Testy',
|
|
102
104
|
'bot_initials': 'TB',
|
|
103
105
|
'chat_model': 'gpt-5-mini',
|
|
104
106
|
'url_model': 'gpt-5',
|
|
105
|
-
'
|
|
106
|
-
'
|
|
107
|
+
'telegram_api_key': '<YOUR TELEGRAM API KEY HERE>',
|
|
108
|
+
'instance_name': None,
|
|
107
109
|
'token_limit': None,
|
|
108
110
|
'search_limit': None,
|
|
109
111
|
'persona_temp': None,
|
|
110
112
|
'archive_days': None,
|
|
113
|
+
'allow_local_webhooks': None,
|
|
111
114
|
'persona_prompt': 'You are a generic test bot powered by a user-configured LLM.'
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
INIT_BOT_CONFIG_COMMENTS = {
|
|
115
|
-
'
|
|
116
|
-
'log_name': '# Optional, label for console prefix and log file name. Defaults to the bot\'s Telegram username',
|
|
118
|
+
'instance_name': '# Optional, sets log label and DB filename (e.g. MyBot -> MyBot.db). If omitted, log label defaults to the bot\'s Telegram username and DB filename remains conversations.db',
|
|
117
119
|
'token_limit': '# Optional, overrides the chat_model\'s default max token limit',
|
|
118
120
|
'search_limit': '# Optional, max results returned by message search (default: 30)',
|
|
119
121
|
'persona_temp': '# Optional, LLM temperature 0.0-2.0 (default: model\'s default)',
|
|
120
122
|
'archive_days': '# Optional, days before messages are eligible for Tier 1 archival (default: 60, min: 1). Tier 2 triggers at 2x this value.',
|
|
123
|
+
'allow_local_webhooks': '# Optional, set to true to permit webhook/MCP URLs targeting loopback or link-local addresses (default: false)',
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
# Append the framework-owned system appendix to the persona prompt.
|
|
@@ -163,24 +166,24 @@ def init_logging():
|
|
|
163
166
|
logging.getLogger('httpcore').setLevel(logging.WARNING)
|
|
164
167
|
|
|
165
168
|
|
|
166
|
-
def bind_log_identity(username: str,
|
|
169
|
+
def bind_log_identity(username: str, instance_name: Optional[str] = None):
|
|
167
170
|
"""
|
|
168
171
|
Bind the bot's identity to the logging system.
|
|
169
172
|
|
|
170
|
-
Updates the console handler formatter to prefix every line with [
|
|
171
|
-
the per-instance log file named {
|
|
173
|
+
Updates the console handler formatter to prefix every line with [instance_name] and opens
|
|
174
|
+
the per-instance log file named {instance_name}_{timestamp}.log.
|
|
172
175
|
|
|
173
176
|
Must be called after the bot's Telegram username is resolved by _tele_info().
|
|
174
177
|
|
|
175
178
|
Args:
|
|
176
179
|
username: The bot's Telegram username (without @); used as the identity label when
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
180
|
+
instance_name is not set.
|
|
181
|
+
instance_name: Optional override from bot config. When set, used for both the console
|
|
182
|
+
prefix and log file name instead of the Telegram username -- useful for
|
|
183
|
+
multi-platform deployments where the same bot runs on Telegram and Discord.
|
|
181
184
|
"""
|
|
182
|
-
raw_label =
|
|
183
|
-
# Sanitize: strip path separators so a misconfigured
|
|
185
|
+
raw_label = instance_name or username
|
|
186
|
+
# Sanitize: strip path separators so a misconfigured instance_name cannot escape TELLMGRAMBOT_LOGS_PATH
|
|
184
187
|
label = os.path.basename(raw_label).strip()
|
|
185
188
|
if not label:
|
|
186
189
|
label = username
|
|
@@ -242,7 +245,7 @@ def _requires_provider(config: dict) -> dict:
|
|
|
242
245
|
all other non-empty models require OpenAI.
|
|
243
246
|
|
|
244
247
|
Args:
|
|
245
|
-
config: Parsed bot configuration dict (from init_bot_config or read_yaml on config
|
|
248
|
+
config: Parsed bot configuration dict (from init_bot_config or read_yaml on bot config).
|
|
246
249
|
|
|
247
250
|
Returns:
|
|
248
251
|
Dict with keys 'openai' and 'anthropic', each a bool indicating if that provider key is needed.
|
|
@@ -264,66 +267,77 @@ def _model_provider(model: str) -> str | None:
|
|
|
264
267
|
return 'anthropic' if model.startswith('claude-') else 'openai'
|
|
265
268
|
|
|
266
269
|
|
|
267
|
-
def
|
|
270
|
+
def _load_telegram_key(config: dict):
|
|
268
271
|
"""
|
|
269
|
-
Load
|
|
272
|
+
Load and validate the Telegram API key into TELLMGRAMBOT_TELEGRAM_API_KEY.
|
|
270
273
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
disable the associated features rather than exiting.
|
|
274
|
+
Lookup order: TELLMGRAMBOT_TELEGRAM_API_KEY env var -> bot config `telegram_api_key`.
|
|
275
|
+
No .key file support. Exits on placeholder, missing, or malformed key.
|
|
274
276
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
277
|
+
Args:
|
|
278
|
+
config: Parsed bot configuration dict from init_bot_config().
|
|
279
|
+
"""
|
|
280
|
+
env_var = 'TELLMGRAMBOT_TELEGRAM_API_KEY'
|
|
281
|
+
if not os.environ.get(env_var):
|
|
282
|
+
config_val = (config.get('telegram_api_key') or '').strip()
|
|
283
|
+
is_placeholder = config_val.startswith('<') and config_val.endswith('>')
|
|
284
|
+
if config_val and not is_placeholder:
|
|
285
|
+
os.environ[env_var] = config_val
|
|
286
|
+
elif is_placeholder:
|
|
287
|
+
sys.exit("telegram_api_key in bot config is still a placeholder. Replace it with your Telegram bot API key. Exiting...")
|
|
288
|
+
else:
|
|
289
|
+
sys.exit(
|
|
290
|
+
"Telegram API key is required. Set telegram_api_key in bot config "
|
|
291
|
+
"or TELLMGRAMBOT_TELEGRAM_API_KEY env var. Exiting..."
|
|
292
|
+
)
|
|
293
|
+
if not _TELEGRAM_KEY_RE.match(os.environ.get(env_var, '')):
|
|
294
|
+
sys.exit(
|
|
295
|
+
"Telegram API key is not in valid format '<digits>:<letters/digits/_/->' "
|
|
296
|
+
"(e.g. 123456789:ABCdef...) - exiting..."
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def init_keys(config: dict) -> ApiKeyStatus:
|
|
301
|
+
"""
|
|
302
|
+
Load API keys and return an ApiKeyStatus indicating which features are available.
|
|
303
|
+
|
|
304
|
+
Telegram key is loaded and validated first via _load_telegram_key(). All other
|
|
305
|
+
keys (OpenAI, Anthropic, VirusTotal) are optional: missing keys disable the
|
|
306
|
+
associated features rather than exiting. These keys are loaded from env var or
|
|
307
|
+
key file (TELLMGRAMBOT_KEYS_PATH or base execution path). Placeholder files are
|
|
308
|
+
created for any missing keys.
|
|
279
309
|
|
|
280
310
|
Args:
|
|
281
|
-
config:
|
|
282
|
-
TELLMGRAMBOT_CONFIGS_PATH/config.yaml (or execution_dir/config.yaml).
|
|
311
|
+
config: Parsed bot configuration dict from init_bot_config().
|
|
283
312
|
|
|
284
313
|
Returns:
|
|
285
314
|
ApiKeyStatus with chat_enabled and url_analysis_enabled flags set based on which keys are available.
|
|
286
315
|
"""
|
|
287
|
-
|
|
288
|
-
# Failures here are non-fatal: config = {} means no models configured.
|
|
289
|
-
if config is None:
|
|
290
|
-
try:
|
|
291
|
-
config_path = os.path.join(os.environ.get('TELLMGRAMBOT_CONFIGS_PATH', execution_dir()), 'config.yaml')
|
|
292
|
-
config = read_yaml(config_path) or {}
|
|
293
|
-
except Exception:
|
|
294
|
-
config = {}
|
|
316
|
+
_load_telegram_key(config)
|
|
295
317
|
|
|
296
318
|
# Determine which provider keys are needed and which feature each model uses.
|
|
297
319
|
provider_needs = _requires_provider(config)
|
|
298
320
|
chat_provider = _model_provider(config.get('chat_model', ''))
|
|
299
321
|
url_provider = _model_provider(config.get('url_model', ''))
|
|
300
322
|
|
|
301
|
-
#
|
|
323
|
+
# Only load the required provider key(s) + VirusTotal.
|
|
302
324
|
provider_keys = {
|
|
303
325
|
'openai': 'https://platform.openai.com/api-keys',
|
|
304
326
|
'anthropic': 'https://docs.anthropic.com/en/api/getting-started',
|
|
305
327
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
'virustotal': 'https://developers.virustotal.com/reference/overview'
|
|
309
|
-
}
|
|
310
|
-
keys = {k: v for k, v in provider_keys.items() if provider_needs.get(k)} | always_keys
|
|
328
|
+
optional_keys = {k: v for k, v in provider_keys.items() if provider_needs.get(k)}
|
|
329
|
+
optional_keys['virustotal'] = 'https://developers.virustotal.com/reference/overview'
|
|
311
330
|
|
|
312
|
-
available = set() #
|
|
313
|
-
for key, url in
|
|
331
|
+
available = set(['telegram']) # telegram already validated above
|
|
332
|
+
for key, url in optional_keys.items():
|
|
314
333
|
env_var = f"TELLMGRAMBOT_{key.upper()}_API_KEY"
|
|
315
334
|
|
|
316
|
-
# If the key isn't already in the environment, try loading it from a key file.
|
|
317
335
|
if not os.environ.get(env_var):
|
|
318
336
|
path = os.path.join(os.environ.get('TELLMGRAMBOT_KEYS_PATH', execution_dir()), f"{key}.key")
|
|
319
337
|
if not os.path.exists(path):
|
|
320
|
-
# Key file missing: create a placeholder and warn (or exit for Telegram).
|
|
321
338
|
generate_file_path(os.path.dirname(path), os.path.basename(path), "API key",
|
|
322
339
|
f"YOUR {key.upper()} API KEY HERE - {url}\n"
|
|
323
340
|
)
|
|
324
|
-
if key == 'telegram':
|
|
325
|
-
sys.exit("Telegram API key is required to run TeLLMgramBot! Exiting...")
|
|
326
|
-
# Build a human-readable list of which features this key covers.
|
|
327
341
|
which = [f"chat_model ({config.get('chat_model', '?')})" if chat_provider == key else None,
|
|
328
342
|
f"url_model ({config.get('url_model', '?')})" if url_provider == key else None,
|
|
329
343
|
"VirusTotal integration" if key == 'virustotal' else None]
|
|
@@ -331,14 +345,10 @@ def init_keys(config: Optional[dict] = None) -> ApiKeyStatus:
|
|
|
331
345
|
logger.warning(f"{key}.key not found - {reason} will be disabled.")
|
|
332
346
|
continue
|
|
333
347
|
else:
|
|
334
|
-
# Key file exists: load it into the environment for this process.
|
|
335
348
|
os.environ[env_var] = read_text(path)
|
|
336
349
|
logger.info(f"Loaded {env_var} secret from: {path}")
|
|
337
350
|
|
|
338
|
-
# Reject blank or whitespace-only values (common copy-paste mistake).
|
|
339
351
|
if not os.environ.get(env_var) or any(c.isspace() for c in os.environ.get(env_var)):
|
|
340
|
-
if key == 'telegram':
|
|
341
|
-
sys.exit("Telegram API key is blank or invalid! Exiting...")
|
|
342
352
|
which = [f"chat_model ({config.get('chat_model', '?')})" if chat_provider == key else None,
|
|
343
353
|
f"url_model ({config.get('url_model', '?')})" if url_provider == key else None,
|
|
344
354
|
"VirusTotal integration" if key == 'virustotal' else None]
|
|
@@ -372,26 +382,9 @@ def init_keys(config: Optional[dict] = None) -> ApiKeyStatus:
|
|
|
372
382
|
reasons.append("missing VirusTotal API key")
|
|
373
383
|
key_status.disabled_reasons['url_analysis'] = ", ".join(reasons)
|
|
374
384
|
|
|
375
|
-
print_api_key_status(key_status)
|
|
376
385
|
return key_status
|
|
377
386
|
|
|
378
387
|
|
|
379
|
-
def print_api_key_status(key_status: ApiKeyStatus):
|
|
380
|
-
"""Print a startup summary of which API keys are available and which features they enable."""
|
|
381
|
-
print("--- TeLLMgramBot API Key Status ---")
|
|
382
|
-
features = [
|
|
383
|
-
('chat', 'Chat (LLM)', key_status.chat_enabled),
|
|
384
|
-
('url_analysis', 'URL Analysis', key_status.url_analysis_enabled),
|
|
385
|
-
]
|
|
386
|
-
for key, label, enabled in features:
|
|
387
|
-
if enabled:
|
|
388
|
-
print(f" {label:<12} : ENABLED")
|
|
389
|
-
else:
|
|
390
|
-
reason = key_status.disabled_reasons.get(key, 'unavailable')
|
|
391
|
-
print(f" {label:<12} : DISABLED ({reason})")
|
|
392
|
-
print("-----------------------------------")
|
|
393
|
-
|
|
394
|
-
|
|
395
388
|
def init_bot_config(file: str = 'config.yaml') -> dict:
|
|
396
389
|
"""
|
|
397
390
|
Returns contents of a bot configuration file (default 'config.yaml' if created).
|
|
@@ -410,9 +403,9 @@ def init_bot_config(file: str = 'config.yaml') -> dict:
|
|
|
410
403
|
env_var = "TELLMGRAMBOT_CONFIGS_PATH"
|
|
411
404
|
try:
|
|
412
405
|
text = ''.join(
|
|
413
|
-
'%s
|
|
414
|
-
parameter
|
|
415
|
-
value if value else INIT_BOT_CONFIG_COMMENTS.get(parameter, '# Optional')
|
|
406
|
+
'%s: %s\n' % (
|
|
407
|
+
parameter,
|
|
408
|
+
(f"'{value}'" if isinstance(value, str) else value) if value is not None else INIT_BOT_CONFIG_COMMENTS.get(parameter, '# Optional')
|
|
416
409
|
)
|
|
417
410
|
for parameter, value in INIT_BOT_CONFIG.items()
|
|
418
411
|
if parameter != 'persona_prompt'
|
|
@@ -530,15 +523,15 @@ def init_structure(
|
|
|
530
523
|
Performs the whole TeLLMgramBot first-run setup including:
|
|
531
524
|
- Directories for configurations, prompts, and conversation/error logs.
|
|
532
525
|
- Logging configuration (console handler; file handler bound later by bind_log_identity()).
|
|
533
|
-
- Database naming and schema initialization from config (conversations.db or custom
|
|
534
|
-
- Provider-conditional API keys (OpenAI/Anthropic determined by config
|
|
535
|
-
- Configuration files (config
|
|
526
|
+
- Database naming and schema initialization from config (conversations.db or custom instance_name).
|
|
527
|
+
- Provider-conditional API keys (OpenAI/Anthropic determined by bot config model prefixes).
|
|
528
|
+
- Configuration files (bot config, models.yaml) with inline parameter descriptions.
|
|
536
529
|
- System prompt files (test_personality.prmpt, url_analysis.prmpt).
|
|
537
530
|
|
|
538
|
-
Provider key requirements are inferred from config
|
|
531
|
+
Provider key requirements are inferred from bot config model prefixes (claude-* -> Anthropic,
|
|
539
532
|
gpt-* -> OpenAI, etc.) to streamline setup for single-provider deployments.
|
|
540
533
|
|
|
541
|
-
Database naming: After init_bot_config() runs, if
|
|
534
|
+
Database naming: After init_bot_config() runs, if instance_name is configured in bot config,
|
|
542
535
|
calls set_db_filename() and performs a one-time rename migration of conversations.db to
|
|
543
536
|
the custom filename (only if the target does not yet exist). This ordering ensures the DB
|
|
544
537
|
filename is settled before schema init.
|
|
@@ -561,19 +554,19 @@ def init_structure(
|
|
|
561
554
|
init_models_config()
|
|
562
555
|
|
|
563
556
|
# Configure DB filename and run schema init now that config is available.
|
|
564
|
-
# Must happen after init_bot_config() so
|
|
565
|
-
|
|
566
|
-
if
|
|
557
|
+
# Must happen after init_bot_config() so instance_name is known before init_db() runs.
|
|
558
|
+
instance_name = config.get('instance_name')
|
|
559
|
+
if instance_name:
|
|
567
560
|
# Sanitize to a plain filename - reject path separators and absolute paths so a
|
|
568
|
-
# misconfigured
|
|
569
|
-
|
|
570
|
-
if
|
|
561
|
+
# misconfigured instance_name cannot escape TELLMGRAMBOT_DATA_PATH.
|
|
562
|
+
instance_name_safe = os.path.basename(instance_name).strip()
|
|
563
|
+
if instance_name_safe != instance_name.strip() or not instance_name_safe:
|
|
571
564
|
logger.warning(
|
|
572
|
-
f"
|
|
565
|
+
f"instance_name '{instance_name}' contains path components; ignoring and using conversations.db"
|
|
573
566
|
)
|
|
574
|
-
|
|
567
|
+
instance_name = None
|
|
575
568
|
else:
|
|
576
|
-
set_db_filename(
|
|
569
|
+
set_db_filename(instance_name_safe)
|
|
577
570
|
# One-time migration: rename conversations.db to the new name if the target
|
|
578
571
|
# doesn't exist yet. Assumes a single-bot deployment owns conversations.db.
|
|
579
572
|
data_dir = os.environ.get('TELLMGRAMBOT_DATA_PATH', os.path.join(execution_dir(), 'data'))
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Webhook and MCP tool registry and executors for TeLLMgramBot.
|
|
3
3
|
|
|
4
|
-
Provides build_tool_registry() for startup parsing of config
|
|
4
|
+
Provides build_tool_registry() for startup parsing of bot config 'tools:' webhook
|
|
5
5
|
entries, discover_mcp_tools() for async MCP server discovery, execute_webhook() for
|
|
6
6
|
dispatching webhook tool calls, and execute_mcp() for MCP tool calls at runtime.
|
|
7
7
|
"""
|
|
@@ -96,7 +96,7 @@ def build_tool_registry(
|
|
|
96
96
|
are skipped with warnings. Duplicate tool names are deduplicated (first wins).
|
|
97
97
|
|
|
98
98
|
Args:
|
|
99
|
-
tools_config: List of raw tool definition dicts from config
|
|
99
|
+
tools_config: List of raw tool definition dicts from bot config 'tools:' key.
|
|
100
100
|
Pass an empty list or None to produce an empty registry.
|
|
101
101
|
allow_local: If True, the executor permits webhook URLs targeting loopback or
|
|
102
102
|
link-local addresses. Mirrors the 'allow_local_webhooks' config key.
|
|
@@ -387,7 +387,7 @@ async def execute_mcp(tool_def: dict, arguments: dict) -> str:
|
|
|
387
387
|
logger.warning(f"MCP '{name}': SSRF block - '{parsed.hostname}' is loopback or link-local")
|
|
388
388
|
return (
|
|
389
389
|
f"[Tool error: '{name}' targets a loopback or link-local address. "
|
|
390
|
-
f"Set allow_local_webhooks: true in config
|
|
390
|
+
f"Set allow_local_webhooks: true in bot config to permit local addresses.]"
|
|
391
391
|
)
|
|
392
392
|
|
|
393
393
|
call_url = f"{server_url}/tools/call"
|
|
@@ -489,7 +489,7 @@ async def execute_webhook(tool_def: dict, arguments: dict) -> str:
|
|
|
489
489
|
logger.warning(f"Webhook '{name}': SSRF block - '{hostname}' is loopback or link-local")
|
|
490
490
|
return (
|
|
491
491
|
f"[Tool error: '{name}' targets a loopback or link-local address. "
|
|
492
|
-
f"Set allow_local_webhooks: true in config
|
|
492
|
+
f"Set allow_local_webhooks: true in bot config to permit local addresses.]"
|
|
493
493
|
)
|
|
494
494
|
|
|
495
495
|
host_part = f"{parsed.hostname}:{parsed.port}" if parsed.port else parsed.hostname
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: TeLLMgramBot
|
|
3
|
-
Version: 3.13.
|
|
3
|
+
Version: 3.13.3
|
|
4
4
|
Summary: LLM-powered Telegram bot (OpenAI + Anthropic)
|
|
5
5
|
Home-page: https://github.com/Digital-Heresy/TeLLMgramBot
|
|
6
6
|
Author: Digital Heresy
|
|
@@ -82,11 +82,11 @@ TeLLMgramBot creates the following directories:
|
|
|
82
82
|
- `test_personality.prmpt` - Sample bot personality (multi-provider, can be renamed)
|
|
83
83
|
- `url_analysis.prmpt` - URL summarization prompt template
|
|
84
84
|
- A system appendix is automatically appended to every persona at runtime, teaching the LLM about cross-chat memory and search behavior. User messages include speaker annotations with chat context and timestamps so the LLM always knows who is speaking, in which chat, and when.
|
|
85
|
-
- **`logs`** - Bot instance logs (one per startup, named after the bot's Telegram username or `
|
|
86
|
-
- Logs include anonymized Telegram IDs for privacy. Console shows INFO-level TeLLMgramBot messages only, prefixed with an `[identity label]` (the bot's Telegram username by default, or `
|
|
85
|
+
- **`logs`** - Bot instance logs (one per startup, named after the bot's Telegram username or `instance_name` config, e.g. `my_bot_2026-03-29_10-30-45.log`)
|
|
86
|
+
- Logs include anonymized Telegram IDs for privacy. Console shows INFO-level TeLLMgramBot messages only, prefixed with an `[identity label]` (the bot's Telegram username by default, or `instance_name` when configured).
|
|
87
87
|
- Bot keeps the 10 most recent logs per bot instance, automatically pruning older ones.
|
|
88
88
|
- Pass `-v` or `--verbose` on startup for DEBUG-level logging.
|
|
89
|
-
- **`data`** - SQLite database (default `conversations.db`, customizable via `
|
|
89
|
+
- **`data`** - SQLite database (default `conversations.db`, customizable via `instance_name` config) storing all messages, users, and chats
|
|
90
90
|
- Users manage their data via `/forget` and `/private` commands.
|
|
91
91
|
|
|
92
92
|
### Environment Variables for Paths
|
|
@@ -102,13 +102,13 @@ Override default directory locations by setting these environment variables (use
|
|
|
102
102
|
If unset, all paths default to subdirectories of the execution directory (the directory containing your entry-point script).
|
|
103
103
|
|
|
104
104
|
## API Keys
|
|
105
|
-
TeLLMgramBot supports four API keys,
|
|
105
|
+
TeLLMgramBot supports four API keys. OpenAI, Anthropic, and VirusTotal keys load from environment variables or `.key` files. The Telegram key loads from `telegram_api_key` in `config.yaml` or its env var (no `.key` file):
|
|
106
106
|
|
|
107
|
-
| Key | Env Var | File | When required |
|
|
108
|
-
|
|
107
|
+
| Key | Env Var | File/Config | When required |
|
|
108
|
+
|-----|---------|-------------|---------------|
|
|
109
109
|
| [OpenAI](https://platform.openai.com/api-keys) | `TELLMGRAMBOT_OPENAI_API_KEY` | `openai.key` | For `gpt-*` models |
|
|
110
110
|
| [Anthropic](https://console.anthropic.com/settings/keys) | `TELLMGRAMBOT_ANTHROPIC_API_KEY` | `anthropic.key` | For `claude-*` models |
|
|
111
|
-
| [Telegram](https://t.me/BotFather) | `TELLMGRAMBOT_TELEGRAM_API_KEY` | `
|
|
111
|
+
| [Telegram](https://t.me/BotFather) | `TELLMGRAMBOT_TELEGRAM_API_KEY` | `telegram_api_key` in config.yaml | Always required |
|
|
112
112
|
| [VirusTotal](https://www.virustotal.com/gui/my-apikey) | `TELLMGRAMBOT_VIRUSTOTAL_API_KEY` | `virustotal.key` | For URL analysis |
|
|
113
113
|
|
|
114
114
|
Missing provider keys (OpenAI or Anthropic) disable chat and URL analysis but allow the bot to start. Missing VirusTotal disables URL analysis. Telegram key is required - the bot will not start without it.
|
|
@@ -151,12 +151,13 @@ When the bot is triggered in a group and about to respond (not deferring to anot
|
|
|
151
151
|
- `bot_owner`: Telegram username(s) with admin access (required, no `@`). Accepts a single string or a YAML list of usernames.
|
|
152
152
|
- `chat_model`: LLM model for conversation (e.g. `gpt-4o-mini` or `claude-sonnet-4-6`)
|
|
153
153
|
- `url_model`: LLM model for URL analysis (e.g. `gpt-4o` or `claude-haiku-4-5`)
|
|
154
|
+
- `telegram_api_key`: Telegram bot API key (required). Lookup order: TELLMGRAMBOT_TELEGRAM_API_KEY env var -> config field.
|
|
154
155
|
- `bot_nickname` / `bot_initials`: Names the bot responds to in groups
|
|
155
|
-
- `
|
|
156
|
-
- `log_name`: Optional label used for the console prefix and log filename (e.g. `MyBot` produces `[MyBot] INFO: ...` on the console and `MyBot_{timestamp}.log`); omit to use the bot's Telegram username. Useful for multi-platform deployments sharing the same config.
|
|
156
|
+
- `instance_name`: Optional label for console prefix, log filename, and database name (e.g. `MyBot` produces `[MyBot] INFO: ...` on console, `MyBot_{timestamp}.log` logs, and `MyBot.db` database); omit to use bot's Telegram username for logging and `conversations.db` for database. Use distinct names when running multiple bot instances in the same directory.
|
|
157
157
|
- `token_limit`: Max tokens (optional; defaults to model's maximum)
|
|
158
158
|
- `search_limit`: Max search results (optional; defaults to 30)
|
|
159
159
|
- `archive_days`: Days before messages are eligible for archival (optional; default 60, minimum 1). Older messages are distilled into daily summaries, then progressively compressed into monthly digests. Once archived their respective raw messages do not return to the LLM context any more, only when searching messages.
|
|
160
|
+
- `allow_local_webhooks`: Set to `true` to permit webhook/MCP URLs targeting loopback or link-local addresses (optional; default `false`). Useful when tools like Home Assistant run on the same host.
|
|
160
161
|
- `tools`: Optional list of webhook and MCP tool definitions (admin-only, private chat only). See [docs/tools.md](docs/tools.md) for schema and examples.
|
|
161
162
|
4. **Disable group privacy mode in BotFather:**
|
|
162
163
|
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|