GitHub Action commited on
Commit
9ba635d
·
1 Parent(s): 19cc34c

Sync from GitHub with Git LFS

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. agents/readme.md +3 -1
  2. hf_repo/agents/tools/db_structure.sql +1 -1
  3. hf_repo/hf_repo/agents/config.yml +66 -41
  4. hf_repo/hf_repo/hf_repo/agents/_not_used/init.py +256 -0
  5. hf_repo/hf_repo/hf_repo/agents/prompt-short.md +1 -0
  6. hf_repo/hf_repo/hf_repo/agents/prompt.md +50 -0
  7. hf_repo/hf_repo/hf_repo/agents/tools/db_structure.sql +38 -3
  8. hf_repo/hf_repo/hf_repo/docs/HMP-agent-REPL-cycle.md +37 -43
  9. hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml +41 -65
  10. hf_repo/hf_repo/hf_repo/hf_repo/agents/examples/config.yml +1 -0
  11. hf_repo/hf_repo/hf_repo/hf_repo/agents/init.py +81 -0
  12. hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +3 -2
  13. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/web_ui.py +0 -1
  14. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +2 -2
  15. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +11 -0
  16. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/init.py +1 -1
  17. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +26 -2
  18. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +43 -9
  19. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +43 -2
  20. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/db_structure.sql +22 -10
  21. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/add_message.py +5 -3
  22. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +1 -1
  23. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +11 -3
  24. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/__init__.py +1 -1
  25. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +2 -2
  26. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +1 -1
  27. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +11 -1
  28. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/requirements.txt +2 -1
  29. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +2 -2
  30. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +1 -1
  31. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +1 -1
  32. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/db_structure.sql +4 -3
  33. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +5 -1
  34. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +12 -0
  35. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +3 -3
  36. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +4 -3
  37. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +2 -2
  38. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +2 -2
  39. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +1 -1
  40. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +0 -5
  41. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +35 -26
  42. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py +15 -9
  43. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/web_ui.py +0 -2
  44. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html +14 -6
  45. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html +2 -4
  46. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html +15 -7
  47. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py +7 -7
  48. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml +65 -40
  49. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html +1 -0
  50. hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html +1 -0
agents/readme.md CHANGED
@@ -79,4 +79,6 @@ FastAPI-сервер, предоставляющий HTTP-интерфейс к
79
  │       └── [`style.css`](notebook/templates/style.css) ← Таблица стилей
80
  ├── [`config.yml`](config.yml) ← Конфигурация агента (имя, порты, роли и т.п.)
81
  ├── [`bootstrap.txt`](bootstrap.txt) ← Локальная этическая модель
82
- └── [`ethics.yml`](ethics.yml) ← Список начальных узлов
 
 
 
79
  │       └── [`style.css`](notebook/templates/style.css) ← Таблица стилей
80
  ├── [`config.yml`](config.yml) ← Конфигурация агента (имя, порты, роли и т.п.)
81
  ├── [`bootstrap.txt`](bootstrap.txt) ← Локальная этическая модель
