Port completo del plugin @tuanhung303/opencode-acp
(que solo funciona en OpenCode V1) sobre la API de plugins de OpenCode V2.
Port no oficial. Este proyecto no lo mantiene tuanhung303, ni esta afiliado ni respaldado por el. Todo el diseno de ACP —las 8 estrategias, las reglas de proteccion, la herramienta
context_pruney los valores por defecto— es trabajo suyo. Aqui solo se reescribio la capa de integracion para que funcione en V2. Si el proyecto original te resulta util, pasate por su repositorio y dale una estrella.
Reduce el gasto de contexto de forma automática: detecta salidas de herramientas que ya
no aportan, las reemplaza por stubs de una línea y deja que el agente pode a mano lo que
quiera con la herramienta context_prune.
ANTES DESPUES
read(a.ts) 3.000 tok read(a.ts) 3.000 tok <- la ultima
edit(a.ts) 2.000 tok edit(a.ts) 2.000 tok
read(a.ts) 3.000 tok ─────► read(a.ts) [ACP pruned read() output: ...]
read(a.ts) 3.000 tok read(a.ts) [ACP pruned read() output: ...]
bash(ls) 1.000 tok bash(ls) 1.000 tok
Cero dependencias npm. Solo node:crypto, node:fs, node:path y la API del host.
- Poda automatica en cada peticion al modelo, antes de enviarla.
- Hash visible en cada salida de herramienta (
<tool_hash>a1b2c3</tool_hash>) para que el agente pueda referenciarla. - Herramienta
context_prunecon accioneslist,discard,distill,replace,statsyreset. - Comando
/acpcon el estado actual (podado, tokens liberados, presion de contexto). - Estadisticas persistentes por sesion y acumuladas, guardadas con
ctx.storage.
Nada de esto modifica tu historial guardado: el pase reescribe solo la copia que se envia al modelo. Si recargas la sesion, el historial original sigue intacto.
- OpenCode V2 (
opencode v2.1.4o superior). - Node 20+ (el que trae OpenCode sirve).
- Ninguna clave de API ni modelo especial.
# desde la carpeta descomprimida
powershell -ExecutionPolicy Bypass -File .\install.ps1Copia el plugin a %USERPROFILE%\.config\opencode\plugins\acp-v2 y ejecuta las pruebas.
Reinicia OpenCode (o abre una sesion nueva) y lista:
opencode plugin listCopia la carpeta completa a:
C:\Users\<tu-usuario>\.config\opencode\plugins\acp-v2\
index.js
package.json
lib\config.js
lib\prune.js
lib\registry.js
lib\tool.js
lib\util.js
OpenCode descubre solo los directorios de ~/.config/opencode/plugins/. No hace falta
tocar opencode.json.
El plugin expone id: "mente.acp-v2" y setup(ctx), que es lo que V2 exige.
Select-String -Path "$env:USERPROFILE\.local\share\opencode\log\opencode.log" `
-Pattern 'acp-v2|failed to load plugin' | Select-Object -Last 5Debe aparecer loading plugin ... \plugins\acp-v2 y ningun failed to load plugin.
Precedencia, de menor a mayor:
- Valores por defecto del plugin.
~/.config/opencode/acp.jsonc(global).<proyecto>/.opencode/acp.jsonc(por proyecto).optionsdel plugin enopencode.json(c).
Copia acp.jsonc como plantilla. Todo es opcional: sin archivo funciona
con el preset balanced.
| Clave | Default | Que hace |
|---|---|---|
enabled |
true |
Apaga el plugin por completo. |
debug |
false |
Logs [acp] en el log de OpenCode. |
visibleHashes |
true |
Anade <tool_hash> a cada salida. |
preset |
"balanced" |
compact, balanced o verbose. |
protectedTools |
ver abajo | Nunca se podan automaticamente. |
protectedFilePatterns |
.env, *.pem, ... |
Archivos que no se podan. |
strategies.* |
ver abajo | Activa o desactiva cada estrategia. |
protection.recentTurns |
2 |
Turnos recientes intactos. |
protection.keepLastResults |
4 |
Ultimas N salidas siempre intactas. |
tokens.warningThreshold |
0.7 |
Aviso de presion alta. |
tokens.criticalThreshold |
0.85 |
Aviso de presion critica. |
Los presets ajustan protection y strategies de golpe:
- compact — poda agresiva (
recentTurns: 1,keepLastResults: 2, purga errores viejos). - balanced — el equilibrio por defecto.
- verbose — no poda nada automatico; solo deja
context_prunemanual.
Se aplican en cada peticion. De cada grupo sobrevive la ultima llamada.
| # | Estrategia | Clave | Que elimina |
|---|---|---|---|
| 1 | Llamadas identicas | identicalCalls |
Repeticiones con los mismos argumentos. |
| 2 | Un archivo, una vista | oneFileOneView |
Lecturas/ediciones anteriores del mismo archivo. |
| 3 | Consultas de estado | stateQueries |
ls, pwd, git status, grep... ya superados. |
| 4 | URLs repetidas | sourceUrls |
La misma URL consultada antes. |
| 5 | Tareas | todos |
Estados de todo-list ya reemplazados. |
| 6 | Snapshots | snapshots |
Checkpoints/reverts superados. |
| 7 | Reintentos | retryAttempts |
El error de un intento que luego funciono. |
| 8 | Entradas verbosas | pruneToolInputs |
content/patch/diff gigantes en los argumentos. |
Extras opcionales:
truncateOldErrors/purgeErrors— poda errores antiguos que nadie resolvio.
Protecciones (nunca se tocan automaticamente):
- Turnos recientes (
recentTurns) y las ultimas N salidas (keepLastResults). - Herramientas de
protectedTools:context_prune,task,todowrite,todoread,todo,batch,write,edit,apply_patch. - Archivos de
protectedFilePatterns: secretos,.env,*.pem,*.key,package.json,tsconfig.json,pyproject.toml,Cargo.toml.
Que
write/editesten protegidos no es un capricho: son el registro de lo que el agente ya cambio. Podarlos invita a repetir trabajo.
Cada salida lleva su hash al final:
<tool_hash>a1b2c3</tool_hash>
| Accion | targets |
Efecto |
|---|---|---|
list |
— | Salidas podables: hash, herramienta, tokens, primera linea. |
discard |
[["a1b2c3"]] |
Reemplaza la salida por un stub. |
distill |
[["a1b2c3","resumen"]] |
La reemplaza por tu resumen. |
replace |
[["inicio","fin","[podado]"]] |
Reemplazo literal de un bloque. |
stats |
— | Sesion, historico y presion de contexto. |
reset |
— | Olvida las podas manuales pendientes. |
Reglas de replace, heredadas del original:
- El bloque debe medir 30 caracteres o mas.
- Al menos uno de los dos extremos debe medir mas de 15 caracteres.
- El marcador de inicio debe aparecer una sola vez.
- Se aplica una unica vez y se descarta.
Las podas manuales se aplican en la siguiente peticion; la herramienta solo las deja en cola. Tambien puedes podar herramientas protegidas a mano (forzado), porque tu decides.
ACP — podado de contexto
Sesion: 4 salidas podadas, ~12.400 tokens liberados
Historico: 30 salidas, ~273.760 tokens
Presion: 17% de 200k tokens (312 salidas)
Se inyecta como mensaje sintetico, no ocupa turno de usuario.
Se calcula sobre toda la conversacion (texto, argumentos y salidas), no solo sobre las salidas de herramientas:
presion = tokens_estimados / ventana_del_modelo
La ventana se lee de ctx.model.list() (cacheada 60 s). Si el modelo no la declara, se
usa 200.000 tokens. La estimacion es caracteres / 4, suficiente para decidir cuando
podar; no pretende ser exacta.
El comportamiento y las reglas se conservan. Lo que cambia es la integracion:
| Aspecto | Original (V1) | Este port (V2) |
|---|---|---|
| Punto de entrada | default async (ctx) => ({hooks}) |
{ id, setup(ctx) } |
| Poda antes del request | experimental.chat.messages.transform |
ctx.session.hook("context") |
| Hash en salidas | chat.message + partes sinteticas |
ctx.tool.hook("execute.after") |
| Herramienta | tool en el objeto de hooks |
ctx.tool.transform |
Comando /acp |
command.execute.before |
ctx.command.transform |
| Estado persistente | archivo propio | ctx.storage |
| Dependencias | zod, jsonc-parser, @anthropic-ai/tokenizer, SDK V1 |
ninguna |
| Compactacion nativa | la desactivaba desde un hook config |
no puede: V2 no expone mutacion de config |
| Poda de bloques de razonamiento | si (hash de reasoning) |
no: V2 no expone esas partes al hook |
Herramienta sintetica context_info |
si (DeepSeek/Kimi) | no: V2 ya inyecta el contexto del sistema |
Consecuencia practica de las dos ultimas filas: en V2 la compactacion nativa sigue activa
y puede resumir la conversacion antes de que el plugin pode. No es un conflicto —la
compactacion es un resumen de ultimo recurso y el plugin evita llegar a ella— pero si
quieres que el plugin tenga la primera y la ultima palabra, sube compaction en
opencode.jsonc:
{
"compaction": {
"auto": true,
"keep": { "tokens": 15000 }
}
}El tokenizador tambien es distinto: el original usaba @anthropic-ai/tokenizer; aqui se
estima con caracteres / 4. Para decidir que podar es mas que suficiente y no arrastra
una dependencia.
- Solo afecta al request saliente. El historial en disco no se toca; al recargar la sesion vuelven las salidas completas.
- Estimacion de tokens heuristica. No es el conteo exacto del proveedor.
- No poda razonamiento. V2 no expone los bloques de
reasoningen el hook de contexto. - No desactiva la compactacion nativa. V2 no permite mutar la config desde un plugin.
- Estado en memoria. Las podas pendientes se pierden si reinicias OpenCode; lo ya aplicado al request tampoco se guarda (por diseno).
- Un archivo por grupo. Si el agente alterna
read(a)→read(b)→read(a), la segunda lectura dease conserva y la primera se poda: siempre gana la ultima. - El hash cambia si cambia la salida. Es el hash de
nombre + argumentos + resultado, asi que la misma llamada con otra salida da otro hash. Es intencional: identifica la salida concreta.
cd acp-v2
node --test "test/*.test.js"22 pruebas: utilidades (hash estable, stubs, globs), configuracion (JSONC, precedencia,
presets) y nucleo (deduplicacion, protecciones, reintentos, discard, distill,
replace, stats, integridad del par tool-call/tool-result).
acp-v2/
├── index.js entrada: setup, hooks, comando, cleanup
├── lib/
│ ├── config.js defaults, presets, JSONC, precedencia
│ ├── prune.js nucleo: 8 estrategias + poda manual
│ ├── registry.js estado por sesion + persistencia
│ ├── tool.js herramienta context_prune
│ └── util.js hash, tokens, globs, stubs
├── test/ 22 pruebas con node:test
├── acp.jsonc config de ejemplo comentada
├── install.ps1 instalador para Windows
├── LICENSE.txt licencia MIT
└── package.json
Esto no es un proyecto oficial. No esta afiliado ni respaldado por el autor original.
Agentic Context Pruning (ACP) — de tuanhung303:
- Repositorio: https://github.com/tuanhung303/opencode-agent-context-pruning
- Paquete npm:
@tuanhung303/opencode-acpv3.0.15 - Licencia: MIT,
Copyright (c) 2025 opencode-acp
De ahi salieron el diseno, las estrategias, las reglas y los valores por defecto. El port
se hizo leyendo el paquete publicado (su dist/, su README y sus documentos de estrategias
y API), no adivinando.
| Del original (MIT, tuanhung303) | Nuevo en este port (Dynerdc) |
|---|---|
| Las 8 estrategias de poda y sus reglas | setup(ctx) y todo el cableado de V2 |
La herramienta context_prune y su semantica |
Registro via ctx.tool.transform |
| Herramientas y archivos protegidos por defecto | Comando /acp con ctx.session.synthetic |
| Umbrales, presets y formato de hash | Estado con ctx.storage, sin dependencias |
| La idea de deduplicar contexto | Medida de presion sobre toda la conversacion |
MIT, la misma del original. El aviso de copyright de tuanhung303 se conserva en
LICENSE.txt, que es exactamente lo que la licencia MIT exige al
distribuir una obra derivada. Puedes usar, copiar, modificar y redistribuir este port
siempre que mantengas ese aviso.
Copyright (c) 2025 opencode-acp (tuanhung303) - ACP original
Copyright (c) 2026 Dynerdc - port a OpenCode V2
El package.json lleva "private": true a proposito: evita publicar el port en npm por
accidente bajo otro nombre. Para distribuirlo, usa el repositorio o el .zip.