@johpaz/hive-sdk 0.4.3 → 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 (49) 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 +9 -8
  28. package/packages/cli/templates/hive-app/package.json +3 -0
  29. package/packages/core/src/agent/llm-providers/hiveagents.ts +2 -2
  30. package/packages/core/src/agent/providers/index.ts +17 -1
  31. package/packages/core/src/api/createAgent.ts +4 -2
  32. package/packages/core/src/config/loader.ts +2 -1
  33. package/packages/core/src/gateway/server.ts +1 -1
  34. package/packages/core/src/mcp/transports/sse.ts +22 -8
  35. package/packages/core/src/mcp/transports/websocket.ts +11 -9
  36. package/packages/core/src/scheduler/CronScheduler.ts +4 -2
  37. package/packages/core/src/scheduler/cron/job.ts +2 -1
  38. package/packages/core/src/scheduler/cron/zoned-time.ts +2 -1
  39. package/packages/core/src/tool-runtime/tool-worker.ts +3 -1
  40. package/packages/core/src/tools/office/office-escribir-pptx.ts +3 -1
  41. package/packages/core/src/tools/office/office-leer-pdf.ts +93 -44
  42. package/packages/core/src/tools/office/office-leer-xlsx.ts +36 -10
  43. package/packages/core/src/tools/office/security-limits.ts +28 -0
  44. package/packages/core/src/utils/port.ts +33 -0
  45. package/packages/core/src/vendor/pptxgenjs/LICENSE +21 -0
  46. package/packages/core/src/vendor/pptxgenjs/README.md +17 -0
  47. package/packages/core/src/vendor/pptxgenjs/pptxgen.es.d.ts +17 -0
  48. package/packages/core/src/vendor/pptxgenjs/pptxgen.es.js +7368 -0
  49. package/packages/core/src/voice/index.ts +6 -5