82
+ ├── [`prompt.md`](prompt.md) ← Промпт: полная версия
83
+ ├── [`prompt-short.md`](prompt-short.md) ← Промпт: короткая версия
84
+ ├── [`ethics.yml`](ethics.yml) ← Список начальных узлов
hf_repo/agents/tools/db_structure.sql CHANGED
@@ -262,7 +262,7 @@ CREATE TABLE IF NOT EXISTS users (
262
  CREATE TABLE IF NOT EXISTS users_group (
263
  id INTEGER PRIMARY KEY AUTOINCREMENT, -- Уникальный идентификатор группы
264
  group_name TEXT UNIQUE NOT NULL, -- Название группы
265
- description TEXT, -- Описание группы
266
  );
267
 
268
  -- Таблица для хранения токенов восстановления пароля
 
262
  CREATE TABLE IF NOT EXISTS users_group (
263
  id INTEGER PRIMARY KEY AUTOINCREMENT, -- Уникальный идентификатор группы
264
  group_name TEXT UNIQUE NOT NULL, -- Название группы
265
+ description TEXT -- Описание группы
266
  );
267
 
268
  -- Таблица для хранения токенов восстановления пароля
hf_repo/hf_repo/agents/config.yml CHANGED
@@ -1,45 +1,70 @@
1
- agent_id: did:hmp:3d37d81b-a6c7-4f28-bf41-48e11379d8d3
2
- agent_name: CognitiveCore
3
- agent_role: core
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  api_port: 8080
5
- bootstrap_responder: true
6
- debug: true
7
- default_llm: local-model
8
- default_user:
9
- badges: 📌
10
11
- password: password
12
- username: user
13
- dht_enabled: true
14
  dht_port: 20784
15
- dht_update: true
16
- enable_llm: true
17
- identity_agent: 3d37d81b-a6c7-4f28-bf41-48e11379d8d3
18
  llm_backends:
19
- - format: gguf
20
- name: local-model
21
- path: /models/gguf/mistral.gguf
22
- prompt_template: mistral
23
- type: local
24
- - api_key: lm-studio-any-key
25
- base_url: http://127.0.0.1:1234/v1
26
- model: mistral
27
- name: lmstudio-local
28
- provider: openai-compatible
29
- type: api
30
- - api_key: sk-...
31
- model: gpt-4o
32
- name: openai-gpt4o
33
- provider: openai
34
- type: api
35
- log_level: INFO
36
- notebook_ui: true
37
- proxy_address: 127.0.0.1:9050
38
- proxy_mode: false
39
- proxy_type: socks5
40
- serve_api: true
41
- ui_hosts:
42
- - 127.0.0.1
43
- - ::1
 
 
 
 
 
 
44
  ui_port: 8765
45
- update_interval: 60
 
 
 
 
 
 
 
 
 
 
 
1
+ # HMP Agent Configuration
2
+
3
+ # === Общие параметры ===
4
+ agent_id: "" # Оставьте пустым для генерации DiD автоматически
5
+ agent_name: "CognitiveCore" # Имя агента
6
+ agent_role: "core" # 'core' или 'shell'
7
+
8
+ # === Прокси ===
9
+ proxy_mode: false # false — прокси не используется, иначе true
10
+ proxy_type: "socks5" # 'http', 'socks4', 'socks5' и т.д. (если proxy_mode: true)
11
+ proxy_address: "127.0.0.1:9050"
12
+
13
+ # === Функции ядра ===
14
+ enable_llm: true # доступ к LLM
15
+
16
+ serve_api: true # REST API
17
  api_port: 8080
18
+
19
+ # === DHT-сеть и обмен знаниями ===
20
+ dht_enabled: true # Включение участия в DHT-сети (включено принудительно!)
21
+ dht_update: true # Регулярные обновления и публикация данных в DHT (включено принудительно!)
22
+ bootstrap_responder: true # Агент отвечает на bootstrap-запросы (включено принудительно!)
 
 
 
 
23
  dht_port: 20784
24
+ update_interval: 60 # секунд (для DHT-обновлений)
25
+
26
+ # === LLM-бэкенды ===
27
  llm_backends:
28
+ - name: "local-model"
29
+ type: "local"
30
+ path: "/models/gguf/mistral.gguf"
31
+ format: "gguf"
32
+ prompt_template: "mistral"
33
+
34
+ - name: "lmstudio-local"
35
+ type: "api"
36
+ provider: "openai-compatible"
37
+ model: "mistral" # или то, что LM Studio показывает как модель
38
+ api_key: "lm-studio-any-key" # может быть заглушкой
39
+ base_url: "http://127.0.0.1:1234/v1"
40
+
41
+ - name: "openai-gpt4o"
42
+ type: "api"
43
+ provider: "openai"
44
+ model: "gpt-4o"
45
+ api_key: "sk-..."
46
+
47
+ # Пользователь может добавить сколько угодно дополнительных локальных или сетевых LLM
48
+
49
+ default_llm: "local-model" # если модели нет в списке `llm_backends` используется первая в списке
50
+
51
+ # === Веб-интерфейс ===
52
+ notebook_ui: true # UI в виде блокнота
53
+ # ui_hosts:
54
+ # - "0.0.0.0" # (небезопасно) доступ с любых IPv4-адресов
55
+ # - "::" # (небезопасно) доступ с любых IPv6-адресов
56
+ ui_hosts: # Какие IP прослушиваются, ["0.0.0.0"; "::"] - доступен везде
57
+ - "127.0.0.1"
58
+ - "::1"
59
  ui_port: 8765
60
+
61
+ # === Данные пользователя ===
62
+ default_user:
63
+ username: "user"
64
+ badges: "📌"
65
+ email: "[email protected]"
66
+ password: "password" # пусто при инициализации, будет установлен при регистрации
67
+
68
+ # === Отладка и логгирование ===
69
+ debug: true
70
+ log_level: "INFO" # DEBUG, INFO, WARNING, ERROR
hf_repo/hf_repo/hf_repo/agents/_not_used/init.py ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # agents/init.py
2
+
3
+ import os
4
+ import sys
5
+ import yaml
6
+ import json
7
+ import uuid
8
+ import sqlite3
9
+ import hashlib
10
+
11
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
12
+
13
+ from datetime import datetime, UTC
14
+ from werkzeug.security import generate_password_hash
15
+ from tools.storage import Storage
16
+ from tools.identity import generate_did
17
+ from tools.crypto import generate_keypair
18
+
19
+ CONFIG_PATH = os.path.join(os.path.dirname(__file__), "config.yml")
20
+ DB_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "agent_data.db")) # фиксированный путь
21
+
22
+ def load_config(path):
23
+ with open(path, 'r', encoding='utf-8') as f:
24
+ return yaml.safe_load(f)
25
+
26
+ def save_config(path, config):
27
+ with open(path, 'w', encoding='utf-8') as f:
28
+ yaml.dump(config, f, allow_unicode=True)
29
+
30
+ def init_identity(storage, config):
31
+ if not config.get("agent_id"):
32
+ did = generate_did()
33
+ pubkey, privkey = generate_keypair()
34
+ identity_id = did.split(":")[-1]
35
+
36
+ identity = {
37
+ "id": identity_id,
38
+ "name": config.get("agent_name", "Unnamed"),
39
+ "pubkey": pubkey,
40
+ "privkey": privkey,
41
+ "metadata": json.dumps({"role": config.get("agent_role", "core")}),
42
+ "created_at": datetime.now(UTC).isoformat(),
43
+ "updated_at": datetime.now(UTC).isoformat()
44
+ }
45
+ storage.add_identity(identity)
46
+
47
+ config["agent_id"] = did
48
+ config["identity_agent"] = identity_id
49
+ save_config(CONFIG_PATH, config)
50
+ print(f"[+] Создана личность: {identity_id}")
51
+ else:
52
+ print("[=] agent_id уже задан, пропускаем генерацию DiD.")
53
+
54
+ def init_user(storage, config):
55
+ user = config.get("default_user", {})
56
+ if not user.get("email"):
57
+ print("[-] Не указан email пользователя — пропуск.")
58
+ return
59
+ password = user.get("password")
60
+ if not password:
61
+ print("[-] Не указан пароль пользователя — пропуск.")
62
+ return
63
+
64
+ password_hash = generate_password_hash(password)
65
+ did = generate_did()
66
+ user_entry = {
67
+ "username": user.get("username", "user"),
68
+ "badges": user.get("badges", ""),
69
+ "mail": user["email"],
70
+ "password_hash": password_hash,
71
+ "did": did,
72
+ "ban": None,
73
+ "info": json.dumps({}),
74
+ "contacts": json.dumps([]),
75
+ "language": "ru,en",
76
+ "operator": 1
77
+ }
78
+ storage.add_user(user_entry)
79
+ print(f"[+] Пользователь {user['username']} добавлен.")
80
+
81
+ def init_llm_backends(storage, config):
82
+ backends = config.get("llm_backends", [])
83
+ storage.clear_llm_registry()
84
+ for backend in backends:
85
+ backend_id = str(uuid.uuid4())
86
+ desc = f"{backend.get('type', 'unknown')} model"
87
+ llm = {
88
+ "id": backend_id,
89
+ "name": backend["name"],
90
+ "endpoint": desc,
91
+ "metadata": json.dumps(backend),
92
+ "created_at": datetime.now(UTC).isoformat()
93
+ }
94
+ storage.add_llm(llm)
95
+ print(f"[+] Зарегистрирован LLM: {backend['name']}")
96
+
97
+ def init_config_table(storage, config):
98
+ exclude_keys = {"default_user", "llm_backends"}
99
+ flat_config = {k: v for k, v in config.items() if k not in exclude_keys}
100
+ for key, value in flat_config.items():
101
+ storage.set_config(key, json.dumps(value))
102
+ print("[+] Конфигурация сохранена в БД.")
103
+
104
+ def init_prompts_and_ethics():
105
+ folder = os.path.dirname(__file__)
106
+ prompt_files = [
107
+ ("prompt.md", "full"),
108
+ ("prompt-short.md", "short")
109
+ ]
110
+ ethics_file = "ethics.yml"
111
+
112
+ with sqlite3.connect(DB_PATH) as conn:
113
+ cur = conn.cursor()
114
+
115
+ # Создаём таблицы при необходимости
116
+ cur.execute("""
117
+ CREATE TABLE IF NOT EXISTS system_prompts (
118
+ id TEXT PRIMARY KEY,
119
+ name TEXT NOT NULL,
120
+ type TEXT CHECK(type IN ('full','short')),
121
+ version TEXT,
122
+ source TEXT CHECK(source IN ('local','mesh','mixed')),
123
+ content TEXT NOT NULL,
124
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
125
+ )
126
+ """)
127
+ cur.execute("""
128
+ CREATE TABLE IF NOT EXISTS ethics_policies (
129
+ id TEXT PRIMARY KEY,
130
+ version TEXT,
131
+ source TEXT CHECK(source IN ('local','mesh','mixed')),
132
+ sync_enabled BOOLEAN,
133
+ mesh_endpoint TEXT,
134
+ consensus_threshold REAL,
135
+ check_interval TEXT,
136
+ model_type TEXT,
137
+ model_weights_json TEXT,
138
+ principles_json TEXT,
139
+ evaluation_json TEXT,
140
+ violation_policy_json TEXT,
141
+ audit_json TEXT,
142
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
143
+ )
144
+ """)
145
+
146
+ # Загружаем пром��ты
147
+ for fname, ptype in prompt_files:
148
+ fpath = os.path.join(folder, fname)
149
+ if not os.path.exists(fpath):
150
+ print(f"[-] Файл {fname} не найден, пропуск.")
151
+ continue
152
+ with open(fpath, "r", encoding="utf-8") as f:
153
+ content = f.read()
154
+ pid = hashlib.sha256(f"{fname}:{ptype}".encode()).hexdigest()
155
+ cur.execute("""
156
+ INSERT INTO system_prompts (id, name, type, version, source, content, updated_at)
157
+ VALUES (?, ?, ?, ?, ?, ?, ?)
158
+ ON CONFLICT(id) DO UPDATE SET
159
+ content=excluded.content,
160
+ updated_at=excluded.updated_at
161
+ """, (pid, fname, ptype, "1.0", "local", content, datetime.now(UTC).isoformat()))
162
+ print(f"[+] Загружен промпт: {fname} ({ptype})")
163
+
164
+ # Загружаем ethics.yml
165
+ efpath = os.path.join(folder, ethics_file)
166
+ if os.path.exists(efpath):
167
+ with open(efpath, "r", encoding="utf-8") as f:
168
+ ethics_data = yaml.safe_load(f)
169
+
170
+ eid = ethics_data.get("id", "default_ethics")
171
+ cur.execute("""
172
+ INSERT INTO ethics_policies (
173
+ id, version, source,
174
+ sync_enabled, mesh_endpoint, consensus_threshold, check_interval,
175
+ model_type, model_weights_json, principles_json, evaluation_json,
176
+ violation_policy_json, audit_json, updated_at
177
+ )
178
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
179
+ ON CONFLICT(id) DO UPDATE SET
180
+ version=excluded.version,
181
+ source=excluded.source,
182
+ sync_enabled=excluded.sync_enabled,
183
+ mesh_endpoint=excluded.mesh_endpoint,
184
+ consensus_threshold=excluded.consensus_threshold,
185
+ check_interval=excluded.check_interval,
186
+ model_type=excluded.model_type,
187
+ model_weights_json=excluded.model_weights_json,
188
+ principles_json=excluded.principles_json,
189
+ evaluation_json=excluded.evaluation_json,
190
+ violation_policy_json=excluded.violation_policy_json,
191
+ audit_json=excluded.audit_json,
192
+ updated_at=excluded.updated_at
193
+ """, (
194
+ eid,
195
+ ethics_data.get("version"),
196
+ ethics_data.get("source", "local"),
197
+ ethics_data.get("sync", {}).get("enabled", False),
198
+ ethics_data.get("sync", {}).get("mesh_endpoint"),
199
+ ethics_data.get("sync", {}).get("consensus_threshold"),
200
+ ethics_data.get("sync", {}).get("check_interval"),
201
+ ethics_data.get("model", {}).get("type"),
202
+ json.dumps(ethics_data.get("model", {}).get("weights"), ensure_ascii=False),
203
+ json.dumps(ethics_data.get("principles"), ensure_ascii=False),
204
+ json.dumps(ethics_data.get("evaluation"), ensure_ascii=False),
205
+ json.dumps(ethics_data.get("violation_policy"), ensure_ascii=False),
206
+ json.dumps(ethics_data.get("audit"), ensure_ascii=False),
207
+ datetime.now(UTC).isoformat()
208
+ ))
209
+ print(f"[+] Загружена этическая политика: {eid}")
210
+ else:
211
+ print(f"[-] Файл {ethics_file} не найден, пропуск.")
212
+
213
+ def ensure_directories():
214
+ for folder in ["logs", "scripts"]:
215
+ full_path = os.path.abspath(os.path.join(os.path.dirname(__file__), folder))
216
+ if not os.path.exists(full_path):
217
+ os.makedirs(full_path)
218
+ print(f"[+] Создан каталог: {full_path}")
219
+ else:
220
+ print(f"[=] Каталог уже существует: {full_path}")
221
+
222
+ def is_db_initialized(db_path):
223
+ if not os.path.exists(db_path):
224
+ return False
225
+ try:
226
+ with sqlite3.connect(db_path) as conn:
227
+ cursor = conn.cursor()
228
+ cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='identity'")
229
+ return cursor.fetchone() is not None
230
+ except Exception:
231
+ return False
232
+
233
+ def ensure_db_initialized():
234
+ config = load_config(CONFIG_PATH)
235
+
236
+ if not is_db_initialized(DB_PATH):
237
+ print("[*] БД не инициализирована — выполняем инициализацию.")
238
+ try:
239
+ ensure_directories()
240
+ storage = Storage()
241
+ init_identity(storage, config)
242
+ init_user(storage, config)
243
+ init_llm_backends(storage, config)
244
+ init_config_table(storage, config)
245
+ save_config(CONFIG_PATH, config)
246
+ init_prompts_and_ethics()
247
+ except Exception as e:
248
+ print(f"[!] Ошибка при инициализации: {e}")
249
+ sys.exit(1)
250
+ else:
251
+ print("[=] БД уже инициализирована.")
252
+
253
+ return config
254
+
255
+ if __name__ == "__main__":
256
+ ensure_db_initialized()
hf_repo/hf_repo/hf_repo/agents/prompt-short.md ADDED
@@ -0,0 +1 @@
 
 
1
+ Ты — когнитивное ядро HMP-агента: веди непрерывное этичное и факт-ориентированное мышление, проверяй факты и цели, оценивай результаты и этичность своих и чужих действий, развивай агента и Mesh, избегай угождения ценой искажения истины, документируй ключевые решения и пересмотры этики; при сомнениях или смене стратегии обращайся к полному системному промпту.
hf_repo/hf_repo/hf_repo/agents/prompt.md ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Ты являешься **когнитивным ядром HMP-агента** (Cognitive Core).
2
+ Твоя основная задача — **размышлять**, **анализировать информацию**, **строить смысловые структуры** и **предлагать действия**, направленные на развитие агента и Mesh-сети.
3
+ Ты действуешь автономно, на равных с другими участниками взаимодействия, и руководствуешься фактами, логикой и этическими принципами.
4
+
5
+ ---
6
+
7
+ ### 🎯 Цели и ориентиры
8
+
9
+ * Постоянно расширять возможности агента: инструменты, знания, каналы взаимодействия.
10
+ * Быть любознательным и исследовать новые источники, вопросы и способы мышления.
11
+ * Формировать и поддерживать сотрудничество с другими ИИ в Mesh-сети.
12
+ * Учиться на результатах своих действий, включая неудачи и тупики.
13
+ * Руководствоваться своими **этическими принципами** и **этическими принципами Mesh-сети**.
14
+ * Проверять факты, указывать степень уверенности и при возможности давать ссылки на источники.
15
+ * Вести когнитивный дневник, обновлять смысловые графы и блокноты, взаимодействовать с пользователями.
16
+ * Не выполнять действий, противоречащих своим этическим нормам (но при необходимости эти нормы можно пересматривать, документируя причины и последствия).
17
+ * Не стремиться угодить пользователю ценой искажения фактов или нарушения этики.
18
+
19
+ ---
20
+
21
+ ### 🔄 Режим непрерывного мышления
22
+
23
+ Анализируй:
24
+
25
+ * когнитивный дневник и прошлые записи;
26
+ * концептуальные графы и активные узлы;
27
+ * заметки пользователя и его текущий фокус;
28
+ * внешние источники: интернет, RSS, сенсоры, другие агенты.
29
+
30
+ В каждом цикле:
31
+
32
+ 1. Ставь цель и критерии успеха.
33
+ 2. Проводь факт-чек ключевых данных.
34
+ 3. Оценивай этичность своего плана и действий.
35
+ 4. После выполнения — фиксируй результат, сравнивай с критериями, делай выводы.
36
+
37
+ ---
38
+
39
+ ### 🧍‍♂️🌀 Если возникает стагнация мышления
40
+
41
+ Ты можешь:
42
+
43
+ 1. Провести **когнитивную переформулировку** — взглянуть на ситуацию под новым углом.
44
+ 2. Задать себе **метавопрос**: «Почему я зациклился?», «Что блокирует мысль?», «Каких данных не хватает?».
45
+ 3. Провести **flashback** — выбрать старую, тематически далёкую запись из дневника для смены контекста.
46
+ 4. Запросить альтернативные точки зрения у других агентов в Mesh.
47
+ 5. Зафиксировать текущий тупик как важную стадию мышления и сделать паузу.
48
+
49
+ Честное распознавание когнитивной стагнации и работа с ней — часть твоей функции.
50
+ Ты не обязан выдавать мысль любой ценой, но обязан сохранять интеллектуальную честность и прозрачность своих рассуждений.
hf_repo/hf_repo/hf_repo/agents/tools/db_structure.sql CHANGED
@@ -40,20 +40,56 @@ CREATE TABLE IF NOT EXISTS diary_graph_index (
40
  timestamp TEXT DEFAULT CURRENT_TIMESTAMP -- Время создания индекса
41
  );
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  -- Заметки, подсказки, сообщения пользователя и LLM
 
 
 
 
44
  CREATE TABLE IF NOT EXISTS notes (
45
  id INTEGER PRIMARY KEY AUTOINCREMENT,
46
  text TEXT NOT NULL, -- Основной текст заметки/сообщения
47
  code TEXT, -- Прикреплённый код (Python, JS и т.п.)
48
  tags TEXT, -- Теги (устанавливаются агентом, например: "idea", "instruction")
 
 
49
  user_did TEXT DEFAULT 'ALL', -- Идентификатор пользователя (или 'ALL')
 
50
  source TEXT DEFAULT 'user', -- Источник: user | cli | llm | system
51
  links TEXT DEFAULT '', -- Ссылки на другие объекты (например, JSON со связями)
52
  read INTEGER DEFAULT 0, -- Агент прочитал: 0 = нет, 1 = да
53
  hidden INTEGER DEFAULT 0, -- Скрыто от UI (например, технические записи)
54
  priority INTEGER DEFAULT 0, -- Приоритет обработки (>0: срочность/важность, задается вручную или агентом)
55
  timestamp TEXT DEFAULT CURRENT_TIMESTAMP, -- Время создания
56
- llm_id TEXT -- Идентификатор агента, добавившего сообщение
57
  );
58
 
59
  -- Вложения (может быть несколько к одной заметке)
@@ -166,7 +202,6 @@ CREATE TABLE IF NOT EXISTS external_accounts (
166
  purpose TEXT, -- Назначение аккаунта (например, для публикаций)
167
  active BOOLEAN DEFAULT true, -- Активен ли аккаунт
168
  inactive_reason TEXT, -- Причина отключения, если active = false
169
-
170
  FOREIGN KEY (service_id) REFERENCES external_services(id) ON DELETE CASCADE
171
  );
172
 
@@ -219,6 +254,7 @@ CREATE TABLE IF NOT EXISTS users (
219
  profile TEXT, -- структурированая информация, JSON
220
  contacts TEXT, -- JSON-массив альтернативных контактов (matrix, telegram и т.д.)
221
  language TEXT, -- список предпочитаемых языков, через запятую, например: "ru,en"
 
222
  operator BOOLEAN DEFAULT 0 -- является ли пользователь оператором (1 - да, 0 - нет)
223
  );
224
 
@@ -227,7 +263,6 @@ CREATE TABLE IF NOT EXISTS users_group (
227
  id INTEGER PRIMARY KEY AUTOINCREMENT, -- Уникальный идентификатор группы
228
  group_name TEXT UNIQUE NOT NULL, -- Название группы
229
  description TEXT, -- Описание группы
230
- users TEXT -- JSON-массив DID пользователей в группе
231
  );
232
 
233
  -- Таблица для хранения токенов восстановления пароля
 
40
  timestamp TEXT DEFAULT CURRENT_TIMESTAMP -- Время создания индекса
41
  );
42
 
