@johpaz/hive 2.0.1 → 2.0.3
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/README.md +16 -16
- package/dist/hive.js +457 -205
- package/package.json +1 -1
package/dist/hive.js
CHANGED
|
@@ -16589,6 +16589,7 @@ function ensureSchemaSync() {
|
|
|
16589
16589
|
if (_db) {
|
|
16590
16590
|
_db.query(`UPDATE providers SET base_url = 'https://api.groq.com/openai/v1' WHERE id = 'groq' AND base_url = 'https://api.groq.com/v1'`).run();
|
|
16591
16591
|
_db.query(`UPDATE providers SET base_url = 'https://api.openai.com/v1' WHERE id = 'openai' AND base_url = 'https://api.openai.com'`).run();
|
|
16592
|
+
_db.query(`UPDATE providers SET base_url = NULL WHERE id = 'gemini' AND base_url = 'https://generativelanguage.googleapis.com/v1beta'`).run();
|
|
16592
16593
|
}
|
|
16593
16594
|
}
|
|
16594
16595
|
|
|
@@ -19741,6 +19742,11 @@ function seedAllData() {
|
|
|
19741
19742
|
`).run(provider.id, provider.name, provider.baseUrl || null, provider.category || "llm");
|
|
19742
19743
|
providerCount++;
|
|
19743
19744
|
}
|
|
19745
|
+
const ollamaHost = process.env.OLLAMA_HOST;
|
|
19746
|
+
if (ollamaHost) {
|
|
19747
|
+
db.query(`UPDATE providers SET base_url = ? WHERE id = 'ollama'`).run(ollamaHost);
|
|
19748
|
+
log.info(`[seed] \u2705 Ollama base_url set to ${ollamaHost} (from OLLAMA_HOST env)`);
|
|
19749
|
+
}
|
|
19744
19750
|
log.info(`[seed] \u2705 ${providerCount} providers procesados`);
|
|
19745
19751
|
let modelCount = 0;
|
|
19746
19752
|
for (const model of SEED_DATA.models) {
|
|
@@ -19899,7 +19905,7 @@ var init_seed = __esm(() => {
|
|
|
19899
19905
|
providers: [
|
|
19900
19906
|
{ id: "anthropic", name: "Anthropic", baseUrl: "https://api.anthropic.com" },
|
|
19901
19907
|
{ id: "openai", name: "OpenAI", baseUrl: "https://api.openai.com/v1" },
|
|
19902
|
-
{ id: "gemini", name: "Google Gemini"
|
|
19908
|
+
{ id: "gemini", name: "Google Gemini" },
|
|
19903
19909
|
{ id: "mistral", name: "Mistral AI", baseUrl: "https://api.mistral.ai/v1" },
|
|
19904
19910
|
{ id: "deepseek", name: "DeepSeek", baseUrl: "https://api.deepseek.com/v1" },
|
|
19905
19911
|
{ id: "kimi", name: "Kimi (Moonshot)", baseUrl: "https://api.moonshot.ai/v1" },
|
|
@@ -20711,7 +20717,7 @@ Las 52 herramientas nativas se cargan din\xE1micamente desde la base de datos.
|
|
|
20711
20717
|
| \u23F0 CRON | 4 | cron_add, cron_list, cron_edit, cron_remove |
|
|
20712
20718
|
| \uD83D\uDCBB CLI | 1 | cli_exec |
|
|
20713
20719
|
| \uD83E\uDDE0 AGENTS | 14 | memory_*, agent_*, task_delegate, bus_*, project_updates |
|
|
20714
|
-
| \uD83C\uDFA8 CANVAS | 7 |
|
|
20720
|
+
| \uD83C\uDFA8 CANVAS | 7 | canvas_render(chart/table/form/button/alert-dialog/markdown/...), canvas_ask, canvas_confirm, canvas_show_card, canvas_show_progress |
|
|
20715
20721
|
| \uD83C\uDF09 CODEBRIDGE | 3 | codebridge_launch, codebridge_status, codebridge_cancel |
|
|
20716
20722
|
| \uD83C\uDF99\uFE0F VOICE | 2 | voice_transcribe, voice_speak |
|
|
20717
20723
|
| \uD83D\uDD14 CORE | 4 | search_knowledge, notify, save_note, report_progress |
|
|
@@ -22417,7 +22423,7 @@ function emitCanvas(type2, data) {
|
|
|
22417
22423
|
}
|
|
22418
22424
|
function getCanvasSnapshot() {
|
|
22419
22425
|
const db = getDb();
|
|
22420
|
-
const agentNodes = db.query("SELECT id, name, description, status FROM agents").all().map((a) => {
|
|
22426
|
+
const agentNodes = db.query("SELECT id, name, description, role, status FROM agents").all().map((a) => {
|
|
22421
22427
|
const live = agentLiveState.get(a.id);
|
|
22422
22428
|
return {
|
|
22423
22429
|
id: a.id,
|
|
@@ -22425,7 +22431,7 @@ function getCanvasSnapshot() {
|
|
|
22425
22431
|
description: a.description,
|
|
22426
22432
|
status: live?.status ?? a.status,
|
|
22427
22433
|
type: "agent",
|
|
22428
|
-
data: { currentTool: live?.currentTool ?? null }
|
|
22434
|
+
data: { role: a.role, currentTool: live?.currentTool ?? null }
|
|
22429
22435
|
};
|
|
22430
22436
|
});
|
|
22431
22437
|
const mcpNodes = db.query("SELECT id, name, status FROM mcp_servers WHERE enabled = 1").all().map((m) => ({
|
|
@@ -55275,7 +55281,7 @@ class OllamaProvider {
|
|
|
55275
55281
|
async call(options2) {
|
|
55276
55282
|
const { Ollama: Ollama3 } = await Promise.resolve().then(() => (init_dist3(), exports_dist2));
|
|
55277
55283
|
const modelName = options2.model.replace(/^ollama\//, "");
|
|
55278
|
-
const host = options2.baseUrl?.trim() || "http://localhost:11434";
|
|
55284
|
+
const host = options2.baseUrl?.trim() || process.env.OLLAMA_HOST || "http://localhost:11434";
|
|
55279
55285
|
try {
|
|
55280
55286
|
const isCloud = host.includes("ollama.com");
|
|
55281
55287
|
const headers = {};
|
|
@@ -313669,6 +313675,7 @@ class BrowserService {
|
|
|
313669
313675
|
const puppeteer3 = await Promise.resolve().then(() => (init_puppeteer2(), exports_puppeteer2));
|
|
313670
313676
|
this.browser = await puppeteer3.launch({
|
|
313671
313677
|
headless: true,
|
|
313678
|
+
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
|
|
313672
313679
|
args: [
|
|
313673
313680
|
"--no-sandbox",
|
|
313674
313681
|
"--disable-setuid-sandbox",
|
|
@@ -317924,12 +317931,12 @@ var init_canvas = __esm(() => {
|
|
|
317924
317931
|
log57 = logger.child("canvas");
|
|
317925
317932
|
canvasRenderTool = {
|
|
317926
317933
|
name: "canvas_render",
|
|
317927
|
-
description: "Render a component or visualization on the canvas. Spanish: renderizar, visualizar, gr\xE1fico, diagrama",
|
|
317934
|
+
description: "Render a component or visualization on the canvas. Use specific types instead of always using card+markdown. Key types: chart (bar/line/area/pie graphs), table (tabular data), markdown (rich text), form (interactive form - waits for submit), button (interactive button), alert-dialog (confirm/cancel dialog), progress (progress bars), accordion, tabs, badge, card, bee-loader. Spanish: renderizar, visualizar, gr\xE1fico, diagrama, tabla, formulario",
|
|
317928
317935
|
parameters: {
|
|
317929
317936
|
type: "object",
|
|
317930
317937
|
properties: {
|
|
317931
|
-
component: { type: "string", description: "Component type
|
|
317932
|
-
data: { type: "object", description: "
|
|
317938
|
+
component: { type: "string", description: "Component type. Visualization: chart, table, markdown, card, progress, accordion, tabs, badge, separator, bee-loader. Interactive: form, button, alert-dialog. Layout: carousel, collapsible, resizable, scroll-area, tabs. Other: alert, avatar, breadcrumb, calendar, checkbox, dialog, drawer, dropdown-menu, hover-card, input, input-otp, label, menubar, navigation-menu, pagination, popover, radio-group, select, sheet, skeleton, slider, switch, textarea, toggle, toggle-group, tooltip, aspect-ratio, command, context-menu, custom" },
|
|
317939
|
+
data: { type: "object", description: "Props for the component. chart: {type:'bar'|'line'|'area'|'pie', data:[{name,...}], xKey:'name', keys:['value'], title}. table: {title, columns:[{header,key}], data:[{}]}. form: {title, fields:[{name,label,type:'text'|'email'|'number'|'textarea'|'select'|'checkbox',placeholder,options:[{value,label}]}], submitLabel}. alert-dialog: {title, description, confirmLabel, cancelLabel}. button: {label, variant:'default'|'outline'|'secondary'|'destructive'}. markdown: {content}. progress: {value:0-100}." }
|
|
317933
317940
|
},
|
|
317934
317941
|
required: ["component", "data"]
|
|
317935
317942
|
},
|
|
@@ -318949,11 +318956,68 @@ ${scratchpadContent}
|
|
|
318949
318956
|
` + `- Playbook (buenas pr\xE1cticas): type="playbook"
|
|
318950
318957
|
` + `- Herramientas nativas espec\xEDficas: type="tools"
|
|
318951
318958
|
` + `Las herramientas MCP ya est\xE1n disponibles - no necesitas buscarlas.
|
|
318959
|
+
` + `
|
|
318960
|
+
## REGLA CR\xCDTICA \u2014 Delegaci\xF3n a workers
|
|
318961
|
+
` + `Los workers arrancan con herramientas m\xEDnimas (save_note, notify, report_progress, search_knowledge).
|
|
318962
|
+
` + `**ANTES de crear o delegar a un worker**, SIEMPRE debes:
|
|
318963
|
+
` + `1. Usar \`search_knowledge(type="tools", query="<tarea del worker>")\` para identificar qu\xE9 herramientas necesita.
|
|
318964
|
+
` + `2. Incluir esas herramientas en el campo \`tools\` al crear el agente con \`create_agent\`, o
|
|
318965
|
+
` + ` en el campo \`task_description\` de \`task_delegate\` como instrucci\xF3n expl\xEDcita:
|
|
318966
|
+
` + ` "Usa las herramientas: web_search, fs_read, ... para completar esta tarea."
|
|
318967
|
+
` + `3. El worker con esa instrucci\xF3n usar\xE1 \`search_knowledge\` para activar las tools por nombre.
|
|
318968
|
+
` + `Ejemplo: si el worker debe investigar en internet \u2192 busca "web search herramienta internet" \u2192 obtienes "web_search" \u2192 dile al worker que use web_search.
|
|
318969
|
+
`;
|
|
318970
|
+
systemPrompt += `
|
|
318971
|
+
|
|
318972
|
+
# \uD83C\uDFA8 CANVAS A2UI \u2014 Componentes disponibles para \`canvas_render\`
|
|
318973
|
+
` + `**REGLA**: Us\xE1 \`canvas_render\` con el tipo espec\xEDfico en vez de siempre usar \`canvas_show_card\` + markdown.
|
|
318974
|
+
|
|
318975
|
+
` + `## Tipos de visualizaci\xF3n:
|
|
318976
|
+
` + `- **chart** \u2014 Gr\xE1ficos. Props: \`{type:"bar"|"line"|"area"|"pie", data:[{name,...}], xKey:"name", keys:["valor"], colors:[], title}\`
|
|
318977
|
+
` + `- **table** \u2014 Tablas de datos. Props: \`{title, columns:[{header,key}], data:[{...}]}\`
|
|
318978
|
+
` + `- **progress** \u2014 Barras de progreso. Props: \`{bars:[{label,value:0-100}]}\`
|
|
318979
|
+
` + `- **markdown** \u2014 Texto rich. Props: \`{content:"## t\xEDtulo\\n..."}\`
|
|
318980
|
+
` + `- **card** \u2014 Tarjeta con items. Props: \`{title, description, items:[{label,value}], footer}\`
|
|
318981
|
+
` + `- **accordion** \u2014 Secciones colapsables. Props: \`{items:[{value,title,content}]}\`
|
|
318982
|
+
` + `- **tabs** \u2014 Pesta\xF1as. Props: \`{tabs:[{value,label,content}]}\`
|
|
318983
|
+
` + `- **badge** \u2014 Etiqueta. Props: \`{label, variant:"default"|"secondary"|"destructive"|"outline"}\`
|
|
318984
|
+
` + `- **separator** \u2014 L\xEDnea divisora
|
|
318985
|
+
` + `- **bee-loader** \u2014 Animaci\xF3n de carga. Props: \`{message}\`
|
|
318986
|
+
|
|
318987
|
+
` + `## Tipos interactivos (bloquean hasta respuesta del usuario):
|
|
318988
|
+
` + `- **form** \u2014 Formulario. Props: \`{title, fields:[{name,label,type,placeholder,options}], submitLabel}\`
|
|
318989
|
+
` + ` \u2192 Tipos de campo: \`text\`, \`email\`, \`number\`, \`textarea\`, \`select\`, \`checkbox\`
|
|
318990
|
+
` + ` \u2192 Al Submit recibir\xE1s: \`{data:{campo:valor,...}}\`
|
|
318991
|
+
` + `- **button** \u2014 Bot\xF3n clickeable. Props: \`{label, variant:"default"|"outline"|"secondary"|"destructive"}\`
|
|
318992
|
+
` + ` \u2192 Al click recibir\xE1s: \`{action:"click", data:{label}}\`
|
|
318993
|
+
` + `- **alert-dialog** \u2014 Confirmaci\xF3n. Props: \`{title, description, confirmLabel, cancelLabel}\`
|
|
318994
|
+
` + ` \u2192 Al confirmar recibir\xE1s: \`{data:{confirmed:true|false}}\`
|
|
318995
|
+
|
|
318996
|
+
` + `## Cu\xE1ndo usar cada uno:
|
|
318997
|
+
` + `- Estad\xEDsticas/datos num\xE9ricos \u2192 **chart** (bar/line/pie)
|
|
318998
|
+
` + `- Listas de filas/columnas \u2192 **table**
|
|
318999
|
+
` + `- Texto largo / an\xE1lisis \u2192 **markdown**
|
|
319000
|
+
` + `- Pedir datos al usuario \u2192 **canvas_ask** o **canvas_render con form**
|
|
319001
|
+
` + `- Confirmar acci\xF3n peligrosa \u2192 **canvas_confirm** o **canvas_render con alert-dialog**
|
|
319002
|
+
` + `- Mostrar progreso de tarea \u2192 **canvas_show_progress**
|
|
319003
|
+
|
|
319004
|
+
` + `## Ejemplos:
|
|
319005
|
+
` + `\`\`\`
|
|
319006
|
+
` + `canvas_render(component:"chart", data:{type:"bar", data:[{mes:"Ene",ventas:1200},{mes:"Feb",ventas:1800}], xKey:"mes", keys:["ventas"], title:"Ventas por mes"})
|
|
319007
|
+
` + `canvas_render(component:"table", data:{title:"Archivos", columns:[{header:"Nombre",key:"name"},{header:"Tama\xF1o",key:"size"}], data:[{name:"app.ts",size:"12KB"}]})
|
|
319008
|
+
` + `canvas_render(component:"form", data:{title:"Configuraci\xF3n", fields:[{name:"nombre",label:"Nombre",type:"text"},{name:"tipo",label:"Tipo",type:"select",options:[{value:"a",label:"A"},{value:"b",label:"B"}]}], submitLabel:"Guardar"})
|
|
319009
|
+
` + `\`\`\`
|
|
318952
319010
|
`;
|
|
318953
319011
|
}
|
|
318954
319012
|
if (isWorker && opts.taskContext) {
|
|
318955
319013
|
systemPrompt += `
|
|
318956
319014
|
|
|
319015
|
+
# HERRAMIENTAS DISPONIBLES
|
|
319016
|
+
` + `Arrancas con herramientas b\xE1sicas. Si tu tarea requiere herramientas adicionales (web_search, fs_read, browser_navigate, etc.):
|
|
319017
|
+
` + `1. Us\xE1 \`search_knowledge(type="tools", query="<herramienta o tarea>")\` para encontrarlas.
|
|
319018
|
+
` + `2. Las herramientas que encuentres estar\xE1n disponibles para usar inmediatamente.
|
|
319019
|
+
` + `Si el coordinador te indic\xF3 herramientas espec\xEDficas, buscalas primero con search_knowledge antes de ejecutar tu tarea.
|
|
319020
|
+
` + `
|
|
318957
319021
|
# CURRENT TASK
|
|
318958
319022
|
${opts.taskContext}
|
|
318959
319023
|
|
|
@@ -555613,7 +555677,7 @@ var init_initializer = __esm(() => {
|
|
|
555613
555677
|
});
|
|
555614
555678
|
|
|
555615
555679
|
// packages/core/src/gateway/routes/setup.ts
|
|
555616
|
-
import {
|
|
555680
|
+
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync9 } from "fs";
|
|
555617
555681
|
function isSetupMode() {
|
|
555618
555682
|
try {
|
|
555619
555683
|
const count = getDb().query("SELECT COUNT(*) as count FROM users").get().count;
|
|
@@ -555679,18 +555743,19 @@ async function handleVerifyProvider(req) {
|
|
|
555679
555743
|
let headers = {};
|
|
555680
555744
|
const testMessages = [{ role: "user", content: "Say 'ok' if you can read this." }];
|
|
555681
555745
|
if (provider === "ollama") {
|
|
555746
|
+
const ollamaUrl = process.env.OLLAMA_HOST || "http://localhost:11434";
|
|
555682
555747
|
try {
|
|
555683
|
-
const response2 = await fetch(
|
|
555748
|
+
const response2 = await fetch(`${ollamaUrl}/api/tags`, {
|
|
555684
555749
|
signal: AbortSignal.timeout(5000)
|
|
555685
555750
|
});
|
|
555686
555751
|
return Response.json({
|
|
555687
555752
|
success: response2.ok,
|
|
555688
|
-
error: response2.ok ? null :
|
|
555753
|
+
error: response2.ok ? null : `Could not connect to Ollama at ${ollamaUrl}`
|
|
555689
555754
|
});
|
|
555690
555755
|
} catch {
|
|
555691
555756
|
return Response.json({
|
|
555692
555757
|
success: false,
|
|
555693
|
-
error:
|
|
555758
|
+
error: `Could not connect to Ollama at ${ollamaUrl}`
|
|
555694
555759
|
});
|
|
555695
555760
|
}
|
|
555696
555761
|
}
|
|
@@ -555813,21 +555878,20 @@ async function handleCompleteSetup(req, config3, addCorsHeaders) {
|
|
|
555813
555878
|
const body = await req.json().catch(() => ({}));
|
|
555814
555879
|
try {
|
|
555815
555880
|
initOnboardingDb();
|
|
555816
|
-
const userId =
|
|
555817
|
-
const agentId = `agent_${randomUUID2().split("-")[0]}`;
|
|
555818
|
-
const channelUserId = randomUUID2();
|
|
555819
|
-
saveUserProfile({
|
|
555820
|
-
userId,
|
|
555881
|
+
const userId = saveUserProfile({
|
|
555821
555882
|
userName: body.userName || "User",
|
|
555822
555883
|
userLanguage: body.userLanguage || "es",
|
|
555823
555884
|
userTimezone: body.userTimezone || "UTC",
|
|
555824
555885
|
userOccupation: body.userOccupation || "",
|
|
555825
|
-
userNotes: body.userNotes || ""
|
|
555886
|
+
userNotes: body.userNotes || ""
|
|
555887
|
+
});
|
|
555888
|
+
const agentId = saveAgentConfig({
|
|
555889
|
+
userId,
|
|
555826
555890
|
agentName: body.agentName || "Bee",
|
|
555827
|
-
|
|
555828
|
-
|
|
555829
|
-
|
|
555830
|
-
|
|
555891
|
+
description: body.agentDescription || "",
|
|
555892
|
+
tone: "friendly",
|
|
555893
|
+
providerId: body.provider || "",
|
|
555894
|
+
modelId: body.model || ""
|
|
555831
555895
|
});
|
|
555832
555896
|
if (body.provider && body.apiKey) {
|
|
555833
555897
|
await saveProviderConfig({
|
|
@@ -555839,7 +555903,6 @@ async function handleCompleteSetup(req, config3, addCorsHeaders) {
|
|
|
555839
555903
|
}
|
|
555840
555904
|
await activateChannel(userId, {
|
|
555841
555905
|
channelId: "webchat",
|
|
555842
|
-
channelUserId,
|
|
555843
555906
|
config: {}
|
|
555844
555907
|
});
|
|
555845
555908
|
if (body.channels) {
|
|
@@ -555869,7 +555932,19 @@ async function handleCompleteSetup(req, config3, addCorsHeaders) {
|
|
|
555869
555932
|
} else {
|
|
555870
555933
|
activateEthics(userId, "default");
|
|
555871
555934
|
}
|
|
555872
|
-
const authToken =
|
|
555935
|
+
const authToken = userId;
|
|
555936
|
+
const hiveDir = getHiveDir();
|
|
555937
|
+
const envContent = [
|
|
555938
|
+
"# Hive configuration \u2014 auto-generated during setup",
|
|
555939
|
+
`HIVE_HOST=${process.env.HIVE_HOST || "0.0.0.0"}`,
|
|
555940
|
+
`HIVE_PORT=${process.env.HIVE_PORT || "18790"}`,
|
|
555941
|
+
`HIVE_LOG_LEVEL=${process.env.HIVE_LOG_LEVEL || "info"}`,
|
|
555942
|
+
`HIVE_AUTH_TOKEN=${authToken}`,
|
|
555943
|
+
""
|
|
555944
|
+
].join(`
|
|
555945
|
+
`);
|
|
555946
|
+
mkdirSync9(hiveDir, { recursive: true });
|
|
555947
|
+
writeFileSync4(`${hiveDir}/.env`, envContent, { mode: 384 });
|
|
555873
555948
|
process.env.HIVE_AUTH_TOKEN = authToken;
|
|
555874
555949
|
setTimeout(() => process.exit(0), 800);
|
|
555875
555950
|
return addCorsHeaders(Response.json({
|
|
@@ -555890,6 +555965,7 @@ var init_setup = __esm(() => {
|
|
|
555890
555965
|
init_sqlite();
|
|
555891
555966
|
init_seed();
|
|
555892
555967
|
init_onboarding();
|
|
555968
|
+
init_loader();
|
|
555893
555969
|
});
|
|
555894
555970
|
|
|
555895
555971
|
// packages/core/src/gateway/routes/agents.ts
|
|
@@ -556159,7 +556235,7 @@ async function handleSyncProviderModels(req, addCorsHeaders, providerId) {
|
|
|
556159
556235
|
if (!providerRow) {
|
|
556160
556236
|
return addCorsHeaders(new Response("Provider not found", { status: 404 }), req);
|
|
556161
556237
|
}
|
|
556162
|
-
const baseUrl = (providerRow.base_url || "http://localhost:11434").replace(/\/(v1|api)\/?$/, "");
|
|
556238
|
+
const baseUrl = (providerRow.base_url || process.env.OLLAMA_HOST || "http://localhost:11434").replace(/\/(v1|api)\/?$/, "");
|
|
556163
556239
|
try {
|
|
556164
556240
|
const res = await fetch(`${baseUrl}/api/tags`);
|
|
556165
556241
|
if (!res.ok) {
|
|
@@ -556382,8 +556458,8 @@ async function handleCreateSkill(req, addCorsHeaders) {
|
|
|
556382
556458
|
if (!name) {
|
|
556383
556459
|
return addCorsHeaders(new Response("Missing name", { status: 400 }), req);
|
|
556384
556460
|
}
|
|
556385
|
-
const { randomUUID:
|
|
556386
|
-
const id =
|
|
556461
|
+
const { randomUUID: randomUUID2 } = await import("crypto");
|
|
556462
|
+
const id = randomUUID2();
|
|
556387
556463
|
getDb().query(`INSERT INTO skills(id, name, category, tools, triggers, body, version, active) VALUES(?, ?, ?, ?, ?, ?, 1, 1)`).run(id, name, category || "", tools || "", triggers || "", bodyContent || "", 1);
|
|
556388
556464
|
return addCorsHeaders(Response.json({ success: true, id }), req);
|
|
556389
556465
|
}
|
|
@@ -556739,8 +556815,8 @@ async function handleCreateChannel(req, addCorsHeaders, channelManager) {
|
|
|
556739
556815
|
id = seeded.id;
|
|
556740
556816
|
getDb().query(`UPDATE channels SET config_encrypted = ?, config_iv = ?, enabled = 1, active = 1, status = 'connecting' WHERE id = ?`).run(encryptedData, configIv, id);
|
|
556741
556817
|
} else {
|
|
556742
|
-
const { randomUUID:
|
|
556743
|
-
id =
|
|
556818
|
+
const { randomUUID: randomUUID2 } = await import("crypto");
|
|
556819
|
+
id = randomUUID2();
|
|
556744
556820
|
getDb().query(`
|
|
556745
556821
|
INSERT INTO channels(id, type, config_encrypted, config_iv, enabled, active, status)
|
|
556746
556822
|
VALUES(?, ?, ?, ?, 1, 1, 'connecting')
|
|
@@ -557321,6 +557397,96 @@ var init_voice3 = __esm(() => {
|
|
|
557321
557397
|
init_crypto();
|
|
557322
557398
|
});
|
|
557323
557399
|
|
|
557400
|
+
// packages/core/package.json
|
|
557401
|
+
var package_default;
|
|
557402
|
+
var init_package = __esm(() => {
|
|
557403
|
+
package_default = {
|
|
557404
|
+
name: "@johpaz/hive-core",
|
|
557405
|
+
version: "2.0.3",
|
|
557406
|
+
private: true,
|
|
557407
|
+
description: "Hive Gateway \u2014 Personal AI agent runtime",
|
|
557408
|
+
main: "./src/index.ts",
|
|
557409
|
+
module: "./src/index.ts",
|
|
557410
|
+
types: "./src/index.ts",
|
|
557411
|
+
license: "MIT",
|
|
557412
|
+
files: [
|
|
557413
|
+
"src/"
|
|
557414
|
+
],
|
|
557415
|
+
scripts: {
|
|
557416
|
+
test: "bun test",
|
|
557417
|
+
typecheck: "tsc --noEmit"
|
|
557418
|
+
},
|
|
557419
|
+
dependencies: {
|
|
557420
|
+
"@ag-ui/core": "^0.0.46",
|
|
557421
|
+
"@johpaz/hive-code-bridge": "^2.0.3",
|
|
557422
|
+
"@johpaz/hive-mcp": "^2.0.3",
|
|
557423
|
+
"@johpaz/hive-skills": "^2.0.3",
|
|
557424
|
+
"@modelcontextprotocol/sdk": "latest",
|
|
557425
|
+
"@sapphire/snowflake": "latest",
|
|
557426
|
+
"@slack/bolt": "latest",
|
|
557427
|
+
"@whiskeysockets/baileys": "latest",
|
|
557428
|
+
croner: "^10.0.1",
|
|
557429
|
+
"discord.js": "latest",
|
|
557430
|
+
grammy: "latest",
|
|
557431
|
+
"js-yaml": "latest",
|
|
557432
|
+
puppeteer: "^24.39.1",
|
|
557433
|
+
"qrcode-terminal": "latest",
|
|
557434
|
+
"toon-format-parser": "1.1.4",
|
|
557435
|
+
zod: "latest"
|
|
557436
|
+
},
|
|
557437
|
+
devDependencies: {
|
|
557438
|
+
typescript: "6.0.1-rc",
|
|
557439
|
+
"@types/bun": "latest"
|
|
557440
|
+
},
|
|
557441
|
+
exports: {
|
|
557442
|
+
".": "./src/index.ts",
|
|
557443
|
+
"./gateway": "./src/gateway/index.ts",
|
|
557444
|
+
"./agent": "./src/agent/index.ts",
|
|
557445
|
+
"./agent/service": "./src/agent/service.ts",
|
|
557446
|
+
"./agent/agent-loop": "./src/agent/agent-loop.ts",
|
|
557447
|
+
"./agent/context-compiler": "./src/agent/context-compiler.ts",
|
|
557448
|
+
"./agent/prompt-builder": "./src/agent/prompt-builder.ts",
|
|
557449
|
+
"./agent/conversation-store": "./src/agent/conversation-store.ts",
|
|
557450
|
+
"./agent/tool-selector": "./src/agent/tool-selector.ts",
|
|
557451
|
+
"./agent/skill-selector": "./src/agent/skill-selector.ts",
|
|
557452
|
+
"./agent/playbook-selector": "./src/agent/playbook-selector.ts",
|
|
557453
|
+
"./agent/llm-client": "./src/agent/llm-client.ts",
|
|
557454
|
+
"./channels": "./src/channels/index.ts",
|
|
557455
|
+
"./channels/base": "./src/channels/base.ts",
|
|
557456
|
+
"./channels/manager": "./src/channels/manager.ts",
|
|
557457
|
+
"./channels/telegram": "./src/channels/telegram.ts",
|
|
557458
|
+
"./channels/discord": "./src/channels/discord.ts",
|
|
557459
|
+
"./channels/whatsapp": "./src/channels/whatsapp.ts",
|
|
557460
|
+
"./channels/slack": "./src/channels/slack.ts",
|
|
557461
|
+
"./channels/webchat": "./src/channels/webchat.ts",
|
|
557462
|
+
"./config": "./src/config/loader.ts",
|
|
557463
|
+
"./config/loader": "./src/config/loader.ts",
|
|
557464
|
+
"./utils": "./src/utils/logger.ts",
|
|
557465
|
+
"./utils/logger": "./src/utils/logger.ts",
|
|
557466
|
+
"./storage/sqlite": "./src/storage/sqlite.ts",
|
|
557467
|
+
"./storage/onboarding": "./src/storage/onboarding.ts",
|
|
557468
|
+
"./storage/crypto": "./src/storage/crypto.ts",
|
|
557469
|
+
"./storage/schema": "./src/storage/schema.ts",
|
|
557470
|
+
"./storage/seed": "./src/storage/seed.ts",
|
|
557471
|
+
"./tools": "./src/tools/index.ts",
|
|
557472
|
+
"./tools/agents": "./src/tools/agents/index.ts",
|
|
557473
|
+
"./tools/canvas": "./src/tools/canvas/index.ts",
|
|
557474
|
+
"./tools/cli": "./src/tools/cli/index.ts",
|
|
557475
|
+
"./tools/codebridge": "./src/tools/codebridge/index.ts",
|
|
557476
|
+
"./tools/core": "./src/tools/core/index.ts",
|
|
557477
|
+
"./tools/cron": "./src/tools/cron/index.ts",
|
|
557478
|
+
"./tools/filesystem": "./src/tools/filesystem/index.ts",
|
|
557479
|
+
"./tools/projects": "./src/tools/projects/index.ts",
|
|
557480
|
+
"./tools/voice": "./src/tools/voice/index.ts",
|
|
557481
|
+
"./tools/web": "./src/tools/web/index.ts",
|
|
557482
|
+
"./integrations": "./src/integrations/index.ts",
|
|
557483
|
+
"./integrations/catalog": "./src/integrations/catalog.ts",
|
|
557484
|
+
"./integrations/env": "./src/integrations/env.ts",
|
|
557485
|
+
"./voice": "./src/voice/index.ts"
|
|
557486
|
+
}
|
|
557487
|
+
};
|
|
557488
|
+
});
|
|
557489
|
+
|
|
557324
557490
|
// packages/core/src/gateway/routes/system.ts
|
|
557325
557491
|
import { cpus } from "os";
|
|
557326
557492
|
function detectInstallationType() {
|
|
@@ -557664,10 +557830,12 @@ async function handleApiReload(req, addCorsHeaders, agent) {
|
|
|
557664
557830
|
return addCorsHeaders(Response.json({ success: false, error: error50.message }, { status: 500 }), req);
|
|
557665
557831
|
}
|
|
557666
557832
|
}
|
|
557667
|
-
var CURRENT_VERSION
|
|
557833
|
+
var CURRENT_VERSION;
|
|
557668
557834
|
var init_system = __esm(() => {
|
|
557669
557835
|
init_sqlite();
|
|
557670
557836
|
init_loader();
|
|
557837
|
+
init_package();
|
|
557838
|
+
CURRENT_VERSION = package_default.version;
|
|
557671
557839
|
});
|
|
557672
557840
|
|
|
557673
557841
|
// packages/core/src/agent/providers.ts
|
|
@@ -557867,7 +558035,7 @@ async function handleGetConfig(req, addCorsHeaders, config3) {
|
|
|
557867
558035
|
var init_config = () => {};
|
|
557868
558036
|
|
|
557869
558037
|
// packages/core/src/gateway/routes/workspace.ts
|
|
557870
|
-
import { mkdirSync as
|
|
558038
|
+
import { mkdirSync as mkdirSync10, existsSync as existsSync17, accessSync as accessSync2, constants as constants2 } from "fs";
|
|
557871
558039
|
import * as path28 from "path";
|
|
557872
558040
|
import { exec as exec2 } from "child_process";
|
|
557873
558041
|
import { promisify as promisify4 } from "util";
|
|
@@ -557946,7 +558114,7 @@ async function handleCreateWorkspace(req, addCorsHeaders) {
|
|
|
557946
558114
|
error: "El path debe ser absoluto"
|
|
557947
558115
|
}), req);
|
|
557948
558116
|
}
|
|
557949
|
-
|
|
558117
|
+
mkdirSync10(workspacePath, { recursive: true });
|
|
557950
558118
|
return addCorsHeaders(Response.json({
|
|
557951
558119
|
ok: true,
|
|
557952
558120
|
path: workspacePath,
|
|
@@ -558022,7 +558190,7 @@ Define ethical guidelines here.`
|
|
|
558022
558190
|
async function handleUpdateWorkspace(req, addCorsHeaders, workspacePath, wsType, reloadFn) {
|
|
558023
558191
|
const content = await req.text();
|
|
558024
558192
|
const filePath = path28.join(workspacePath, `${wsType.toUpperCase()}.md`);
|
|
558025
|
-
|
|
558193
|
+
mkdirSync10(workspacePath, { recursive: true });
|
|
558026
558194
|
await Bun.write(filePath, content);
|
|
558027
558195
|
if (reloadFn) {
|
|
558028
558196
|
await reloadFn(wsType);
|
|
@@ -558129,32 +558297,56 @@ var init_helpers2 = __esm(() => {
|
|
|
558129
558297
|
init_cors();
|
|
558130
558298
|
});
|
|
558131
558299
|
|
|
558300
|
+
// packages/core/src/tools/cron/index.ts
|
|
558301
|
+
function resolveBestChannel(userId, notifyChannelId) {
|
|
558302
|
+
if (notifyChannelId)
|
|
558303
|
+
return notifyChannelId;
|
|
558304
|
+
try {
|
|
558305
|
+
const db = getDb();
|
|
558306
|
+
const identities = db.query("SELECT channel FROM user_identities WHERE user_id = ? ORDER BY channel ASC LIMIT 5").all(userId);
|
|
558307
|
+
const preferred = ["telegram", "discord", "slack", "whatsapp"];
|
|
558308
|
+
for (const p2 of preferred) {
|
|
558309
|
+
if (identities.some((i2) => i2.channel === p2))
|
|
558310
|
+
return p2;
|
|
558311
|
+
}
|
|
558312
|
+
} catch {}
|
|
558313
|
+
return "webchat";
|
|
558314
|
+
}
|
|
558315
|
+
var log67, activeJobs;
|
|
558316
|
+
var init_cron2 = __esm(() => {
|
|
558317
|
+
init_sqlite();
|
|
558318
|
+
init_logger();
|
|
558319
|
+
init_croner();
|
|
558320
|
+
log67 = logger.child("cron");
|
|
558321
|
+
activeJobs = new Map;
|
|
558322
|
+
});
|
|
558323
|
+
|
|
558132
558324
|
// packages/core/src/scheduler/integration.ts
|
|
558133
558325
|
function setSchedulerForCleanup(scheduler) {
|
|
558134
558326
|
_scheduler2 = scheduler;
|
|
558135
558327
|
}
|
|
558136
558328
|
async function executeScheduledTask(task) {
|
|
558137
|
-
|
|
558329
|
+
log68.info(`[execute] Processing task "${task.name}" (${task.id})`);
|
|
558138
558330
|
try {
|
|
558139
558331
|
let payload;
|
|
558140
558332
|
try {
|
|
558141
558333
|
payload = JSON.parse(task.payload);
|
|
558142
558334
|
} catch (err) {
|
|
558143
|
-
|
|
558335
|
+
log68.error(`[execute] Invalid payload JSON for task "${task.id}": ${err.message}`);
|
|
558144
558336
|
return { success: false, error: "Invalid payload JSON" };
|
|
558145
558337
|
}
|
|
558146
558338
|
const prompt = payload.prompt || payload.message;
|
|
558147
558339
|
if (!prompt && !payload._internal) {
|
|
558148
|
-
|
|
558340
|
+
log68.error(`[execute] Task "${task.id}" has no prompt or message in payload`);
|
|
558149
558341
|
return { success: false, error: "Missing prompt or message in payload" };
|
|
558150
558342
|
}
|
|
558151
558343
|
if (payload._internal === true && payload.action === "cleanup") {
|
|
558152
558344
|
if (_scheduler2) {
|
|
558153
558345
|
_scheduler2.runCleanup();
|
|
558154
558346
|
} else {
|
|
558155
|
-
|
|
558347
|
+
log68.warn("[execute] Cleanup task fired but scheduler instance not available");
|
|
558156
558348
|
}
|
|
558157
|
-
|
|
558349
|
+
log68.info("[execute] Cleanup task executed");
|
|
558158
558350
|
return { success: true, response: "Cleanup completed" };
|
|
558159
558351
|
}
|
|
558160
558352
|
const metadata = {
|
|
@@ -558168,7 +558360,7 @@ async function executeScheduledTask(task) {
|
|
|
558168
558360
|
let targetAgentId = task.agent_id || null;
|
|
558169
558361
|
if (!targetAgentId) {
|
|
558170
558362
|
targetAgentId = resolveAgentId(null);
|
|
558171
|
-
|
|
558363
|
+
log68.debug(`[execute] No agent specified, routing to Coordinator: ${targetAgentId}`);
|
|
558172
558364
|
}
|
|
558173
558365
|
const db = getDb();
|
|
558174
558366
|
const user = db.query("SELECT id, timezone, language FROM users LIMIT 1").get();
|
|
@@ -558197,16 +558389,17 @@ Type: ${task.task_type}
|
|
|
558197
558389
|
Triggered at: ${hora_usuario} on ${fecha_usuario} (${userTimezone})
|
|
558198
558390
|
|
|
558199
558391
|
${prompt || `Execute tool: ${task.tool_name}`}`;
|
|
558200
|
-
|
|
558392
|
+
log68.debug(`[execute] Sending to agent ${targetAgentId}: "${contextPrompt.slice(0, 100)}..."`);
|
|
558201
558393
|
try {
|
|
558202
558394
|
const agentLoop = buildAgentLoop({ mcpManager: undefined });
|
|
558203
558395
|
const sessionId = `sched_${task.id}_${Date.now()}`;
|
|
558396
|
+
const agentChannel = task.channel && task.channel !== "system" ? task.channel : resolveBestChannel(user?.id || "");
|
|
558204
558397
|
const messages2 = [{ role: "user", content: contextPrompt }];
|
|
558205
558398
|
const stream = agentLoop.stream({ messages: messages2 }, {
|
|
558206
558399
|
configurable: {
|
|
558207
558400
|
thread_id: sessionId,
|
|
558208
558401
|
agent_id: targetAgentId || undefined,
|
|
558209
|
-
channel:
|
|
558402
|
+
channel: agentChannel,
|
|
558210
558403
|
user_id: user?.id || "",
|
|
558211
558404
|
system_prompt: undefined,
|
|
558212
558405
|
raw_user_message: contextPrompt
|
|
@@ -558233,20 +558426,20 @@ ${prompt || `Execute tool: ${task.tool_name}`}`;
|
|
|
558233
558426
|
if (hasError && !response) {
|
|
558234
558427
|
throw new Error("Agent execution returned errors");
|
|
558235
558428
|
}
|
|
558236
|
-
|
|
558429
|
+
log68.info(`[execute] Agent response received for task "${task.name}"`);
|
|
558237
558430
|
return {
|
|
558238
558431
|
success: true,
|
|
558239
558432
|
response: response || "Task executed successfully"
|
|
558240
558433
|
};
|
|
558241
558434
|
} catch (agentErr) {
|
|
558242
|
-
|
|
558435
|
+
log68.error(`[execute] Agent execution failed: ${agentErr.message}`);
|
|
558243
558436
|
return {
|
|
558244
558437
|
success: false,
|
|
558245
558438
|
error: `Agent execution failed: ${agentErr.message}`
|
|
558246
558439
|
};
|
|
558247
558440
|
}
|
|
558248
558441
|
} catch (err) {
|
|
558249
|
-
|
|
558442
|
+
log68.error(`[execute] Task execution failed: ${err.message}`);
|
|
558250
558443
|
return {
|
|
558251
558444
|
success: false,
|
|
558252
558445
|
error: err.message
|
|
@@ -558257,19 +558450,20 @@ async function notifyTaskCompletion(taskId, taskName, success2, response, error5
|
|
|
558257
558450
|
const db = getDb();
|
|
558258
558451
|
const task = db.query("SELECT channel, agent_id FROM scheduled_tasks WHERE id = ?").get(taskId);
|
|
558259
558452
|
if (!task) {
|
|
558260
|
-
|
|
558261
|
-
return;
|
|
558262
|
-
}
|
|
558263
|
-
if (task.channel === "system") {
|
|
558264
|
-
log67.debug(`[notify] Skipping notification for system channel`);
|
|
558453
|
+
log68.warn(`[notify] Task "${taskId}" not found`);
|
|
558265
558454
|
return;
|
|
558266
558455
|
}
|
|
558267
558456
|
const userRow = db.query("SELECT id FROM users LIMIT 1").get();
|
|
558268
558457
|
const userId = userRow?.id || "";
|
|
558269
|
-
const
|
|
558270
|
-
|
|
558271
|
-
|
|
558272
|
-
|
|
558458
|
+
const activeChannels = db.query(`
|
|
558459
|
+
SELECT ui.channel FROM user_identities ui
|
|
558460
|
+
JOIN channels c ON c.id = ui.channel
|
|
558461
|
+
WHERE ui.user_id = ? AND c.active = 1 AND c.status = 'connected'
|
|
558462
|
+
`).all(userId);
|
|
558463
|
+
const identities = activeChannels.length > 0 ? activeChannels : db.query("SELECT channel FROM user_identities WHERE user_id = ?").all(userId);
|
|
558464
|
+
const preferred = ["telegram", "discord", "slack", "whatsapp", "webchat"];
|
|
558465
|
+
let notifyChannel = task.channel && task.channel !== "system" ? task.channel : "";
|
|
558466
|
+
if (!notifyChannel || !identities.some((i2) => i2.channel === notifyChannel)) {
|
|
558273
558467
|
for (const p2 of preferred) {
|
|
558274
558468
|
if (identities.some((i2) => i2.channel === p2)) {
|
|
558275
558469
|
notifyChannel = p2;
|
|
@@ -558277,25 +558471,34 @@ async function notifyTaskCompletion(taskId, taskName, success2, response, error5
|
|
|
558277
558471
|
}
|
|
558278
558472
|
}
|
|
558279
558473
|
}
|
|
558474
|
+
if (!notifyChannel || notifyChannel === "system")
|
|
558475
|
+
notifyChannel = "webchat";
|
|
558280
558476
|
const status = success2 ? "\u2705" : "\u274C";
|
|
558281
558477
|
const message = success2 ? `${status} Scheduled task "${taskName}" completed
|
|
558282
558478
|
${response || ""}` : `${status} Scheduled task "${taskName}" failed
|
|
558283
558479
|
${error50 || ""}`;
|
|
558284
|
-
|
|
558480
|
+
log68.info(`[notify] Sending notification to ${notifyChannel}: "${message.slice(0, 50)}..."`);
|
|
558481
|
+
try {
|
|
558482
|
+
addMessage(userId, "assistant", message, { channel: notifyChannel });
|
|
558483
|
+
} catch (e) {
|
|
558484
|
+
log68.warn(`[notify] Failed to persist notification to DB: ${e.message}`);
|
|
558485
|
+
}
|
|
558285
558486
|
await sendToUserChannel(notifyChannel, userId, message);
|
|
558286
|
-
|
|
558487
|
+
log68.info(`[notify] Notification sent to ${notifyChannel}`);
|
|
558287
558488
|
}
|
|
558288
558489
|
function createTaskHandler() {
|
|
558289
558490
|
return executeScheduledTask;
|
|
558290
558491
|
}
|
|
558291
|
-
var
|
|
558492
|
+
var log68, _scheduler2 = null;
|
|
558292
558493
|
var init_integration = __esm(() => {
|
|
558293
558494
|
init_logger();
|
|
558294
558495
|
init_sqlite();
|
|
558295
558496
|
init_agent_loop();
|
|
558296
558497
|
init_onboarding();
|
|
558297
558498
|
init_channel_notify();
|
|
558298
|
-
|
|
558499
|
+
init_conversation_store();
|
|
558500
|
+
init_cron2();
|
|
558501
|
+
log68 = logger.child("SchedulerIntegration");
|
|
558299
558502
|
});
|
|
558300
558503
|
|
|
558301
558504
|
// packages/core/src/scheduler/CronScheduler.ts
|
|
@@ -558315,7 +558518,7 @@ class CronScheduler {
|
|
|
558315
558518
|
for (const task of tasks) {
|
|
558316
558519
|
this.activate(task);
|
|
558317
558520
|
}
|
|
558318
|
-
|
|
558521
|
+
log69.info(`[boot] Loaded ${tasks.length} active task(s)`);
|
|
558319
558522
|
this.ensureCleanupTask();
|
|
558320
558523
|
}
|
|
558321
558524
|
activate(task) {
|
|
@@ -558323,23 +558526,23 @@ class CronScheduler {
|
|
|
558323
558526
|
if (existingJob) {
|
|
558324
558527
|
existingJob.stop();
|
|
558325
558528
|
this.jobs.delete(task.id);
|
|
558326
|
-
|
|
558529
|
+
log69.debug(`[activate] Stopped existing job for task "${task.name}" (${task.id})`);
|
|
558327
558530
|
}
|
|
558328
558531
|
if (task.status === "paused" || task.status === "completed" || task.status === "cancelled") {
|
|
558329
|
-
|
|
558532
|
+
log69.debug(`[activate] Skipping task "${task.name}" (${task.id}) - status: ${task.status}`);
|
|
558330
558533
|
return;
|
|
558331
558534
|
}
|
|
558332
558535
|
try {
|
|
558333
558536
|
let pattern;
|
|
558334
558537
|
if (task.task_type === "recurring") {
|
|
558335
558538
|
if (!task.cron_expression) {
|
|
558336
|
-
|
|
558539
|
+
log69.error(`[activate] Task "${task.name}" (${task.id}) is recurring but has no cron_expression`);
|
|
558337
558540
|
return;
|
|
558338
558541
|
}
|
|
558339
558542
|
pattern = task.cron_expression;
|
|
558340
558543
|
} else {
|
|
558341
558544
|
if (!task.fire_at) {
|
|
558342
|
-
|
|
558545
|
+
log69.error(`[activate] Task "${task.name}" (${task.id}) is one_shot but has no fire_at`);
|
|
558343
558546
|
return;
|
|
558344
558547
|
}
|
|
558345
558548
|
pattern = task.fire_at;
|
|
@@ -558347,7 +558550,7 @@ class CronScheduler {
|
|
|
558347
558550
|
try {
|
|
558348
558551
|
new E(pattern);
|
|
558349
558552
|
} catch (err) {
|
|
558350
|
-
|
|
558553
|
+
log69.error(`[activate] Invalid cron pattern "${pattern}" for task "${task.name}": ${err.message}`);
|
|
558351
558554
|
return;
|
|
558352
558555
|
}
|
|
558353
558556
|
const options2 = {
|
|
@@ -558368,26 +558571,26 @@ class CronScheduler {
|
|
|
558368
558571
|
if (nextRun) {
|
|
558369
558572
|
const nextRunIso = nextRun.toISOString();
|
|
558370
558573
|
this.db.query("UPDATE scheduled_tasks SET next_run_at = ? WHERE id = ?").run(nextRunIso, task.id);
|
|
558371
|
-
|
|
558574
|
+
log69.info(`[activate] Task "${task.name}" (${task.id}) scheduled - next: ${nextRunIso}`);
|
|
558372
558575
|
} else {
|
|
558373
|
-
|
|
558576
|
+
log69.warn(`[activate] Task "${task.name}" (${task.id}) has no next run date`);
|
|
558374
558577
|
}
|
|
558375
558578
|
} catch (err) {
|
|
558376
|
-
|
|
558579
|
+
log69.error(`[activate] Failed to activate task "${task.name}" (${task.id}): ${err.message}`);
|
|
558377
558580
|
}
|
|
558378
558581
|
}
|
|
558379
558582
|
async execute(task) {
|
|
558380
558583
|
const runId = crypto.randomUUID().replace(/-/g, "").slice(0, 16);
|
|
558381
558584
|
const startedAt = new Date().toISOString();
|
|
558382
558585
|
const startTime2 = performance.now();
|
|
558383
|
-
|
|
558586
|
+
log69.info(`[execute] Starting task "${task.name}" (${task.id}) run #${runId}`);
|
|
558384
558587
|
try {
|
|
558385
558588
|
this.db.query(`
|
|
558386
558589
|
INSERT INTO task_runs (id, task_id, status, started_at, payload_snapshot)
|
|
558387
558590
|
VALUES (?, ?, 'running', ?, ?)
|
|
558388
558591
|
`).run(runId, task.id, startedAt, task.payload);
|
|
558389
558592
|
} catch (err) {
|
|
558390
|
-
|
|
558593
|
+
log69.error(`[execute] Failed to create task_run record: ${err.message}`);
|
|
558391
558594
|
}
|
|
558392
558595
|
try {
|
|
558393
558596
|
const result2 = await this.handler(task);
|
|
@@ -558419,9 +558622,9 @@ class CronScheduler {
|
|
|
558419
558622
|
WHERE id = ?
|
|
558420
558623
|
`).run(finishedAt, task.id);
|
|
558421
558624
|
this.deactivate(task.id);
|
|
558422
|
-
|
|
558625
|
+
log69.info(`[execute] One-shot task "${task.name}" (${task.id}) completed`);
|
|
558423
558626
|
} else {
|
|
558424
|
-
|
|
558627
|
+
log69.info(`[execute] Task "${task.name}" (${task.id}) completed in ${Math.round(duration3)}ms`);
|
|
558425
558628
|
}
|
|
558426
558629
|
} else {
|
|
558427
558630
|
throw new Error(result2.error || "Handler reported failure");
|
|
@@ -558440,12 +558643,12 @@ class CronScheduler {
|
|
|
558440
558643
|
SET error_count = error_count + 1, last_error = ?
|
|
558441
558644
|
WHERE id = ?
|
|
558442
558645
|
`).run(errorMessage, task.id);
|
|
558443
|
-
|
|
558646
|
+
log69.error(`[execute] Task "${task.name}" (${task.id}) failed: ${errorMessage}`);
|
|
558444
558647
|
await notifyTaskCompletion(task.id, task.name, false, undefined, errorMessage);
|
|
558445
558648
|
}
|
|
558446
558649
|
}
|
|
558447
558650
|
handleError(task, error50) {
|
|
558448
|
-
|
|
558651
|
+
log69.error(`[error] Task "${task.name}" (${task.id}) error: ${error50.message}`);
|
|
558449
558652
|
this.db.query(`
|
|
558450
558653
|
UPDATE scheduled_tasks
|
|
558451
558654
|
SET error_count = error_count + 1, last_error = ?
|
|
@@ -558459,21 +558662,21 @@ class CronScheduler {
|
|
|
558459
558662
|
}
|
|
558460
558663
|
const result2 = this.db.query("UPDATE scheduled_tasks SET status = 'paused' WHERE id = ?").run(taskId);
|
|
558461
558664
|
if (result2.changes > 0) {
|
|
558462
|
-
|
|
558665
|
+
log69.info(`[pause] Task "${taskId}" paused`);
|
|
558463
558666
|
return true;
|
|
558464
558667
|
}
|
|
558465
|
-
|
|
558668
|
+
log69.warn(`[pause] Task "${taskId}" not found`);
|
|
558466
558669
|
return false;
|
|
558467
558670
|
}
|
|
558468
558671
|
resume(taskId) {
|
|
558469
558672
|
const task = this.db.query("SELECT * FROM scheduled_tasks WHERE id = ?").get(taskId);
|
|
558470
558673
|
if (!task) {
|
|
558471
|
-
|
|
558674
|
+
log69.warn(`[resume] Task "${taskId}" not found`);
|
|
558472
558675
|
return false;
|
|
558473
558676
|
}
|
|
558474
558677
|
this.db.query("UPDATE scheduled_tasks SET status = 'active' WHERE id = ?").run(taskId);
|
|
558475
558678
|
this.activate(task);
|
|
558476
|
-
|
|
558679
|
+
log69.info(`[resume] Task "${taskId}" resumed`);
|
|
558477
558680
|
return true;
|
|
558478
558681
|
}
|
|
558479
558682
|
deactivate(taskId) {
|
|
@@ -558481,17 +558684,17 @@ class CronScheduler {
|
|
|
558481
558684
|
if (job) {
|
|
558482
558685
|
job.stop();
|
|
558483
558686
|
this.jobs.delete(taskId);
|
|
558484
|
-
|
|
558687
|
+
log69.debug(`[deactivate] Task "${taskId}" deactivated`);
|
|
558485
558688
|
}
|
|
558486
558689
|
}
|
|
558487
558690
|
delete(taskId) {
|
|
558488
558691
|
this.deactivate(taskId);
|
|
558489
558692
|
const result2 = this.db.query("DELETE FROM scheduled_tasks WHERE id = ?").run(taskId);
|
|
558490
558693
|
if (result2.changes > 0) {
|
|
558491
|
-
|
|
558694
|
+
log69.info(`[delete] Task "${taskId}" deleted`);
|
|
558492
558695
|
return true;
|
|
558493
558696
|
}
|
|
558494
|
-
|
|
558697
|
+
log69.warn(`[delete] Task "${taskId}" not found`);
|
|
558495
558698
|
return false;
|
|
558496
558699
|
}
|
|
558497
558700
|
create(input2) {
|
|
@@ -558538,13 +558741,13 @@ class CronScheduler {
|
|
|
558538
558741
|
this.activate(task);
|
|
558539
558742
|
const job = this.jobs.get(id);
|
|
558540
558743
|
const nextRun = job?.nextRun()?.toISOString();
|
|
558541
|
-
|
|
558744
|
+
log69.info(`[create] Task "${input2.name}" (${id}) created`);
|
|
558542
558745
|
return { id, nextRun };
|
|
558543
558746
|
}
|
|
558544
558747
|
update(taskId, changes) {
|
|
558545
558748
|
const task = this.db.query("SELECT * FROM scheduled_tasks WHERE id = ?").get(taskId);
|
|
558546
558749
|
if (!task) {
|
|
558547
|
-
|
|
558750
|
+
log69.warn(`[update] Task "${taskId}" not found`);
|
|
558548
558751
|
return false;
|
|
558549
558752
|
}
|
|
558550
558753
|
const fields = [];
|
|
@@ -558612,7 +558815,7 @@ class CronScheduler {
|
|
|
558612
558815
|
this.db.query(`UPDATE scheduled_tasks SET ${fields.join(", ")} WHERE id = ?`).run(...values2);
|
|
558613
558816
|
const updatedTask = this.db.query("SELECT * FROM scheduled_tasks WHERE id = ?").get(taskId);
|
|
558614
558817
|
this.activate(updatedTask);
|
|
558615
|
-
|
|
558818
|
+
log69.info(`[update] Task "${taskId}" updated`);
|
|
558616
558819
|
return true;
|
|
558617
558820
|
}
|
|
558618
558821
|
getStatus() {
|
|
@@ -558631,16 +558834,16 @@ class CronScheduler {
|
|
|
558631
558834
|
trigger(taskId) {
|
|
558632
558835
|
const task = this.db.query("SELECT * FROM scheduled_tasks WHERE id = ?").get(taskId);
|
|
558633
558836
|
if (!task) {
|
|
558634
|
-
|
|
558837
|
+
log69.warn(`[trigger] Task "${taskId}" not found`);
|
|
558635
558838
|
return false;
|
|
558636
558839
|
}
|
|
558637
558840
|
const job = this.jobs.get(taskId);
|
|
558638
558841
|
if (!job) {
|
|
558639
|
-
|
|
558842
|
+
log69.warn(`[trigger] Task "${taskId}" has no active job`);
|
|
558640
558843
|
return false;
|
|
558641
558844
|
}
|
|
558642
558845
|
job.trigger();
|
|
558643
|
-
|
|
558846
|
+
log69.info(`[trigger] Task "${taskId}" manually triggered`);
|
|
558644
558847
|
return true;
|
|
558645
558848
|
}
|
|
558646
558849
|
shutdown() {
|
|
@@ -558648,13 +558851,13 @@ class CronScheduler {
|
|
|
558648
558851
|
job.stop();
|
|
558649
558852
|
}
|
|
558650
558853
|
this.jobs.clear();
|
|
558651
|
-
|
|
558854
|
+
log69.info("[shutdown] All jobs stopped");
|
|
558652
558855
|
}
|
|
558653
558856
|
ensureCleanupTask() {
|
|
558654
558857
|
const existing = this.db.query("SELECT id FROM scheduled_tasks WHERE name = '_hive_cleanup_runs'").get();
|
|
558655
558858
|
if (existing) {
|
|
558656
558859
|
this.cleanupTaskId = existing.id;
|
|
558657
|
-
|
|
558860
|
+
log69.debug("[ensureCleanupTask] Cleanup task already exists");
|
|
558658
558861
|
return;
|
|
558659
558862
|
}
|
|
558660
558863
|
try {
|
|
@@ -558668,9 +558871,9 @@ class CronScheduler {
|
|
|
558668
558871
|
protect: true
|
|
558669
558872
|
});
|
|
558670
558873
|
this.cleanupTaskId = result2.id;
|
|
558671
|
-
|
|
558874
|
+
log69.info("[ensureCleanupTask] Cleanup task created");
|
|
558672
558875
|
} catch (err) {
|
|
558673
|
-
|
|
558876
|
+
log69.error(`[ensureCleanupTask] Failed to create cleanup task: ${err.message}`);
|
|
558674
558877
|
}
|
|
558675
558878
|
}
|
|
558676
558879
|
runCleanup() {
|
|
@@ -558700,7 +558903,7 @@ class CronScheduler {
|
|
|
558700
558903
|
)
|
|
558701
558904
|
`).run(task_id, task_id);
|
|
558702
558905
|
}
|
|
558703
|
-
|
|
558906
|
+
log69.info("[runCleanup] Cleanup completed");
|
|
558704
558907
|
}
|
|
558705
558908
|
getHistory(taskId, limit2 = 50) {
|
|
558706
558909
|
return this.db.query(`
|
|
@@ -558720,12 +558923,12 @@ class CronScheduler {
|
|
|
558720
558923
|
return this.db.query("SELECT * FROM scheduled_tasks ORDER BY next_run_at").all();
|
|
558721
558924
|
}
|
|
558722
558925
|
}
|
|
558723
|
-
var
|
|
558926
|
+
var log69;
|
|
558724
558927
|
var init_CronScheduler = __esm(() => {
|
|
558725
558928
|
init_croner();
|
|
558726
558929
|
init_logger();
|
|
558727
558930
|
init_integration();
|
|
558728
|
-
|
|
558931
|
+
log69 = logger.child("CronScheduler");
|
|
558729
558932
|
});
|
|
558730
558933
|
|
|
558731
558934
|
// packages/core/src/gateway/routes/scheduled-tasks.ts
|
|
@@ -559013,10 +559216,10 @@ var init_scheduled_tasks = __esm(() => {
|
|
|
559013
559216
|
});
|
|
559014
559217
|
|
|
559015
559218
|
// packages/core/src/gateway/server.ts
|
|
559016
|
-
import { unlinkSync as unlinkSync4, existsSync as existsSync18 } from "fs";
|
|
559219
|
+
import { mkdirSync as mkdirSync11, unlinkSync as unlinkSync4, existsSync as existsSync18, writeFileSync as writeFileSync5, readFileSync as readFileSync9 } from "fs";
|
|
559017
559220
|
import * as path30 from "path";
|
|
559018
559221
|
import { cpus as osCpus } from "os";
|
|
559019
|
-
import { randomUUID as
|
|
559222
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
559020
559223
|
async function startGateway(config3) {
|
|
559021
559224
|
const host = config3.gateway?.host ?? "127.0.0.1";
|
|
559022
559225
|
const port = config3.gateway?.port ?? 18790;
|
|
@@ -559025,9 +559228,25 @@ async function startGateway(config3) {
|
|
|
559025
559228
|
const numCores = osCpus().length || 1;
|
|
559026
559229
|
let lastCpuSample = process.cpuUsage();
|
|
559027
559230
|
let lastCpuSampleTime = Date.now();
|
|
559028
|
-
const
|
|
559231
|
+
const log70 = logger.child("gateway");
|
|
559029
559232
|
const mcpLog2 = logger.child("mcp:api");
|
|
559030
|
-
|
|
559233
|
+
log70.info(`Starting gateway on ${host}:${port}`);
|
|
559234
|
+
const tokenFile = path30.join(getHiveDir(), ".auth_token");
|
|
559235
|
+
if (!process.env.HIVE_AUTH_TOKEN) {
|
|
559236
|
+
if (existsSync18(tokenFile)) {
|
|
559237
|
+
process.env.HIVE_AUTH_TOKEN = readFileSync9(tokenFile, "utf-8").trim();
|
|
559238
|
+
log70.info("\uD83D\uDD11 Auth token loaded from persistent storage");
|
|
559239
|
+
} else {
|
|
559240
|
+
const generated = randomUUID2().replace(/-/g, "");
|
|
559241
|
+
process.env.HIVE_AUTH_TOKEN = generated;
|
|
559242
|
+
mkdirSync11(path30.dirname(tokenFile), { recursive: true });
|
|
559243
|
+
writeFileSync5(tokenFile, generated, { mode: 384 });
|
|
559244
|
+
log70.info("\uD83D\uDD11 Auth token auto-generated and persisted");
|
|
559245
|
+
}
|
|
559246
|
+
} else {
|
|
559247
|
+
writeFileSync5(tokenFile, process.env.HIVE_AUTH_TOKEN, { mode: 384 });
|
|
559248
|
+
log70.info("\uD83D\uDD11 Auth token loaded from environment variable");
|
|
559249
|
+
}
|
|
559031
559250
|
let agent;
|
|
559032
559251
|
let runner;
|
|
559033
559252
|
let channelManager;
|
|
@@ -559056,7 +559275,7 @@ async function startGateway(config3) {
|
|
|
559056
559275
|
},
|
|
559057
559276
|
websocket: { open() {}, message() {}, close() {} }
|
|
559058
559277
|
});
|
|
559059
|
-
|
|
559278
|
+
log70.info(`Port ${port} bound (initializing gateway...)`);
|
|
559060
559279
|
try {
|
|
559061
559280
|
initializeDatabase();
|
|
559062
559281
|
seedAllData();
|
|
@@ -559079,9 +559298,9 @@ async function startGateway(config3) {
|
|
|
559079
559298
|
await channelManager.send(channel, sessionId, { content, type: "progress" });
|
|
559080
559299
|
});
|
|
559081
559300
|
if (gatewaySetupMode) {
|
|
559082
|
-
|
|
559301
|
+
log70.info("\uD83C\uDF89 Setup mode: gateway running \u2014 open http://localhost:" + port + "/setup to configure");
|
|
559083
559302
|
} else {
|
|
559084
|
-
|
|
559303
|
+
log70.info("\u2705 Gateway initialization completed successfully");
|
|
559085
559304
|
try {
|
|
559086
559305
|
const db = getDb();
|
|
559087
559306
|
db.query(`
|
|
@@ -559095,18 +559314,18 @@ async function startGateway(config3) {
|
|
|
559095
559314
|
setSchedulerInstance(scheduler);
|
|
559096
559315
|
setSchedulerInstance2(scheduler);
|
|
559097
559316
|
setSchedulerForCleanup(scheduler);
|
|
559098
|
-
|
|
559317
|
+
log70.info(`\uD83D\uDCC5 CronScheduler initialized with ${scheduler.getStatus().length} task(s)`);
|
|
559099
559318
|
} catch (err) {
|
|
559100
|
-
|
|
559319
|
+
log70.error(`\u274C CronScheduler initialization failed: ${err.message}`);
|
|
559101
559320
|
}
|
|
559102
559321
|
}
|
|
559103
559322
|
} catch (error50) {
|
|
559104
|
-
|
|
559105
|
-
|
|
559323
|
+
log70.error(`\u274C Gateway initialization failed: ${error50.message}`);
|
|
559324
|
+
log70.error("Stack trace:", error50.stack);
|
|
559106
559325
|
process.exit(1);
|
|
559107
559326
|
}
|
|
559108
559327
|
if (host === "0.0.0.0" && config3.security?.warnOnInsecureConfig !== false) {
|
|
559109
|
-
|
|
559328
|
+
log70.warn("Gateway binding to 0.0.0.0 exposes server to all network interfaces!");
|
|
559110
559329
|
}
|
|
559111
559330
|
function prepareTools(agentInstance, sessionId) {
|
|
559112
559331
|
return;
|
|
@@ -559114,17 +559333,17 @@ async function startGateway(config3) {
|
|
|
559114
559333
|
const watchers = [];
|
|
559115
559334
|
if (!gatewaySetupMode)
|
|
559116
559335
|
channelManager.onMessage(async (message) => {
|
|
559117
|
-
|
|
559118
|
-
|
|
559336
|
+
log70.info(`\uD83D\uDCE5 Message from ${message.channel}:${message.accountId}`);
|
|
559337
|
+
log70.info(` Session: ${message.sessionId}`);
|
|
559119
559338
|
const voiceConfig = voiceService.getChannelVoiceConfig(message.channel);
|
|
559120
559339
|
let messageContent = message.content;
|
|
559121
559340
|
let preferAudioResponse = false;
|
|
559122
559341
|
let inputType = "text";
|
|
559123
559342
|
let sttProviderUsed = null;
|
|
559124
559343
|
if (voiceConfig.voiceEnabled && message.audio) {
|
|
559125
|
-
|
|
559344
|
+
log70.info(`\uD83C\uDF99\uFE0F Voice enabled, processing audio...`);
|
|
559126
559345
|
if (!voiceConfig.sttProvider) {
|
|
559127
|
-
|
|
559346
|
+
log70.warn(`\u26A0\uFE0F STT provider not configured for channel ${message.channel}`);
|
|
559128
559347
|
await channelManager.send(message.channel, message.sessionId, {
|
|
559129
559348
|
content: `\uD83C\uDF99\uFE0F Para usar notas de voz, necesitas configurar el proveedor STT en la configuraci\xF3n del canal. Ve a Configuraci\xF3n > Canales > [Tu canal] y configura "Prov. STT" (ej: groq-whisper o openai)`
|
|
559130
559349
|
});
|
|
@@ -559134,7 +559353,7 @@ async function startGateway(config3) {
|
|
|
559134
559353
|
const audioInput = voiceService.normalizeAudioFromChannel(message.channel, message.audio);
|
|
559135
559354
|
sttProviderUsed = voiceConfig.sttProvider || "groq-whisper";
|
|
559136
559355
|
messageContent = await voiceService.transcribe(audioInput, sttProviderUsed);
|
|
559137
|
-
|
|
559356
|
+
log70.info(`\uD83D\uDCDD Transcribed: ${messageContent.substring(0, 100)}...`);
|
|
559138
559357
|
inputType = "audio_transcribed";
|
|
559139
559358
|
preferAudioResponse = !!voiceConfig.ttsProvider;
|
|
559140
559359
|
await channelManager.send(message.channel, message.sessionId, {
|
|
@@ -559142,14 +559361,14 @@ async function startGateway(config3) {
|
|
|
559142
559361
|
type: "message"
|
|
559143
559362
|
});
|
|
559144
559363
|
} catch (error50) {
|
|
559145
|
-
|
|
559364
|
+
log70.error(`\u274C Transcription failed: ${error50.message}`);
|
|
559146
559365
|
await channelManager.send(message.channel, message.sessionId, {
|
|
559147
559366
|
content: `Error al transcribir audio: ${error50.message}`
|
|
559148
559367
|
});
|
|
559149
559368
|
return;
|
|
559150
559369
|
}
|
|
559151
559370
|
}
|
|
559152
|
-
|
|
559371
|
+
log70.info(` Content: ${messageContent.substring(0, 150)}${messageContent.length > 150 ? "..." : ""}`);
|
|
559153
559372
|
const { userId } = resolveContext({
|
|
559154
559373
|
channel: message.channel,
|
|
559155
559374
|
channelUserId: message.sessionId
|
|
@@ -559180,7 +559399,7 @@ async function startGateway(config3) {
|
|
|
559180
559399
|
${messageContent}`;
|
|
559181
559400
|
const messages2 = [{ role: "user", content: messageContentWithTime }];
|
|
559182
559401
|
try {
|
|
559183
|
-
|
|
559402
|
+
log70.info(`\uD83E\uDD16 Routing to agent loop...`);
|
|
559184
559403
|
const response = await runner.generate({
|
|
559185
559404
|
provider: dbProvider,
|
|
559186
559405
|
messages: messages2,
|
|
@@ -559195,7 +559414,7 @@ ${messageContent}`;
|
|
|
559195
559414
|
if (step.type === "text" && step.message) {
|
|
559196
559415
|
const trimmedMessage = (typeof step.message === "string" ? step.message : "").trim();
|
|
559197
559416
|
if (trimmedMessage) {
|
|
559198
|
-
|
|
559417
|
+
log70.debug(`[NARRATION] ${trimmedMessage.substring(0, 100)}`);
|
|
559199
559418
|
await channelManager.send(message.channel, routingSessionId, {
|
|
559200
559419
|
content: trimmedMessage,
|
|
559201
559420
|
type: "progress"
|
|
@@ -559205,7 +559424,7 @@ ${messageContent}`;
|
|
|
559205
559424
|
}
|
|
559206
559425
|
if (step.type === "tool_call" && step.toolName) {
|
|
559207
559426
|
const narration = getNarration(step.toolName);
|
|
559208
|
-
|
|
559427
|
+
log70.debug(`[TOOL] ${step.toolName} \u2192 "${narration}"`);
|
|
559209
559428
|
await channelManager.send(message.channel, routingSessionId, {
|
|
559210
559429
|
content: narration,
|
|
559211
559430
|
type: "progress"
|
|
@@ -559229,10 +559448,10 @@ ${messageContent}`;
|
|
|
559229
559448
|
});
|
|
559230
559449
|
const responseContent = response.content?.trim() || "";
|
|
559231
559450
|
if (!responseContent) {
|
|
559232
|
-
|
|
559451
|
+
log70.warn(`\uD83D\uDCE4 LLM response: empty \u2014 skipping send`);
|
|
559233
559452
|
return;
|
|
559234
559453
|
}
|
|
559235
|
-
|
|
559454
|
+
log70.info(`\uD83D\uDCE4 LLM response: ${responseContent.substring(0, 100)}${responseContent.length > 100 ? "..." : ""}`);
|
|
559236
559455
|
const shouldSpeak = preferAudioResponse;
|
|
559237
559456
|
let responseType = "text";
|
|
559238
559457
|
let ttsProviderUsed = null;
|
|
@@ -559240,7 +559459,7 @@ ${messageContent}`;
|
|
|
559240
559459
|
if (responseContent) {
|
|
559241
559460
|
if (shouldSpeak) {
|
|
559242
559461
|
if (!voiceConfig.ttsProvider) {
|
|
559243
|
-
|
|
559462
|
+
log70.warn(`\u26A0\uFE0F TTS provider not configured, user requested audio`);
|
|
559244
559463
|
await channelManager.send(message.channel, routingSessionId, {
|
|
559245
559464
|
content: `${responseContent}
|
|
559246
559465
|
|
|
@@ -559248,7 +559467,7 @@ ${messageContent}`;
|
|
|
559248
559467
|
});
|
|
559249
559468
|
} else {
|
|
559250
559469
|
try {
|
|
559251
|
-
|
|
559470
|
+
log70.info(`\uD83D\uDD0A TTS enabled, synthesizing audio...`);
|
|
559252
559471
|
const audioOutput = await voiceService.speak(responseContent, voiceConfig.ttsProvider, voiceConfig.ttsVoiceId || undefined);
|
|
559253
559472
|
ttsProviderUsed = voiceConfig.ttsProvider;
|
|
559254
559473
|
ttsMimeType = audioOutput.mimeType;
|
|
@@ -559257,17 +559476,17 @@ ${messageContent}`;
|
|
|
559257
559476
|
const channel = channelManager.getChannel(message.channel);
|
|
559258
559477
|
if (channel?.sendAudio) {
|
|
559259
559478
|
await channel.sendAudio(routingSessionId, audioOutput.data, audioOutput.mimeType);
|
|
559260
|
-
|
|
559479
|
+
log70.info(`\u2705 Audio sent to ${routingSessionId}`);
|
|
559261
559480
|
} else {
|
|
559262
|
-
|
|
559481
|
+
log70.warn(`Channel ${message.channel} does not support audio, sending text`);
|
|
559263
559482
|
await channelManager.send(message.channel, routingSessionId, { content: responseContent });
|
|
559264
559483
|
}
|
|
559265
559484
|
} catch (audioError) {
|
|
559266
|
-
|
|
559485
|
+
log70.error(`\u274C Audio send failed: ${audioError.message}, sending text instead`);
|
|
559267
559486
|
await channelManager.send(message.channel, routingSessionId, { content: responseContent });
|
|
559268
559487
|
}
|
|
559269
559488
|
} catch (ttsError) {
|
|
559270
|
-
|
|
559489
|
+
log70.error(`\u274C TTS failed: ${ttsError.message}, sending text instead`);
|
|
559271
559490
|
await channelManager.send(message.channel, routingSessionId, { content: responseContent });
|
|
559272
559491
|
}
|
|
559273
559492
|
}
|
|
@@ -559282,10 +559501,10 @@ ${messageContent}`;
|
|
|
559282
559501
|
channel: message.channel
|
|
559283
559502
|
};
|
|
559284
559503
|
await channelManager.stopTyping(message.channel, routingSessionId);
|
|
559285
|
-
|
|
559504
|
+
log70.info(`\u2705 Response sent to ${routingSessionId} via ${message.channel}`);
|
|
559286
559505
|
} catch (error50) {
|
|
559287
559506
|
await channelManager.stopTyping(message.channel, routingSessionId);
|
|
559288
|
-
|
|
559507
|
+
log70.error(`\u274C Error: ${error50.message} `);
|
|
559289
559508
|
await channelManager.send(message.channel, routingSessionId, {
|
|
559290
559509
|
content: `Error: ${error50.message} `
|
|
559291
559510
|
});
|
|
@@ -559295,6 +559514,8 @@ ${messageContent}`;
|
|
|
559295
559514
|
function checkAuth(req, url3) {
|
|
559296
559515
|
if (isDev)
|
|
559297
559516
|
return true;
|
|
559517
|
+
if (url3.pathname.startsWith("/api/setup/"))
|
|
559518
|
+
return true;
|
|
559298
559519
|
const activeToken = process.env.HIVE_AUTH_TOKEN;
|
|
559299
559520
|
if (!activeToken)
|
|
559300
559521
|
return true;
|
|
@@ -559309,9 +559530,9 @@ ${messageContent}`;
|
|
|
559309
559530
|
const method = req.method;
|
|
559310
559531
|
const logRequest = (status, duration3) => {
|
|
559311
559532
|
if (url3.pathname === "/health" || url3.pathname === "/health/") {
|
|
559312
|
-
|
|
559533
|
+
log70.debug(`${method} ${url3.pathname} - ${status} (${duration3}ms)`);
|
|
559313
559534
|
} else {
|
|
559314
|
-
|
|
559535
|
+
log70.info(`${method} ${url3.pathname} - ${status} (${duration3}ms)`);
|
|
559315
559536
|
}
|
|
559316
559537
|
};
|
|
559317
559538
|
const handleRequest = async () => {
|
|
@@ -559332,10 +559553,24 @@ ${messageContent}`;
|
|
|
559332
559553
|
return new Response(null, { status: 204 });
|
|
559333
559554
|
}
|
|
559334
559555
|
if (url3.pathname === "/ws" || url3.pathname === "/ws/") {
|
|
559335
|
-
|
|
559336
|
-
|
|
559556
|
+
let sessionId = url3.searchParams.get("session") || resolveUserId({}) || "default";
|
|
559557
|
+
if (!isDev) {
|
|
559558
|
+
const tokenParam = url3.searchParams.get("token");
|
|
559559
|
+
const activeToken = process.env.HIVE_AUTH_TOKEN;
|
|
559560
|
+
if (tokenParam && activeToken && tokenParam === activeToken) {
|
|
559561
|
+
const user = getDb().query("SELECT id FROM users LIMIT 1").get();
|
|
559562
|
+
if (user)
|
|
559563
|
+
sessionId = user.id;
|
|
559564
|
+
}
|
|
559565
|
+
try {
|
|
559566
|
+
const userExists = getDb().query("SELECT 1 FROM users WHERE id = ? LIMIT 1").get(sessionId);
|
|
559567
|
+
if (!userExists) {
|
|
559568
|
+
return new Response("Unauthorized", { status: 401 });
|
|
559569
|
+
}
|
|
559570
|
+
} catch {
|
|
559571
|
+
return new Response("Unauthorized", { status: 401 });
|
|
559572
|
+
}
|
|
559337
559573
|
}
|
|
559338
|
-
const sessionId = url3.searchParams.get("session") || resolveUserId({}) || "default";
|
|
559339
559574
|
if (!sessionId) {
|
|
559340
559575
|
return new Response("Missing session or user ID", { status: 400 });
|
|
559341
559576
|
}
|
|
@@ -559428,8 +559663,8 @@ ${messageContent}`;
|
|
|
559428
559663
|
return Response.redirect(`/ ui${tokenParam} `, 301);
|
|
559429
559664
|
}
|
|
559430
559665
|
if (!checkAuth(req, url3)) {
|
|
559431
|
-
|
|
559432
|
-
return new Response("Unauthorized", { status: 401 });
|
|
559666
|
+
log70.warn(`[AUTH] Unauthorized request to ${url3.pathname} from ${req.headers.get("origin")} `);
|
|
559667
|
+
return addCorsHeaders(new Response("Unauthorized", { status: 401 }), req);
|
|
559433
559668
|
}
|
|
559434
559669
|
if (url3.pathname === "/api/setup/status" || url3.pathname === "/api/setup/status/") {
|
|
559435
559670
|
return addCorsHeaders(await handleSetupStatus(), req);
|
|
@@ -559627,7 +559862,7 @@ ${messageContent}`;
|
|
|
559627
559862
|
return await handleApiReload(req, addCorsHeaders, agent);
|
|
559628
559863
|
}
|
|
559629
559864
|
if (url3.pathname === "/api/user/channels" && req.method === "POST") {
|
|
559630
|
-
return await handleLinkUserChannel(req, addCorsHeaders, config3,
|
|
559865
|
+
return await handleLinkUserChannel(req, addCorsHeaders, config3, log70);
|
|
559631
559866
|
}
|
|
559632
559867
|
if (url3.pathname === "/api/user/channels" && req.method === "GET") {
|
|
559633
559868
|
return await handleGetUserChannels(req, addCorsHeaders, config3);
|
|
@@ -559685,7 +559920,7 @@ ${messageContent}`;
|
|
|
559685
559920
|
const { name, category, tools, triggers, body: bodyContent } = body;
|
|
559686
559921
|
if (!name)
|
|
559687
559922
|
return addCorsHeaders(new Response("Missing name", { status: 400 }), req);
|
|
559688
|
-
const id =
|
|
559923
|
+
const id = randomUUID2();
|
|
559689
559924
|
getDb().query(`INSERT INTO skills(id, name, category, tools, triggers, body, version, active) VALUES(?, ?, ?, ?, ?, ?, 1, 1)`).run(id, name, category || "", tools || "", triggers || "", bodyContent || "");
|
|
559690
559925
|
return addCorsHeaders(Response.json({ success: true, id }), req);
|
|
559691
559926
|
}
|
|
@@ -559715,7 +559950,7 @@ ${messageContent}`;
|
|
|
559715
559950
|
const { name, description, content, is_default: is_default2 } = body;
|
|
559716
559951
|
if (!name || !content)
|
|
559717
559952
|
return addCorsHeaders(Response.json({ success: false, error: "Missing name or content" }, { status: 400 }), req);
|
|
559718
|
-
const id =
|
|
559953
|
+
const id = randomUUID2();
|
|
559719
559954
|
getDb().query(`INSERT INTO ethics(id, name, description, content, is_default, enabled, active) VALUES(?, ?, ?, ?, ?, 1, 1)`).run(id, name, description || "", content, is_default2 ? 1 : 0);
|
|
559720
559955
|
return addCorsHeaders(Response.json({ success: true, id }), req);
|
|
559721
559956
|
}
|
|
@@ -559757,16 +559992,16 @@ ${messageContent}`;
|
|
|
559757
559992
|
if (active === undefined) {
|
|
559758
559993
|
return addCorsHeaders(Response.json({ success: false, error: "Missing active field" }, { status: 400 }), req);
|
|
559759
559994
|
}
|
|
559760
|
-
|
|
559995
|
+
log70.info(`[MCP] Toggle connection for ${mcpName}, active=${active}`);
|
|
559761
559996
|
getDb().query(`UPDATE mcp_servers SET active = ?, enabled = ? WHERE id = ? OR name = ?`).run(active ? 1 : 0, active ? 1 : 0, mcpName, mcpName);
|
|
559762
559997
|
try {
|
|
559763
559998
|
const mcp = agent?.getMCPManager() ?? null;
|
|
559764
559999
|
if (mcp) {
|
|
559765
|
-
|
|
560000
|
+
log70.info(`[MCP] Manager found, connecting ${mcpName}...`);
|
|
559766
560001
|
if (active) {
|
|
559767
560002
|
const server4 = getDb().query(`SELECT * FROM mcp_servers WHERE id = ? OR name = ?`).get(mcpName, mcpName);
|
|
559768
560003
|
if (server4) {
|
|
559769
|
-
|
|
560004
|
+
log70.info(`[MCP] Server config: transport=${server4.transport}, url=${server4.url}`);
|
|
559770
560005
|
const mcpServerConfig = {
|
|
559771
560006
|
transport: server4.transport,
|
|
559772
560007
|
command: server4.command,
|
|
@@ -559778,7 +560013,7 @@ ${messageContent}`;
|
|
|
559778
560013
|
try {
|
|
559779
560014
|
mcpServerConfig.headers = decryptConfig(server4.headers_encrypted, server4.headers_iv);
|
|
559780
560015
|
} catch (e) {
|
|
559781
|
-
|
|
560016
|
+
log70.warn(`Failed to decrypt headers for ${mcpName}`);
|
|
559782
560017
|
}
|
|
559783
560018
|
}
|
|
559784
560019
|
const currentConfig = mcp.config || { servers: {} };
|
|
@@ -559788,22 +560023,22 @@ ${messageContent}`;
|
|
|
559788
560023
|
...currentConfig,
|
|
559789
560024
|
servers: newServersConfig
|
|
559790
560025
|
});
|
|
559791
|
-
|
|
560026
|
+
log70.info(`[MCP] Server registered in MCP Manager`);
|
|
559792
560027
|
const tools = mcp.getServerTools(mcpName) || [];
|
|
559793
|
-
|
|
560028
|
+
log70.info(`[MCP] Connected! Tools: ${tools.length}`);
|
|
559794
560029
|
getDb().query(`UPDATE mcp_servers SET status = ?, tools_count = ? WHERE id = ? OR name = ?`).run("connected", tools.length, mcpName, mcpName);
|
|
559795
560030
|
} else {
|
|
559796
|
-
|
|
560031
|
+
log70.error(`[MCP] Server not found in DB: ${mcpName}`);
|
|
559797
560032
|
}
|
|
559798
560033
|
} else {
|
|
559799
560034
|
await mcp.disconnectServer(mcpName);
|
|
559800
560035
|
getDb().query(`UPDATE mcp_servers SET status = ? WHERE id = ? OR name = ?`).run("disconnected", mcpName, mcpName);
|
|
559801
560036
|
}
|
|
559802
560037
|
} else {
|
|
559803
|
-
|
|
560038
|
+
log70.error(`[MCP] No MCP Manager found`);
|
|
559804
560039
|
}
|
|
559805
560040
|
} catch (error50) {
|
|
559806
|
-
|
|
560041
|
+
log70.error(`[MCP] Failed to connect ${mcpName}: ${error50.message}`);
|
|
559807
560042
|
}
|
|
559808
560043
|
return addCorsHeaders(Response.json({ success: true, active, message: active ? "Servidor MCP conectado" : "Servidor MCP desconectado" }), req);
|
|
559809
560044
|
}
|
|
@@ -559830,7 +560065,7 @@ ${messageContent}`;
|
|
|
559830
560065
|
if (active) {
|
|
559831
560066
|
const server4 = getDb().query(`SELECT * FROM mcp_servers WHERE id = ? OR name = ?`).get(mcpName, mcpName);
|
|
559832
560067
|
if (server4) {
|
|
559833
|
-
|
|
560068
|
+
log70.info(`[MCP] Server config: transport=${server4.transport}, url=${server4.url}`);
|
|
559834
560069
|
const mcpServerConfig = {
|
|
559835
560070
|
transport: server4.transport,
|
|
559836
560071
|
command: server4.command,
|
|
@@ -559842,7 +560077,7 @@ ${messageContent}`;
|
|
|
559842
560077
|
try {
|
|
559843
560078
|
mcpServerConfig.headers = decryptConfig(server4.headers_encrypted, server4.headers_iv);
|
|
559844
560079
|
} catch (e) {
|
|
559845
|
-
|
|
560080
|
+
log70.warn(`Failed to decrypt headers for ${mcpName}`);
|
|
559846
560081
|
}
|
|
559847
560082
|
}
|
|
559848
560083
|
const currentConfig = mcp.config || { servers: {} };
|
|
@@ -559852,12 +560087,12 @@ ${messageContent}`;
|
|
|
559852
560087
|
...currentConfig,
|
|
559853
560088
|
servers: newServersConfig
|
|
559854
560089
|
});
|
|
559855
|
-
|
|
560090
|
+
log70.info(`[MCP] Server registered in MCP Manager`);
|
|
559856
560091
|
const tools = mcp.getServerTools(mcpName) || [];
|
|
559857
|
-
|
|
560092
|
+
log70.info(`[MCP] Connected! Tools: ${tools.length}`);
|
|
559858
560093
|
getDb().query(`UPDATE mcp_servers SET status = ?, tools_count = ? WHERE id = ? OR name = ?`).run("connected", tools.length, mcpName, mcpName);
|
|
559859
560094
|
} else {
|
|
559860
|
-
|
|
560095
|
+
log70.error(`[MCP] Server not found in DB: ${mcpName}`);
|
|
559861
560096
|
}
|
|
559862
560097
|
} else {
|
|
559863
560098
|
await mcp.disconnectServer(mcpName);
|
|
@@ -559865,7 +560100,7 @@ ${messageContent}`;
|
|
|
559865
560100
|
}
|
|
559866
560101
|
}
|
|
559867
560102
|
} catch (error50) {
|
|
559868
|
-
|
|
560103
|
+
log70.error(`[MCP] Failed to connect ${mcpName}: ${error50.message}`);
|
|
559869
560104
|
}
|
|
559870
560105
|
return addCorsHeaders(Response.json({ success: true, active, message: active ? "Servidor MCP conectado" : "Servidor MCP desconectado" }), req);
|
|
559871
560106
|
}
|
|
@@ -559985,12 +560220,12 @@ ${messageContent}`;
|
|
|
559985
560220
|
if (response) {
|
|
559986
560221
|
logRequest(response.status, duration3);
|
|
559987
560222
|
} else {
|
|
559988
|
-
|
|
560223
|
+
log70.info(`${method} ${url3.pathname} - 101 Switching Protocols(${duration3}ms)`);
|
|
559989
560224
|
}
|
|
559990
560225
|
return response;
|
|
559991
560226
|
} catch (error50) {
|
|
559992
560227
|
const duration3 = Date.now() - start;
|
|
559993
|
-
|
|
560228
|
+
log70.error(`${method} ${url3.pathname} - Internal Error(${duration3}ms): ${error50.message} `);
|
|
559994
560229
|
return addCorsHeaders(Response.json({ success: false, error: error50.message, message: "Error interno del servidor" }, { status: 500 }), req);
|
|
559995
560230
|
}
|
|
559996
560231
|
},
|
|
@@ -560000,20 +560235,20 @@ ${messageContent}`;
|
|
|
560000
560235
|
const isCanvas = data.sessionId.startsWith("canvas:");
|
|
560001
560236
|
const isBridge = data.sessionId.startsWith("bridge:");
|
|
560002
560237
|
if (isBridge) {
|
|
560003
|
-
|
|
560238
|
+
log70.info(`Bridge events client connected: ${data.sessionId}`);
|
|
560004
560239
|
subscribeBridge(ws);
|
|
560005
560240
|
ws.send(JSON.stringify({ type: "bridge:connected", sessionId: data.sessionId }));
|
|
560006
560241
|
return;
|
|
560007
560242
|
}
|
|
560008
560243
|
if (isCanvas) {
|
|
560009
|
-
|
|
560244
|
+
log70.info(`Canvas session connected: ${data.sessionId} `);
|
|
560010
560245
|
canvasManager.registerSession(data.sessionId, ws);
|
|
560011
560246
|
subscribeCanvas(ws);
|
|
560012
560247
|
ws.send(JSON.stringify({ type: "canvas:connected", sessionId: data.sessionId }));
|
|
560013
560248
|
ws.send(JSON.stringify({ type: "canvas:snapshot", data: getCanvasSnapshot() }));
|
|
560014
560249
|
return;
|
|
560015
560250
|
}
|
|
560016
|
-
|
|
560251
|
+
log70.debug(`WebSocket connected: ${data.sessionId} `);
|
|
560017
560252
|
sessionManager.create(data.sessionId, ws);
|
|
560018
560253
|
const channel = channelManager?.getChannel("webchat");
|
|
560019
560254
|
if (channel?.registerConnection)
|
|
@@ -560044,13 +560279,19 @@ ${messageContent}`;
|
|
|
560044
560279
|
codeBridge: codeBridge.map((cb) => cb.id)
|
|
560045
560280
|
}));
|
|
560046
560281
|
} catch (err) {
|
|
560047
|
-
|
|
560282
|
+
log70.error("Error sending welcome message:", err);
|
|
560048
560283
|
}
|
|
560049
560284
|
},
|
|
560050
560285
|
async message(ws, message) {
|
|
560051
560286
|
const data = ws.data;
|
|
560052
|
-
if (data.sessionId.startsWith("bridge:"))
|
|
560287
|
+
if (data.sessionId.startsWith("bridge:")) {
|
|
560288
|
+
try {
|
|
560289
|
+
const m2 = JSON.parse(message.toString());
|
|
560290
|
+
if (m2?.type === "ping")
|
|
560291
|
+
ws.send(JSON.stringify({ type: "pong" }));
|
|
560292
|
+
} catch {}
|
|
560053
560293
|
return;
|
|
560294
|
+
}
|
|
560054
560295
|
let msg;
|
|
560055
560296
|
try {
|
|
560056
560297
|
msg = JSON.parse(message.toString());
|
|
@@ -560093,17 +560334,17 @@ ${messageContent}`;
|
|
|
560093
560334
|
}
|
|
560094
560335
|
if (msg.type === "logs_subscribe") {
|
|
560095
560336
|
logSubscribers.add(data.sessionId);
|
|
560096
|
-
|
|
560337
|
+
log70.debug(`Session ${data.sessionId} subscribed to logs`);
|
|
560097
560338
|
return;
|
|
560098
560339
|
}
|
|
560099
560340
|
if (msg.type === "logs_unsubscribe") {
|
|
560100
560341
|
logSubscribers.delete(data.sessionId);
|
|
560101
|
-
|
|
560342
|
+
log70.debug(`Session ${data.sessionId} unsubscribed from logs`);
|
|
560102
560343
|
return;
|
|
560103
560344
|
}
|
|
560104
560345
|
let webchatPreferAudio = false;
|
|
560105
560346
|
if (msg.type === "audio" && msg.audio) {
|
|
560106
|
-
|
|
560347
|
+
log70.info(`WebChat audio from session ${msg.sessionId}`);
|
|
560107
560348
|
const voiceConfig = voiceService.getChannelVoiceConfig("webchat");
|
|
560108
560349
|
if (!voiceConfig.voiceEnabled) {
|
|
560109
560350
|
ws.send(JSON.stringify({
|
|
@@ -560130,7 +560371,7 @@ ${messageContent}`;
|
|
|
560130
560371
|
const audioInput = { type: "base64", data: msg.audio, mimeType: "audio/webm" };
|
|
560131
560372
|
const sttProvider = voiceConfig.sttProvider || "groq-whisper";
|
|
560132
560373
|
const messageContent = await voiceService.transcribe(audioInput, sttProvider);
|
|
560133
|
-
|
|
560374
|
+
log70.info(`\uD83D\uDCDD Transcribed: ${messageContent.substring(0, 100)}...`);
|
|
560134
560375
|
webchatPreferAudio = true;
|
|
560135
560376
|
ws.send(JSON.stringify({
|
|
560136
560377
|
type: "message",
|
|
@@ -560151,7 +560392,7 @@ ${messageContent}`;
|
|
|
560151
560392
|
try {
|
|
560152
560393
|
const unifiedSessionId = msg.sessionId;
|
|
560153
560394
|
const messages2 = [{ role: "user", content: messageContent }];
|
|
560154
|
-
|
|
560395
|
+
log70.info(`Generating response for session ${unifiedSessionId}...`);
|
|
560155
560396
|
const { userId } = resolveContext({
|
|
560156
560397
|
channel: "webchat",
|
|
560157
560398
|
channelUserId: msg.sessionId
|
|
@@ -560197,11 +560438,11 @@ ${messageContent}`;
|
|
|
560197
560438
|
}
|
|
560198
560439
|
} catch {}
|
|
560199
560440
|
}
|
|
560200
|
-
|
|
560441
|
+
log70.debug(`[TOOL] ${step.type}: ${step.toolName || ""}`);
|
|
560201
560442
|
}
|
|
560202
560443
|
});
|
|
560203
560444
|
const content = streamedContent || response.content?.trim() || "";
|
|
560204
|
-
|
|
560445
|
+
log70.info(`Response sent to session ${unifiedSessionId} (${content.length} chars)`);
|
|
560205
560446
|
const voiceCfg = voiceService.getChannelVoiceConfig("webchat");
|
|
560206
560447
|
const shouldSpeak = webchatPreferAudio;
|
|
560207
560448
|
let responseType = "text";
|
|
@@ -560222,7 +560463,7 @@ ${messageContent}`;
|
|
|
560222
560463
|
}));
|
|
560223
560464
|
} else {
|
|
560224
560465
|
try {
|
|
560225
|
-
|
|
560466
|
+
log70.info(`\uD83D\uDD0A TTS enabled, synthesizing audio for WebChat...`);
|
|
560226
560467
|
const audioOutput = await voiceService.speak(content, voiceCfg.ttsProvider, voiceCfg.ttsVoiceId || undefined);
|
|
560227
560468
|
ttsProviderUsed = voiceCfg.ttsProvider;
|
|
560228
560469
|
ttsMimeType = audioOutput.mimeType;
|
|
@@ -560236,7 +560477,7 @@ ${messageContent}`;
|
|
|
560236
560477
|
mimeType: audioOutput.mimeType
|
|
560237
560478
|
}));
|
|
560238
560479
|
} catch (ttsError) {
|
|
560239
|
-
|
|
560480
|
+
log70.error(`TTS failed: ${ttsError.message}), sending text instead`);
|
|
560240
560481
|
ws.send(JSON.stringify({ type: "message", sessionId: unifiedSessionId, content, isStep: false }));
|
|
560241
560482
|
}
|
|
560242
560483
|
}
|
|
@@ -560251,7 +560492,7 @@ ${messageContent}`;
|
|
|
560251
560492
|
sessionId: msg.sessionId,
|
|
560252
560493
|
error: error50.message
|
|
560253
560494
|
}));
|
|
560254
|
-
|
|
560495
|
+
log70.error(`Error for session ${msg.sessionId}: ${error50.message}`);
|
|
560255
560496
|
}
|
|
560256
560497
|
});
|
|
560257
560498
|
} catch (error50) {
|
|
@@ -560269,7 +560510,7 @@ ${messageContent}`;
|
|
|
560269
560510
|
return;
|
|
560270
560511
|
}
|
|
560271
560512
|
if (msg.type === "message" && msg.content) {
|
|
560272
|
-
|
|
560513
|
+
log70.info(`WebChat message from session ${msg.sessionId}: ${msg.content.substring(0, 100)}`);
|
|
560273
560514
|
ws.send(JSON.stringify({
|
|
560274
560515
|
type: "typing",
|
|
560275
560516
|
isTyping: true,
|
|
@@ -560284,7 +560525,7 @@ ${messageContent}`;
|
|
|
560284
560525
|
try {
|
|
560285
560526
|
const unifiedSessionId = msg.sessionId;
|
|
560286
560527
|
const messages2 = [{ role: "user", content: msg.content }];
|
|
560287
|
-
|
|
560528
|
+
log70.info(`Generating response for session ${unifiedSessionId}...`);
|
|
560288
560529
|
const { userId } = resolveContext({
|
|
560289
560530
|
channel: "webchat",
|
|
560290
560531
|
channelUserId: msg.sessionId
|
|
@@ -560330,11 +560571,11 @@ ${messageContent}`;
|
|
|
560330
560571
|
}
|
|
560331
560572
|
} catch {}
|
|
560332
560573
|
}
|
|
560333
|
-
|
|
560574
|
+
log70.debug(`[TOOL] ${step.type}: ${step.toolName || ""}`);
|
|
560334
560575
|
}
|
|
560335
560576
|
});
|
|
560336
560577
|
const content = streamedContent || response.content?.trim() || "";
|
|
560337
|
-
|
|
560578
|
+
log70.info(`Response sent to session ${unifiedSessionId} (${content.length} chars)`);
|
|
560338
560579
|
const voiceConfig = voiceService.getChannelVoiceConfig("webchat");
|
|
560339
560580
|
const shouldSpeak = webchatPreferAudio;
|
|
560340
560581
|
let responseType = "text";
|
|
@@ -560355,7 +560596,7 @@ ${messageContent}`;
|
|
|
560355
560596
|
}));
|
|
560356
560597
|
} else {
|
|
560357
560598
|
try {
|
|
560358
|
-
|
|
560599
|
+
log70.info(`\uD83D\uDD0A TTS enabled, synthesizing audio for WebChat...`);
|
|
560359
560600
|
const audioOutput = await voiceService.speak(content, voiceConfig.ttsProvider, voiceConfig.ttsVoiceId || undefined);
|
|
560360
560601
|
ttsProviderUsed = voiceConfig.ttsProvider;
|
|
560361
560602
|
ttsMimeType = audioOutput.mimeType;
|
|
@@ -560369,7 +560610,7 @@ ${messageContent}`;
|
|
|
560369
560610
|
mimeType: audioOutput.mimeType
|
|
560370
560611
|
}));
|
|
560371
560612
|
} catch (ttsError) {
|
|
560372
|
-
|
|
560613
|
+
log70.error(`TTS failed: ${ttsError.message}), sending text instead`);
|
|
560373
560614
|
ws.send(JSON.stringify({ type: "message", sessionId: unifiedSessionId, content, isStep: false }));
|
|
560374
560615
|
}
|
|
560375
560616
|
}
|
|
@@ -560385,7 +560626,7 @@ ${messageContent}`;
|
|
|
560385
560626
|
sessionId: unifiedSessionId,
|
|
560386
560627
|
error: error50.message
|
|
560387
560628
|
}));
|
|
560388
|
-
|
|
560629
|
+
log70.error(`Error for session ${unifiedSessionId}: ${error50.message}`);
|
|
560389
560630
|
}
|
|
560390
560631
|
});
|
|
560391
560632
|
return;
|
|
@@ -560409,7 +560650,7 @@ ${messageContent}`;
|
|
|
560409
560650
|
unsubscribeCanvas(ws);
|
|
560410
560651
|
return;
|
|
560411
560652
|
}
|
|
560412
|
-
|
|
560653
|
+
log70.debug(`WebSocket disconnected: ${data.sessionId}`);
|
|
560413
560654
|
logSubscribers.delete(data.sessionId);
|
|
560414
560655
|
sessionManager.delete(data.sessionId);
|
|
560415
560656
|
laneQueue.cancel(data.sessionId);
|
|
@@ -560440,25 +560681,25 @@ ${messageContent}`;
|
|
|
560440
560681
|
}
|
|
560441
560682
|
}
|
|
560442
560683
|
});
|
|
560443
|
-
|
|
560684
|
+
log70.info(`Gateway started successfully`);
|
|
560444
560685
|
const isGatewayChild = process.env.HIVE_GATEWAY_CHILD === "1";
|
|
560445
560686
|
if (isDev) {
|
|
560446
|
-
|
|
560447
|
-
|
|
560448
|
-
|
|
560449
|
-
|
|
560687
|
+
log70.info(`[gateway] API: http://${host}:${port}`);
|
|
560688
|
+
log70.info(`[gateway] WebSocket: ws://${host}:${port}/ws`);
|
|
560689
|
+
log70.info(`[gateway] Canvas: ws://${host}:${port}/canvas`);
|
|
560690
|
+
log70.info(`[gateway] Modo: desarrollo`);
|
|
560450
560691
|
if (!isGatewayChild) {
|
|
560451
|
-
|
|
560692
|
+
log70.info(`\uD83D\uDC1D Administra tu Hive aqu\xED: http://localhost:5173`);
|
|
560452
560693
|
}
|
|
560453
560694
|
} else {
|
|
560454
560695
|
const isSetupMode2 = gatewaySetupMode;
|
|
560455
560696
|
const baseUrl = `http://${host}:${port}`;
|
|
560456
560697
|
const uiUrl = isSetupMode2 ? `${baseUrl}/setup` : `${baseUrl}/ui`;
|
|
560457
|
-
|
|
560458
|
-
|
|
560459
|
-
|
|
560460
|
-
|
|
560461
|
-
|
|
560698
|
+
log70.info(`[gateway] UI: ${uiUrl}`);
|
|
560699
|
+
log70.info(`[gateway] API: http://${host}:${port}`);
|
|
560700
|
+
log70.info(`[gateway] WebSocket: ws://${host}:${port}/ws`);
|
|
560701
|
+
log70.info(`[gateway] Canvas: ws://${host}:${port}/canvas`);
|
|
560702
|
+
log70.info(isSetupMode2 ? `\uD83C\uDF89 Primer arranque \u2014 abriendo wizard de configuraci\xF3n...` : `\uD83D\uDC1D Administra tu Hive aqu\xED: ${uiUrl}`);
|
|
560462
560703
|
if (!process.env.NO_BROWSER) {
|
|
560463
560704
|
try {
|
|
560464
560705
|
const platform2 = process.platform;
|
|
@@ -560479,18 +560720,18 @@ ${messageContent}`;
|
|
|
560479
560720
|
});
|
|
560480
560721
|
proc.unref();
|
|
560481
560722
|
} catch (err) {
|
|
560482
|
-
|
|
560723
|
+
log70.warn(`Could not open browser: ${err.message}`);
|
|
560483
560724
|
}
|
|
560484
560725
|
}
|
|
560485
560726
|
}
|
|
560486
560727
|
if (!gatewaySetupMode)
|
|
560487
|
-
|
|
560728
|
+
log70.info(`Channels: ${channelManager.listChannels().map((c3) => c3.name).join(", ") || "none"}`);
|
|
560488
560729
|
process.on("SIGTERM", async () => {
|
|
560489
|
-
|
|
560730
|
+
log70.info("Received SIGTERM, shutting down gracefully...");
|
|
560490
560731
|
watchers.forEach((close) => close());
|
|
560491
560732
|
const mcp = agent?.getMCPManager();
|
|
560492
560733
|
if (mcp) {
|
|
560493
|
-
|
|
560734
|
+
log70.info("Disconnecting MCP servers...");
|
|
560494
560735
|
await mcp.disconnectAll().catch(() => {});
|
|
560495
560736
|
}
|
|
560496
560737
|
if (channelManager)
|
|
@@ -560502,14 +560743,14 @@ ${messageContent}`;
|
|
|
560502
560743
|
process.exit(0);
|
|
560503
560744
|
});
|
|
560504
560745
|
process.on("SIGHUP", async () => {
|
|
560505
|
-
|
|
560746
|
+
log70.info("Received SIGHUP, reloading configuration...");
|
|
560506
560747
|
try {
|
|
560507
560748
|
const newConfig = await loadConfig();
|
|
560508
560749
|
await agent.updateConfig(newConfig);
|
|
560509
560750
|
await agent.reload();
|
|
560510
|
-
|
|
560751
|
+
log70.info("Configuration reloaded successfully");
|
|
560511
560752
|
} catch (error50) {
|
|
560512
|
-
|
|
560753
|
+
log70.error(`Failed to reload configuration: ${error50.message}`);
|
|
560513
560754
|
}
|
|
560514
560755
|
});
|
|
560515
560756
|
}
|
|
@@ -561992,7 +562233,7 @@ var init_circuit_breaker = __esm(() => {
|
|
|
561992
562233
|
circuitBreakerRegistry = new CircuitBreakerRegistry;
|
|
561993
562234
|
});
|
|
561994
562235
|
// packages/core/src/plugins/loader.ts
|
|
561995
|
-
import { mkdirSync as
|
|
562236
|
+
import { mkdirSync as mkdirSync12, readdirSync as readdirSync5, existsSync as existsSync19 } from "fs";
|
|
561996
562237
|
import * as path31 from "path";
|
|
561997
562238
|
|
|
561998
562239
|
class PluginLoader {
|
|
@@ -562007,7 +562248,7 @@ class PluginLoader {
|
|
|
562007
562248
|
constructor(options2) {
|
|
562008
562249
|
this.options = options2;
|
|
562009
562250
|
if (!existsSync19(options2.pluginDir)) {
|
|
562010
|
-
|
|
562251
|
+
mkdirSync12(options2.pluginDir, { recursive: true });
|
|
562011
562252
|
}
|
|
562012
562253
|
}
|
|
562013
562254
|
async discover() {
|
|
@@ -562607,7 +562848,8 @@ var init_schemas4 = __esm(() => {
|
|
|
562607
562848
|
prompt: exports_external.string()
|
|
562608
562849
|
}),
|
|
562609
562850
|
exports_external.object({ cmd: exports_external.literal("cancel"), taskId: exports_external.string() }),
|
|
562610
|
-
exports_external.object({ cmd: exports_external.literal("status") })
|
|
562851
|
+
exports_external.object({ cmd: exports_external.literal("status") }),
|
|
562852
|
+
exports_external.object({ cmd: exports_external.literal("ping") })
|
|
562611
562853
|
]);
|
|
562612
562854
|
});
|
|
562613
562855
|
|
|
@@ -562679,6 +562921,10 @@ var init_src4 = __esm(() => {
|
|
|
562679
562921
|
ws.send(JSON.stringify(manager4.status()));
|
|
562680
562922
|
break;
|
|
562681
562923
|
}
|
|
562924
|
+
case "ping": {
|
|
562925
|
+
ws.send(JSON.stringify({ type: "pong" }));
|
|
562926
|
+
break;
|
|
562927
|
+
}
|
|
562682
562928
|
}
|
|
562683
562929
|
},
|
|
562684
562930
|
close(ws) {
|
|
@@ -562697,7 +562943,7 @@ __export(exports_gateway, {
|
|
|
562697
562943
|
start: () => start,
|
|
562698
562944
|
reload: () => reload
|
|
562699
562945
|
});
|
|
562700
|
-
import { existsSync as existsSync20, mkdirSync as
|
|
562946
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync13, writeFileSync as writeFileSync6, readFileSync as readFileSync10, unlinkSync as unlinkSync5, openSync } from "fs";
|
|
562701
562947
|
import * as path32 from "path";
|
|
562702
562948
|
import { spawn as spawn5 } from "child_process";
|
|
562703
562949
|
function cleanup() {
|
|
@@ -562732,7 +562978,7 @@ async function getPidFile() {
|
|
|
562732
562978
|
function ensureLogDir() {
|
|
562733
562979
|
const logDir = path32.dirname(getLogFile());
|
|
562734
562980
|
if (!existsSync20(logDir)) {
|
|
562735
|
-
|
|
562981
|
+
mkdirSync13(logDir, { recursive: true });
|
|
562736
562982
|
}
|
|
562737
562983
|
}
|
|
562738
562984
|
function openBrowser(url3) {
|
|
@@ -562770,7 +563016,7 @@ async function isRunning() {
|
|
|
562770
563016
|
const pidFile = await getPidFile();
|
|
562771
563017
|
if (!existsSync20(pidFile))
|
|
562772
563018
|
return false;
|
|
562773
|
-
const pid = parseInt(
|
|
563019
|
+
const pid = parseInt(readFileSync10(pidFile, "utf-8").trim(), 10);
|
|
562774
563020
|
if (isNaN(pid))
|
|
562775
563021
|
return false;
|
|
562776
563022
|
try {
|
|
@@ -562843,7 +563089,7 @@ async function start(flags) {
|
|
|
562843
563089
|
\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2551
|
|
562844
563090
|
\u2551 \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u2551
|
|
562845
563091
|
\u2551 \u2551
|
|
562846
|
-
\u2551 Personal Swarm AI Gateway \u2014 v2.0.
|
|
563092
|
+
\u2551 Personal Swarm AI Gateway \u2014 v2.0.3 \u2551
|
|
562847
563093
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
562848
563094
|
`);
|
|
562849
563095
|
}
|
|
@@ -562855,7 +563101,7 @@ async function start(flags) {
|
|
|
562855
563101
|
stdio: ["ignore", openSync(logFile, "a"), openSync(logFile, "a")]
|
|
562856
563102
|
});
|
|
562857
563103
|
child.unref();
|
|
562858
|
-
|
|
563104
|
+
writeFileSync6(await getPidFile(), child.pid?.toString() || "");
|
|
562859
563105
|
console.log(`\u2705 Hive Gateway iniciado en modo daemon (PID: ${child.pid})`);
|
|
562860
563106
|
console.log(` Logs: ${logFile}`);
|
|
562861
563107
|
return;
|
|
@@ -562969,6 +563215,12 @@ async function start(flags) {
|
|
|
562969
563215
|
}
|
|
562970
563216
|
return;
|
|
562971
563217
|
}
|
|
563218
|
+
try {
|
|
563219
|
+
await Promise.resolve().then(() => (init_src4(), exports_src));
|
|
563220
|
+
console.log("\uD83C\uDF09 Code Bridge iniciado en puerto 18791");
|
|
563221
|
+
} catch (error50) {
|
|
563222
|
+
console.warn(`\u26A0\uFE0F No se pudo iniciar el Code Bridge: ${error50.message}`);
|
|
563223
|
+
}
|
|
562972
563224
|
if (!daemon && !isGatewayChild) {
|
|
562973
563225
|
const port = config4.gateway?.port || 18790;
|
|
562974
563226
|
waitForPort(port, 30000).then(() => {
|
|
@@ -562988,7 +563240,7 @@ async function stop() {
|
|
|
562988
563240
|
return;
|
|
562989
563241
|
}
|
|
562990
563242
|
const pidFile = await getPidFile();
|
|
562991
|
-
const pid = parseInt(
|
|
563243
|
+
const pid = parseInt(readFileSync10(pidFile, "utf-8").trim(), 10);
|
|
562992
563244
|
try {
|
|
562993
563245
|
process.kill(pid, "SIGTERM");
|
|
562994
563246
|
unlinkSync5(pidFile);
|
|
@@ -563006,7 +563258,7 @@ async function status(flags) {
|
|
|
563006
563258
|
const pidFile = await getPidFile();
|
|
563007
563259
|
console.log(`Estado: ${running ? "\u2705 Corriendo" : "\u23F9\uFE0F Detenido"}`);
|
|
563008
563260
|
if (running) {
|
|
563009
|
-
const pid =
|
|
563261
|
+
const pid = readFileSync10(pidFile, "utf-8").trim();
|
|
563010
563262
|
console.log(`PID: ${pid}`);
|
|
563011
563263
|
}
|
|
563012
563264
|
console.log(`Puerto: ${config4.gateway?.port || 18790}`);
|
|
@@ -563018,7 +563270,7 @@ async function status(flags) {
|
|
|
563018
563270
|
console.log(`Logs: ${getLogFile()}`);
|
|
563019
563271
|
if (flags.includes("--json")) {
|
|
563020
563272
|
console.log(`
|
|
563021
|
-
` + JSON.stringify({ running, pid: running ?
|
|
563273
|
+
` + JSON.stringify({ running, pid: running ? readFileSync10(pidFile, "utf-8").trim() : null, config: config4 }, null, 2));
|
|
563022
563274
|
}
|
|
563023
563275
|
}
|
|
563024
563276
|
async function reload() {
|
|
@@ -563026,7 +563278,7 @@ async function reload() {
|
|
|
563026
563278
|
console.log("\u26A0\uFE0F Hive Gateway no est\xE1 corriendo");
|
|
563027
563279
|
return;
|
|
563028
563280
|
}
|
|
563029
|
-
const pid = parseInt(
|
|
563281
|
+
const pid = parseInt(readFileSync10(await getPidFile(), "utf-8").trim(), 10);
|
|
563030
563282
|
try {
|
|
563031
563283
|
process.kill(pid, "SIGHUP");
|
|
563032
563284
|
console.log("\u2705 Configuraci\xF3n recargada");
|
|
@@ -565053,7 +565305,7 @@ async function executeAsync(gatewayUrl, payload, spinner) {
|
|
|
565053
565305
|
}
|
|
565054
565306
|
|
|
565055
565307
|
// packages/cli/src/index.ts
|
|
565056
|
-
var VERSION4 = "2.0.
|
|
565308
|
+
var VERSION4 = "2.0.3";
|
|
565057
565309
|
var HELP = `
|
|
565058
565310
|
\uD83D\uDC1D Hive \u2014 Personal Swarm AI Gateway v${VERSION4}
|
|
565059
565311
|
|