@innvisor/conny-ai 9.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/.env.example +68 -0
  2. package/CHANGELOG.md +54 -0
  3. package/LICENSE +21 -0
  4. package/README.md +369 -0
  5. package/brand-assets/A_dark_luxury_web_background_202605210700.jpeg +0 -0
  6. package/brand-assets/Conny.web.logo.png +0 -0
  7. package/brand-assets/Logo_Conny_Petalo_Claro.png +0 -0
  8. package/brand-assets/cl-nica-de-las-am-ricas/manifest.json +22 -0
  9. package/brand-assets/cl-nica-de-las-am-ricas/processed/business-identity.txt +11 -0
  10. package/brand-assets/cl-nica-de-las-am-ricas/raw/business-identity.txt +11 -0
  11. package/brand-assets/cl-nica-las-am-ricas/manifest.json +22 -0
  12. package/brand-assets/cl-nica-las-am-ricas/processed/business-identity.txt +11 -0
  13. package/brand-assets/cl-nica-las-am-ricas/raw/business-identity.txt +11 -0
  14. package/brand-assets/conny-demo/manifest.json +22 -0
  15. package/brand-assets/conny-demo/processed/business-identity.txt +7 -0
  16. package/brand-assets/conny-demo/raw/business-identity.txt +7 -0
  17. package/brand-assets/conny-logo.png +0 -0
  18. package/brand-assets/web.background.png +0 -0
  19. package/brand_assets.py +323 -0
  20. package/conny +28 -0
  21. package/conny-chat.py +579 -0
  22. package/conny-omni.py +3843 -0
  23. package/conny.py +113 -0
  24. package/conny_agents/__init__.py +1 -0
  25. package/conny_agents/agenda.py +1 -0
  26. package/conny_agents/captacion.py +1 -0
  27. package/conny_agents/conocimiento.py +1 -0
  28. package/conny_agents/escalacion.py +1 -0
  29. package/conny_agents/objeciones.py +1 -0
  30. package/conny_agents/seguimiento.py +1 -0
  31. package/conny_app.py +287 -0
  32. package/conny_audio.py +350 -0
  33. package/conny_audio_learn.py +84 -0
  34. package/conny_brain_v10.py +804 -0
  35. package/conny_bridge.py +656 -0
  36. package/conny_calendar.py +169 -0
  37. package/conny_cli.py +11784 -0
  38. package/conny_cli_bb.py +437 -0
  39. package/conny_commands.py +243 -0
  40. package/conny_config.py +215 -0
  41. package/conny_core/__init__.py +3 -0
  42. package/conny_core/conversation_engine.py +446 -0
  43. package/conny_core/first_turn_ops.py +287 -0
  44. package/conny_core/persona_registry.py +157 -0
  45. package/conny_core/prompt_ops.py +561 -0
  46. package/conny_cron.py +72 -0
  47. package/conny_demo_v2.py +209 -0
  48. package/conny_demo_voice.py +134 -0
  49. package/conny_design.py +43 -0
  50. package/conny_doctor.py +319 -0
  51. package/conny_domino.py +696 -0
  52. package/conny_generator.py +447 -0
  53. package/conny_google_auth.py +159 -0
  54. package/conny_i18n.py +619 -0
  55. package/conny_init.py +509 -0
  56. package/conny_integrations/__init__.py +4 -0
  57. package/conny_integrations/llm.py +1 -0
  58. package/conny_integrations/vault.py +77 -0
  59. package/conny_integrations/whatsapp.py +1 -0
  60. package/conny_intelligence.py +65 -0
  61. package/conny_learning.py +154 -0
  62. package/conny_memory.py +243 -0
  63. package/conny_memory_engine.py +292 -0
  64. package/conny_nova_proxy.py +170 -0
  65. package/conny_nuke_robot_phrases.py +493 -0
  66. package/conny_pairing.py +253 -0
  67. package/conny_patch.py +291 -0
  68. package/conny_persona_cli.py +150 -0
  69. package/conny_router.py +308 -0
  70. package/conny_runtime_ops.py +271 -0
  71. package/conny_session.py +516 -0
  72. package/conny_skills/__init__.py +1 -0
  73. package/conny_skills/demo_mode.py +35 -0
  74. package/conny_skills/text_processing.py +1 -0
  75. package/conny_skills/tone_detection.py +1 -0
  76. package/conny_smart_features.py +333 -0
  77. package/conny_studio.py +161 -0
  78. package/conny_sync_fix.py +306 -0
  79. package/conny_tui.py +512 -0
  80. package/conny_tui_select.py +202 -0
  81. package/conny_ultra_config.py +411 -0
  82. package/conny_uncertainty.py +174 -0
  83. package/conny_utils.py +87 -0
  84. package/conny_voice.py +156 -0
  85. package/conny_voice_engine.py +124 -0
  86. package/conny_web_search.py +66 -0
  87. package/conny_weekly_report.py +85 -0
  88. package/conny_worm.py +88 -0
  89. package/core/__init__.py +25 -0
  90. package/ecosystem.config.js +24 -0
  91. package/fix_init.py +27 -0
  92. package/install.sh +78 -0
  93. package/knowledge_base.py +330 -0
  94. package/nova/rules/default.yaml +37 -0
  95. package/nova_bridge.py +509 -0
  96. package/npm/conny.js +471 -0
  97. package/package.json +102 -0
  98. package/personas/conny/base/default.yaml +35 -0
  99. package/personas/conny/base/estetica_whatsapp.yaml +36 -0
  100. package/requirements.txt +14 -0
  101. package/run.sh +47 -0
  102. package/search.py +465 -0
  103. package/smart_handoff.py +1150 -0
  104. package/src/__init__.py +0 -0
  105. package/src/conny/__init__.py +0 -0
  106. package/src/conny/admin/__init__.py +0 -0
  107. package/src/conny/admin/api.py +234 -0
  108. package/src/conny/admin/dashboard.py +772 -0
  109. package/src/conny/api/__init__.py +0 -0
  110. package/src/conny/api/routes.py +8851 -0
  111. package/src/conny/brain/__init__.py +15 -0
  112. package/src/conny/brain/engine.py +804 -0
  113. package/src/conny/brain/learning.py +154 -0
  114. package/src/conny/brain/memory.py +324 -0
  115. package/src/conny/brain/smart_features.py +333 -0
  116. package/src/conny/brain/uncertainty.py +167 -0
  117. package/src/conny/channels/__init__.py +0 -0
  118. package/src/conny/channels/audio.py +316 -0
  119. package/src/conny/channels/cli.py +11795 -0
  120. package/src/conny/channels/logo_art.py +11 -0
  121. package/src/conny/channels/voice.py +156 -0
  122. package/src/conny/core/__init__.py +0 -0
  123. package/src/conny/core/config.py +215 -0
  124. package/src/conny/core/cron.py +72 -0
  125. package/src/conny/core/messenger.py +563 -0
  126. package/src/conny/core/router.py +297 -0
  127. package/src/conny/core/session.py +312 -0
  128. package/src/conny/demo/__init__.py +0 -0
  129. package/src/conny/demo/handler.py +3110 -0
  130. package/src/conny/integrations/__init__.py +19 -0
  131. package/src/conny/integrations/calendar.py +169 -0
  132. package/src/conny/integrations/knowledge.py +312 -0
  133. package/src/conny/integrations/search.py +66 -0
  134. package/src/conny/personas/__init__.py +0 -0
  135. package/src/conny/personas/generator.py +447 -0
  136. package/src/conny/production/__init__.py +0 -0
  137. package/src/conny/production/domino.py +696 -0
  138. package/src/conny/production/guard.py +550 -0
  139. package/src/conny/production/handoff.py +1150 -0
  140. package/src/conny/production/monitor.py +353 -0
  141. package/src/conny/utils/__init__.py +2 -0
  142. package/src/conny/utils/helpers.py +75 -0
  143. package/src/conny/utils/i18n.py +619 -0
  144. package/src/core/admin_engines.py +772 -0
  145. package/src/core/globals.py +11845 -0
  146. package/src/core/orchestrator.py +273 -0
  147. package/src/core/production_monitor.py +353 -0
  148. package/src/core/runtime.py +5487 -0
  149. package/src/domain/onboarding_flow.py +230 -0
  150. package/src/domain/prompts/__init__.py +1 -0
  151. package/src/domain/prompts/prospect_pitch.py +282 -0
  152. package/src/domain/send_guard.py +636 -0
  153. package/src/domain/swarm/queen.py +96 -0
  154. package/src/infrastructure/llm_providers/engine.py +487 -0
  155. package/src/interfaces/mcp_server.py +73 -0
  156. package/src/interfaces/nova_bridge.py +58 -0
  157. package/src/interfaces/web/admin_api.py +1379 -0
  158. package/src/interfaces/web/app.py +9408 -0
  159. package/src/interfaces/web/demo_handler.py +3450 -0
  160. package/src/interfaces/web/static/generate_avatars.py +46 -0
  161. package/v7/__init__.py +46 -0
  162. package/v7/agents/__init__.py +46 -0
  163. package/v7/agents/agenda.py +77 -0
  164. package/v7/agents/base.py +216 -0
  165. package/v7/agents/captacion.py +60 -0
  166. package/v7/agents/conocimiento.py +69 -0
  167. package/v7/agents/escalacion.py +83 -0
  168. package/v7/agents/objeciones.py +109 -0
  169. package/v7/agents/seguimiento.py +71 -0
  170. package/v7/memory/__init__.py +46 -0
  171. package/v7/memory/patient_profile.py +200 -0
  172. package/v7/orchestrator.py +275 -0
  173. package/v7/postprocess.py +127 -0
  174. package/v7/router.py +239 -0
  175. package/verify_conversation_impl.py +48 -0
