@johpaz/hive-sdk 0.1.6 → 0.3.0
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 +441 -0
- package/README.md +21 -3
- package/package.json +27 -5
- package/packages/core/src/agent/acceptance-checks.ts +9 -9
- package/packages/core/src/agent/agent-catalog.ts +82 -25
- package/packages/core/src/agent/agent-loop.ts +115 -26
- package/packages/core/src/agent/capability-search.ts +2 -2
- package/packages/core/src/agent/catalog-selector.ts +4 -4
- package/packages/core/src/agent/compaction.ts +30 -10
- package/packages/core/src/agent/context-compiler.ts +63 -36
- package/packages/core/src/agent/conversation-store.ts +167 -9
- package/packages/core/src/agent/curator.ts +16 -7
- package/packages/core/src/agent/delegation-runtime.ts +5 -5
- package/packages/core/src/agent/goal-runner.ts +9 -9
- package/packages/core/src/agent/index.ts +1 -0
- package/packages/core/src/agent/llm-client.ts +98 -37
- package/packages/core/src/agent/llm-providers/anthropic.ts +4 -4
- package/packages/core/src/agent/llm-providers/deepseek.ts +1 -1
- package/packages/core/src/agent/llm-providers/gemini.ts +4 -4
- package/packages/core/src/agent/llm-providers/groq.ts +1 -1
- package/packages/core/src/agent/llm-providers/hiveagents.ts +3 -3
- package/packages/core/src/agent/llm-providers/interface.ts +2 -2
- package/packages/core/src/agent/llm-providers/kimi.ts +1 -1
- package/packages/core/src/agent/llm-providers/minimax.ts +1 -1
- package/packages/core/src/agent/llm-providers/mistral.ts +1 -1
- package/packages/core/src/agent/llm-providers/modelscope.ts +1 -1
- package/packages/core/src/agent/llm-providers/nvidia.ts +40 -1
- package/packages/core/src/agent/llm-providers/ollama.ts +4 -4
- package/packages/core/src/agent/llm-providers/openai-compat-base.ts +47 -7
- package/packages/core/src/agent/llm-providers/openai.ts +1 -1
- package/packages/core/src/agent/llm-providers/opencode-go.ts +1 -1
- package/packages/core/src/agent/llm-providers/openrouter.ts +1 -1
- package/packages/core/src/agent/llm-providers/qwen.ts +1 -1
- package/packages/core/src/agent/llm-providers/z-ai.ts +1 -1
- package/packages/core/src/agent/mcp-result-normalizer.ts +192 -0
- package/packages/core/src/agent/playbook-selector.ts +22 -7
- package/packages/core/src/agent/prompt-builder.ts +5 -5
- package/packages/core/src/agent/proof-packet.ts +5 -5
- package/packages/core/src/agent/providers/index.ts +39 -4
- package/packages/core/src/agent/realtime-providers/gemini-live.ts +238 -0
- package/packages/core/src/agent/realtime-providers/index.ts +29 -0
- package/packages/core/src/agent/realtime-providers/interface.ts +108 -0
- package/packages/core/src/agent/reflector.ts +38 -15
- package/packages/core/src/agent/run-store.ts +8 -8
- package/packages/core/src/agent/service.ts +10 -10
- package/packages/core/src/agent/skill-selector.ts +6 -6
- package/packages/core/src/agent/thread-id.ts +71 -0
- package/packages/core/src/agent/thread-store.ts +293 -0
- package/packages/core/src/agent/tool-selector.ts +9 -5
- package/packages/core/src/agent/tracer.ts +5 -5
- package/packages/core/src/api/createAgent.ts +67 -2
- package/packages/core/src/artifacts/index.ts +15 -0
- package/packages/core/src/artifacts/store.ts +161 -5
- package/packages/core/src/canvas/emitter.ts +2 -2
- package/packages/core/src/canvas/index.ts +9 -0
- package/packages/core/src/channels/telegram.ts +1 -1
- package/packages/core/src/channels/webchat.ts +1 -1
- package/packages/core/src/config/loader.ts +14 -5
- package/packages/core/src/ethics/EthicsGuard.ts +7 -1
- package/packages/core/src/events/agent-bus.ts +3 -3
- package/packages/core/src/events/channel-narration.ts +3 -3
- package/packages/core/src/events/event-bus.ts +1 -1
- package/packages/core/src/events/index.ts +18 -0
- package/packages/core/src/events/narration.ts +3 -3
- package/packages/core/src/events/tool-narration.ts +4 -0
- package/packages/core/src/gateway/channel-notify.ts +103 -6
- package/packages/core/src/gateway/delegation-groups.ts +4 -4
- package/packages/core/src/gateway/durable-queue.ts +18 -6
- package/packages/core/src/gateway/index.ts +3 -0
- package/packages/core/src/gateway/job-store.ts +11 -5
- package/packages/core/src/gateway/notification-inbox.ts +2 -2
- package/packages/core/src/gateway/server.ts +2 -2
- package/packages/core/src/harness/executors.ts +493 -0
- package/packages/core/src/harness/index.ts +12 -2
- package/packages/core/src/hooks/index.ts +203 -0
- package/packages/core/src/images/index.ts +161 -0
- package/packages/core/src/index.ts +1 -0
- package/packages/core/src/mcp/MCPClient.ts +3 -3
- package/packages/core/src/mcp/hot-reload.ts +5 -5
- package/packages/core/src/mcp/tool-sync.ts +5 -5
- package/packages/core/src/mcp/transports/index.ts +2 -2
- package/packages/core/src/mcp/transports/sse.ts +1 -1
- package/packages/core/src/models/index.ts +36 -0
- package/packages/core/src/multimodal/index.ts +2 -2
- package/packages/core/src/multimodal/vision-service.ts +51 -19
- package/packages/core/src/plugins/loader.ts +4 -1
- package/packages/core/src/resilience/circuit-breaker.ts +16 -5
- package/packages/core/src/resilience/index.ts +13 -0
- package/packages/core/src/resilience/retry.ts +1 -1
- package/packages/core/src/scheduler/CronScheduler.ts +54 -27
- package/packages/core/src/scheduler/cron/expression.ts +165 -0
- package/packages/core/src/scheduler/cron/index.ts +10 -0
- package/packages/core/src/scheduler/cron/job.ts +339 -0
- package/packages/core/src/scheduler/cron/next-run.ts +121 -0
- package/packages/core/src/scheduler/cron/zoned-time.ts +138 -0
- package/packages/core/src/scheduler/index.ts +21 -3
- package/packages/core/src/scheduler/integration.ts +25 -14
- package/packages/core/src/scheduler/types.ts +3 -18
- package/packages/core/src/services/agents.ts +268 -0
- package/packages/core/src/services/cron.ts +257 -0
- package/packages/core/src/services/endpoints.ts +289 -0
- package/packages/core/src/services/ethics.ts +107 -0
- package/packages/core/src/services/images.ts +212 -0
- package/packages/core/src/services/index.ts +112 -0
- package/packages/core/src/services/mcp.ts +201 -0
- package/packages/core/src/services/memory.ts +133 -0
- package/packages/core/src/services/models.ts +179 -0
- package/packages/core/src/services/providers.ts +152 -0
- package/packages/core/src/services/setup.ts +222 -0
- package/packages/core/src/services/skills.ts +241 -0
- package/packages/core/src/services/swarms.ts +307 -0
- package/packages/core/src/services/tools.ts +106 -0
- package/packages/core/src/sessions/index.ts +268 -0
- package/packages/core/src/sessions/resolve.ts +108 -0
- package/packages/core/src/skills/SkillLoader.ts +8 -1
- package/packages/core/src/skills/bundled/artifacts/artifact_reader/SKILL.md +105 -0
- package/packages/core/src/skills/bundled/cron_manager/SKILL.md +21 -11
- package/packages/core/src/skills/bundled/images/image_editor/SKILL.md +120 -0
- package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +12 -3
- package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +22 -7
- package/packages/core/src/skills/bundled-data.generated.ts +110 -12
- package/packages/core/src/storage/bootstrap.ts +107 -12
- package/packages/core/src/storage/causal-events.ts +1 -1
- package/packages/core/src/storage/collections.ts +138 -2
- package/packages/core/src/storage/crypto.ts +35 -4
- package/packages/core/src/storage/hive.ts +1 -1
- package/packages/core/src/storage/hivedb.ts +10 -1
- package/packages/core/src/storage/index.ts +2 -1
- package/packages/core/src/storage/onboarding.ts +61 -45
- package/packages/core/src/storage/reconcile.ts +11 -6
- package/packages/core/src/storage/seed.ts +191 -23
- package/packages/core/src/storage/usage.ts +3 -3
- package/packages/core/src/swarm/AgentExecutor.ts +2 -2
- package/packages/core/src/swarm/Coordinator.ts +8 -8
- package/packages/core/src/swarm/EventBridge.ts +2 -2
- package/packages/core/src/swarm/RoleSwarm.ts +234 -0
- package/packages/core/src/swarm/TaskGraph.ts +2 -2
- package/packages/core/src/swarm/index.ts +7 -0
- package/packages/core/src/swarm/presets/HiveLearnPreset.ts +2 -2
- package/packages/core/src/swarm/presets/ResearchPreset.ts +2 -2
- package/packages/core/src/swarm/strategies/ParallelStrategy.ts +1 -1
- package/packages/core/src/swarm/strategies/PriorityStrategy.ts +3 -3
- package/packages/core/src/swarm/types.ts +3 -18
- package/packages/core/src/tool-runtime/embedded-worker.generated.ts +21 -0
- package/packages/core/src/tool-runtime/index.ts +129 -14
- package/packages/core/src/tools/ToolExecutor.ts +7 -3
- package/packages/core/src/tools/agents/index.ts +18 -60
- package/packages/core/src/tools/cli/index.ts +55 -0
- package/packages/core/src/tools/core/index.ts +52 -4
- package/packages/core/src/tools/cron/index.ts +8 -8
- package/packages/core/src/tools/images/index.ts +130 -0
- package/packages/core/src/tools/index.ts +14 -1
- package/packages/core/src/tools/office/office-escribir-xlsx.ts +2 -1
- package/packages/core/src/tools/office/office-leer-xlsx.ts +2 -1
- package/packages/core/src/tools/office/xlsx-loader.ts +19 -0
- package/packages/core/src/tools/web/artifact-inspect.ts +2 -2
- package/packages/core/src/tools/web/artifact-read.ts +162 -0
- package/packages/core/src/tools/web/browser-backend.ts +141 -44
- package/packages/core/src/tools/web/browser-click.ts +2 -2
- package/packages/core/src/tools/web/browser-extract.ts +2 -2
- package/packages/core/src/tools/web/browser-navigate.ts +2 -2
- package/packages/core/src/tools/web/browser-screenshot.ts +12 -5
- package/packages/core/src/tools/web/browser-script.ts +2 -2
- package/packages/core/src/tools/web/browser-service.ts +63 -384
- package/packages/core/src/tools/web/browser-session.ts +125 -0
- package/packages/core/src/tools/web/browser-type.ts +2 -2
- package/packages/core/src/tools/web/browser-wait.ts +2 -2
- package/packages/core/src/tools/web/computer-use.ts +553 -0
- package/packages/core/src/tools/web/index.ts +8 -1
- package/packages/core/src/tools/web/webview-backend.ts +460 -21
- package/packages/core/src/utils/index.ts +1 -0
- package/packages/core/src/utils/logger.ts +12 -4
- package/packages/core/src/utils/redact-binary.ts +17 -0
- package/packages/core/src/utils/toon.ts +1 -1
- package/packages/core/src/voice/index.ts +6 -6
- package/bun.lock +0 -859
- package/bunfig.toml +0 -9
- package/docs/API-AGENTS.md +0 -367
- package/docs/API-CONTEXT-COMPILER.md +0 -249
- package/docs/API-DAG-SCHEDULER.md +0 -273
- package/docs/API-TOOLS-SKILLS-CHANNELS.md +0 -446
- package/docs/API-WORKERS-EVENTS.md +0 -299
- package/docs/HIVE-HARNESS.md +0 -113
- package/docs/INDEX.md +0 -190
- package/docs/TEMPLATE-HIVE-APP.md +0 -360
- package/packages/cli/package.json +0 -17
- package/packages/cli/src/commands/create-app.test.ts +0 -180
- package/packages/core/package.json +0 -70
- package/packages/core/src/api/createAgent.test.ts +0 -160
- package/packages/core/src/canvas/canvas.test.ts +0 -36
- package/packages/core/src/channels/channels.test.ts +0 -18
- package/packages/core/src/ethics/EthicsGuard.test.ts +0 -108
- package/packages/core/src/gateway/gateway.test.ts +0 -38
- package/packages/core/src/memory/Scratchpad.test.ts +0 -68
- package/packages/core/src/scheduler/scheduler.test.ts +0 -15
- package/packages/core/src/skills/skills.test.ts +0 -62
- package/packages/core/src/swarm/swarm.test.ts +0 -24
- package/packages/core/src/tool-runtime/tool-runtime.test.ts +0 -99
- package/packages/core/src/tools/ToolRegistry.test.ts +0 -98
- package/packages/core/src/tools/api/api-request.test.ts +0 -164
- package/packages/core/src/tools/web/browser-service.test.ts +0 -83
- package/packages/core/src/workers/workers.test.ts +0 -41
- package/scripts/bump-version.ts +0 -248
- package/scripts/generate-skill-bundle.ts +0 -108
- package/test/acceptance-checks.test.ts +0 -403
- package/test/agent-loop-terminal-synthesis.test.ts +0 -32
- package/test/browser-backend.test.ts +0 -308
- package/test/catalog-agents-stay-enabled.test.ts +0 -117
- package/test/causal-events.test.ts +0 -117
- package/test/compaction.test.ts +0 -105
- package/test/context-compiler.test.ts +0 -269
- package/test/curator.test.ts +0 -130
- package/test/durable-queue.test.ts +0 -114
- package/test/harness-barrel.test.ts +0 -64
- package/test/hive-helpers.test.ts +0 -130
- package/test/hivedb-search.test.ts +0 -189
- package/test/internal-turns.test.ts +0 -166
- package/test/job-idempotency.test.ts +0 -68
- package/test/job-retry-backoff.test.ts +0 -184
- package/test/job-store.test.ts +0 -381
- package/test/llm-retry.test.ts +0 -97
- package/test/memory-perf.test.ts +0 -774
- package/test/minimal-loadout.test.ts +0 -78
- package/test/model-catalog.test.ts +0 -105
- package/test/preload.ts +0 -12
- package/test/reflector.test.ts +0 -320
- package/test/retention-cap.test.ts +0 -91
- package/test/retired-capabilities-pruned.test.ts +0 -192
- package/test/run-store.test.ts +0 -355
- package/test/scratchpad.test.ts +0 -74
- package/test/secrets-durability.test.ts +0 -119
- package/test/seed-model-reseed.test.ts +0 -155
- package/test/setup-agent-seed.test.ts +0 -264
- package/test/tool-inventory.test.ts +0 -65
- package/test/tool-runtime.test.ts +0 -258
- package/test/tool-selector-runtime-tools.test.ts +0 -117
- package/test/toon.test.ts +0 -429
- package/tsconfig.json +0 -42
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* context-compiler tests: G9 causal context window (buildAgentContext).
|
|
3
|
-
*
|
|
4
|
-
* Exercises the real compileContext() path with a real (in-memory) HiveDB —
|
|
5
|
-
* only the pieces that would otherwise need network/process I/O
|
|
6
|
-
* (MCP manager, native tool executors) are left at their defaults since
|
|
7
|
-
* createAllTools() works standalone in-process.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
process.env.HIVE_DB_PATH = ":memory:";
|
|
11
|
-
|
|
12
|
-
import { describe, test, expect, beforeEach, afterEach } from "bun:test";
|
|
13
|
-
import { closeHiveDb, getHiveDb } from "../packages/core/src/storage/hivedb";
|
|
14
|
-
import { ensureHiveDb } from "../packages/core/src/storage/bootstrap";
|
|
15
|
-
import { resetBootId } from "../packages/core/src/storage/boot-id";
|
|
16
|
-
import { col, toIndexable } from "../packages/core/src/storage/hive";
|
|
17
|
-
import { addMessage, saveSummary } from "../packages/core/src/agent/conversation-store";
|
|
18
|
-
import { compileContext } from "../packages/core/src/agent/context-compiler";
|
|
19
|
-
import type { AgentDoc, ModelDoc, ProviderDoc, UserDoc } from "../packages/core/src/storage/collections";
|
|
20
|
-
|
|
21
|
-
async function seedAgentWithSmallContextWindow() {
|
|
22
|
-
const usersCol = await col<UserDoc>("users");
|
|
23
|
-
await usersCol.put("test-user", {
|
|
24
|
-
id: "test-user",
|
|
25
|
-
name: "Test User",
|
|
26
|
-
language: "es",
|
|
27
|
-
timezone: null,
|
|
28
|
-
occupation: null,
|
|
29
|
-
notes: null,
|
|
30
|
-
master_key_hash: null,
|
|
31
|
-
email: null,
|
|
32
|
-
password_hash: null,
|
|
33
|
-
preferred_cron_channel: "webchat",
|
|
34
|
-
created_at: Date.now(),
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const agentsCol = await col<AgentDoc>("agents");
|
|
38
|
-
await agentsCol.put("test-agent", {
|
|
39
|
-
id: "test-agent",
|
|
40
|
-
user_id: "test-user",
|
|
41
|
-
name: "Test Agent",
|
|
42
|
-
description: null,
|
|
43
|
-
system_prompt: "Eres un agente de prueba.",
|
|
44
|
-
tone: null,
|
|
45
|
-
role: "coordinator",
|
|
46
|
-
status: "idle",
|
|
47
|
-
enabled: true,
|
|
48
|
-
provider_id: toIndexable("hiveagents"),
|
|
49
|
-
model_id: toIndexable("test-model"),
|
|
50
|
-
tools_json: null,
|
|
51
|
-
skills_json: null,
|
|
52
|
-
parent_id: toIndexable(null),
|
|
53
|
-
max_iterations: 10,
|
|
54
|
-
workspace: null,
|
|
55
|
-
lastTraceAt: null,
|
|
56
|
-
created_at: Date.now(),
|
|
57
|
-
updated_at: Date.now(),
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const providersCol = await col<ProviderDoc>("providers");
|
|
61
|
-
await providersCol.put("hiveagents", {
|
|
62
|
-
id: "hiveagents",
|
|
63
|
-
name: "HiveAgents",
|
|
64
|
-
enabled: true,
|
|
65
|
-
active: true,
|
|
66
|
-
base_url: "https://fake.api.com/v1",
|
|
67
|
-
category: "llm",
|
|
68
|
-
num_ctx: null,
|
|
69
|
-
num_gpu: 0,
|
|
70
|
-
created_at: Date.now(),
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Small context window so a handful of messages is enough to cross
|
|
74
|
-
// compactThreshold (window * 0.8) and force the summary/compaction path.
|
|
75
|
-
const modelsCol = await col<ModelDoc>("models");
|
|
76
|
-
await modelsCol.put("test-model", {
|
|
77
|
-
id: "test-model",
|
|
78
|
-
provider_id: "hiveagents",
|
|
79
|
-
name: "Test Model",
|
|
80
|
-
model_type: "llm",
|
|
81
|
-
active: true,
|
|
82
|
-
enabled: true,
|
|
83
|
-
context_window: 1000,
|
|
84
|
-
capabilities: null,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// KEEP_LAST_N_MESSAGES in context-compiler.ts is 30 — insert enough messages
|
|
89
|
-
// that the recent-messages window is a strict suffix starting AFTER the
|
|
90
|
-
// summary's last_message_id. That's what makes a summary "apply": the window
|
|
91
|
-
// no longer reaches back far enough to cover what the summary already does.
|
|
92
|
-
async function forceCompaction(threadId: string) {
|
|
93
|
-
for (let i = 0; i < 35; i++) {
|
|
94
|
-
await addMessage(threadId, i % 2 === 0 ? "user" : "assistant", `msg-${i}`);
|
|
95
|
-
}
|
|
96
|
-
await saveSummary(threadId, "Resumen de la conversación previa.", 5, 5);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
beforeEach(async () => {
|
|
100
|
-
closeHiveDb();
|
|
101
|
-
resetBootId();
|
|
102
|
-
await ensureHiveDb();
|
|
103
|
-
await seedAgentWithSmallContextWindow();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
afterEach(() => {
|
|
107
|
-
closeHiveDb();
|
|
108
|
-
delete process.env.HIVE_CAUSAL_LOG;
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
describe("context-compiler: G9 causal context window", () => {
|
|
112
|
-
test("injects a # CAUSAL CONTEXT section once compaction fires and a causal stream has decisions", async () => {
|
|
113
|
-
process.env.HIVE_CAUSAL_LOG = "true";
|
|
114
|
-
const db = await getHiveDb();
|
|
115
|
-
|
|
116
|
-
const streamId = "ctx-stream-1";
|
|
117
|
-
const intentSeq = await db.append({
|
|
118
|
-
agentId: "test-agent",
|
|
119
|
-
streamId,
|
|
120
|
-
kind: "IntentLogged",
|
|
121
|
-
payload: JSON.stringify({ actor: "test-agent", intent: "deploy the checkout service" }),
|
|
122
|
-
});
|
|
123
|
-
await db.append({
|
|
124
|
-
agentId: "test-agent",
|
|
125
|
-
streamId,
|
|
126
|
-
kind: "StateTransition",
|
|
127
|
-
payload: JSON.stringify({ description: "Calling deploy_service on checkout" }),
|
|
128
|
-
causation: intentSeq,
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
await forceCompaction("thread-ctx-1");
|
|
132
|
-
|
|
133
|
-
const ctx = await compileContext({
|
|
134
|
-
agentId: "test-agent",
|
|
135
|
-
threadId: "thread-ctx-1",
|
|
136
|
-
userMessage: "Seguí con el deploy",
|
|
137
|
-
causalStreamId: streamId,
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
expect(ctx.systemPrompt).toContain("# CAUSAL CONTEXT");
|
|
141
|
-
expect(ctx.systemPrompt).toContain("Calling deploy_service on checkout");
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
test("does not inject a causal context section when causalLog is disabled", async () => {
|
|
145
|
-
process.env.HIVE_CAUSAL_LOG = "false";
|
|
146
|
-
const db = await getHiveDb();
|
|
147
|
-
|
|
148
|
-
const streamId = "ctx-stream-2";
|
|
149
|
-
const intentSeq = await db.append({
|
|
150
|
-
agentId: "test-agent",
|
|
151
|
-
streamId,
|
|
152
|
-
kind: "IntentLogged",
|
|
153
|
-
payload: JSON.stringify({ actor: "test-agent", intent: "deploy the checkout service" }),
|
|
154
|
-
});
|
|
155
|
-
await db.append({
|
|
156
|
-
agentId: "test-agent",
|
|
157
|
-
streamId,
|
|
158
|
-
kind: "StateTransition",
|
|
159
|
-
payload: JSON.stringify({ description: "Calling deploy_service on checkout" }),
|
|
160
|
-
causation: intentSeq,
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
await forceCompaction("thread-ctx-2");
|
|
164
|
-
|
|
165
|
-
const ctx = await compileContext({
|
|
166
|
-
agentId: "test-agent",
|
|
167
|
-
threadId: "thread-ctx-2",
|
|
168
|
-
userMessage: "Seguí con el deploy",
|
|
169
|
-
causalStreamId: streamId,
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
expect(ctx.systemPrompt).not.toContain("# CAUSAL CONTEXT");
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
test("does not inject a causal context section when compaction hasn't fired", async () => {
|
|
176
|
-
process.env.HIVE_CAUSAL_LOG = "true";
|
|
177
|
-
const db = await getHiveDb();
|
|
178
|
-
|
|
179
|
-
const streamId = "ctx-stream-3";
|
|
180
|
-
const intentSeq = await db.append({
|
|
181
|
-
agentId: "test-agent",
|
|
182
|
-
streamId,
|
|
183
|
-
kind: "IntentLogged",
|
|
184
|
-
payload: JSON.stringify({ actor: "test-agent", intent: "deploy the checkout service" }),
|
|
185
|
-
});
|
|
186
|
-
await db.append({
|
|
187
|
-
agentId: "test-agent",
|
|
188
|
-
streamId,
|
|
189
|
-
kind: "StateTransition",
|
|
190
|
-
payload: JSON.stringify({ description: "Calling deploy_service on checkout" }),
|
|
191
|
-
causation: intentSeq,
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
// No forceCompaction() call — conversation is short, no summary exists.
|
|
195
|
-
|
|
196
|
-
const ctx = await compileContext({
|
|
197
|
-
agentId: "test-agent",
|
|
198
|
-
threadId: "thread-ctx-3",
|
|
199
|
-
userMessage: "Hola",
|
|
200
|
-
causalStreamId: streamId,
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
expect(ctx.systemPrompt).not.toContain("# CAUSAL CONTEXT");
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
describe("context-compiler: conversation summary + internal events", () => {
|
|
208
|
-
test("folds the summary into systemPrompt as # RESUMEN DE LA CONVERSACIÓN when it applies", async () => {
|
|
209
|
-
await forceCompaction("thread-summary-1");
|
|
210
|
-
|
|
211
|
-
const ctx = await compileContext({
|
|
212
|
-
agentId: "test-agent",
|
|
213
|
-
threadId: "thread-summary-1",
|
|
214
|
-
userMessage: "Continuemos",
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
expect(ctx.systemPrompt).toContain("# RESUMEN DE LA CONVERSACIÓN");
|
|
218
|
-
expect(ctx.systemPrompt).toContain("Resumen de la conversación previa.");
|
|
219
|
-
expect(ctx.conversationSummarySection).not.toBe("");
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
test("does not include a summary section when none applies", async () => {
|
|
223
|
-
await addMessage("thread-summary-2", "user", "Hola");
|
|
224
|
-
|
|
225
|
-
const ctx = await compileContext({
|
|
226
|
-
agentId: "test-agent",
|
|
227
|
-
threadId: "thread-summary-2",
|
|
228
|
-
userMessage: "Hola de nuevo",
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
expect(ctx.systemPrompt).not.toContain("# RESUMEN DE LA CONVERSACIÓN");
|
|
232
|
-
expect(ctx.conversationSummarySection).toBe("");
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
test("never emits a second role:system message in ctx.messages, even when a summary applies", async () => {
|
|
236
|
-
await forceCompaction("thread-summary-3");
|
|
237
|
-
|
|
238
|
-
const ctx = await compileContext({
|
|
239
|
-
agentId: "test-agent",
|
|
240
|
-
threadId: "thread-summary-3",
|
|
241
|
-
userMessage: "Continuemos",
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
expect(ctx.messages.every((m) => m.role !== "system")).toBe(true);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
test("an internal event keeps its chronological position and role:user in ctx.messages", async () => {
|
|
248
|
-
const threadId = "thread-internal-1";
|
|
249
|
-
await addMessage(threadId, "user", "Delegá esto a un worker");
|
|
250
|
-
await addMessage(threadId, "assistant", "Listo, delegado.");
|
|
251
|
-
await addMessage(threadId, "user", "El agente completó la tarea X.", { source: "task_complete" });
|
|
252
|
-
await addMessage(threadId, "assistant", "El worker terminó la tarea X exitosamente.");
|
|
253
|
-
|
|
254
|
-
const ctx = await compileContext({
|
|
255
|
-
agentId: "test-agent",
|
|
256
|
-
threadId,
|
|
257
|
-
userMessage: "¿Cómo va todo?",
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
expect(ctx.messages.every((m) => m.role !== "system")).toBe(true);
|
|
261
|
-
|
|
262
|
-
const idx = ctx.messages.findIndex(
|
|
263
|
-
(m) => typeof m.content === "string" && m.content.includes("hive:internal_event")
|
|
264
|
-
);
|
|
265
|
-
expect(idx).toBeGreaterThan(0);
|
|
266
|
-
expect(idx).toBeLessThan(ctx.messages.length - 1);
|
|
267
|
-
expect(ctx.messages[idx].role).toBe("user");
|
|
268
|
-
});
|
|
269
|
-
});
|
package/test/curator.test.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Curator tests: baseline regression coverage for the existing
|
|
3
|
-
* reflection → playbook pipeline (none existed before), plus the new
|
|
4
|
-
* category mapping for G9 evaluateHarness() insight types
|
|
5
|
-
* (root_cause/learning_proposal — see reflector.ts's analyzeCausalThreads).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
process.env.HIVE_DB_PATH = ":memory:";
|
|
9
|
-
|
|
10
|
-
import { describe, test, expect, beforeEach, afterEach } from "bun:test";
|
|
11
|
-
import { closeHiveDb } from "../packages/core/src/storage/hivedb";
|
|
12
|
-
import { ensureHiveDb } from "../packages/core/src/storage/bootstrap";
|
|
13
|
-
import { resetBootId } from "../packages/core/src/storage/boot-id";
|
|
14
|
-
import { col, nextId } from "../packages/core/src/storage/hive";
|
|
15
|
-
import type { ReflectionDoc, PlaybookDoc } from "../packages/core/src/storage/collections";
|
|
16
|
-
import { runCurator } from "../packages/core/src/agent/curator";
|
|
17
|
-
|
|
18
|
-
async function seedReflection(overrides: Partial<ReflectionDoc>) {
|
|
19
|
-
const reflectionsCol = await col<ReflectionDoc>("reflections");
|
|
20
|
-
const id = await nextId("reflections");
|
|
21
|
-
await reflectionsCol.put(id, {
|
|
22
|
-
id,
|
|
23
|
-
trace_ids: "[]",
|
|
24
|
-
insight_type: "failure_pattern",
|
|
25
|
-
description: "Tool 'flaky_tool' failed 5 times recently.",
|
|
26
|
-
affected_tools: null,
|
|
27
|
-
affected_agents: null,
|
|
28
|
-
confidence: 0.5,
|
|
29
|
-
created_at: Date.now(),
|
|
30
|
-
...overrides,
|
|
31
|
-
});
|
|
32
|
-
return id;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
beforeEach(async () => {
|
|
36
|
-
closeHiveDb();
|
|
37
|
-
resetBootId();
|
|
38
|
-
await ensureHiveDb();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
afterEach(() => {
|
|
42
|
-
closeHiveDb();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
describe("curator: baseline reflection → playbook pipeline", () => {
|
|
46
|
-
test("a new reflection creates a new active playbook rule", async () => {
|
|
47
|
-
await seedReflection({ description: "Tool 'flaky_tool' failed 5 times recently." });
|
|
48
|
-
|
|
49
|
-
await runCurator();
|
|
50
|
-
|
|
51
|
-
const playbookCol = await col<PlaybookDoc>("playbook");
|
|
52
|
-
const all = await playbookCol.scan({});
|
|
53
|
-
const rule = all.find((e) => e.doc.rule === "Tool 'flaky_tool' failed 5 times recently.");
|
|
54
|
-
expect(rule).toBeDefined();
|
|
55
|
-
expect(rule!.doc.category).toBe("error_avoidance");
|
|
56
|
-
expect(rule!.doc.helpful_count).toBe(1);
|
|
57
|
-
expect(rule!.doc.harmful_count).toBe(0);
|
|
58
|
-
expect(rule!.doc.active).toBe(true);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("a reflection matching an existing rule's prefix reinforces it instead of duplicating", async () => {
|
|
62
|
-
const description = "Tool 'flaky_tool' failed 5 times recently. Consider verifying its configuration.";
|
|
63
|
-
await seedReflection({ description });
|
|
64
|
-
await runCurator();
|
|
65
|
-
|
|
66
|
-
// Second, near-identical reflection (same first-60-chars prefix)
|
|
67
|
-
await seedReflection({ description: description + " Extra detail." });
|
|
68
|
-
await runCurator();
|
|
69
|
-
|
|
70
|
-
const playbookCol = await col<PlaybookDoc>("playbook");
|
|
71
|
-
const all = await playbookCol.scan({});
|
|
72
|
-
const matching = all.filter((e) => e.doc.rule.startsWith(description.substring(0, 60)));
|
|
73
|
-
expect(matching.length).toBe(1);
|
|
74
|
-
expect(matching[0].doc.helpful_count).toBe(2);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test("a rule with harmful_count >= 3 and > helpful_count is deactivated on the next curator run", async () => {
|
|
78
|
-
const playbookCol = await col<PlaybookDoc>("playbook");
|
|
79
|
-
const now = Date.now();
|
|
80
|
-
await playbookCol.put("bad-rule", {
|
|
81
|
-
id: "bad-rule",
|
|
82
|
-
rule: "This rule turned out to be harmful.",
|
|
83
|
-
category: "optimization",
|
|
84
|
-
applicable_to: null,
|
|
85
|
-
helpful_count: 1,
|
|
86
|
-
harmful_count: 3,
|
|
87
|
-
active: true,
|
|
88
|
-
source_reflection_id: "NO_PARENT",
|
|
89
|
-
created_at: now,
|
|
90
|
-
updated_at: now,
|
|
91
|
-
}, { expectedVersion: 0 });
|
|
92
|
-
|
|
93
|
-
await runCurator();
|
|
94
|
-
|
|
95
|
-
const entry = await playbookCol.get("bad-rule");
|
|
96
|
-
expect(entry!.doc.active).toBe(false);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
describe("curator: G9 evaluateHarness() insight category mapping", () => {
|
|
101
|
-
test("root_cause insights map to the error_avoidance category", async () => {
|
|
102
|
-
await seedReflection({
|
|
103
|
-
insight_type: "root_cause",
|
|
104
|
-
description: "Root cause in stream s1: called deploy_prod without running tests first.",
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
await runCurator();
|
|
108
|
-
|
|
109
|
-
const playbookCol = await col<PlaybookDoc>("playbook");
|
|
110
|
-
const all = await playbookCol.scan({});
|
|
111
|
-
const rule = all.find((e) => e.doc.rule.startsWith("Root cause in stream s1"));
|
|
112
|
-
expect(rule).toBeDefined();
|
|
113
|
-
expect(rule!.doc.category).toBe("error_avoidance");
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test("learning_proposal insights map to the response_quality category", async () => {
|
|
117
|
-
await seedReflection({
|
|
118
|
-
insight_type: "learning_proposal",
|
|
119
|
-
description: "Add pre-checks before calling tool 'flaky_tool' to avoid repeated errors",
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
await runCurator();
|
|
123
|
-
|
|
124
|
-
const playbookCol = await col<PlaybookDoc>("playbook");
|
|
125
|
-
const all = await playbookCol.scan({});
|
|
126
|
-
const rule = all.find((e) => e.doc.rule.startsWith("Add pre-checks before calling tool"));
|
|
127
|
-
expect(rule).toBeDefined();
|
|
128
|
-
expect(rule!.doc.category).toBe("response_quality");
|
|
129
|
-
});
|
|
130
|
-
});
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests: DurableLaneQueue — dispatch, boot re-dispatch, forced reclaim.
|
|
3
|
-
*
|
|
4
|
-
* 1. enqueue → dispatch → executor runs → job completed
|
|
5
|
-
* 2. start() dispatches jobs left pending by a previous boot
|
|
6
|
-
* 3. reconcileOnBoot reclaims "running" jobs immediately (single-process:
|
|
7
|
-
* any running row at boot belongs to a dead process, lease ignored)
|
|
8
|
-
* 4. reclaimOrInterrupt force interrupts when attempts are exhausted
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
process.env.HIVE_DB_PATH = ":memory:";
|
|
12
|
-
|
|
13
|
-
import { describe, test, expect, beforeEach, afterEach } from "bun:test";
|
|
14
|
-
import { closeHiveDb } from "../packages/core/src/storage/hivedb";
|
|
15
|
-
import { ensureHiveDb } from "../packages/core/src/storage/bootstrap";
|
|
16
|
-
import { resetBootId, getBootId } from "../packages/core/src/storage/boot-id";
|
|
17
|
-
import { DurableLaneQueue, registerExecutor } from "../packages/core/src/gateway/durable-queue";
|
|
18
|
-
import { createJob, claimJob, getJob, reclaimOrInterrupt } from "../packages/core/src/gateway/job-store";
|
|
19
|
-
import { reconcileOnBoot } from "../packages/core/src/storage/reconcile";
|
|
20
|
-
|
|
21
|
-
let queue: DurableLaneQueue | null = null;
|
|
22
|
-
|
|
23
|
-
beforeEach(async () => {
|
|
24
|
-
closeHiveDb();
|
|
25
|
-
resetBootId();
|
|
26
|
-
await ensureHiveDb();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
afterEach(() => {
|
|
30
|
-
queue?.stop();
|
|
31
|
-
queue = null;
|
|
32
|
-
closeHiveDb();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
async function waitFor(predicate: () => Promise<boolean>, timeoutMs = 3000): Promise<void> {
|
|
36
|
-
const start = Date.now();
|
|
37
|
-
while (Date.now() - start < timeoutMs) {
|
|
38
|
-
if (await predicate()) return;
|
|
39
|
-
await new Promise((r) => setTimeout(r, 25));
|
|
40
|
-
}
|
|
41
|
-
throw new Error("waitFor timed out");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
describe("durable-queue: dispatch + reclaim", () => {
|
|
45
|
-
test("enqueue dispatches the job and persists the executor result", async () => {
|
|
46
|
-
const executed: string[] = [];
|
|
47
|
-
registerExecutor("worker_task", async (job) => {
|
|
48
|
-
executed.push(job.id);
|
|
49
|
-
return { ok: true, result: "done!" };
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
queue = new DurableLaneQueue({ maxGlobalConcurrency: 2 });
|
|
53
|
-
const job = await queue.enqueue({
|
|
54
|
-
lane: "task:test-1",
|
|
55
|
-
type: "worker_task",
|
|
56
|
-
run_id: "run-x",
|
|
57
|
-
payload: { hello: "world" },
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
await waitFor(async () => (await getJob(job.id))?.status === "completed");
|
|
61
|
-
|
|
62
|
-
const finished = await getJob(job.id);
|
|
63
|
-
expect(executed).toContain(job.id);
|
|
64
|
-
expect(finished!.status).toBe("completed");
|
|
65
|
-
expect(JSON.parse(finished!.result_json!)).toBe("done!");
|
|
66
|
-
expect(finished!.boot_id).toBeNull();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test("start() re-dispatches jobs left pending by a previous boot", async () => {
|
|
70
|
-
const executed: string[] = [];
|
|
71
|
-
registerExecutor("worker_task", async (job) => {
|
|
72
|
-
executed.push(job.id);
|
|
73
|
-
return { ok: true, result: null };
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Jobs created directly (as if the process died right after enqueue)
|
|
77
|
-
const j1 = await createJob({ lane: "task:a", type: "worker_task", payload: {}, run_id: "r1" });
|
|
78
|
-
const j2 = await createJob({ lane: "task:b", type: "worker_task", payload: {}, run_id: "r2" });
|
|
79
|
-
|
|
80
|
-
queue = new DurableLaneQueue({ maxGlobalConcurrency: 2 });
|
|
81
|
-
queue.start();
|
|
82
|
-
|
|
83
|
-
await waitFor(async () =>
|
|
84
|
-
(await getJob(j1.id))?.status === "completed" && (await getJob(j2.id))?.status === "completed"
|
|
85
|
-
);
|
|
86
|
-
expect(executed.sort()).toEqual([j1.id, j2.id].sort());
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
test("reconcileOnBoot reclaims a running job immediately, ignoring its lease", async () => {
|
|
90
|
-
const job = await createJob({ lane: "task:c", type: "worker_task", payload: {}, run_id: "r3" });
|
|
91
|
-
const claimed = await claimJob(job.id, "dead-boot");
|
|
92
|
-
expect(claimed!.status).toBe("running");
|
|
93
|
-
// Lease is still fresh (30 min) — at boot it must be reclaimed anyway
|
|
94
|
-
expect(claimed!.lease_expires_at! > Date.now()).toBe(true);
|
|
95
|
-
|
|
96
|
-
await reconcileOnBoot(getBootId());
|
|
97
|
-
|
|
98
|
-
const after = await getJob(job.id);
|
|
99
|
-
expect(after!.status).toBe("pending");
|
|
100
|
-
expect(after!.boot_id).toBeNull();
|
|
101
|
-
expect(after!.attempts).toBe(1);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test("forced reclaim interrupts the job when attempts are exhausted", async () => {
|
|
105
|
-
const job = await createJob({ lane: "task:d", type: "worker_task", payload: {}, run_id: "r4", max_attempts: 2 });
|
|
106
|
-
await claimJob(job.id, "boot-1"); // attempts = 1
|
|
107
|
-
await reclaimOrInterrupt(job.id, { force: true }); // back to pending
|
|
108
|
-
await claimJob(job.id, "boot-2"); // attempts = 2
|
|
109
|
-
const final = await reclaimOrInterrupt(job.id, { force: true });
|
|
110
|
-
|
|
111
|
-
expect(final!.status).toBe("interrupted");
|
|
112
|
-
expect(final!.error).toContain("Max attempts");
|
|
113
|
-
});
|
|
114
|
-
});
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `harness/` pasó de tener implementación propia a ser un barrel.
|
|
3
|
-
*
|
|
4
|
-
* Hasta 0.1.5 el módulo traía sus propias copias de `db-helpers`, `boot-id`,
|
|
5
|
-
* `reconcile`, `collections`, `run-store`, `run-epoch` y `proof-packet`, en
|
|
6
|
-
* paralelo con las de `storage/` y `agent/`. Dos almacenes de jobs sobre las
|
|
7
|
-
* mismas colecciones de HiveDB son una sola cosa con dos estados posibles.
|
|
8
|
-
*
|
|
9
|
-
* Lo que este test protege no es el comportamiento (eso lo cubren
|
|
10
|
-
* job-store/durable-queue/run-store.test.ts) sino el contrato del subpath
|
|
11
|
-
* `@johpaz/hive-sdk/harness`: que siga exportando los mismos nombres y que
|
|
12
|
-
* apunten a la implementación única.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
process.env.HIVE_DB_PATH = ":memory:";
|
|
16
|
-
|
|
17
|
-
import { describe, test, expect } from "bun:test";
|
|
18
|
-
import * as harness from "../packages/core/src/harness/index.ts";
|
|
19
|
-
import { createJob } from "../packages/core/src/gateway/job-store.ts";
|
|
20
|
-
import { createRun } from "../packages/core/src/agent/run-store.ts";
|
|
21
|
-
import { col } from "../packages/core/src/storage/hive.ts";
|
|
22
|
-
|
|
23
|
-
describe("subpath @johpaz/hive-sdk/harness", () => {
|
|
24
|
-
test("sigue exportando la superficie que tenía", () => {
|
|
25
|
-
for (const name of [
|
|
26
|
-
"createJob",
|
|
27
|
-
"getJob",
|
|
28
|
-
"registerExecutor",
|
|
29
|
-
"getDurableQueue",
|
|
30
|
-
"initDurableQueue",
|
|
31
|
-
"DurableLaneQueue",
|
|
32
|
-
"createRun",
|
|
33
|
-
"checkpoint",
|
|
34
|
-
"completeRun",
|
|
35
|
-
"failRun",
|
|
36
|
-
"interruptRun",
|
|
37
|
-
"reclaimRun",
|
|
38
|
-
"getRun",
|
|
39
|
-
"buildRunEpoch",
|
|
40
|
-
"buildProofPacket",
|
|
41
|
-
"verifyGoal",
|
|
42
|
-
"getBootId",
|
|
43
|
-
"resetBootId",
|
|
44
|
-
"reconcileOnBoot",
|
|
45
|
-
"ensureHarnessIndexes",
|
|
46
|
-
"col",
|
|
47
|
-
"nextId",
|
|
48
|
-
"updateDoc",
|
|
49
|
-
"findByAny",
|
|
50
|
-
"toIndexable",
|
|
51
|
-
"fromIndexable",
|
|
52
|
-
"NO_PARENT",
|
|
53
|
-
]) {
|
|
54
|
-
expect(harness[name as keyof typeof harness], `falta el export ${name}`).toBeDefined();
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("re-exporta la misma función, no una copia", () => {
|
|
59
|
-
// Si esto falla es que harness/ volvió a tener implementación propia.
|
|
60
|
-
expect(harness.createJob).toBe(createJob);
|
|
61
|
-
expect(harness.createRun).toBe(createRun);
|
|
62
|
-
expect(harness.col).toBe(col);
|
|
63
|
-
});
|
|
64
|
-
});
|