@johpaz/hive-sdk 0.4.4 → 0.4.5

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 (40) hide show
  1. package/CHANGELOG.md +20 -4
  2. package/README.md +48 -7
  3. package/SECURITY.md +17 -0
  4. package/docs/API-AGENTS.md +430 -0
  5. package/docs/API-ARTIFACTS.md +55 -0
  6. package/docs/API-CONTEXT-COMPILER.md +285 -0
  7. package/docs/API-CRON.md +188 -0
  8. package/docs/API-DAG-SCHEDULER.md +291 -0
  9. package/docs/API-HOOKS.md +147 -0
  10. package/docs/API-RESILIENCE.md +45 -0
  11. package/docs/API-SERVICES.md +458 -0
  12. package/docs/API-SESSIONS.md +146 -0
  13. package/docs/API-TOOLS-SKILLS-CHANNELS.md +499 -0
  14. package/docs/API-WORKERS-EVENTS.md +311 -0
  15. package/docs/HIVE-HARNESS.md +232 -0
  16. package/docs/INDEX.md +198 -0
  17. package/docs/SECURITY-GUARDRAILS.md +87 -0
  18. package/docs/TEMPLATE-HIVE-APP.md +360 -0
  19. package/docs/UPGRADING.md +65 -0
  20. package/docs/assets/logoblack.png +0 -0
  21. package/docs/assets/logocolor-dark.png +0 -0
  22. package/docs/assets/logocolorbg.png +0 -0
  23. package/docs/plans/2026-09-05-office-dependency-hardening-design.md +28 -0
  24. package/docs/plans/2026-09-06-dependency-audit-remediation-design.md +25 -0
  25. package/docs/plans/2026-09-06-pptx-image-size-remediation-design.md +54 -0
  26. package/docs/plans/2026-09-06-typescript7-bun142-documentation-design.md +48 -0
  27. package/package.json +5 -4
  28. package/packages/core/src/agent/llm-providers/hiveagents.ts +2 -2
  29. package/packages/core/src/agent/providers/index.ts +17 -1
  30. package/packages/core/src/api/createAgent.ts +4 -2
  31. package/packages/core/src/gateway/server.ts +1 -1
  32. package/packages/core/src/mcp/transports/sse.ts +11 -3
  33. package/packages/core/src/mcp/transports/websocket.ts +11 -9
  34. package/packages/core/src/tool-runtime/tool-worker.ts +3 -1
  35. package/packages/core/src/tools/office/office-escribir-pptx.ts +3 -1
  36. package/packages/core/src/vendor/pptxgenjs/LICENSE +21 -0
  37. package/packages/core/src/vendor/pptxgenjs/README.md +17 -0
  38. package/packages/core/src/vendor/pptxgenjs/pptxgen.es.d.ts +17 -0
  39. package/packages/core/src/vendor/pptxgenjs/pptxgen.es.js +7368 -0
  40. package/packages/core/src/voice/index.ts +4 -4
