@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
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACE Reflector — analyzes recent traces and produces insights.
|
|
3
|
+
*
|
|
4
|
+
* Runs in the background (never blocks the main agent loop).
|
|
5
|
+
* Triggered by the tracer after N new traces.
|
|
6
|
+
*
|
|
7
|
+
* Output → `reflections` collection → picked up by Curator.
|
|
8
|
+
*
|
|
9
|
+
* "Last processed trace" is tracked via a `cursors` collection doc
|
|
10
|
+
* (id="reflector:lastTrace") instead of the SQL json_each/MAX(CAST(...))
|
|
11
|
+
* trick the SQLite version used — HiveDB has no equivalent primitive.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { logger } from "../utils/logger"
|
|
15
|
+
import { col, nextId } from "../storage/hive"
|
|
16
|
+
import { getHiveDb } from "../storage/hivedb"
|
|
17
|
+
import { loadConfig } from "../config/loader"
|
|
18
|
+
import type { HiveDB, ToolStats } from "@johpaz/hive-db"
|
|
19
|
+
import type { TraceDoc, ReflectionDoc, CursorDoc } from "../storage/collections"
|
|
20
|
+
|
|
21
|
+
const log = logger.child("reflector")
|
|
22
|
+
|
|
23
|
+
const MAX_TRACES_TO_ANALYZE = 30
|
|
24
|
+
const MIN_TRACES_TO_RUN = 10
|
|
25
|
+
const CURSOR_ID = "reflector:lastTrace"
|
|
26
|
+
|
|
27
|
+
/** Main entry point — called from tracer.ts */
|
|
28
|
+
export async function runReflector(): Promise<void> {
|
|
29
|
+
try {
|
|
30
|
+
log.info(`[reflector] Starting reflection cycle...`)
|
|
31
|
+
|
|
32
|
+
const cursorsCol = await col<CursorDoc>("cursors")
|
|
33
|
+
const cursorEntry = await cursorsCol.get(CURSOR_ID)
|
|
34
|
+
const lastProcessedId = cursorEntry?.doc.value ?? null
|
|
35
|
+
log.debug(`[reflector] Last processed trace ID: ${lastProcessedId ?? "(none)"}`)
|
|
36
|
+
|
|
37
|
+
const tracesCol = await col<TraceDoc>("traces")
|
|
38
|
+
let candidates = lastProcessedId
|
|
39
|
+
? await tracesCol.scan({ start: lastProcessedId })
|
|
40
|
+
: await tracesCol.scan({})
|
|
41
|
+
if (lastProcessedId && candidates[0]?.id === lastProcessedId) candidates = candidates.slice(1)
|
|
42
|
+
|
|
43
|
+
const traceEntries = candidates.slice(0, MAX_TRACES_TO_ANALYZE)
|
|
44
|
+
const traces = traceEntries.map(e => e.doc)
|
|
45
|
+
log.debug(`[reflector] Fetched ${traces.length} traces from DB`)
|
|
46
|
+
|
|
47
|
+
if (traces.length < MIN_TRACES_TO_RUN) {
|
|
48
|
+
log.debug(`[reflector] Not enough traces (${traces.length}/${MIN_TRACES_TO_RUN}), skipping`)
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
log.info(`[reflector] Analyzing ${traces.length} traces...`)
|
|
53
|
+
|
|
54
|
+
// G9: when enabled, per-tool insights use whole-history stats from HiveDB's
|
|
55
|
+
// event log (toolStats) instead of counters built from just this batch, and
|
|
56
|
+
// causal threads add root-cause/learning-proposal insights on top.
|
|
57
|
+
const causalDb = loadConfig().causalLog?.enabled ? await getHiveDb() : null
|
|
58
|
+
const localInsights = await analyzeTracesLocally(traces, causalDb)
|
|
59
|
+
const causalInsights = await analyzeCausalThreads(traces, causalDb)
|
|
60
|
+
const insights = [...localInsights, ...causalInsights]
|
|
61
|
+
|
|
62
|
+
if (insights.length === 0) {
|
|
63
|
+
log.debug("[reflector] No insights generated")
|
|
64
|
+
} else {
|
|
65
|
+
const traceIds = JSON.stringify(traceEntries.map(e => e.id))
|
|
66
|
+
const reflectionsCol = await col<ReflectionDoc>("reflections")
|
|
67
|
+
|
|
68
|
+
for (const insight of insights) {
|
|
69
|
+
const id = await nextId("reflections")
|
|
70
|
+
await reflectionsCol.put(id, {
|
|
71
|
+
id,
|
|
72
|
+
trace_ids: traceIds,
|
|
73
|
+
insight_type: insight.type,
|
|
74
|
+
description: insight.description,
|
|
75
|
+
affected_tools: insight.affectedTools ? JSON.stringify(insight.affectedTools) : null,
|
|
76
|
+
affected_agents: insight.affectedAgents ? JSON.stringify(insight.affectedAgents) : null,
|
|
77
|
+
confidence: insight.confidence,
|
|
78
|
+
created_at: Date.now(),
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
log.info(`[reflector] Generated ${insights.length} insights`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Advance the cursor regardless of whether insights were generated —
|
|
86
|
+
// these traces have been considered either way.
|
|
87
|
+
const newCursor = traceEntries[traceEntries.length - 1].id
|
|
88
|
+
await cursorsCol.put(CURSOR_ID, { value: newCursor }, cursorEntry ? { expectedVersion: cursorEntry.version } : { expectedVersion: 0 })
|
|
89
|
+
|
|
90
|
+
// Trigger curator
|
|
91
|
+
const { runCurator } = await import("./curator")
|
|
92
|
+
await runCurator()
|
|
93
|
+
|
|
94
|
+
log.info(`[reflector] Reflection cycle completed successfully`)
|
|
95
|
+
} catch (err) {
|
|
96
|
+
log.error(`[reflector] Error during reflection:`, {
|
|
97
|
+
message: (err as Error).message,
|
|
98
|
+
stack: (err as Error).stack,
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ─── Local analysis (heuristic, no LLM call needed for basic patterns) ────────
|
|
104
|
+
|
|
105
|
+
interface Insight {
|
|
106
|
+
type: "success_pattern" | "failure_pattern" | "optimization" | "ethics_violation" | "root_cause" | "learning_proposal"
|
|
107
|
+
description: string
|
|
108
|
+
affectedTools?: string[]
|
|
109
|
+
affectedAgents?: string[]
|
|
110
|
+
confidence: number
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ─── G9 causal-thread analysis (evaluateHarness) ──────────────────────────────
|
|
114
|
+
|
|
115
|
+
interface DecisionNode {
|
|
116
|
+
seq: number
|
|
117
|
+
agent: string
|
|
118
|
+
description: string
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
interface CausalThreadShape {
|
|
122
|
+
decisions: DecisionNode[]
|
|
123
|
+
toolCalls: Array<{ seq: number; agent: string; tool: string }>
|
|
124
|
+
anomalies: unknown[]
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
interface HarnessFinding {
|
|
128
|
+
kind: "inefficientLoop" | "objectiveDrift" | "rootCause" | "insufficientEvidence"
|
|
129
|
+
seq?: number
|
|
130
|
+
description: string
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface HarnessProposal {
|
|
134
|
+
description: string
|
|
135
|
+
confidence: number
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
interface HarnessEvaluationShape {
|
|
139
|
+
processQuality: number
|
|
140
|
+
outputQuality: number
|
|
141
|
+
rootCause?: { seq: number; agent: string }
|
|
142
|
+
findings: HarnessFinding[]
|
|
143
|
+
proposals: HarnessProposal[]
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Evaluate the causal thread of every distinct G9 stream touched by this
|
|
148
|
+
* batch of traces (one thread per agent-loop invocation — see
|
|
149
|
+
* agent-loop.ts's causalStreamId) with HiveDB's harness loop, and turn its
|
|
150
|
+
* root cause / findings / learning proposals into reflector insights.
|
|
151
|
+
*
|
|
152
|
+
* Runs alongside, not instead of, analyzeTracesLocally(): it needs a full
|
|
153
|
+
* causal thread per stream, so it operates per-run rather than per-batch.
|
|
154
|
+
*/
|
|
155
|
+
async function analyzeCausalThreads(traces: TraceDoc[], causalDb: HiveDB | null): Promise<Insight[]> {
|
|
156
|
+
if (!causalDb) return []
|
|
157
|
+
|
|
158
|
+
const insights: Insight[] = []
|
|
159
|
+
const streamIds = new Set(traces.map((t) => t.causal_stream_id).filter((s): s is string => !!s))
|
|
160
|
+
|
|
161
|
+
for (const streamId of streamIds) {
|
|
162
|
+
try {
|
|
163
|
+
const thread = (await causalDb.causalThread(streamId)) as CausalThreadShape
|
|
164
|
+
if (!thread.decisions?.length && !thread.toolCalls?.length) continue
|
|
165
|
+
|
|
166
|
+
const subset = traces.filter((t) => t.causal_stream_id === streamId)
|
|
167
|
+
const originalIntent = subset[0]?.input_summary ?? ""
|
|
168
|
+
const success = subset.every((t) => t.success)
|
|
169
|
+
|
|
170
|
+
const evaluation = (await causalDb.evaluateHarness({
|
|
171
|
+
causalThread: thread,
|
|
172
|
+
similarEpisodes: [],
|
|
173
|
+
originalIntent,
|
|
174
|
+
currentState: { success },
|
|
175
|
+
minConfidence: 0.5,
|
|
176
|
+
})) as HarnessEvaluationShape
|
|
177
|
+
|
|
178
|
+
// Description deliberately omits streamId/seq: curator.ts only reinforces
|
|
179
|
+
// an existing rule when its first-60-chars prefix matches exactly, so any
|
|
180
|
+
// per-run identifier in the text would make every occurrence of the same
|
|
181
|
+
// underlying root cause mint a brand new playbook rule instead of
|
|
182
|
+
// reinforcing one (confirmed via a local before/after canary run).
|
|
183
|
+
if (evaluation.rootCause) {
|
|
184
|
+
const decision = thread.decisions?.find((d) => d.seq === evaluation.rootCause!.seq)
|
|
185
|
+
insights.push({
|
|
186
|
+
type: "root_cause",
|
|
187
|
+
description: decision
|
|
188
|
+
? `Root cause: decision "${decision.description}" (agent ${evaluation.rootCause.agent}) preceded a tool failure.`
|
|
189
|
+
: `Root cause: a decision by agent ${evaluation.rootCause.agent} preceded a tool failure.`,
|
|
190
|
+
affectedAgents: [evaluation.rootCause.agent],
|
|
191
|
+
confidence: 0.6,
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Only inefficientLoop findings here: harness.rs's find_root_cause() always
|
|
196
|
+
// emits evaluation.rootCause and an equivalent finding{kind:"rootCause"}
|
|
197
|
+
// together from the same resolution — including both would double-insight
|
|
198
|
+
// every single failure. The block above already covers it, with a richer
|
|
199
|
+
// description (the actual decision text, not just its seq).
|
|
200
|
+
for (const finding of evaluation.findings ?? []) {
|
|
201
|
+
if (finding.kind === "inefficientLoop") {
|
|
202
|
+
insights.push({
|
|
203
|
+
type: "root_cause",
|
|
204
|
+
description: finding.description,
|
|
205
|
+
confidence: 0.6,
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
for (const proposal of evaluation.proposals ?? []) {
|
|
211
|
+
insights.push({
|
|
212
|
+
type: "learning_proposal",
|
|
213
|
+
description: proposal.description,
|
|
214
|
+
confidence: proposal.confidence,
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
} catch (err) {
|
|
218
|
+
log.warn(`[reflector] Causal-thread analysis failed for stream ${streamId}: ${(err as Error).message}`)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return insights
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async function analyzeTracesLocally(traces: TraceDoc[], causalDb: HiveDB | null): Promise<Insight[]> {
|
|
226
|
+
const insights: Insight[] = []
|
|
227
|
+
|
|
228
|
+
// G9: whole-history stats per tool touched by this batch (undefined when
|
|
229
|
+
// disabled, or when the tool has no events in the log yet).
|
|
230
|
+
const statsByTool = new Map<string, ToolStats>()
|
|
231
|
+
if (causalDb) {
|
|
232
|
+
const distinctTools = new Set(traces.map((t) => t.tool_used).filter((t): t is string => !!t))
|
|
233
|
+
for (const tool of distinctTools) {
|
|
234
|
+
try {
|
|
235
|
+
const stats = await causalDb.toolStats(tool)
|
|
236
|
+
if (stats) statsByTool.set(tool, stats)
|
|
237
|
+
} catch (err) {
|
|
238
|
+
log.warn(`[reflector] toolStats(${tool}) failed: ${(err as Error).message}`)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ── Failure patterns ─────────────────────────────────────────────────────
|
|
244
|
+
const failures = traces.filter((t) => !t.success)
|
|
245
|
+
if (failures.length > 3) {
|
|
246
|
+
// Group by tool
|
|
247
|
+
const toolFailures: Record<string, number> = {}
|
|
248
|
+
for (const f of failures) {
|
|
249
|
+
if (f.tool_used) {
|
|
250
|
+
toolFailures[f.tool_used] = (toolFailures[f.tool_used] || 0) + 1
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
for (const [tool, batchCount] of Object.entries(toolFailures)) {
|
|
254
|
+
const count = statsByTool.get(tool)?.errors ?? batchCount
|
|
255
|
+
if (count >= 3) {
|
|
256
|
+
insights.push({
|
|
257
|
+
type: "failure_pattern",
|
|
258
|
+
description: `Tool '${tool}' failed ${count} times recently. Consider verifying its configuration or avoiding it for this type of task.`,
|
|
259
|
+
affectedTools: [tool],
|
|
260
|
+
confidence: Math.min(0.9, count / 10),
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ── Slow tools ───────────────────────────────────────────────────────────
|
|
267
|
+
const slowThresholdMs = 5000
|
|
268
|
+
const slowTools: Record<string, number[]> = {}
|
|
269
|
+
for (const t of traces) {
|
|
270
|
+
if (t.tool_used && (t.duration_ms ?? 0) > slowThresholdMs) {
|
|
271
|
+
if (!slowTools[t.tool_used]) slowTools[t.tool_used] = []
|
|
272
|
+
slowTools[t.tool_used].push(t.duration_ms!)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
for (const [tool, durations] of Object.entries(slowTools)) {
|
|
276
|
+
if (durations.length >= 3) {
|
|
277
|
+
const stats = statsByTool.get(tool)
|
|
278
|
+
const avg = stats && stats.invocations > 0
|
|
279
|
+
? Math.round(stats.totalLatencyMs / stats.invocations)
|
|
280
|
+
: Math.round(durations.reduce((a, b) => a + b, 0) / durations.length)
|
|
281
|
+
insights.push({
|
|
282
|
+
type: "optimization",
|
|
283
|
+
description: `Tool '${tool}' is consistently slow (avg ${avg}ms). Cache results when possible or use a faster alternative.`,
|
|
284
|
+
affectedTools: [tool],
|
|
285
|
+
confidence: 0.6,
|
|
286
|
+
})
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ── High success pattern ─────────────────────────────────────────────────
|
|
291
|
+
const successByTool: Record<string, { ok: number; total: number }> = {}
|
|
292
|
+
for (const t of traces) {
|
|
293
|
+
if (!t.tool_used) continue
|
|
294
|
+
if (!successByTool[t.tool_used]) successByTool[t.tool_used] = { ok: 0, total: 0 }
|
|
295
|
+
successByTool[t.tool_used].total++
|
|
296
|
+
if (t.success) successByTool[t.tool_used].ok++
|
|
297
|
+
}
|
|
298
|
+
for (const [tool, stats] of Object.entries(successByTool)) {
|
|
299
|
+
if (stats.total >= 5 && stats.ok / stats.total >= 0.9) {
|
|
300
|
+
insights.push({
|
|
301
|
+
type: "success_pattern",
|
|
302
|
+
description: `Tool '${tool}' has a high success rate (${stats.ok}/${stats.total}). Prefer it for related tasks.`,
|
|
303
|
+
affectedTools: [tool],
|
|
304
|
+
confidence: stats.ok / stats.total,
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ── High token usage ─────────────────────────────────────────────────────
|
|
310
|
+
const highTokenTraces = traces.filter((t) => (t.tokens_used ?? 0) > 4000)
|
|
311
|
+
if (highTokenTraces.length > 3) {
|
|
312
|
+
insights.push({
|
|
313
|
+
type: "optimization",
|
|
314
|
+
description: `${highTokenTraces.length} recent calls used >4000 tokens. Be more concise and use tool results as summaries, not raw dumps.`,
|
|
315
|
+
confidence: 0.7,
|
|
316
|
+
})
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return insights
|
|
320
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
function normalizeIntent(value: string): string {
|
|
2
|
+
return value
|
|
3
|
+
.normalize("NFD")
|
|
4
|
+
.replace(/\p{Diacritic}/gu, "")
|
|
5
|
+
.toLowerCase();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Calendar operations are external data mutations/lookups, not future Hive
|
|
10
|
+
* executions. Keep them out of the native cron tool and skill selectors so
|
|
11
|
+
* the coordinator can discover the configured calendar MCP server instead.
|
|
12
|
+
*/
|
|
13
|
+
export function isCalendarOperation(value: string): boolean {
|
|
14
|
+
const text = normalizeIntent(value);
|
|
15
|
+
const namesCalendar = /\b(calendario|calendar|agenda)\b/.test(text);
|
|
16
|
+
const calendarAction = /\b(crear?|agend\w*|anad\w*|agreg\w*|consult\w*|list\w*|modific\w*|mov\w*|cancel\w*|elimin\w*|invit\w*|reserv\w*|disponibilidad|availability)\b/.test(text);
|
|
17
|
+
if (namesCalendar && calendarAction) return true;
|
|
18
|
+
|
|
19
|
+
const directlySchedulesMeeting = /\b(crea(?:r)?|agenda(?:r)?|programa(?:r)?|reserva(?:r)?)\s+(?:un|una|la|el|nueva|nuevo)?\s*(reunion|cita|meeting)\b/.test(text);
|
|
20
|
+
const managesAttendees = /\b(invit\w*|asistente\w*|attendee\w*)\b.*\b(reunion|cita|meeting)\b|\b(reunion|cita|meeting)\b.*\b(invit\w*|asistente\w*|attendee\w*)\b/.test(text);
|
|
21
|
+
return directlySchedulesMeeting || managesAttendees;
|
|
22
|
+
}
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
* were unchanged.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import rootPackage from "../../../../package.json";
|
|
10
|
+
|
|
9
11
|
export interface RunEpoch {
|
|
10
12
|
provider: string;
|
|
11
13
|
model: string;
|
|
12
|
-
/** Caller-supplied version identifier (e.g. the host app's package version) — the harness doesn't assume its own version is what matters. */
|
|
13
14
|
app_version: string;
|
|
14
15
|
tool_catalog_hash: string;
|
|
15
16
|
}
|
|
@@ -22,11 +23,11 @@ function hashToolNames(names: string[]): string {
|
|
|
22
23
|
return hash.toString(16);
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
export function buildRunEpoch(opts: { provider: string; model: string;
|
|
26
|
+
export function buildRunEpoch(opts: { provider: string; model: string; toolNames: string[] }): RunEpoch {
|
|
26
27
|
return {
|
|
27
28
|
provider: opts.provider,
|
|
28
29
|
model: opts.model,
|
|
29
|
-
app_version:
|
|
30
|
+
app_version: (rootPackage as { version: string }).version,
|
|
30
31
|
tool_catalog_hash: hashToolNames(opts.toolNames),
|
|
31
32
|
};
|
|
32
33
|
}
|