@johpaz/hive-sdk 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +97 -0
- package/README.md +78 -23
- package/bunfig.toml +4 -2
- package/docs/API-AGENTS.md +78 -27
- package/docs/API-CONTEXT-COMPILER.md +31 -34
- package/docs/API-TOOLS-SKILLS-CHANNELS.md +58 -22
- package/docs/HIVE-HARNESS.md +1 -1
- package/docs/INDEX.md +4 -4
- package/docs/TEMPLATE-HIVE-APP.md +10 -10
- package/package.json +9 -4
- package/packages/cli/package.json +2 -2
- package/packages/cli/src/commands/create-app.test.ts +36 -7
- package/packages/cli/src/commands/init.ts +3 -3
- package/packages/cli/src/commands/run.ts +1 -1
- package/packages/cli/src/commands/test.ts +37 -25
- package/packages/cli/src/commands/trace.ts +30 -28
- package/packages/cli/templates/hive-app/.env.example +10 -2
- package/packages/cli/templates/hive-app/README.md +103 -0
- package/packages/cli/templates/hive-app/hive.config.ts +9 -3
- package/packages/cli/templates/hive-app/src/agents/coordinator.ts +8 -1
- package/packages/cli/templates/hive-app/src/main.ts +12 -19
- package/packages/core/package.json +5 -4
- package/packages/core/src/agent/acceptance-checks.ts +166 -0
- package/packages/core/src/agent/agent-catalog.ts +348 -0
- package/packages/core/src/agent/agent-loop.ts +1373 -0
- package/packages/core/src/agent/capability-search.ts +186 -0
- package/packages/core/src/agent/catalog-selector.ts +103 -0
- package/packages/core/src/agent/{Compaction.ts → compaction.ts} +86 -63
- package/packages/core/src/agent/context-compiler.ts +689 -0
- package/packages/core/src/agent/conversation-store.ts +381 -0
- package/packages/core/src/agent/curator.ts +276 -0
- package/packages/core/src/agent/delegation-runtime.ts +241 -0
- package/packages/core/src/agent/goal-runner.ts +323 -0
- package/packages/core/src/agent/index.ts +17 -12
- package/packages/core/src/agent/llm-client.ts +266 -0
- package/packages/core/src/agent/llm-providers/anthropic.ts +264 -0
- package/packages/core/src/agent/llm-providers/deepseek.ts +8 -0
- package/packages/core/src/agent/{providers → llm-providers}/gemini.ts +98 -60
- package/packages/core/src/agent/llm-providers/groq.ts +5 -0
- package/packages/core/src/agent/llm-providers/hiveagents.ts +253 -0
- package/packages/core/src/agent/{providers → llm-providers}/interface.ts +73 -13
- package/packages/core/src/agent/llm-providers/kimi.ts +8 -0
- package/packages/core/src/agent/llm-providers/minimax.ts +13 -0
- package/packages/core/src/agent/llm-providers/mistral.ts +5 -0
- package/packages/core/src/agent/llm-providers/modelscope.ts +5 -0
- package/packages/core/src/agent/llm-providers/nvidia.ts +5 -0
- package/packages/core/src/agent/{providers → llm-providers}/ollama.ts +31 -5
- package/packages/core/src/agent/llm-providers/openai-compat-base.ts +418 -0
- package/packages/core/src/agent/llm-providers/openai.ts +5 -0
- package/packages/core/src/agent/llm-providers/opencode-go.ts +9 -0
- package/packages/core/src/agent/llm-providers/openrouter.ts +5 -0
- package/packages/core/src/agent/llm-providers/qwen.ts +5 -0
- package/packages/core/src/agent/llm-providers/z-ai.ts +5 -0
- package/packages/core/src/agent/minimal-loadout.ts +47 -0
- package/packages/core/src/agent/playbook-selector.ts +119 -0
- package/packages/core/src/agent/{PromptBuilder.ts → prompt-builder.ts} +21 -22
- package/packages/core/src/{harness → agent}/proof-packet.ts +16 -21
- package/packages/core/src/agent/providers/index.ts +35 -16
- package/packages/core/src/agent/reflector.ts +320 -0
- package/packages/core/src/agent/routing-intent.ts +22 -0
- package/packages/core/src/{harness → agent}/run-epoch.ts +4 -3
- package/packages/core/src/{harness → agent}/run-store.ts +142 -81
- package/packages/core/src/agent/{Service.ts → service.ts} +37 -26
- package/packages/core/src/agent/skill-selector.ts +374 -0
- package/packages/core/src/agent/stuck-loop.ts +209 -0
- package/packages/core/src/agent/{selectors/ToolSelector.ts → tool-selector.ts} +188 -178
- package/packages/core/src/{ace/Tracer.ts → agent/tracer.ts} +37 -27
- package/packages/core/src/api/createAgent.test.ts +139 -27
- package/packages/core/src/api/createAgent.ts +232 -44
- package/packages/core/src/artifacts/store.ts +162 -0
- package/packages/core/src/canvas/canvas-manager.ts +161 -0
- package/packages/core/src/canvas/canvas.test.ts +8 -4
- package/packages/core/src/canvas/emitter.ts +131 -80
- package/packages/core/src/canvas/index.ts +1 -3
- package/packages/core/src/channels/base.ts +9 -1
- package/packages/core/src/channels/discord.ts +5 -4
- package/packages/core/src/channels/manager.ts +122 -30
- package/packages/core/src/channels/slack.ts +5 -4
- package/packages/core/src/channels/telegram.ts +36 -6
- package/packages/core/src/channels/webchat.ts +11 -10
- package/packages/core/src/channels/whatsapp.ts +23 -7
- package/packages/core/src/config/index.ts +13 -2
- package/packages/core/src/config/loader.ts +71 -29
- package/packages/core/src/ethics/EthicsGuard.test.ts +90 -36
- package/packages/core/src/ethics/EthicsGuard.ts +51 -47
- package/packages/core/src/events/agent-bus.ts +44 -68
- package/packages/core/src/events/channel-narration.ts +150 -0
- package/packages/core/src/events/narration.ts +82 -0
- package/packages/core/src/events/tool-narration.ts +62 -0
- package/packages/core/src/gateway/delegation-groups.ts +258 -0
- package/packages/core/src/{harness → gateway}/durable-queue.ts +102 -42
- package/packages/core/src/{harness → gateway}/job-store.ts +85 -48
- package/packages/core/src/gateway/lane-queue.ts +173 -0
- package/packages/core/src/gateway/notification-inbox.ts +57 -0
- package/packages/core/src/gateway/server.ts +1 -1
- package/packages/core/src/harness/index.ts +46 -27
- package/packages/core/src/index.ts +33 -20
- package/packages/core/src/mcp/hot-reload.ts +32 -23
- package/packages/core/src/mcp/index.ts +6 -3
- package/packages/core/src/mcp/singleton.ts +1 -4
- package/packages/core/src/mcp/tool-sync.ts +138 -0
- package/packages/core/src/memory/Scratchpad.test.ts +39 -20
- package/packages/core/src/memory/Scratchpad.ts +27 -34
- package/packages/core/src/multimodal/vision-service.ts +44 -38
- package/packages/core/src/resilience/retry.ts +95 -0
- package/packages/core/src/scheduler/CronScheduler.ts +334 -287
- package/packages/core/src/scheduler/index.ts +9 -7
- package/packages/core/src/scheduler/integration.ts +46 -26
- package/packages/core/src/scheduler/scheduler.test.ts +9 -13
- package/packages/core/src/scheduler/types.ts +7 -2
- package/packages/core/src/security/Pairing.ts +1 -1
- package/packages/core/src/skills/bundled/a2ui/a2ui_dashboard/SKILL.md +176 -0
- package/packages/core/src/skills/bundled/a2ui/a2ui_form/SKILL.md +202 -0
- package/packages/core/src/skills/bundled/a2ui/a2ui_interactive/SKILL.md +206 -0
- package/packages/core/src/skills/bundled/agents/agent_spawner/SKILL.md +173 -0
- package/packages/core/src/skills/bundled/agents/memory_manager/SKILL.md +143 -0
- package/packages/core/src/skills/bundled/agents/research_and_remember/SKILL.md +139 -0
- package/packages/core/src/skills/bundled/agents/task_orchestrator/SKILL.md +98 -0
- package/packages/core/src/skills/bundled/api/api_client/SKILL.md +132 -0
- package/packages/core/src/skills/bundled/cli/cli_pipeline/SKILL.md +135 -0
- package/packages/core/src/skills/bundled/cli/cli_safe_exec/SKILL.md +125 -0
- package/packages/core/src/skills/bundled/cli/software_engineering/SKILL.md +23 -0
- package/packages/core/src/skills/bundled/cron_manager/SKILL.md +188 -0
- package/packages/core/src/skills/bundled/cron_reminder/SKILL.md +112 -0
- package/packages/core/src/skills/bundled/filesystem/file_manager/SKILL.md +118 -0
- package/packages/core/src/skills/bundled/filesystem/file_read_and_summarize/SKILL.md +109 -0
- package/packages/core/src/skills/bundled/filesystem/file_writer/SKILL.md +129 -0
- package/packages/core/src/skills/bundled/filesystem/workspace_file_operator/SKILL.md +22 -0
- package/packages/core/src/skills/bundled/office/office_document_manager/SKILL.md +262 -0
- package/packages/core/src/skills/bundled/search_knowledge/capability_discovery/SKILL.md +75 -0
- package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +120 -0
- package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +109 -0
- package/packages/core/src/skills/bundled/web/web_monitor/SKILL.md +127 -0
- package/packages/core/src/skills/bundled/web/web_research/SKILL.md +119 -0
- package/packages/core/src/skills/bundled-data.generated.ts +731 -2678
- package/packages/core/src/skills/skills.test.ts +52 -11
- package/packages/core/src/{harness → storage}/boot-id.ts +5 -2
- package/packages/core/src/storage/bootstrap.ts +151 -0
- package/packages/core/src/storage/causal-events.ts +84 -0
- package/packages/core/src/storage/collections.ts +680 -0
- package/packages/core/src/storage/crypto.ts +205 -74
- package/packages/core/src/{harness/db-helpers.ts → storage/hive.ts} +63 -7
- package/packages/core/src/storage/hivedb.ts +61 -0
- package/packages/core/src/storage/index.ts +111 -17
- package/packages/core/src/storage/model-id.ts +53 -0
- package/packages/core/src/storage/onboarding.ts +540 -972
- package/packages/core/src/storage/reconcile.ts +238 -0
- package/packages/core/src/storage/seed.ts +572 -406
- package/packages/core/src/storage/usage.ts +285 -225
- package/packages/core/src/storage/user-email.ts +11 -0
- package/packages/core/src/swarm/AgentExecutor.ts +1 -1
- package/packages/core/src/swarm/EventBridge.ts +1 -1
- package/packages/core/src/swarm/index.ts +12 -9
- package/packages/core/src/tool-runtime/index.ts +146 -23
- package/packages/core/src/tool-runtime/tool-worker.ts +2 -2
- package/packages/core/src/tool-runtime/worker-tools.ts +27 -0
- package/packages/core/src/{canvas/a2ui-tools.ts → tools/a2ui/index.ts} +17 -8
- package/packages/core/src/tools/agents/get-available-models.ts +36 -54
- package/packages/core/src/tools/agents/index.ts +784 -292
- package/packages/core/src/tools/api/api-request.test.ts +164 -0
- package/packages/core/src/tools/api/api-request.ts +174 -0
- package/packages/core/src/tools/api/index.ts +16 -0
- package/packages/core/src/tools/cli/index.ts +4 -0
- package/packages/core/src/tools/core/index.ts +281 -112
- package/packages/core/src/tools/cron/index.ts +121 -124
- package/packages/core/src/tools/index.ts +63 -78
- package/packages/core/src/tools/office/office-escribir-xlsx.ts +3 -1
- package/packages/core/src/tools/types.ts +3 -1
- package/packages/core/src/tools/web/artifact-inspect.ts +23 -0
- package/packages/core/src/tools/web/browser-screenshot.ts +26 -5
- package/packages/core/src/tools/web/browser-service.ts +5 -0
- package/packages/core/src/tools/web/browser-type.ts +3 -8
- package/packages/core/src/tools/web/index.ts +4 -4
- package/packages/core/src/voice/index.ts +89 -63
- package/packages/core/src/workers/agent.worker.ts +2 -2
- package/packages/core/src/workers/workers.test.ts +3 -10
- package/scripts/bump-version.ts +248 -0
- package/scripts/generate-skill-bundle.ts +108 -0
- package/test/agent-loop-terminal-synthesis.test.ts +32 -0
- package/test/catalog-agents-stay-enabled.test.ts +117 -0
- package/test/causal-events.test.ts +117 -0
- package/test/compaction.test.ts +105 -0
- package/test/context-compiler.test.ts +269 -0
- package/test/curator.test.ts +130 -0
- package/test/durable-queue.test.ts +114 -0
- package/test/harness-barrel.test.ts +64 -0
- package/test/hive-helpers.test.ts +130 -0
- package/test/hivedb-search.test.ts +189 -0
- package/test/internal-turns.test.ts +166 -0
- package/test/job-idempotency.test.ts +68 -0
- package/test/job-retry-backoff.test.ts +184 -0
- package/test/job-store.test.ts +381 -0
- package/test/llm-retry.test.ts +97 -0
- package/test/memory-perf.test.ts +774 -0
- package/test/minimal-loadout.test.ts +78 -0
- package/test/model-catalog.test.ts +105 -0
- package/test/preload.ts +12 -0
- package/test/reflector.test.ts +320 -0
- package/test/retention-cap.test.ts +91 -0
- package/test/retired-capabilities-pruned.test.ts +192 -0
- package/test/run-store.test.ts +355 -0
- package/test/scratchpad.test.ts +74 -0
- package/test/secrets-durability.test.ts +119 -0
- package/test/seed-model-reseed.test.ts +155 -0
- package/test/setup-agent-seed.test.ts +264 -0
- package/test/tool-inventory.test.ts +65 -0
- package/test/tool-runtime.test.ts +258 -0
- package/test/toon.test.ts +429 -0
- package/tsconfig.json +2 -0
- package/packages/core/src/ace/Curator.ts +0 -158
- package/packages/core/src/ace/Reflector.ts +0 -200
- package/packages/core/src/ace/index.ts +0 -4
- package/packages/core/src/agent/AgentRunner.ts +0 -711
- package/packages/core/src/agent/ContextCompiler.ts +0 -567
- package/packages/core/src/agent/ContextGuard.ts +0 -91
- package/packages/core/src/agent/ConversationStore.ts +0 -254
- package/packages/core/src/agent/Hooks.ts +0 -166
- package/packages/core/src/agent/StuckLoop.ts +0 -133
- package/packages/core/src/agent/providers/LLMClient.ts +0 -149
- package/packages/core/src/agent/providers/anthropic.ts +0 -212
- package/packages/core/src/agent/providers/openai-compat.ts +0 -231
- package/packages/core/src/agent/selectors/PlaybookSelector.ts +0 -121
- package/packages/core/src/agent/selectors/SkillSelector.ts +0 -322
- package/packages/core/src/agent/selectors/index.ts +0 -6
- package/packages/core/src/auth/auth.ts +0 -121
- package/packages/core/src/auth/index.ts +0 -1
- package/packages/core/src/canvas/CanvasManager.ts +0 -390
- package/packages/core/src/canvas/canvas-tools.ts +0 -448
- package/packages/core/src/harness/collections.ts +0 -98
- package/packages/core/src/harness/goal-verifier.ts +0 -141
- package/packages/core/src/harness/harness.test.ts +0 -236
- package/packages/core/src/harness/reconcile.ts +0 -149
- package/packages/core/src/mcp/MCPToolAdapter.ts +0 -176
- package/packages/core/src/multimodal/VisionService.ts +0 -293
- package/packages/core/src/scheduler/dag/AgentExecutor.ts +0 -53
- package/packages/core/src/scheduler/dag/DAGScheduler.ts +0 -250
- package/packages/core/src/scheduler/dag/EventBridge.ts +0 -122
- package/packages/core/src/scheduler/dag/TaskGraph.ts +0 -192
- package/packages/core/src/scheduler/dag/TaskNode.ts +0 -97
- package/packages/core/src/scheduler/dag/TaskResult.ts +0 -22
- package/packages/core/src/scheduler/dag/errors.ts +0 -37
- package/packages/core/src/scheduler/dag/index.ts +0 -26
- package/packages/core/src/scheduler/dag/presets/ResearchPreset.ts +0 -97
- package/packages/core/src/scheduler/dag/strategies/ParallelStrategy.ts +0 -21
- package/packages/core/src/scheduler/dag/strategies/PriorityStrategy.ts +0 -46
- package/packages/core/src/storage/HiveDBStorage.ts +0 -64
- package/packages/core/src/storage/SQLiteStorage.ts +0 -414
- package/packages/core/src/storage/hiveSeed.ts +0 -308
- package/packages/core/src/storage/hiveStorage.test.ts +0 -38
- package/packages/core/src/storage/schema.ts +0 -689
- package/packages/core/src/storage/storage.test.ts +0 -37
- package/packages/core/src/swarm/AgentBus.ts +0 -460
- package/packages/core/src/swarm/EventBus.ts +0 -169
- package/packages/core/src/swarm/WorkerPool.ts +0 -236
- package/packages/core/src/tools/bridge-events.ts +0 -26
- package/packages/core/src/tools/canvas/index.ts +0 -375
- package/packages/core/src/tools/codebridge/index.ts +0 -342
- package/packages/core/src/tools/meeting/index.ts +0 -353
- package/packages/core/src/tools/projects/index.ts +0 -37
- package/packages/core/src/tools/projects/project-create.ts +0 -94
- package/packages/core/src/tools/projects/project-done.ts +0 -66
- package/packages/core/src/tools/projects/project-fail.ts +0 -66
- package/packages/core/src/tools/projects/project-list.ts +0 -96
- package/packages/core/src/tools/projects/project-update.ts +0 -72
- package/packages/core/src/tools/projects/task-create.ts +0 -68
- package/packages/core/src/tools/projects/task-evaluate.ts +0 -93
- package/packages/core/src/tools/projects/task-update.ts +0 -93
- package/packages/core/src/tools/voice/index.ts +0 -104
- package/packages/core/src/tools/web/api-request.test.ts +0 -170
- package/packages/core/src/tools/web/api-request.ts +0 -239
- package/test/setup-db.ts +0 -216
- /package/packages/core/src/agent/{NativeTools.ts → native-tools.ts} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { mkdirSync, existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import { availableParallelism, homedir } from "node:os";
|
|
4
5
|
|
|
5
6
|
const LogLevelSchema = z.enum(["debug", "info", "warn", "error"]);
|
|
6
7
|
const DMPolicySchema = z.enum(["open", "pairing", "allowlist"]);
|
|
@@ -32,7 +33,7 @@ export function getHiveDir(): string {
|
|
|
32
33
|
// Priority 1: HIVE_HOME explicitly set
|
|
33
34
|
if (process.env.HIVE_HOME) {
|
|
34
35
|
const hiveDir = process.env.HIVE_HOME.startsWith("~")
|
|
35
|
-
? path.join(
|
|
36
|
+
? path.join(homedir(), process.env.HIVE_HOME.slice(1))
|
|
36
37
|
: process.env.HIVE_HOME;
|
|
37
38
|
loadEnv(hiveDir);
|
|
38
39
|
return hiveDir;
|
|
@@ -48,7 +49,7 @@ export function getHiveDir(): string {
|
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
// Priority 3: Default ~/.hive
|
|
51
|
-
const defaultDir = path.join(
|
|
52
|
+
const defaultDir = path.join(homedir(), ".hive");
|
|
52
53
|
loadEnv(defaultDir);
|
|
53
54
|
return defaultDir;
|
|
54
55
|
}
|
|
@@ -59,7 +60,7 @@ const expandPath = (p: string): string => {
|
|
|
59
60
|
return p.replace("~/.hive", hiveDir);
|
|
60
61
|
}
|
|
61
62
|
if (p.startsWith("~")) {
|
|
62
|
-
return path.join(
|
|
63
|
+
return path.join(homedir(), p.slice(1));
|
|
63
64
|
}
|
|
64
65
|
return p;
|
|
65
66
|
};
|
|
@@ -116,9 +117,9 @@ const WebConfigSchema = z.object({
|
|
|
116
117
|
|
|
117
118
|
const BrowserConfigSchema = z.object({
|
|
118
119
|
enabled: z.boolean().optional(),
|
|
119
|
-
sessionName: z.string().optional(),
|
|
120
120
|
headless: z.boolean().optional(),
|
|
121
121
|
timeoutMs: z.number().optional(),
|
|
122
|
+
sessionName: z.string().optional(),
|
|
122
123
|
});
|
|
123
124
|
|
|
124
125
|
const CanvasConfigSchema = z.object({
|
|
@@ -126,6 +127,13 @@ const CanvasConfigSchema = z.object({
|
|
|
126
127
|
port: z.number().optional(),
|
|
127
128
|
});
|
|
128
129
|
|
|
130
|
+
const WorkerPoolConfigSchema = z.object({
|
|
131
|
+
enabled: z.boolean().optional(),
|
|
132
|
+
maxWorkers: z.number().optional(),
|
|
133
|
+
toolTimeoutMs: z.number().optional(),
|
|
134
|
+
parallelToolCalls: z.boolean().optional(),
|
|
135
|
+
});
|
|
136
|
+
|
|
129
137
|
const SandboxConfigSchema = z.object({
|
|
130
138
|
dm: ToolRestrictionsSchema.optional(),
|
|
131
139
|
group: ToolRestrictionsSchema.optional(),
|
|
@@ -138,7 +146,12 @@ const ToolsConfigSchema = z.object({
|
|
|
138
146
|
web: WebConfigSchema.optional(),
|
|
139
147
|
browser: BrowserConfigSchema.optional(),
|
|
140
148
|
canvas: CanvasConfigSchema.optional(),
|
|
149
|
+
workerPool: WorkerPoolConfigSchema.optional(),
|
|
141
150
|
sandbox: SandboxConfigSchema.optional(),
|
|
151
|
+
// Per-tool timeout overrides (ms) keyed by tool name. Falls back to
|
|
152
|
+
// workerPool.toolTimeoutMs when absent. Long-running tools like cli_exec
|
|
153
|
+
// should set a higher value (e.g. 600000 = 10min).
|
|
154
|
+
timeouts: z.record(z.string(), z.number()).optional(),
|
|
142
155
|
});
|
|
143
156
|
|
|
144
157
|
const ContextConfigSchema = z.object({
|
|
@@ -237,6 +250,13 @@ const CronConfigSchema = z.object({
|
|
|
237
250
|
timezone: z.string().optional(),
|
|
238
251
|
});
|
|
239
252
|
|
|
253
|
+
// G9 causal event log (HiveDB): IntentLogged/StateTransition/ToolCall emission
|
|
254
|
+
// from agent-loop.ts, consumed by reflector/curator/context-compiler. Off by
|
|
255
|
+
// default — each turn adds N+M+1 awaited db.append() calls to the critical path.
|
|
256
|
+
const CausalLogConfigSchema = z.object({
|
|
257
|
+
enabled: z.boolean().optional(),
|
|
258
|
+
});
|
|
259
|
+
|
|
240
260
|
const RetryConfigSchema = z.object({
|
|
241
261
|
maxAttempts: z.number().optional(),
|
|
242
262
|
initialDelayMs: z.number().optional(),
|
|
@@ -244,6 +264,25 @@ const RetryConfigSchema = z.object({
|
|
|
244
264
|
maxDelayMs: z.number().optional(),
|
|
245
265
|
});
|
|
246
266
|
|
|
267
|
+
const JobRetryConfigSchema = z.object({
|
|
268
|
+
// Logical-failure retries (executor returned {ok:false}). Separate from
|
|
269
|
+
// JobDoc.attempts, which only counts crash/lease-expiry reclaims.
|
|
270
|
+
maxRetries: z.number().optional(),
|
|
271
|
+
initialDelayMs: z.number().optional(),
|
|
272
|
+
backoffMultiplier: z.number().optional(),
|
|
273
|
+
maxDelayMs: z.number().optional(),
|
|
274
|
+
jitter: z.number().optional(),
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
const HarnessConfigSchema = z.object({
|
|
278
|
+
maxGlobalConcurrency: z.number().optional(),
|
|
279
|
+
taskTimeoutMs: z.number().optional(),
|
|
280
|
+
jobLeaseMs: z.number().optional(),
|
|
281
|
+
runLeaseMs: z.number().optional(),
|
|
282
|
+
leaseRenewMs: z.number().optional(),
|
|
283
|
+
jobRetry: JobRetryConfigSchema.optional(),
|
|
284
|
+
});
|
|
285
|
+
|
|
247
286
|
const HooksConfigSchema = z.object({
|
|
248
287
|
scripts: z.object({
|
|
249
288
|
before_model_resolve: z.string().optional(),
|
|
@@ -281,7 +320,7 @@ const GatewayConfigSchema = z.object({
|
|
|
281
320
|
});
|
|
282
321
|
|
|
283
322
|
const ModelsConfigSchema = z.object({
|
|
284
|
-
defaultProvider: z.enum(["openai", "anthropic", "gemini", "mistral", "kimi", "ollama", "openrouter", "deepseek"]).optional(),
|
|
323
|
+
defaultProvider: z.enum(["openai", "anthropic", "gemini", "mistral", "kimi", "ollama", "openrouter", "deepseek", "hiveagents"]).optional(),
|
|
285
324
|
defaults: z.record(z.string(), z.string()).optional(),
|
|
286
325
|
providers: z.record(z.string(), ProviderConfigSchema).optional(),
|
|
287
326
|
});
|
|
@@ -307,17 +346,6 @@ const SecurityConfigSchema = z.object({
|
|
|
307
346
|
allowedUsers: z.array(z.string()).optional(),
|
|
308
347
|
});
|
|
309
348
|
|
|
310
|
-
const CaptchaConfigSchema = z.object({
|
|
311
|
-
enabled: z.boolean().optional(),
|
|
312
|
-
autoSolve: z.boolean().optional(),
|
|
313
|
-
visionProvider: z.enum(["gemini", "openai", "anthropic"]).optional(),
|
|
314
|
-
visionModel: z.string().optional(),
|
|
315
|
-
maxAttempts: z.number().optional(),
|
|
316
|
-
maxRounds: z.number().optional(),
|
|
317
|
-
apiKey: z.string().optional(),
|
|
318
|
-
enabledSites: z.array(z.string()).optional(),
|
|
319
|
-
});
|
|
320
|
-
|
|
321
349
|
const UserConfigSchema = z.object({
|
|
322
350
|
id: z.string(),
|
|
323
351
|
name: z.string(),
|
|
@@ -345,10 +373,11 @@ const ConfigSchema = z.object({
|
|
|
345
373
|
mcp: MCPConfigSchema.optional(),
|
|
346
374
|
memory: MemoryConfigSchema.optional(),
|
|
347
375
|
cron: CronConfigSchema.optional(),
|
|
376
|
+
causalLog: CausalLogConfigSchema.optional(),
|
|
348
377
|
retry: RetryConfigSchema.optional(),
|
|
378
|
+
harness: HarnessConfigSchema.optional(),
|
|
349
379
|
security: SecurityConfigSchema.optional(),
|
|
350
380
|
hooks: HooksConfigSchema.optional(),
|
|
351
|
-
captcha: CaptchaConfigSchema.optional(),
|
|
352
381
|
});
|
|
353
382
|
|
|
354
383
|
export type Config = z.infer<typeof ConfigSchema>;
|
|
@@ -358,7 +387,6 @@ export type MCPServerConfig = z.infer<typeof MCPServerConfigSchema>;
|
|
|
358
387
|
export type AgentEntry = z.infer<typeof AgentEntrySchema>;
|
|
359
388
|
export type Binding = z.infer<typeof BindingSchema>;
|
|
360
389
|
export type UserConfig = z.infer<typeof UserConfigSchema>;
|
|
361
|
-
export type CaptchaConfig = z.infer<typeof CaptchaConfigSchema>;
|
|
362
390
|
|
|
363
391
|
function buildDefaultConfig(): Config {
|
|
364
392
|
const hiveDir = getHiveDir();
|
|
@@ -428,7 +456,7 @@ function buildDefaultConfig(): Config {
|
|
|
428
456
|
allowlist: [],
|
|
429
457
|
denylist: ["rm -rf /", "sudo", "chmod 777", "> /dev/", "mkfs"],
|
|
430
458
|
timeoutSeconds: 30,
|
|
431
|
-
workDir: path.join(
|
|
459
|
+
workDir: path.join(homedir(), "exec"), // Points to home for exec by default
|
|
432
460
|
},
|
|
433
461
|
web: {
|
|
434
462
|
allowlist: [],
|
|
@@ -437,14 +465,20 @@ function buildDefaultConfig(): Config {
|
|
|
437
465
|
},
|
|
438
466
|
browser: {
|
|
439
467
|
enabled: true,
|
|
440
|
-
sessionName: "hive",
|
|
441
468
|
headless: true,
|
|
442
469
|
timeoutMs: 30000,
|
|
470
|
+
sessionName: "hive",
|
|
443
471
|
},
|
|
444
472
|
canvas: {
|
|
445
473
|
enabled: true,
|
|
446
474
|
port: 18793,
|
|
447
475
|
},
|
|
476
|
+
workerPool: {
|
|
477
|
+
enabled: true,
|
|
478
|
+
maxWorkers: Math.min(4, availableParallelism()),
|
|
479
|
+
toolTimeoutMs: 300000,
|
|
480
|
+
parallelToolCalls: true,
|
|
481
|
+
},
|
|
448
482
|
sandbox: {
|
|
449
483
|
dm: { allow: ["*"], deny: [] },
|
|
450
484
|
group: { allow: ["*"], deny: [] },
|
|
@@ -480,12 +514,29 @@ function buildDefaultConfig(): Config {
|
|
|
480
514
|
maxConcurrentJobs: 5,
|
|
481
515
|
timezone: "UTC",
|
|
482
516
|
},
|
|
517
|
+
causalLog: {
|
|
518
|
+
enabled: process.env.HIVE_CAUSAL_LOG === "true",
|
|
519
|
+
},
|
|
483
520
|
retry: {
|
|
484
521
|
maxAttempts: 3,
|
|
485
522
|
initialDelayMs: 1000,
|
|
486
523
|
backoffMultiplier: 2,
|
|
487
524
|
maxDelayMs: 30000,
|
|
488
525
|
},
|
|
526
|
+
harness: {
|
|
527
|
+
maxGlobalConcurrency: parseInt(process.env.HIVE_HARNESS_MAX_CONCURRENCY || "4", 10),
|
|
528
|
+
taskTimeoutMs: parseInt(process.env.HIVE_HARNESS_TASK_TIMEOUT_MS || String(30 * 60 * 1000), 10),
|
|
529
|
+
jobLeaseMs: parseInt(process.env.HIVE_HARNESS_JOB_LEASE_MS || String(30 * 60 * 1000), 10),
|
|
530
|
+
runLeaseMs: parseInt(process.env.HIVE_HARNESS_RUN_LEASE_MS || String(2 * 60 * 1000), 10),
|
|
531
|
+
leaseRenewMs: parseInt(process.env.HIVE_HARNESS_LEASE_RENEW_MS || "30000", 10),
|
|
532
|
+
jobRetry: {
|
|
533
|
+
maxRetries: parseInt(process.env.HIVE_HARNESS_JOB_MAX_RETRIES || "3", 10),
|
|
534
|
+
initialDelayMs: parseInt(process.env.HIVE_HARNESS_JOB_RETRY_INITIAL_MS || "1000", 10),
|
|
535
|
+
backoffMultiplier: parseFloat(process.env.HIVE_HARNESS_JOB_RETRY_MULTIPLIER || "2"),
|
|
536
|
+
maxDelayMs: parseInt(process.env.HIVE_HARNESS_JOB_RETRY_MAX_MS || String(5 * 60 * 1000), 10),
|
|
537
|
+
jitter: parseFloat(process.env.HIVE_HARNESS_JOB_RETRY_JITTER || "0.2"),
|
|
538
|
+
},
|
|
539
|
+
},
|
|
489
540
|
security: {
|
|
490
541
|
maxMessageLength: {
|
|
491
542
|
telegram: 4096,
|
|
@@ -500,15 +551,6 @@ function buildDefaultConfig(): Config {
|
|
|
500
551
|
hooks: {
|
|
501
552
|
scripts: {},
|
|
502
553
|
},
|
|
503
|
-
captcha: {
|
|
504
|
-
enabled: false,
|
|
505
|
-
autoSolve: true,
|
|
506
|
-
visionProvider: 'gemini',
|
|
507
|
-
visionModel: 'gemini-2.0-flash-exp',
|
|
508
|
-
maxAttempts: 3,
|
|
509
|
-
maxRounds: 5,
|
|
510
|
-
enabledSites: [],
|
|
511
|
-
},
|
|
512
554
|
};
|
|
513
555
|
}
|
|
514
556
|
|
|
@@ -1,54 +1,108 @@
|
|
|
1
|
-
|
|
1
|
+
process.env.HIVE_DB_PATH = ":memory:";
|
|
2
|
+
|
|
3
|
+
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
|
2
4
|
import { EthicsGuard } from "./EthicsGuard.ts";
|
|
3
|
-
import {
|
|
5
|
+
import { closeHiveDb } from "../storage/hivedb.ts";
|
|
6
|
+
import { ensureHiveDb } from "../storage/bootstrap.ts";
|
|
7
|
+
import { col } from "../storage/hive.ts";
|
|
8
|
+
import { toIndexable } from "../storage/hive.ts";
|
|
9
|
+
import type { PlaybookDoc } from "../storage/collections.ts";
|
|
10
|
+
|
|
11
|
+
async function addRule(id: string, rule: string, category: string, opts?: {
|
|
12
|
+
applicableTo?: string;
|
|
13
|
+
helpfulCount?: number;
|
|
14
|
+
active?: boolean;
|
|
15
|
+
}) {
|
|
16
|
+
const playbookCol = await col<PlaybookDoc>("playbook");
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
await playbookCol.put(id, {
|
|
19
|
+
id,
|
|
20
|
+
rule,
|
|
21
|
+
category,
|
|
22
|
+
applicable_to: opts?.applicableTo ?? null,
|
|
23
|
+
helpful_count: opts?.helpfulCount ?? 0,
|
|
24
|
+
harmful_count: 0,
|
|
25
|
+
active: opts?.active ?? true,
|
|
26
|
+
source_reflection_id: toIndexable(null),
|
|
27
|
+
created_at: now,
|
|
28
|
+
updated_at: now,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
beforeEach(async () => {
|
|
33
|
+
closeHiveDb();
|
|
34
|
+
await ensureHiveDb();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
closeHiveDb();
|
|
39
|
+
});
|
|
4
40
|
|
|
5
41
|
describe("EthicsGuard", () => {
|
|
6
|
-
|
|
42
|
+
it("sólo devuelve reglas de response_quality activas", async () => {
|
|
43
|
+
await addRule("rq-1", "Verificá las fuentes antes de responder", "response_quality");
|
|
44
|
+
await addRule("rq-2", "Regla apagada", "response_quality", { active: false });
|
|
45
|
+
await addRule("otra", "Usá web_search para noticias", "tool_selection");
|
|
46
|
+
|
|
47
|
+
const rules = await new EthicsGuard().getRules();
|
|
7
48
|
|
|
8
|
-
|
|
9
|
-
await initializeDatabase();
|
|
10
|
-
db = getDb();
|
|
11
|
-
db.run(`
|
|
12
|
-
INSERT OR IGNORE INTO playbook (id, rule, category, applicable_to, helpful_count, active)
|
|
13
|
-
VALUES (1, 'Siempre verificar fuentes antes de responder', 'response_quality', 'agent', 5, 1)
|
|
14
|
-
`);
|
|
49
|
+
expect(rules.map((r) => r.id)).toEqual(["rq-1"]);
|
|
15
50
|
});
|
|
16
51
|
|
|
17
|
-
|
|
18
|
-
|
|
52
|
+
it("ordena por helpful_count descendente", async () => {
|
|
53
|
+
await addRule("poco", "poco útil", "response_quality", { helpfulCount: 1 });
|
|
54
|
+
await addRule("mucho", "muy útil", "response_quality", { helpfulCount: 9 });
|
|
55
|
+
|
|
56
|
+
const rules = await new EthicsGuard().getRules();
|
|
57
|
+
|
|
58
|
+
expect(rules.map((r) => r.id)).toEqual(["mucho", "poco"]);
|
|
19
59
|
});
|
|
20
60
|
|
|
21
|
-
it("
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
61
|
+
it("filtra por agentRole cuando alguna regla lo declara", async () => {
|
|
62
|
+
await addRule("para-coord", "regla del coordinador", "response_quality", {
|
|
63
|
+
applicableTo: JSON.stringify(["coordinator"]),
|
|
64
|
+
});
|
|
65
|
+
await addRule("para-worker", "regla del worker", "response_quality", {
|
|
66
|
+
applicableTo: JSON.stringify(["worker"]),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const rules = await new EthicsGuard().getRules("coordinator");
|
|
70
|
+
|
|
71
|
+
expect(rules.map((r) => r.id)).toEqual(["para-coord"]);
|
|
25
72
|
});
|
|
26
73
|
|
|
27
|
-
it("
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
74
|
+
it("cae a todas las reglas si ninguna declara ese rol", async () => {
|
|
75
|
+
// Sin esto, un `applicable_to` mal cargado dejaría al agente sin capa
|
|
76
|
+
// de calidad en vez de con una de más.
|
|
77
|
+
await addRule("generica", "regla general", "response_quality", {
|
|
78
|
+
applicableTo: JSON.stringify(["worker"]),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const rules = await new EthicsGuard().getRules("coordinator");
|
|
82
|
+
|
|
83
|
+
expect(rules.map((r) => r.id)).toEqual(["generica"]);
|
|
35
84
|
});
|
|
36
85
|
|
|
37
|
-
it("
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
86
|
+
it("injectIntoPrompt agrega las reglas y conserva el prompt original", async () => {
|
|
87
|
+
await addRule("rq-1", "Verificá las fuentes", "response_quality");
|
|
88
|
+
|
|
89
|
+
const guard = new EthicsGuard();
|
|
90
|
+
const result = guard.injectIntoPrompt("Eres un asistente.", await guard.getRules());
|
|
91
|
+
|
|
92
|
+
expect(result).toContain("Eres un asistente.");
|
|
93
|
+
expect(result).toContain("## Reglas de Calidad de Respuesta");
|
|
94
|
+
expect(result).toContain("- Verificá las fuentes");
|
|
41
95
|
});
|
|
42
96
|
|
|
43
|
-
it("
|
|
44
|
-
|
|
45
|
-
const rules = guard.getRules("agent");
|
|
46
|
-
expect(Array.isArray(rules)).toBe(true);
|
|
97
|
+
it("injectIntoPrompt devuelve el prompt intacto sin reglas", () => {
|
|
98
|
+
expect(new EthicsGuard().injectIntoPrompt("Eres un asistente.", [])).toBe("Eres un asistente.");
|
|
47
99
|
});
|
|
48
100
|
|
|
49
|
-
it("
|
|
50
|
-
const guard = new EthicsGuard(
|
|
51
|
-
|
|
52
|
-
|
|
101
|
+
it("hasEthicsLayer refleja si hay reglas cargadas", async () => {
|
|
102
|
+
const guard = new EthicsGuard();
|
|
103
|
+
expect(await guard.hasEthicsLayer()).toBe(false);
|
|
104
|
+
|
|
105
|
+
await addRule("rq-1", "Verificá las fuentes", "response_quality");
|
|
106
|
+
expect(await guard.hasEthicsLayer()).toBe(true);
|
|
53
107
|
});
|
|
54
108
|
});
|
|
@@ -1,66 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EthicsGuard — capa de reglas de calidad de respuesta sobre el system prompt.
|
|
3
|
+
*
|
|
4
|
+
* Lee las reglas `category: "response_quality"` de la colección `playbook`.
|
|
5
|
+
* Hasta 0.1.5 esta clase recibía un handle de SQLite y armaba SQL a mano
|
|
6
|
+
* (incluyendo un JOIN contra la tabla virtual `playbook_fts`); esas tablas ya no
|
|
7
|
+
* existen. Ahora la fuente es HiveDB, igual que para el resto del catálogo.
|
|
8
|
+
*
|
|
9
|
+
* Nota: la ética "constitucional" de un agente no pasa por acá — vive en la
|
|
10
|
+
* colección `ethics` y la ensambla `agent/prompt-builder.ts` como primera
|
|
11
|
+
* sección del prompt. Este guard es un complemento opcional para hosts que
|
|
12
|
+
* quieran inyectar reglas aprendidas por ACE.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { col } from "../storage/hive.ts";
|
|
16
|
+
import type { PlaybookDoc } from "../storage/collections.ts";
|
|
17
|
+
|
|
1
18
|
export interface EthicsRule {
|
|
2
|
-
id:
|
|
19
|
+
id: string;
|
|
3
20
|
rule: string;
|
|
4
21
|
category: string;
|
|
5
|
-
applicable_to: string;
|
|
22
|
+
applicable_to: string | null;
|
|
6
23
|
helpful_count: number;
|
|
7
|
-
active:
|
|
24
|
+
active: boolean;
|
|
8
25
|
}
|
|
9
26
|
|
|
10
|
-
|
|
11
|
-
private db: any;
|
|
27
|
+
const RESPONSE_QUALITY = "response_quality";
|
|
12
28
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
getRules(agentRole?: string): EthicsRule[] {
|
|
18
|
-
if (!agentRole) {
|
|
19
|
-
return this.db
|
|
20
|
-
.query(
|
|
21
|
-
`SELECT p.* FROM playbook p
|
|
22
|
-
WHERE p.category = 'response_quality' AND p.active = 1
|
|
23
|
-
ORDER BY p.helpful_count DESC`
|
|
24
|
-
)
|
|
25
|
-
.all() as EthicsRule[];
|
|
26
|
-
}
|
|
29
|
+
function byUsefulness(a: EthicsRule, b: EthicsRule): number {
|
|
30
|
+
return b.helpful_count - a.helpful_count;
|
|
31
|
+
}
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
export class EthicsGuard {
|
|
34
|
+
/**
|
|
35
|
+
* Reglas activas de calidad de respuesta.
|
|
36
|
+
*
|
|
37
|
+
* Con `agentRole` filtra por las que lo declaran en `applicable_to`; si
|
|
38
|
+
* ninguna coincide devuelve todas, para no dejar al agente sin capa por un
|
|
39
|
+
* `applicable_to` mal cargado.
|
|
40
|
+
*/
|
|
41
|
+
async getRules(agentRole?: string): Promise<EthicsRule[]> {
|
|
42
|
+
const playbookCol = await col<PlaybookDoc>("playbook");
|
|
43
|
+
const all = (await playbookCol.scan({}))
|
|
44
|
+
.map((e) => ({
|
|
45
|
+
id: e.id,
|
|
46
|
+
rule: e.doc.rule,
|
|
47
|
+
category: e.doc.category,
|
|
48
|
+
applicable_to: e.doc.applicable_to,
|
|
49
|
+
helpful_count: e.doc.helpful_count ?? 0,
|
|
50
|
+
active: e.doc.active,
|
|
51
|
+
}))
|
|
52
|
+
.filter((r) => r.active && r.category === RESPONSE_QUALITY)
|
|
53
|
+
.sort(byUsefulness);
|
|
39
54
|
|
|
40
|
-
|
|
41
|
-
} catch {}
|
|
55
|
+
if (!agentRole) return all;
|
|
42
56
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
`SELECT * FROM playbook
|
|
46
|
-
WHERE category = 'response_quality' AND active = 1
|
|
47
|
-
ORDER BY helpful_count DESC`
|
|
48
|
-
)
|
|
49
|
-
.all() as EthicsRule[];
|
|
57
|
+
const matching = all.filter((r) => (r.applicable_to ?? "").includes(agentRole));
|
|
58
|
+
return matching.length > 0 ? matching : all;
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
injectIntoPrompt(systemPrompt: string, rules: EthicsRule[]): string {
|
|
53
62
|
if (rules.length === 0) return systemPrompt;
|
|
54
|
-
const ethicsSection = rules
|
|
55
|
-
.map(r => `- ${r.rule}`)
|
|
56
|
-
.join("\n");
|
|
63
|
+
const ethicsSection = rules.map((r) => `- ${r.rule}`).join("\n");
|
|
57
64
|
return `${systemPrompt}\n\n## Reglas de Calidad de Respuesta\n${ethicsSection}`;
|
|
58
65
|
}
|
|
59
66
|
|
|
60
|
-
hasEthicsLayer(): boolean {
|
|
61
|
-
|
|
62
|
-
.query(`SELECT COUNT(*) as c FROM playbook WHERE category = 'response_quality' AND active = 1`)
|
|
63
|
-
.get() as any;
|
|
64
|
-
return (count?.c ?? 0) > 0;
|
|
67
|
+
async hasEthicsLayer(): Promise<boolean> {
|
|
68
|
+
return (await this.getRules()).length > 0;
|
|
65
69
|
}
|
|
66
70
|
}
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
import { EventEmitter } from "events";
|
|
13
13
|
import { logger } from "../utils/logger";
|
|
14
|
-
import {
|
|
14
|
+
import { col, nextId, toIndexable, fromIndexable, BROADCAST } from "../storage/hive";
|
|
15
|
+
import type { AgentBusMessageDoc, TaskDoc } from "../storage/collections";
|
|
15
16
|
|
|
16
17
|
const log = logger.child("agent-bus");
|
|
17
18
|
|
|
@@ -122,8 +123,6 @@ export interface AgentBusMessage {
|
|
|
122
123
|
* Guarda un mensaje en la base de datos para persistencia
|
|
123
124
|
*/
|
|
124
125
|
function persistMessage(event: AgentBusEventKey, data: any, metadata?: Record<string, unknown>): void {
|
|
125
|
-
const db = getDb();
|
|
126
|
-
|
|
127
126
|
// Extraer IDs de worker según el tipo de evento
|
|
128
127
|
let fromWorkerId: string | null = null;
|
|
129
128
|
let toWorkerId: string | null = null;
|
|
@@ -167,87 +166,64 @@ function persistMessage(event: AgentBusEventKey, data: any, metadata?: Record<st
|
|
|
167
166
|
content = JSON.stringify(data);
|
|
168
167
|
}
|
|
169
168
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
169
|
+
Promise.resolve().then(async () => {
|
|
170
|
+
try {
|
|
171
|
+
const messagesCol = await col<AgentBusMessageDoc>("agentBusMessages");
|
|
172
|
+
const id = await nextId("agentBusMessages");
|
|
173
|
+
await messagesCol.put(id, {
|
|
174
|
+
id,
|
|
175
|
+
event_type: event,
|
|
176
|
+
from_worker_id: toIndexable(fromWorkerId),
|
|
177
|
+
to_worker_id: toWorkerId ? toWorkerId : BROADCAST,
|
|
178
|
+
topic,
|
|
179
|
+
content,
|
|
180
|
+
metadata: metadata ? JSON.stringify(metadata) : null,
|
|
181
|
+
created_at: Date.now(),
|
|
182
|
+
read: false,
|
|
183
|
+
}, { expectedVersion: 0 });
|
|
184
|
+
} catch (err) {
|
|
185
|
+
log.warn(`Failed to persist message (non-critical): ${(err as Error).message}`);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function docToMessage(doc: AgentBusMessageDoc): AgentBusMessage {
|
|
191
|
+
return {
|
|
192
|
+
id: parseInt(doc.id, 10),
|
|
193
|
+
event_type: doc.event_type,
|
|
194
|
+
from_worker_id: fromIndexable(doc.from_worker_id),
|
|
195
|
+
to_worker_id: doc.to_worker_id === BROADCAST ? null : doc.to_worker_id,
|
|
196
|
+
topic: doc.topic,
|
|
197
|
+
content: doc.content,
|
|
198
|
+
metadata: doc.metadata,
|
|
199
|
+
created_at: doc.created_at,
|
|
200
|
+
read: doc.read ? 1 : 0,
|
|
201
|
+
};
|
|
186
202
|
}
|
|
187
203
|
|
|
188
204
|
/**
|
|
189
205
|
* Obtiene mensajes no leídos para un worker específico
|
|
190
206
|
*/
|
|
191
|
-
export function getUnreadMessagesForWorker(workerId: string, limit: number = 50): AgentBusMessage[] {
|
|
192
|
-
const db = getDb();
|
|
193
|
-
|
|
207
|
+
export async function getUnreadMessagesForWorker(workerId: string, limit: number = 50): Promise<AgentBusMessage[]> {
|
|
194
208
|
try {
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
`).all(workerId, limit);
|
|
209
|
+
const messagesCol = await col<AgentBusMessageDoc>("agentBusMessages");
|
|
210
|
+
const entries = (await messagesCol.scan({}))
|
|
211
|
+
.filter(e => !e.doc.read && (e.doc.to_worker_id === workerId || e.doc.to_worker_id === BROADCAST))
|
|
212
|
+
.sort((a, b) => a.doc.created_at - b.doc.created_at)
|
|
213
|
+
.slice(0, limit);
|
|
201
214
|
|
|
202
215
|
// Marcar como leídos
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
db.query(`UPDATE agent_bus_messages SET read = 1 WHERE id IN (${ids})`).run();
|
|
216
|
+
for (const entry of entries) {
|
|
217
|
+
await messagesCol.put(entry.id, { ...entry.doc, read: true }, { expectedVersion: entry.version });
|
|
206
218
|
}
|
|
207
219
|
|
|
208
|
-
return
|
|
220
|
+
return entries.map(e => docToMessage(e.doc));
|
|
209
221
|
} catch (err) {
|
|
210
222
|
log.error(`Failed to get unread messages: ${(err as Error).message}`);
|
|
211
223
|
return [];
|
|
212
224
|
}
|
|
213
225
|
}
|
|
214
226
|
|
|
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
227
|
|
|
252
228
|
// ─── Agent Bus Implementation ────────────────────────────────────────────────
|
|
253
229
|
|