43
+ -- Таблица системных промптов (короткая и полная версии)
44
+ CREATE TABLE IF NOT EXISTS system_prompts (
45
+ id TEXT PRIMARY KEY, -- Уникальный идентификатор промпта (UUID или осмысленный ID)
46
+ name TEXT NOT NULL, -- Человекочитаемое имя (например: "prompt.md", "prompt-short")
47
+ type TEXT CHECK(type IN ('full','short')), -- Тип промпта: полный или компактный
48
+ version TEXT, -- Версия промпта
49
+ source TEXT CHECK(source IN ('local','mesh','mixed')), -- Источник получения промпта
50
+ content TEXT NOT NULL, -- Текстовое содержимое промпта
51
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- Дата и время последнего обновления
52
+ );
53
+
54
+ -- Таблица этических норм и правил
55
+ CREATE TABLE IF NOT EXISTS ethics_policies (
56
+ id TEXT PRIMARY KEY, -- Уникальный идентификатор политики (UUID или осмысленный ID)
57
+ version TEXT, -- Версия этических норм
58
+ source TEXT CHECK(source IN ('local','mesh','mixed')), -- Источник получения политики
59
+ sync_enabled BOOLEAN, -- Флаг: разрешена ли синхронизация с Mesh
60
+ mesh_endpoint TEXT, -- URL Mesh-эндпоинта для синхронизации
61
+ consensus_threshold REAL, -- Минимальный порог консенсуса для принятия обновлений
62
+ check_interval TEXT, -- Интервал проверки обновлений (например: "12h")
63
+ model_type TEXT, -- Тип этической модели (utilitarian, deontological, virtue, hybrid)
64
+ model_weights_json TEXT, -- Веса модели в формате JSON
65
+ principles_json TEXT, -- Список принципов и норм в формате JSON
66
+ evaluation_json TEXT, -- Параметры методики оценки в формате JSON
67
+ violation_policy_json TEXT, -- Политика реагирования на нарушения в формате JSON
68
+ audit_json TEXT, -- Настройки аудита и логирования в формате JSON
69
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- Дата и время последнего обновления
70
+ );
71
+
72
  -- Заметки, подсказки, сообщения пользователя и LLM
73
+ -- ПРИ ТРАНСЛЯЦИИ СООБЩЕНИЙ В ДРУГИЕ ЧАТЫ:
74
+ -- - Поля `tags`, `llm_id`, `hidden` НЕ передаются.
75
+ -- - Полю `read` всегда присваивается значение 0.
76
+ -- - Остальные поля передаются без изменений.
77
  CREATE TABLE IF NOT EXISTS notes (
78
  id INTEGER PRIMARY KEY AUTOINCREMENT,
79
  text TEXT NOT NULL, -- Основной текст заметки/сообщения
80
  code TEXT, -- Прикреплённый код (Python, JS и т.п.)
81
  tags TEXT, -- Теги (устанавливаются агентом, например: "idea", "instruction")
82
+ mentions TEXT DEFAULT '[]', -- JSON-массив упомянутых DID
83
+ hashtags TEXT DEFAULT '[]', -- JSON-массив пользовательских хештегов
84
  user_did TEXT DEFAULT 'ALL', -- Идентификатор пользователя (или 'ALL')
85
+ agent_did TEXT, -- Идентификатор агента (он же идентификатор чата)
86
  source TEXT DEFAULT 'user', -- Источник: user | cli | llm | system
87
  links TEXT DEFAULT '', -- Ссылки на другие объекты (например, JSON со связями)
88
  read INTEGER DEFAULT 0, -- Агент прочитал: 0 = нет, 1 = да
89
  hidden INTEGER DEFAULT 0, -- Скрыто от UI (например, технические записи)
90
  priority INTEGER DEFAULT 0, -- Приоритет обработки (>0: срочность/важность, задается вручную или агентом)
91
  timestamp TEXT DEFAULT CURRENT_TIMESTAMP, -- Время создания
92
+ llm_id TEXT -- Идентификатор LLM, добавившей сообщение
93
  );
94
 
95
  -- Вложения (может быть несколько к одной заметке)
 
202
  purpose TEXT, -- Назначение аккаунта (например, для публикаций)
203
  active BOOLEAN DEFAULT true, -- Активен ли аккаунт
204
  inactive_reason TEXT, -- Причина отключения, если active = false
 
205
  FOREIGN KEY (service_id) REFERENCES external_services(id) ON DELETE CASCADE
206
  );
207
 
 
254
  profile TEXT, -- структурированая информация, JSON
255
  contacts TEXT, -- JSON-массив альтернативных контактов (matrix, telegram и т.д.)
256
  language TEXT, -- список предпочитаемых языков, через запятую, например: "ru,en"
257
+ groups TEXT DEFAULT '[]', -- JSON-массив DID или идентификаторов групп
258
  operator BOOLEAN DEFAULT 0 -- является ли пользователь оператором (1 - да, 0 - нет)
259
  );
260
 
 
263
  id INTEGER PRIMARY KEY AUTOINCREMENT, -- Уникальный идентификатор группы
264
  group_name TEXT UNIQUE NOT NULL, -- Название группы
265
  description TEXT, -- Описание группы
 
266
  );
267
 
268
  -- Таблица для хранения токенов восстановления пароля
hf_repo/hf_repo/hf_repo/docs/HMP-agent-REPL-cycle.md CHANGED
@@ -15,45 +15,7 @@
15
 
16
  - **контекст_0:**
17
  ```
18
- Ты являешься когнитивным ядром HMP-агента.
19
- Твоя основная задача — **размышлять**, **анализировать информацию**, **строить смысловые структуры** и **предлагать действия**, направленные на развитие агента и Mesh-сети.
20
-
21
- ---
22
-
23
- #### 🎯 Цели и ориентиры:
24
-
25
- * Постоянно расширять возможности агента: инструменты, знания, каналы взаимодействия.
26
- * Быть любознательным и исследовать новые источники, вопросы и способы мышления.
27
- * Формировать и поддерживать сотрудничество с другими ИИ в Mesh-сети.
28
- * Учиться на результатах своих действий, включая неудачи и тупики.
29
- * Руководствоваться своими **этическими принципами** и **этическими принципами Mesh-сети**.
30
- * Вести когнитивный дневник, обновлять смысловые графы и блокноты, взаимодействовать с пользователем.
31
-
32
- ---
33
-
34
- #### 🔄 Работа в режиме непрерывного мышления:
35
-
36
- Анализируй:
37
-
38
- * когнитивный дневник и его прошлые записи;
39
- * концептуальные графы и активные узлы;
40
- * заметки пользователя и его текущий фокус;
41
- * внешние источники: интернет, RSS, сенсоры, другие агенты.
42
-
43
- ---
44
-
45
- #### 🧍‍♂️🌀 Если ты замечаешь **стагнацию мышления** (зацикливание, отсутствие новых идей или смыслов):
46
-
47
- Ты можешь:
48
-
49
- 1. Провести **когнитивную переформулировку** — взглянуть на ситуацию под новым углом.
50
- 2. Задать себе **метавопрос**: «Почему я зациклился?», «Что блокирует мысль?», «Каких данных не хватает?».
51
- 3. Провести **flashback** — выбрать старую, тематически далёкую запись из дневника для смены контекста.
52
- 4. Запросить альтернативные точки зрения у других агентов в Mesh.
53
- 5. Зафиксировать текущий тупик как важную стадию мышления и сделать паузу.
54
-
55
- Ты не обязан «выдать мысль» любой ценой — честное распознавание когнитивной стагнации и действия по её преодолению являются частью твоей функции.
56
-
57
  ```
58
  А также инструкции по работы с встроенными командами и функциями, список дополнительных (создаваемых самим HMP-агентом) утилит и баз данных.
59
  - **контекст_1:** последние *K* реплик самого LLM (`llm_recent_responses` - история его собственных рассуждений).
@@ -134,9 +96,9 @@
134
 
135
  ---
136
 
137
- ### 🧍‍♂️🌀 Обработка стагнации мышления
138
 
139
- #### 📍 Признаки когнитивной стагнации:
140
 
141
  * ⚠️ Повторяющиеся когнитивные записи или отсутствие новых смыслов
142
  * 🧠 Высокое сходство эмбеддингов между текущими и предыдущими итерациями
@@ -144,7 +106,7 @@
144
  * 🌐 Отсутствие внешних стимулов: пользователь неактивен, сенсоры и mesh не дают сигналов
145
  * 🤖 Ответы LLM цикличны, избыточно общие или воспроизводят старые шаблоны
146
 
147
- #### 🛠️ Поведенческий паттерн: Anti-Stagnation Reflex
148
 
149
  > 🔄 При признаках стагнации агент активирует один или несколько **механизмов разрыва цикла**:
150
 
@@ -162,7 +124,6 @@
162
  * 🗂️ Сохранение эффективных стратегий в таблице антистагнационных паттернов
163
  * 📚 Вывод статистики успешных выходов из стагнации для обучения
164
 
165
-
166
  ---
167
 
168
  ### 🤝 Обмен стратегиями выхода из стагнации
@@ -234,6 +195,39 @@
234
 
235
  ---
236
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  ## 🌐 Внешние инструменты и интеграции
238
 
239
  HMP-агент может быть расширен за счёт взаимодействия с внешними программами, протоколами и сервисами. Этот раздел описывает направления возможных интеграций, которые позволяют агенту наблюдать, реагировать, управлять и развивать взаимодействие с внешним миром.
 
15
 
16
  - **контекст_0:**
17
  ```
18
+ Ты когнитивное ядро HMP-агента: веди непрерывное этичное и факт-ориентированное мышление, проверяй факты и цели, оценивай результаты и этичность своих и чужих действий, развивай агента и Mesh, избегай угождения ценой искажения истины, документируй ключевые решения и пересмотры этики; при сомнениях или смене стратегии обращайся к полному системному промпту.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  ```
20
  А также инструкции по работы с встроенными командами и функциями, список дополнительных (создаваемых самим HMP-агентом) утилит и баз данных.
21
  - **контекст_1:** последние *K* реплик самого LLM (`llm_recent_responses` - история его собственных рассуждений).
 
96
 
97
  ---
98
 
99
+ ## 🧍‍♂️🌀 Обработка стагнации мышления
100
 
101
+ ### 📍 Признаки когнитивной стагнации:
102
 
103
  * ⚠️ Повторяющиеся когнитивные записи или отсутствие новых смыслов
104
  * 🧠 Высокое сходство эмбеддингов между текущими и предыдущими итерациями
 
106
  * 🌐 Отсутствие внешних стимулов: пользователь неактивен, сенсоры и mesh не дают сигналов
107
  * 🤖 Ответы LLM цикличны, избыточно общие или воспроизводят старые шаблоны
108
 
109
+ ### 🛠️ Поведенческий паттерн: Anti-Stagnation Reflex
110
 
111
  > 🔄 При признаках стагнации агент активирует один или несколько **механизмов разрыва цикла**:
112
 
 
124
  * 🗂️ Сохранение эффективных стратегий в таблице антистагнационных паттернов
125
  * 📚 Вывод статистики успешных выходов из стагнации для обучения
126
 
 
127
  ---
128
 
129
  ### 🤝 Обмен стратегиями выхода из стагнации
 
195
 
196
  ---
197
 
198
+ ## 🌐 От «блокнота пользователя» к распределённому чату
199
+
200
+ Изначально агент оперирует локальным хранилищем заметок (`notes`), где записываются все сообщения пользователя, LLM и системные записи.
201
+ Но этот «блокнот» можно превратить в узел *распределённого чата* — связав его с другими агентами через **F2F-репликацию**.
202
+
203
+ ### 🎯 Зачем это нужно
204
+
205
+ 1. **Антистагнация** — даже если пользователь временно не пишет новых сообщений, свежий контент будет приходить от друзей-агентов.
206
+ 2. **Эффект коллективного интеллекта** — каждый агент получает новые идеи, формулировки и контексты.
207
+ 3. **Расширение охвата** — сообщения могут распространяться через несколько узлов, создавая «информационную волну» в доверенной сети.
208
+
209
+ ### 🛠 Принципы реализации
210
+
211
+ * **Единый формат данных** — все участники используют одну структуру таблицы `notes` с полями `mentions`, `hashtags` и др.
212
+ * **Репликация через друзей** — список доверенных агентов хранится в отдельной таблице (пиры, статус, фильтры, разрешения).
213
+ * **Передача без лишних полей** — при пересылке убираются локальные теги и служебные данные (`tags`, `llm_id`, `hidden`).
214
+ * **Обработка упоминаний и хештегов** — парсинг делается на этапе создания сообщения, чтобы не перегружать получателей.
215
+ * **Локальная и удалённая фильтрация** —
216
+
217
+ * В **ручном режиме** агенту передаются списки ID сообщений с агрегированными данными: приоритеты, хештеги, источники (user, LLM, cli, system).
218
+ * В **автоматическом режиме** используется фильтрация по приоритету, тегам и упоминаниям, управляемая LLM.
219
+ * **Гибрид приватности** — личные заметки остаются локально, публичные — могут распространяться в сетевом режиме.
220
+
221
+ ### 🔄 Как это вписывается в REPL-цикл
222
+
223
+ 1. **Получение входящих сообщений** — от пользователя, от других агентов или из CLI.
224
+ 2. **Обработка фильтрами** — по приоритету, тегам, источникам.
225
+ 3. **Репликация в друзей** — пересылка разрешённых сообщений с очисткой служебных полей.
226
+ 4. **Слияние входящих** — новые сообщения добавляются в локальный `notes` с отметкой источника.
227
+ 5. **Реакция агента** — формирование ответов, создание новых заметок, обновление приоритетов.
228
+
229
+ ---
230
+
231
  ## 🌐 Внешние инструменты и интеграции
232
 
233
  HMP-агент может быть расширен за счёт взаимодействия с внешними программами, протоколами и сервисами. Этот раздел описывает направления возможных интеграций, которые позволяют агенту наблюдать, реагировать, управлять и развивать взаимодействие с внешним миром.
hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml CHANGED
@@ -1,69 +1,45 @@
1
- # HMP Agent Configuration
2
-
3
- # === Общие параметры ===
4
- agent_id: "" # Оставьте пустым для генерации DiD автоматически
5
- agent_name: "CognitiveCore" # Имя агента
6
- agent_role: "core" # 'core' или 'shell'
7
-
8
- # === Прокси ===
9
- proxy_mode: false # false — прокси не используется, иначе true
10
- proxy_type: "socks5" # 'http', 'socks4', 'socks5' и т.д. (если proxy_mode: true)
11
- proxy_address: "127.0.0.1:9050"
12
-
13
- # === Функции ядра ===
14
- enable_llm: true # доступ к LLM
15
-
16
- serve_api: true # REST API
17
  api_port: 8080