@@ -0,0 +1,285 @@
1
+ # API Reference — Context Compiler y Componentes Avanzados
2
+
3
+ ## Índice
4
+
5
+ 1. [Context Compiler](#context-compiler)
6
+ 2. [Message History](#message-history)
7
+ 3. [Scratchpad](#scratchpad)
8
+ 4. [EthicsGuard](#ethicsguard)
9
+ 5. [ACE (Tracer, Reflector, Curator)](#ace)
10
+ 6. [MCP Internals](#mcp)
11
+
12
+ ---
13
+
14
+ ## Context Compiler
15
+
16
+ Compila todo el contexto necesario para cada ejecución del agente.
17
+
18
+ ### compileContext
19
+
20
+ ```typescript
21
+ import { compileContext } from "@johpaz/hive-sdk";
22
+
23
+ const ctx = await compileContext({
24
+ agentId: "analyst",
25
+ threadId: "thread-123",
26
+ userMessage: "Analiza esto",
27
+ channel: "slack",
28
+ mcpManager: mcpClient,
29
+ isolated: false,
30
+ });
31
+
32
+ // Resultado
33
+ console.log(ctx.systemPrompt);
34
+ console.log(ctx.messages); // Historial compilado
35
+ ```
36
+
37
+ ### Estrategias
38
+
39
+ El Context Compiler implementa 4 estrategias de Context Engineering:
40
+
41
+ | Estrategia | Descripción |
42
+ |------------|-------------|
43
+ | **ESCRIBIR** | Guardar información fuera del contexto (Scratchpad, trazas) |
44
+ | **SELECCIONAR** | Traer solo lo relevante (selección BM25 de tool/skill/playbook) |
45
+ | **COMPRIMIR** | Reducir tokens (compaction, tool result clearing) |
46
+ | **AISLAR** | Separar contextos por agente (workers reciben contexto mínimo) |
47
+
48
+ ---
49
+
50
+ ## Message History
51
+
52
+ ### addMessage
53
+
54
+ ```typescript
55
+ import { addMessage } from "@johpaz/hive-sdk";
56
+
57
+ await addMessage(
58
+ threadId: string,
59
+ role: "user" | "assistant" | "system",
60
+ content: string | ContentPart[],
61
+ options?: {
62
+ channel?: string;
63
+ tool_calls?: ToolCall[];
64
+ }
65
+ );
66
+ ```
67
+
68
+ ### getRecentMessages
69
+
70
+ ```typescript
71
+ import { getRecentMessages } from "@johpaz/hive-sdk";
72
+
73
+ const messages = await getRecentMessages(threadId, {
74
+ maxTokens: 32000,
75
+ maxMessages: 50,
76
+ });
77
+ ```
78
+
79
+ ### maybeCompact
80
+
81
+ Reduce el historial cuando excede el límite de tokens.
82
+
83
+ ```typescript
84
+ import { maybeCompact } from "@johpaz/hive-sdk";
85
+
86
+ await maybeCompact(threadId, { channel: "slack", userId: "U123" });
87
+ ```
88
+
89
+ ### clearOldToolResults
90
+
91
+ ```typescript
92
+ import { clearOldToolResults } from "@johpaz/hive-sdk";
93
+
94
+ const clean = clearOldToolResults(messages);
95
+ ```
96
+
97
+ ### ConversationStore
98
+
99
+ ```typescript
100
+ import { getSummary, saveSummary, getScratchpad, saveScratchpadNote } from "@johpaz/hive-sdk";
101
+
102
+ // Resumen de conversación
103
+ const summary = getSummary(threadId);
104
+
105
+ // Notas del scratchpad
106
+ const notes = getScratchpad(threadId, "worker-1");
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Scratchpad
112
+
113
+ Memoria temporal por hilo de conversación.
114
+
115
+ ```typescript
116
+ import { Scratchpad } from "@johpaz/hive-sdk";
117
+
118
+ const pad = new Scratchpad();
119
+
120
+ await pad.write("thread-1", "mi-nota", "contenido");
121
+ const value = await pad.read("thread-1", "mi-nota");
122
+ const all = await pad.list("thread-1"); // { "mi-nota": "contenido" }
123
+ await pad.delete("thread-1", "mi-nota");
124
+ await pad.clear("thread-1");
125
+ ```
126
+
127
+ El scratchpad se inyecta al system prompt en cada turno bajo
128
+ `# SCRATCHPAD (Persistent Notes)`, comprimido con TOON. La clase es una fachada
129
+ sobre las funciones de `conversation-store`: hasta 0.1.5 tenía implementación
130
+ propia y, como usaba el mismo id, escribía las mismas filas con un documento
131
+ incompleto que rompía el orden por recencia.
132
+
133
+ ---
134
+
135
+ ## EthicsGuard
136
+
137
+ Capa opcional de reglas de calidad de respuesta, leídas de la colección
138
+ `playbook` (`category: "response_quality"`).
139
+
140
+ ```typescript
141
+ import { EthicsGuard } from "@johpaz/hive-sdk";
142
+
143
+ const guard = new EthicsGuard();
144
+
145
+ const rules = await guard.getRules(); // sólo las globales
146
+ const rulesForRole = await guard.getRules("coordinator"); // filtra por applicable_to
147
+ const rulesForUser = await guard.getRules(undefined, userId); // globales + las de ese usuario
148
+
149
+ const prompt = guard.injectIntoPrompt("Eres un asistente.", rules);
150
+
151
+ if (await guard.hasEthicsLayer()) {
152
+ console.log("Reglas de calidad activas");
153
+ }
154
+ ```
155
+
156
+ > El constructor ya no recibe un handle de base y todos los métodos son async:
157
+ > hasta 0.1.5 la clase armaba SQL a mano contra la tabla `playbook` y hacía un
158
+ > JOIN con la tabla virtual `playbook_fts`. Ninguna de las dos existe.
159
+
160
+ **Esto no es la ética constitucional del agente.** Esa vive en la colección
161
+ `ethics` y la ensambla `buildSystemPrompt()` como primera sección, completa y sin
162
+ comprimir. `EthicsGuard` es un complemento para hosts que quieran inyectar,
163
+ además, reglas aprendidas por ACE.
164
+
165
+ ---
166
+
167
+ ## ACE (Tracer, Reflector, Curator)
168
+
169
+ Sistema de Auto-Corrección por Experiencia.
170
+
171
+ ### Tracer
172
+
173
+ ```typescript
174
+ import { saveTrace, recordLLMUsage } from "@hive/core/ace";
175
+
176
+ // Guardar traza de ejecución
177
+ saveTrace({
178
+ agentId: "analyst",
179
+ model: "gpt-5.6-luna",
180
+ messages: 5,
181
+ toolCalls: ["web_search", "read_file"],
182
+ durationMs: 1200,
183
+ tokensUsed: 450,
184
+ success: true,
185
+ });
186
+
187
+ // Registrar uso de LLM
188
+ recordLLMUsage({
189
+ model: "gpt-5.6-luna",
190
+ inputTokens: 200,
191
+ outputTokens: 250,
192
+ durationMs: 800,
193
+ });
194
+ ```
195
+
196
+ ### Reflector + Curator
197
+
198
+ ```typescript
199
+ import { runReflector, runCurator } from "@hive/core/ace";
200
+
201
+ // Analizar trazas y generar insights
202
+ await runReflector();
203
+
204
+ // Curar insights en reglas del playbook
205
+ await runCurator();
206
+ ```
207
+
208
+ ### A quién se le aplica lo aprendido
209
+
210
+ Una regla del playbook se inyecta en el system prompt de cada turno, así que
211
+ quién la ve importa tanto como qué dice. `PlaybookDoc.user_id` y
212
+ `ReflectionDoc.user_id` marcan de quién salió:
213
+
214
+ | `user_id` | Origen | Quién la ve |
215
+ |---|---|---|
216
+ | `""` | Sembrada con el producto (`INITIAL_PLAYBOOK_RULES`) | Todos |
217
+ | `"user-ana"` | Aprendida de las trazas de esa persona | Sólo ella |
218
+
219
+ El reflector agrupa el lote de trazas por usuario antes de analizarlo —lo saca
220
+ del `thread_id`, que es `${userId}/${channel}/${peerId}`— y emite una reflexión
221
+ por grupo. El curador propaga ese dueño a la regla, y deduplica **dentro** del
222
+ usuario: la misma observación en dos personas son dos reglas, no una reforzada
223
+ al doble.
224
+
225
+ Las tres puertas de lectura filtran igual (global + propio):
226
+
227
+ ```typescript
228
+ await selectPlaybookRules(texto, userId) // inyección en el prompt
229
+ await guard.getRules(undefined, userId) // EthicsGuard
230
+ // search_knowledge toma el usuario de config.configurable.user_id
231
+ ```
232
+
233
+ `selectPlaybookRules` pide un pozo de candidatos más ancho que el que devuelve,
234
+ porque el índice BM25 es único para todo el proceso: filtrando después de un
235
+ `k` justo, un usuario con pocas reglas se quedaría sin ninguna cuando las mejor
236
+ puntuadas son de otro.
237
+
238
+ > **Migración.** Las reglas anteriores a este campo se aprendieron cuando la
239
+ > instalación era de un solo usuario: `ensureHiveDb()` se las asigna al primer
240
+ > usuario de la base, no las deja globales. Las sembradas son la excepción —
241
+ > `seedAllData()` les fija `user_id: ""` en cada arranque.
242
+
243
+ ---
244
+
245
+ ## MCP Internals
246
+
247
+ ### Config
248
+
249
+ ```typescript
250
+ import type { MCPConfig, MCPServerConfig } from "@johpaz/hive-sdk";
251
+
252
+ const config: MCPConfig = {
253
+ servers: {
254
+ "my-server": {
255
+ transport: "stdio", // "stdio" | "sse" | "websocket"
256
+ command: "npx",
257
+ args: ["-y", "@server/pkg"],
258
+ env: { KEY: "value" },
259
+ enabled: true,
260
+ },
261
+ },
262
+ };
263
+ ```
264
+
265
+ ### Singleton
266
+
267
+ ```typescript
268
+ import { setMCPManager, getMCPManager, hasMCPManager } from "@johpaz/hive-sdk";
269
+
270
+ setMCPManager(mcpManager);
271
+ const mcp = getMCPManager(); // MCPClientManager | undefined
272
+ const exists = hasMCPManager(); // boolean
273
+ ```
274
+
275
+ ### Hot Reload
276
+
277
+ ```typescript
278
+ import { startMCPHotReload, stopMCPHotReload } from "@johpaz/hive-sdk";
279
+
280
+ // Watch de configuración MCP
281
+ startMCPHotReload();
282
+
283
+ // Detener watch
284
+ stopMCPHotReload();
285
+ ```
@@ -0,0 +1,188 @@
1
+ # Cron — tareas programadas
2
+
3
+ Jobs recurrentes y de una sola vez, persistidos en HiveDB, que se ejecutan a
4
+ través del pipeline de agentes.
5
+
6
+ **Sin dependencias.** El motor de cron es propio (`scheduler/cron/`) y usa sólo
7
+ `setTimeout` e `Intl` del runtime de Bun. Hasta 0.2.0 era `croner`.
8
+
9
+ ```typescript
10
+ import { CronScheduler, Cron, parseCronExpression } from "@johpaz/hive-sdk/scheduler";
11
+ ```
12
+
13
+ ## Por qué un motor propio y no `Bun.cron()`
14
+
15
+ Bun 1.4 trae `Bun.cron()` nativo y la pregunta se repite, así que acá está la
16
+ respuesta reevaluada contra el runtime soportado (1.4.2). `Bun.cron` **no alcanza**
17
+ para lo que este scheduler ya expone y persiste en `CronJobDoc`:
18
+
19
+ | Lo que hace falta | `Bun.cron` 1.4.2 |
20
+ |---|---|
21
+ | 6 campos (con segundos) | Falla: *"seconds are not supported"* |
22
+ | Fecha ISO como patrón — así se agendan los `one_shot` | La rechaza: espera 5 campos |
23
+ | Zona horaria por job | Usa la zona local del proceso; no acepta una zona distinta por job |
24
+ | `nextRun()` — de ahí sale `next_run_at` | El handle es `{ cron, ref, stop, unref }` |
25
+ | `pause()` / `resume()` | No existen |
26
+ | `protect`, `maxRuns`, `interval`, `startAt`/`stopAt`, `domAndDow` | Sin equivalente |
27
+ | Controles persistidos | Sin equivalente para la política completa de Hive |
28
+
29
+ Sin fecha ISO no hay jobs de una sola vez, y sin zona horaria "todos los días a
30
+ las 9" significa las 9 UTC para todo el mundo. Por eso el motor es propio: la
31
+ meta era **cero dependencias**, no *usar `Bun.cron` a cualquier precio*.
32
+
33
+ Vale la pena volver a mirarlo cuando `Bun.cron` tenga zona horaria y next-run.
34
+
35
+ ---
36
+
37
+ ## Crear un job
38
+
39
+ ```typescript
40
+ const scheduler = new CronScheduler(async (job) => {
41
+ // Acá corre lo tuyo. Devolver { success } decide si cuenta como corrida o error.
42
+ return { success: true, response: "listo" };
43
+ });
44
+
45
+ await scheduler.boot(); // carga los jobs activos de la BD y detecta los perdidos
46
+
47
+ const { id, nextRun } = await scheduler.create({
48
+ name: "Reporte diario",
49
+ task: "Generá el reporte de ventas de ayer",
50
+ task_type: "recurring",
51
+ cron_expression: "0 9 * * 1-5",
52
+ timezone: "America/Bogota",
53
+ });
54
+ ```
55
+
56
+ Para una sola vez, `task_type: "one_shot"` con `fire_at` en ISO 8601. Debe estar
57
+ en el futuro; si no, `create` lo rechaza.
58
+
59
+ ## Expresiones
60
+
61
+ 5 campos, o 6 poniendo los segundos adelante:
62
+
63
+ ```
64
+ ┌───────── segundos (0-59) ← opcional
65
+ │ ┌─────── minuto (0-59)
66
+ │ │ ┌───── hora (0-23)
67
+ │ │ │ ┌─── día del mes (1-31)
68
+ │ │ │ │ ┌─ mes (1-12 o JAN-DEC)
69
+ │ │ │ │ │ ┌ día de semana (0-7 o SUN-SAT, 0 y 7 = domingo)
70
+ * * * * * *
71
+ ```
72
+
73
+ Acepta `*`, `?` (igual que `*`), listas `1,15`, rangos `1-5`, pasos `*/2`,
74
+ `1-9/3` y `5/15`, nombres de mes y de día, y rangos que dan la vuelta (`22-2` en
75
+ horas = 22, 23, 0, 1, 2).
76
+
77
+ | Expresión | Significado |
78
+ |---|---|
79
+ | `0 9 * * *` | Todos los días a las 9:00 |
80
+ | `0 7 * * 1-5` | Lunes a viernes a las 7:00 |
81
+ | `0 */2 * * *` | Cada 2 horas |
82
+ | `0 0 1 * *` | El 1 de cada mes |
83
+ | `*/30 * * * * *` | Cada 30 segundos |
84
+
85
+ Un error de sintaxis dice **qué campo** falló, porque ese mensaje termina en la
86
+ respuesta de `cron.create` y lo lee quien se equivocó al escribirla:
87
+
88
+ ```
89
+ campo horas: 25 fuera de rango 0-23 (en "0 25 * * *")
90
+ ```
91
+
92
+ ## Opciones del job
93
+
94
+ | Campo | Qué hace |
95
+ |---|---|
96
+ | `timezone` | Zona IANA en la que se lee la expresión. Obligatoria en la práctica |
97
+ | `protect` | No arranca una corrida si la anterior sigue en curso |
98
+ | `max_runs` | Deja de correr después de N corridas |
99
+ | `interval_sec` | Piso de segundos entre arranques, además de la expresión |
100
+ | `start_at` / `stop_at` | Ventana: no corre antes / después de esas fechas |
101
+ | `dom_and_dow` | Exige día del mes **y** de semana, en vez de cualquiera de los dos |
102
+ | `misfire_policy` | Qué hacer con lo que se perdió mientras el proceso estaba caído |
103
+
104
+ ### `dom_and_dow`
105
+
106
+ El cron clásico usa **O** cuando los dos campos de día están restringidos:
107
+ `0 9 15 * 1` es "los 15 **o** los lunes". Con `dom_and_dow: true` pasa a ser
108
+ "los 15 **que sean** lunes". No es un detalle: la diferencia entre las dos
109
+ lecturas es de ~4 corridas por mes a 1 cada varios meses.
110
+
111
+ ### `misfire_policy`
112
+
113
+ Si el proceso estuvo caído cuando tocaba correr, al arrancar `boot()` lo detecta:
114
+
115
+ - `skip` (por defecto) — se anota y se sigue con la próxima.
116
+ - `fire_once` — se corre una vez ahora, si el atraso entra en `misfire_grace_min`.
117
+
118
+ Un `one_shot` que se perdió y no se pone al día pasa a `failed`: su `fire_at` ya
119
+ pasó y no puede volver a ocurrir, así que dejarlo activo sería un job zombi.
120
+
121
+ ## Zona horaria y horario de verano
122
+
123
+ La expresión se lee contra **el reloj de pared de la zona del job**, no contra
124
+ UTC ni contra la zona del servidor. "Todos los días a las 9" en Bogotá son las
125
+ 14:00Z, y en Madrid cambia dos veces al año.
126
+
127
+ Los dos casos raros están resueltos, y no de forma arbitraria:
128
+
129
+ - **La hora que no existe.** Cuando el reloj se adelanta, salta de 01:59 a
130
+ 03:00: un job de las 2:30 no tiene cuándo correr ese día. **Se saltea ese día**
131
+ en vez de correr a una hora inventada.
132
+ - **La hora que ocurre dos veces.** Cuando el reloj se atrasa, las 2:30 pasan
133
+ dos veces. **Corre en la primera**, una sola vez.
134
+
135
+ ## Usar el motor suelto
136
+
137
+ Sirve sin montar un scheduler — por ejemplo para que una UI muestre las próximas
138
+ corridas mientras la persona escribe la expresión:
139
+
140
+ ```typescript
141
+ import { Cron, isValidCronExpression, parseCronExpression } from "@johpaz/hive-sdk/scheduler";
142
+
143
+ isValidCronExpression("0 9 * * *"); // true
144
+
145
+ const c = new Cron("0 9 * * 1-5", { timezone: "America/Bogota" });
146
+ c.nextRun(); // Date de la próxima corrida
147
+ c.nextRuns(5); // las próximas cinco
148
+
149
+ // Con función, se agenda de verdad
150
+ const job = new Cron("*/30 * * * * *", { protect: true }, async () => {
151
+ await hacerAlgo();
152
+ });
153
+ job.pause(); job.resume(); job.trigger(); job.stop();
154
+ ```
155
+
156
+ `new Cron(expr)` **sin función no agenda nada**: es la forma de validar una
157
+ expresión sin dejar un timer suelto.
158
+
159
+ ## Contadores y auto-pausa
160
+
161
+ Cada corrida deja una fila en `taskRuns` y actualiza `run_count` / `error_count`
162
+ del job. A los **5 errores seguidos** el job se auto-pausa: un job roto no debe
163
+ reintentar para siempre.
164
+
165
+ Los incrementos se calculan dentro del reintento por conflicto de versión, no
166
+ antes. Con dos corridas solapadas —normal en un job que tarda más que su
167
+ intervalo y no declara `protect`— calcularlos afuera hace que una escritura se
168
+ pierda, y entonces el umbral de auto-pausa no se alcanza nunca.
169
+
170
+ ## Limpieza
171
+
172
+ `runCleanup()` corre sola como job interno: borra corridas de más de 30 días,
173
+ cancela los `one_shot` completados hace más de 7, deja como mucho las últimas
174
+ 1000 corridas por job, y expira los artefactos vencidos.
175
+
176
+ ## API
177
+
178
+ **`CronScheduler`** — `boot` · `create` · `update` · `delete` · `pause` ·
179
+ `resume` · `trigger` · `activate` · `deactivate` · `getStatus` · `getTask` ·
180
+ `listTasks` · `getHistory` · `runCleanup` · `shutdown`
181
+
182
+ **Motor** — `Cron` · `parseCronExpression` · `isValidCronExpression` ·
183
+ `nextOccurrence` · `toWallClock` · `toInstant` · `assertTimeZone`
184
+
185
+ Para el CRUD desde una UI, sin manejar el scheduler a mano, ver
186
+ [API-SERVICES.md](./API-SERVICES.md) (`createCronJob`, `listCronJobs`, …).
187
+
188
+ *Documentación Hive SDK — ver `version` en package.json*