@@ -0,0 +1,291 @@
1
+ # API Reference — DAG Scheduler
2
+
3
+ ## Índice
4
+
5
+ 1. [Arquitectura](#arquitectura)
6
+ 2. [TaskNode](#tasknode)
7
+ 3. [TaskGraph](#taskgraph)
8
+ 4. [DAGScheduler](#dagscheduler)
9
+ 5. [Estrategias](#estrategias)
10
+ 6. [Presets](#presets)
11
+ 7. [EventBridge](#eventbridge)
12
+ 8. [Errores Comunes](#errores-comunes)
13
+
14
+ ---
15
+
16
+ ## Arquitectura
17
+
18
+ El DAG Scheduler orquesta la ejecución de grafos acíclicos dirigidos (DAG) de tareas.
19
+
20
+ ```
21
+ TaskNode → TaskGraph → DAGScheduler
22
+
23
+ ┌──────────────┼──────────────┐
24
+ ▼ ▼ ▼
25
+ Worker 1 Worker 2 Worker 3
26
+ (agente) (agente) (agente)
27
+ ```
28
+
29
+ ---
30
+
31
+ ## TaskNode
32
+
33
+ Representa una tarea individual en el grafo.
34
+
35
+ ### TaskNodeConfig
36
+
37
+ ```typescript
38
+ import { TaskNode } from "@johpaz/hive-sdk";
39
+
40
+ interface TaskNodeConfig {
41
+ id: string;
42
+ agentId: string;
43
+ name?: string;
44
+ taskDescription: string;
45
+ deps: string[];
46
+ priority?: number;
47
+ timeout?: number;
48
+ maxRetries?: number;
49
+ }
50
+ ```
51
+
52
+ ### Estados
53
+
54
+ ```typescript
55
+ type NodeStatus = "PENDING" | "READY" | "RUNNING" | "COMPLETED" | "FAILED";
56
+ ```
57
+
58
+ ### Ejemplo
59
+
60
+ ```typescript
61
+ const node = new TaskNode({
62
+ id: "fetch-data",
63
+ agentId: "fetcher",
64
+ taskDescription: "Obtener datos de API",
65
+ deps: [],
66
+ });
67
+ node.markRunning();
68
+ // ... ejecutar ...
69
+ node.markCompleted("datos obtenidos");
70
+ ```
71
+
72
+ ---
73
+
74
+ ## TaskGraph
75
+
76
+ Grafo acíclico dirigido de tareas.
77
+
78
+ ```typescript
79
+ import { TaskGraph } from "@johpaz/hive-sdk";
80
+
81
+ const graph = new TaskGraph([
82
+ { id: "a", agentId: "worker", taskDescription: "Tarea A", deps: [] },
83
+ { id: "b", agentId: "worker", taskDescription: "Tarea B", deps: ["a"] },
84
+ { id: "c", agentId: "worker", taskDescription: "Tarea C", deps: ["a"] },
85
+ { id: "d", agentId: "worker", taskDescription: "Tarea D", deps: ["b", "c"] },
86
+ ]);
87
+
88
+ // Nodos listos para ejecutar (sin deps pendientes)
89
+ const ready = graph.getReadyNodes();
90
+
91
+ // IDs de nodos completados
92
+ const completed = graph.getCompletedIds();
93
+
94
+ // Nodos recién listos tras completar uno
95
+ const newlyReady = graph.getNewlyReadyIds(new Set(["a"]));
96
+
97
+ // Resultados de dependencias
98
+ const depResults = graph.getDepResults("d");
99
+
100
+ // Progreso
101
+ const progress = graph.getProgress();
102
+ // { total: 4, completed: 1, running: 0, failed: 0, pending: 3, percentComplete: 25 }
103
+ ```
104
+
105
+ ---
106
+
107
+ ## DAGScheduler
108
+
109
+ Orquestador principal de la ejecución.
110
+
111
+ ```typescript
112
+ import { DAGScheduler, TaskGraph } from "@johpaz/hive-sdk";
113
+
114
+ const graph = new TaskGraph([
115
+ { id: "fetch", agentId: "fetcher", taskDescription: "Fetch data", deps: [] },
116
+ { id: "process", agentId: "processor", taskDescription: "Process", deps: ["fetch"] },
117
+ { id: "save", agentId: "saver", taskDescription: "Save", deps: ["process"] },
118
+ ]);
119
+
120
+ const scheduler = new DAGScheduler({
121
+ maxConcurrentWorkers: 2,
122
+ });
123
+
124
+ const result = await scheduler.execute(graph);
125
+
126
+ console.log(`Success: ${result.success}`);
127
+ console.log(`Duration: ${result.totalDurationMs}ms`);
128
+ ```
129
+
130
+ ### DAGResult
131
+
132
+ ```typescript
133
+ interface DAGResult {
134
+ swarmId: string;
135
+ totalDurationMs: number;
136
+ completed: NodeSummary[];
137
+ failed: NodeSummary[];
138
+ success: boolean;
139
+ }
140
+
141
+ interface NodeSummary {
142
+ id: string;
143
+ name: string;
144
+ status: "COMPLETED" | "FAILED";
145
+ durationMs: number;
146
+ result?: string;
147
+ error?: string;
148
+ retries: number;
149
+ }
150
+ ```
151
+
152
+ ### Control
153
+
154
+ ```typescript
155
+ scheduler.abort(); // Abortar ejecución en curso
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Estrategias
161
+
162
+ ### ParallelStrategy (FIFO)
163
+
164
+ ```typescript
165
+ import { ParallelStrategy } from "@johpaz/hive-sdk";
166
+
167
+ const strategy = new ParallelStrategy(); // Orden de llegada
168
+ ```
169
+
170
+ ### PriorityStrategy
171
+
172
+ ```typescript
173
+ import { PriorityStrategy } from "@johpaz/hive-sdk";
174
+
175
+ const strategy = new PriorityStrategy(); // Por prioridad + path crítico
176
+ ```
177
+
178
+ ### Custom Strategy
179
+
180
+ ```typescript
181
+ import type { ExecutionStrategy } from "@johpaz/hive-sdk";
182
+
183
+ const myStrategy: ExecutionStrategy = {
184
+ initialize(nodes) { /* precomputar */ },
185
+ pick(nodes) { return nodes[0]; }, // FIFO
186
+ };
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Presets
192
+
193
+ Grafos predefinidos.
194
+
195
+ ### ResearchPreset
196
+
197
+ ```typescript
198
+ import { createResearchGraph } from "@hive/core/swarm/presets";
199
+
200
+ const graph = createResearchGraph({
201
+ agents: { researcher: "researcher-id", writer: "writer-id" },
202
+ query: "Análisis de mercado",
203
+ });
204
+ ```
205
+
206
+ ### HiveLearnPreset
207
+
208
+ ```typescript
209
+ import { createHiveLearnGraph } from "@hive/core/swarm/presets";
210
+
211
+ const graph = createHiveLearnGraph({
212
+ agents: { teacher: "teacher-id", student: "student-id" },
213
+ topic: "Machine Learning",
214
+ });
215
+ ```
216
+
217
+ ---
218
+
219
+ ## EventBridge
220
+
221
+ Puente de eventos entre el scheduler y el resto del sistema.
222
+
223
+ ```typescript
224
+ import { EventBridge } from "@johpaz/hive-sdk";
225
+
226
+ const bridge = new EventBridge("swarm-123", "project-1", "coordinator-1");
227
+
228
+ bridge.onTaskCompleted = (node, progress) => {
229
+ console.log(`${node.name}: ${progress.percentComplete}%`);
230
+ };
231
+
232
+ bridge.onSwarmCompleted = (result) => {
233
+ console.log(`Swarm completed. Success: ${result.success}`);
234
+ };
235
+ ```
236
+
237
+ ---
238
+
239
+ ## IAgentExecutor
240
+
241
+ ```typescript
242
+ import type { IAgentExecutor } from "@johpaz/hive-sdk";
243
+
244
+ const myExecutor: IAgentExecutor = {
245
+ async execute(node, depResults, threadId) {
246
+ const context = Object.values(depResults).join("\n");
247
+ return await myCustomFunction(node.taskDescription, context);
248
+ },
249
+ };
250
+
251
+ const result = await scheduler.execute(graph, { executor: myExecutor });
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Errores Comunes
257
+
258
+ ### Cyclic dependency detected
259
+
260
+ ```typescript
261
+ // ❌ Ciclo: a→b→a
262
+ [{ id: "a", deps: ["b"] }, { id: "b", deps: ["a"] }];
263
+
264
+ // ✅ Sin ciclo
265
+ [{ id: "a", deps: [] }, { id: "b", deps: ["a"] }];
266
+ ```
267
+
268
+ ### Task timeout
269
+
270
+ ```typescript
271
+ // Configurar timeout razonable
272
+ const config = { id: "task", agentId: "w", taskDescription: "...", deps: [], timeout: 30000 };
273
+ ```
274
+
275
+ ## Errores y utilidades
276
+
277
+ | | |
278
+ |---|---|
279
+ | `CyclicDependencyError` | El grafo tiene un ciclo: no hay orden posible. Se detecta al construirlo, no al ejecutarlo. |
280
+ | `TaskTimeoutError` | Un nodo agotó su ventana. Lleva el id del nodo. |
281
+ | `TaskFailureError` | Un nodo falló; sus dependientes se marcan sin llegar a correr. |
282
+
283
+ `defaultInvoker` es cómo se invoca a un agente por defecto en `runRoleSwarm`
284
+ (`runAgentIsolated`). Se puede reemplazar para instrumentar o para tests, sin
285
+ tocar la topología.
286
+
287
+ `createTaskHandler` · `notifyTaskCompletion` · `setSchedulerForCleanup` conectan
288
+ el enjambre con el scheduler: son lo que hace que una tarea programada pueda
289
+ disparar un grafo y que su finalización se notifique.
290
+
291
+ *Documentación Hive SDK — ver `version` en package.json*
@@ -0,0 +1,147 @@
1
+ # API-HOOKS — engancharse al ciclo de vida
2
+
3
+ ## Por qué existe
4
+
5
+ `HooksConfigSchema` declaraba 14 hooks en la configuración y **ninguno se
6
+ invocaba**: era un esquema sin implementación. Quien lo encontrara asumiría que
7
+ funciona, que es peor que no tenerlo.
8
+
9
+ Ahora están conectados, con dos formas:
10
+
11
+ - **Callbacks en proceso** (`registerHook`) — tipados, sin costo de arranque, y
12
+ pueden **devolver una decisión**. Es el primitivo: quien consume el SDK ya está
13
+ en el mismo proceso.
14
+ - **Scripts externos** (`hooks.scripts` en la configuración) — para quien no
15
+ escribe TypeScript. Se montan encima del primitivo. Cuestan un `Bun.spawn` por
16
+ invocación, así que conviene reservarlos para lo que no ocurre en cada tool call.
17
+
18
+ Sólo están los cinco con un uso claro. Los otros nueve del esquema original
19
+ quedaron fuera a propósito: cada hook es una promesa que después hay que
20
+ sostener, y uno que nadie usa es superficie que envejece mal.
21
+
22
+ ```typescript
23
+ import { registerHook } from "@johpaz/hive-sdk/hooks";
24
+ ```
25
+
26
+ ## Los cinco
27
+
28
+ | Hook | Cuándo | Puede bloquear |
29
+ |---|---|---|
30
+ | `beforeToolCall` | Antes de ejecutar una tool | **sí** |
31
+ | `afterToolCall` | Con el resultado, haya salido bien o mal | no |
32
+ | `beforeCompaction` | Antes de comprimir el historial | no |
33
+ | `sessionStart` | Al abrir una conversación (crearla o reabrirla) | no |
34
+ | `sessionEnd` | Al cerrarla (archivarla o borrarla) | no |
35
+
36
+ ## Bloquear una tool
37
+
38
+ ```typescript
39
+ registerHook("beforeToolCall", (ctx) => {
40
+ if (ctx.toolName === "cli_exec" && String(ctx.args.command).includes("curl")) {
41
+ return { block: true, reason: "las llamadas de red salen por api_request" };
42
+ }
43
+ });
44
+ ```
45
+
46
+ La tool **no se ejecuta**, y el motivo le llega al modelo como resultado, para
47
+ que sepa por qué no se hizo en vez de reintentar a ciegas.
48
+
49
+ Detalles que importan:
50
+
51
+ - **El primero que bloquea gana.** No tiene sentido seguir preguntando cuando ya
52
+ hay una negativa.
53
+ - **Un hook que lanza no bloquea.** Un observador roto no debería frenar el
54
+ trabajo; se registra el error y se sigue.
55
+ - **Se aplica a las tools que corren en un worker también.** El enganche está en
56
+ `executeToolBatch`, no en la ejecución del hilo principal: engancharlo abajo
57
+ dejaría la mitad de las llamadas sin revisar, que en un hook de política es
58
+ peor que no tenerlo.
59
+ - **Bloquear una no impide las demás**, y el orden se conserva: el modelo espera
60
+ una respuesta por cada llamada que hizo, en el orden en que las hizo.
61
+
62
+ ## Auditar
63
+
64
+ ```typescript
65
+ registerHook("afterToolCall", (ctx) => {
66
+ auditoria.registrar({
67
+ tool: ctx.toolName, ok: ctx.ok, ms: ctx.durationMs,
68
+ agente: ctx.agentId, usuario: ctx.userId,
69
+ });
70
+ });
71
+ ```
72
+
73
+ `afterToolCall` **también ve las bloqueadas**: auditar incluye lo que no pasó.
74
+
75
+ ## Sesiones
76
+
77
+ ```typescript
78
+ registerHook("sessionStart", async ({ threadId, userId, channel }) => {
79
+ await miPanel.registrarConversacion(userId, threadId, channel);
80
+ });
81
+
82
+ registerHook("sessionEnd", async ({ threadId, userId }) => {
83
+ await miPanel.cerrarConversacion(userId, threadId);
84
+ });
85
+ ```
86
+
87
+ Se disparan en las cuatro transiciones del ciclo de vida de un hilo, todas en
88
+ `agent/thread-store.ts`:
89
+
90
+ | Transición | Hook | API pública |
91
+ |---|---|---|
92
+ | Se crea el hilo | `sessionStart` | `createSession` · `createWebSession` |
93
+ | Se reabre | `sessionStart` | `reopenSession` |
94
+ | Se archiva | `sessionEnd` | `closeSession` |
95
+ | Se borra | `sessionEnd` | `deleteSession` |
96
+
97
+ Detalles que importan:
98
+
99
+ - **`sessionStart` no se dispara en cada turno.** `createSession` es idempotente
100
+ y se llama con cada mensaje entrante; el enganche está en el `put` que crea la
101
+ fila, no en la función. Quien use el hook para inicializar estado o para
102
+ cobrar por conversación cuenta conversaciones, no mensajes.
103
+ - **Dos turnos concurrentes lo disparan una sola vez.** El `put` con
104
+ `expectedVersion: 0` es el punto de serialización: el que pierde la carrera no
105
+ dispara nada.
106
+ - **Archivar o reabrir dos veces seguidas dispara una sola vez**: el estado se
107
+ compara antes de escribir, y un no-op no anuncia nada.
108
+ - **`sessionEnd` por borrado lleva `userId` y `channel`.** La fila se lee antes
109
+ de borrarla; si no, el hook recibiría un `threadId` y nada más, y quien lo use
110
+ para limpiar no sabría de quién era lo que se fue.
111
+ - **Cubre a los canales que llaman `ensureThread` directo**, sin pasar por el
112
+ módulo `sessions`.
113
+
114
+ ## Scripts
115
+
116
+ ```jsonc
117
+ // hive.config.json
118
+ { "hooks": { "scripts": { "before_tool_call": "./hooks/politica.ts" } } }
119
+ ```
120
+
121
+ ```typescript
122
+ loadConfiguredHookScripts(); // opt-in: ejecutar procesos externos no debería
123
+ // pasar por el solo hecho de importar el SDK
124
+ ```
125
+
126
+ El contexto llega por stdin como JSON. Para `before_tool_call`, **salir con
127
+ código distinto de 0 bloquea** y lo que el script escriba en stdout es el motivo
128
+ — el equivalente en procesos a devolver `{ block }`.
129
+
130
+ ## Utilidades
131
+
132
+ `hasHooks(nombre)` para saltarse trabajo cuando no hay ninguno registrado;
133
+ `clearHooks(nombre?)` para tests. `registerHook` devuelve la función que lo quita.
134
+
135
+ ## Los disparadores
136
+
137
+ `runBeforeToolCall` · `runAfterToolCall` · `runBeforeCompaction` ·
138
+ `runSessionStart` · `runSessionEnd`
139
+
140
+ Los llama el SDK en cada punto del ciclo; están exportados para quien integre los
141
+ hooks en su propio flujo —un gateway con su propia noción de sesión, por ejemplo—
142
+ pero **no hay que llamarlos** para que los hooks funcionen en un turno normal.
143
+
144
+ `runBeforeToolCall` devuelve el motivo del bloqueo o `null`; los demás no
145
+ devuelven nada, porque son observadores.
146
+
147
+ *Documentación Hive SDK — ver `version` en package.json*
@@ -0,0 +1,45 @@
1
+ # API-RESILIENCE — reintentos y circuit breakers
2
+
3
+ ```typescript
4
+ import { withRetry, isRetryableError, CircuitBreaker } from "@johpaz/hive-sdk/resilience";
5
+ ```
6
+
7
+ ## Reintentos
8
+
9
+ ```typescript
10
+ const res = await withRetry(
11
+ () => llamarAlProveedor(),
12
+ { maxAttempts: 3, initialDelayMs: 1000, backoffMultiplier: 2, maxDelayMs: 30000 },
13
+ (err) => isRetryableError(err),
14
+ );
15
+ ```
16
+
17
+ `isRetryableError` distingue lo que mejora reintentando —429, 5xx, timeouts,
18
+ cortes de red— de lo que no. **Un 400 no mejora reintentando**: el cuerpo está
19
+ mal y volver a mandarlo igual sólo gasta una llamada. Lo mismo con 401 y 403.
20
+
21
+ El backoff es exponencial con jitter, y respeta el `Retry-After` cuando el
22
+ proveedor lo manda: si te dicen cuánto esperar, discutirlo es contraproducente.
23
+
24
+ `computeRetryDelay(intento, policy)` calcula la espera si necesitas programarla
25
+ por tu cuenta.
26
+
27
+ ## Circuit breakers
28
+
29
+ ```typescript
30
+ const breaker = new CircuitBreaker("proveedor-x", { failureThreshold: 5, resetTimeoutMs: 30000 });
31
+ const r = await breaker.execute(() => llamar());
32
+ ```
33
+
34
+ Cuando un servicio ya viene fallando, seguir intentando le agrega carga y te
35
+ gasta el presupuesto de reintentos. El breaker corta: tras N fallos se abre y
36
+ rechaza sin llamar, hasta que pasa el tiempo de reposo y deja pasar una de
37
+ prueba.
38
+
39
+ `CircuitBreakerOpenError` lleva `retryAfterMs`, que es lo que necesita quien
40
+ quiera decirle al usuario cuándo volver a intentar.
41
+
42
+ `circuitBreakerRegistry` mantiene uno por nombre, para no crear un breaker nuevo
43
+ en cada llamada y perder el estado que le da sentido.
44
+
45
+ *Documentación Hive SDK — ver `version` en package.json*