@johpaz/hive-sdk 0.0.12 → 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,460 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Bus - Sistema de mensajería pub/sub para comunicación entre workers
|
|
3
|
+
*
|
|
4
|
+
* Permite que los workers se comuniquen entre sí sin pasar por el coordinador.
|
|
5
|
+
* Útil para:
|
|
6
|
+
* - Notificar completado de tareas con dependencias
|
|
7
|
+
* - Solicitar ayuda entre workers
|
|
8
|
+
* - Compartir resultados intermedios
|
|
9
|
+
* - Coordinar ejecución en paralelo
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { EventEmitter } from "events";
|
|
13
|
+
import { logger } from "../utils/logger.ts";
|
|
14
|
+
import { getDb } from "../storage/SQLiteStorage.ts";
|
|
15
|
+
|
|
16
|
+
const log = logger.child("agent-bus");
|
|
17
|
+
|
|
18
|
+
// ─── Tipos de eventos ────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
export interface AgentBusEventMap {
|
|
21
|
+
"worker:task_started": {
|
|
22
|
+
workerId: string;
|
|
23
|
+
workerName: string;
|
|
24
|
+
taskId: number;
|
|
25
|
+
taskName: string;
|
|
26
|
+
projectId: string;
|
|
27
|
+
timestamp: number;
|
|
28
|
+
};
|
|
29
|
+
"worker:task_completed": {
|
|
30
|
+
workerId: string;
|
|
31
|
+
workerName: string;
|
|
32
|
+
taskId: number;
|
|
33
|
+
taskName: string;
|
|
34
|
+
projectId: string;
|
|
35
|
+
result: string;
|
|
36
|
+
timestamp: number;
|
|
37
|
+
};
|
|
38
|
+
"worker:task_failed": {
|
|
39
|
+
workerId: string;
|
|
40
|
+
workerName: string;
|
|
41
|
+
taskId: number;
|
|
42
|
+
taskName: string;
|
|
43
|
+
projectId: string;
|
|
44
|
+
error: string;
|
|
45
|
+
timestamp: number;
|
|
46
|
+
};
|
|
47
|
+
"worker:help_request": {
|
|
48
|
+
fromWorkerId: string;
|
|
49
|
+
fromWorkerName: string;
|
|
50
|
+
taskId: number;
|
|
51
|
+
request: string;
|
|
52
|
+
requiredSkill?: string;
|
|
53
|
+
timestamp: number;
|
|
54
|
+
};
|
|
55
|
+
"worker:help_response": {
|
|
56
|
+
toWorkerId: string;
|
|
57
|
+
fromWorkerId: string;
|
|
58
|
+
fromWorkerName: string;
|
|
59
|
+
taskId: number;
|
|
60
|
+
response: string;
|
|
61
|
+
timestamp: number;
|
|
62
|
+
};
|
|
63
|
+
"worker:blocked": {
|
|
64
|
+
workerId: string;
|
|
65
|
+
workerName: string;
|
|
66
|
+
taskId: number;
|
|
67
|
+
blockedBy: string;
|
|
68
|
+
reason: string;
|
|
69
|
+
timestamp: number;
|
|
70
|
+
};
|
|
71
|
+
"worker:unblocked": {
|
|
72
|
+
workerId: string;
|
|
73
|
+
workerName: string;
|
|
74
|
+
taskId: number;
|
|
75
|
+
unblockedBy: string;
|
|
76
|
+
timestamp: number;
|
|
77
|
+
};
|
|
78
|
+
"project:started": {
|
|
79
|
+
projectId: string;
|
|
80
|
+
projectName: string;
|
|
81
|
+
coordinatorId: string;
|
|
82
|
+
timestamp: number;
|
|
83
|
+
};
|
|
84
|
+
"project:completed": {
|
|
85
|
+
projectId: string;
|
|
86
|
+
projectName: string;
|
|
87
|
+
coordinatorId: string;
|
|
88
|
+
summary: string;
|
|
89
|
+
timestamp: number;
|
|
90
|
+
};
|
|
91
|
+
"message:custom": {
|
|
92
|
+
fromWorkerId: string;
|
|
93
|
+
fromWorkerName: string;
|
|
94
|
+
toWorkerId?: string;
|
|
95
|
+
topic: string;
|
|
96
|
+
content: string;
|
|
97
|
+
timestamp: number;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type AgentBusEventKey = keyof AgentBusEventMap;
|
|
102
|
+
|
|
103
|
+
export interface AgentBusEventHandler<K extends AgentBusEventKey> {
|
|
104
|
+
(data: AgentBusEventMap[K]): void | Promise<void>;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ─── Message Store - Persistencia de mensajes en BD ─────────────────────────
|
|
108
|
+
|
|
109
|
+
export interface AgentBusMessage {
|
|
110
|
+
id: number;
|
|
111
|
+
event_type: string;
|
|
112
|
+
from_worker_id: string | null;
|
|
113
|
+
to_worker_id: string | null;
|
|
114
|
+
topic: string | null;
|
|
115
|
+
content: string;
|
|
116
|
+
metadata: string | null;
|
|
117
|
+
created_at: number;
|
|
118
|
+
read: number;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Guarda un mensaje en la base de datos para persistencia
|
|
123
|
+
*/
|
|
124
|
+
function persistMessage(event: AgentBusEventKey, data: any, metadata?: Record<string, unknown>): void {
|
|
125
|
+
const db = getDb();
|
|
126
|
+
|
|
127
|
+
// Extraer IDs de worker según el tipo de evento
|
|
128
|
+
let fromWorkerId: string | null = null;
|
|
129
|
+
let toWorkerId: string | null = null;
|
|
130
|
+
let topic: string | null = null;
|
|
131
|
+
let content: string;
|
|
132
|
+
|
|
133
|
+
switch (event) {
|
|
134
|
+
case "worker:task_started":
|
|
135
|
+
case "worker:task_completed":
|
|
136
|
+
case "worker:task_failed":
|
|
137
|
+
fromWorkerId = (data as any).workerId || null;
|
|
138
|
+
topic = event;
|
|
139
|
+
content = JSON.stringify(data);
|
|
140
|
+
break;
|
|
141
|
+
case "worker:help_request":
|
|
142
|
+
fromWorkerId = (data as any).fromWorkerId || null;
|
|
143
|
+
topic = "help_request";
|
|
144
|
+
content = (data as any).request || "";
|
|
145
|
+
break;
|
|
146
|
+
case "worker:help_response":
|
|
147
|
+
fromWorkerId = (data as any).fromWorkerId || null;
|
|
148
|
+
toWorkerId = (data as any).toWorkerId || null;
|
|
149
|
+
topic = "help_response";
|
|
150
|
+
content = (data as any).response || "";
|
|
151
|
+
break;
|
|
152
|
+
case "worker:blocked":
|
|
153
|
+
case "worker:unblocked":
|
|
154
|
+
fromWorkerId = (data as any).workerId || null;
|
|
155
|
+
topic = event;
|
|
156
|
+
content = JSON.stringify(data);
|
|
157
|
+
break;
|
|
158
|
+
case "message:custom":
|
|
159
|
+
fromWorkerId = (data as any).fromWorkerId || null;
|
|
160
|
+
toWorkerId = (data as any).toWorkerId || null;
|
|
161
|
+
topic = (data as any).topic || null;
|
|
162
|
+
content = (data as any).content || "";
|
|
163
|
+
break;
|
|
164
|
+
default:
|
|
165
|
+
fromWorkerId = (data as any).workerId || (data as any).fromWorkerId || null;
|
|
166
|
+
topic = event;
|
|
167
|
+
content = JSON.stringify(data);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
db.query(`
|
|
172
|
+
INSERT OR IGNORE INTO agent_bus_messages
|
|
173
|
+
(event_type, from_worker_id, to_worker_id, topic, content, metadata, created_at, read)
|
|
174
|
+
VALUES (?, ?, ?, ?, ?, ?, unixepoch(), 0)
|
|
175
|
+
`).run(
|
|
176
|
+
event,
|
|
177
|
+
fromWorkerId,
|
|
178
|
+
toWorkerId,
|
|
179
|
+
topic,
|
|
180
|
+
content,
|
|
181
|
+
metadata ? JSON.stringify(metadata) : null
|
|
182
|
+
);
|
|
183
|
+
} catch (err) {
|
|
184
|
+
log.warn(`Failed to persist message (non-critical): ${(err as Error).message}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Obtiene mensajes no leídos para un worker específico
|
|
190
|
+
*/
|
|
191
|
+
export function getUnreadMessagesForWorker(workerId: string, limit: number = 50): AgentBusMessage[] {
|
|
192
|
+
const db = getDb();
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
const messages = db.query<any, [string, number]>(`
|
|
196
|
+
SELECT * FROM agent_bus_messages
|
|
197
|
+
WHERE (to_worker_id = ? OR to_worker_id IS NULL) AND read = 0
|
|
198
|
+
ORDER BY created_at ASC
|
|
199
|
+
LIMIT ?
|
|
200
|
+
`).all(workerId, limit);
|
|
201
|
+
|
|
202
|
+
// Marcar como leídos
|
|
203
|
+
if (messages.length > 0) {
|
|
204
|
+
const ids = messages.map((m: AgentBusMessage) => m.id).join(",");
|
|
205
|
+
db.query(`UPDATE agent_bus_messages SET read = 1 WHERE id IN (${ids})`).run();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return messages;
|
|
209
|
+
} catch (err) {
|
|
210
|
+
log.error(`Failed to get unread messages: ${(err as Error).message}`);
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Obtiene el historial de mensajes de un proyecto
|
|
217
|
+
*/
|
|
218
|
+
export function getProjectMessageHistory(projectId: string, limit: number = 100): AgentBusMessage[] {
|
|
219
|
+
const db = getDb();
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
// Primero obtenemos los task_ids del proyecto
|
|
223
|
+
const tasks = db.query<any, [string]>(
|
|
224
|
+
"SELECT id FROM tasks WHERE project_id = ?"
|
|
225
|
+
).all(projectId);
|
|
226
|
+
|
|
227
|
+
if (tasks.length === 0) return [];
|
|
228
|
+
|
|
229
|
+
// Obtenemos los agent_ids de las tareas
|
|
230
|
+
const agentIds = tasks
|
|
231
|
+
.map((t: any) => t.agent_id)
|
|
232
|
+
.filter((id: string | null) => id !== null);
|
|
233
|
+
|
|
234
|
+
if (agentIds.length === 0) return [];
|
|
235
|
+
|
|
236
|
+
// Obtenemos mensajes relacionados a estos agents
|
|
237
|
+
const placeholders = agentIds.map(() => "?").join(",");
|
|
238
|
+
const messages = db.query<any, any[]>(`
|
|
239
|
+
SELECT * FROM agent_bus_messages
|
|
240
|
+
WHERE from_worker_id IN (${placeholders})
|
|
241
|
+
ORDER BY created_at DESC
|
|
242
|
+
LIMIT ?
|
|
243
|
+
`).all([...agentIds, limit]);
|
|
244
|
+
|
|
245
|
+
return messages;
|
|
246
|
+
} catch (err) {
|
|
247
|
+
log.error(`Failed to get project message history: ${(err as Error).message}`);
|
|
248
|
+
return [];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ─── Agent Bus Implementation ────────────────────────────────────────────────
|
|
253
|
+
|
|
254
|
+
class AgentBusImpl {
|
|
255
|
+
private emitter = new EventEmitter();
|
|
256
|
+
private logPrefix = "[agent-bus]";
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Publica un evento en el bus
|
|
260
|
+
*/
|
|
261
|
+
publish<K extends AgentBusEventKey>(event: K, data: AgentBusEventMap[K], metadata?: Record<string, unknown>): void {
|
|
262
|
+
const enrichedData = {
|
|
263
|
+
...data,
|
|
264
|
+
_eventId: crypto.randomUUID(),
|
|
265
|
+
_timestamp: Date.now(),
|
|
266
|
+
_event: event,
|
|
267
|
+
} as AgentBusEventMap[K] & { _eventId: string; _timestamp: number; _event: string };
|
|
268
|
+
|
|
269
|
+
// Emitir evento en memoria
|
|
270
|
+
this.emitter.emit(event, enrichedData);
|
|
271
|
+
|
|
272
|
+
// Persistir en BD
|
|
273
|
+
persistMessage(event, enrichedData, metadata);
|
|
274
|
+
|
|
275
|
+
log.info(`${this.logPrefix} published: ${event}`, {
|
|
276
|
+
event,
|
|
277
|
+
fromWorkerId: (data as any).workerId || (data as any).fromWorkerId,
|
|
278
|
+
toWorkerId: (data as any).toWorkerId
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Se suscribe a un tipo de evento
|
|
284
|
+
*/
|
|
285
|
+
subscribe<K extends AgentBusEventKey>(
|
|
286
|
+
event: K,
|
|
287
|
+
handler: AgentBusEventHandler<K>
|
|
288
|
+
): () => void {
|
|
289
|
+
this.emitter.on(event, handler);
|
|
290
|
+
log.debug(`${this.logPrefix} subscribed to: ${event}`);
|
|
291
|
+
|
|
292
|
+
return () => this.unsubscribe(event, handler);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Se suscribe una vez a un evento
|
|
297
|
+
*/
|
|
298
|
+
subscribeOnce<K extends AgentBusEventKey>(
|
|
299
|
+
event: K,
|
|
300
|
+
handler: AgentBusEventHandler<K>
|
|
301
|
+
): void {
|
|
302
|
+
this.emitter.once(event, handler);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Cancela suscripción
|
|
307
|
+
*/
|
|
308
|
+
unsubscribe<K extends AgentBusEventKey>(
|
|
309
|
+
event: K,
|
|
310
|
+
handler: AgentBusEventHandler<K>
|
|
311
|
+
): void {
|
|
312
|
+
this.emitter.off(event, handler);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Elimina todos los listeners
|
|
317
|
+
*/
|
|
318
|
+
removeAllListeners<K extends AgentBusEventKey>(event?: K): void {
|
|
319
|
+
if (event) {
|
|
320
|
+
this.emitter.removeAllListeners(event);
|
|
321
|
+
} else {
|
|
322
|
+
this.emitter.removeAllListeners();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Obtiene cantidad de listeners para un evento
|
|
328
|
+
*/
|
|
329
|
+
listenerCount<K extends AgentBusEventKey>(event: K): number {
|
|
330
|
+
return this.emitter.listenerCount(event);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Publica un mensaje personalizado de worker a worker
|
|
335
|
+
*/
|
|
336
|
+
sendMessage(
|
|
337
|
+
fromWorkerId: string,
|
|
338
|
+
fromWorkerName: string,
|
|
339
|
+
content: string,
|
|
340
|
+
options?: { toWorkerId?: string; topic?: string }
|
|
341
|
+
): void {
|
|
342
|
+
this.publish("message:custom", {
|
|
343
|
+
fromWorkerId,
|
|
344
|
+
fromWorkerName,
|
|
345
|
+
toWorkerId: options?.toWorkerId,
|
|
346
|
+
topic: options?.topic || "general",
|
|
347
|
+
content,
|
|
348
|
+
timestamp: Date.now(),
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Notifica que una tarea comenzó
|
|
354
|
+
*/
|
|
355
|
+
notifyTaskStarted(
|
|
356
|
+
workerId: string,
|
|
357
|
+
workerName: string,
|
|
358
|
+
taskId: number,
|
|
359
|
+
taskName: string,
|
|
360
|
+
projectId: string
|
|
361
|
+
): void {
|
|
362
|
+
this.publish("worker:task_started", {
|
|
363
|
+
workerId,
|
|
364
|
+
workerName,
|
|
365
|
+
taskId,
|
|
366
|
+
taskName,
|
|
367
|
+
projectId,
|
|
368
|
+
timestamp: Date.now(),
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Notifica que una tarea completó
|
|
374
|
+
*/
|
|
375
|
+
notifyTaskCompleted(
|
|
376
|
+
workerId: string,
|
|
377
|
+
workerName: string,
|
|
378
|
+
taskId: number,
|
|
379
|
+
taskName: string,
|
|
380
|
+
projectId: string,
|
|
381
|
+
result: string
|
|
382
|
+
): void {
|
|
383
|
+
this.publish("worker:task_completed", {
|
|
384
|
+
workerId,
|
|
385
|
+
workerName,
|
|
386
|
+
taskId,
|
|
387
|
+
taskName,
|
|
388
|
+
projectId,
|
|
389
|
+
result,
|
|
390
|
+
timestamp: Date.now(),
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Notifica que una tarea falló
|
|
396
|
+
*/
|
|
397
|
+
notifyTaskFailed(
|
|
398
|
+
workerId: string,
|
|
399
|
+
workerName: string,
|
|
400
|
+
taskId: number,
|
|
401
|
+
taskName: string,
|
|
402
|
+
projectId: string,
|
|
403
|
+
error: string
|
|
404
|
+
): void {
|
|
405
|
+
this.publish("worker:task_failed", {
|
|
406
|
+
workerId,
|
|
407
|
+
workerName,
|
|
408
|
+
taskId,
|
|
409
|
+
taskName,
|
|
410
|
+
projectId,
|
|
411
|
+
error,
|
|
412
|
+
timestamp: Date.now(),
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Solicita ayuda a otros workers
|
|
418
|
+
*/
|
|
419
|
+
requestHelp(
|
|
420
|
+
fromWorkerId: string,
|
|
421
|
+
fromWorkerName: string,
|
|
422
|
+
taskId: number,
|
|
423
|
+
request: string,
|
|
424
|
+
requiredSkill?: string
|
|
425
|
+
): void {
|
|
426
|
+
this.publish("worker:help_request", {
|
|
427
|
+
fromWorkerId,
|
|
428
|
+
fromWorkerName,
|
|
429
|
+
taskId,
|
|
430
|
+
request,
|
|
431
|
+
requiredSkill,
|
|
432
|
+
timestamp: Date.now(),
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Responde a una solicitud de ayuda
|
|
438
|
+
*/
|
|
439
|
+
respondToHelp(
|
|
440
|
+
toWorkerId: string,
|
|
441
|
+
fromWorkerId: string,
|
|
442
|
+
fromWorkerName: string,
|
|
443
|
+
taskId: number,
|
|
444
|
+
response: string
|
|
445
|
+
): void {
|
|
446
|
+
this.publish("worker:help_response", {
|
|
447
|
+
toWorkerId,
|
|
448
|
+
fromWorkerId,
|
|
449
|
+
fromWorkerName,
|
|
450
|
+
taskId,
|
|
451
|
+
response,
|
|
452
|
+
timestamp: Date.now(),
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Singleton
|
|
458
|
+
export const agentBus = new AgentBusImpl();
|
|
459
|
+
|
|
460
|
+
export type AgentBus = typeof agentBus;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DAGScheduler — AgentExecutor
|
|
3
|
+
*
|
|
4
|
+
* Bridges the DAGScheduler to the existing runAgentIsolated() call.
|
|
5
|
+
* Adds timeout enforcement via Promise.race().
|
|
6
|
+
*
|
|
7
|
+
* NOTE: There are no Bun Worker threads in Hive OSS. "Workers" are logical
|
|
8
|
+
* agents stored in the DB and executed as async calls in the same process.
|
|
9
|
+
* Parallelism is achieved by launching multiple runAgentIsolated() calls
|
|
10
|
+
* concurrently without awaiting each one serially.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { runAgentIsolated } from "../agent/AgentRunner.ts"
|
|
14
|
+
import { TaskNode } from "./TaskNode"
|
|
15
|
+
import { TaskTimeoutError } from "./errors"
|
|
16
|
+
|
|
17
|
+
export class AgentExecutor {
|
|
18
|
+
/**
|
|
19
|
+
* Execute a TaskNode.
|
|
20
|
+
* Injects dependency results into the task description as context.
|
|
21
|
+
* Returns the final text output from the agent.
|
|
22
|
+
*/
|
|
23
|
+
async execute(
|
|
24
|
+
node: TaskNode,
|
|
25
|
+
depResults: Record<string, string>,
|
|
26
|
+
threadId: string
|
|
27
|
+
): Promise<string> {
|
|
28
|
+
const hasDeps = Object.keys(depResults).length > 0
|
|
29
|
+
const contextBlock = hasDeps
|
|
30
|
+
? `\n\n---\nContext from completed dependencies:\n${JSON.stringify(depResults, null, 2)}\n---`
|
|
31
|
+
: ""
|
|
32
|
+
|
|
33
|
+
const taskDescription = node.taskDescription + contextBlock
|
|
34
|
+
|
|
35
|
+
const agentPromise = runAgentIsolated({
|
|
36
|
+
agentId: node.agentId,
|
|
37
|
+
taskDescription,
|
|
38
|
+
threadId,
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
42
|
+
const t = setTimeout(() => {
|
|
43
|
+
reject(new TaskTimeoutError(node.id, node.timeout))
|
|
44
|
+
}, node.timeout)
|
|
45
|
+
// Ensure the timeout timer doesn't prevent process exit
|
|
46
|
+
if (typeof t === "object" && t !== null && "unref" in t) {
|
|
47
|
+
(t as any).unref()
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
return Promise.race([agentPromise, timeoutPromise])
|
|
52
|
+
}
|
|
53
|
+
}
|