@@ -0,0 +1,306 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ conny_sync_fix.py — Parcha conny_cli.py con 3 correcciones críticas
4
+
5
+ Bugs que corrige:
6
+ 1. INSTANCES_DIR apuntaba a ~/.conny/instances en vez de ~/conny-instances
7
+ 2. 'personas' en SYNC_RUNTIME_DIRS sobrescribía identidades de clientes
8
+ 3. _clone_runtime_entries usaba rmtree en directorios (destructivo)
9
+
10
+ Uso:
11
+ cd ~/conny
12
+ python3 conny_sync_fix.py
13
+
14
+ El script crea un backup antes de modificar.
15
+ """
16
+
17
+ import sys
18
+ import os
19
+ import shutil
20
+ import re
21
+ from pathlib import Path
22
+ from datetime import datetime
23
+
24
+ CLI_PATH = Path(__file__).resolve().parent / "conny_cli.py"
25
+
26
+ # ══════════════════════════════════════════════════════════════════════════════
27
+ # Parches exactos (old_str → new_str)
28
+ # ══════════════════════════════════════════════════════════════════════════════
29
+
30
+ PATCHES = [
31
+
32
+ # ── FIX 1: INSTANCES_DIR default path ────────────────────────────────────
33
+ {
34
+ "id": "fix-instances-dir",
35
+ "desc": "Corregir INSTANCES_DIR: ~/.conny/instances → ~/conny-instances",
36
+ "old": 'INSTANCES_DIR = os.getenv("INSTANCES_DIR", str(Path(CONNY_HOME) / "instances"))',
37
+ "new": 'INSTANCES_DIR = os.getenv("INSTANCES_DIR", str(Path.home() / "conny-instances"))',
38
+ },
39
+
40
+ # ── FIX 2: Remove 'personas' from SYNC_RUNTIME_DIRS ─────────────────────
41
+ {
42
+ "id": "fix-sync-dirs",
43
+ "desc": "Proteger directorios de identidad de instancias en sync",
44
+ "old": '''SYNC_RUNTIME_DIRS = [
45
+ "v7",
46
+ "conny_core",
47
+ "conny_agents",
48
+ "conny_skills",
49
+ "conny_integrations",
50
+ "personas",
51
+ ]''',
52
+ "new": '''# ── Directorios que se sincronizan a todas las instancias ──────────────────
53
+ SYNC_RUNTIME_DIRS = [
54
+ "v7",
55
+ "conny_core",
56
+ "conny_agents",
57
+ "conny_skills",
58
+ "conny_integrations",
59
+ # "personas" INTENCIONALMENTE EXCLUIDO:
60
+ # cada instancia tiene su propia identidad, prompts y tono.
61
+ # Usa 'conny config <nombre>' para editar la persona de un cliente.
62
+ ]
63
+
64
+ # ── Paths que NUNCA se tocan durante sync ──────────────────────────────────
65
+ INSTANCE_PROTECTED_PATHS = {
66
+ ".env",
67
+ "conny.db", "conny.db-shm", "conny.db-wal",
68
+ "conny_ultra.db", "vectors.db", "data.db",
69
+ "logs",
70
+ "identity", # Nombre, voz, tono del agente
71
+ "soul", # Valores y ética del agente
72
+ "personas", # Prompts de sistema del cliente
73
+ "knowledge_base", # Base de conocimiento del cliente
74
+ "instance.json",
75
+ "auth_info_multi.txt",
76
+ "__pycache__",
77
+ "backups",
78
+ ".venv",
79
+ }
80
+ ''',
81
+ },
82
+
83
+ # ── FIX 3: Smart directory sync (no rmtree) ───────────────────────────────
84
+ {
85
+ "id": "fix-clone-entries",
86
+ "desc": "Sync inteligente: actualiza archivos sin borrar los específicos de la instancia",
87
+ "old": '''def _clone_runtime_entries(source_root: str, dest_root: str, entries: Optional[List[str]] = None) -> List[str]:
88
+ src_root = Path(source_root)
89
+ dst_root = Path(dest_root)
90
+ copied: List[str] = []
91
+ for rel_path in entries or _runtime_sync_entries(source_root):
92
+ src = src_root / rel_path
93
+ dst = dst_root / rel_path
94
+ if not src.exists():
95
+ continue
96
+ dst.parent.mkdir(parents=True, exist_ok=True)
97
+ if src.is_dir():
98
+ _remove_runtime_target(dst)
99
+ shutil.copytree(src, dst)
100
+ else:
101
+ if dst.exists() or dst.is_symlink():
102
+ _remove_runtime_target(dst)
103
+ shutil.copy2(src, dst)
104
+ copied.append(rel_path)
105
+ return copied''',
106
+ "new": '''def _sync_dir_smart(src: Path, dst: Path) -> None:
107
+ """
108
+ Sync de directorio que ACTUALIZA archivos sin borrar extras.
109
+ A diferencia de copytree(dirs_exist_ok=False), no elimina archivos
110
+ que solo existen en el destino (configuraciones del cliente).
111
+ """
112
+ dst.mkdir(parents=True, exist_ok=True)
113
+ for item in src.rglob("*"):
114
+ rel = item.relative_to(src)
115
+ target = dst / rel
116
+ # Nunca pisar rutas protegidas dentro de subdirectorios
117
+ top = rel.parts[0] if rel.parts else ""
118
+ if top in INSTANCE_PROTECTED_PATHS:
119
+ continue
120
+ try:
121
+ if item.is_dir():
122
+ target.mkdir(parents=True, exist_ok=True)
123
+ else:
124
+ target.parent.mkdir(parents=True, exist_ok=True)
125
+ shutil.copy2(item, target)
126
+ except Exception:
127
+ pass # permisos u otros errores no detienen el sync
128
+
129
+
130
+ def _clone_runtime_entries(source_root: str, dest_root: str, entries: Optional[List[str]] = None) -> List[str]:
131
+ src_root = Path(source_root)
132
+ dst_root = Path(dest_root)
133
+ copied: List[str] = []
134
+ for rel_path in entries or _runtime_sync_entries(source_root):
135
+ # Saltar rutas protegidas de la instancia
136
+ top_level = Path(rel_path).parts[0] if Path(rel_path).parts else rel_path
137
+ if top_level in INSTANCE_PROTECTED_PATHS:
138
+ continue
139
+ src = src_root / rel_path
140
+ dst = dst_root / rel_path
141
+ if not src.exists():
142
+ continue
143
+ dst.parent.mkdir(parents=True, exist_ok=True)
144
+ if src.is_dir():
145
+ # Sync inteligente: actualiza sin borrar archivos del cliente
146
+ _sync_dir_smart(src, dst)
147
+ else:
148
+ if dst.exists() or dst.is_symlink():
149
+ _remove_runtime_target(dst)
150
+ shutil.copy2(src, dst)
151
+ copied.append(rel_path)
152
+ return copied''',
153
+ },
154
+
155
+ # ── FIX 4: Lanzar TUI cuando conny se corre sin args ───────────────────
156
+ {
157
+ "id": "fix-tui-launch",
158
+ "desc": "Lanzar conny_tui cuando no hay argumentos",
159
+ "old": ''' if cmd == "" and not args.help:
160
+ ensure_workspace_files()
161
+ if not workspace_is_configured() or not get_instances():
162
+ cmd_init(args)
163
+ return
164
+
165
+ # Help
166
+ if args.help or cmd in ("help", "--help", "-h", ""):
167
+ cmd_help_extended(args)
168
+ return''',
169
+ "new": ''' if cmd == "" and not args.help:
170
+ # ── Intentar lanzar TUI interactivo ──────────────────────────────
171
+ _tui_path = Path(__file__).resolve().parent / "conny_tui.py"
172
+ if sys.stdout.isatty() and _tui_path.exists():
173
+ try:
174
+ import importlib.util as _ilu
175
+ _spec = _ilu.spec_from_file_location("conny_tui", str(_tui_path))
176
+ _mod = _ilu.module_from_spec(_spec)
177
+ _spec.loader.exec_module(_mod)
178
+ _mod.run_tui()
179
+ return
180
+ except Exception:
181
+ pass # Fallback a help normal
182
+
183
+ ensure_workspace_files()
184
+ if not workspace_is_configured() or not get_instances():
185
+ cmd_init(args)
186
+ return
187
+
188
+ # Help
189
+ if args.help or cmd in ("help", "--help", "-h", ""):
190
+ cmd_help_extended(args)
191
+ return''',
192
+ },
193
+ ]
194
+
195
+
196
+ # ══════════════════════════════════════════════════════════════════════════════
197
+ # Motor del patcher
198
+ # ══════════════════════════════════════════════════════════════════════════════
199
+
200
+ GREEN = "\033[32m"
201
+ RED = "\033[31m"
202
+ YELLOW = "\033[33m"
203
+ CYAN = "\033[36m"
204
+ DIM = "\033[2m"
205
+ BOLD = "\033[1m"
206
+ RESET = "\033[0m"
207
+
208
+ def _c(color, text): return f"{color}{text}{RESET}"
209
+
210
+
211
+ def apply_patches(cli_path: Path) -> None:
212
+ print(f"\n {_c(BOLD, 'conny_sync_fix')} — Parcheando {cli_path.name}")
213
+ print()
214
+
215
+ if not cli_path.exists():
216
+ print(f" {_c(RED, '✗')} No encontré {cli_path}")
217
+ print(f" Asegúrate de correr este script desde ~/conny/")
218
+ sys.exit(1)
219
+
220
+ # Backup
221
+ stamp = datetime.now().strftime("%Y%m%d_%H%M%S")
222
+ bak = cli_path.with_suffix(f".py.bak.{stamp}")
223
+ shutil.copy2(cli_path, bak)
224
+ print(f" {_c(GREEN, '✓')} Backup creado: {bak.name}")
225
+ print()
226
+
227
+ content = cli_path.read_text(encoding="utf-8", errors="replace")
228
+ applied = 0
229
+ skipped = 0
230
+
231
+ for patch in PATCHES:
232
+ pid = patch["id"]
233
+ desc = patch["desc"]
234
+ old = patch["old"]
235
+ new = patch["new"]
236
+
237
+ if old not in content:
238
+ # Verificar si el nuevo código ya está presente (ya parcheado)
239
+ if new.strip()[:40] in content:
240
+ print(f" {_c(DIM, '·')} [{pid}] Ya estaba aplicado — {_c(DIM, desc)}")
241
+ else:
242
+ print(f" {_c(YELLOW, '!')} [{pid}] No encontré el fragmento exacto — {_c(DIM, desc)}")
243
+ print(f" {_c(DIM, 'Puede que el código haya cambiado. Revisa manualmente.')}")
244
+ skipped += 1
245
+ continue
246
+
247
+ content = content.replace(old, new, 1)
248
+ applied += 1
249
+ print(f" {_c(GREEN, '✓')} [{pid}] {desc}")
250
+
251
+ print()
252
+
253
+ if applied > 0:
254
+ cli_path.write_text(content, encoding="utf-8")
255
+ print(f" {_c(GREEN, '✓')} {applied} fix(es) aplicado(s) correctamente")
256
+ else:
257
+ print(f" {_c(YELLOW, '·')} Nada que aplicar — todos los fixes ya estaban presentes")
258
+
259
+ if skipped > 0 and applied == 0:
260
+ print(f" {_c(YELLOW, '!')} {skipped} patch(es) no coincidieron — revisa el CHANGELOG abajo")
261
+ print()
262
+ print(" ── Fixes manuales si el auto-patch no funcionó ─────────────────")
263
+ _print_manual_guide()
264
+
265
+ print()
266
+ print(f" {_c(CYAN, 'Siguiente paso:')} pm2 restart conny-clinica-americas")
267
+ print(f" {_c(CYAN, 'Probar sync:')} conny sync")
268
+ print()
269
+
270
+
271
+ def _print_manual_guide():
272
+ print("""
273
+ FIX 1 — INSTANCES_DIR (línea ~158 en conny_cli.py)
274
+ ┌──────────────────────────────────────────────────────────────────
275
+ │ - INSTANCES_DIR = os.getenv("INSTANCES_DIR", str(Path(CONNY_HOME) / "instances"))
276
+ │ + INSTANCES_DIR = os.getenv("INSTANCES_DIR", str(Path.home() / "conny-instances"))
277
+ └──────────────────────────────────────────────────────────────────
278
+
279
+ FIX 2 — SYNC_RUNTIME_DIRS (línea ~192)
280
+ ┌──────────────────────────────────────────────────────────────────
281
+ │ Elimina "personas" de la lista SYNC_RUNTIME_DIRS
282
+ │ (esa lista está al principio del archivo)
283
+ └──────────────────────────────────────────────────────────────────
284
+
285
+ FIX 3 — _clone_runtime_entries (función)
286
+ ┌──────────────────────────────────────────────────────────────────
287
+ │ En el loop, agrega antes del if src.is_dir():
288
+ │ top_level = Path(rel_path).parts[0]
289
+ │ if top_level in {".env","conny.db","personas","identity","soul","logs"}:
290
+ │ continue
291
+ │ Y reemplaza:
292
+ │ _remove_runtime_target(dst)
293
+ │ shutil.copytree(src, dst)
294
+ │ Por un loop que copie solo archivos nuevos/modificados
295
+ └──────────────────────────────────────────────────────────────────
296
+ """)
297
+
298
+
299
+ # ══════════════════════════════════════════════════════════════════════════════
300
+
301
+ if __name__ == "__main__":
302
+ target = CLI_PATH
303
+ if len(sys.argv) > 1:
304
+ target = Path(sys.argv[1])
305
+
306
+ apply_patches(target)