@johpaz/hive-sdk 0.2.0 → 0.3.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/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/compaction.ts +20 -1
- package/packages/core/src/agent/context-compiler.ts +6 -3
- 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 +36 -1
- 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 +66 -1
- 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/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 +89 -11
- 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
|
|
|
@@ -621,7 +625,32 @@ async function pruneRetired(): Promise<void> {
|
|
|
621
625
|
if (removed > 0) log.info(`[seed] 🗑️ Removed ${removed} retired capability row(s)`);
|
|
622
626
|
}
|
|
623
627
|
|
|
624
|
-
|
|
628
|
+
/**
|
|
629
|
+
* Qué tools y skills deben nacer activas, según los especialistas elegidos.
|
|
630
|
+
*
|
|
631
|
+
* `null` = todas, que es el modo `"all"`. En cualquier otro modo la elección
|
|
632
|
+
* gobierna también las capacidades: un arranque `"none"` con las 62 tools
|
|
633
|
+
* activas sería contradecir el punto entero —ningún especialista instalado y
|
|
634
|
+
* todas las herramientas encendidas—, y el usuario terminaría apagándolas a
|
|
635
|
+
* mano una por una.
|
|
636
|
+
*
|
|
637
|
+
* Sólo afecta a las filas **nuevas**: `active` de una fila existente es la
|
|
638
|
+
* elección del usuario y sobrevive a todos los arranques.
|
|
639
|
+
*/
|
|
640
|
+
function capacidadesIniciales(
|
|
641
|
+
especialistas: SpecialistSeedMode,
|
|
642
|
+
): { tools: Set<string>; skills: Set<string> } | null {
|
|
643
|
+
if (especialistas === "all") return null
|
|
644
|
+
const elegidos = especialistas === "none" ? [] : especialistas
|
|
645
|
+
const { toolPatterns, skills } = requiredCapabilitiesFor(elegidos)
|
|
646
|
+
return {
|
|
647
|
+
tools: new Set([...MINIMAL_TOOLS, ...expandToolAllowlist(toolPatterns)]),
|
|
648
|
+
skills: new Set(skills),
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
async function reseedToolsAndSkills(especialistas: SpecialistSeedMode = "all"): Promise<void> {
|
|
653
|
+
const iniciales = capacidadesIniciales(especialistas);
|
|
625
654
|
// Seeding only writes the rows; the search index is rebuilt from them at
|
|
626
655
|
// startup by the sync pass in gateway/initializer.ts.
|
|
627
656
|
|
|
@@ -630,9 +659,17 @@ async function reseedToolsAndSkills(): Promise<void> {
|
|
|
630
659
|
const now = Date.now();
|
|
631
660
|
let toolCount = 0;
|
|
632
661
|
for (const tool of SEED_DATA.tools) {
|
|
662
|
+
// La descripción y la categoría vienen del código y se sobrescriben —son la
|
|
663
|
+
// fuente de verdad—, pero `active` NO: es la elección del usuario sobre qué
|
|
664
|
+
// capacidades quiere en su colmena (services/setup.ts). Pisarla en cada
|
|
665
|
+
// arranque haría que el seed selectivo durara hasta el próximo reinicio.
|
|
666
|
+
const existing = await toolsCol.get(tool.id);
|
|
633
667
|
await toolsCol.put(tool.id, {
|
|
634
668
|
id: tool.id, name: tool.name, description: tool.description, category: tool.category,
|
|
635
|
-
enabled:
|
|
669
|
+
enabled: existing?.doc.enabled ?? true,
|
|
670
|
+
active: existing?.doc.active ?? (iniciales ? iniciales.tools.has(tool.name) : true),
|
|
671
|
+
created_at: existing?.doc.created_at ?? now,
|
|
672
|
+
updated_at: now,
|
|
636
673
|
});
|
|
637
674
|
toolCount++;
|
|
638
675
|
}
|
|
@@ -646,6 +683,9 @@ async function reseedToolsAndSkills(): Promise<void> {
|
|
|
646
683
|
|
|
647
684
|
let skillCount = 0;
|
|
648
685
|
for (const s of realSkills) {
|
|
686
|
+
// Igual que con las tools: el contenido viene del archivo, pero `active` es
|
|
687
|
+
// del usuario y sobrevive al reseed.
|
|
688
|
+
const existingSkill = await skillsCol.get(s.name);
|
|
649
689
|
await skillsCol.put(s.name, {
|
|
650
690
|
id: s.name,
|
|
651
691
|
name: s.name,
|
|
@@ -661,8 +701,8 @@ async function reseedToolsAndSkills(): Promise<void> {
|
|
|
661
701
|
preferred_agents: JSON.stringify(s.preferred_agents || []),
|
|
662
702
|
body: s.content || "",
|
|
663
703
|
version_num: parseInt(String(s.version || "0.0.1").split(".")[0]) || 1,
|
|
664
|
-
active: true,
|
|
665
|
-
created_at: now,
|
|
704
|
+
active: existingSkill?.doc.active ?? (iniciales ? iniciales.skills.has(s.name) : true),
|
|
705
|
+
created_at: existingSkill?.doc.created_at ?? now,
|
|
666
706
|
updated_at: now,
|
|
667
707
|
});
|
|
668
708
|
skillCount++;
|
|
@@ -672,10 +712,30 @@ async function reseedToolsAndSkills(): Promise<void> {
|
|
|
672
712
|
await pruneRetired();
|
|
673
713
|
}
|
|
674
714
|
|
|
675
|
-
|
|
715
|
+
/**
|
|
716
|
+
* Qué especialistas del catálogo crear en el arranque.
|
|
717
|
+
*
|
|
718
|
+
* - `"all"` — los 8. Comportamiento histórico y default.
|
|
719
|
+
* - `"none"` — ninguno. La colmena arranca con el coordinador y nada más; los
|
|
720
|
+
* especialistas se crean cuando el usuario arma el enjambre que los pide.
|
|
721
|
+
* Es el modo para un producto donde cada quien elige su equipo.
|
|
722
|
+
* - lista — sólo esos.
|
|
723
|
+
*
|
|
724
|
+
* **Nunca borra.** Los que ya existen en la base se siguen reconciliando en
|
|
725
|
+
* cada arranque, elija lo que elija: una instalación que ya tiene sus ocho
|
|
726
|
+
* agentes no los pierde por cambiar esta opción.
|
|
727
|
+
*/
|
|
728
|
+
export type SpecialistSeedMode = "all" | "none" | string[]
|
|
729
|
+
|
|
730
|
+
export interface SeedOptions {
|
|
731
|
+
specialists?: SpecialistSeedMode
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
export async function seedAllData(opts?: SeedOptions): Promise<void> {
|
|
676
735
|
log.info("[seed] 🌱 Iniciando seed de datos predeterminados...")
|
|
736
|
+
const especialistas = opts?.specialists ?? "all"
|
|
677
737
|
|
|
678
|
-
await reseedToolsAndSkills();
|
|
738
|
+
await reseedToolsAndSkills(especialistas);
|
|
679
739
|
|
|
680
740
|
try {
|
|
681
741
|
const now = Date.now();
|
|
@@ -830,9 +890,22 @@ export async function seedAllData(): Promise<void> {
|
|
|
830
890
|
// factory values from older releases are migrated in place.
|
|
831
891
|
let catalogAgentCount = 0;
|
|
832
892
|
let repairedCatalogSkills = 0;
|
|
893
|
+
const quiereEspecialista = (id: string) =>
|
|
894
|
+
especialistas === "all" ? true
|
|
895
|
+
: especialistas === "none" ? false
|
|
896
|
+
: especialistas.includes(id);
|
|
897
|
+
|
|
833
898
|
for (const catalogAgent of createSeedCatalogAgents()) {
|
|
834
|
-
|
|
835
|
-
|
|
899
|
+
// Sembrar sólo los elegidos, pero seguir reconciliando los que ya
|
|
900
|
+
// existan: la elección gobierna qué se CREA, nunca qué se conserva. Una
|
|
901
|
+
// base que ya trae los ocho no los pierde por arrancar con "none", y
|
|
902
|
+
// tampoco se queda sin las migraciones de abajo.
|
|
903
|
+
let existing = await agentsCol.get(catalogAgent.id);
|
|
904
|
+
if (!existing) {
|
|
905
|
+
if (!quiereEspecialista(catalogAgent.id)) continue;
|
|
906
|
+
await putIfAbsent(agentsCol, catalogAgent.id, catalogAgent);
|
|
907
|
+
existing = await agentsCol.get(catalogAgent.id);
|
|
908
|
+
}
|
|
836
909
|
if (!existing || existing.doc.source !== "catalog") {
|
|
837
910
|
catalogAgentCount++;
|
|
838
911
|
continue;
|
|
@@ -925,12 +998,17 @@ export async function seedAllData(): Promise<void> {
|
|
|
925
998
|
const existing = byRule.get(rule.rule);
|
|
926
999
|
if (existing) {
|
|
927
1000
|
await playbookCol.put(existing.id, {
|
|
928
|
-
|
|
1001
|
+
// `user_id: ""` va explícito y no heredado de `existing.doc`: en una
|
|
1002
|
+
// base anterior a este campo las filas sembradas no lo tienen, y son
|
|
1003
|
+
// justamente las que deben ser globales.
|
|
1004
|
+
...existing.doc, category: rule.category, applicable_to: rule.applicable_to, user_id: "", active: true, updated_at: now,
|
|
929
1005
|
}, { expectedVersion: existing.version });
|
|
930
1006
|
} else {
|
|
931
1007
|
const id = await nextId("playbook");
|
|
932
1008
|
await playbookCol.put(id, {
|
|
933
1009
|
id, rule: rule.rule, category: rule.category, applicable_to: rule.applicable_to,
|
|
1010
|
+
// Conocimiento del producto, no aprendido de nadie: aplica a todos.
|
|
1011
|
+
user_id: "",
|
|
934
1012
|
helpful_count: 1, harmful_count: 0, active: true,
|
|
935
1013
|
source_reflection_id: toIndexable(null), created_at: now, updated_at: now,
|
|
936
1014
|
});
|
|
@@ -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
|