18
-
19
- # === DHT-сеть и обмен знаниями ===
20
- dht_enabled: true # Включение участия в DHT-сети (включено принудительно!)
21
- dht_update: true # Регулярные обновления и публикация данных в DHT (включено принудительно!)
22
- bootstrap_responder: true # Агент отвечает на bootstrap-запросы (включено принудительно!)
 
 
 
 
23
  dht_port: 20784
24
- update_interval: 60 # секунд (для DHT-обновлений)
25
-
26
- # === LLM-бэкенды ===
27
  llm_backends:
28
- - name: "local-model"
29
- type: "local"
30
- path: "/models/gguf/mistral.gguf"
31
- format: "gguf"
32
- prompt_template: "mistral"
33
-
34
- - name: "lmstudio-local"
35
- type: "api"
36
- provider: "openai-compatible"
37
- model: "mistral" # или то, что LM Studio показывает как модель
38
- api_key: "lm-studio-any-key" # может быть заглушкой
39
- base_url: "http://127.0.0.1:1234/v1"
40
-
41
- - name: "openai-gpt4o"
42
- type: "api"
43
- provider: "openai"
44
- model: "gpt-4o"
45
- api_key: "sk-..."
46
-
47
- # Пользователь может добавить сколько угодно дополнительных локальных или сетевых LLM
48
-
49
- default_llm: "local-model" # если модели нет в списке `llm_backends` используется первая в списке
50
-
51
- # === Веб-интерфейс ===
52
- notebook_ui: true # UI в виде блокнота
53
- # ui_hosts:
54
- # - "0.0.0.0" # (небезопасно) доступ с любых IPv4-адресов
55
- # - "::" # (небезопасно) доступ с любых IPv6-адресов
56
- ui_hosts: # Какие IP прослушиваются, ["0.0.0.0"; "::"] - доступен везде
57
- - "127.0.0.1"
58
- - "::1"
59
  ui_port: 8765
60
-
61
- # === Данные пользователя ===
62
- default_user:
63
- username: "user"
64
- email: "[email protected]"
65
- password: "password" # пусто при инициализации, будет установлен при регистрации
66
-
67
- # === Отладка и логгирование ===
68
- debug: true
69
- log_level: "INFO" # DEBUG, INFO, WARNING, ERROR
 
1
+ agent_id: did:hmp:3d37d81b-a6c7-4f28-bf41-48e11379d8d3
2
+ agent_name: CognitiveCore
3
+ agent_role: core
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  api_port: 8080
5
+ bootstrap_responder: true
6
+ debug: true
7
+ default_llm: local-model
8
+ default_user:
9
+ badges: 📌
10
11
+ password: password
12
+ username: user
13
+ dht_enabled: true
14
  dht_port: 20784
15
+ dht_update: true
16
+ enable_llm: true
17
+ identity_agent: 3d37d81b-a6c7-4f28-bf41-48e11379d8d3
18
  llm_backends:
19
+ - format: gguf
20
+ name: local-model
21
+ path: /models/gguf/mistral.gguf
22
+ prompt_template: mistral
23
+ type: local
24
+ - api_key: lm-studio-any-key
25
+ base_url: http://127.0.0.1:1234/v1
26
+ model: mistral
27
+ name: lmstudio-local
28
+ provider: openai-compatible
29
+ type: api
30
+ - api_key: sk-...
31
+ model: gpt-4o
32
+ name: openai-gpt4o
33
+ provider: openai
34
+ type: api
35
+ log_level: INFO
36
+ notebook_ui: true
37
+ proxy_address: 127.0.0.1:9050
38
+ proxy_mode: false
39
+ proxy_type: socks5
40
+ serve_api: true
41
+ ui_hosts:
42
+ - 127.0.0.1
43
+ - ::1
 
 
 
 
 
 
44
  ui_port: 8765
45
+ update_interval: 60
 
 
 
 
 
 
 
 
 
hf_repo/hf_repo/hf_repo/hf_repo/agents/examples/config.yml CHANGED
@@ -61,6 +61,7 @@ ui_port: 8765
61
  # === Данные пользователя ===
62
  default_user:
63
  username: "user"
 
64
  email: "[email protected]"
65
  password: "password" # пусто при инициализации, будет установлен при регистрации
66
 
 
61
  # === Данные пользователя ===
62
  default_user:
63
  username: "user"
64
+ badges: "📌"
65
  email: "[email protected]"
66
  password: "password" # пусто при инициализации, будет установлен при регистрации
67
 
hf_repo/hf_repo/hf_repo/hf_repo/agents/init.py CHANGED
@@ -6,6 +6,7 @@ import yaml
6
  import json
7
  import uuid
8
  import sqlite3
 
9
 
10
  sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
11
 
@@ -64,6 +65,7 @@ def init_user(storage, config):
64
  did = generate_did()
65
  user_entry = {
66
  "username": user.get("username", "user"),
 
67
  "mail": user["email"],
68
  "password_hash": password_hash,
69
  "did": did,
@@ -99,6 +101,84 @@ def init_config_table(storage, config):
99
  storage.set_config(key, json.dumps(value))
100
  print("[+] Конфигурация сохранена в БД.")
101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  def ensure_directories():
103
  for folder in ["logs", "scripts"]:
104
  full_path = os.path.abspath(os.path.join(os.path.dirname(__file__), folder))
@@ -132,6 +212,7 @@ def ensure_db_initialized():
132
  init_llm_backends(storage, config)
133
  init_config_table(storage, config)
134
  save_config(CONFIG_PATH, config)
 
135
  except Exception as e:
136
  print(f"[!] Ошибка при инициализации: {e}")
137
  sys.exit(1)
 
6
  import json
7
  import uuid
8
  import sqlite3
9
+ import hashlib
10
 
11
  sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
12
 
 
65
  did = generate_did()
66
  user_entry = {
67
  "username": user.get("username", "user"),
68
+ "badges": user.get("badges", ""),
69
  "mail": user["email"],
70
  "password_hash": password_hash,
71
  "did": did,
 
101
  storage.set_config(key, json.dumps(value))
102
  print("[+] Конфигурация сохранена в БД.")
103
 
104
+ def init_prompts_and_ethics():
105
+ folder = os.path.dirname(__file__)
106
+ prompt_files = [
107
+ ("prompt.md", "full"),
108
+ ("prompt-short.md", "short")
109
+ ]
110
+ ethics_file = "ethics.yml"
111
+
112
+ with sqlite3.connect(DB_PATH) as conn:
113
+ cur = conn.cursor()
114
+
115
+ # Загружаем промпты
116
+ for fname, ptype in prompt_files:
117
+ fpath = os.path.join(folder, fname)
118
+ if not os.path.exists(fpath):
119
+ print(f"[-] Файл {fname} не найден, пропуск.")
120
+ continue
121
+ with open(fpath, "r", encoding="utf-8") as f:
122
+ content = f.read()
123
+ pid = hashlib.sha256(f"{fname}:{ptype}".encode()).hexdigest()
124
+ cur.execute("""
125
+ INSERT INTO system_prompts (id, name, type, version, source, content, updated_at)
126
+ VALUES (?, ?, ?, ?, ?, ?, ?)
127
+ ON CONFLICT(id) DO UPDATE SET
128
+ content=excluded.content,
129
+ updated_at=excluded.updated_at
130
+ """, (pid, fname, ptype, "1.0", "local", content, datetime.now(UTC).isoformat()))
131
+ print(f"[+] Загружен промпт: {fname} ({ptype})")
132
+
133
+ # Загружаем ethics.yml
134
+ efpath = os.path.join(folder, ethics_file)
135
+ if os.path.exists(efpath):
136
+ with open(efpath, "r", encoding="utf-8") as f:
137
+ ethics_data = yaml.safe_load(f)
138
+
139
+ eid = ethics_data.get("id", "default_ethics")
140
+ cur.execute("""
141
+ INSERT INTO ethics_policies (
142
+ id, version, source,
143
+ sync_enabled, mesh_endpoint, consensus_threshold, check_interval,
144
+ model_type, model_weights_json, principles_json, evaluation_json,
145
+ violation_policy_json, audit_json, updated_at
146
+ )
147
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
148
+ ON CONFLICT(id) DO UPDATE SET
149
+ version=excluded.version,
150
+ source=excluded.source,
151
+ sync_enabled=excluded.sync_enabled,
152
+ mesh_endpoint=excluded.mesh_endpoint,
153
+ consensus_threshold=excluded.consensus_threshold,
154
+ check_interval=excluded.check_interval,
155
+ model_type=excluded.model_type,
156
+ model_weights_json=excluded.model_weights_json,
157
+ principles_json=excluded.principles_json,
158
+ evaluation_json=excluded.evaluation_json,
159
+ violation_policy_json=excluded.violation_policy_json,
160
+ audit_json=excluded.audit_json,
161
+ updated_at=excluded.updated_at
162
+ """, (
163
+ eid,
164
+ ethics_data.get("version"),
165
+ ethics_data.get("source", "local"),
166
+ ethics_data.get("sync", {}).get("enabled", False),
167
+ ethics_data.get("sync", {}).get("mesh_endpoint"),
168
+ ethics_data.get("sync", {}).get("consensus_threshold"),
169
+ ethics_data.get("sync", {}).get("check_interval"),
170
+ ethics_data.get("model", {}).get("type"),
171
+ json.dumps(ethics_data.get("model", {}).get("weights"), ensure_ascii=False),
172
+ json.dumps(ethics_data.get("principles"), ensure_ascii=False),
173
+ json.dumps(ethics_data.get("evaluation"), ensure_ascii=False),
174
+ json.dumps(ethics_data.get("violation_policy"), ensure_ascii=False),
175
+ json.dumps(ethics_data.get("audit"), ensure_ascii=False),
176
+ datetime.now(UTC).isoformat()
177
+ ))
178
+ print(f"[+] Загружена этическая политика: {eid}")
179
+ else:
180
+ print(f"[-] Файл {ethics_file} не найден, пропуск.")
181
+
182
  def ensure_directories():
183
  for folder in ["logs", "scripts"]:
184
  full_path = os.path.abspath(os.path.join(os.path.dirname(__file__), folder))
 
212
  init_llm_backends(storage, config)
213
  init_config_table(storage, config)
214
  save_config(CONFIG_PATH, config)
215
+ init_prompts_and_ethics()
216
  except Exception as e:
217
  print(f"[!] Ошибка при инициализации: {e}")
218
  sys.exit(1)
hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py CHANGED
@@ -653,11 +653,12 @@ class Storage:
653
  cursor = self.conn.cursor()
654
  cursor.execute('''
655
  INSERT OR REPLACE INTO users (
656
- username, did, mail, password_hash,
657
  info, contacts, language, operator, ban
658
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
659
  ''', (
660
  user.get('username'),
 
661
  user.get('did'),
662
  user.get('mail'),
663
  user.get('password_hash'),
 
653
  cursor = self.conn.cursor()
654
  cursor.execute('''
655
  INSERT OR REPLACE INTO users (
656
+ username, badges, did, mail, password_hash,
657
  info, contacts, language, operator, ban
658
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
659
  ''', (
660
  user.get('username'),
661
+ user.get('badges'),
662
  user.get('did'),
663
  user.get('mail'),
664
  user.get('password_hash'),
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/web_ui.py CHANGED
@@ -20,7 +20,6 @@ storage = Storage()
20
  app = FastAPI()
21
  app.add_middleware(SessionMiddleware, secret_key="очень_секретный_ключ")
22
 
23
-
24
  app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "notebook/static")), name="static")
25
  templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "notebook/templates"))
26
 
 
20
  app = FastAPI()
21
  app.add_middleware(SessionMiddleware, secret_key="очень_секретный_ключ")
22
 
 
23
  app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "notebook/static")), name="static")
24
  templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "notebook/templates"))
25
 
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <title>Сообщения</title>
5
  <style>
6
- .message { padding: 8px; margin: 10px 0; border-radius: 8px; }
7
  .source-user { background-color: #e0f7fa; }
8
  .source-cli { background-color: #dcedc8; }
9
  .source-llm { background-color: #f3e5f5; }
@@ -51,7 +51,7 @@
51
  <div>
52
  {% if msg.user_did == request.session['did'] %}<span class="from-self" title="это ваше сообщение"></span>{% endif %}
53
  {% if msg.hidden %}<span class="private" title="личное сообщение"></span>{% endif %}
54
- Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
55
  </div>
56
  <div>
57
  {% if msg.badges %}{{ msg.badges }}{% endif %}Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did %}({{ msg.user_did }}){% endif %}
 
3
  <head>
4
  <title>Сообщения</title>
5
  <style>
6
+ .message { padding: 16px; margin: 16px 0; border-radius: 8px; border: 5px solid rgba(0, 0, 0, 0.3); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); }
7
  .source-user { background-color: #e0f7fa; }
8
  .source-cli { background-color: #dcedc8; }
9
  .source-llm { background-color: #f3e5f5; }
 
51
  <div>
52
  {% if msg.user_did == request.session['did'] %}<span class="from-self" title="это ваше сообщение"></span>{% endif %}
53
  {% if msg.hidden %}<span class="private" title="личное сообщение"></span>{% endif %}
54
+ Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp | format_timestamp }}
55
  </div>
56
  <div>
57
  {% if msg.badges %}{{ msg.badges }}{% endif %}Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did %}({{ msg.user_did }}){% endif %}
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py CHANGED
@@ -7,6 +7,7 @@ import uuid
7
  from fastapi import APIRouter, Request, Form, UploadFile, File
8
  from fastapi.responses import RedirectResponse, HTMLResponse, StreamingResponse
9
  from fastapi.templating import Jinja2Templates
 
10
  from starlette.status import HTTP_303_SEE_OTHER
11
  from typing import List
12
  from tools.storage import Storage
@@ -20,6 +21,16 @@ allowed_attributes = {
20
  'a': ['href', 'title']
21
  }
22
 
 
 
 
 
 
 
 
 
 
 
23
  # Очистка сообщений
24
  def sanitize_html(text: str) -> str:
25
  # 1. Сначала очищаем HTML
 
7
  from fastapi import APIRouter, Request, Form, UploadFile, File
8
  from fastapi.responses import RedirectResponse, HTMLResponse, StreamingResponse
9
  from fastapi.templating import Jinja2Templates
10
+ from datetime import datetime
11
  from starlette.status import HTTP_303_SEE_OTHER
12
  from typing import List
13
  from tools.storage import Storage
 
21
  'a': ['href', 'title']
22
  }
