@johpaz/hive-sdk 0.0.14 → 0.0.15
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/.github/CODEOWNERS +9 -0
- package/.github/workflows/publish.yml +89 -0
- package/.github/workflows/version-bump.yml +102 -0
- package/CHANGELOG.md +38 -0
- package/README.md +158 -0
- package/bun.lock +543 -0
- package/bunfig.toml +7 -0
- package/docs/API-AGENTS.md +316 -0
- package/docs/API-CONTEXT-COMPILER.md +252 -0
- package/docs/API-DAG-SCHEDULER.md +273 -0
- package/docs/API-TOOLS-SKILLS-CHANNELS.md +293 -0
- package/docs/API-WORKERS-EVENTS.md +152 -0
- package/docs/INDEX.md +141 -0
- package/docs/README.md +68 -0
- package/package.json +54 -105
- package/packages/cli/package.json +17 -0
- package/packages/cli/src/commands/init.ts +56 -0
- package/packages/cli/src/commands/run.ts +45 -0
- package/packages/cli/src/commands/test.ts +42 -0
- package/packages/cli/src/commands/trace.ts +55 -0
- package/packages/cli/src/index.ts +43 -0
- package/packages/core/package.json +58 -0
- package/packages/core/src/ace/Curator.ts +158 -0
- package/packages/core/src/ace/Reflector.ts +200 -0
- package/packages/core/src/ace/Tracer.ts +100 -0
- package/packages/core/src/ace/index.ts +4 -0
- package/packages/core/src/agent/AgentRunner.ts +699 -0
- package/packages/core/src/agent/Compaction.ts +221 -0
- package/packages/core/src/agent/ContextCompiler.ts +567 -0
- package/packages/core/src/agent/ContextGuard.ts +91 -0
- package/packages/core/src/agent/ConversationStore.ts +244 -0
- package/packages/core/src/agent/Hooks.ts +166 -0
- package/packages/core/src/agent/NativeTools.ts +31 -0
- package/packages/core/src/agent/PromptBuilder.ts +169 -0
- package/packages/core/src/agent/Service.ts +267 -0
- package/packages/core/src/agent/StuckLoop.ts +133 -0
- package/packages/core/src/agent/index.ts +12 -0
- package/packages/core/src/agent/providers/LLMClient.ts +149 -0
- package/packages/core/src/agent/providers/anthropic.ts +212 -0
- package/packages/core/src/agent/providers/gemini.ts +215 -0
- package/packages/core/src/agent/providers/index.ts +199 -0
- package/packages/core/src/agent/providers/interface.ts +195 -0
- package/packages/core/src/agent/providers/ollama.ts +175 -0
- package/packages/core/src/agent/providers/openai-compat.ts +231 -0
- package/packages/core/src/agent/providers.ts +1 -0
- package/packages/core/src/agent/selectors/PlaybookSelector.ts +147 -0
- package/packages/core/src/agent/selectors/SkillSelector.ts +478 -0
- package/packages/core/src/agent/selectors/ToolSelector.ts +577 -0
- package/packages/core/src/agent/selectors/index.ts +6 -0
- package/packages/core/src/api/createAgent.test.ts +48 -0
- package/packages/core/src/api/createAgent.ts +122 -0
- package/packages/core/src/api/index.ts +2 -0
- package/packages/core/src/canvas/CanvasManager.ts +390 -0
- package/packages/core/src/canvas/a2ui-tools.ts +255 -0
- package/packages/core/src/canvas/canvas-tools.ts +448 -0
- package/packages/core/src/canvas/emitter.ts +149 -0
- package/packages/core/src/canvas/index.ts +6 -0
- package/packages/core/src/config/index.ts +2 -0
- package/packages/core/src/config/loader.ts +554 -0
- package/packages/core/src/ethics/EthicsGuard.test.ts +54 -0
- package/packages/core/src/ethics/EthicsGuard.ts +66 -0
- package/packages/core/src/ethics/index.ts +2 -0
- package/packages/core/src/gateway/channel-notify.test.ts +14 -0
- package/packages/core/src/gateway/channel-notify.ts +12 -0
- package/packages/core/src/gateway/index.ts +1 -0
- package/packages/core/src/index.ts +37 -0
- package/packages/core/src/mcp/MCPClient.ts +439 -0
- package/packages/core/src/mcp/MCPToolAdapter.ts +176 -0
- package/packages/core/src/mcp/config.ts +13 -0
- package/packages/core/src/mcp/hot-reload.ts +147 -0
- package/packages/core/src/mcp/index.ts +11 -0
- package/packages/core/src/mcp/logger.ts +42 -0
- package/packages/core/src/mcp/singleton.ts +21 -0
- package/packages/core/src/mcp/transports/index.ts +67 -0
- package/packages/core/src/mcp/transports/sse.ts +241 -0
- package/packages/core/src/mcp/transports/websocket.ts +159 -0
- package/packages/core/src/memory/Scratchpad.test.ts +47 -0
- package/packages/core/src/memory/Scratchpad.ts +37 -0
- package/packages/core/src/memory/Storage.ts +6 -0
- package/packages/core/src/memory/index.ts +2 -0
- package/packages/core/src/multimodal/VisionService.ts +293 -0
- package/packages/core/src/multimodal/index.ts +2 -0
- package/packages/core/src/multimodal/types.ts +28 -0
- package/packages/core/src/security/Pairing.ts +250 -0
- package/packages/core/src/security/RateLimit.ts +270 -0
- package/packages/core/src/security/index.ts +4 -0
- package/packages/core/src/skills/SkillLoader.ts +388 -0
- package/packages/core/src/skills/bundled-data.generated.ts +3332 -0
- package/packages/core/src/skills/defineSkill.ts +18 -0
- package/packages/core/src/skills/index.ts +4 -0
- package/packages/core/src/state/index.ts +2 -0
- package/packages/core/src/state/store.ts +312 -0
- package/packages/core/src/storage/SQLiteStorage.ts +407 -0
- package/packages/core/src/storage/crypto.ts +101 -0
- package/packages/core/src/storage/index.ts +10 -0
- package/packages/core/src/storage/onboarding.ts +1603 -0
- package/packages/core/src/storage/schema.ts +689 -0
- package/packages/core/src/storage/seed.ts +740 -0
- package/packages/core/src/storage/usage.ts +374 -0
- package/packages/core/src/swarm/AgentBus.ts +460 -0
- package/packages/core/src/swarm/AgentExecutor.ts +53 -0
- package/packages/core/src/swarm/Coordinator.ts +251 -0
- package/packages/core/src/swarm/EventBridge.ts +122 -0
- package/packages/core/src/swarm/EventBus.ts +169 -0
- package/packages/core/src/swarm/TaskGraph.ts +192 -0
- package/packages/core/src/swarm/TaskNode.ts +97 -0
- package/packages/core/src/swarm/TaskResult.ts +22 -0
- package/packages/core/src/swarm/WorkerPool.ts +236 -0
- package/packages/core/src/swarm/errors.ts +37 -0
- package/packages/core/src/swarm/index.ts +30 -0
- package/packages/core/src/swarm/presets/HiveLearnPreset.ts +99 -0
- package/packages/core/src/swarm/presets/ResearchPreset.ts +97 -0
- package/packages/core/src/swarm/presets/index.ts +4 -0
- package/packages/core/src/swarm/strategies/ParallelStrategy.ts +21 -0
- package/packages/core/src/swarm/strategies/PriorityStrategy.ts +46 -0
- package/packages/core/src/swarm/strategies/index.ts +3 -0
- package/packages/core/src/swarm/types.ts +164 -0
- package/packages/core/src/tools/ToolExecutor.ts +58 -0
- package/packages/core/src/tools/ToolRegistry.test.ts +98 -0
- package/packages/core/src/tools/ToolRegistry.ts +61 -0
- package/packages/core/src/tools/agents/get-available-models.ts +118 -0
- package/packages/core/src/tools/agents/index.ts +715 -0
- package/packages/core/src/tools/bridge-events.ts +26 -0
- package/packages/core/src/tools/canvas/index.ts +375 -0
- package/packages/core/src/tools/cli/index.ts +142 -0
- package/packages/core/src/tools/codebridge/index.ts +342 -0
- package/packages/core/src/tools/core/index.ts +476 -0
- package/packages/core/src/tools/cron/index.ts +626 -0
- package/packages/core/src/tools/filesystem/fs-delete.ts +78 -0
- package/packages/core/src/tools/filesystem/fs-edit.ts +106 -0
- package/packages/core/src/tools/filesystem/fs-exists.ts +63 -0
- package/packages/core/src/tools/filesystem/fs-glob.ts +108 -0
- package/packages/core/src/tools/filesystem/fs-list.ts +129 -0
- package/packages/core/src/tools/filesystem/fs-read.ts +72 -0
- package/packages/core/src/tools/filesystem/fs-write.ts +67 -0
- package/packages/core/src/tools/filesystem/index.ts +34 -0
- package/packages/core/src/tools/filesystem/workspace-guard.ts +62 -0
- package/packages/core/src/tools/index.ts +231 -0
- package/packages/core/src/tools/meeting/index.ts +363 -0
- package/packages/core/src/tools/office/index.ts +47 -0
- package/packages/core/src/tools/office/office-escribir-docx.ts +192 -0
- package/packages/core/src/tools/office/office-escribir-pdf.ts +172 -0
- package/packages/core/src/tools/office/office-escribir-pptx.ts +174 -0
- package/packages/core/src/tools/office/office-escribir-xlsx.ts +116 -0
- package/packages/core/src/tools/office/office-leer-docx.ts +93 -0
- package/packages/core/src/tools/office/office-leer-pdf.ts +114 -0
- package/packages/core/src/tools/office/office-leer-pptx.ts +136 -0
- package/packages/core/src/tools/office/office-leer-xlsx.ts +124 -0
- package/packages/core/src/tools/projects/index.ts +37 -0
- package/packages/core/src/tools/projects/project-create.ts +94 -0
- package/packages/core/src/tools/projects/project-done.ts +66 -0
- package/packages/core/src/tools/projects/project-fail.ts +66 -0
- package/packages/core/src/tools/projects/project-list.ts +96 -0
- package/packages/core/src/tools/projects/project-update.ts +72 -0
- package/packages/core/src/tools/projects/task-create.ts +68 -0
- package/packages/core/src/tools/projects/task-evaluate.ts +93 -0
- package/packages/core/src/tools/projects/task-update.ts +93 -0
- package/packages/core/src/tools/types.ts +39 -0
- package/packages/core/src/tools/voice/index.ts +104 -0
- package/packages/core/src/tools/web/browser-click.ts +78 -0
- package/packages/core/src/tools/web/browser-extract.ts +139 -0
- package/packages/core/src/tools/web/browser-navigate.ts +106 -0
- package/packages/core/src/tools/web/browser-screenshot.ts +87 -0
- package/packages/core/src/tools/web/browser-script.ts +88 -0
- package/packages/core/src/tools/web/browser-service.ts +554 -0
- package/packages/core/src/tools/web/browser-type.ts +101 -0
- package/packages/core/src/tools/web/browser-wait.ts +136 -0
- package/packages/core/src/tools/web/index.ts +41 -0
- package/packages/core/src/tools/web/web-fetch.ts +78 -0
- package/packages/core/src/tools/web/web-search.ts +123 -0
- package/packages/core/src/utils/benchmark.ts +80 -0
- package/packages/core/src/utils/crypto.ts +73 -0
- package/packages/core/src/utils/date.ts +42 -0
- package/packages/core/src/utils/index.ts +10 -0
- package/packages/core/src/utils/logger.ts +389 -0
- package/packages/core/src/utils/retry.ts +70 -0
- package/packages/core/src/utils/toon.ts +253 -0
- package/packages/core/src/voice/index.ts +656 -0
- package/test/setup-db.ts +216 -0
- package/tsconfig.json +39 -0
- package/src/agents.ts +0 -1
- package/src/canvas.ts +0 -1
- package/src/channels.ts +0 -1
- package/src/config.ts +0 -1
- package/src/events.ts +0 -1
- package/src/gateway.ts +0 -1
- package/src/index.ts +0 -304
- package/src/mcp.ts +0 -1
- package/src/multimodal.ts +0 -1
- package/src/scheduler.ts +0 -1
- package/src/security.ts +0 -1
- package/src/skills.ts +0 -1
- package/src/state.ts +0 -1
- package/src/storage.ts +0 -1
- package/src/tools.ts +0 -1
- package/src/tts.ts +0 -1
- package/src/types.ts +0 -82
- package/src/utils.ts +0 -1
- package/src/voice.ts +0 -1
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Tools - 4 tools
|
|
3
|
+
*
|
|
4
|
+
* @category core
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Tool } from "../types.ts";
|
|
8
|
+
import { getDb } from "../../storage/SQLiteStorage.ts";
|
|
9
|
+
import { logger } from "../../utils/logger.ts";
|
|
10
|
+
|
|
11
|
+
const log = logger.child("core");
|
|
12
|
+
|
|
13
|
+
// ─── Bilingual dictionary: Spanish → English ────────────────────────────────
|
|
14
|
+
|
|
15
|
+
const ES_EN_DICT: Record<string, string[]> = {
|
|
16
|
+
// Acciones
|
|
17
|
+
"buscar": ["search", "find", "list", "get", "query"],
|
|
18
|
+
"listar": ["list", "get", "fetch", "retrieve"],
|
|
19
|
+
"crear": ["create", "add", "insert", "new", "make"],
|
|
20
|
+
"actualizar": ["update", "edit", "modify", "change"],
|
|
21
|
+
"eliminar": ["delete", "remove", "destroy"],
|
|
22
|
+
"obtener": ["get", "fetch", "retrieve", "read"],
|
|
23
|
+
"enviar": ["send", "post", "submit", "push"],
|
|
24
|
+
"leer": ["read", "get", "fetch"],
|
|
25
|
+
"escribir": ["write", "create", "save"],
|
|
26
|
+
"modificar": ["update", "modify", "edit", "change"],
|
|
27
|
+
"ejecutar": ["execute", "run", "invoke"],
|
|
28
|
+
"conectar": ["connect", "link"],
|
|
29
|
+
"desconectar": ["disconnect", "remove"],
|
|
30
|
+
"descargar": ["download", "export", "fetch"],
|
|
31
|
+
"subir": ["upload", "import", "create"],
|
|
32
|
+
"analizar": ["analyze", "review", "examine"],
|
|
33
|
+
"generar": ["generate", "create", "produce"],
|
|
34
|
+
"convertir": ["convert", "transform", "translate"],
|
|
35
|
+
"validar": ["validate", "verify", "check"],
|
|
36
|
+
"importar": ["import", "load", "ingest"],
|
|
37
|
+
"exportar": ["export", "download", "extract"],
|
|
38
|
+
"comprimir": ["compress", "zip", "archive"],
|
|
39
|
+
"extraer": ["extract", "get", "retrieve", "parse"],
|
|
40
|
+
"reemplazar": ["replace", "update", "swap"],
|
|
41
|
+
"cargar": ["load", "import", "upload"],
|
|
42
|
+
"guardar": ["save", "store", "create"],
|
|
43
|
+
"consultar": ["query", "search", "get", "list"],
|
|
44
|
+
"registrar": ["register", "create", "log", "record"],
|
|
45
|
+
"programar": ["schedule", "plan", "cron"],
|
|
46
|
+
"notificar": ["notify", "alert", "send"],
|
|
47
|
+
"reiniciar": ["restart", "reset", "reboot"],
|
|
48
|
+
"configurar": ["configure", "setup", "set"],
|
|
49
|
+
"autenticar": ["authenticate", "login", "auth"],
|
|
50
|
+
"publicar": ["publish", "deploy", "release"],
|
|
51
|
+
"desplegar": ["deploy", "publish", "release"],
|
|
52
|
+
"copiar": ["copy", "clone", "duplicate"],
|
|
53
|
+
"mover": ["move", "transfer", "migrate"],
|
|
54
|
+
"comparar": ["compare", "diff", "match"],
|
|
55
|
+
"fusionar": ["merge", "combine", "join"],
|
|
56
|
+
"dividir": ["split", "divide", "partition"],
|
|
57
|
+
"filtrar": ["filter", "search", "query"],
|
|
58
|
+
"ordenar": ["sort", "order", "arrange"],
|
|
59
|
+
"traducir": ["translate", "convert"],
|
|
60
|
+
|
|
61
|
+
// Entidades
|
|
62
|
+
"base": ["base", "database", "db"],
|
|
63
|
+
"bases": ["bases", "databases"],
|
|
64
|
+
"datos": ["data", "records", "rows", "entries"],
|
|
65
|
+
"registro": ["record", "entry", "row", "item"],
|
|
66
|
+
"registros": ["records", "entries", "rows", "items"],
|
|
67
|
+
"tabla": ["table", "schema", "collection"],
|
|
68
|
+
"tablas": ["tables", "schemas"],
|
|
69
|
+
"campo": ["field", "column", "property"],
|
|
70
|
+
"campos": ["fields", "columns", "properties"],
|
|
71
|
+
"usuario": ["user", "account"],
|
|
72
|
+
"usuarios": ["users", "accounts"],
|
|
73
|
+
"proyecto": ["project", "repo", "workspace"],
|
|
74
|
+
"proyectos": ["projects", "repos", "workspaces"],
|
|
75
|
+
"archivo": ["file", "document"],
|
|
76
|
+
"archivos": ["files", "documents"],
|
|
77
|
+
"correo": ["email", "mail", "message"],
|
|
78
|
+
"correos": ["emails", "mails", "messages"],
|
|
79
|
+
"noticia": ["news", "article", "post"],
|
|
80
|
+
"noticias": ["news", "articles", "posts"],
|
|
81
|
+
"contenido": ["content", "data", "text"],
|
|
82
|
+
"tarea": ["task", "job", "issue", "ticket"],
|
|
83
|
+
"tareas": ["tasks", "jobs", "issues", "tickets"],
|
|
84
|
+
"pagina": ["page", "site", "web"],
|
|
85
|
+
"enlace": ["link", "url", "reference"],
|
|
86
|
+
"imagen": ["image", "picture", "photo"],
|
|
87
|
+
"video": ["video", "media"],
|
|
88
|
+
"audio": ["audio", "sound", "media"],
|
|
89
|
+
"categoria": ["category", "tag", "label"],
|
|
90
|
+
"estado": ["status", "state", "condition"],
|
|
91
|
+
"error": ["error", "exception", "fault"],
|
|
92
|
+
"fuente": ["source", "origin", "reference"],
|
|
93
|
+
"esquema": ["schema", "structure", "model"],
|
|
94
|
+
"respuesta": ["response", "reply", "answer"],
|
|
95
|
+
"solicitud": ["request", "query", "call"],
|
|
96
|
+
"repositorio": ["repository", "repo"],
|
|
97
|
+
"seguridad": ["security", "auth", "permission"],
|
|
98
|
+
"permiso": ["permission", "role", "access"],
|
|
99
|
+
"acceso": ["access", "login", "entry"],
|
|
100
|
+
"servidor": ["server", "host", "service"],
|
|
101
|
+
"conexion": ["connection", "link", "integration"],
|
|
102
|
+
"integracion": ["integration", "connector", "plugin"],
|
|
103
|
+
"herramienta": ["tool", "utility", "function"],
|
|
104
|
+
"informacion": ["info", "information", "details"],
|
|
105
|
+
"lista": ["list", "collection", "array"],
|
|
106
|
+
"reporte": ["report", "summary", "analytics"],
|
|
107
|
+
"metrica": ["metric", "stat", "analytics"],
|
|
108
|
+
"contacto": ["contact", "lead", "person"],
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Translate a Spanish query to English equivalents for FTS5 fallback.
|
|
113
|
+
* Returns an array of English keyword tokens.
|
|
114
|
+
*/
|
|
115
|
+
function translateQueryToEnglish(query: string): string {
|
|
116
|
+
const words = query.toLowerCase().replace(/_/g, " ").split(/\s+/).filter(w => w.length > 1);
|
|
117
|
+
const translated: string[] = [];
|
|
118
|
+
|
|
119
|
+
for (const word of words) {
|
|
120
|
+
const equivalents = ES_EN_DICT[word];
|
|
121
|
+
if (equivalents) {
|
|
122
|
+
translated.push(...equivalents);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return [...new Set(translated)].join(" ");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Build an FTS5 MATCH expression from a list of words.
|
|
131
|
+
* Multi-word: AND with prefix wildcard. Single: exact OR prefix.
|
|
132
|
+
*/
|
|
133
|
+
function buildFtsMatch(words: string[]): string {
|
|
134
|
+
if (words.length > 1) {
|
|
135
|
+
return words.map(w => `${w}*`).join(' AND ');
|
|
136
|
+
}
|
|
137
|
+
return `"${words.join(' ')}" OR ${words[0]}*`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ─── search_knowledge ────────────────────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
export const searchKnowledgeTool: Tool = {
|
|
143
|
+
name: "search_knowledge",
|
|
144
|
+
description: "Busca herramientas NATIVAS (tools), MCP (tools externas), habilidades (skills) o reglas del playbook en la base de conocimientos. Usa búsqueda full-text (FTS5) con fallback bilingüe español→inglés. type='mcp' para herramientas MCP, type='all' para buscar en todo.",
|
|
145
|
+
parameters: {
|
|
146
|
+
type: "object",
|
|
147
|
+
properties: {
|
|
148
|
+
query: {
|
|
149
|
+
type: "string",
|
|
150
|
+
description: "Término de búsqueda (nombre, descripción, categoría). Se busca primero en español, luego en inglés si hay pocos resultados.",
|
|
151
|
+
},
|
|
152
|
+
type: {
|
|
153
|
+
type: "string",
|
|
154
|
+
enum: ["all", "tools", "skills", "playbook", "mcp"],
|
|
155
|
+
description: "Tipo de conocimiento a buscar",
|
|
156
|
+
},
|
|
157
|
+
limit: {
|
|
158
|
+
type: "number",
|
|
159
|
+
description: "Máximo de resultados (default: 10)",
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
required: ["query"],
|
|
163
|
+
},
|
|
164
|
+
execute: async (params: Record<string, unknown>) => {
|
|
165
|
+
const db = getDb();
|
|
166
|
+
const query = params.query as string;
|
|
167
|
+
const type = (params.type as string) ?? "all";
|
|
168
|
+
const limit = (params.limit as number) ?? 10;
|
|
169
|
+
const MIN_RESULTS_FOR_BILINGUAL = 2;
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
const escapedQuery = query.replace(/'/g, "''");
|
|
173
|
+
const normalizedQuery = escapedQuery.replace(/_/g, " ").trim();
|
|
174
|
+
const words = normalizedQuery.split(/\s+/).filter(w => w.length > 0);
|
|
175
|
+
const ftsMatch = buildFtsMatch(words);
|
|
176
|
+
|
|
177
|
+
const result: any = { query, type, tools: [], skills: [], playbook: [], toolsmcp: [] };
|
|
178
|
+
|
|
179
|
+
// ─── Search functions (reusable for bilingual fallback) ───────────
|
|
180
|
+
|
|
181
|
+
function searchTools(matchExpr: string): any[] {
|
|
182
|
+
if (type !== "all" && type !== "tools") return [];
|
|
183
|
+
try {
|
|
184
|
+
return db.query(`
|
|
185
|
+
SELECT
|
|
186
|
+
COALESCE(t.id, tools_fts.tool_name) as id,
|
|
187
|
+
COALESCE(t.name, tools_fts.tool_name) as name,
|
|
188
|
+
COALESCE(t.description, tools_fts.description) as description,
|
|
189
|
+
COALESCE(t.category, tools_fts.category) as category,
|
|
190
|
+
COALESCE(t.enabled, 1) as enabled,
|
|
191
|
+
COALESCE(t.active, 1) as active,
|
|
192
|
+
bm25(tools_fts) as rank
|
|
193
|
+
FROM tools_fts
|
|
194
|
+
LEFT JOIN tools t ON t.name = tools_fts.tool_name
|
|
195
|
+
WHERE tools_fts MATCH ?
|
|
196
|
+
ORDER BY rank
|
|
197
|
+
LIMIT ?
|
|
198
|
+
`).all(matchExpr, limit) as any[];
|
|
199
|
+
} catch { return []; }
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function searchSkills(matchExpr: string): any[] {
|
|
203
|
+
if (type !== "all" && type !== "skills") return [];
|
|
204
|
+
try {
|
|
205
|
+
return db.query(`
|
|
206
|
+
SELECT s.id, s.name, s.description, s.category, s.tools, s.triggers, s.preferred_agents, s.body, s.active, bm25(skills_fts) as rank
|
|
207
|
+
FROM skills_fts
|
|
208
|
+
JOIN skills s ON s.id = skills_fts.id
|
|
209
|
+
WHERE skills_fts MATCH ?
|
|
210
|
+
ORDER BY rank
|
|
211
|
+
LIMIT ?
|
|
212
|
+
`).all(matchExpr, limit) as any[];
|
|
213
|
+
} catch { return []; }
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function searchPlaybook(matchExpr: string): any[] {
|
|
217
|
+
if (type !== "all" && type !== "playbook") return [];
|
|
218
|
+
try {
|
|
219
|
+
return db.query(`
|
|
220
|
+
SELECT p.id, p.rule, p.category, p.applicable_to, p.helpful_count, p.harmful_count, p.active, bm25(playbook_fts) as rank
|
|
221
|
+
FROM playbook_fts
|
|
222
|
+
JOIN playbook p ON p.id = playbook_fts.rowid
|
|
223
|
+
WHERE playbook_fts MATCH ?
|
|
224
|
+
ORDER BY rank
|
|
225
|
+
LIMIT ?
|
|
226
|
+
`).all(matchExpr, limit) as any[];
|
|
227
|
+
} catch { return []; }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function searchMcpTools(matchExpr: string): any[] {
|
|
231
|
+
if (type !== "all" && type !== "mcp") return [];
|
|
232
|
+
try {
|
|
233
|
+
return db.query(`
|
|
234
|
+
SELECT m.id, m.server_name, m.tool_name, m.description, m.category, m.active, bm25(mcp_tools_fts) as rank
|
|
235
|
+
FROM mcp_tools_fts
|
|
236
|
+
JOIN mcp_tools m ON m.id = mcp_tools_fts.id
|
|
237
|
+
WHERE mcp_tools_fts MATCH ?
|
|
238
|
+
ORDER BY rank
|
|
239
|
+
LIMIT ?
|
|
240
|
+
`).all(matchExpr, limit) as any[];
|
|
241
|
+
} catch { return []; }
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ─── Pass 1: Search with original query ─────────────────────────
|
|
245
|
+
|
|
246
|
+
const tools1 = searchTools(ftsMatch);
|
|
247
|
+
const skills1 = searchSkills(ftsMatch);
|
|
248
|
+
const playbook1 = searchPlaybook(ftsMatch);
|
|
249
|
+
const mcp1 = searchMcpTools(ftsMatch);
|
|
250
|
+
|
|
251
|
+
const totalFirst = tools1.length + skills1.length + playbook1.length + mcp1.length;
|
|
252
|
+
|
|
253
|
+
// Map results
|
|
254
|
+
result.tools = tools1.map((t: any) => ({
|
|
255
|
+
id: t.id, name: t.name, description: t.description, category: t.category,
|
|
256
|
+
enabled: t.enabled === 1, active: t.active === 1, rank: t.rank,
|
|
257
|
+
}));
|
|
258
|
+
result.skills = skills1.map((s: any) => ({
|
|
259
|
+
id: s.id, name: s.name, description: s.description, category: s.category,
|
|
260
|
+
tools: s.tools, triggers: s.triggers,
|
|
261
|
+
preferred_agents: s.preferred_agents ? JSON.parse(s.preferred_agents) : [],
|
|
262
|
+
body: s.body ? (s.body.length > 400 ? s.body.substring(0, 400) + "…" : s.body) : undefined,
|
|
263
|
+
active: s.active === 1, rank: s.rank,
|
|
264
|
+
}));
|
|
265
|
+
result.playbook = playbook1.map((p: any) => ({
|
|
266
|
+
id: p.id, rule: p.rule, category: p.category,
|
|
267
|
+
applicable_to: p.applicable_to ? JSON.parse(p.applicable_to) : null,
|
|
268
|
+
helpful_count: p.helpful_count, harmful_count: p.harmful_count,
|
|
269
|
+
active: p.active === 1, rank: p.rank,
|
|
270
|
+
}));
|
|
271
|
+
result.toolsmcp = mcp1.map((t: any) => ({
|
|
272
|
+
id: t.id, full_name: t.id, server_name: t.server_name, tool_name: t.tool_name,
|
|
273
|
+
description: t.description, category: t.category,
|
|
274
|
+
active: t.active === 1, rank: t.rank,
|
|
275
|
+
}));
|
|
276
|
+
|
|
277
|
+
// ─── Pass 2: Bilingual fallback (ES → EN) ──────────────────────
|
|
278
|
+
|
|
279
|
+
if (totalFirst < MIN_RESULTS_FOR_BILINGUAL) {
|
|
280
|
+
const englishQuery = translateQueryToEnglish(normalizedQuery);
|
|
281
|
+
if (englishQuery.length > 0) {
|
|
282
|
+
const enWords = englishQuery.split(/\s+/).filter(w => w.length > 0);
|
|
283
|
+
const enMatch = buildFtsMatch(enWords);
|
|
284
|
+
|
|
285
|
+
log.info(`[search_knowledge] Bilingual fallback: "${normalizedQuery}" → "${englishQuery}" (first pass: ${totalFirst} results)`);
|
|
286
|
+
|
|
287
|
+
const existingIds = new Set([
|
|
288
|
+
...result.tools.map((t: any) => t.name),
|
|
289
|
+
...result.skills.map((s: any) => s.id),
|
|
290
|
+
...result.playbook.map((p: any) => p.id),
|
|
291
|
+
...result.toolsmcp.map((t: any) => t.id),
|
|
292
|
+
]);
|
|
293
|
+
|
|
294
|
+
// Merge English results (dedup by id)
|
|
295
|
+
for (const t of searchTools(enMatch)) {
|
|
296
|
+
if (!existingIds.has(t.name || t.id)) {
|
|
297
|
+
result.tools.push({
|
|
298
|
+
id: t.id, name: t.name, description: t.description, category: t.category,
|
|
299
|
+
enabled: t.enabled === 1, active: t.active === 1, rank: t.rank,
|
|
300
|
+
});
|
|
301
|
+
existingIds.add(t.name || t.id);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
for (const s of searchSkills(enMatch)) {
|
|
305
|
+
if (!existingIds.has(s.id)) {
|
|
306
|
+
result.skills.push({
|
|
307
|
+
id: s.id, name: s.name, description: s.description, category: s.category,
|
|
308
|
+
tools: s.tools, triggers: s.triggers,
|
|
309
|
+
preferred_agents: s.preferred_agents ? JSON.parse(s.preferred_agents) : [],
|
|
310
|
+
body: s.body ? (s.body.length > 400 ? s.body.substring(0, 400) + "…" : s.body) : undefined,
|
|
311
|
+
active: s.active === 1, rank: s.rank,
|
|
312
|
+
});
|
|
313
|
+
existingIds.add(s.id);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
for (const p of searchPlaybook(enMatch)) {
|
|
317
|
+
if (!existingIds.has(p.id)) {
|
|
318
|
+
result.playbook.push({
|
|
319
|
+
id: p.id, rule: p.rule, category: p.category,
|
|
320
|
+
applicable_to: p.applicable_to ? JSON.parse(p.applicable_to) : null,
|
|
321
|
+
helpful_count: p.helpful_count, harmful_count: p.harmful_count,
|
|
322
|
+
active: p.active === 1, rank: p.rank,
|
|
323
|
+
});
|
|
324
|
+
existingIds.add(p.id);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
for (const t of searchMcpTools(enMatch)) {
|
|
328
|
+
if (!existingIds.has(t.id)) {
|
|
329
|
+
result.toolsmcp.push({
|
|
330
|
+
id: t.id, full_name: t.id, server_name: t.server_name, tool_name: t.tool_name,
|
|
331
|
+
description: t.description, category: t.category,
|
|
332
|
+
active: t.active === 1, rank: t.rank,
|
|
333
|
+
});
|
|
334
|
+
existingIds.add(t.id);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
result.totalResults = result.tools.length + result.skills.length + result.playbook.length + result.toolsmcp.length;
|
|
341
|
+
|
|
342
|
+
return { ok: true, ...result };
|
|
343
|
+
} catch (error) {
|
|
344
|
+
return {
|
|
345
|
+
ok: false,
|
|
346
|
+
error: `Search failed: ${(error as Error).message}`,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// ─── notify ──────────────────────────────────────────────────────────────────
|
|
353
|
+
|
|
354
|
+
export const notifyTool: Tool = {
|
|
355
|
+
name: "notify",
|
|
356
|
+
description: "Send a notification or progress update to the user's active channel. Use this to keep the user informed while working on long tasks.",
|
|
357
|
+
parameters: {
|
|
358
|
+
type: "object",
|
|
359
|
+
properties: {
|
|
360
|
+
message: {
|
|
361
|
+
type: "string",
|
|
362
|
+
description: "Notification message to send to the user",
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
required: ["message"],
|
|
366
|
+
},
|
|
367
|
+
execute: async (params: Record<string, unknown>, config?: any) => {
|
|
368
|
+
const { sendToUserChannel } = await import("../../gateway/channel-notify.ts");
|
|
369
|
+
const message = params.message as string;
|
|
370
|
+
const channel = (config?.configurable?.channel as string) ?? "webchat";
|
|
371
|
+
const userId = (config?.configurable?.user_id as string) ?? "";
|
|
372
|
+
|
|
373
|
+
log.info(`[notify] Sending to ${channel}/${userId}: ${message.substring(0, 80)}`);
|
|
374
|
+
|
|
375
|
+
const result = await sendToUserChannel(channel, userId, message)
|
|
376
|
+
if (!result.ok) throw new Error(`Channel send failed: ${result.error}`)
|
|
377
|
+
return result
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// ─── save_note (scratchpad) ──────────────────────────────────────────────────
|
|
382
|
+
|
|
383
|
+
export const saveNoteTool: Tool = {
|
|
384
|
+
name: "save_note",
|
|
385
|
+
description: "Save a note to the scratchpad (survives context compression).",
|
|
386
|
+
parameters: {
|
|
387
|
+
type: "object",
|
|
388
|
+
properties: {
|
|
389
|
+
key: {
|
|
390
|
+
type: "string",
|
|
391
|
+
description: "Unique key for the note",
|
|
392
|
+
},
|
|
393
|
+
value: {
|
|
394
|
+
type: "string",
|
|
395
|
+
description: "Note content",
|
|
396
|
+
},
|
|
397
|
+
thread_id: {
|
|
398
|
+
type: "string",
|
|
399
|
+
description: "Thread ID (optional, uses current thread if not specified)",
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
required: ["key", "value"],
|
|
403
|
+
},
|
|
404
|
+
execute: async (params: Record<string, unknown>, config?: any) => {
|
|
405
|
+
const db = getDb();
|
|
406
|
+
const key = params.key as string;
|
|
407
|
+
const value = params.value as string;
|
|
408
|
+
const threadId = (params.thread_id as string) ?? config?.configurable?.thread_id ?? "default";
|
|
409
|
+
|
|
410
|
+
try {
|
|
411
|
+
db.query(`
|
|
412
|
+
INSERT OR REPLACE INTO scratchpad (thread_id, key, value, source, updated_at)
|
|
413
|
+
VALUES (?, ?, ?, 'agent', unixepoch())
|
|
414
|
+
`).run(threadId, key, value);
|
|
415
|
+
|
|
416
|
+
return { ok: true, key, message: "Note saved." };
|
|
417
|
+
} catch (error) {
|
|
418
|
+
return {
|
|
419
|
+
ok: false,
|
|
420
|
+
error: `Failed to save note: ${(error as Error).message}`,
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// ─── report_progress ─────────────────────────────────────────────────────────
|
|
427
|
+
|
|
428
|
+
export const reportProgressTool: Tool = {
|
|
429
|
+
name: "report_progress",
|
|
430
|
+
description: "Report progress of an ongoing task to the user. Sends a real-time update to the active channel. Use frequently during long operations so the user knows what's happening.",
|
|
431
|
+
parameters: {
|
|
432
|
+
type: "object",
|
|
433
|
+
properties: {
|
|
434
|
+
progress: {
|
|
435
|
+
type: "number",
|
|
436
|
+
description: "Progress percentage (0-100)",
|
|
437
|
+
},
|
|
438
|
+
message: {
|
|
439
|
+
type: "string",
|
|
440
|
+
description: "Progress message describing what you are currently doing",
|
|
441
|
+
},
|
|
442
|
+
task_id: {
|
|
443
|
+
type: "string",
|
|
444
|
+
description: "Task or project ID (optional)",
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
required: ["progress", "message"],
|
|
448
|
+
},
|
|
449
|
+
execute: async (params: Record<string, unknown>, config?: any) => {
|
|
450
|
+
const { sendToUserChannel } = await import("../../gateway/channel-notify.ts");
|
|
451
|
+
const progress = params.progress as number;
|
|
452
|
+
const message = params.message as string;
|
|
453
|
+
const taskId = (params.task_id as string) ?? null;
|
|
454
|
+
const channel = (config?.configurable?.channel as string) ?? "webchat";
|
|
455
|
+
const userId = (config?.configurable?.user_id as string) ?? "";
|
|
456
|
+
|
|
457
|
+
log.info(`[report_progress] ${progress}% — ${message}`);
|
|
458
|
+
|
|
459
|
+
// Update task progress in DB if task_id provided
|
|
460
|
+
if (taskId) {
|
|
461
|
+
const db = getDb();
|
|
462
|
+
db.query(`UPDATE tasks SET progress = ?, updated_at = unixepoch() WHERE id = ?`).run(progress, taskId);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Send real-time update to the user's channel
|
|
466
|
+
const progressEmoji = progress >= 100 ? "✅" : progress >= 50 ? "⚙️" : "🔄";
|
|
467
|
+
const result = await sendToUserChannel(channel, userId, `${progressEmoji} ${progress}% — ${message}`)
|
|
468
|
+
if (!result.ok) throw new Error(`Channel send failed: ${result.error}`)
|
|
469
|
+
|
|
470
|
+
return { ok: true, progress, message, task_id: taskId };
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
export function createTools(): Tool[] {
|
|
475
|
+
return [searchKnowledgeTool, notifyTool, saveNoteTool, reportProgressTool];
|
|
476
|
+
}
|