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,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* La memoria de una conversación de TrueForge, en disco: la FOTO del hilo raíz.
|
|
3
|
+
*
|
|
4
|
+
* Sin esto el árbol de hilos vivía en memoria y reabrir una sesión de este motor empezaba de
|
|
5
|
+
* cero, con la interfaz enseñando la conversación de antes como si el modelo la recordara.
|
|
6
|
+
*
|
|
7
|
+
* **Es la foto del RAÍZ, no la capa `agent-session` de TrueForge, y es a propósito.** Esa capa
|
|
8
|
+
* trae su propio registro de sesiones, turnos y eventos —un segundo índice al lado del nuestro,
|
|
9
|
+
* con su propio «de quién es esto»— y su factoría de subagentes SUSTITUYE el primer mensaje del
|
|
10
|
+
* hijo por el encargo pelado. Lo que hace falta para «reabrir continúa» es menos:
|
|
11
|
+
* `AgentThread.toSnapshot()` y su constructor, que aceptan el contexto de vuelta. Los hijos mueren
|
|
12
|
+
* con su turno por diseño, así que no hay nada suyo que guardar.
|
|
13
|
+
*
|
|
14
|
+
* Tres reglas, las mismas que el checkpoint de deepagents:
|
|
15
|
+
* - **Modo 0600 ANTES de tener contenido**: la foto lleva los mensajes enteros —contenido de
|
|
16
|
+
* ficheros incluido—, igual que `checkpoint.sqlite`.
|
|
17
|
+
* - **Vive en la carpeta de la sesión**, dentro de `.xonecode/`, que no entra en git ni sube.
|
|
18
|
+
* - **Una tool call sin respuesta se SALDA al guardar** (`saldarColgadas`), con una respuesta
|
|
19
|
+
* que dice la verdad: al modelo le llegaría un mensaje con tool calls sin su respuesta detrás, y
|
|
20
|
+
* Gemini y OpenAI contestan 400. El `OpenToolCallCloser` de TrueForge no cubre este caso:
|
|
21
|
+
* se salta a propósito las que crean un hilo (`create_sub_agent`), que es justo la que queda
|
|
22
|
+
* colgada cuando un turno se corta con un hijo esperando aprobación.
|
|
23
|
+
*
|
|
24
|
+
* **Y la foto lleva VERSIÓN, y se lee de forma ESTRICTA** (`interpretarFoto`). Es un fichero que
|
|
25
|
+
* sobrevive a las subidas de XOneCode y de la librería —que es 0.x y no promete nada entre
|
|
26
|
+
* versiones—, así que lo que no se entiende no se carga a medias: un contexto a medio entender
|
|
27
|
+
* es una conversación que el modelo cree recordar y no recuerda. Fail-closed hacia el lado que
|
|
28
|
+
* NO destruye: una foto que no se entiende no tumba la sesión, se abre SIN memoria y se DICE
|
|
29
|
+
* (`textoDeMemoriaDescartada`), y la foto se APARTA con otro nombre (`apartarMemoria`) en vez de
|
|
30
|
+
* borrarse — o el primer guardado del turno siguiente la pisaría.
|
|
31
|
+
*/
|
|
32
|
+
import { chmodSync, existsSync, mkdirSync, openSync, closeSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
33
|
+
import { basename, dirname, join } from "node:path";
|
|
34
|
+
import { VERSION_DE_TRUEFORGE } from "./trueforge.js";
|
|
35
|
+
/** Un id de sesión que se puede usar como nombre de carpeta: segmento llano y nada más. */
|
|
36
|
+
const ID_VALIDO = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
|
|
37
|
+
/** Dónde vive la memoria de la sesión `hilo`, o `undefined` si el id no es un segmento llano. */
|
|
38
|
+
export function rutaDeMemoria(raiz, hilo) {
|
|
39
|
+
if (!ID_VALIDO.test(hilo))
|
|
40
|
+
return undefined;
|
|
41
|
+
return join(raiz, ".xonecode", "sesiones", hilo, "memoria-trueforge.json");
|
|
42
|
+
}
|
|
43
|
+
/** El texto con que se salda una tool call que el turno no llegó a contestar. */
|
|
44
|
+
export const RESPUESTA_A_UNA_COLGADA = "No se completó: el turno se cortó antes (quedó sin aprobar, se canceló o se agotó el tope). " +
|
|
45
|
+
"Si sigue haciendo falta, vuelve a pedirlo.";
|
|
46
|
+
/**
|
|
47
|
+
* El contexto con las tool calls del ÚLTIMO mensaje del asistente que no tienen respuesta,
|
|
48
|
+
* saldadas. Solo el último: una anterior sin respuesta ya habría roto la conversación antes.
|
|
49
|
+
* Puro: no toca el contexto que recibe.
|
|
50
|
+
*/
|
|
51
|
+
export function saldarColgadas(context, excepto) {
|
|
52
|
+
const mensajes = context;
|
|
53
|
+
let ultimo = -1;
|
|
54
|
+
for (let i = mensajes.length - 1; i >= 0; i -= 1) {
|
|
55
|
+
const m = mensajes[i];
|
|
56
|
+
if (m?.role === "assistant" && (m.tool_calls?.length ?? 0) > 0) {
|
|
57
|
+
ultimo = i;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (ultimo === -1)
|
|
62
|
+
return [...context];
|
|
63
|
+
const pedidas = new Set((mensajes[ultimo].tool_calls ?? []).map((t) => t.id).filter((id) => typeof id === "string"));
|
|
64
|
+
for (const m of mensajes.slice(ultimo + 1))
|
|
65
|
+
if (m?.role === "tool" && m.tool_call_id !== undefined)
|
|
66
|
+
pedidas.delete(m.tool_call_id);
|
|
67
|
+
// La que espera la respuesta de la persona no está colgada: está esperando, y saldarla la mataría.
|
|
68
|
+
if (excepto !== undefined)
|
|
69
|
+
pedidas.delete(excepto);
|
|
70
|
+
return [...context, ...[...pedidas].map((id) => ({ role: "tool", tool_call_id: id, content: RESPUESTA_A_UNA_COLGADA }))];
|
|
71
|
+
}
|
|
72
|
+
/** La foto lista para guardar o para rehacer el hilo: con las colgadas saldadas. */
|
|
73
|
+
export function fotoSaneada(foto) {
|
|
74
|
+
const pregunta = foto.pregunta_pendiente;
|
|
75
|
+
return { ...foto, context: saldarColgadas(foto.context, pregunta?.id) };
|
|
76
|
+
}
|
|
77
|
+
// ── La versión del FORMATO, y cómo se llega a ella ────────────────────────────────────────────
|
|
78
|
+
/**
|
|
79
|
+
* La versión del formato de la foto en disco. Sube cuando cambia lo que se escribe, y cada subida
|
|
80
|
+
* trae su entrada en `MIGRACIONES`: una foto de antes se MIGRA al leerla, nunca se descarta por
|
|
81
|
+
* vieja. Es NUESTRA, no la de la librería: la de la librería va aparte, en `trueforge`.
|
|
82
|
+
*
|
|
83
|
+
* El formato v1, entero —y nada más, que es lo que hace estricta la lectura—:
|
|
84
|
+
*
|
|
85
|
+
* ```json
|
|
86
|
+
* { "version": 1, "trueforge": "0.2.1", "context": [...],
|
|
87
|
+
* "current_context_usage": {...}, "capability_state": {...} | null,
|
|
88
|
+
* "pregunta_pendiente": { "hilo": "...", "id": "...", "args": {...}, "encargo"?: "..." } }
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* Solo `version` y `context` son obligatorios. `trueforge` es la versión de la librería que
|
|
92
|
+
* escribió el `toSnapshot()`: se APUNTA, no se exige —rechazar por ella tiraría todas las
|
|
93
|
+
* conversaciones en cada subida de la librería—, y está para que una migración futura sepa de
|
|
94
|
+
* dónde parte. Falta en una foto MIGRADA desde v0, porque no se inventa lo que no consta; el
|
|
95
|
+
* guardado siguiente la sella.
|
|
96
|
+
*/
|
|
97
|
+
export const VERSION_DE_MEMORIA = 1;
|
|
98
|
+
/**
|
|
99
|
+
* De cada versión a la SIGUIENTE: devuelve la foto migrada o el MOTIVO por el que no se puede.
|
|
100
|
+
* Puras, y se encadenan (`interpretarFoto`), así que una foto de hace tres versiones pasa por
|
|
101
|
+
* las tres. Una migración no valida el resultado final: eso lo hace UNA vez `validarV1`.
|
|
102
|
+
*/
|
|
103
|
+
export const MIGRACIONES = {
|
|
104
|
+
/**
|
|
105
|
+
* v0 → v1. La v0 es la foto de antes de versionar: `toSnapshot()` del raíz tal cual, más
|
|
106
|
+
* `pregunta_pendiente`. Traía cuatro campos que el constructor del raíz no recibe de vuelta
|
|
107
|
+
* (`thread_id`, `parent`, `agent_info`, `completion`) y aquí se retiran — pero solo con el valor
|
|
108
|
+
* que tiene un RAÍZ: un `parent` o una `completion` puestos serían la foto de un hijo, y
|
|
109
|
+
* retirarlos en silencio sería cargarla a medias.
|
|
110
|
+
*/
|
|
111
|
+
0: (foto) => {
|
|
112
|
+
const { thread_id, parent, agent_info, completion, ...resto } = foto;
|
|
113
|
+
if (thread_id !== undefined && typeof thread_id !== "string")
|
|
114
|
+
return "la foto sin versión trae un `thread_id` que no es texto";
|
|
115
|
+
for (const [campo, valor] of [
|
|
116
|
+
["parent", parent],
|
|
117
|
+
["agent_info", agent_info],
|
|
118
|
+
["completion", completion],
|
|
119
|
+
]) {
|
|
120
|
+
if (valor !== undefined && valor !== null)
|
|
121
|
+
return `la foto sin versión trae \`${campo}\`: no es la de un hilo raíz`;
|
|
122
|
+
}
|
|
123
|
+
return { ...resto, version: 1 };
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
const esObjeto = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
127
|
+
/** Un nombre de campo que sale del FICHERO, recortado: el motivo viaja a la pantalla. */
|
|
128
|
+
const nombreDeCampo = (k) => (k.length > 40 ? `${k.slice(0, 40)}…` : k);
|
|
129
|
+
const CAMPOS_V1 = new Set(["version", "trueforge", "context", "current_context_usage", "capability_state", "pregunta_pendiente"]);
|
|
130
|
+
/**
|
|
131
|
+
* La foto v1, comprobada campo a campo, o el motivo. **Un campo que no se conoce es un NO**, no
|
|
132
|
+
* un campo que se ignora: la v1 la escribe `guardarMemoria` con una lista cerrada, así que uno de
|
|
133
|
+
* más significa que no la escribió este código. Y **un campo conocido y mal formado se lleva la
|
|
134
|
+
* foto ENTERA**: soltar solo la pregunta pendiente, por ejemplo, dejaría una conversación que
|
|
135
|
+
* espera una respuesta que ya nadie sabe a qué va.
|
|
136
|
+
*
|
|
137
|
+
* **Límite declarado**: de cada mensaje del contexto se mira que sea un objeto con `role` o `type`
|
|
138
|
+
* de texto, y no más. Su esquema entero es de la librería (zod, dentro de ella), y repetirlo aquí
|
|
139
|
+
* sería un segundo sitio donde decidir qué es un mensaje.
|
|
140
|
+
*/
|
|
141
|
+
function validarV1(foto) {
|
|
142
|
+
for (const k of Object.keys(foto))
|
|
143
|
+
if (!CAMPOS_V1.has(k))
|
|
144
|
+
return `campo desconocido «${nombreDeCampo(k)}»`;
|
|
145
|
+
if (foto.version !== 1)
|
|
146
|
+
return "la migración no dejó la versión 1";
|
|
147
|
+
if (foto.trueforge !== undefined && typeof foto.trueforge !== "string")
|
|
148
|
+
return "`trueforge` no es texto";
|
|
149
|
+
const { context, current_context_usage, capability_state, pregunta_pendiente } = foto;
|
|
150
|
+
if (!Array.isArray(context))
|
|
151
|
+
return "falta el contexto, o no es una lista";
|
|
152
|
+
const roto = context.findIndex((m) => !esObjeto(m) || (typeof m.role !== "string" && typeof m.type !== "string"));
|
|
153
|
+
if (roto !== -1)
|
|
154
|
+
return `el mensaje ${roto} del contexto no tiene forma de mensaje`;
|
|
155
|
+
if (current_context_usage !== undefined && !esObjeto(current_context_usage))
|
|
156
|
+
return "`current_context_usage` no es un objeto";
|
|
157
|
+
if (capability_state !== undefined && capability_state !== null && !esObjeto(capability_state))
|
|
158
|
+
return "`capability_state` no es un objeto";
|
|
159
|
+
let pregunta;
|
|
160
|
+
if (pregunta_pendiente !== undefined) {
|
|
161
|
+
const p = pregunta_pendiente;
|
|
162
|
+
if (!esObjeto(p) ||
|
|
163
|
+
typeof p.hilo !== "string" ||
|
|
164
|
+
typeof p.id !== "string" ||
|
|
165
|
+
!esObjeto(p.args) ||
|
|
166
|
+
(p.encargo !== undefined && typeof p.encargo !== "string") ||
|
|
167
|
+
Object.keys(p).some((k) => k !== "hilo" && k !== "id" && k !== "args" && k !== "encargo")) {
|
|
168
|
+
return "la pregunta pendiente está mal formada";
|
|
169
|
+
}
|
|
170
|
+
pregunta = { hilo: p.hilo, id: p.id, args: p.args, ...(typeof p.encargo === "string" ? { encargo: p.encargo } : {}) };
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
context,
|
|
174
|
+
...(current_context_usage === undefined ? {} : { current_context_usage }),
|
|
175
|
+
...(capability_state === undefined ? {} : { capability_state: capability_state }),
|
|
176
|
+
...(pregunta === undefined ? {} : { pregunta_pendiente: pregunta }),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* El TEXTO de una foto, entendido: migrado hasta la versión actual y validado, o el motivo por el
|
|
181
|
+
* que no. Pura, y es toda la regla de la lectura. El motivo nunca repite el contenido —un error de
|
|
182
|
+
* `JSON.parse` cita un trozo del fichero, que lleva mensajes enteros— ni ninguna ruta.
|
|
183
|
+
*/
|
|
184
|
+
export function interpretarFoto(texto) {
|
|
185
|
+
let crudo;
|
|
186
|
+
try {
|
|
187
|
+
crudo = JSON.parse(texto);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return { estado: "incompatible", motivo: "no es JSON válido" };
|
|
191
|
+
}
|
|
192
|
+
if (!esObjeto(crudo))
|
|
193
|
+
return { estado: "incompatible", motivo: "no es un objeto JSON" };
|
|
194
|
+
// Ausente es v0; `null` NO: no lo escribe nadie, y leerlo como v0 sería adivinar.
|
|
195
|
+
const v = crudo.version === undefined ? 0 : crudo.version;
|
|
196
|
+
if (typeof v !== "number" || !Number.isInteger(v) || v < 0)
|
|
197
|
+
return { estado: "incompatible", motivo: "la versión no es un entero" };
|
|
198
|
+
if (v > VERSION_DE_MEMORIA) {
|
|
199
|
+
return { estado: "incompatible", motivo: `la escribió un XOneCode más nuevo (versión ${v}; este lee hasta la ${VERSION_DE_MEMORIA})` };
|
|
200
|
+
}
|
|
201
|
+
let foto = crudo;
|
|
202
|
+
for (let desde = v; desde < VERSION_DE_MEMORIA; desde += 1) {
|
|
203
|
+
const migrar = MIGRACIONES[desde];
|
|
204
|
+
if (migrar === undefined)
|
|
205
|
+
return { estado: "incompatible", motivo: `no hay migración desde la versión ${desde}` };
|
|
206
|
+
const r = migrar(foto);
|
|
207
|
+
if (typeof r === "string")
|
|
208
|
+
return { estado: "incompatible", motivo: r };
|
|
209
|
+
foto = r;
|
|
210
|
+
}
|
|
211
|
+
const validada = validarV1(foto);
|
|
212
|
+
return typeof validada === "string" ? { estado: "incompatible", motivo: validada } : { estado: "ok", foto: validada };
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Escribe la foto, en el formato ACTUAL: la versión y la de la librería las SELLA aquí quien
|
|
216
|
+
* escribe, no quien llama, y los campos van por lista cerrada —lo que `toSnapshot()` traiga de más
|
|
217
|
+
* no llega a disco, y así la lectura estricta no rechaza lo que este mismo código escribió—.
|
|
218
|
+
* El fichero se CREA con 0600 antes de tener contenido y se reemplaza con `renameSync`, para que
|
|
219
|
+
* un corte a mitad no deje media conversación ni un JSON roto.
|
|
220
|
+
*/
|
|
221
|
+
export function guardarMemoria(raiz, hilo, foto) {
|
|
222
|
+
const ruta = rutaDeMemoria(raiz, hilo);
|
|
223
|
+
if (ruta === undefined)
|
|
224
|
+
return;
|
|
225
|
+
const saneada = fotoSaneada(foto);
|
|
226
|
+
const pregunta = saneada.pregunta_pendiente;
|
|
227
|
+
const enDisco = {
|
|
228
|
+
version: VERSION_DE_MEMORIA,
|
|
229
|
+
trueforge: VERSION_DE_TRUEFORGE,
|
|
230
|
+
context: saneada.context,
|
|
231
|
+
...(saneada.current_context_usage === undefined ? {} : { current_context_usage: saneada.current_context_usage }),
|
|
232
|
+
...(saneada.capability_state === undefined ? {} : { capability_state: saneada.capability_state }),
|
|
233
|
+
...(pregunta === undefined
|
|
234
|
+
? {}
|
|
235
|
+
: {
|
|
236
|
+
pregunta_pendiente: {
|
|
237
|
+
hilo: pregunta.hilo,
|
|
238
|
+
id: pregunta.id,
|
|
239
|
+
args: pregunta.args,
|
|
240
|
+
...(pregunta.encargo === undefined ? {} : { encargo: pregunta.encargo }),
|
|
241
|
+
},
|
|
242
|
+
}),
|
|
243
|
+
};
|
|
244
|
+
mkdirSync(dirname(ruta), { recursive: true });
|
|
245
|
+
const temporal = `${ruta}.${process.pid}.tmp`;
|
|
246
|
+
closeSync(openSync(temporal, "w", 0o600));
|
|
247
|
+
chmodSync(temporal, 0o600);
|
|
248
|
+
writeFileSync(temporal, JSON.stringify(enDisco), { mode: 0o600 });
|
|
249
|
+
renameSync(temporal, ruta);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* La memoria de la sesión, con su estado. No tener fichero es `sin-memoria`, no un fallo; uno que
|
|
253
|
+
* existe y no se puede leer es `incompatible` con el `code` de Node y nada más (su mensaje lleva
|
|
254
|
+
* la ruta absoluta). NO aparta ni borra nada: esto lo llama también quien solo PREGUNTA
|
|
255
|
+
* (`hayMemoria`, la web al reabrir), y preguntar no puede mover ficheros.
|
|
256
|
+
*/
|
|
257
|
+
export function cargarMemoria(raiz, hilo) {
|
|
258
|
+
const ruta = rutaDeMemoria(raiz, hilo);
|
|
259
|
+
if (ruta === undefined || !existsSync(ruta))
|
|
260
|
+
return { estado: "sin-memoria" };
|
|
261
|
+
let texto;
|
|
262
|
+
try {
|
|
263
|
+
texto = readFileSync(ruta, "utf8");
|
|
264
|
+
}
|
|
265
|
+
catch (e) {
|
|
266
|
+
const code = e.code;
|
|
267
|
+
return { estado: "incompatible", motivo: `no se pudo leer${typeof code === "string" ? ` (${code})` : ""}` };
|
|
268
|
+
}
|
|
269
|
+
return interpretarFoto(texto);
|
|
270
|
+
}
|
|
271
|
+
/** La foto guardada y entendida, o `undefined` si no hay o no se entiende (ver `cargarMemoria`). */
|
|
272
|
+
export function leerMemoria(raiz, hilo) {
|
|
273
|
+
const lectura = cargarMemoria(raiz, hilo);
|
|
274
|
+
return lectura.estado === "ok" ? lectura.foto : undefined;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* ¿Hay una conversación de TrueForge que continuar en esta sesión? Solo si la foto se ENTIENDE:
|
|
278
|
+
* una incompatible no se va a cargar, y decir que sí haría que la web presentara como continuada
|
|
279
|
+
* una sesión que empieza de cero.
|
|
280
|
+
*/
|
|
281
|
+
export function hayMemoria(raiz, hilo) {
|
|
282
|
+
return cargarMemoria(raiz, hilo).estado === "ok";
|
|
283
|
+
}
|
|
284
|
+
/** Cómo se llama una foto apartada: la de siempre, con la marca y la hora. */
|
|
285
|
+
const APARTADA = /^memoria-trueforge\.incompatible-\d+(?:-\d+)?\.json$/;
|
|
286
|
+
/**
|
|
287
|
+
* Aparta la foto que no se entiende, con otro nombre y en la MISMA carpeta, y devuelve ese nombre
|
|
288
|
+
* (solo el nombre: viaja a la pantalla). Apartar y no borrar, porque no la entendemos y puede que
|
|
289
|
+
* un XOneCode más nuevo sí; y apartar y no dejarla, porque el guardado del primer turno la pisaría.
|
|
290
|
+
* Un nombre que ya existe nunca se pisa. Si no se puede, devuelve `undefined` y quien llama lo
|
|
291
|
+
* DICE: la foto se queda donde estaba y el siguiente guardado la sustituirá.
|
|
292
|
+
*/
|
|
293
|
+
export function apartarMemoria(raiz, hilo, ahora = Date.now()) {
|
|
294
|
+
const ruta = rutaDeMemoria(raiz, hilo);
|
|
295
|
+
if (ruta === undefined || !existsSync(ruta))
|
|
296
|
+
return undefined;
|
|
297
|
+
try {
|
|
298
|
+
let nombre = `memoria-trueforge.incompatible-${ahora}.json`;
|
|
299
|
+
for (let n = 1; existsSync(join(dirname(ruta), nombre)); n += 1)
|
|
300
|
+
nombre = `memoria-trueforge.incompatible-${ahora}-${n}.json`;
|
|
301
|
+
renameSync(ruta, join(dirname(ruta), nombre));
|
|
302
|
+
return basename(nombre);
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* El aviso de una memoria que no se cargó, con el motivo y con lo que se hizo con la foto. Se
|
|
310
|
+
* emite UNA vez, en el primer turno: es cuando importa, porque es el turno en que el modelo no
|
|
311
|
+
* recuerda lo que la pantalla enseña. Solo con una foto que EXISTÍA: sin foto no ha pasado nada.
|
|
312
|
+
*/
|
|
313
|
+
export function textoDeMemoriaDescartada(motivo, apartada) {
|
|
314
|
+
return (`⚠ la memoria guardada de esta sesión no se pudo cargar (${motivo}): este turno empieza sin la conversación anterior. ` +
|
|
315
|
+
(apartada === undefined
|
|
316
|
+
? "No se pudo apartar la foto, y el próximo guardado la sustituirá."
|
|
317
|
+
: `La foto no se ha borrado: queda apartada como «${apartada}» en la carpeta de la sesión.`));
|
|
318
|
+
}
|
|
319
|
+
/** Borra la memoria de la sesión, las fotos apartadas incluidas: lo llama el borrado de una sesión. */
|
|
320
|
+
export function olvidarMemoria(raiz, hilo) {
|
|
321
|
+
const ruta = rutaDeMemoria(raiz, hilo);
|
|
322
|
+
if (ruta === undefined)
|
|
323
|
+
return;
|
|
324
|
+
rmSync(ruta, { force: true });
|
|
325
|
+
let nombres = [];
|
|
326
|
+
try {
|
|
327
|
+
nombres = readdirSync(dirname(ruta));
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
for (const n of nombres)
|
|
333
|
+
if (APARTADA.test(n))
|
|
334
|
+
rmSync(join(dirname(ruta), n), { force: true });
|
|
335
|
+
}
|
|
336
|
+
//# sourceMappingURL=memoriaTrueforge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoriaTrueforge.js","sourceRoot":"","sources":["../../../../src/agent/motores/trueforge/memoriaTrueforge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Las métricas PROPIAS de TrueForge (`AgentThreadOrchestrator.getMetrics()`), puestas al lado de
|
|
3
|
+
* las nuestras como CONTRASTE, no como sustituto.
|
|
4
|
+
*
|
|
5
|
+
* Las nuestras salen de traducir cada evento (`eventosTrueforge.ts#traducirEvento`) y son las que
|
|
6
|
+
* se enseñan y se guardan, porque son las mismas cuentas que las de deepagents. Las de la librería
|
|
7
|
+
* las lleva ella por dentro. Si las dos divergen, una de las dos cuenta mal, y hasta ahora no había
|
|
8
|
+
* forma de enterarse: esto lo apunta en la traza (`XONECODE_TRACE_TOOLS=1`) y `xonecode traza` lo
|
|
9
|
+
* dice. Puro, para poder probar la regla sin montar un turno.
|
|
10
|
+
*
|
|
11
|
+
* Se lee al final de CADA turno y es de ESE turno: el raíz se rehace desde su foto al acabar
|
|
12
|
+
* (`sesionTrueforge.ts`), así que el árbol que se mide es el de un solo turno.
|
|
13
|
+
*/
|
|
14
|
+
/** De la forma de la librería (`AgentThreadMetrics`) a la nuestra; lo que no es número no consta. */
|
|
15
|
+
export function metricasDeTrueforge(m) {
|
|
16
|
+
const n = (v) => (typeof v === "number" && Number.isFinite(v) ? v : 0);
|
|
17
|
+
const opcional = (v) => (typeof v === "number" && Number.isFinite(v) ? v : undefined);
|
|
18
|
+
const cache = opcional(m["total_cache_read_tokens"]);
|
|
19
|
+
const coste = opcional(m["total_cost_in_usd"]);
|
|
20
|
+
return {
|
|
21
|
+
entrada: n(m["total_input_tokens"]),
|
|
22
|
+
salida: n(m["total_output_tokens"]),
|
|
23
|
+
...(cache === undefined ? {} : { cache }),
|
|
24
|
+
iteraciones: n(m["iterations"]),
|
|
25
|
+
tools: n(m["total_tool_calls"]),
|
|
26
|
+
subagentes: n(m["total_sub_agents"]),
|
|
27
|
+
resumenes: n(m["total_summarizations"]),
|
|
28
|
+
...(coste === undefined ? {} : { costeUsd: coste }),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* En qué difieren, dicho con las dos cifras. Vacío = coinciden.
|
|
33
|
+
*
|
|
34
|
+
* Los TOKENS se comparan tal cual: los dos lados suman el mismo `usage` de cada llamada, así que
|
|
35
|
+
* cualquier diferencia es una cuenta que se pierde en uno de ellos. Las LLAMADAS no se cuentan
|
|
36
|
+
* igual, y las dos diferencias están MEDIDAS contra la librería real: un hijo EXTERNO es una
|
|
37
|
+
* iteración para ella y cero llamadas para nosotros —su gasto es del producto, en la cuenta
|
|
38
|
+
* `externo`—; y una COMPACTACIÓN es una llamada para nosotros —se paga— y para ella no es una
|
|
39
|
+
* iteración, la lleva aparte en `resumenes`. Las dos se ajustan antes de comparar. Y la caché solo
|
|
40
|
+
* si la librería la trae: ausente no es cero.
|
|
41
|
+
*/
|
|
42
|
+
export function diferenciasDelContraste(nuestras, suyas, hijosExternos) {
|
|
43
|
+
const salida = [];
|
|
44
|
+
const comparar = (que, nuestra, suya) => {
|
|
45
|
+
if (nuestra !== suya)
|
|
46
|
+
salida.push(`${que}: nuestra ${nuestra}, TrueForge ${suya}`);
|
|
47
|
+
};
|
|
48
|
+
comparar("entrada", nuestras.entrada, suyas.entrada);
|
|
49
|
+
comparar("salida", nuestras.salida, suyas.salida);
|
|
50
|
+
if (suyas.cache !== undefined)
|
|
51
|
+
comparar("caché", nuestras.cache, suyas.cache);
|
|
52
|
+
comparar("llamadas", nuestras.llamadas, suyas.iteraciones - hijosExternos + suyas.resumenes);
|
|
53
|
+
return salida;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=metricasTrueforge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metricasTrueforge.js","sourceRoot":"","sources":["../../../../src/agent/motores/trueforge/metricasTrueforge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAsBH,qGAAqG;AACrG,MAAM,UAAU,mBAAmB,CAAC,CAA0B;IAC5D,MAAM,CAAC,GAAG,CAAC,CAAU,EAAU,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAsB,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACnH,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC/C,OAAO;QACL,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC;QACnC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;QACnC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;QACzC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QAC/B,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;QAC/B,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;QACpC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC;QACvC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;KACpD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAwB,EAAE,KAA0B,EAAE,aAAqB;IACjH,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,OAAe,EAAE,IAAY,EAAQ,EAAE;QACpE,IAAI,OAAO,KAAK,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,aAAa,OAAO,eAAe,IAAI,EAAE,CAAC,CAAC;IACrF,CAAC,CAAC;IACF,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACrD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAClD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9E,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,GAAG,aAAa,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7F,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* El «modelo» de un hijo EXTERNO de TrueForge: Claude Code, Codex u OpenCode detrás de un
|
|
3
|
+
* `AgentThread` normal.
|
|
4
|
+
*
|
|
5
|
+
* TrueForge exige que su factoría de hijos devuelva un `AgentThread`, y un hilo necesita un
|
|
6
|
+
* `ILLM`; el `Runnable` que deepagents acepta como `CompiledSubAgent` no tiene sitio aquí. Así que
|
|
7
|
+
* el hilo se construye como cualquier otro y lo que cambia es lo que hay detrás de su modelo: una
|
|
8
|
+
* llamada a `SubagenteExternoPort.correr()` —la MISMA integración de deepagents, con sus guardas de
|
|
9
|
+
* ruta, su política de aprobación y su consumo—, cuya respuesta final vuelve como la respuesta del
|
|
10
|
+
* hilo. El bucle agéntico vive dentro del producto, no aquí: el hilo hace UNA llamada y termina.
|
|
11
|
+
*
|
|
12
|
+
* No es un segundo `ILLM`: es un objeto con la forma de un modelo de LangChain —`stream()`— que
|
|
13
|
+
* `modeloParaTrueforge` ya sabe traducir. Un adaptador propio sería un segundo sitio donde
|
|
14
|
+
* componer los trozos que TrueForge espera.
|
|
15
|
+
*
|
|
16
|
+
* **Lo que manda TrueForge al «modelo» se IGNORA** —su identidad, su prompt de sistema, el primer
|
|
17
|
+
* mensaje—: el hijo externo recibe SUS instrucciones y SU encargo, que se capturan al crear el hilo.
|
|
18
|
+
*/
|
|
19
|
+
import { AIMessageChunk } from "@langchain/core/messages";
|
|
20
|
+
import { modeloParaTrueforge } from "./modeloLangchain.js";
|
|
21
|
+
import { textoDeFalloExterno } from "../../subagentes/subagenteExterno.js";
|
|
22
|
+
export function modeloExternoParaTrueforge(opciones) {
|
|
23
|
+
return modeloParaTrueforge({
|
|
24
|
+
nombre: "externo",
|
|
25
|
+
modelo: () => ({
|
|
26
|
+
stream: async () => {
|
|
27
|
+
const peticion = opciones.peticion();
|
|
28
|
+
const senal = opciones.senal?.();
|
|
29
|
+
let texto;
|
|
30
|
+
try {
|
|
31
|
+
texto = await opciones.puerto.correr({ ...peticion, ...(senal === undefined ? {} : { senal }) });
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
// Cancelado: no hay respuesta que dar, y el turno ya se está cerrando por su lado.
|
|
35
|
+
if (senal?.aborted === true)
|
|
36
|
+
throw error;
|
|
37
|
+
texto = textoDeFalloExterno(peticion.motor, error);
|
|
38
|
+
}
|
|
39
|
+
return (async function* () {
|
|
40
|
+
yield new AIMessageChunk({ content: texto });
|
|
41
|
+
})();
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=modeloExterno.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modeloExterno.js","sourceRoot":"","sources":["../../../../src/agent/motores/trueforge/modeloExterno.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,MAAM,UAAU,0BAA0B,CAAC,QAM1C;IACC,OAAO,mBAAmB,CAAC;QACzB,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YACb,MAAM,EAAE,KAAK,IAAI,EAAE;gBACjB,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;gBACjC,IAAI,KAAa,CAAC;gBAClB,IAAI,CAAC;oBACH,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;gBACnG,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,mFAAmF;oBACnF,IAAI,KAAK,EAAE,OAAO,KAAK,IAAI;wBAAE,MAAM,KAAK,CAAC;oBACzC,KAAK,GAAG,mBAAmB,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;gBACrD,CAAC;gBACD,OAAO,CAAC,KAAK,SAAS,CAAC;oBACrB,MAAM,IAAI,cAAc,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC/C,CAAC,CAAC,EAAE,CAAC;YACP,CAAC;SACF,CAAC;KACH,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* El modelo de TrueForge (`ILLM`) hecho con NUESTRO modelo de LangChain.
|
|
3
|
+
*
|
|
4
|
+
* TrueForge trae su propio cliente (`VercelAILLM`), que construye el modelo desde una
|
|
5
|
+
* configuración de proveedor. No se usa, y es la decisión que hace el motor intercambiable sin
|
|
6
|
+
* que se note: nuestros modelos salen de `Modelos.paraPapel()` ya con todo lo que se les ha ido
|
|
7
|
+
* poniendo —el `user_id` de DeepSeek, el eco de su razonamiento, el tope de salida y el
|
|
8
|
+
* pensamiento adaptativo de Claude, el esfuerzo por modelo—, y reconstruirlos con la
|
|
9
|
+
* configuración de TrueForge lo perdería todo en silencio.
|
|
10
|
+
*
|
|
11
|
+
* El contrato de TrueForge habla en la forma de las chat completions de OpenAI, así que esto es
|
|
12
|
+
* una traducción en los dos sentidos: los mensajes que manda a mensajes de LangChain, y el stream
|
|
13
|
+
* de LangChain a los fragmentos que espera.
|
|
14
|
+
*
|
|
15
|
+
* **La cancelación entra por aquí**: `ILLM.create` no recibe señal, así que la de la llamada en
|
|
16
|
+
* curso se pide a `senal()` en cada `create`, y quien corre el turno la pone.
|
|
17
|
+
*/
|
|
18
|
+
import { AIMessage, HumanMessage, SystemMessage, ToolMessage } from "@langchain/core/messages";
|
|
19
|
+
import { razonamientoDe, textoDe } from "../../turno/puente.js";
|
|
20
|
+
/** El texto de un `content` de OpenAI, sea cadena o lista de partes. */
|
|
21
|
+
function textoDeContenido(contenido) {
|
|
22
|
+
if (typeof contenido === "string")
|
|
23
|
+
return contenido;
|
|
24
|
+
if (!Array.isArray(contenido))
|
|
25
|
+
return "";
|
|
26
|
+
return contenido
|
|
27
|
+
.map((p) => (typeof p === "object" && p !== null && p.type === "text" ? String(p.text) : ""))
|
|
28
|
+
.join("");
|
|
29
|
+
}
|
|
30
|
+
/** Los argumentos de una tool call, que en OpenAI viajan como cadena JSON. Rotos = `{}`. */
|
|
31
|
+
function argumentosDe(json) {
|
|
32
|
+
try {
|
|
33
|
+
const v = JSON.parse(json);
|
|
34
|
+
return typeof v === "object" && v !== null ? v : {};
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Los mensajes que manda TrueForge, en mensajes de LangChain. */
|
|
41
|
+
export function aMensajesDeLangchain(mensajes) {
|
|
42
|
+
return mensajes.map((m) => {
|
|
43
|
+
switch (m.role) {
|
|
44
|
+
case "system":
|
|
45
|
+
case "developer":
|
|
46
|
+
return new SystemMessage(textoDeContenido(m.content));
|
|
47
|
+
case "assistant":
|
|
48
|
+
return new AIMessage({
|
|
49
|
+
content: textoDeContenido(m.content),
|
|
50
|
+
tool_calls: (m.tool_calls ?? []).map((t) => ({ id: t.id, name: t.function.name, args: argumentosDe(t.function.arguments), type: "tool_call" })),
|
|
51
|
+
// El razonamiento de la vuelta anterior, por si el proveedor lo exige de vuelta
|
|
52
|
+
// (DeepSeek): el eco lo repone por id de tool call, pero no se tira si viene.
|
|
53
|
+
...(m.reasoning_content === undefined ? {} : { additional_kwargs: { reasoning_content: m.reasoning_content } }),
|
|
54
|
+
});
|
|
55
|
+
case "tool":
|
|
56
|
+
return new ToolMessage({ tool_call_id: m.tool_call_id ?? "", content: textoDeContenido(m.content) });
|
|
57
|
+
default:
|
|
58
|
+
// `user` y cualquier otro rol: el contenido tal cual, que puede traer imágenes.
|
|
59
|
+
return new HumanMessage({ content: (typeof m.content === "string" || Array.isArray(m.content) ? m.content : "") });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Un `ILLM` sobre un modelo de LangChain. `modelo` y `senal` son funciones y no valores: el modelo
|
|
65
|
+
* cambia con `/modelo` sin rehacer el hilo, y la señal es la de la llamada EN CURSO.
|
|
66
|
+
*/
|
|
67
|
+
export function modeloParaTrueforge(opciones) {
|
|
68
|
+
let secuencia = 0;
|
|
69
|
+
async function* crear(cuerpo) {
|
|
70
|
+
const base = opciones.modelo();
|
|
71
|
+
const tools = cuerpo.tools ?? [];
|
|
72
|
+
const modelo = tools.length > 0 && typeof base.bindTools === "function" ? base.bindTools(tools) : base;
|
|
73
|
+
const mensajes = aMensajesDeLangchain(cuerpo.messages);
|
|
74
|
+
const senal = opciones.senal?.();
|
|
75
|
+
const id = `xc-${++secuencia}`;
|
|
76
|
+
const creado = Math.floor(Date.now() / 1000);
|
|
77
|
+
const nombre = opciones.nombre ?? "xonecode";
|
|
78
|
+
let acumulado;
|
|
79
|
+
for await (const trozo of await modelo.stream(mensajes, senal === undefined ? {} : { signal: senal })) {
|
|
80
|
+
acumulado = acumulado === undefined ? trozo : acumulado.concat(trozo);
|
|
81
|
+
const texto = textoDe(trozo);
|
|
82
|
+
const pensado = razonamientoDe(trozo);
|
|
83
|
+
const llamadas = (trozo.tool_call_chunks ?? []).map((t, i) => ({
|
|
84
|
+
index: t.index ?? i,
|
|
85
|
+
...(t.id === undefined ? {} : { id: t.id, type: "function" }),
|
|
86
|
+
function: { ...(t.name === undefined ? {} : { name: t.name }), arguments: t.args ?? "" },
|
|
87
|
+
}));
|
|
88
|
+
if (texto === "" && pensado === "" && llamadas.length === 0)
|
|
89
|
+
continue;
|
|
90
|
+
yield {
|
|
91
|
+
id,
|
|
92
|
+
object: "chat.completion.chunk",
|
|
93
|
+
created: creado,
|
|
94
|
+
model: nombre,
|
|
95
|
+
choices: [
|
|
96
|
+
{
|
|
97
|
+
index: 0,
|
|
98
|
+
delta: {
|
|
99
|
+
role: "assistant",
|
|
100
|
+
...(texto === "" ? {} : { content: texto }),
|
|
101
|
+
...(pensado === "" ? {} : { reasoning_content: pensado }),
|
|
102
|
+
...(llamadas.length === 0 ? {} : { tool_calls: llamadas }),
|
|
103
|
+
},
|
|
104
|
+
finish_reason: null,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const llamadas = acumulado?.tool_calls ?? [];
|
|
110
|
+
const uso = acumulado?.usage_metadata;
|
|
111
|
+
const razonamiento = acumulado === undefined ? "" : razonamientoDe(acumulado);
|
|
112
|
+
return {
|
|
113
|
+
output: {
|
|
114
|
+
role: "assistant",
|
|
115
|
+
content: acumulado === undefined ? "" : textoDe(acumulado),
|
|
116
|
+
...(llamadas.length === 0
|
|
117
|
+
? {}
|
|
118
|
+
: {
|
|
119
|
+
tool_calls: llamadas.map((t, i) => ({
|
|
120
|
+
id: t.id ?? `${id}-${i}`,
|
|
121
|
+
type: "function",
|
|
122
|
+
function: { name: t.name, arguments: JSON.stringify(t.args ?? {}) },
|
|
123
|
+
})),
|
|
124
|
+
}),
|
|
125
|
+
...(razonamiento === "" ? {} : { reasoning_content: razonamiento }),
|
|
126
|
+
},
|
|
127
|
+
usage: {
|
|
128
|
+
input_tokens: uso?.input_tokens ?? 0,
|
|
129
|
+
output_tokens: uso?.output_tokens ?? 0,
|
|
130
|
+
total_tokens: uso?.total_tokens ?? 0,
|
|
131
|
+
...(uso?.input_token_details?.cache_read === undefined ? {} : { cache_read_tokens: uso.input_token_details.cache_read }),
|
|
132
|
+
},
|
|
133
|
+
finish_reason: llamadas.length > 0 ? "tool_calls" : "stop",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
create: (cuerpo) => crear(cuerpo),
|
|
138
|
+
// La compactación de contexto de TrueForge pide una respuesta entera: el mismo camino,
|
|
139
|
+
// agotado.
|
|
140
|
+
createNonStream: async (cuerpo) => {
|
|
141
|
+
const it = crear(cuerpo);
|
|
142
|
+
let r = await it.next();
|
|
143
|
+
while (!r.done)
|
|
144
|
+
r = await it.next();
|
|
145
|
+
return r.value;
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=modeloLangchain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modeloLangchain.js","sourceRoot":"","sources":["../../../../src/agent/motores/trueforge/modeloLangchain.ts"],"names":[],"mappings":"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"}
|