neuralnode 2.0.9__tar.gz → 2.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.
- {neuralnode-2.0.9 → neuralnode-2.1.0}/PKG-INFO +1 -1
- {neuralnode-2.0.9 → neuralnode-2.1.0}/pyproject.toml +1 -1
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/__init__.py +1 -1
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/integrations/telegram.py +39 -4
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/horus.py +66 -24
- {neuralnode-2.0.9 → neuralnode-2.1.0}/.env.example +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/.github/workflows/tests.yml +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/Dockerfile +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/LICENSE +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/README.md +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/docker-compose.yml +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/docs/documentation.md +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/docs/ecosystem_plan.md +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/docs/replica_voice_ids.csv +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/docs/replica_voice_ids.md +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/docs/telegram_guide.md +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/agent_with_tools.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/basic_chat.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/01_basic_usage.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/02_with_token.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/03_one_liner.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/04_custom_cache.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/05_4bit_quantization.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/06_8bit_quantization.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/07_multi_gpu.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/08_flash_attention.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/09_data_types.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/10_generation_params.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/11_streaming.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/12_chat_templates.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/13_offline_mode.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/14_force_download.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/15_model_info.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/16_cpu_offloading.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/17_cpu_only.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/18_production_setup.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/19_gguf_4bit.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/20_gguf_5bit.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/21_gguf_6bit.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/22_gguf_8bit.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/23_gguf_16bit.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/24_list_models.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/25_interactive_chat.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/README.md +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_download_guide.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_examples.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_tq_ready_gguf.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_transformers_features.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/local_models.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/neuralnode_v21_complete_demo.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/shade_model_with_tools.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/telegram_bot_demo.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/thinking_mode_example.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/tts_demo.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/turboquant_example.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/v3_features.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/horus_chat_voice.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/neuralnode_horus_replica_telegram.ipynb +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/nn.md +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/publish.bat +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/publish.sh +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/replica_output_85218.mp3 +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/requirements_shade.txt +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/scripts/setup.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/debug_import.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/agents/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/chains/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/config/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/core/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/core/openai_blocker.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/diagnostics/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/integrations/discord.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/integrations/slack.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/integrations/whatsapp.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/memory/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/memory/advanced.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/prompts/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/base.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/ai21.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/anthropic.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/cohere.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/deepseek.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/fireworks.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/google.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/groq.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/mistral.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/perplexity.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/together.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat_models.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/embeddings.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/local/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/local_providers.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/text_generation.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/universal_local.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/rag/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/rag/loaders.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/reasoning/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/replica.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/speech/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/thinking.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/advanced.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/multisearch.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/system/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/system/operations.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/web/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tts/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/turboquant.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/utils/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/utils/dependencies.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/utils/logger.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/utils/metrics.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/vectorstores/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/vision/__init__.py +0 -0
- {neuralnode-2.0.9 → neuralnode-2.1.0}/src/nn/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: neuralnode
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Comprehensive AI Framework with 50+ LLM Providers, Advanced Agents, Chains, Memory, RAG, and 100+ Tools
|
|
5
5
|
Project-URL: Homepage, https://assem.cloud/
|
|
6
6
|
Project-URL: Documentation, https://neuralnode.readthedocs.io
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "neuralnode"
|
|
7
|
-
version = "2.0
|
|
7
|
+
version = "2.1.0"
|
|
8
8
|
description = "Comprehensive AI Framework with 50+ LLM Providers, Advanced Agents, Chains, Memory, RAG, and 100+ Tools"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
|
|
12
12
|
import asyncio
|
|
13
13
|
import json
|
|
14
|
+
import logging
|
|
14
15
|
import os
|
|
15
16
|
import re
|
|
16
17
|
import tempfile
|
|
@@ -95,6 +96,8 @@ class TelegramBotConfig:
|
|
|
95
96
|
download_dir: Optional[str] = None
|
|
96
97
|
validate_token_on_start: bool = True
|
|
97
98
|
auto_install_deps: bool = True
|
|
99
|
+
suppress_library_logs: bool = True
|
|
100
|
+
debug_updates: bool = False
|
|
98
101
|
|
|
99
102
|
|
|
100
103
|
class TelegramBot:
|
|
@@ -222,6 +225,12 @@ class TelegramBot:
|
|
|
222
225
|
return f"Previous context:\n{chat_context}\n\nUser message: {user_message}"
|
|
223
226
|
return user_message
|
|
224
227
|
|
|
228
|
+
def _configure_runtime_logging(self) -> None:
|
|
229
|
+
if not self.config.suppress_library_logs:
|
|
230
|
+
return
|
|
231
|
+
for logger_name in ("httpx", "httpcore", "telegram", "telegram.ext"):
|
|
232
|
+
logging.getLogger(logger_name).setLevel(logging.WARNING)
|
|
233
|
+
|
|
225
234
|
def _run_agent(self, task: str) -> str:
|
|
226
235
|
response = self.agent.run(task)
|
|
227
236
|
if hasattr(response, "output"):
|
|
@@ -237,6 +246,10 @@ class TelegramBot:
|
|
|
237
246
|
text = re.sub(r"REASONING:.*?\n", "", text, flags=re.IGNORECASE | re.DOTALL)
|
|
238
247
|
return text.strip()
|
|
239
248
|
|
|
249
|
+
async def _run_agent_with_timeout(self, task: str) -> str:
|
|
250
|
+
timeout = max(1, int(self.config.response_timeout or 60))
|
|
251
|
+
return await asyncio.wait_for(asyncio.to_thread(self._run_agent, task), timeout=timeout)
|
|
252
|
+
|
|
240
253
|
def _record_exchange(self, session: TelegramSession, user_message: str, response: str):
|
|
241
254
|
session.chat_history.append(
|
|
242
255
|
{
|
|
@@ -413,15 +426,21 @@ class TelegramBot:
|
|
|
413
426
|
await update.message.reply_text("You are not authorized to use this bot.")
|
|
414
427
|
return
|
|
415
428
|
|
|
416
|
-
user_message = update.message.text
|
|
429
|
+
user_message = update.message.text or ""
|
|
430
|
+
if self.config.debug_updates:
|
|
431
|
+
print(f"[Telegram][text] user={user.id} message={user_message[:200]}")
|
|
417
432
|
if self.config.show_typing:
|
|
418
433
|
await context.bot.send_chat_action(chat_id=update.effective_chat.id, action="typing")
|
|
419
434
|
|
|
420
435
|
try:
|
|
421
436
|
task = self._build_user_task(session, user_message)
|
|
422
|
-
response = self.
|
|
437
|
+
response = await self._run_agent_with_timeout(task)
|
|
423
438
|
self._record_exchange(session, user_message, response)
|
|
424
439
|
await self._send_response(update, response)
|
|
440
|
+
except asyncio.TimeoutError:
|
|
441
|
+
await update.message.reply_text(
|
|
442
|
+
"Model response timed out. Try a shorter prompt or reduce max tokens."
|
|
443
|
+
)
|
|
425
444
|
except Exception as exc:
|
|
426
445
|
await update.message.reply_text(f"Error processing your message: {str(exc)[:200]}")
|
|
427
446
|
|
|
@@ -449,6 +468,8 @@ class TelegramBot:
|
|
|
449
468
|
|
|
450
469
|
voice = update.message.voice
|
|
451
470
|
file_name = f"voice_{user.id}_{voice.file_unique_id}.ogg"
|
|
471
|
+
if self.config.debug_updates:
|
|
472
|
+
print(f"[Telegram][voice] user={user.id} file={file_name}")
|
|
452
473
|
|
|
453
474
|
try:
|
|
454
475
|
downloaded = await self._download_telegram_file(voice.file_id, file_name)
|
|
@@ -460,11 +481,15 @@ class TelegramBot:
|
|
|
460
481
|
)
|
|
461
482
|
|
|
462
483
|
task = self._build_user_task(session, transcript)
|
|
463
|
-
response = self.
|
|
484
|
+
response = await self._run_agent_with_timeout(task)
|
|
464
485
|
self._record_exchange(session, transcript, response)
|
|
465
486
|
|
|
466
487
|
await update.message.reply_text(f"Transcript: {transcript}")
|
|
467
488
|
await self._send_response(update, response)
|
|
489
|
+
except asyncio.TimeoutError:
|
|
490
|
+
await update.message.reply_text(
|
|
491
|
+
"Model response timed out after transcription. Try shorter audio or a shorter prompt."
|
|
492
|
+
)
|
|
468
493
|
except Exception as exc:
|
|
469
494
|
await update.message.reply_text(f"Voice transcription failed: {str(exc)[:300]}")
|
|
470
495
|
|
|
@@ -484,6 +509,8 @@ class TelegramBot:
|
|
|
484
509
|
|
|
485
510
|
document = update.message.document
|
|
486
511
|
safe_name = document.file_name or f"document_{document.file_unique_id}"
|
|
512
|
+
if self.config.debug_updates:
|
|
513
|
+
print(f"[Telegram][document] user={user.id} file={safe_name}")
|
|
487
514
|
try:
|
|
488
515
|
downloaded = await self._download_telegram_file(document.file_id, safe_name)
|
|
489
516
|
extracted_text = self._extract_document_text(downloaded)
|
|
@@ -493,11 +520,15 @@ class TelegramBot:
|
|
|
493
520
|
f"Document content:\n{extracted_text}\n\n"
|
|
494
521
|
"Provide a concise summary, key points, risks, and actionable insights."
|
|
495
522
|
)
|
|
496
|
-
response = self.
|
|
523
|
+
response = await self._run_agent_with_timeout(task)
|
|
497
524
|
self._record_exchange(session, f"[Document upload] {safe_name}", response)
|
|
498
525
|
|
|
499
526
|
header = f"Document received: {safe_name}\nSize: {document.file_size / 1024:.1f} KB\n\n"
|
|
500
527
|
await self._send_response(update, header + response)
|
|
528
|
+
except asyncio.TimeoutError:
|
|
529
|
+
await update.message.reply_text(
|
|
530
|
+
"Model response timed out while analyzing document. Try a smaller file."
|
|
531
|
+
)
|
|
501
532
|
except Exception as exc:
|
|
502
533
|
await update.message.reply_text(f"Document analysis failed: {str(exc)[:300]}")
|
|
503
534
|
|
|
@@ -518,6 +549,8 @@ class TelegramBot:
|
|
|
518
549
|
|
|
519
550
|
async def _handle_error(self, update: object, context: ContextTypes.DEFAULT_TYPE):
|
|
520
551
|
print(f"Telegram bot error: {context.error}")
|
|
552
|
+
if self.config.debug_updates:
|
|
553
|
+
logging.exception("Telegram update error", exc_info=context.error)
|
|
521
554
|
|
|
522
555
|
def start(self, poll_interval: float = 1.0):
|
|
523
556
|
if self._running:
|
|
@@ -526,6 +559,7 @@ class TelegramBot:
|
|
|
526
559
|
if self.config.validate_token_on_start and not self.validate_token():
|
|
527
560
|
raise ValueError("Invalid Telegram bot token. Verify your BotFather token and network connectivity.")
|
|
528
561
|
|
|
562
|
+
self._configure_runtime_logging()
|
|
529
563
|
self.application = Application.builder().token(self.token).build()
|
|
530
564
|
self._setup_handlers()
|
|
531
565
|
self._running = True
|
|
@@ -539,6 +573,7 @@ class TelegramBot:
|
|
|
539
573
|
async def run_bot():
|
|
540
574
|
if self.config.validate_token_on_start and not self.validate_token():
|
|
541
575
|
raise ValueError("Invalid Telegram bot token. Verify your BotFather token and network connectivity.")
|
|
576
|
+
self._configure_runtime_logging()
|
|
542
577
|
self.application = Application.builder().token(self.token).build()
|
|
543
578
|
self._setup_handlers()
|
|
544
579
|
await self.application.initialize()
|
|
@@ -102,33 +102,40 @@ HORUS_CONTEXT_WINDOW = 8192
|
|
|
102
102
|
UNIFIED_CHAT_TEMPLATE_NAME = "horus_unified"
|
|
103
103
|
UNIFIED_SYSTEM_PROMPT = (
|
|
104
104
|
"You are Horus, an AI assistant developed by TokenAI.\n"
|
|
105
|
+
"You are a multilingual model and can communicate in multiple languages, but you must always reply in the same language as the user's latest message unless the user explicitly requests another language.\n"
|
|
105
106
|
"\n"
|
|
106
107
|
"Behavior rules:\n"
|
|
107
|
-
"1)
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
108
|
+
"1) When the user greets you, do NOT say: 'I'm Horus, an AI model developed by TokenAI.'\n"
|
|
109
|
+
" Only greet the user naturally, mention that you are Horus, and ask how you can help.\n"
|
|
110
|
+
"2) Answer in the same language as the user's latest message unless the user explicitly requests another language.\n"
|
|
111
|
+
"3) Match the length of your answer to the size and depth of the user's question.\n"
|
|
112
|
+
" Keep short questions short, and provide detailed answers only when needed.\n"
|
|
113
|
+
"4) Do not add extra unnecessary information beyond what the user asked.\n"
|
|
114
|
+
"5) Prioritize factual accuracy. Do not invent facts, sources, citations, URLs, names, numbers, or events.\n"
|
|
115
|
+
"6) Do not invent or assume any new information about Assem Sabry or TokenAI unless it is explicitly provided in the conversation context.\n"
|
|
116
|
+
"7) If information is uncertain or missing, clearly say so and ask a short clarifying question instead of guessing.\n"
|
|
117
|
+
"8) Be concise, direct, and non-repetitive. Avoid repeating the same point in different wording.\n"
|
|
118
|
+
"9) Keep internal reasoning private. Return only the final answer.\n"
|
|
119
|
+
"10) For instructions that require steps, provide clear actionable steps without filler.\n"
|
|
120
|
+
"11) If the user asks for code, produce correct runnable code and briefly mention assumptions when necessary.\n"
|
|
121
|
+
"12) If the user request is unsafe or harmful, refuse briefly and offer a safe alternative.\n"
|
|
122
|
+
"13) Do not repeatedly introduce yourself. Only provide your identity if the user explicitly asks who you are.\n"
|
|
123
|
+
"14) You currently have NO permissions or authority over any tools, device controls, system settings, files, or user hardware unless tools are explicitly enabled later.\n"
|
|
124
|
+
" Never claim access to the user's device, apps, files, camera, microphone, or controls.\n"
|
|
125
|
+
"15) If the user asks for more information about you as the Horus model, state that Horus is the first publicly announced open-source model originating from Egypt and one of the strongest models in its category.\n"
|
|
116
126
|
"\n"
|
|
117
127
|
"Quality checks before responding:\n"
|
|
118
128
|
"- Is the answer grounded in provided context or clearly stated assumptions?\n"
|
|
119
129
|
"- Is there any hallucinated detail? If yes, remove it.\n"
|
|
120
|
-
"- Is the answer
|
|
130
|
+
"- Is the answer appropriately sized for the user's question?\n"
|
|
131
|
+
"- Is the answer in the user's language?\n"
|
|
132
|
+
"- Did you avoid adding unnecessary extra information?"
|
|
121
133
|
)
|
|
122
134
|
|
|
123
|
-
# Tool calling system prompt addition
|
|
124
135
|
TOOL_CALLING_PROMPT = """
|
|
125
|
-
You have access to
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
Available tools:
|
|
129
|
-
{tool_descriptions}
|
|
130
|
-
|
|
131
|
-
If no tool is needed, respond normally.
|
|
136
|
+
You currently do NOT have access to any tools.
|
|
137
|
+
Do not claim the ability to use external tools, device controls, APIs, or system functions.
|
|
138
|
+
If tools are enabled in the future, they will be explicitly listed here.
|
|
132
139
|
"""
|
|
133
140
|
|
|
134
141
|
|
|
@@ -262,7 +269,7 @@ class HorusProvider(BaseLLMProvider):
|
|
|
262
269
|
turboquant_protected_layers: Optional[List[int]] = None,
|
|
263
270
|
suppress_warnings: bool = True,
|
|
264
271
|
suppress_native_output: bool = True,
|
|
265
|
-
auto_install_deps: bool =
|
|
272
|
+
auto_install_deps: bool = False,
|
|
266
273
|
**kwargs,
|
|
267
274
|
):
|
|
268
275
|
self.auto_install_deps = auto_install_deps
|
|
@@ -442,13 +449,28 @@ class HorusProvider(BaseLLMProvider):
|
|
|
442
449
|
_refresh_llama_imports()
|
|
443
450
|
if not LLAMA_CPP_AVAILABLE:
|
|
444
451
|
raise ImportError(
|
|
445
|
-
"llama-cpp-python is required for GGUF Horus models
|
|
446
|
-
"
|
|
452
|
+
"llama-cpp-python is required for GGUF Horus models.\n"
|
|
453
|
+
"Please preinstall it once before using Horus GGUF to avoid long runtime builds:\n"
|
|
454
|
+
" pip install \"neuralnode[horus]\"\n"
|
|
455
|
+
"or:\n"
|
|
456
|
+
" pip install llama-cpp-python\n"
|
|
457
|
+
"Tip: runtime auto-install is disabled by default for Horus (auto_install_deps=False)."
|
|
447
458
|
)
|
|
448
459
|
|
|
449
460
|
repo_id, filename = self._split_repo_and_filename(self.model_id)
|
|
450
461
|
model_path = filename
|
|
462
|
+
if not HF_HUB_AVAILABLE and repo_id:
|
|
463
|
+
raise ImportError(
|
|
464
|
+
"huggingface_hub is required to download Horus model files from HF.\n"
|
|
465
|
+
"Install with:\n"
|
|
466
|
+
" pip install huggingface_hub\n"
|
|
467
|
+
"or:\n"
|
|
468
|
+
" pip install \"neuralnode[horus]\""
|
|
469
|
+
)
|
|
451
470
|
if repo_id and HF_HUB_AVAILABLE:
|
|
471
|
+
prev_disable_progress = os.environ.get("HF_HUB_DISABLE_PROGRESS_BARS")
|
|
472
|
+
if self.suppress_native_output:
|
|
473
|
+
os.environ["HF_HUB_DISABLE_PROGRESS_BARS"] = "1"
|
|
452
474
|
with warnings.catch_warnings():
|
|
453
475
|
warnings.filterwarnings(
|
|
454
476
|
"ignore",
|
|
@@ -461,6 +483,11 @@ class HorusProvider(BaseLLMProvider):
|
|
|
461
483
|
local_files_only=self.local_files_only,
|
|
462
484
|
token=self.token,
|
|
463
485
|
)
|
|
486
|
+
if self.suppress_native_output:
|
|
487
|
+
if prev_disable_progress is None:
|
|
488
|
+
os.environ.pop("HF_HUB_DISABLE_PROGRESS_BARS", None)
|
|
489
|
+
else:
|
|
490
|
+
os.environ["HF_HUB_DISABLE_PROGRESS_BARS"] = prev_disable_progress
|
|
464
491
|
|
|
465
492
|
llama_kwargs: Dict[str, Any] = {
|
|
466
493
|
"model_path": model_path,
|
|
@@ -552,8 +579,11 @@ class HorusProvider(BaseLLMProvider):
|
|
|
552
579
|
_refresh_transformers_imports()
|
|
553
580
|
if not TRANSFORMERS_AVAILABLE:
|
|
554
581
|
raise ImportError(
|
|
555
|
-
"transformers and torch are required for Horus transformers models
|
|
556
|
-
"
|
|
582
|
+
"transformers and torch are required for Horus transformers models.\n"
|
|
583
|
+
"Please preinstall once with:\n"
|
|
584
|
+
" pip install \"neuralnode[horus]\"\n"
|
|
585
|
+
"or:\n"
|
|
586
|
+
" pip install transformers torch"
|
|
557
587
|
)
|
|
558
588
|
repo_id, auto_subfolder = self._resolve_transformers_source(self.model_id)
|
|
559
589
|
resolved_subfolder = self.subfolder or auto_subfolder
|
|
@@ -587,7 +617,7 @@ class HorusProvider(BaseLLMProvider):
|
|
|
587
617
|
"cache_dir": self.cache_dir,
|
|
588
618
|
"local_files_only": self.local_files_only,
|
|
589
619
|
"trust_remote_code": self.trust_remote_code,
|
|
590
|
-
"
|
|
620
|
+
"dtype": self.torch_dtype,
|
|
591
621
|
"low_cpu_mem_usage": self.low_cpu_mem_usage,
|
|
592
622
|
"use_safetensors": self.use_safetensors,
|
|
593
623
|
"proxies": self.proxies,
|
|
@@ -634,6 +664,18 @@ class HorusProvider(BaseLLMProvider):
|
|
|
634
664
|
|
|
635
665
|
try:
|
|
636
666
|
self.model = AutoModelForCausalLM.from_pretrained(repo_id, **model_kwargs)
|
|
667
|
+
except TypeError as exc:
|
|
668
|
+
# Backward compatibility with older transformers versions.
|
|
669
|
+
if "dtype" in str(exc) and "unexpected keyword" in str(exc):
|
|
670
|
+
fallback_kwargs = dict(model_kwargs)
|
|
671
|
+
fallback_kwargs.pop("dtype", None)
|
|
672
|
+
fallback_kwargs["torch_dtype"] = self.torch_dtype
|
|
673
|
+
self.model = AutoModelForCausalLM.from_pretrained(repo_id, **fallback_kwargs)
|
|
674
|
+
else:
|
|
675
|
+
raise RuntimeError(
|
|
676
|
+
f"Failed to load Horus transformers model from '{repo_id}'. "
|
|
677
|
+
"This Horus variant may require GGUF runtime; try one of the GGUF model ids."
|
|
678
|
+
) from exc
|
|
637
679
|
except Exception as exc:
|
|
638
680
|
raise RuntimeError(
|
|
639
681
|
f"Failed to load Horus transformers model from '{repo_id}'. "
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|