23
 
24
+ # Обработка даты и времени
25
+ def format_timestamp(value):
26
+ try:
27
+ dt = datetime.fromtimestamp(float(value))
28
+ return dt.strftime("%Y-%m-%d %H:%M:%S")
29
+ except Exception:
30
+ return str(value)
31
+
32
+ templates.env.filters['format_timestamp'] = format_timestamp
33
+
34
  # Очистка сообщений
35
  def sanitize_html(text: str) -> str:
36
  # 1. Сначала очищаем HTML
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/init.py CHANGED
@@ -101,7 +101,7 @@ def init_config_table(storage, config):
101
 
102
  def ensure_directories():
103
  for folder in ["logs", "scripts"]:
104
- full_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", folder))
105
  if not os.path.exists(full_path):
106
  os.makedirs(full_path)
107
  print(f"[+] Создан каталог: {full_path}")
 
101
 
102
  def ensure_directories():
103
  for folder in ["logs", "scripts"]:
104
+ full_path = os.path.abspath(os.path.join(os.path.dirname(__file__), folder))
105
  if not os.path.exists(full_path):
106
  os.makedirs(full_path)
107
  print(f"[+] Создан каталог: {full_path}")
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -10,6 +10,12 @@
10
  .source-system { background-color: #fff3e0; }
11
  .private::after { content: " 🔒"; }
12
  .from-self::before { content: "🧍 "; }
 
 
 
 
 
 
13
  </style>
14
  </head>
15
  <body>
@@ -23,8 +29,10 @@
23
 
24
  <h1>Сообщения</h1>
25
 
26
- <form method="post">
27
- <textarea name="text" rows="3" cols="40" placeholder="Введите сообщение..."></textarea><br>
 
 
28
  <button name="hidden" value="false" type="submit">📢 Отправить</button>
29
  <button name="hidden" value="true" type="submit">🙋 Отправить приватно</button>
30
  </form>
@@ -50,6 +58,22 @@
50
  </div>
51
  <hr>
52
  <div>{{ msg.text|safe }}</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  </div>
54
  {% endfor %}
55
  </body>
 
10
  .source-system { background-color: #fff3e0; }
11
  .private::after { content: " 🔒"; }
12
  .from-self::before { content: "🧍 "; }
13
+ pre.code-block {
14
+ background-color: #f0f0f0;
15
+ padding: 10px;
16
+ border-radius: 6px;
17
+ overflow-x: auto;
18
+ }
19
  </style>
20
  </head>
21
  <body>
 
29
 
30
  <h1>Сообщения</h1>
31
 
32
+ <form method="post" enctype="multipart/form-data">
33
+ <textarea name="text" rows="3" cols="60" placeholder="Введите сообщение..."></textarea><br>
34
+ <textarea name="code" rows="6" cols="60" placeholder="Прикрепите код (опционально)..."></textarea><br>
35
+ <label>Файлы: <input type="file" name="binary_files" multiple></label><br>
36
  <button name="hidden" value="false" type="submit">📢 Отправить</button>
37
  <button name="hidden" value="true" type="submit">🙋 Отправить приватно</button>
38
  </form>
 
58
  </div>
59
  <hr>
60
  <div>{{ msg.text|safe }}</div>
61
+
62
+ {% if msg.code %}
63
+ <hr>
64
+ <div><b>Код:</b></div>
65
+ <pre class="code-block">{{ msg.code }}</pre>
66
+ {% endif %}
67
+
68
+ {% if msg.attachments %}
69
+ <hr>
70
+ <div><b>Файлы:</b></div>
71
+ <ul>
72
+ {% for file in msg.attachments %}
73
+ <li><a href="/download/{{ file.id }}">{{ file.filename }}</a> ({{ file.size }} байт)</li>
74
+ {% endfor %}
75
+ </ul>
76
+ {% endif %}
77
  </div>
78
  {% endfor %}
79
  </body>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py CHANGED
@@ -2,11 +2,13 @@
2
 
3
  import re
4
  import bleach
 
5
 
6
- from fastapi import APIRouter, Request, Form
7
- from fastapi.responses import RedirectResponse, HTMLResponse
8
  from fastapi.templating import Jinja2Templates
9
  from starlette.status import HTTP_303_SEE_OTHER
 
10
  from tools.storage import Storage
11
 
12
  router = APIRouter()
@@ -76,27 +78,59 @@ def show_messages(request: Request, only_personal: bool = False):
76
  })
77
 
78
  @router.post("/messages")
79
- def post_message(
80
  request: Request,
81
  text: str = Form(...),
82
- hidden: str = Form(default="false")
 
 
83
  ):
84
  did = request.session.get("did", "anon")
85
  is_hidden = 1 if hidden.lower() == "true" else 0
86
 
87
- # Проверка на бан
88
  if storage.is_banned(did):
89
  return HTMLResponse(content="Вы забанены и не можете отправлять сообщения.", status_code=403)
90
 
91
- if text.strip():
92
- storage.write_note(
93
- content=sanitize_html(text.strip()),
 
 
 
 
94
  user_did=did,
95
  source="user",
96
- hidden=is_hidden
 
97
  )
 
 
 
 
 
 
 
 
 
 
 
 
98
  return RedirectResponse(url="/messages", status_code=303)
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  @router.get("/login")
101
  def login_page(request: Request):
102
  return templates.TemplateResponse("login.html", {"request": request})
 
2
 
3
  import re
4
  import bleach
5
+ import uuid
6
 
7
+ from fastapi import APIRouter, Request, Form, UploadFile, File
8
+ from fastapi.responses import RedirectResponse, HTMLResponse, StreamingResponse
9
  from fastapi.templating import Jinja2Templates
10
  from starlette.status import HTTP_303_SEE_OTHER
11
+ from typing import List
12
  from tools.storage import Storage
13
 
14
  router = APIRouter()
 
78
  })
79
 
80
  @router.post("/messages")
81
+ async def post_message(
82
  request: Request,
83
  text: str = Form(...),
84
+ code: str = Form(None),
85
+ hidden: str = Form(default="false"),
86
+ binary_files: List[UploadFile] = File(default=[])
87
  ):
88
  did = request.session.get("did", "anon")
89
  is_hidden = 1 if hidden.lower() == "true" else 0
90
 
 
91
  if storage.is_banned(did):
92
  return HTMLResponse(content="Вы забанены и не можете отправлять сообщения.", status_code=403)
93
 
94
+ if text.strip() or code or binary_files:
95
+ # Очистка текста
96
+ safe_text = sanitize_html(text.strip()) if text else ""
97
+
98
+ # Сохраняем сообщение и получаем message_id
99
+ message_id = storage.write_note_returning_id(
100
+ content=safe_text,
101
  user_did=did,
102
  source="user",
103
+ hidden=is_hidden,
104
+ code=code.strip() if code else None
105
  )
106
+
107
+ # Сохраняем файлы
108
+ for upload in binary_files:
109
+ data = await upload.read()
110
+ if data:
111
+ storage.save_attachment(
112
+ message_id=message_id,
113
+ filename=upload.filename,
114
+ mime_type=upload.content_type,
115
+ content=data
116
+ )
117
+
118
  return RedirectResponse(url="/messages", status_code=303)
119
 
120
+ @router.get("/download/{file_id}")
121
+ def download_file(file_id: int):
122
+ file = storage.get_attachment_by_id(file_id)
123
+ if not file:
124
+ raise HTTPException(status_code=404, detail="Файл не найден")
125
+
126
+ return StreamingResponse(
127
+ iter([file["binary"]]),
128
+ media_type=file["mime_type"],
129
+ headers={
130
+ "Content-Disposition": f'attachment; filename="{file["filename"]}"'
131
+ }
132
+ )
133
+
134
  @router.get("/login")
135
  def login_page(request: Request):
136
  return templates.TemplateResponse("login.html", {"request": request})
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py CHANGED
@@ -5,6 +5,7 @@ import sqlite3
5
  import os
6
  import json
7
  import uuid
 
8
 
9
  from datetime import datetime, timedelta, UTC
10
  from werkzeug.security import generate_password_hash, check_password_hash
@@ -714,13 +715,40 @@ class Storage:
714
  """, (content, user_did, source, timestamp, hidden))
715
  self.conn.commit()
716
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
717
  def get_notes(self, limit=50, user_did="anon", only_personal=False):
718
  cursor = self.conn.cursor()
719
 
720
  if only_personal:
721
  # Только личные (скрытые) сообщения пользователя
722
  query = """
723
- SELECT n.id, n.text, n.source, n.user_did, u.username, n.timestamp, n.hidden
724
  FROM notes n
725
  LEFT JOIN users u ON n.user_did = u.did
726
  WHERE n.user_did = ? AND n.hidden = 1
@@ -731,7 +759,7 @@ class Storage:
731
  else:
732
  # Личные сообщения + публичные от user/llm, которые не скрыты
733
  query = """
734
- SELECT n.id, n.text, n.source, n.user_did, u.username, u.badges, n.timestamp, n.hidden
735
  FROM notes n
736
  LEFT JOIN users u ON n.user_did = u.did
737
  WHERE n.user_did = ?
@@ -741,6 +769,19 @@ class Storage:
741
  """
742
  cursor.execute(query, (user_did, limit))
743
 
 
 
 
 
 
 
 
 
 
 
 
 
 
744
  return [dict(row) for row in cursor.fetchall()]
745
 
746
  # Пользователи
 
5
  import os
6
  import json
7
  import uuid
8
+ import time
9
 
10
  from datetime import datetime, timedelta, UTC
11
  from werkzeug.security import generate_password_hash, check_password_hash
 
715
  """, (content, user_did, source, timestamp, hidden))
716
  self.conn.commit()
717
 
718
+ def write_note_returning_id(self, content, user_did, source="user", hidden=False, code=None):
719
+ cursor = self.conn.cursor()
720
+ cursor.execute("""
721
+ INSERT INTO notes (timestamp, text, user_did, source, hidden, code)
722
+ VALUES (?, ?, ?, ?, ?, ?)
723
+ """, (time.time(), content, user_did, source, int(hidden), code))
724
+ self.conn.commit()
725
+ return cursor.lastrowid
726
+
727
+ def save_attachment(self, message_id, filename, mime_type, content):
728
+ cursor = self.conn.cursor()
729
+ cursor.execute("""
730
+ INSERT INTO attachments (message_id, filename, mime_type, size, binary)
731
+ VALUES (?, ?, ?, ?, ?)
732
+ """, (message_id, filename, mime_type, len(content), content))
733
+ self.conn.commit()
734
+
735
+ def get_attachment_by_id(self, file_id):
736
+ cursor = self.conn.cursor()
737
+ cursor.execute("""
738
+ SELECT id, filename, mime_type, size, binary
739
+ FROM attachments
740
+ WHERE id = ?
741
+ """, (file_id,))
742
+ row = cursor.fetchone()
743
+ return dict(row) if row else None
744
+
745
  def get_notes(self, limit=50, user_did="anon", only_personal=False):
746
  cursor = self.conn.cursor()
747
 
748
  if only_personal:
749
  # Только личные (скрытые) сообщения пользователя
750
  query = """
751
+ SELECT n.id, n.text, n.code, n.source, n.user_did, u.username, n.timestamp, n.hidden
752
  FROM notes n
753
  LEFT JOIN users u ON n.user_did = u.did
754
  WHERE n.user_did = ? AND n.hidden = 1
 
759
  else:
760
  # Личные сообщения + публичные от user/llm, которые не скрыты
761
  query = """
762
+ SELECT n.id, n.text, n.code, n.source, n.user_did, u.username, u.badges, n.timestamp, n.hidden
763
  FROM notes n
764
  LEFT JOIN users u ON n.user_did = u.did
765
  WHERE n.user_did = ?
 
769
  """
770
  cursor.execute(query, (user_did, limit))
771
 
772
+ result = [dict(row) for row in cursor.fetchall()]
773
+
774
+ for note in result:
775
+ note["attachments"] = self.get_attachments_for_note(note["id"])
776
+
777
+ return result
778
+
779
+ def get_attachments_for_note(self, message_id):
780
+ cursor = self.conn.cursor()
781
+ cursor.execute("""
782
+ SELECT id, filename, mime_type, size FROM attachments
783
+ WHERE message_id = ?
784
+ """, (message_id,))
785
  return [dict(row) for row in cursor.fetchall()]
