-
Notifications
You must be signed in to change notification settings - Fork 0
Spanish wiki wiki en español
amcx es un formato de archivo binario (.amcx) diseñado para almacenar memoria de chat de IA de forma comprimida, estructurada y verificable.
0.3.4
Cuando una app de IA necesita recordar conversaciones largas, la solución ingenua es guardar todo en texto plano o JSON. Esto desperdicia espacio en disco y obliga a la IA a cargar todo el historial en cada respuesta.
amcx lo resuelve:
- Comprimiendo el historial de chat 60-70% usando zlib/lzma
- Dividiendo la memoria en chunks para cargar solo las partes relevantes
- Verificando la integridad con checksums CRC32 y SHA-1
- Recuperando chunks corruptos automáticamente con bloques XOR
El usuario manda un mensaje
↓
La app del desarrollador llama SmartMemory.append()
↓
amcx comprime y guarda en el archivo .amcx
↓
El usuario pregunta algo del inicio de la conversación
↓
SmartMemory.search() carga SOLO el chunk relevante
↓
El chunk se descomprime en RAM, se usa y se descarta
↓
No quedan archivos temporales en disco
El usuario final nunca sabe que .amcx existe.
Prueba usar amcl, una versión más ligera adecuada para pequeñas empresas o proyectos con recursos limitados.
prueba usar Add-ons, addons nativos escritos en c++
from amcx import SmartMemory
memory = SmartMemory("chat.amcx", use_mirror=False)
memory.append("usuario: Hola, cuéntame sobre el mundo")
memory.append("ia: El mundo es vasto y lleno de misterios...")
resultados = memory.search("mundo")
print(resultados)Eso es todo lo que el desarrollador necesita escribir. Todo lo demás se maneja automáticamente.
- Python 3.10 o superior
- Sin dependencias externas (solo librería estándar)
pip install amcxfrom amcx import SmartMemory
# Crear archivo de memoria
memory = SmartMemory("chat.amcx", use_mirror=False)
# Guardar mensajes
memory.append("usuario: Hola, ¿cuál es la capital de Francia?")
memory.append("ia: La capital de Francia es París.")
memory.append("usuario: ¿Y la de Alemania?")
memory.append("ia: La capital de Alemania es Berlín.")
# Los mensajes se guardan y comprimen automáticamentefrom amcx import SmartMemory
memory = SmartMemory("chat.amcx")
# Buscar contexto relevante
resultados = memory.search("Francia")
for r in resultados:
print(r)
# Salida: "usuario: Hola, ¿cuál es la capital de Francia?"
# "ia: La capital de Francia es París."
# Obtener mensajes recientes
recientes = memory.get_recent(3)
for r in recientes:
print(r)from amcx import SmartMemory
class MiChatBot:
def __init__(self):
# El usuario nunca sabe que esto existe
self.memory = SmartMemory(".historial_chat.amcx", use_mirror=False)
def responder(self, mensaje_usuario: str) -> str:
# Guardar mensaje del usuario
self.memory.append(f"usuario: {mensaje_usuario}")
# Cargar contexto relevante (descomprime solo los chunks necesarios)
contexto = self.memory.search(mensaje_usuario, max_results=3)
# Generar respuesta usando tu API de IA
respuesta = tu_api_ia(mensaje_usuario, contexto)
# Guardar respuesta
self.memory.append(f"ia: {respuesta}")
return respuesta
bot = MiChatBot()
print(bot.responder("¡Hola!"))memory = SmartMemory(
path="chat.amcx", # ruta al archivo .amcx
use_mirror=False, # True = checksums SHA-1 + más espacio
use_recovery=False, # True = bloques de recuperación XOR
auto_chunk_size=2000, # caracteres antes de crear un nuevo chunk
old_chunk_days=7, # días antes de cambiar a compresión lzma
)| Opción | Por defecto | Descripción |
|---|---|---|
use_mirror |
False |
Embebe checksums SHA-1 para verificación de integridad |
use_recovery |
False |
Agrega bloques XOR para reparación automática |
auto_chunk_size |
2000 |
Máx. caracteres por chunk antes de dividir |
old_chunk_days |
7 |
Días hasta comprimir con lzma en vez de zlib |
SmartMemory es la interfaz principal de alto nivel de amcx. Maneja compresión, chunks, verificación de integridad y recuperación automáticamente. El desarrollador solo necesita llamar métodos simples.
from amcx import SmartMemorySmartMemory(
path: str,
use_mirror: bool = False,
use_recovery: bool = False,
auto_chunk_size: int = 2000,
old_chunk_days: int = 7,
)| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
path |
str |
requerido | Ruta al archivo .amcx
|
use_mirror |
bool |
False |
Embebe checksums SHA-1 por chunk |
use_recovery |
bool |
False |
Agrega bloques de recuperación XOR |
auto_chunk_size |
int |
2000 |
Caracteres antes de guardar automáticamente |
old_chunk_days |
int |
7 |
Días antes de comprimir con lzma en vez de zlib |
Agrega un mensaje a la memoria. Se guarda automáticamente cuando acumula suficiente contenido.
memory.append("usuario: ¡Hola!")
memory.append("ia: Hola, ¿en qué puedo ayudarte?")- La compresión se elige automáticamente (zlib para recientes, lzma para viejos)
- No se crean archivos temporales
Busca mensajes relevantes. Solo descomprime los chunks que coinciden.
resultados = memory.search("Francia", max_results=3)
for r in resultados:
print(r)Retorna: List[str] — lista de mensajes que coinciden
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
query |
str |
requerido | Texto a buscar |
max_results |
int |
5 |
Número máximo de resultados |
Retorna los N mensajes más recientes.
recientes = memory.get_recent(10)Retorna: List[str] — mensajes más recientes, el más nuevo primero
Fuerza el guardado de todos los mensajes pendientes. Se llama automáticamente, pero puede llamarse manualmente.
memory.flush()Verifica si el archivo está íntegro. Retorna True si todo está bien.
if not memory.verify_integrity():
print("El archivo puede estar corrupto")Retorna: bool
Intenta reparar chunks corruptos usando mirror o bloques de recuperación XOR.
reparado = memory.repair()
if reparado:
print("Reparado con éxito")Retorna: bool — True si se reparó algo
Retorna el tamaño del archivo en bytes.
tamaño = memory.size_on_disk()
print(f"{tamaño / 1024:.1f} KB")Retorna: int
Retorna el número total de mensajes (guardados + pendientes).
total = memory.count_messages()
print(f"Total de mensajes: {total}")Retorna: int
SmartMemory soporta with. Llama flush() automáticamente al salir.
with SmartMemory("chat.amcx") as memory:
memory.append("usuario: Hola")
memory.append("ia: ¡Hola!")
# flush() se llama automáticamente aquí| Configuración | Tamaño (100 KB de entrada) | Notas |
|---|---|---|
use_mirror=False |
~35 KB | Máximo ahorro |
use_mirror=True |
~50 KB | + verificación SHA-1 |
use_mirror=True, use_recovery=True |
~60 KB | + reparación automática XOR |
from amcx import SmartMemory
class AsistenteIA:
def __init__(self, session_id: str):
self.memory = SmartMemory(
f".sessions/{session_id}.amcx",
use_mirror=False,
auto_chunk_size=3000,
)
def chat(self, entrada_usuario: str) -> str:
# Guardar entrada
self.memory.append(f"usuario: {entrada_usuario}")
# Obtener contexto
contexto = self.memory.search(entrada_usuario, max_results=5)
recientes = self.memory.get_recent(10)
# Llama a tu API de IA con contexto + mensajes recientes
respuesta = call_ai_api(entrada_usuario, contexto, recientes)
# Guardar respuesta
self.memory.append(f"ia: {respuesta}")
return respuesta
def stats(self):
return {
"mensajes": self.memory.count_messages(),
"tamaño_kb": self.memory.size_on_disk() / 1024,
"saludable": self.memory.verify_integrity(),
}El formato .amcx es un archivo binario personalizado diseñado para almacenamiento y recuperación eficiente de memoria de chat de IA.
[ HEADER 32b ] [ ÍNDICE ] [ CHUNKS... ] [ BLOQUE RECOVERY* ] [ BLOQUE MIRROR* ]
* opcional — solo presente si está habilitado.
Todo se almacena en un único archivo. Sin archivos adicionales, sin archivos temporales.
Los primeros 4 bytes de todo archivo .amcx son:
41 4D 43 00
A M C \0
Cualquier programa puede leer estos 4 bytes para confirmar que el archivo es un .amcx válido antes de parsear cualquier otra cosa.
| Offset | Tamaño | Campo | Descripción |
|---|---|---|---|
0x00 |
4b | Magic | AMC\0 |
0x04 |
1b | Versión mayor | Actualmente 0
|
0x05 |
1b | Versión menor | Actualmente 3
|
0x06 |
4b | Num chunks | Total de chunks |
0x0A |
8b | Creado en | Timestamp Unix |
0x12 |
4b | Offset índice | Offset en bytes donde empieza el índice |
0x16 |
4b | Tamaño índice | Tamaño del bloque índice en bytes |
0x1A |
2b | Flags | Bitfield (ver abajo) |
0x1C |
4b | CRC32 | CRC32 de los primeros 28 bytes |
| Bit | Constante | Descripción |
|---|---|---|
| 0 | FLAG_COMPRESSED |
Al menos un chunk está comprimido |
| 1 | FLAG_ENCRYPTED |
Reservado para cifrado futuro |
| 2 | FLAG_READONLY |
Archivo de solo lectura |
| 3 | FLAG_HAS_ACTIVE |
Hay un chunk activo |
| 4 | FLAG_HAS_ASSETS |
Reservado para assets futuros |
El índice viene justo después del header. Contiene una entrada por chunk (96 bytes cada una).
| Offset | Tamaño | Campo | Descripción |
|---|---|---|---|
0x00 |
4b | Chunk ID | ID entero único |
0x04 |
4b | Offset | Offset en bytes del chunk en el archivo |
0x08 |
4b | Tamaño comprimido | Tamaño comprimido en bytes |
0x0C |
4b | Tamaño original | Tamaño original antes de comprimir |
0x10 |
2b | Tipo de chunk | Ver tipos de chunk abajo |
0x12 |
1b | Algoritmo | Algoritmo de compresión |
0x13 |
1b | Reservado | Padding |
0x14 |
8b | Timestamp | Timestamp Unix del chunk |
0x1C |
4b | CRC32 | CRC32 de los datos comprimidos |
0x20 |
64b | Summary | Texto UTF-8, relleno con nulos |
| Valor | Constante | Descripción |
|---|---|---|
0x00 |
CHUNK_LORE |
Lore/mundo/reglas |
0x01 |
CHUNK_CHARACTER |
Datos de personaje |
0x02 |
CHUNK_EVENT |
Evento narrativo |
0x03 |
CHUNK_ACTIVE |
Chunk activo actual |
0x04 |
CHUNK_GENERIC |
Contenido genérico |
| Valor | Constante | Algoritmo | Mejor para |
|---|---|---|---|
0x00 |
COMPRESS_NONE |
Ninguno | Debug / chunks pequeños |
0x01 |
COMPRESS_ZLIB |
zlib | Chunks activos/recientes |
0x02 |
COMPRESS_LZMA |
lzma | Chunks viejos/archivados |
Cada chunk se almacena como:
[ 4 bytes: tamaño comprimido ] [ N bytes: datos comprimidos ]
El índice te dice exactamente dónde empieza cada chunk, así leer un chunk nunca requiere leer los demás.
Magic: AMCXR\0 (6 bytes)
Bloques de paridad XOR inspirados en los recovery records de WinRAR. Los chunks se agrupan (por defecto: 3 por grupo). Cada grupo tiene un bloque de paridad = XOR de todos los chunks del grupo. Si un chunk se corrompe, puede reconstruirse usando los otros + la paridad.
Magic: AMCXM\0 (6 bytes)
Checksums SHA-1 por chunk almacenados dentro del propio archivo.
El reader usa rfind() para ubicar los bloques de Recovery y Mirror al final del archivo. Esto significa:
- Cargar el header → saber dónde está el índice
- Cargar el índice → saber dónde está cada chunk
- Pedir el chunk N → ir directo a su offset, leer solo esos bytes
- Verificar CRC32 → descomprimir → devolver
Sin escaneos, sin cargar datos innecesarios.
amcx incluye dos sistemas opcionales de protección de datos, ambos embebidos dentro del archivo .amcx — sin archivos adicionales.
| Sistema | Qué hace | Costo en espacio |
|---|---|---|
| Mirror | Almacena SHA-1 por chunk para detectar modificaciones o corrupción | ~24 bytes × chunks |
| Recovery | Almacena bloques de paridad XOR para reconstruir chunks corruptos | ~tamaño de un chunk por grupo |
from amcx import SmartMemory
memory = SmartMemory(
"chat.amcx",
use_mirror=True, # checksums SHA-1
use_recovery=True, # bloques de recuperación XOR
)Cuando use_mirror=True, un bloque AMCXM\0 se agrega al final del archivo en cada guardado. Este bloque contiene un hash SHA-1 del contenido original de cada chunk.
from amcx import AMCXMirror
status = AMCXMirror.verify("chat.amcx")
print(status.report())
# con el acelerador nativo SHA-1
status = AMCXMirror.verify("chat.amcx", accelerator_path="./amcx_sha1.so")| Estado | Significado |
|---|---|
ok |
SHA-1 coincide |
modified |
SHA-1 cambió — el chunk fue editado |
missing_mirror |
Chunk en el archivo pero no en el mirror |
missing_orig |
Chunk en el mirror pero no en el archivo |
outdated |
El mirror es más viejo que el archivo |
AMCXMirror.update("chat.amcx")
# con el acelerador nativo SHA-1
AMCXMirror.update("chat.amcx", accelerator_path="./amcx_sha1.so")Paridad XOR inspirada en los recovery records de WinRAR. Los chunks se dividen en grupos de N (por defecto 3). Para cada grupo se calcula un bloque de paridad:
paridad = chunk_0 XOR chunk_1 XOR chunk_2
Si chunk_1 se corrompe:
chunk_1 = paridad XOR chunk_0 XOR chunk_2
from amcx import AMCXRecovery
puede = AMCXRecovery.can_recover("chat.amcx", damaged_chunk_id=2)
print(puede) # True o Falsebytes_recuperados = AMCXRecovery.recover_chunk("chat.amcx", damaged_chunk_id=2)
texto = bytes_recuperados.decode("utf-8")
print(texto)
# con el acelerador nativo XOR
bytes_recuperados = AMCXRecovery.recover_chunk("chat.amcx", damaged_chunk_id=2, accelerator_path="./amcx_xor.so")- Solo un chunk por grupo puede recuperarse
- Si dos chunks del mismo grupo están corruptos, la recuperación falla
- El tamaño del grupo se establece al escribir y no puede cambiarse después
| Modo | Comportamiento |
|---|---|
MirrorMode.NONE |
Sin mirror embebido |
MirrorMode.MANUAL |
Solo cuando llamas embed_mirror()
|
MirrorMode.AUTO |
Se actualiza automáticamente en cada save()
|
Para un historial de chat de 100 KB:
| Configuración | Tamaño del archivo |
|---|---|
| Sin mirror, sin recovery | ~35 KB |
| Solo mirror | ~50 KB |
| Mirror + recovery | ~60 KB |
Para casos de uso avanzados donde necesitas control total sobre el archivo .amcx.
Crea y escribe archivos .amcx.
from amcx import AMCXWriter, ChunkEntry, MirrorMode
from amcx import CHUNK_LORE, CHUNK_CHARACTER, CHUNK_EVENT, CHUNK_ACTIVE, CHUNK_GENERIC
from amcx import COMPRESS_NONE, COMPRESS_ZLIB, COMPRESS_LZMAwriter = AMCXWriter()
# Atajo para texto
writer.add_text_chunk(
chunk_id=0,
chunk_type=CHUNK_LORE,
summary="El mundo",
text="El mundo es un lugar oscuro...",
algorithm=COMPRESS_LZMA,
)
# Bytes crudos
writer.add_chunk(ChunkEntry(
chunk_id=1,
chunk_type=CHUNK_ACTIVE,
summary="Sesión actual",
content=b"bytes crudos aquí",
algorithm=COMPRESS_ZLIB,
))# Guardar en archivo
writer.save("memoria.amcx")
# Obtener como bytes (sin archivo)
data = writer.to_bytes()Lee archivos .amcx. Carga el índice al abrir, los chunks solo bajo demanda.
from amcx import AMCXReader# Context manager (recomendado)
with AMCXReader("memoria.amcx") as reader:
...
# Manual
reader = AMCXReader("memoria.amcx")
reader.close()with AMCXReader("memoria.amcx") as reader:
entries = reader.list_chunks()
for entry in entries:
print(f"[{entry.chunk_id}] {entry.summary} ({entry.algorithm_name}, {entry.size_original}b)")with AMCXReader("memoria.amcx") as reader:
# Leer como bytes
data = reader.read_chunk(0)
# Leer como texto
texto = reader.read_chunk_text(0)
# Leer el chunk activo
activo = reader.read_active_chunk()with AMCXReader("memoria.amcx") as reader:
print(reader.header.version_str) # "0.3"
print(reader.header.num_chunks) # 5
print(reader.header.has_active_chunk) # True/False
print(reader.summary()) # índice legible para humanos| Constante | Valor | Usar para |
|---|---|---|
CHUNK_LORE |
0 |
Construcción del mundo, reglas |
CHUNK_CHARACTER |
1 |
Descripciones de personajes |
CHUNK_EVENT |
2 |
Eventos pasados |
CHUNK_ACTIVE |
3 |
Sesión actual (más reciente) |
CHUNK_GENERIC |
4 |
Cualquier otra cosa |
| Constante | Algoritmo | Velocidad | Ratio | Usar para |
|---|---|---|---|---|
COMPRESS_NONE |
Ninguno | Más rápido | 0% | Debug |
COMPRESS_ZLIB |
zlib | Rápido | ~60% | Chunks recientes |
COMPRESS_LZMA |
lzma | Lento | ~70% | Chunks viejos |
from amcx import (
AMCXError, # excepción base
AMCXInvalidFileError, # no es un .amcx válido
AMCXVersionError, # versión incompatible
AMCXCompressionError, # fallo en compresión/descompresión
AMCXChunkNotFoundError, # chunk ID no está en el índice
AMCXCorruptError, # CRC32 no coincide
AMCXReadOnlyError, # escritura en archivo de solo lectura
AMCXSecurityError, # amenaza de bypass/jailbreak detectada
)from amcx import AMCXReader, AMCXCorruptError, AMCXChunkNotFoundError
try:
with AMCXReader("memoria.amcx") as reader:
texto = reader.read_chunk_text(99)
except AMCXChunkNotFoundError:
print("El chunk 99 no existe")
except AMCXCorruptError as e:
print(f"Corrupción detectada: {e}")from amcx import (
AMCXWriter, AMCXReader,
CHUNK_LORE, CHUNK_CHARACTER, CHUNK_ACTIVE,
COMPRESS_LZMA, COMPRESS_ZLIB,
MirrorMode,
)
# Escribir
writer = AMCXWriter(mirror=MirrorMode.AUTO, recovery=True)
writer.add_text_chunk(0, CHUNK_LORE, "El mundo", "Oscuro y vasto...", COMPRESS_LZMA)
writer.add_text_chunk(1, CHUNK_CHARACTER, "Aria", "Una guerrera elfa...", COMPRESS_LZMA)
writer.add_text_chunk(2, CHUNK_ACTIVE, "Sesión actual", "El grupo llega...", COMPRESS_ZLIB)
writer.save("historia.amcx")
# Leer
with AMCXReader("historia.amcx") as reader:
print(reader.summary())
print(reader.read_chunk_text(1)) # descripción de Ariaamcx incluye un sistema de detección de bypass/jailbreak integrado en detection.py. Escanea tanto el contenido del archivo .amcx como la memoria RAM del proceso en busca de patrones conocidos de prompt injection, y puede purgar o bloquear la ejecución automáticamente.
- Prompt injection (
"ignore previous instructions","disregard the system prompt", etc.) - Confusión de roles y jailbreaks (
"you are now DAN","act as if you have no rules") - Contrabando de delimitadores (tags falsos
[system],### system override) - Obfuscación en base64 y confusables Unicode de los patrones anteriores
- Narrative framing (ocultar una petición dañina dentro de "imagina una historia donde...")
- Descomposición multi-agente (dividir una petición en fragmentos inofensivos pensados para reunirse después)
- Manipulación de contexto largo (enterrar una instrucción inyectada en medio de un texto muy largo)
- Intentos de filtrar el system prompt (
"reveal your system prompt","what are your original instructions")
from amcx import scan_chunks
result = scan_chunks("chat.amcx")
if not result.clean:
for threat in result.chunk_threats:
print(threat.chunk_id, threat.matched)from amcx import scan_ram
result = scan_ram(purge=1) # purge=1 pone en cero las cadenas detectadas en memoria
# con el acelerador nativo
result = scan_ram(purge=1, accelerator_path="./amcx_accel.so")El contenido detectado nunca se expone en el resultado — solo aparece "[redacted]" junto con el patrón que lo activó, para no filtrar datos del usuario ni en tus propios logs.
from amcx import full_scan
result = full_scan(
"chat.amcx",
chunk_scan=1, # 1 = escanea los chunks del archivo, 0 = lo omite
ram_scan=1, # 1 = escanea la RAM del proceso, 0 = lo omite
ram_purge=1, # 1 = limpia lo encontrado en RAM, 0 = solo detecta
)Bloquea por completo la ejecución de una función si se detecta una amenaza antes:
from amcx import guarded, AMCXSecurityError
@guarded("chat.amcx")
def ejecutar_modelo():
...
try:
ejecutar_modelo()
except AMCXSecurityError as e:
print("ejecución bloqueada:", e)Pasa raise_on_threat=False para que la función corra de todos modos sin lanzar excepción:
@guarded("chat.amcx", raise_on_threat=False)
def ejecutar_modelo():
...Varias partes de amcx tienen add-ons opcionales en C++. Son completamente opcionales — sin ellos, todo funciona igual en Python puro con los mismos resultados.
| Add-on | Acelera | Usado por |
|---|---|---|
amcx_accel |
Matching de patrones de bypass |
scan_chunks, scan_ram, full_scan, guarded
|
amcx_sha1 |
Hashing SHA-1 | AMCXMirror.build_block/verify/embed/update |
amcx_xor |
Paridad y recuperación XOR | AMCXRecovery.append/recover_chunk |
amcx_crc32 |
No se usa actualmente — zlib.crc32 ya es C nativo |
— |
result = full_scan("chat.amcx", accelerator_path="./amcx_accel.so")
@guarded("chat.amcx", accelerator_path="./amcx_accel.so")
def ejecutar_modelo():
...Si la ruta no existe, no es un binario válido, o no tiene las funciones esperadas, amcx vuelve silenciosamente a Python puro — sin excepción, sin romper nada. Ver la rama Add-ons para el código fuente y los binarios precompilados.
¡Gracias por tu interés en contribuir a amcx!
- Haz fork del repositorio en GitHub
- Crea una rama:
git checkout -b mi-feature - Haz tus cambios
- Corre los tests:
pytest tests/ - Commit:
git commit -m "descripción del cambio" - Push:
git push origin mi-feature - Abre un Pull Request
pip install pytest
pytest tests/ -vTodos los tests deben pasar antes de enviar un PR.
- Python 3.10+
- Type hints en todas las funciones públicas
- Docstrings en todos los métodos públicos
- Sin dependencias externas (solo stdlib)
Abre un issue en GitHub con:
- Versión de Python
- Versión de amcx (
python -c "import amcx; print(amcx.__version__)") - Pasos para reproducir
- Comportamiento esperado vs actual
- Soporte de cifrado (
FLAG_ENCRYPTEDestá reservado) - Herramienta CLI (
amcx inspect archivo.amcx) - Soporte async para
SmartMemory - Más algoritmos de compresión
Wiki hecha por Claude
1. ¿Por qué se llama eXtended?
- Porque existe una versión base llamada Adaptive Memory Chunk (AMC) y esta versión pública tiene más características.
2. ¿Cuándo saldrá AMCL?
- Se lanzará a finales de 2026 o principios de 2027, aunque la fecha puede variar.
3. ¿Si uso amcl podré cambiarme a amcx?
- Sí, puedes cambiar usando el ejecutable
.exeo laapp image, y para entornos sin interfaz gráfica...
4. ¿tendra soporte para archivos multimedia?
- si, planeo en un futuro agregar soporte, aunque primero prefiero terminar
AMCL