xonecode 0.8.46 → 0.9.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.
- package/apps/web/dist/assets/{index-_cBVqq54.css → index-CtfT1BjI.css} +1 -1
- package/apps/web/dist/assets/{index-GRwyotMV.js → index-DqcZ7_Rx.js} +65 -65
- package/apps/web/dist/assets/{php-Bx1jVads.js → php-DjRQ1K-w.js} +1 -1
- package/apps/web/dist/assets/{ruby-L0I9KR6K.js → ruby-BcLyZ3qi.js} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/dist/agent/grafo/arbolDeProyecto.js +1 -1
- package/dist/agent/grafo/arbolDeProyecto.js.map +1 -1
- package/dist/agent/grafo/opcionesDeFicheros.js +24 -0
- package/dist/agent/grafo/opcionesDeFicheros.js.map +1 -0
- package/dist/agent/grafo/perfiles.js +1 -1
- package/dist/agent/grafo/perfiles.js.map +1 -1
- package/dist/agent/grafo/xoneAgent.js +49 -51
- package/dist/agent/grafo/xoneAgent.js.map +1 -1
- package/dist/agent/motores/trueforge/capacidades.js +138 -0
- package/dist/agent/motores/trueforge/capacidades.js.map +1 -0
- package/dist/agent/motores/trueforge/eventosTrueforge.js +98 -0
- package/dist/agent/motores/trueforge/eventosTrueforge.js.map +1 -0
- package/dist/agent/motores/trueforge/memoriaTrueforge.js +336 -0
- package/dist/agent/motores/trueforge/memoriaTrueforge.js.map +1 -0
- package/dist/agent/motores/trueforge/metricasTrueforge.js +55 -0
- package/dist/agent/motores/trueforge/metricasTrueforge.js.map +1 -0
- package/dist/agent/motores/trueforge/modeloExterno.js +46 -0
- package/dist/agent/motores/trueforge/modeloExterno.js.map +1 -0
- package/dist/agent/motores/trueforge/modeloLangchain.js +149 -0
- package/dist/agent/motores/trueforge/modeloLangchain.js.map +1 -0
- package/dist/agent/motores/trueforge/recortes.js +121 -0
- package/dist/agent/motores/trueforge/recortes.js.map +1 -0
- package/dist/agent/motores/trueforge/sesionTrueforge.js +1045 -0
- package/dist/agent/motores/trueforge/sesionTrueforge.js.map +1 -0
- package/dist/agent/motores/trueforge/skillsTrueforge.js +14 -0
- package/dist/agent/motores/trueforge/skillsTrueforge.js.map +1 -0
- package/dist/agent/motores/trueforge/toolsDeFichero.js +264 -0
- package/dist/agent/motores/trueforge/toolsDeFichero.js.map +1 -0
- package/dist/agent/motores/trueforge/toolsPropias.js +65 -0
- package/dist/agent/motores/trueforge/toolsPropias.js.map +1 -0
- package/dist/agent/motores/trueforge/trueforge.js +45 -0
- package/dist/agent/motores/trueforge/trueforge.js.map +1 -0
- package/dist/agent/sesiones/memoriaDeHilo.js +24 -0
- package/dist/agent/sesiones/memoriaDeHilo.js.map +1 -0
- package/dist/agent/subagentes/actividadDeCodex.js +60 -0
- package/dist/agent/subagentes/actividadDeCodex.js.map +1 -0
- package/dist/agent/subagentes/escrituraExterna.js +2 -0
- package/dist/agent/subagentes/escrituraExterna.js.map +1 -1
- package/dist/agent/subagentes/subagenteCodex.js +20 -0
- package/dist/agent/subagentes/subagenteCodex.js.map +1 -1
- package/dist/agent/subagentes/subagenteExterno.js +269 -202
- package/dist/agent/subagentes/subagenteExterno.js.map +1 -1
- package/dist/agent/subagentes/subagenteOpencode.js +18 -1
- package/dist/agent/subagentes/subagenteOpencode.js.map +1 -1
- package/dist/agent/turno/diagnosticoDeTools.js +3 -0
- package/dist/agent/turno/diagnosticoDeTools.js.map +1 -1
- package/dist/agent/turno/ficherosDelProyecto.js +62 -0
- package/dist/agent/turno/ficherosDelProyecto.js.map +1 -0
- package/dist/agent/turno/informeDeTraza.js +28 -1
- package/dist/agent/turno/informeDeTraza.js.map +1 -1
- package/dist/agent/turno/resumenDeTool.js +3 -0
- package/dist/agent/turno/resumenDeTool.js.map +1 -1
- package/dist/agent/turno/sesionReal.js +2 -0
- package/dist/agent/turno/sesionReal.js.map +1 -0
- package/dist/agent/turno/turnoReal.js +40 -163
- package/dist/agent/turno/turnoReal.js.map +1 -1
- package/dist/agent/turno/verificacion.js +142 -0
- package/dist/agent/turno/verificacion.js.map +1 -0
- package/dist/cli/config.js +19 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/consola.js.map +1 -1
- package/dist/cli/main.js +35 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/tui/correrTui.js +1 -1
- package/dist/cli/tui/correrTui.js.map +1 -1
- package/dist/cli/tui/transcript.js +5 -0
- package/dist/cli/tui/transcript.js.map +1 -1
- package/dist/core/actos.js.map +1 -1
- package/dist/core/config.js +13 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/motor.js +41 -0
- package/dist/core/motor.js.map +1 -0
- package/dist/core/ports.js.map +1 -1
- package/dist/core/trazaDeErrores.js +8 -2
- package/dist/core/trazaDeErrores.js.map +1 -1
- package/dist/core/turno.js +10 -0
- package/dist/core/turno.js.map +1 -1
- package/dist/web/servidor/arranque.js +7 -4
- package/dist/web/servidor/arranque.js.map +1 -1
- package/dist/web/servidor/pielWeb.js +6 -0
- package/dist/web/servidor/pielWeb.js.map +1 -1
- package/dist/web/servidor/sesiones.js +11 -0
- package/dist/web/servidor/sesiones.js.map +1 -1
- package/dist/web/servidor/vestibulo.js +23 -2
- package/dist/web/servidor/vestibulo.js.map +1 -1
- package/package.json +7 -2
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lo que deepagents RECORTA de un resultado de tool antes de meterlo en el contexto, en TrueForge.
|
|
3
|
+
*
|
|
4
|
+
* Medido en una sesión real de MyAllXOne con la MISMA petición («lanza la app en el emulador»):
|
|
5
|
+
* TrueForge gastó 510k de entrada y deepagents 227k, con un número de tools parecido. La diferencia
|
|
6
|
+
* no estaba en el motor sino en lo que cada resultado DEJABA en el contexto: el `FilesystemMiddleware`
|
|
7
|
+
* de deepagents hace tres cosas que el adaptador de TrueForge no hacía, y un resultado que entra
|
|
8
|
+
* entero se vuelve a mandar en CADA llamada siguiente de ese hilo.
|
|
9
|
+
*
|
|
10
|
+
* 1. **Desaloja** lo que pasa de `toolTokenLimitBeforeEvict` tokens (a 4 caracteres por token) en
|
|
11
|
+
* `execute` y en las tools que no son de fichero: lo escribe en `/large_tool_results/` y al
|
|
12
|
+
* modelo le llega la ruta y un extracto de cabeza y cola. Las de fichero no se desalojan —ya
|
|
13
|
+
* paginan—, igual que en la librería.
|
|
14
|
+
* 2. **Trunca** `ls`, `glob` y `grep` por encima de 80.000 caracteres.
|
|
15
|
+
* 3. **Topa** `grep` en `grepMaxCount` coincidencias.
|
|
16
|
+
*
|
|
17
|
+
* Los VALORES son los nuestros de deepagents (`OPCIONES_BUSQUEDA_FICHEROS`), no una copia: dos
|
|
18
|
+
* motores con dos umbrales serían dos gastos que no se pueden comparar.
|
|
19
|
+
*/
|
|
20
|
+
import { OPCIONES_BUSQUEDA_FICHEROS } from "../../grafo/opcionesDeFicheros.js";
|
|
21
|
+
/** Por encima de esto `ls`/`glob`/`grep` se truncan (el `truncateIfTooLong` de deepagents). */
|
|
22
|
+
export const CARACTERES_ANTES_DE_TRUNCAR = 80_000;
|
|
23
|
+
/** Lo que se conserva al truncar: 20.000 tokens a 4 caracteres, como la librería. */
|
|
24
|
+
const CARACTERES_TRAS_TRUNCAR = 20_000 * 4;
|
|
25
|
+
export const AVISO_DE_TRUNCADO = "\n... [resultados truncados: afina el patrón o la ruta]";
|
|
26
|
+
/** Por encima de esto un resultado de `execute` o de una tool propia se desaloja del contexto. */
|
|
27
|
+
export const CARACTERES_ANTES_DE_DESALOJAR = OPCIONES_BUSQUEDA_FICHEROS.toolTokenLimitBeforeEvict * 4;
|
|
28
|
+
export const MAXIMO_DE_COINCIDENCIAS = OPCIONES_BUSQUEDA_FICHEROS.grepMaxCount;
|
|
29
|
+
export function truncarSiLargo(texto) {
|
|
30
|
+
return texto.length > CARACTERES_ANTES_DE_TRUNCAR ? texto.slice(0, CARACTERES_TRAS_TRUNCAR) + AVISO_DE_TRUNCADO : texto;
|
|
31
|
+
}
|
|
32
|
+
const numerar = (lineas, desde) => lineas.map((l, i) => `${String(desde + i).padStart(6)}\t${l.slice(0, 1000)}`).join("\n");
|
|
33
|
+
/** Cabeza y cola numeradas, con cuántas líneas se saltan en medio (`createContentPreview`). */
|
|
34
|
+
export function vistaPrevia(texto, cabeza = 5, cola = 5) {
|
|
35
|
+
const lineas = texto.split("\n");
|
|
36
|
+
if (lineas.length <= cabeza + cola)
|
|
37
|
+
return numerar(lineas, 1);
|
|
38
|
+
return [
|
|
39
|
+
numerar(lineas.slice(0, cabeza), 1),
|
|
40
|
+
`... [${lineas.length - cabeza - cola} líneas omitidas] ...`,
|
|
41
|
+
numerar(lineas.slice(-cola), lineas.length - cola + 1),
|
|
42
|
+
].join("\n");
|
|
43
|
+
}
|
|
44
|
+
let secuencia = 0;
|
|
45
|
+
/**
|
|
46
|
+
* El texto que VE el modelo: el mismo si cabe, o la ruta donde quedó y un extracto si no. Si no
|
|
47
|
+
* se puede guardar —sin carpeta de artefactos no hay dónde colgar `/large_tool_results/`, y la
|
|
48
|
+
* guarda del proyecto lo rechaza, como debe— se dice y va el extracto igual: meter el resultado
|
|
49
|
+
* entero es justo lo que esto evita.
|
|
50
|
+
*/
|
|
51
|
+
export async function desalojarSiGrande(texto, backend, forzar = false) {
|
|
52
|
+
if (!forzar && texto.length <= CARACTERES_ANTES_DE_DESALOJAR)
|
|
53
|
+
return texto;
|
|
54
|
+
const ruta = `/large_tool_results/tf-${Date.now()}-${++secuencia}.txt`;
|
|
55
|
+
let error;
|
|
56
|
+
try {
|
|
57
|
+
const r = (await backend.write(ruta, texto));
|
|
58
|
+
error = r?.error;
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
error = e instanceof Error ? e.message : String(e);
|
|
62
|
+
}
|
|
63
|
+
const extracto = vistaPrevia(texto);
|
|
64
|
+
if (error !== undefined) {
|
|
65
|
+
return `Resultado demasiado grande (${texto.length} caracteres) y no se pudo guardar aparte (${error}). Extracto:\n\n${extracto}`;
|
|
66
|
+
}
|
|
67
|
+
return (`Resultado demasiado grande (${texto.length} caracteres): se guardó en ${ruta}. Léelo con read_file por ` +
|
|
68
|
+
`partes (offset y limit), no entero. Extracto de cabeza y cola:\n\n${extracto}`);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* **El presupuesto de un PASO**, que el recorte de arriba no ve: cada resultado se mira solo, así
|
|
72
|
+
* que cinco `execute` en paralelo de 20.000 caracteres pasan uno a uno y juntos meten 100.000 en
|
|
73
|
+
* el contexto. Es la regla del `largeToolResponse` de TrueForge, con su umbral (10.000 tokens),
|
|
74
|
+
* portada y no montada: con los dos puestos la misma salida se procesaría dos veces.
|
|
75
|
+
*/
|
|
76
|
+
export const CARACTERES_DEL_PASO = 10_000 * 4;
|
|
77
|
+
/** Un error que haya que recortar se TRUNCA a esto en vez de desalojarse: ahí no hay nada que releer. */
|
|
78
|
+
export const CARACTERES_DE_UN_ERROR = 500;
|
|
79
|
+
const textoDelResultado = (r) => typeof r.message.content === "string" ? r.message.content : JSON.stringify(r.message.content ?? "");
|
|
80
|
+
function recortarError(r, texto) {
|
|
81
|
+
if (texto.length <= CARACTERES_DE_UN_ERROR)
|
|
82
|
+
return;
|
|
83
|
+
r.message.content = `${texto.slice(0, CARACTERES_DE_UN_ERROR)}\n... [error truncado: ${texto.length} caracteres]`;
|
|
84
|
+
r.isStructuredContent = false;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Los resultados de UN paso, dentro del presupuesto: un error ENORME se trunca, y mientras el
|
|
88
|
+
* total se pase se desalojan los mayores primero. Modifica los resultados, que es el contrato del
|
|
89
|
+
* procesador de la librería; no quita ninguno (la librería lanza si falta uno).
|
|
90
|
+
*/
|
|
91
|
+
export async function recortarPaso(resultados, backend) {
|
|
92
|
+
for (const r of resultados) {
|
|
93
|
+
const texto = textoDelResultado(r);
|
|
94
|
+
if (r.failure && texto.length > CARACTERES_ANTES_DE_DESALOJAR)
|
|
95
|
+
recortarError(r, texto);
|
|
96
|
+
}
|
|
97
|
+
let total = resultados.reduce((suma, r) => suma + textoDelResultado(r).length, 0);
|
|
98
|
+
const porTamano = [...resultados].sort((a, b) => textoDelResultado(b).length - textoDelResultado(a).length);
|
|
99
|
+
for (const r of porTamano) {
|
|
100
|
+
if (total <= CARACTERES_DEL_PASO)
|
|
101
|
+
break;
|
|
102
|
+
const antes = textoDelResultado(r);
|
|
103
|
+
if (r.failure)
|
|
104
|
+
recortarError(r, antes);
|
|
105
|
+
else {
|
|
106
|
+
r.message.content = await desalojarSiGrande(antes, backend, true);
|
|
107
|
+
r.isStructuredContent = false;
|
|
108
|
+
}
|
|
109
|
+
total -= antes.length - textoDelResultado(r).length;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** El procesador que TrueForge llama con todos los resultados de un paso. */
|
|
113
|
+
export function presupuestoDelPaso(backend) {
|
|
114
|
+
return {
|
|
115
|
+
process: async (resultados) => {
|
|
116
|
+
await recortarPaso(resultados, backend);
|
|
117
|
+
return {};
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=recortes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recortes.js","sourceRoot":"","sources":["../../../../src/agent/motores/trueforge/recortes.ts"],"names":[],"mappings":"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"}
|