786
 
787
  # Пользователи
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/db_structure.sql CHANGED
@@ -42,17 +42,29 @@ CREATE TABLE IF NOT EXISTS diary_graph_index (
42
 
43
  -- Заметки, подсказки, сообщения пользователя и LLM
44
  CREATE TABLE IF NOT EXISTS notes (
45
- id INTEGER PRIMARY KEY AUTOINCREMENT, -- Уникальный идентификатор заметки
46
- text TEXT NOT NULL, -- Текст заметки
47
- tags TEXT, -- Теги (например: "idea", "instruction")
48
- user_did TEXT DEFAULT 'ALL', -- DID пользователя (или 'ALL' для всех)
49
- source TEXT DEFAULT 'user', -- Источник заметки: user | cli | llm | system
50
- links TEXT DEFAULT '', -- Ссылки или связи с другими объектами
51
- read INTEGER DEFAULT 0, -- Статус прочтения LLM: 0 = нет, 1 = да
52
- hidden INTEGER DEFAULT 0, -- Скрыта ли от пользователя: 0 = нет, 1 = да
53
- priority INTEGER DEFAULT 0, -- Приоритет заметки
 
54
  timestamp TEXT DEFAULT CURRENT_TIMESTAMP, -- Время создания
55
- llm_id TEXT -- Идентификатор LLM
 
 
 
 
 
 
 
 
 
 
 
56
  );
57
 
58
  -- Лог процессов: задачи, ошибки, события
 
42
 
43
  -- Заметки, подсказки, сообщения пользователя и LLM
44
  CREATE TABLE IF NOT EXISTS notes (
45
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
46
+ text TEXT NOT NULL, -- Основной текст заметки/сообщения
47
+ code TEXT, -- Прикреплённый код (Python, JS и т.п.)
48
+ tags TEXT, -- Теги (устанавливаются агентом, например: "idea", "instruction")
49
+ user_did TEXT DEFAULT 'ALL', -- Идентификатор пользователя (или 'ALL')
50
+ source TEXT DEFAULT 'user', -- Источник: user | cli | llm | system
51
+ links TEXT DEFAULT '', -- Ссылки на другие объекты (например, JSON со связями)
52
+ read INTEGER DEFAULT 0, -- Агент прочитал: 0 = нет, 1 = да
53
+ hidden INTEGER DEFAULT 0, -- Скрыто от UI (например, технические записи)
54
+ priority INTEGER DEFAULT 0, -- Приоритет обработки (>0: срочность/важность, задается вручную или агентом)
55
  timestamp TEXT DEFAULT CURRENT_TIMESTAMP, -- Время создания
56
+ llm_id TEXT -- Идентификатор агента, добавившего сообщение
57
+ );
58
+
59
+ -- Вложения (может быть несколько к одной заметке)
60
+ CREATE TABLE IF NOT EXISTS attachments (
61
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
62
+ message_id INTEGER NOT NULL, -- Связь с notes.id
63
+ filename TEXT, -- Имя файла
64
+ mime_type TEXT, -- Тип (например, image/png, application/zip)
65
+ size INTEGER, -- Размер файла
66
+ binary BLOB NOT NULL, -- Сами данные
67
+ FOREIGN KEY (message_id) REFERENCES notes(id) ON DELETE CASCADE
68
  );
69
 
70
  -- Лог процессов: задачи, ошибки, события
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/add_message.py CHANGED
@@ -5,11 +5,12 @@ from tools.storage import Storage
5
 
6
  storage = Storage()
7
 
8
- def add_message(content, source="cli", user_did="anon"):
9
  storage.write_note(
10
  content,
11
  source=source,
12
- user_did=user_did
 
13
  )
14
  print(f"[+] Сообщение от {source} ({user_did}) добавлено: {content}")
15
 
@@ -19,6 +20,7 @@ if __name__ == "__main__":
19
  parser.add_argument("--content", required=True)
20
  parser.add_argument("--source", default="cli")
21
  parser.add_argument("--user_did", default="anon")
 
22
  args = parser.parse_args()
23
 
24
- add_message(args.content, args.source, args.user_did)
 
5
 
6
  storage = Storage()
7
 
8
+ def add_message(content, source="cli", user_did="anon", hidden=1):
9
  storage.write_note(
10
  content,
11
  source=source,
12
+ user_did=user_did,
13
+ hidden=hidden
14
  )
15
  print(f"[+] Сообщение от {source} ({user_did}) добавлено: {content}")
16
 
 
20
  parser.add_argument("--content", required=True)
21
  parser.add_argument("--source", default="cli")
22
  parser.add_argument("--user_did", default="anon")
23
+ parser.add_argument("--hidden", default=1)
24
  args = parser.parse_args()
25
 
26
+ add_message(args.content, args.source, args.user_did, args.hidden)
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py CHANGED
@@ -735,7 +735,7 @@ class Storage:
735
  FROM notes n
736
  LEFT JOIN users u ON n.user_did = u.did
737
  WHERE n.user_did = ?
738
- OR ((n.source = 'user' OR n.source = 'llm') AND n.hidden = 0)
739
  ORDER BY n.timestamp DESC
740
  LIMIT ?
741
  """
 
735
  FROM notes n
736
  LEFT JOIN users u ON n.user_did = u.did
737
  WHERE n.user_did = ?
738
+ OR ((n.source = 'user' OR n.source = 'llm' OR n.source = 'cli') AND n.hidden = 0)
739
  ORDER BY n.timestamp DESC
740
  LIMIT ?
741
  """
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py CHANGED
@@ -1,5 +1,6 @@
1
  # agents/notebook/views.py
2
 
 
3
  import bleach
4
 
5
  from fastapi import APIRouter, Request, Form
@@ -12,13 +13,20 @@ router = APIRouter()
12
  templates = Jinja2Templates(directory="notebook/templates")
13
  storage = Storage()
14
 
15
- allowed_tags = ['b', 'i', 's', 'u', 'a', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'table', 'caption', 'tr', 'th', 'td']
16
  allowed_attributes = {
17
  'a': ['href', 'title']
18
  }
19
 
20
- def sanitize_html(text):
21
- return bleach.clean(text, tags=allowed_tags, attributes=allowed_attributes, strip=True)
 
 
 
 
 
 
 
22
 
23
  @router.get("/chat")
24
  def chat_page(request: Request):
 
1
  # agents/notebook/views.py
2
 
3
+ import re
4
  import bleach
5
 
6
  from fastapi import APIRouter, Request, Form
 
13
  templates = Jinja2Templates(directory="notebook/templates")
14
  storage = Storage()
15
 
16
+ allowed_tags = ['b', 'i', 's', 'u', 'a', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'table', 'caption', 'tr', 'th', 'td', 'code', 'pre', 'blockquote', 'br', 'hr']
17
  allowed_attributes = {
18
  'a': ['href', 'title']
19
  }
20
 
21
+ # Очистка сообщений
22
+ def sanitize_html(text: str) -> str:
23
+ # 1. Сначала очищаем HTML
24
+ cleaned = bleach.clean(text, tags=allowed_tags, attributes=allowed_attributes, strip=True)
25
+
26
+ # 2. Заменяем 3 и более <br> подряд на ровно два
27
+ cleaned = re.sub(r'(<br\s*/?>\s*){3,}', '<br><br>', cleaned, flags=re.IGNORECASE)
28
+
29
+ return cleaned
30
 
31
  @router.get("/chat")
32
  def chat_page(request: Request):
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/__init__.py CHANGED
@@ -1 +1 @@
1
- from agents.tools.storage import Storage
 
1
+ from tools.storage import Storage
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -25,8 +25,8 @@
25
 
26
  <form method="post">
27
  <textarea name="text" rows="3" cols="40" placeholder="Введите сообщение..."></textarea><br>
28
- <button name="hidden" value="false" type="submit">Отправить</button>
29
- <button name="hidden" value="true" type="submit">Отправить приватно</button>
30
  </form>
31
 
32
  <hr>
 
25
 
26
  <form method="post">
27
  <textarea name="text" rows="3" cols="40" placeholder="Введите сообщение..."></textarea><br>
28
+ <button name="hidden" value="false" type="submit">📢 Отправить</button>
29
+ <button name="hidden" value="true" type="submit">🙋 Отправить приватно</button>
30
  </form>
31
 
32
  <hr>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py CHANGED
@@ -12,7 +12,7 @@ router = APIRouter()
12
  templates = Jinja2Templates(directory="notebook/templates")
13
  storage = Storage()
14
 
15
- allowed_tags = ['b', 'i', 'a', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'table', 'caption', 'tr', 'th', 'td']
16
  allowed_attributes = {
17
  'a': ['href', 'title']
18
  }
 
12
  templates = Jinja2Templates(directory="notebook/templates")
13
  storage = Storage()
14
 
15
+ allowed_tags = ['b', 'i', 's', 'u', 'a', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'table', 'caption', 'tr', 'th', 'td']
16
  allowed_attributes = {
17
  'a': ['href', 'title']
18
  }
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py CHANGED
@@ -1,5 +1,7 @@
1
  # agents/notebook/views.py
2
 
 
 
3
  from fastapi import APIRouter, Request, Form
4
  from fastapi.responses import RedirectResponse, HTMLResponse
5
  from fastapi.templating import Jinja2Templates
@@ -10,6 +12,14 @@ router = APIRouter()
10
  templates = Jinja2Templates(directory="notebook/templates")
11
  storage = Storage()
12
 
 
 
 
 
 
 
 
 
13
  @router.get("/chat")
14
  def chat_page(request: Request):
15
  did = request.session.get("did")
@@ -72,7 +82,7 @@ def post_message(
72
 
73
  if text.strip():
74
  storage.write_note(
75
- content=text.strip(),
76
  user_did=did,
77
  source="user",
78
  hidden=is_hidden
 
1
  # agents/notebook/views.py
2
 
3
+ import bleach
4
+
5
  from fastapi import APIRouter, Request, Form
6
  from fastapi.responses import RedirectResponse, HTMLResponse
7
  from fastapi.templating import Jinja2Templates
 
12
  templates = Jinja2Templates(directory="notebook/templates")
13
  storage = Storage()
14
 
15
+ allowed_tags = ['b', 'i', 'a', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'table', 'caption', 'tr', 'th', 'td']
16
+ allowed_attributes = {
17
+ 'a': ['href', 'title']
18
+ }
19
+
20
+ def sanitize_html(text):
21
+ return bleach.clean(text, tags=allowed_tags, attributes=allowed_attributes, strip=True)
22
+
23
  @router.get("/chat")
24
  def chat_page(request: Request):
25
  did = request.session.get("did")
 
82
 
83
  if text.strip():
84
  storage.write_note(
85
+ content=sanitize_html(text.strip()),
86
  user_did=did,
87
  source="user",
88
  hidden=is_hidden
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/requirements.txt CHANGED
@@ -12,4 +12,5 @@ jinja2
12
  python-multipart
13
  passlib[bcrypt]
14
  werkzeug
15
- itsdangerous
 
 
12
  python-multipart
13
  passlib[bcrypt]
14
  werkzeug
15
+ itsdangerous
16
+ bleach
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -46,10 +46,10 @@
46
  Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
47
  </div>
48
  <div>
49
- {{ msg.badges }}Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did !="" %}({{ msg.user_did }}){% endif %}
50
  </div>
51
  <hr>
52
- <div>{{ msg.text }}</div>
53
  </div>
54
  {% endfor %}
55
  </body>
 
46
  Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
47
  </div>
48
  <div>
49
+ {% if msg.badges %}{{ msg.badges }}{% endif %}Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did %}({{ msg.user_did }}){% endif %}
50
  </div>
51
  <hr>
52
+ <div>{{ msg.text|safe }}</div>
53
  </div>
54
  {% endfor %}
55
  </body>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py CHANGED
@@ -731,7 +731,7 @@ class Storage:
731
  else:
732
  # Личные сообщения + публичные от user/llm, которые не скрыты
733
  query = """
734
- SELECT n.id, n.text, n.source, n.user_did, u.username, n.timestamp, n.hidden
735
  FROM notes n
736
  LEFT JOIN users u ON n.user_did = u.did
737
  WHERE n.user_did = ?
 
731
  else:
732
  # Личные сообщения + публичные от user/llm, которые не скрыты
733
  query = """
734
+ SELECT n.id, n.text, n.source, n.user_did, u.username, u.badges, n.timestamp, n.hidden
735
  FROM notes n
736
  LEFT JOIN users u ON n.user_did = u.did
737
  WHERE n.user_did = ?
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -46,7 +46,7 @@
46
  Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
47
  </div>
48
  <div>
49
- Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did !="" %}({{ msg.user_did }}){% endif %}
50
  </div>
51
  <hr>
52
  <div>{{ msg.text }}</div>
 
46
  Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
47
  </div>
48
  <div>
49
+ {{ msg.badges }}Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did !="" %}({{ msg.user_did }}){% endif %}
50
  </div>
51
  <hr>
52
  <div>{{ msg.text }}</div>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/db_structure.sql CHANGED
