@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,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reconcileOnBoot — centralized repair of rows left in inconsistent states
|
|
3
|
+
* by a previous crash/kill.
|
|
4
|
+
*
|
|
5
|
+
* Currently repairs:
|
|
6
|
+
* - taskRuns: running → timeout (moved from server.ts inline)
|
|
7
|
+
* - meetingSessions: active (orphaned) → stopped
|
|
8
|
+
* - agentRuns: running + expired lease → interrupted (chat) or mark for re-enqueue
|
|
9
|
+
* - jobQueue: running + expired lease → pending (reclaim) or interrupted
|
|
10
|
+
*
|
|
11
|
+
* This is called early in the boot sequence, before the scheduler and
|
|
12
|
+
* durable queue are activated.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { col, updateDoc } from "./hive";
|
|
16
|
+
import type { TaskRunDoc, MeetingSessionDoc, AgentRunDoc, JobDoc, TaskDoc } from "./collections";
|
|
17
|
+
import { logger } from "../utils/logger";
|
|
18
|
+
import { reclaimOrInterrupt } from "../gateway/job-store.ts";
|
|
19
|
+
import { interruptRun } from "../agent/run-store";
|
|
20
|
+
import { sendToUserChannel } from "../gateway/channel-notify";
|
|
21
|
+
|
|
22
|
+
const log = logger.child("reconcile");
|
|
23
|
+
|
|
24
|
+
export interface ReconcileResult {
|
|
25
|
+
bootId: string;
|
|
26
|
+
taskRunsTimedOut: number;
|
|
27
|
+
meetingsStopped: number;
|
|
28
|
+
runsInterrupted: number;
|
|
29
|
+
runsReEnqueueable: number;
|
|
30
|
+
jobsReclaimed: number;
|
|
31
|
+
jobsInterrupted: number;
|
|
32
|
+
tasksRequeued: number;
|
|
33
|
+
tasksFailed: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function reconcileOnBoot(bootId: string): Promise<ReconcileResult> {
|
|
37
|
+
log.info(`[reconcileOnBoot] Starting with boot_id=${bootId}`);
|
|
38
|
+
const result: ReconcileResult = {
|
|
39
|
+
bootId,
|
|
40
|
+
taskRunsTimedOut: 0,
|
|
41
|
+
meetingsStopped: 0,
|
|
42
|
+
runsInterrupted: 0,
|
|
43
|
+
runsReEnqueueable: 0,
|
|
44
|
+
jobsReclaimed: 0,
|
|
45
|
+
jobsInterrupted: 0,
|
|
46
|
+
tasksRequeued: 0,
|
|
47
|
+
tasksFailed: 0,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// 1. taskRuns: running → timeout (moved from server.ts:211-220)
|
|
51
|
+
try {
|
|
52
|
+
const taskRunsCol = await col<TaskRunDoc>("taskRuns");
|
|
53
|
+
const orphanedRuns = (await taskRunsCol.scan({})).filter((e) => e.doc.status === "running");
|
|
54
|
+
for (const run of orphanedRuns) {
|
|
55
|
+
await taskRunsCol.put(
|
|
56
|
+
run.id,
|
|
57
|
+
{ ...run.doc, status: "timeout", finished_at: new Date().toISOString() },
|
|
58
|
+
{ expectedVersion: run.version }
|
|
59
|
+
);
|
|
60
|
+
result.taskRunsTimedOut++;
|
|
61
|
+
}
|
|
62
|
+
if (result.taskRunsTimedOut > 0) {
|
|
63
|
+
log.info(`[reconcileOnBoot] ${result.taskRunsTimedOut} orphaned taskRuns → timeout`);
|
|
64
|
+
}
|
|
65
|
+
} catch (err) {
|
|
66
|
+
log.warn(`[reconcileOnBoot] Failed to repair taskRuns: ${(err as Error).message}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 2. meetingSessions: active (orphaned) → stopped
|
|
70
|
+
try {
|
|
71
|
+
const meetingsCol = await col<MeetingSessionDoc>("meetingSessions");
|
|
72
|
+
const activeMeetings = await meetingsCol.findBy("status", "active");
|
|
73
|
+
for (const m of activeMeetings) {
|
|
74
|
+
await meetingsCol.put(
|
|
75
|
+
m.id,
|
|
76
|
+
{ ...m.doc, status: "stopped", stopped_at: Date.now() },
|
|
77
|
+
{ expectedVersion: m.version }
|
|
78
|
+
);
|
|
79
|
+
result.meetingsStopped++;
|
|
80
|
+
}
|
|
81
|
+
if (result.meetingsStopped > 0) {
|
|
82
|
+
log.info(`[reconcileOnBoot] ${result.meetingsStopped} orphaned meetings → stopped`);
|
|
83
|
+
}
|
|
84
|
+
} catch (err) {
|
|
85
|
+
log.warn(`[reconcileOnBoot] Failed to repair meetings: ${(err as Error).message}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 3. agentRuns: any "running" row is orphaned at boot — HiveDB is
|
|
89
|
+
// single-process and this process just started, so no run can actually be
|
|
90
|
+
// executing. Waiting out the lease would leave fast restarts (< lease
|
|
91
|
+
// duration) unrepaired forever.
|
|
92
|
+
try {
|
|
93
|
+
const agentRunsCol = await col<AgentRunDoc>("agentRuns");
|
|
94
|
+
const runningRuns = await agentRunsCol.findBy("status", "running");
|
|
95
|
+
for (const entry of runningRuns) {
|
|
96
|
+
const run = entry.doc;
|
|
97
|
+
|
|
98
|
+
if (run.kind === "chat") {
|
|
99
|
+
await interruptRun(run.id, "Process restarted while chat turn was in flight");
|
|
100
|
+
result.runsInterrupted++;
|
|
101
|
+
try {
|
|
102
|
+
if (run.channel && run.user_id) {
|
|
103
|
+
await sendToUserChannel(run.channel, run.user_id, "Se interrumpió un turno en progreso por un reinicio del proceso.");
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
// non-critical
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
await interruptRun(run.id, "Process restarted — job will be re-enqueued if durable");
|
|
110
|
+
result.runsReEnqueueable++;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (result.runsInterrupted > 0 || result.runsReEnqueueable > 0) {
|
|
114
|
+
log.info(
|
|
115
|
+
`[reconcileOnBoot] ${result.runsInterrupted} chat runs interrupted, ${result.runsReEnqueueable} durable runs flagged for re-enqueue`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
} catch (err) {
|
|
119
|
+
log.warn(`[reconcileOnBoot] Failed to repair agentRuns: ${(err as Error).message}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 4. jobQueue: any "running" row is orphaned at boot (same single-process
|
|
123
|
+
// argument as above) → reclaim (pending) or interrupt, ignoring the lease.
|
|
124
|
+
try {
|
|
125
|
+
const jobsCol = await col<JobDoc>("jobQueue");
|
|
126
|
+
const runningJobs = await jobsCol.findBy("status", "running");
|
|
127
|
+
for (const entry of runningJobs) {
|
|
128
|
+
const job = entry.doc;
|
|
129
|
+
const result_doc = await reclaimOrInterrupt(job.id, { force: true });
|
|
130
|
+
if (result_doc?.status === "pending") result.jobsReclaimed++;
|
|
131
|
+
else if (result_doc?.status === "interrupted") result.jobsInterrupted++;
|
|
132
|
+
}
|
|
133
|
+
if (result.jobsReclaimed > 0 || result.jobsInterrupted > 0) {
|
|
134
|
+
log.info(
|
|
135
|
+
`[reconcileOnBoot] ${result.jobsReclaimed} jobs reclaimed to pending, ${result.jobsInterrupted} jobs interrupted (attempts exhausted)`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
} catch (err) {
|
|
139
|
+
log.warn(`[reconcileOnBoot] Failed to repair jobQueue: ${(err as Error).message}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 5. tasks: in_progress without a live job → pending (attempts+1) or failed
|
|
143
|
+
try {
|
|
144
|
+
const tasksCol = await col<TaskDoc>("tasks");
|
|
145
|
+
const inProgress = await tasksCol.findBy("status", "in_progress");
|
|
146
|
+
const { getJob } = await import("../gateway/job-store.ts");
|
|
147
|
+
for (const entry of inProgress) {
|
|
148
|
+
const task = entry.doc;
|
|
149
|
+
let hasLiveJob = false;
|
|
150
|
+
if (task.job_id) {
|
|
151
|
+
const job = await getJob(task.job_id);
|
|
152
|
+
// pending counts as live: the durable queue re-dispatches it at boot
|
|
153
|
+
if (job && (job.status === "running" || job.status === "pending")) {
|
|
154
|
+
hasLiveJob = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (!hasLiveJob) {
|
|
158
|
+
const attempts = (task.attempts ?? 0) + 1;
|
|
159
|
+
if (attempts >= 2) {
|
|
160
|
+
await tasksCol.put(entry.id, {
|
|
161
|
+
...task,
|
|
162
|
+
status: "failed",
|
|
163
|
+
error: "Max attempts reached after process restart",
|
|
164
|
+
attempts,
|
|
165
|
+
updated_at: Date.now(),
|
|
166
|
+
}, { expectedVersion: entry.version });
|
|
167
|
+
result.tasksFailed++;
|
|
168
|
+
} else {
|
|
169
|
+
await tasksCol.put(entry.id, {
|
|
170
|
+
...task,
|
|
171
|
+
status: "pending",
|
|
172
|
+
attempts,
|
|
173
|
+
updated_at: Date.now(),
|
|
174
|
+
}, { expectedVersion: entry.version });
|
|
175
|
+
result.tasksRequeued++;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (result.tasksRequeued > 0 || result.tasksFailed > 0) {
|
|
180
|
+
log.info(`[reconcileOnBoot] ${result.tasksRequeued} tasks requeued, ${result.tasksFailed} tasks failed (attempts exhausted)`);
|
|
181
|
+
}
|
|
182
|
+
} catch (err) {
|
|
183
|
+
log.warn(`[reconcileOnBoot] Failed to repair tasks: ${(err as Error).message}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// 6. Retention cap: keep only the most recent 500 agentRuns and 500 jobs per thread/run
|
|
187
|
+
const RETENTION_LIMIT = 500;
|
|
188
|
+
try {
|
|
189
|
+
const agentRunsCol = await col<AgentRunDoc>("agentRuns");
|
|
190
|
+
const allRuns = await agentRunsCol.scan({});
|
|
191
|
+
const runsByThread = new Map<string, typeof allRuns>();
|
|
192
|
+
for (const entry of allRuns) {
|
|
193
|
+
const threadId = entry.doc.thread_id ?? entry.doc.agent_id ?? "_default";
|
|
194
|
+
const list = runsByThread.get(threadId) ?? [];
|
|
195
|
+
list.push(entry);
|
|
196
|
+
runsByThread.set(threadId, list);
|
|
197
|
+
}
|
|
198
|
+
let runsPruned = 0;
|
|
199
|
+
for (const [, runs] of runsByThread) {
|
|
200
|
+
if (runs.length <= RETENTION_LIMIT) continue;
|
|
201
|
+
const sorted = runs.sort((a, b) => (b.doc.created_at ?? 0) - (a.doc.created_at ?? 0));
|
|
202
|
+
for (const entry of sorted.slice(RETENTION_LIMIT)) {
|
|
203
|
+
await agentRunsCol.delete(entry.id);
|
|
204
|
+
runsPruned++;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (runsPruned > 0) {
|
|
208
|
+
log.info(`[reconcileOnBoot] Retention: pruned ${runsPruned} old agentRuns (cap=${RETENTION_LIMIT}/thread)`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const jobsCol = await col<JobDoc>("jobQueue");
|
|
212
|
+
const allJobs = await jobsCol.scan({});
|
|
213
|
+
const jobsByRun = new Map<string, typeof allJobs>();
|
|
214
|
+
for (const entry of allJobs) {
|
|
215
|
+
const runId = entry.doc.run_id ?? "_default";
|
|
216
|
+
const list = jobsByRun.get(runId) ?? [];
|
|
217
|
+
list.push(entry);
|
|
218
|
+
jobsByRun.set(runId, list);
|
|
219
|
+
}
|
|
220
|
+
let jobsPruned = 0;
|
|
221
|
+
for (const [, jobs] of jobsByRun) {
|
|
222
|
+
if (jobs.length <= RETENTION_LIMIT) continue;
|
|
223
|
+
const sorted = jobs.sort((a, b) => (b.doc.created_at ?? 0) - (a.doc.created_at ?? 0));
|
|
224
|
+
for (const entry of sorted.slice(RETENTION_LIMIT)) {
|
|
225
|
+
await jobsCol.delete(entry.id);
|
|
226
|
+
jobsPruned++;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (jobsPruned > 0) {
|
|
230
|
+
log.info(`[reconcileOnBoot] Retention: pruned ${jobsPruned} old jobs (cap=${RETENTION_LIMIT}/run)`);
|
|
231
|
+
}
|
|
232
|
+
} catch (err) {
|
|
233
|
+
log.warn(`[reconcileOnBoot] Failed to enforce retention cap: ${(err as Error).message}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
log.info(`[reconcileOnBoot] Done`, result);
|
|
237
|
+
return result;
|
|
238
|
+
}
|