@johpaz/hive-sdk 0.1.4 → 0.1.6
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 +129 -0
- package/README.md +78 -23
- package/bun.lock +55 -29
- 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 +17 -12
- 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 +13 -12
- package/packages/core/src/agent/acceptance-checks.ts +172 -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 +76 -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 -27
- 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 -18
- 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-backend.ts +129 -0
- package/packages/core/src/tools/web/browser-screenshot.ts +26 -5
- package/packages/core/src/tools/web/browser-service.ts +80 -35
- 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/tools/web/webview-backend.ts +412 -0
- 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/acceptance-checks.test.ts +403 -0
- package/test/agent-loop-terminal-synthesis.test.ts +32 -0
- package/test/browser-backend.test.ts +308 -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/tool-selector-runtime-tools.test.ts +117 -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,14 @@ 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(),
|
|
123
|
+
// "agent-browser" (default) usa Chrome via CLI y sirve headless/Docker.
|
|
124
|
+
// "webview" usa Bun.WebView in-process — mucho más rápido y sin instalación,
|
|
125
|
+
// pero requiere Chrome instalado (o macOS con WebKit). "auto" toma webview
|
|
126
|
+
// sólo si hay motor. Lo pisa HIVE_BROWSER_BACKEND.
|
|
127
|
+
backend: z.enum(["agent-browser", "webview", "auto"]).optional(),
|
|
122
128
|
});
|
|
123
129
|
|
|
124
130
|
const CanvasConfigSchema = z.object({
|
|
@@ -126,6 +132,13 @@ const CanvasConfigSchema = z.object({
|
|
|
126
132
|
port: z.number().optional(),
|
|
127
133
|
});
|
|
128
134
|
|
|
135
|
+
const WorkerPoolConfigSchema = z.object({
|
|
136
|
+
enabled: z.boolean().optional(),
|
|
137
|
+
maxWorkers: z.number().optional(),
|
|
138
|
+
toolTimeoutMs: z.number().optional(),
|
|
139
|
+
parallelToolCalls: z.boolean().optional(),
|
|
140
|
+
});
|
|
141
|
+
|
|
129
142
|
const SandboxConfigSchema = z.object({
|
|
130
143
|
dm: ToolRestrictionsSchema.optional(),
|
|
131
144
|
group: ToolRestrictionsSchema.optional(),
|
|
@@ -138,7 +151,12 @@ const ToolsConfigSchema = z.object({
|
|
|
138
151
|
web: WebConfigSchema.optional(),
|
|
139
152
|
browser: BrowserConfigSchema.optional(),
|
|
140
153
|
canvas: CanvasConfigSchema.optional(),
|
|
154
|
+
workerPool: WorkerPoolConfigSchema.optional(),
|
|
141
155
|
sandbox: SandboxConfigSchema.optional(),
|
|
156
|
+
// Per-tool timeout overrides (ms) keyed by tool name. Falls back to
|
|
157
|
+
// workerPool.toolTimeoutMs when absent. Long-running tools like cli_exec
|
|
158
|
+
// should set a higher value (e.g. 600000 = 10min).
|
|
159
|
+
timeouts: z.record(z.string(), z.number()).optional(),
|
|
142
160
|
});
|
|
143
161
|
|
|
144
162
|
const ContextConfigSchema = z.object({
|
|
@@ -237,6 +255,13 @@ const CronConfigSchema = z.object({
|
|
|
237
255
|
timezone: z.string().optional(),
|
|
238
256
|
});
|
|
239
257
|
|
|
258
|
+
// G9 causal event log (HiveDB): IntentLogged/StateTransition/ToolCall emission
|
|
259
|
+
// from agent-loop.ts, consumed by reflector/curator/context-compiler. Off by
|
|
260
|
+
// default — each turn adds N+M+1 awaited db.append() calls to the critical path.
|
|
261
|
+
const CausalLogConfigSchema = z.object({
|
|
262
|
+
enabled: z.boolean().optional(),
|
|
263
|
+
});
|
|
264
|
+
|
|
240
265
|
const RetryConfigSchema = z.object({
|
|
241
266
|
maxAttempts: z.number().optional(),
|
|
242
267
|
initialDelayMs: z.number().optional(),
|
|
@@ -244,6 +269,25 @@ const RetryConfigSchema = z.object({
|
|
|
244
269
|
maxDelayMs: z.number().optional(),
|
|
245
270
|
});
|
|
246
271
|
|
|
272
|
+
const JobRetryConfigSchema = z.object({
|
|
273
|
+
// Logical-failure retries (executor returned {ok:false}). Separate from
|
|
274
|
+
// JobDoc.attempts, which only counts crash/lease-expiry reclaims.
|
|
275
|
+
maxRetries: z.number().optional(),
|
|
276
|
+
initialDelayMs: z.number().optional(),
|
|
277
|
+
backoffMultiplier: z.number().optional(),
|
|
278
|
+
maxDelayMs: z.number().optional(),
|
|
279
|
+
jitter: z.number().optional(),
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
const HarnessConfigSchema = z.object({
|
|
283
|
+
maxGlobalConcurrency: z.number().optional(),
|
|
284
|
+
taskTimeoutMs: z.number().optional(),
|
|
285
|
+
jobLeaseMs: z.number().optional(),
|
|
286
|
+
runLeaseMs: z.number().optional(),
|
|
287
|
+
leaseRenewMs: z.number().optional(),
|
|
288
|
+
jobRetry: JobRetryConfigSchema.optional(),
|
|
289
|
+
});
|
|
290
|
+
|
|
247
291
|
const HooksConfigSchema = z.object({
|
|
248
292
|
scripts: z.object({
|
|
249
293
|
before_model_resolve: z.string().optional(),
|
|
@@ -281,7 +325,7 @@ const GatewayConfigSchema = z.object({
|
|
|
281
325
|
});
|
|
282
326
|
|
|
283
327
|
const ModelsConfigSchema = z.object({
|
|
284
|
-
defaultProvider: z.enum(["openai", "anthropic", "gemini", "mistral", "kimi", "ollama", "openrouter", "deepseek"]).optional(),
|
|
328
|
+
defaultProvider: z.enum(["openai", "anthropic", "gemini", "mistral", "kimi", "ollama", "openrouter", "deepseek", "hiveagents"]).optional(),
|
|
285
329
|
defaults: z.record(z.string(), z.string()).optional(),
|
|
286
330
|
providers: z.record(z.string(), ProviderConfigSchema).optional(),
|
|
287
331
|
});
|
|
@@ -307,17 +351,6 @@ const SecurityConfigSchema = z.object({
|
|
|
307
351
|
allowedUsers: z.array(z.string()).optional(),
|
|
308
352
|
});
|
|
309
353
|
|
|
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
354
|
const UserConfigSchema = z.object({
|
|
322
355
|
id: z.string(),
|
|
323
356
|
name: z.string(),
|
|
@@ -345,10 +378,11 @@ const ConfigSchema = z.object({
|
|
|
345
378
|
mcp: MCPConfigSchema.optional(),
|
|
346
379
|
memory: MemoryConfigSchema.optional(),
|
|
347
380
|
cron: CronConfigSchema.optional(),
|
|
381
|
+
causalLog: CausalLogConfigSchema.optional(),
|
|
348
382
|
retry: RetryConfigSchema.optional(),
|
|
383
|
+
harness: HarnessConfigSchema.optional(),
|
|
349
384
|
security: SecurityConfigSchema.optional(),
|
|
350
385
|
hooks: HooksConfigSchema.optional(),
|
|
351
|
-
captcha: CaptchaConfigSchema.optional(),
|
|
352
386
|
});
|
|
353
387
|
|
|
354
388
|
export type Config = z.infer<typeof ConfigSchema>;
|
|
@@ -358,7 +392,6 @@ export type MCPServerConfig = z.infer<typeof MCPServerConfigSchema>;
|
|
|
358
392
|
export type AgentEntry = z.infer<typeof AgentEntrySchema>;
|
|
359
393
|
export type Binding = z.infer<typeof BindingSchema>;
|
|
360
394
|
export type UserConfig = z.infer<typeof UserConfigSchema>;
|
|
361
|
-
export type CaptchaConfig = z.infer<typeof CaptchaConfigSchema>;
|
|
362
395
|
|
|
363
396
|
function buildDefaultConfig(): Config {
|
|
364
397
|
const hiveDir = getHiveDir();
|
|
@@ -428,7 +461,7 @@ function buildDefaultConfig(): Config {
|
|
|
428
461
|
allowlist: [],
|
|
429
462
|
denylist: ["rm -rf /", "sudo", "chmod 777", "> /dev/", "mkfs"],
|
|
430
463
|
timeoutSeconds: 30,
|
|
431
|
-
workDir: path.join(
|
|
464
|
+
workDir: path.join(homedir(), "exec"), // Points to home for exec by default
|
|
432
465
|
},
|
|
433
466
|
web: {
|
|
434
467
|
allowlist: [],
|
|
@@ -437,14 +470,20 @@ function buildDefaultConfig(): Config {
|
|
|
437
470
|
},
|
|
438
471
|
browser: {
|
|
439
472
|
enabled: true,
|
|
440
|
-
sessionName: "hive",
|
|
441
473
|
headless: true,
|
|
442
474
|
timeoutMs: 30000,
|
|
475
|
+
sessionName: "hive",
|
|
443
476
|
},
|
|
444
477
|
canvas: {
|
|
445
478
|
enabled: true,
|
|
446
479
|
port: 18793,
|
|
447
480
|
},
|
|
481
|
+
workerPool: {
|
|
482
|
+
enabled: true,
|
|
483
|
+
maxWorkers: Math.min(4, availableParallelism()),
|
|
484
|
+
toolTimeoutMs: 300000,
|
|
485
|
+
parallelToolCalls: true,
|
|
486
|
+
},
|
|
448
487
|
sandbox: {
|
|
449
488
|
dm: { allow: ["*"], deny: [] },
|
|
450
489
|
group: { allow: ["*"], deny: [] },
|
|
@@ -480,12 +519,29 @@ function buildDefaultConfig(): Config {
|
|
|
480
519
|
maxConcurrentJobs: 5,
|
|
481
520
|
timezone: "UTC",
|
|
482
521
|
},
|
|
522
|
+
causalLog: {
|
|
523
|
+
enabled: process.env.HIVE_CAUSAL_LOG === "true",
|
|
524
|
+
},
|
|
483
525
|
retry: {
|
|
484
526
|
maxAttempts: 3,
|
|
485
527
|
initialDelayMs: 1000,
|
|
486
528
|
backoffMultiplier: 2,
|
|
487
529
|
maxDelayMs: 30000,
|
|
488
530
|
},
|
|
531
|
+
harness: {
|
|
532
|
+
maxGlobalConcurrency: parseInt(process.env.HIVE_HARNESS_MAX_CONCURRENCY || "4", 10),
|
|
533
|
+
taskTimeoutMs: parseInt(process.env.HIVE_HARNESS_TASK_TIMEOUT_MS || String(30 * 60 * 1000), 10),
|
|
534
|
+
jobLeaseMs: parseInt(process.env.HIVE_HARNESS_JOB_LEASE_MS || String(30 * 60 * 1000), 10),
|
|
535
|
+
runLeaseMs: parseInt(process.env.HIVE_HARNESS_RUN_LEASE_MS || String(2 * 60 * 1000), 10),
|
|
536
|
+
leaseRenewMs: parseInt(process.env.HIVE_HARNESS_LEASE_RENEW_MS || "30000", 10),
|
|
537
|
+
jobRetry: {
|
|
538
|
+
maxRetries: parseInt(process.env.HIVE_HARNESS_JOB_MAX_RETRIES || "3", 10),
|
|
539
|
+
initialDelayMs: parseInt(process.env.HIVE_HARNESS_JOB_RETRY_INITIAL_MS || "1000", 10),
|
|
540
|
+
backoffMultiplier: parseFloat(process.env.HIVE_HARNESS_JOB_RETRY_MULTIPLIER || "2"),
|
|
541
|
+
maxDelayMs: parseInt(process.env.HIVE_HARNESS_JOB_RETRY_MAX_MS || String(5 * 60 * 1000), 10),
|
|
542
|
+
jitter: parseFloat(process.env.HIVE_HARNESS_JOB_RETRY_JITTER || "0.2"),
|
|
543
|
+
},
|
|
544
|
+
},
|
|
489
545
|
security: {
|
|
490
546
|
maxMessageLength: {
|
|
491
547
|
telegram: 4096,
|
|
@@ -500,15 +556,6 @@ function buildDefaultConfig(): Config {
|
|
|
500
556
|
hooks: {
|
|
501
557
|
scripts: {},
|
|
502
558
|
},
|
|
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
559
|
};
|
|
513
560
|
}
|
|
514
561
|
|
|
@@ -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
|
|