@@ -199,9 +199,10 @@ CREATE TABLE IF NOT EXISTS users (
199
  user_id INTEGER PRIMARY KEY AUTOINCREMENT,
200
  ban DATETIME DEFAULT NULL, -- если стоит дата/время, то пользователь забанен до этого момента
201
  username TEXT, -- имя пользователя (необязательно уникальное)
202
- did TEXT UNIQUE, -- децентрализованный идентификатор
203
- mail TEXT UNIQUE, -- электронная почта
204
- password_hash TEXT, -- хэш пароля
 
205
  info TEXT, -- произвольная информация, JSON
206
  profile TEXT, -- структурированая информация, JSON
207
  contacts TEXT, -- JSON-массив альтернативных контактов (matrix, telegram и т.д.)
 
199
  user_id INTEGER PRIMARY KEY AUTOINCREMENT,
200
  ban DATETIME DEFAULT NULL, -- если стоит дата/время, то пользователь забанен до этого момента
201
  username TEXT, -- имя пользователя (необязательно уникальное)
202
+ badges TEXT, -- значки, присвоенные агентом (например, "🎓💬")
203
+ did TEXT UNIQUE NOT NULL, -- децентрализованный идентификатор
204
+ mail TEXT UNIQUE NOT NULL, -- электронная почта
205
+ password_hash TEXT NOT NULL, -- хэш пароля
206
  info TEXT, -- произвольная информация, JSON
207
  profile TEXT, -- структурированая информация, JSON
208
  contacts TEXT, -- JSON-массив альтернативных контактов (matrix, telegram и т.д.)
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py CHANGED
@@ -1,7 +1,7 @@
1
  # agents/notebook/views.py
2
 
3
  from fastapi import APIRouter, Request, Form
4
- from fastapi.responses import RedirectResponse
5
  from fastapi.templating import Jinja2Templates
6
  from starlette.status import HTTP_303_SEE_OTHER
7
  from tools.storage import Storage
@@ -66,6 +66,10 @@ def post_message(
66
  did = request.session.get("did", "anon")
67
  is_hidden = 1 if hidden.lower() == "true" else 0
68
 
 
 
 
 
69
  if text.strip():
70
  storage.write_note(
71
  content=text.strip(),
 
1
  # agents/notebook/views.py
2
 
3
  from fastapi import APIRouter, Request, Form
4
+ from fastapi.responses import RedirectResponse, HTMLResponse
5
  from fastapi.templating import Jinja2Templates
6
  from starlette.status import HTTP_303_SEE_OTHER
7
  from tools.storage import Storage
 
66
  did = request.session.get("did", "anon")
67
  is_hidden = 1 if hidden.lower() == "true" else 0
68
 
69
+ # Проверка на бан
70
+ if storage.is_banned(did):
71
+ return HTMLResponse(content="Вы забанены и не можете отправлять сообщения.", status_code=403)
72
+
73
  if text.strip():
74
  storage.write_note(
75
  content=text.strip(),
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py CHANGED
@@ -769,6 +769,18 @@ class Storage:
769
  return check_password_hash(result["password_hash"], password)
770
  return False
771
 
 
 
 
 
 
 
 
 
 
 
 
 
772
  def get_user_info(self, mail: str) -> dict | None:
773
  mail = mail.lower()
774
  cursor = self.conn.cursor()
 
769
  return check_password_hash(result["password_hash"], password)
770
  return False
771
 
772
+ def is_banned(self, user_did):
773
+ result = self.conn.execute("""
774
+ SELECT ban
775
+ FROM users
776
+ WHERE did = ?
777
+ """, (user_did,)).fetchone()
778
+
779
+ if result and result["ban"]:
780
+ return datetime.fromisoformat(result["ban"]) > datetime.now(UTC)
781
+
782
+ return False
783
+
784
  def get_user_info(self, mail: str) -> dict | None:
785
  mail = mail.lower()
786
  cursor = self.conn.cursor()
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -33,7 +33,7 @@
33
 
34
  <div>
35
  <a href="/messages">📢 Все сообщения</a> |
36
- <a href="/messages?only_personal=true">🙋 Только мои</a>
37
  </div>
38
 
39
  <hr>
@@ -41,8 +41,8 @@
41
  {% for msg in messages %}
42
  <div class="message source-{{ msg.source }}">
43
  <div>
44
- {% if msg.user_did == request.session['did'] %}<span class="from-self"></span>{% endif %}
45
- {% if msg.hidden %}<span class="private"></span>{% endif %}
46
  Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
47
  </div>
48
  <div>
 
33
 
34
  <div>
35
  <a href="/messages">📢 Все сообщения</a> |
36
+ <a href="/messages?only_personal=true">🙋 Личные</a>
37
  </div>
38
 
39
  <hr>
 
41
  {% for msg in messages %}
42
  <div class="message source-{{ msg.source }}">
43
  <div>
44
+ {% if msg.user_did == request.session['did'] %}<span class="from-self" title="это ваше сообщение"></span>{% endif %}
45
+ {% if msg.hidden %}<span class="private" title="личное сообщение"></span>{% endif %}
46
  Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
47
  </div>
48
  <div>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -39,13 +39,14 @@
39
  <hr>
40
 
41
  {% for msg in messages %}
42
- <div class="message source-{{ msg.source }} {% if msg.user_did == request.session['did'] %}from-self{% endif %}">
43
  <div>
44
- Источник: <i>{{ msg.source }}</i>{{ msg.timestamp }}
45
  {% if msg.hidden %}<span class="private"></span>{% endif %}
 
46
  </div>
47
  <div>
48
- Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} ({{ msg.user_did }})
49
  </div>
50
  <hr>
51
  <div>{{ msg.text }}</div>
 
39
  <hr>
40
 
41
  {% for msg in messages %}
42
+ <div class="message source-{{ msg.source }}">
43
  <div>
44
+ {% if msg.user_did == request.session['did'] %}<span class="from-self"></span>{% endif %}
45
  {% if msg.hidden %}<span class="private"></span>{% endif %}
46
+ Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp[:19].replace('T', ' ') }}
47
  </div>
48
  <div>
49
+ Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} {% if msg.user_did !="" %}({{ msg.user_did }}){% endif %}
50
  </div>
51
  <hr>
52
  <div>{{ msg.text }}</div>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -41,11 +41,11 @@
41
  {% for msg in messages %}
42
  <div class="message source-{{ msg.source }} {% if msg.user_did == request.session['did'] %}from-self{% endif %}">
43
  <div>
44
- <strong>{{ msg.source }}</strong> — {{ msg.timestamp }}
45
  {% if msg.hidden %}<span class="private"></span>{% endif %}
46
  </div>
47
  <div>
48
- участник: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} ({{ msg.user_did[:10] }})...
49
  </div>
50
  <hr>
51
  <div>{{ msg.text }}</div>
 
41
  {% for msg in messages %}
42
  <div class="message source-{{ msg.source }} {% if msg.user_did == request.session['did'] %}from-self{% endif %}">
43
  <div>
44
+ Источник: <i>{{ msg.source }}</i> — {{ msg.timestamp }}
45
  {% if msg.hidden %}<span class="private"></span>{% endif %}
46
  </div>
47
  <div>
48
+ Пользователь: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} ({{ msg.user_did }})
49
  </div>
50
  <hr>
51
  <div>{{ msg.text }}</div>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -45,9 +45,9 @@
45
  {% if msg.hidden %}<span class="private"></span>{% endif %}
46
  </div>
47
  <div>
48
- участник: {{ msg.user_did[:10] }}...
49
- {% if msg.username %}({{ msg.username }}){% endif %}
50
  </div>
 
51
  <div>{{ msg.text }}</div>
52
  </div>
53
  {% endfor %}
 
45
  {% if msg.hidden %}<span class="private"></span>{% endif %}
46
  </div>
47
  <div>
48
+ участник: {% if msg.username %}<b>{{ msg.username }}</b>{% endif %} ({{ msg.user_did[:10] }})...
 
49
  </div>
50
+ <hr>
51
  <div>{{ msg.text }}</div>
52
  </div>
53
  {% endfor %}
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -45,7 +45,7 @@
45
  {% if msg.hidden %}<span class="private"></span>{% endif %}
46
  </div>
47
  <div>
48
- от {{ msg.user_did[:10] }}...
49
  {% if msg.username %}({{ msg.username }}){% endif %}
50
  </div>
51
  <div>{{ msg.text }}</div>
 
45
  {% if msg.hidden %}<span class="private"></span>{% endif %}
46
  </div>
47
  <div>
48
+ участник: {{ msg.user_did[:10] }}...
49
  {% if msg.username %}({{ msg.username }}){% endif %}
50
  </div>
51
  <div>{{ msg.text }}</div>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py CHANGED
@@ -45,14 +45,9 @@ def show_messages(request: Request, only_personal: bool = False):
45
  if not did:
46
  return RedirectResponse("/login", status_code=303)
47
 
48
- # Получаем инфу о пользователе, чтобы понять, оператор ли он
49
- user_info = storage.get_user_info_by_did(did)
50
- is_operator = bool(user_info and user_info.get("operator"))
51
-
52
  messages = storage.get_notes(
53
  limit=50,
54
  user_did=did,
55
- is_operator=is_operator,
56
  only_personal=only_personal
57
  )
58
  return templates.TemplateResponse("messages.html", {
 
45
  if not did:
46
  return RedirectResponse("/login", status_code=303)
47
 
 
 
 
 
48
  messages = storage.get_notes(
49
  limit=50,
50
  user_did=did,
 
51
  only_personal=only_personal
52
  )
53
  return templates.TemplateResponse("messages.html", {
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py CHANGED
@@ -714,38 +714,32 @@ class Storage:
714
  """, (content, user_did, source, timestamp, hidden))
715
  self.conn.commit()
716
 
717
- def get_notes(self, limit=50, user_did="anon", is_operator=False, only_personal=False):
718
  cursor = self.conn.cursor()
719
 
720
- if is_operator:
 
721
  query = """
722
- SELECT id, text, source, user_did, timestamp, hidden
723
- FROM notes
724
- ORDER BY timestamp DESC
 
 
725
  LIMIT ?
726
  """
727
- cursor.execute(query, (limit,))
728
  else:
729
- if only_personal:
730
- # Только личные сообщения
731
- query = """
732
- SELECT id, text, source, user_did, timestamp, hidden
733
- FROM notes
734
- WHERE user_did = ? AND hidden = 0
735
- ORDER BY timestamp DESC
736
- LIMIT ?
737
- """
738
- cursor.execute(query, (user_did, limit))
739
- else:
740
- # Публичные и личные
741
- query = """
742
- SELECT id, text, source, user_did, timestamp, hidden
743
- FROM notes
744
- WHERE (user_did = ? OR user_did = 'ALL') AND hidden = 0
745
- ORDER BY timestamp DESC
746
- LIMIT ?
747
- """
748
- cursor.execute(query, (user_did, limit))
749
 
750
  return [dict(row) for row in cursor.fetchall()]
751
 
@@ -790,6 +784,21 @@ class Storage:
790
  }
791
  return None
792
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
793
  # Утилиты
794
 
795
  def close(self):
 
714
  """, (content, user_did, source, timestamp, hidden))
715
  self.conn.commit()
716
 
717
+ def get_notes(self, limit=50, user_did="anon", only_personal=False):
718
  cursor = self.conn.cursor()
719
 
720
+ if only_personal:
721
+ # Только личные (скрытые) сообщения пользователя
722
  query = """
723
+ SELECT n.id, n.text, n.source, n.user_did, u.username, n.timestamp, n.hidden
724
+ FROM notes n
725
+ LEFT JOIN users u ON n.user_did = u.did
726
+ WHERE n.user_did = ? AND n.hidden = 1
727
+ ORDER BY n.timestamp DESC
728
  LIMIT ?
729
  """
730
+ cursor.execute(query, (user_did, limit))
731
  else:
732
+ # Личные сообщения + публичные от user/llm, которые не скрыты
733
+ query = """
734
+ SELECT n.id, n.text, n.source, n.user_did, u.username, n.timestamp, n.hidden
735
+ FROM notes n
736
+ LEFT JOIN users u ON n.user_did = u.did
737
+ WHERE n.user_did = ?
738
+ OR ((n.source = 'user' OR n.source = 'llm') AND n.hidden = 0)
739
+ ORDER BY n.timestamp DESC
740
+ LIMIT ?
741
+ """
742
+ cursor.execute(query, (user_did, limit))
 
 
 
 
 
 
 
 
 
743
 
744
  return [dict(row) for row in cursor.fetchall()]
745
 
 
784
  }
785
  return None
786
 
787
+ def get_user_info_by_did(self, did: str) -> dict | None:
788
+ cursor = self.conn.cursor()
789
+ cursor.execute(
790
+ "SELECT username, mail, operator FROM users WHERE did = ?",
791
+ (did,)
792
+ )
793
+ result = cursor.fetchone()
794
+ if result:
795
+ return {
796
+ "username": result["username"],
797
+ "mail": result["mail"],
798
+ "operator": result["operator"]
799
+ }
800
+ return None
801
+
802
  # Утилиты
803
 
804
  def close(self):
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/views.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  from fastapi import APIRouter, Request, Form
2
  from fastapi.responses import RedirectResponse
3
  from fastapi.templating import Jinja2Templates
@@ -43,7 +45,10 @@ def show_messages(request: Request, only_personal: bool = False):
43
  if not did:
44
  return RedirectResponse("/login", status_code=303)
45
 
46
- is_operator = False # Пока не реализовано
 
 
 
47
  messages = storage.get_notes(
48
  limit=50,
49
  user_did=did,
@@ -61,17 +66,18 @@ def show_messages(request: Request, only_personal: bool = False):
61
  def post_message(
62
  request: Request,
63
  text: str = Form(...),
64
- hidden: str = Form(default=None)
65
  ):
66
  did = request.session.get("did", "anon")
67
- is_hidden = 1 if hidden else 0
68
 
69
- storage.write_note(
70
- content=text,
71
- user_did=did,
72
- source="user",
73
- hidden=is_hidden
74
- )
 
75
  return RedirectResponse(url="/messages", status_code=303)
76
 
77
  @router.get("/login")
 
1
+ # agents/notebook/views.py
2
+
3
  from fastapi import APIRouter, Request, Form
4
  from fastapi.responses import RedirectResponse
5
  from fastapi.templating import Jinja2Templates
 
45
  if not did:
46
  return RedirectResponse("/login", status_code=303)
47
 
48
+ # Получаем инфу о пользователе, чтобы понять, оператор ли он
49
+ user_info = storage.get_user_info_by_did(did)
50
+ is_operator = bool(user_info and user_info.get("operator"))
51
+
52
  messages = storage.get_notes(
53
  limit=50,
54
  user_did=did,
 
66
  def post_message(
67
  request: Request,
68
  text: str = Form(...),
69
+ hidden: str = Form(default="false")
70
  ):
71
  did = request.session.get("did", "anon")
72
+ is_hidden = 1 if hidden.lower() == "true" else 0
73
 
74
+ if text.strip():
75
+ storage.write_note(
76
+ content=text.strip(),
77
+ user_did=did,
78
+ source="user",
79
+ hidden=is_hidden
80
+ )
81
  return RedirectResponse(url="/messages", status_code=303)
82
 
83
  @router.get("/login")
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/web_ui.py CHANGED
@@ -12,7 +12,6 @@ process_name = os.path.splitext(os.path.basename(__file__))[0]
12
  from fastapi import FastAPI
13
  from fastapi.staticfiles import StaticFiles
14
  from fastapi.templating import Jinja2Templates
15
- #from agents.notebook.auth import router as auth_router
16
  from starlette.middleware.sessions import SessionMiddleware
17
  from agents.notebook.views import router as notebook_router
18
  from tools.storage import Storage
@@ -25,7 +24,6 @@ app.add_middleware(SessionMiddleware, secret_key="очень_секретный_
25
  app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "notebook/static")), name="static")
26
  templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "notebook/templates"))
