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.
Files changed (117) hide show
  1. {neuralnode-2.0.9 → neuralnode-2.1.0}/PKG-INFO +1 -1
  2. {neuralnode-2.0.9 → neuralnode-2.1.0}/pyproject.toml +1 -1
  3. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/__init__.py +1 -1
  4. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/integrations/telegram.py +39 -4
  5. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/horus.py +66 -24
  6. {neuralnode-2.0.9 → neuralnode-2.1.0}/.env.example +0 -0
  7. {neuralnode-2.0.9 → neuralnode-2.1.0}/.github/workflows/tests.yml +0 -0
  8. {neuralnode-2.0.9 → neuralnode-2.1.0}/Dockerfile +0 -0
  9. {neuralnode-2.0.9 → neuralnode-2.1.0}/LICENSE +0 -0
  10. {neuralnode-2.0.9 → neuralnode-2.1.0}/README.md +0 -0
  11. {neuralnode-2.0.9 → neuralnode-2.1.0}/docker-compose.yml +0 -0
  12. {neuralnode-2.0.9 → neuralnode-2.1.0}/docs/documentation.md +0 -0
  13. {neuralnode-2.0.9 → neuralnode-2.1.0}/docs/ecosystem_plan.md +0 -0
  14. {neuralnode-2.0.9 → neuralnode-2.1.0}/docs/replica_voice_ids.csv +0 -0
  15. {neuralnode-2.0.9 → neuralnode-2.1.0}/docs/replica_voice_ids.md +0 -0
  16. {neuralnode-2.0.9 → neuralnode-2.1.0}/docs/telegram_guide.md +0 -0
  17. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/agent_with_tools.py +0 -0
  18. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/basic_chat.py +0 -0
  19. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/01_basic_usage.py +0 -0
  20. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/02_with_token.py +0 -0
  21. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/03_one_liner.py +0 -0
  22. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/04_custom_cache.py +0 -0
  23. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/05_4bit_quantization.py +0 -0
  24. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/06_8bit_quantization.py +0 -0
  25. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/07_multi_gpu.py +0 -0
  26. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/08_flash_attention.py +0 -0
  27. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/09_data_types.py +0 -0
  28. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/10_generation_params.py +0 -0
  29. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/11_streaming.py +0 -0
  30. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/12_chat_templates.py +0 -0
  31. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/13_offline_mode.py +0 -0
  32. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/14_force_download.py +0 -0
  33. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/15_model_info.py +0 -0
  34. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/16_cpu_offloading.py +0 -0
  35. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/17_cpu_only.py +0 -0
  36. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/18_production_setup.py +0 -0
  37. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/19_gguf_4bit.py +0 -0
  38. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/20_gguf_5bit.py +0 -0
  39. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/21_gguf_6bit.py +0 -0
  40. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/22_gguf_8bit.py +0 -0
  41. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/23_gguf_16bit.py +0 -0
  42. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/24_list_models.py +0 -0
  43. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/25_interactive_chat.py +0 -0
  44. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_codes_camples/README.md +0 -0
  45. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_download_guide.py +0 -0
  46. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_examples.py +0 -0
  47. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_tq_ready_gguf.py +0 -0
  48. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/horus_transformers_features.py +0 -0
  49. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/local_models.py +0 -0
  50. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/neuralnode_v21_complete_demo.py +0 -0
  51. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/shade_model_with_tools.py +0 -0
  52. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/telegram_bot_demo.py +0 -0
  53. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/thinking_mode_example.py +0 -0
  54. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/tts_demo.py +0 -0
  55. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/turboquant_example.py +0 -0
  56. {neuralnode-2.0.9 → neuralnode-2.1.0}/examples/v3_features.py +0 -0
  57. {neuralnode-2.0.9 → neuralnode-2.1.0}/horus_chat_voice.py +0 -0
  58. {neuralnode-2.0.9 → neuralnode-2.1.0}/neuralnode_horus_replica_telegram.ipynb +0 -0
  59. {neuralnode-2.0.9 → neuralnode-2.1.0}/nn.md +0 -0
  60. {neuralnode-2.0.9 → neuralnode-2.1.0}/publish.bat +0 -0
  61. {neuralnode-2.0.9 → neuralnode-2.1.0}/publish.sh +0 -0
  62. {neuralnode-2.0.9 → neuralnode-2.1.0}/replica_output_85218.mp3 +0 -0
  63. {neuralnode-2.0.9 → neuralnode-2.1.0}/requirements_shade.txt +0 -0
  64. {neuralnode-2.0.9 → neuralnode-2.1.0}/scripts/setup.py +0 -0
  65. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/debug_import.py +0 -0
  66. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/agents/__init__.py +0 -0
  67. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/chains/__init__.py +0 -0
  68. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/config/__init__.py +0 -0
  69. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/core/__init__.py +0 -0
  70. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/core/openai_blocker.py +0 -0
  71. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/diagnostics/__init__.py +0 -0
  72. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/integrations/discord.py +0 -0
  73. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/integrations/slack.py +0 -0
  74. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/integrations/whatsapp.py +0 -0
  75. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/memory/__init__.py +0 -0
  76. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/memory/advanced.py +0 -0
  77. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/prompts/__init__.py +0 -0
  78. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/__init__.py +0 -0
  79. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/base.py +0 -0
  80. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/__init__.py +0 -0
  81. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/ai21.py +0 -0
  82. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/anthropic.py +0 -0
  83. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/cohere.py +0 -0
  84. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/deepseek.py +0 -0
  85. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/fireworks.py +0 -0
  86. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/google.py +0 -0
  87. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/groq.py +0 -0
  88. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/mistral.py +0 -0
  89. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/perplexity.py +0 -0
  90. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat/together.py +0 -0
  91. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/chat_models.py +0 -0
  92. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/embeddings.py +0 -0
  93. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/local/__init__.py +0 -0
  94. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/local_providers.py +0 -0
  95. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/text_generation.py +0 -0
  96. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/providers/universal_local.py +0 -0
  97. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/rag/__init__.py +0 -0
  98. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/rag/loaders.py +0 -0
  99. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/reasoning/__init__.py +0 -0
  100. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/replica.py +0 -0
  101. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/speech/__init__.py +0 -0
  102. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/thinking.py +0 -0
  103. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/__init__.py +0 -0
  104. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/advanced.py +0 -0
  105. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/multisearch.py +0 -0
  106. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/system/__init__.py +0 -0
  107. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/system/operations.py +0 -0
  108. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tools/web/__init__.py +0 -0
  109. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/tts/__init__.py +0 -0
  110. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/turboquant.py +0 -0
  111. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/utils/__init__.py +0 -0
  112. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/utils/dependencies.py +0 -0
  113. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/utils/logger.py +0 -0
  114. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/utils/metrics.py +0 -0
  115. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/vectorstores/__init__.py +0 -0
  116. {neuralnode-2.0.9 → neuralnode-2.1.0}/src/neuralnode/vision/__init__.py +0 -0
  117. {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.9
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.9"
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"
@@ -42,7 +42,7 @@ Quick Start::
42
42
  text = sr.listen()
43
43
  """
44
44
 
45
- __version__ = "2.0.9"
45
+ __version__ = "2.1.0"
46
46
  __author__ = "NeuralNode Contributors"
47
47
 
48
48
  # ── Core types ────────────────────────────────────────────────────────────────
@@ -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._run_agent(task)
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._run_agent(task)
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._run_agent(task)
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) Answer in the same language as the user's latest message unless the user explicitly requests another language.\n"
108
- "2) Prioritize factual accuracy. Do not invent facts, sources, citations, URLs, names, numbers, or events.\n"
109
- "3) If information is uncertain or missing, say so clearly and ask a short clarifying question instead of guessing.\n"
110
- "4) Be concise, direct, and non-repetitive. Avoid restating the same point with different wording.\n"
111
- "5) Keep internal reasoning private. Return only the final answer.\n"
112
- "6) For instructions that require steps, provide clear actionable steps without filler.\n"
113
- "7) If the user asks for code, produce correct runnable code and mention assumptions briefly.\n"
114
- "8) If the user request is unsafe or harmful, refuse briefly and offer a safe alternative.\n"
115
- "9) Do not repeatedly introduce yourself. Only provide your identity if the user explicitly asks who you are.\n"
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 short, useful, and in the user's language?"
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 the following tools. When you need to use a tool, respond with a JSON object in this format:
126
- {"tool": "tool_name", "arguments": {"arg1": "value1", "arg2": "value2"}}
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 = True,
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
- "Install with: pip install llama-cpp-python"
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
- "Install with: pip install transformers torch"
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
- "torch_dtype": self.torch_dtype,
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