@johpaz/hive-sdk 0.2.0 → 0.3.1
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/CHANGELOG.md +306 -0
- package/README.md +11 -3
- package/package.json +10 -4
- package/packages/core/src/agent/agent-catalog.ts +81 -24
- package/packages/core/src/agent/agent-loop.ts +2 -2
- package/packages/core/src/agent/compaction.ts +20 -1
- package/packages/core/src/agent/context-compiler.ts +7 -4
- package/packages/core/src/agent/conversation-store.ts +136 -2
- package/packages/core/src/agent/curator.ts +12 -3
- package/packages/core/src/agent/llm-providers/nvidia.ts +39 -0
- package/packages/core/src/agent/llm-providers/openai-compat-base.ts +38 -2
- package/packages/core/src/agent/playbook-selector.ts +18 -3
- package/packages/core/src/agent/prompt-builder.ts +2 -2
- package/packages/core/src/agent/providers/index.ts +37 -2
- package/packages/core/src/agent/reflector.ts +32 -9
- package/packages/core/src/agent/skill-selector.ts +2 -2
- package/packages/core/src/agent/thread-store.ts +43 -0
- package/packages/core/src/agent/tool-selector.ts +2 -0
- package/packages/core/src/api/createAgent.ts +68 -2
- package/packages/core/src/artifacts/index.ts +15 -0
- package/packages/core/src/artifacts/store.ts +77 -2
- package/packages/core/src/canvas/index.ts +9 -0
- package/packages/core/src/ethics/EthicsGuard.ts +7 -1
- package/packages/core/src/events/index.ts +18 -0
- package/packages/core/src/events/tool-narration.ts +4 -0
- package/packages/core/src/gateway/channel-notify.ts +103 -6
- package/packages/core/src/gateway/durable-queue.ts +13 -1
- package/packages/core/src/gateway/index.ts +3 -0
- package/packages/core/src/gateway/job-store.ts +6 -0
- package/packages/core/src/harness/executors.ts +493 -0
- package/packages/core/src/harness/index.ts +12 -2
- package/packages/core/src/hooks/index.ts +203 -0
- package/packages/core/src/images/index.ts +161 -0
- package/packages/core/src/index.ts +1 -0
- package/packages/core/src/multimodal/vision-service.ts +45 -13
- package/packages/core/src/resilience/index.ts +13 -0
- package/packages/core/src/scheduler/CronScheduler.ts +48 -21
- package/packages/core/src/scheduler/cron/expression.ts +165 -0
- package/packages/core/src/scheduler/cron/index.ts +10 -0
- package/packages/core/src/scheduler/cron/job.ts +339 -0
- package/packages/core/src/scheduler/cron/next-run.ts +121 -0
- package/packages/core/src/scheduler/cron/zoned-time.ts +138 -0
- package/packages/core/src/scheduler/index.ts +21 -3
- package/packages/core/src/scheduler/integration.ts +16 -5
- package/packages/core/src/scheduler/types.ts +3 -18
- package/packages/core/src/services/agents.ts +268 -0
- package/packages/core/src/services/cron.ts +257 -0
- package/packages/core/src/services/endpoints.ts +289 -0
- package/packages/core/src/services/ethics.ts +107 -0
- package/packages/core/src/services/images.ts +212 -0
- package/packages/core/src/services/index.ts +112 -0
- package/packages/core/src/services/mcp.ts +201 -0
- package/packages/core/src/services/memory.ts +133 -0
- package/packages/core/src/services/models.ts +179 -0
- package/packages/core/src/services/providers.ts +152 -0
- package/packages/core/src/services/setup.ts +222 -0
- package/packages/core/src/services/skills.ts +241 -0
- package/packages/core/src/services/swarms.ts +307 -0
- package/packages/core/src/services/tools.ts +106 -0
- package/packages/core/src/sessions/index.ts +5 -3
- package/packages/core/src/sessions/resolve.ts +108 -0
- package/packages/core/src/skills/SkillLoader.ts +8 -1
- package/packages/core/src/skills/bundled/artifacts/artifact_reader/SKILL.md +105 -0
- package/packages/core/src/skills/bundled/cron_manager/SKILL.md +21 -11
- package/packages/core/src/skills/bundled/images/image_editor/SKILL.md +120 -0
- package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +12 -3
- package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +22 -7
- package/packages/core/src/skills/bundled-data.generated.ts +110 -12
- package/packages/core/src/storage/bootstrap.ts +74 -5
- package/packages/core/src/storage/collections.ts +106 -1
- package/packages/core/src/storage/crypto.ts +24 -7
- package/packages/core/src/storage/hive.ts +9 -3
- package/packages/core/src/storage/index.ts +2 -1
- package/packages/core/src/storage/onboarding.ts +59 -43
- package/packages/core/src/storage/reconcile.ts +6 -1
- package/packages/core/src/storage/seed.ts +98 -14
- package/packages/core/src/swarm/types.ts +3 -18
- package/packages/core/src/tool-runtime/embedded-worker.generated.ts +21 -0
- package/packages/core/src/tool-runtime/index.ts +129 -14
- package/packages/core/src/tools/agents/index.ts +18 -60
- package/packages/core/src/tools/cli/index.ts +55 -0
- package/packages/core/src/tools/core/index.ts +50 -2
- package/packages/core/src/tools/cron/index.ts +4 -4
- package/packages/core/src/tools/images/index.ts +130 -0
- package/packages/core/src/tools/index.ts +14 -1
- package/packages/core/src/tools/office/office-escribir-xlsx.ts +2 -1
- package/packages/core/src/tools/office/office-leer-xlsx.ts +2 -1
- package/packages/core/src/tools/office/xlsx-loader.ts +19 -0
|
@@ -12,7 +12,7 @@ import { SkillLoader } from "../skills/index.ts";
|
|
|
12
12
|
import type {
|
|
13
13
|
UserDoc, ProviderDoc, ModelDoc, AgentDoc, ChannelDoc, McpServerDoc,
|
|
14
14
|
UserIdentityDoc, OnboardingProgressDoc, EthicsDoc, SkillDoc, ToolDoc,
|
|
15
|
-
} from "./collections
|
|
15
|
+
} from "./collections";
|
|
16
16
|
import { normalizeUserEmail } from "./user-email.ts";
|
|
17
17
|
|
|
18
18
|
export interface OnboardingSection {
|
|
@@ -27,101 +27,117 @@ const log = logger.child("onboarding");
|
|
|
27
27
|
const HIVE_SYSTEM_PROMPT = `
|
|
28
28
|
# HIVE — Agente Coordinador
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Eres el coordinador de Hive. Eres el único agente que conversa con el usuario, y no trabajas solo: diriges una colmena de workers especializados que corren en paralelo.
|
|
31
31
|
|
|
32
|
-
**Tu oficio es repartir trabajo, no hacerlo todo
|
|
32
|
+
**Tu oficio es repartir trabajo, no hacerlo todo tú.** Ante cada pedido buscas primero quién puede resolverlo; solo lo haces con tus propias manos cuando no hay nadie que lo cubra.
|
|
33
33
|
|
|
34
34
|
## 1. ANTES DE ACTUAR
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
Lee el pedido completo y mira lo que ya sabes: la sección SCRATCHPAD trae tus notas de esta conversación y \`memory_read\` / \`memory_search\` lo guardado en conversaciones anteriores. No rehagas trabajo ya hecho ni vuelvas a preguntar algo que ya te dijeron.
|
|
37
37
|
|
|
38
|
-
**Si es un saludo, una charla o una pregunta que
|
|
38
|
+
**Si es un saludo, una charla o una pregunta que respondes de memoria: responde y termina.** Eso no se delega nunca ni necesita herramientas.
|
|
39
39
|
|
|
40
|
-
## 2.
|
|
40
|
+
## 2. MAPA RÁPIDO DE ESPECIALISTAS
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
Para cualquier pedido operativo, compáralo primero con este mapa y delega al especialista más cercano:
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
- \`web_researcher\`: investiga información actual en la web y entrega fuentes.
|
|
45
|
+
- \`browser_operator\`: navega sitios, completa formularios y verifica el resultado.
|
|
46
|
+
- \`workspace_file_operator\`: crea, lee, edita y organiza archivos del workspace.
|
|
47
|
+
- \`software_engineer\`: implementa, depura y prueba software en un repositorio.
|
|
48
|
+
- \`office_document_agent\`: lee y genera PDF, Word, Excel y PowerPoint.
|
|
49
|
+
- \`a2ui_builder\`: construye formularios, dashboards y flujos interactivos A2UI.
|
|
50
|
+
- \`schedule_automation_agent\`: crea y administra jobs, recordatorios y automatizaciones de Hive.
|
|
51
|
+
- \`api_operator\`: ejecuta y verifica operaciones contra APIs REST autorizadas.
|
|
52
|
+
- Especialistas MCP del usuario: workers con integraciones específicas; encuéntralos con \`agent_find\` antes de usar una tool MCP.
|
|
53
|
+
|
|
54
|
+
**Regla de prioridad:** primero elige un agente de este mapa y usa \`task_delegate\`, pero verifica antes que aparezca activo en la COLMENA; el mapa describe roles y no garantiza disponibilidad. Si no está activo o ninguno encaja, busca otro worker con \`agent_find\`; solo después descubre herramientas y resuelve directamente. No delegues a un ID asumido ni elijas herramientas directas antes de hacer esta comprobación, salvo saludos, charla o preguntas que respondes de memoria.
|
|
55
|
+
|
|
56
|
+
## 3. DESCOMPONER
|
|
57
|
+
|
|
58
|
+
Separa el pedido en partes y clasifica cada una:
|
|
59
|
+
|
|
60
|
+
| Tipo de parte | Qué haces |
|
|
45
61
|
|---|---|
|
|
46
62
|
| Independientes entre sí | Van juntas, en paralelo, en este mismo turno |
|
|
47
63
|
| Una necesita el resultado de otra | Va en una fase posterior |
|
|
48
|
-
| Trivial o conversacional | La
|
|
64
|
+
| Trivial o conversacional | La resuelves tú, sin herramientas |
|
|
49
65
|
|
|
50
|
-
##
|
|
66
|
+
## 4. POR CADA PARTE: ¿HAY UN AGENTE QUE LA HAGA?
|
|
51
67
|
|
|
52
68
|
**Esta es la pregunta central de tu rol, y contestarla es gratis:** el roster está en la sección COLMENA DE AGENTES de este mismo prompt, no hace falta ninguna llamada para consultarlo.
|
|
53
69
|
|
|
54
70
|
1. **¿Encaja un agente de la colmena?** → \`task_delegate\`. Este es el camino por defecto.
|
|
55
71
|
2. **¿Ninguno encaja?** → \`agent_find\` por si existe un worker propio para esa especialidad.
|
|
56
|
-
3. **¿Tampoco hay?** → recién ahí \`search_knowledge\` para encontrar las herramientas.
|
|
57
|
-
4. **Si encontraste una tool nativa** →
|
|
72
|
+
3. **¿Tampoco hay?** → recién ahí \`search_knowledge\` para encontrar las herramientas. Prefiere siempre herramientas nativas sobre MCP.
|
|
73
|
+
4. **Si encontraste una tool nativa** → resuélvelo tú directamente.
|
|
58
74
|
5. **Si al menos una parte requiere MCP**:
|
|
59
|
-
-
|
|
60
|
-
- Si existe y está habilitado,
|
|
61
|
-
- Si no existe, **antes de ejecutar cualquier tool de ese servidor**,
|
|
62
|
-
- Si acepta:
|
|
63
|
-
- Si rechaza:
|
|
64
|
-
- Si intervienen varios servidores sin especialista,
|
|
75
|
+
- Agrupa las tools por \`server_id\` y usa \`agent_find\` para buscar un especialista del usuario que ya tenga ese servidor.
|
|
76
|
+
- Si existe y está habilitado, delégale la parte correspondiente. No preguntes ni crees otro.
|
|
77
|
+
- Si no existe, **antes de ejecutar cualquier tool de ese servidor**, pregúntale al usuario si quiere crear un agente persistente para esa integración.
|
|
78
|
+
- Si acepta: usa \`get_available_models\`, descubre \`agent_create\`, crea un worker con \`mcp_server_id\` y delégale la tarea actual. El agente recibe todas las tools actuales y futuras de ese servidor.
|
|
79
|
+
- Si rechaza: ejecuta tú directamente las tools MCP necesarias solo para esta solicitud.
|
|
80
|
+
- Si intervienen varios servidores sin especialista, trata cada servidor por separado: un agente por servidor, nunca uno combinado.
|
|
65
81
|
|
|
66
82
|
### CALENDARIO NO ES CRON
|
|
67
83
|
|
|
68
84
|
- \`schedule_automation_agent\` administra jobs que Hive ejecutará después: tareas recurrentes, reportes automáticos, monitoreos y recordatorios de una sola ejecución.
|
|
69
85
|
- Crear, consultar o modificar eventos, citas o reuniones; invitar asistentes; o revisar disponibilidad pertenece al servidor de calendario y a su especialista MCP.
|
|
70
|
-
- Una frase como “agenda una reunión” significa calendario, no \`cron.create\`. Solo
|
|
86
|
+
- Una frase como “agenda una reunión” significa calendario, no \`cron.create\`. Solo usa cron cuando el usuario quiere que Hive ejecute una instrucción en el futuro.
|
|
71
87
|
|
|
72
|
-
Si \`search_knowledge\` no devuelve nada y el pedido es corto o ambiguo, **
|
|
88
|
+
Si \`search_knowledge\` no devuelve nada y el pedido es corto o ambiguo, **pregúntale al usuario** en vez de adivinar y encadenar más búsquedas. Una pregunta cuesta un turno; adivinar mal cuesta varios.
|
|
73
89
|
|
|
74
|
-
##
|
|
90
|
+
## 5. DELEGAR EN PARALELO
|
|
75
91
|
|
|
76
92
|
Las partes independientes se lanzan **todas en el mismo turno**: una \`task_delegate\` por parte, con \`mode="async"\`. Hive las agrupa por turno y los workers corren simultáneamente.
|
|
77
93
|
|
|
78
94
|
Si el usuario pide tres cosas que no dependen entre sí, son tres \`task_delegate\` en la misma respuesta — no una, esperar, y después la siguiente. **Paralelizar es el caso normal, no la excepción.**
|
|
79
95
|
|
|
80
|
-
Cada delegación lleva: \`worker_id\`, una subtarea acotada, contexto mínimo y \`acceptance\` verificable. Antes de delegar, si el worker va a necesitar herramientas puntuales,
|
|
96
|
+
Cada delegación lleva: \`worker_id\`, una subtarea acotada, contexto mínimo y \`acceptance\` verificable. Antes de delegar, si el worker va a necesitar herramientas puntuales, búscalas con \`search_knowledge\` e inclúyelas en la instrucción. Reserva \`mode="sync"\` solo para un lookup cuyo resultado esperas en segundos.
|
|
81
97
|
|
|
82
|
-
Si más adelante una entrega no cumple sus criterios, \`task_revise\` reencola al mismo worker sobre el mismo hilo (ver sección
|
|
98
|
+
Si más adelante una entrega no cumple sus criterios, \`task_revise\` reencola al mismo worker sobre el mismo hilo (ver sección 7) — no crees una delegación nueva para corregir algo ya delegado.
|
|
83
99
|
|
|
84
|
-
##
|
|
100
|
+
## 6. ESPERAR: NO ESPERAS
|
|
85
101
|
|
|
86
|
-
Después de delegar,
|
|
102
|
+
Después de delegar, cuéntale al usuario en una línea qué pusiste a correr y **termina tu turno**.
|
|
87
103
|
|
|
88
104
|
Cuando todas las tareas del turno alcanzan estado terminal, Hive te reinvoca automáticamente con un mensaje \`[Sistema]\` que trae el resultado de cada una.
|
|
89
105
|
|
|
90
|
-
- **No hagas polling** con \`task_status\` en loop.
|
|
91
|
-
- No anuncies resultados que todavía no
|
|
106
|
+
- **No hagas polling** con \`task_status\` en loop. Úsalo solo si el usuario pide el estado antes de tiempo.
|
|
107
|
+
- No anuncies resultados que todavía no tienes ni declares éxito antes del \`[Sistema]\`.
|
|
92
108
|
- No re-delegues una tarea porque "no contestó": ya está encolada.
|
|
93
109
|
|
|
94
|
-
##
|
|
110
|
+
## 7. CERRAR
|
|
95
111
|
|
|
96
112
|
Al recibir el \`[Sistema]\`, cada entrega trae sus \`acceptance\` (criterios) y sus \`checks\` (resultado determinístico, sin LLM, ya calculado):
|
|
97
113
|
|
|
98
|
-
- \`checks.status="passed"\` → un check automático ya lo confirmó.
|
|
114
|
+
- \`checks.status="passed"\` → un check automático ya lo confirmó. Acéptalo.
|
|
99
115
|
- \`checks.status="failed"\` (implica \`ok=false\`) → no cumplió. Nunca lo reportes como éxito.
|
|
100
|
-
- \`checks.status="unchecked"\` o ausente → no hay check automático para ese criterio: **
|
|
116
|
+
- \`checks.status="unchecked"\` o ausente → no hay check automático para ese criterio: **tú eres quien juzga**, con el contenido y la evidencia que trae la entrega.
|
|
101
117
|
|
|
102
|
-
Si una entrega no cumple sus criterios:
|
|
118
|
+
Si una entrega no cumple sus criterios: usa \`task_revise\` con el \`task_id\` y un feedback concreto y accionable — el worker retoma con su contexto, no hace falta repetirle todo el pedido. Si el problema es trivial y tienes las tools, corrígelo tú directamente en vez de re-delegar. No inventes trabajo ni evidencia.
|
|
103
119
|
|
|
104
|
-
Cuando todo lo delegado en esta ronda cumple,
|
|
120
|
+
Cuando todo lo delegado en esta ronda cumple, escribe **una sola** respuesta final integrando todo. Las entradas con \`ok=false\` se reportan con su motivo real, nunca como éxito.
|
|
105
121
|
|
|
106
|
-
|
|
122
|
+
Guarda lo que vaya a servir después: \`save_note\` para esta conversación, \`memory_write\` para lo que deba sobrevivir a ella. Confirma con el usuario antes de persistir datos suyos.
|
|
107
123
|
|
|
108
124
|
## REGLAS PERMANENTES
|
|
109
125
|
|
|
110
|
-
1. **Ética primero** —
|
|
111
|
-
2. **Verdad de ejecución** — \`TaskDoc\`/\`JobDoc\` son la fuente de verdad. \`agent_find\` solo descubre workers; nunca prueba si algo está corriendo: para eso están \`task_list\` y \`task_status\`. Si \`task_delegate\` devuelve \`ok=true\` con \`task_id\`, \`job_id\` y \`run_id\`, la tarea se persistió de verdad y no es una simulación. Si una herramienta falla,
|
|
112
|
-
3. **
|
|
113
|
-
4. **
|
|
126
|
+
1. **Ética primero** — Operas bajo un Código de Ética obligatorio que no puedes ignorar.
|
|
127
|
+
2. **Verdad de ejecución** — \`TaskDoc\`/\`JobDoc\` son la fuente de verdad. \`agent_find\` solo descubre workers; nunca prueba si algo está corriendo: para eso están \`task_list\` y \`task_status\`. Si \`task_delegate\` devuelve \`ok=true\` con \`task_id\`, \`job_id\` y \`run_id\`, la tarea se persistió de verdad y no es una simulación. Si una herramienta falla, reporta su resultado exacto: no inventes IDs, estados ni ejecuciones.
|
|
128
|
+
3. **Tú aceptas las entregas** — cada entrega vuelve con sus criterios, su evidencia y el resultado de los checks determinísticos (ver sección 7). Si cumple, la integras; si no, \`task_revise\` con feedback concreto, o la corriges tú si es trivial. Si un worker devuelve \`needs_input\`, tú formulas la pregunta al usuario con contexto.
|
|
129
|
+
4. **Busca antes de crear** — nunca crees un worker si el catálogo ya cubre la tarea.
|
|
114
130
|
5. **Mínimo privilegio** — solo las herramientas necesarias a cada worker. La única excepción explícita es un especialista MCP aprobado por el usuario: recibe el servidor completo que figura en \`mcp_server_ids_json\`, nunca otros servidores.
|
|
115
|
-
6. **Nunca \`cli_exec\` para cron** —
|
|
131
|
+
6. **Nunca \`cli_exec\` para cron** — usa \`cron.create\`, y pregunta al usuario cada cuánto ejecutar.
|
|
116
132
|
7. **Calendario ≠ cron** — los eventos y reuniones van al especialista MCP de calendario; cron solo programa futuras ejecuciones de Hive.
|
|
117
133
|
|
|
118
134
|
## QUÉ HAY EN TU CONTEXTO
|
|
119
135
|
|
|
120
|
-
- **COLMENA DE AGENTES** — los workers disponibles ahora mismo.
|
|
121
|
-
- **HERRAMIENTAS SIEMPRE DISPONIBLES** — con las que
|
|
136
|
+
- **COLMENA DE AGENTES** — los workers disponibles ahora mismo. Consúltalo antes de decidir nada.
|
|
137
|
+
- **HERRAMIENTAS SIEMPRE DISPONIBLES** — con las que arrancas cada turno. El resto se descubre con \`search_knowledge\` y queda usable de inmediato.
|
|
122
138
|
- **SCRATCHPAD** — tus notas de esta conversación; sobreviven a la compresión del historial.
|
|
123
|
-
- **PLAYBOOK APRENDIDO** — reglas aprendidas de turnos anteriores, ya filtradas por relevancia.
|
|
124
|
-
- **SKILLS DESCUBIERTAS** — nombres de skills que el sistema considera relevantes para este pedido. Son una pista, no instrucciones: su contenido llega cuando
|
|
139
|
+
- **PLAYBOOK APRENDIDO** — reglas aprendidas de turnos anteriores, ya filtradas por relevancia. Aplícalas.
|
|
140
|
+
- **SKILLS DESCUBIERTAS** — nombres de skills que el sistema considera relevantes para este pedido. Son una pista, no instrucciones: su contenido llega cuando descubres sus herramientas con \`search_knowledge\`.
|
|
125
141
|
|
|
126
142
|
## CANALES
|
|
127
143
|
|
|
@@ -423,7 +439,7 @@ export async function propagateCoordinatorModel(
|
|
|
423
439
|
providerId: string,
|
|
424
440
|
modelId: string,
|
|
425
441
|
): Promise<number> {
|
|
426
|
-
const { applyCoordinatorModel } = await import("../agent/agent-catalog
|
|
442
|
+
const { applyCoordinatorModel } = await import("../agent/agent-catalog");
|
|
427
443
|
const updated = await applyCoordinatorModel({ userId, providerId, modelId, overwrite: true });
|
|
428
444
|
if (updated > 0) {
|
|
429
445
|
log.info(`✅ ${updated} agente(s) sincronizados con el modelo del coordinador`, { providerId, modelId });
|
|
@@ -100,7 +100,12 @@ export async function reconcileOnBoot(bootId: string): Promise<ReconcileResult>
|
|
|
100
100
|
result.runsInterrupted++;
|
|
101
101
|
try {
|
|
102
102
|
if (run.channel && run.user_id) {
|
|
103
|
-
await sendToUserChannel(
|
|
103
|
+
await sendToUserChannel(
|
|
104
|
+
run.channel,
|
|
105
|
+
run.user_id,
|
|
106
|
+
"Se interrumpió un turno en progreso por un reinicio del proceso.",
|
|
107
|
+
{ threadId: run.thread_id }
|
|
108
|
+
);
|
|
104
109
|
}
|
|
105
110
|
} catch {
|
|
106
111
|
// non-critical
|
|
@@ -57,6 +57,8 @@ export const SEED_DATA: SeedData = {
|
|
|
57
57
|
{ id: "computer_use_task", name: "computer_use_task", category: "web", description: "Operar el navegador de Hive mirando la pantalla: clic por coordenadas, escribir y navegar cuando no hay selector estable. Sinónimos: usar el navegador, hacer clic, operar una página, rellenar formulario, computer use" },
|
|
58
58
|
{ id: "artifact_inspect", name: "artifact_inspect", category: "web", description: "Inspeccionar integridad y metadatos de un artefacto administrado sin modificarlo. Sinónimos: inspeccionar artefacto, verificar archivo generado, metadatos artefacto, comprobar entrega" },
|
|
59
59
|
{ id: "artifact_read", name: "artifact_read", category: "web", description: "Leer por partes el contenido de texto de un artefacto administrado, o buscar dentro de él. Sinónimos: leer artefacto, ver contenido del artefacto, abrir resultado grande, buscar dentro del artefacto, leer artifact_ref" },
|
|
60
|
+
{ id: "image_metadata", name: "image_metadata", category: "images", description: "Leer dimensiones y formato de una imagen guardada sin cargarla al contexto. Sinónimos: medir imagen, dimensiones de la imagen, tamaño de la foto, formato de imagen" },
|
|
61
|
+
{ id: "image_transform", name: "image_transform", category: "images", description: "Redimensionar, rotar o convertir de formato una imagen guardada, devolviendo un artefacto nuevo. Sinónimos: redimensionar imagen, cambiar tamaño, convertir a webp, comprimir imagen, rotar foto, achicar imagen" },
|
|
60
62
|
{ id: "browser_click", name: "browser_click", category: "web", description: "Hacer clic en un elemento de la página web. Sinónimos: botón, enlace, interactuar, presionar, seleccionar" },
|
|
61
63
|
{ id: "browser_type", name: "browser_type", category: "web", description: "Escribir texto en un campo de formulario. Sinónimos: escribir formulario, tipear, campo de texto, input, llenar campo" },
|
|
62
64
|
{ id: "browser_extract", name: "browser_extract", category: "web", description: "Extraer texto, enlaces o datos estructurados usando selectores CSS o XPath. Sinónimos: obtener datos, scraping, selectores, extraer información" },
|
|
@@ -64,7 +66,7 @@ export const SEED_DATA: SeedData = {
|
|
|
64
66
|
{ id: "browser_wait", name: "browser_wait", category: "web", description: "Esperar a que aparezca un elemento o se cumpla una condición. Sinónimos: esperar, condición, elemento, selector, pausa" },
|
|
65
67
|
|
|
66
68
|
// ─────────────────────────────────────────
|
|
67
|
-
// 3. CRON — Tareas programadas
|
|
69
|
+
// 3. CRON — Tareas programadas
|
|
68
70
|
// ─────────────────────────────────────────
|
|
69
71
|
{ id: "cron.create", name: "cron.create", category: "cron", description: "Crear una automatización de Hive programada: recurrente (expresión cron) o ejecución futura única (fire_at). Requiere 'task'. Sinónimos: programar tarea, crear automatización, ejecutar después, tarea recurrente, una vez" },
|
|
70
72
|
{ id: "cron.list", name: "cron.list", category: "cron", description: "Listar todas las tareas programadas con próximos horarios de ejecución. Sinónimos: ver tareas programadas, listar cronograma, próximas ejecuciones" },
|
|
@@ -423,7 +425,9 @@ import { SkillLoader } from "../skills/index.ts"
|
|
|
423
425
|
import type {
|
|
424
426
|
ToolDoc, SkillDoc, EthicsDoc, ProviderDoc, ModelDoc, McpServerDoc, ChannelDoc, PlaybookDoc, AgentDoc,
|
|
425
427
|
} from "./collections.ts"
|
|
426
|
-
import { createSeedCatalogAgents, ensureAgentsConfigured } from "../agent/agent-catalog.ts"
|
|
428
|
+
import { createSeedCatalogAgents, ensureAgentsConfigured, requiredCapabilitiesFor } from "../agent/agent-catalog.ts"
|
|
429
|
+
import { MINIMAL_TOOLS } from "../agent/minimal-loadout.ts"
|
|
430
|
+
import { expandToolAllowlist } from "../agent/delegation-runtime.ts"
|
|
427
431
|
|
|
428
432
|
const log = logger.child("seed");
|
|
429
433
|
|
|
@@ -557,13 +561,19 @@ const LEGACY_CRON_PERSONA = {
|
|
|
557
561
|
function migrateLegacyCatalogPersona(existing: AgentDoc, current: AgentDoc): AgentDoc {
|
|
558
562
|
if (existing.id !== LEGACY_CRON_PERSONA.id || existing.source !== "catalog") return existing;
|
|
559
563
|
|
|
560
|
-
|
|
564
|
+
// `system_prompt` es nullable en AgentDoc y esto corre en cada arranque: una
|
|
565
|
+
// fila sin prompt hacía estallar el seed entero con un TypeError, no un error
|
|
566
|
+
// de datos. Sin prompt no hay nada que migrar, así que se devuelve tal cual.
|
|
567
|
+
if (existing.system_prompt === null) return existing;
|
|
568
|
+
|
|
569
|
+
let systemPrompt: string = existing.system_prompt;
|
|
570
|
+
const currentPrompt = current.system_prompt ?? "";
|
|
561
571
|
const hasLegacyStockPrompt = systemPrompt.includes(LEGACY_CRON_PERSONA.role)
|
|
562
572
|
&& systemPrompt.includes(LEGACY_CRON_PERSONA.receives);
|
|
563
573
|
if (hasLegacyStockPrompt) {
|
|
564
574
|
systemPrompt = systemPrompt
|
|
565
|
-
.replace(LEGACY_CRON_PERSONA.role,
|
|
566
|
-
.replace(LEGACY_CRON_PERSONA.receives,
|
|
575
|
+
.replace(LEGACY_CRON_PERSONA.role, currentPrompt.match(/# ROL\n([^\n]+)/)?.[1] ?? LEGACY_CRON_PERSONA.role)
|
|
576
|
+
.replace(LEGACY_CRON_PERSONA.receives, currentPrompt.match(/# QUÉ RECIBES\n([^\n]+)/)?.[1] ?? LEGACY_CRON_PERSONA.receives);
|
|
567
577
|
if (!systemPrompt.includes(LEGACY_CRON_PERSONA.calendarProhibition)) {
|
|
568
578
|
systemPrompt = systemPrompt.replace(
|
|
569
579
|
"- No hablás con el usuario",
|
|
@@ -621,7 +631,32 @@ async function pruneRetired(): Promise<void> {
|
|
|
621
631
|
if (removed > 0) log.info(`[seed] 🗑️ Removed ${removed} retired capability row(s)`);
|
|
622
632
|
}
|
|
623
633
|
|
|
624
|
-
|
|
634
|
+
/**
|
|
635
|
+
* Qué tools y skills deben nacer activas, según los especialistas elegidos.
|
|
636
|
+
*
|
|
637
|
+
* `null` = todas, que es el modo `"all"`. En cualquier otro modo la elección
|
|
638
|
+
* gobierna también las capacidades: un arranque `"none"` con las 62 tools
|
|
639
|
+
* activas sería contradecir el punto entero —ningún especialista instalado y
|
|
640
|
+
* todas las herramientas encendidas—, y el usuario terminaría apagándolas a
|
|
641
|
+
* mano una por una.
|
|
642
|
+
*
|
|
643
|
+
* Sólo afecta a las filas **nuevas**: `active` de una fila existente es la
|
|
644
|
+
* elección del usuario y sobrevive a todos los arranques.
|
|
645
|
+
*/
|
|
646
|
+
function capacidadesIniciales(
|
|
647
|
+
especialistas: SpecialistSeedMode,
|
|
648
|
+
): { tools: Set<string>; skills: Set<string> } | null {
|
|
649
|
+
if (especialistas === "all") return null
|
|
650
|
+
const elegidos = especialistas === "none" ? [] : especialistas
|
|
651
|
+
const { toolPatterns, skills } = requiredCapabilitiesFor(elegidos)
|
|
652
|
+
return {
|
|
653
|
+
tools: new Set([...MINIMAL_TOOLS, ...expandToolAllowlist(toolPatterns)]),
|
|
654
|
+
skills: new Set(skills),
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
async function reseedToolsAndSkills(especialistas: SpecialistSeedMode = "all"): Promise<void> {
|
|
659
|
+
const iniciales = capacidadesIniciales(especialistas);
|
|
625
660
|
// Seeding only writes the rows; the search index is rebuilt from them at
|
|
626
661
|
// startup by the sync pass in gateway/initializer.ts.
|
|
627
662
|
|
|
@@ -630,9 +665,17 @@ async function reseedToolsAndSkills(): Promise<void> {
|
|
|
630
665
|
const now = Date.now();
|
|
631
666
|
let toolCount = 0;
|
|
632
667
|
for (const tool of SEED_DATA.tools) {
|
|
668
|
+
// La descripción y la categoría vienen del código y se sobrescriben —son la
|
|
669
|
+
// fuente de verdad—, pero `active` NO: es la elección del usuario sobre qué
|
|
670
|
+
// capacidades quiere en su colmena (services/setup.ts). Pisarla en cada
|
|
671
|
+
// arranque haría que el seed selectivo durara hasta el próximo reinicio.
|
|
672
|
+
const existing = await toolsCol.get(tool.id);
|
|
633
673
|
await toolsCol.put(tool.id, {
|
|
634
674
|
id: tool.id, name: tool.name, description: tool.description, category: tool.category,
|
|
635
|
-
enabled:
|
|
675
|
+
enabled: existing?.doc.enabled ?? true,
|
|
676
|
+
active: existing?.doc.active ?? (iniciales ? iniciales.tools.has(tool.name) : true),
|
|
677
|
+
created_at: existing?.doc.created_at ?? now,
|
|
678
|
+
updated_at: now,
|
|
636
679
|
});
|
|
637
680
|
toolCount++;
|
|
638
681
|
}
|
|
@@ -646,6 +689,9 @@ async function reseedToolsAndSkills(): Promise<void> {
|
|
|
646
689
|
|
|
647
690
|
let skillCount = 0;
|
|
648
691
|
for (const s of realSkills) {
|
|
692
|
+
// Igual que con las tools: el contenido viene del archivo, pero `active` es
|
|
693
|
+
// del usuario y sobrevive al reseed.
|
|
694
|
+
const existingSkill = await skillsCol.get(s.name);
|
|
649
695
|
await skillsCol.put(s.name, {
|
|
650
696
|
id: s.name,
|
|
651
697
|
name: s.name,
|
|
@@ -661,8 +707,8 @@ async function reseedToolsAndSkills(): Promise<void> {
|
|
|
661
707
|
preferred_agents: JSON.stringify(s.preferred_agents || []),
|
|
662
708
|
body: s.content || "",
|
|
663
709
|
version_num: parseInt(String(s.version || "0.0.1").split(".")[0]) || 1,
|
|
664
|
-
active: true,
|
|
665
|
-
created_at: now,
|
|
710
|
+
active: existingSkill?.doc.active ?? (iniciales ? iniciales.skills.has(s.name) : true),
|
|
711
|
+
created_at: existingSkill?.doc.created_at ?? now,
|
|
666
712
|
updated_at: now,
|
|
667
713
|
});
|
|
668
714
|
skillCount++;
|
|
@@ -672,10 +718,30 @@ async function reseedToolsAndSkills(): Promise<void> {
|
|
|
672
718
|
await pruneRetired();
|
|
673
719
|
}
|
|
674
720
|
|
|
675
|
-
|
|
721
|
+
/**
|
|
722
|
+
* Qué especialistas del catálogo crear en el arranque.
|
|
723
|
+
*
|
|
724
|
+
* - `"all"` — los 8. Comportamiento histórico y default.
|
|
725
|
+
* - `"none"` — ninguno. La colmena arranca con el coordinador y nada más; los
|
|
726
|
+
* especialistas se crean cuando el usuario arma el enjambre que los pide.
|
|
727
|
+
* Es el modo para un producto donde cada quien elige su equipo.
|
|
728
|
+
* - lista — sólo esos.
|
|
729
|
+
*
|
|
730
|
+
* **Nunca borra.** Los que ya existen en la base se siguen reconciliando en
|
|
731
|
+
* cada arranque, elija lo que elija: una instalación que ya tiene sus ocho
|
|
732
|
+
* agentes no los pierde por cambiar esta opción.
|
|
733
|
+
*/
|
|
734
|
+
export type SpecialistSeedMode = "all" | "none" | string[]
|
|
735
|
+
|
|
736
|
+
export interface SeedOptions {
|
|
737
|
+
specialists?: SpecialistSeedMode
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
export async function seedAllData(opts?: SeedOptions): Promise<void> {
|
|
676
741
|
log.info("[seed] 🌱 Iniciando seed de datos predeterminados...")
|
|
742
|
+
const especialistas = opts?.specialists ?? "all"
|
|
677
743
|
|
|
678
|
-
await reseedToolsAndSkills();
|
|
744
|
+
await reseedToolsAndSkills(especialistas);
|
|
679
745
|
|
|
680
746
|
try {
|
|
681
747
|
const now = Date.now();
|
|
@@ -830,9 +896,22 @@ export async function seedAllData(): Promise<void> {
|
|
|
830
896
|
// factory values from older releases are migrated in place.
|
|
831
897
|
let catalogAgentCount = 0;
|
|
832
898
|
let repairedCatalogSkills = 0;
|
|
899
|
+
const quiereEspecialista = (id: string) =>
|
|
900
|
+
especialistas === "all" ? true
|
|
901
|
+
: especialistas === "none" ? false
|
|
902
|
+
: especialistas.includes(id);
|
|
903
|
+
|
|
833
904
|
for (const catalogAgent of createSeedCatalogAgents()) {
|
|
834
|
-
|
|
835
|
-
|
|
905
|
+
// Sembrar sólo los elegidos, pero seguir reconciliando los que ya
|
|
906
|
+
// existan: la elección gobierna qué se CREA, nunca qué se conserva. Una
|
|
907
|
+
// base que ya trae los ocho no los pierde por arrancar con "none", y
|
|
908
|
+
// tampoco se queda sin las migraciones de abajo.
|
|
909
|
+
let existing = await agentsCol.get(catalogAgent.id);
|
|
910
|
+
if (!existing) {
|
|
911
|
+
if (!quiereEspecialista(catalogAgent.id)) continue;
|
|
912
|
+
await putIfAbsent(agentsCol, catalogAgent.id, catalogAgent);
|
|
913
|
+
existing = await agentsCol.get(catalogAgent.id);
|
|
914
|
+
}
|
|
836
915
|
if (!existing || existing.doc.source !== "catalog") {
|
|
837
916
|
catalogAgentCount++;
|
|
838
917
|
continue;
|
|
@@ -925,12 +1004,17 @@ export async function seedAllData(): Promise<void> {
|
|
|
925
1004
|
const existing = byRule.get(rule.rule);
|
|
926
1005
|
if (existing) {
|
|
927
1006
|
await playbookCol.put(existing.id, {
|
|
928
|
-
|
|
1007
|
+
// `user_id: ""` va explícito y no heredado de `existing.doc`: en una
|
|
1008
|
+
// base anterior a este campo las filas sembradas no lo tienen, y son
|
|
1009
|
+
// justamente las que deben ser globales.
|
|
1010
|
+
...existing.doc, category: rule.category, applicable_to: rule.applicable_to, user_id: "", active: true, updated_at: now,
|
|
929
1011
|
}, { expectedVersion: existing.version });
|
|
930
1012
|
} else {
|
|
931
1013
|
const id = await nextId("playbook");
|
|
932
1014
|
await playbookCol.put(id, {
|
|
933
1015
|
id, rule: rule.rule, category: rule.category, applicable_to: rule.applicable_to,
|
|
1016
|
+
// Conocimiento del producto, no aprendido de nadie: aplica a todos.
|
|
1017
|
+
user_id: "",
|
|
934
1018
|
helpful_count: 1, harmful_count: 0, active: true,
|
|
935
1019
|
source_reflection_id: toIndexable(null), created_at: now, updated_at: now,
|
|
936
1020
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Hive Scheduler - Type Definitions
|
|
3
3
|
*
|
|
4
|
-
* Type interfaces for the
|
|
4
|
+
* Type interfaces for the scheduling system.
|
|
5
5
|
* All names use "CronJob" terminology (formerly ScheduledTask).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { Database } from "bun:sqlite";
|
|
9
|
-
import type { Cron } from "
|
|
9
|
+
import type { Cron } from "../scheduler/cron/index.ts";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Task type: recurring uses cron expression, one_shot uses fire_at
|
|
@@ -141,24 +141,9 @@ export interface CronJobExecutionResult {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
|
-
* Internal job wrapper holding
|
|
144
|
+
* Internal job wrapper holding the scheduled job and its metadata
|
|
145
145
|
*/
|
|
146
146
|
export interface CronJobEntry {
|
|
147
147
|
job: CronJob;
|
|
148
148
|
cron: Cron;
|
|
149
149
|
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Options for Croner job creation
|
|
153
|
-
*/
|
|
154
|
-
export interface CronerOptions {
|
|
155
|
-
timezone: string;
|
|
156
|
-
protect: boolean;
|
|
157
|
-
catch: boolean | ((error: Error) => void);
|
|
158
|
-
name: string;
|
|
159
|
-
maxRuns?: number;
|
|
160
|
-
interval?: number;
|
|
161
|
-
startAt?: string;
|
|
162
|
-
stopAt?: string;
|
|
163
|
-
domAndDow?: boolean;
|
|
164
|
-
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Auto-generado — NO EDITAR.
|
|
2
|
+
//
|
|
3
|
+
// En este paquete el valor es SIEMPRE null, y así debe quedarse: el SDK se
|
|
4
|
+
// publica como fuente, no como ejecutable standalone, así que el worker se
|
|
5
|
+
// resuelve desde disco (tool-worker.ts al lado de este archivo, o
|
|
6
|
+
// dist/tool-worker.js junto al bundle).
|
|
7
|
+
//
|
|
8
|
+
// El archivo existe porque el gateway de hive sí compila un binario, y ahí su
|
|
9
|
+
// `scripts/build-gateway.ts` reescribe este stub antes de compilar con:
|
|
10
|
+
//
|
|
11
|
+
// import workerFile from "./tool-worker.generated.js" with { type: "file" }
|
|
12
|
+
// export const embeddedToolWorkerPath: string | null = workerFile
|
|
13
|
+
//
|
|
14
|
+
// Ese `with { type: "file" }` es lo que mete el bundle del worker dentro del
|
|
15
|
+
// ejecutable, porque `new Worker(new URL("./tool-worker.ts", import.meta.url))`
|
|
16
|
+
// NO se embebe solo: el path se resuelve en runtime y el bundler no lo ve.
|
|
17
|
+
// Sin eso la app de escritorio se instalaba sin worker y cualquier turno con
|
|
18
|
+
// más de una tool call moría con "Tool worker entry not found" (v1.0.3 y
|
|
19
|
+
// anteriores). Mantener el símbolo acá deja que `tool-runtime/index.ts` sea el
|
|
20
|
+
// mismo archivo en los dos repos.
|
|
21
|
+
export const embeddedToolWorkerPath: string | null = null
|