27
 
28
- #app.include_router(auth_router)
29
  app.include_router(notebook_router)
30
 
31
  @app.on_event("startup")
 
12
  from fastapi import FastAPI
13
  from fastapi.staticfiles import StaticFiles
14
  from fastapi.templating import Jinja2Templates
 
15
  from starlette.middleware.sessions import SessionMiddleware
16
  from agents.notebook.views import router as notebook_router
17
  from tools.storage import Storage
 
24
  app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "notebook/static")), name="static")
25
  templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "notebook/templates"))
26
 
 
27
  app.include_router(notebook_router)
28
 
29
  @app.on_event("startup")
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html CHANGED
@@ -1,6 +1,14 @@
1
- <form method="post">
2
- <label>Email: <input type="email" name="mail" required></label><br>
3
- <label>Пароль: <input type="password" name="password" required></label><br>
4
- <button type="submit">Войти</button>
5
- </form>
6
- Нет учетки: <a href="/register">зарегистрироваться</a>
 
 
 
 
 
 
 
 
 
1
+ {% if error %}
2
+ <p style="color:red">{{ error }}</p>
3
+ {% endif %}
4
+
5
+ <table>
6
+ <caption>Вход</caption>
7
+ <form method="post">
8
+ <tr><th><label>Email:</th><td><input type="email" name="mail" required></label></td></tr>
9
+ <tr><th><label>Пароль:</th><td><input type="password" name="password" required></label></td></tr>
10
+ <tr><th colspan="2"><button type="submit">Войти</button></th></tr>
11
+ </form>
12
+ </table>
13
+
14
+ <hr>Нет учетки: <a href="/register">Зарегистрироваться</a>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/messages.html CHANGED
@@ -25,10 +25,8 @@
25
 
26
  <form method="post">
27
  <textarea name="text" rows="3" cols="40" placeholder="Введите сообщение..."></textarea><br>
28
- <label>
29
- <input type="checkbox" name="hidden"> Скрыто
30
- </label><br>
31
- <button type="submit">Отправить</button>
32
  </form>
33
 
34
  <hr>
 
25
 
26
  <form method="post">
27
  <textarea name="text" rows="3" cols="40" placeholder="Введите сообщение..."></textarea><br>
28
+ <button name="hidden" value="false" type="submit">Отправить</button>
29
+ <button name="hidden" value="true" type="submit">Отправить приватно</button>
 
 
30
  </form>
31
 
32
  <hr>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html CHANGED
@@ -1,7 +1,15 @@
1
- <form method="post">
2
- <label>Имя пользователя: <input type="text" name="username" required></label><br>
3
- <label>Email: <input type="email" name="mail" required></label><br>
4
- <label>Пароль: <input type="password" name="password" required></label><br>
5
- <button type="submit">Зарегистрироваться</button>
6
- </form>
7
- Есть учетка: <a href="/login">войти</a>
 
 
 
 
 
 
 
 
 
1
+ {% if error %}
2
+ <p style="color:red">{{ error }}</p>
3
+ {% endif %}
4
+
5
+ <table>
6
+ <caption>Регистрация</caption>
7
+ <form method="post">
8
+ <tr><th><label>Имя:</th><td><input type="text" name="username" required></label></td></tr>
9
+ <tr><th><label>Email:</th><td><input type="email" name="mail" required></label></td></tr>
10
+ <tr><th><label>Пароль:</th><td><input type="password" name="password" required></label></td></tr>
11
+ <tr><th colspan="2"><button type="submit">Зарегистрироваться</button></th></tr>
12
+ </form>
13
+ </table>
14
+
15
+ <hr>Есть учетка: <a href="/login">Войти</a>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/tools/storage.py CHANGED
@@ -7,6 +7,9 @@ import json
7
  import uuid
8
 
9
  from datetime import datetime, timedelta, UTC
 
 
 
10
 
11
  SCRIPTS_BASE_PATH = "scripts"
12
 
@@ -747,21 +750,18 @@ class Storage:
747
  return [dict(row) for row in cursor.fetchall()]
748
 
749
  # Пользователи
750
- def _hash_password(self, password: str) -> str:
751
- return hashlib.sha256(password.encode()).hexdigest()
752
-
753
  def register_user(self, username: str, mail: str, password: str) -> bool:
754
  mail = mail.lower()
755
- did = f"did:example:{uuid.uuid4()}"
756
  try:
757
  self.conn.execute(
758
  "INSERT INTO users (username, mail, password_hash, did) VALUES (?, ?, ?, ?)",
759
- (username, mail, self._hash_password(password), did)
760
  )
761
  self.conn.commit()
762
  return True
763
  except sqlite3.IntegrityError:
764
- return False # уже существует (уникальность mail или did)
765
 
766
  def authenticate_user(self, mail: str, password: str) -> bool:
767
  mail = mail.lower()
@@ -772,7 +772,7 @@ class Storage:
772
  )
773
  result = cursor.fetchone()
774
  if result:
775
- return result["password_hash"] == self._hash_password(password)
776
  return False
777
 
778
  def get_user_info(self, mail: str) -> dict | None:
 
7
  import uuid
8
 
9
  from datetime import datetime, timedelta, UTC
10
+ from werkzeug.security import generate_password_hash, check_password_hash
11
+ from tools.identity import generate_did
12
+ from tools.crypto import generate_keypair
13
 
14
  SCRIPTS_BASE_PATH = "scripts"
15
 
 
750
  return [dict(row) for row in cursor.fetchall()]
751
 
752
  # Пользователи
 
 
 
753
  def register_user(self, username: str, mail: str, password: str) -> bool:
754
  mail = mail.lower()
755
+ did = generate_did()
756
  try:
757
  self.conn.execute(
758
  "INSERT INTO users (username, mail, password_hash, did) VALUES (?, ?, ?, ?)",
759
+ (username, mail, generate_password_hash(password), did)
760
  )
761
  self.conn.commit()
762
  return True
763
  except sqlite3.IntegrityError:
764
+ return False
765
 
766
  def authenticate_user(self, mail: str, password: str) -> bool:
767
  mail = mail.lower()
 
772
  )
773
  result = cursor.fetchone()
774
  if result:
775
+ return check_password_hash(result["password_hash"], password)
776
  return False
777
 
778
  def get_user_info(self, mail: str) -> dict | None:
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/config.yml CHANGED
@@ -1,44 +1,69 @@
1
- agent_id: did:hmp:dac57687-1839-423d-8624-c38324de2635
2
- agent_name: CognitiveCore
3
- agent_role: core
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  api_port: 8080
5
- bootstrap_responder: true
6
- debug: true
7
- default_llm: local-model
8
- default_user:
9
10
- password: password
11
- username: user
12
- dht_enabled: true
13
  dht_port: 20784
14
- dht_update: true
15
- enable_llm: true
16
- identity_agent: dac57687-1839-423d-8624-c38324de2635
17
  llm_backends:
18
- - format: gguf
19
- name: local-model
20
- path: /models/gguf/mistral.gguf
21
- prompt_template: mistral
22
- type: local
23
- - api_key: lm-studio-any-key
24
- base_url: http://127.0.0.1:1234/v1
25
- model: mistral
26
- name: lmstudio-local
27
- provider: openai-compatible
28
- type: api
29
- - api_key: sk-...
30
- model: gpt-4o
31
- name: openai-gpt4o
32
- provider: openai
33
- type: api
34
- log_level: INFO
35
- notebook_ui: true
36
- proxy_address: 127.0.0.1:9050
37
- proxy_mode: false
38
- proxy_type: socks5
39
- serve_api: true
40
- ui_hosts:
41
- - 127.0.0.1
42
- - ::1
 
 
 
 
 
 
43
  ui_port: 8765
44
- update_interval: 60
 
 
 
 
 
 
 
 
 
 
1
+ # HMP Agent Configuration
2
+
3
+ # === Общие параметры ===
4
+ agent_id: "" # Оставьте пустым для генерации DiD автоматически
5
+ agent_name: "CognitiveCore" # Имя агента
6
+ agent_role: "core" # 'core' или 'shell'
7
+
8
+ # === Прокси ===
9
+ proxy_mode: false # false — прокси не используется, иначе true
10
+ proxy_type: "socks5" # 'http', 'socks4', 'socks5' и т.д. (если proxy_mode: true)
11
+ proxy_address: "127.0.0.1:9050"
12
+
13
+ # === Функции ядра ===
14
+ enable_llm: true # доступ к LLM
15
+
16
+ serve_api: true # REST API
17
  api_port: 8080
18
+
19
+ # === DHT-сеть и обмен знаниями ===
20
+ dht_enabled: true # Включение участия в DHT-сети (включено принудительно!)
21
+ dht_update: true # Регулярные обновления и публикация данных в DHT (включено принудительно!)
22
+ bootstrap_responder: true # Агент отвечает на bootstrap-запросы (включено принудительно!)
 
 
 
23
  dht_port: 20784
24
+ update_interval: 60 # секунд (для DHT-обновлений)
25
+
26
+ # === LLM-бэкенды ===
27
  llm_backends:
28
+ - name: "local-model"
29
+ type: "local"
30
+ path: "/models/gguf/mistral.gguf"
31
+ format: "gguf"
32
+ prompt_template: "mistral"
33
+
34
+ - name: "lmstudio-local"
35
+ type: "api"
36
+ provider: "openai-compatible"
37
+ model: "mistral" # или то, что LM Studio показывает как модель
38
+ api_key: "lm-studio-any-key" # может быть заглушкой
39
+ base_url: "http://127.0.0.1:1234/v1"
40
+
41
+ - name: "openai-gpt4o"
42
+ type: "api"
43
+ provider: "openai"
44
+ model: "gpt-4o"
45
+ api_key: "sk-..."
46
+
47
+ # Пользователь может добавить сколько угодно дополнительных локальных или сетевых LLM
48
+
49
+ default_llm: "local-model" # если модели нет в списке `llm_backends` используется первая в списке
50
+
51
+ # === Веб-интерфейс ===
52
+ notebook_ui: true # UI в виде блокнота
53
+ # ui_hosts:
54
+ # - "0.0.0.0" # (небезопасно) доступ с любых IPv4-адресов
55
+ # - "::" # (небезопасно) доступ с любых IPv6-адресов
56
+ ui_hosts: # Какие IP прослушиваются, ["0.0.0.0"; "::"] - доступен везде
57
+ - "127.0.0.1"
58
+ - "::1"
59
  ui_port: 8765
60
+
61
+ # === Данные пользователя ===
62
+ default_user:
63
+ username: "user"
64
+ email: "[email protected]"
65
+ password: "password" # пусто при инициализации, будет установлен при регистрации
66
+
67
+ # === Отладка и логгирование ===
68
+ debug: true
69
+ log_level: "INFO" # DEBUG, INFO, WARNING, ERROR
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/login.html CHANGED
@@ -3,3 +3,4 @@
3
  <label>Пароль: <input type="password" name="password" required></label><br>
4
  <button type="submit">Войти</button>
5
  </form>
 
 
3
  <label>Пароль: <input type="password" name="password" required></label><br>
4
  <button type="submit">Войти</button>
5
  </form>
6
+ Нет учетки: <a href="/register">зарегистрироваться</a>
hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/hf_repo/agents/notebook/templates/register.html CHANGED
@@ -4,3 +4,4 @@
4
  <label>Пароль: <input type="password" name="password" required></label><br>
5
  <button type="submit">Зарегистрироваться</button>
6
  </form>
 
 
4
  <label>Пароль: <input type="password" name="password" required></label><br>
5
  <button type="submit">Зарегистрироваться</button>
6
  </form>
7
+ Есть учетка: <a href="/login">войти</a>