@johpaz/hive-sdk 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +129 -0
- package/README.md +78 -23
- package/bun.lock +55 -29
- package/bunfig.toml +4 -2
- package/docs/API-AGENTS.md +78 -27
- package/docs/API-CONTEXT-COMPILER.md +31 -34
- package/docs/API-TOOLS-SKILLS-CHANNELS.md +58 -22
- package/docs/HIVE-HARNESS.md +1 -1
- package/docs/INDEX.md +4 -4
- package/docs/TEMPLATE-HIVE-APP.md +10 -10
- package/package.json +17 -12
- package/packages/cli/package.json +2 -2
- package/packages/cli/src/commands/create-app.test.ts +36 -7
- package/packages/cli/src/commands/init.ts +3 -3
- package/packages/cli/src/commands/run.ts +1 -1
- package/packages/cli/src/commands/test.ts +37 -25
- package/packages/cli/src/commands/trace.ts +30 -28
- package/packages/cli/templates/hive-app/.env.example +10 -2
- package/packages/cli/templates/hive-app/README.md +103 -0
- package/packages/cli/templates/hive-app/hive.config.ts +9 -3
- package/packages/cli/templates/hive-app/src/agents/coordinator.ts +8 -1
- package/packages/cli/templates/hive-app/src/main.ts +12 -19
- package/packages/core/package.json +13 -12
- package/packages/core/src/agent/acceptance-checks.ts +172 -0
- package/packages/core/src/agent/agent-catalog.ts +348 -0
- package/packages/core/src/agent/agent-loop.ts +1373 -0
- package/packages/core/src/agent/capability-search.ts +186 -0
- package/packages/core/src/agent/catalog-selector.ts +103 -0
- package/packages/core/src/agent/{Compaction.ts → compaction.ts} +86 -63
- package/packages/core/src/agent/context-compiler.ts +689 -0
- package/packages/core/src/agent/conversation-store.ts +381 -0
- package/packages/core/src/agent/curator.ts +276 -0
- package/packages/core/src/agent/delegation-runtime.ts +241 -0
- package/packages/core/src/agent/goal-runner.ts +323 -0
- package/packages/core/src/agent/index.ts +17 -12
- package/packages/core/src/agent/llm-client.ts +266 -0
- package/packages/core/src/agent/llm-providers/anthropic.ts +264 -0
- package/packages/core/src/agent/llm-providers/deepseek.ts +8 -0
- package/packages/core/src/agent/{providers → llm-providers}/gemini.ts +98 -60
- package/packages/core/src/agent/llm-providers/groq.ts +5 -0
- package/packages/core/src/agent/llm-providers/hiveagents.ts +253 -0
- package/packages/core/src/agent/{providers → llm-providers}/interface.ts +73 -13
- package/packages/core/src/agent/llm-providers/kimi.ts +8 -0
- package/packages/core/src/agent/llm-providers/minimax.ts +13 -0
- package/packages/core/src/agent/llm-providers/mistral.ts +5 -0
- package/packages/core/src/agent/llm-providers/modelscope.ts +5 -0
- package/packages/core/src/agent/llm-providers/nvidia.ts +5 -0
- package/packages/core/src/agent/{providers → llm-providers}/ollama.ts +31 -5
- package/packages/core/src/agent/llm-providers/openai-compat-base.ts +418 -0
- package/packages/core/src/agent/llm-providers/openai.ts +5 -0
- package/packages/core/src/agent/llm-providers/opencode-go.ts +9 -0
- package/packages/core/src/agent/llm-providers/openrouter.ts +5 -0
- package/packages/core/src/agent/llm-providers/qwen.ts +5 -0
- package/packages/core/src/agent/llm-providers/z-ai.ts +5 -0
- package/packages/core/src/agent/minimal-loadout.ts +47 -0
- package/packages/core/src/agent/playbook-selector.ts +119 -0
- package/packages/core/src/agent/{PromptBuilder.ts → prompt-builder.ts} +21 -22
- package/packages/core/src/{harness → agent}/proof-packet.ts +16 -21
- package/packages/core/src/agent/providers/index.ts +35 -16
- package/packages/core/src/agent/reflector.ts +320 -0
- package/packages/core/src/agent/routing-intent.ts +22 -0
- package/packages/core/src/{harness → agent}/run-epoch.ts +4 -3
- package/packages/core/src/{harness → agent}/run-store.ts +142 -81
- package/packages/core/src/agent/{Service.ts → service.ts} +37 -26
- package/packages/core/src/agent/skill-selector.ts +374 -0
- package/packages/core/src/agent/stuck-loop.ts +209 -0
- package/packages/core/src/agent/{selectors/ToolSelector.ts → tool-selector.ts} +188 -178
- package/packages/core/src/{ace/Tracer.ts → agent/tracer.ts} +37 -27
- package/packages/core/src/api/createAgent.test.ts +139 -27
- package/packages/core/src/api/createAgent.ts +232 -44
- package/packages/core/src/artifacts/store.ts +162 -0
- package/packages/core/src/canvas/canvas-manager.ts +161 -0
- package/packages/core/src/canvas/canvas.test.ts +8 -4
- package/packages/core/src/canvas/emitter.ts +131 -80
- package/packages/core/src/canvas/index.ts +1 -3
- package/packages/core/src/channels/base.ts +9 -1
- package/packages/core/src/channels/discord.ts +5 -4
- package/packages/core/src/channels/manager.ts +122 -30
- package/packages/core/src/channels/slack.ts +5 -4
- package/packages/core/src/channels/telegram.ts +36 -6
- package/packages/core/src/channels/webchat.ts +11 -10
- package/packages/core/src/channels/whatsapp.ts +23 -7
- package/packages/core/src/config/index.ts +13 -2
- package/packages/core/src/config/loader.ts +76 -29
- package/packages/core/src/ethics/EthicsGuard.test.ts +90 -36
- package/packages/core/src/ethics/EthicsGuard.ts +51 -47
- package/packages/core/src/events/agent-bus.ts +44 -68
- package/packages/core/src/events/channel-narration.ts +150 -0
- package/packages/core/src/events/narration.ts +82 -0
- package/packages/core/src/events/tool-narration.ts +62 -0
- package/packages/core/src/gateway/delegation-groups.ts +258 -0
- package/packages/core/src/{harness → gateway}/durable-queue.ts +102 -42
- package/packages/core/src/{harness → gateway}/job-store.ts +85 -48
- package/packages/core/src/gateway/lane-queue.ts +173 -0
- package/packages/core/src/gateway/notification-inbox.ts +57 -0
- package/packages/core/src/gateway/server.ts +1 -1
- package/packages/core/src/harness/index.ts +46 -27
- package/packages/core/src/index.ts +33 -27
- package/packages/core/src/mcp/hot-reload.ts +32 -23
- package/packages/core/src/mcp/index.ts +6 -3
- package/packages/core/src/mcp/singleton.ts +1 -4
- package/packages/core/src/mcp/tool-sync.ts +138 -0
- package/packages/core/src/memory/Scratchpad.test.ts +39 -20
- package/packages/core/src/memory/Scratchpad.ts +27 -34
- package/packages/core/src/multimodal/vision-service.ts +44 -38
- package/packages/core/src/resilience/retry.ts +95 -0
- package/packages/core/src/scheduler/CronScheduler.ts +334 -287
- package/packages/core/src/scheduler/index.ts +9 -7
- package/packages/core/src/scheduler/integration.ts +46 -26
- package/packages/core/src/scheduler/scheduler.test.ts +9 -13
- package/packages/core/src/scheduler/types.ts +7 -2
- package/packages/core/src/security/Pairing.ts +1 -1
- package/packages/core/src/skills/bundled/a2ui/a2ui_dashboard/SKILL.md +176 -0
- package/packages/core/src/skills/bundled/a2ui/a2ui_form/SKILL.md +202 -0
- package/packages/core/src/skills/bundled/a2ui/a2ui_interactive/SKILL.md +206 -0
- package/packages/core/src/skills/bundled/agents/agent_spawner/SKILL.md +173 -0
- package/packages/core/src/skills/bundled/agents/memory_manager/SKILL.md +143 -0
- package/packages/core/src/skills/bundled/agents/research_and_remember/SKILL.md +139 -0
- package/packages/core/src/skills/bundled/agents/task_orchestrator/SKILL.md +98 -0
- package/packages/core/src/skills/bundled/api/api_client/SKILL.md +132 -0
- package/packages/core/src/skills/bundled/cli/cli_pipeline/SKILL.md +135 -0
- package/packages/core/src/skills/bundled/cli/cli_safe_exec/SKILL.md +125 -0
- package/packages/core/src/skills/bundled/cli/software_engineering/SKILL.md +23 -0
- package/packages/core/src/skills/bundled/cron_manager/SKILL.md +188 -0
- package/packages/core/src/skills/bundled/cron_reminder/SKILL.md +112 -0
- package/packages/core/src/skills/bundled/filesystem/file_manager/SKILL.md +118 -0
- package/packages/core/src/skills/bundled/filesystem/file_read_and_summarize/SKILL.md +109 -0
- package/packages/core/src/skills/bundled/filesystem/file_writer/SKILL.md +129 -0
- package/packages/core/src/skills/bundled/filesystem/workspace_file_operator/SKILL.md +22 -0
- package/packages/core/src/skills/bundled/office/office_document_manager/SKILL.md +262 -0
- package/packages/core/src/skills/bundled/search_knowledge/capability_discovery/SKILL.md +75 -0
- package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +120 -0
- package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +109 -0
- package/packages/core/src/skills/bundled/web/web_monitor/SKILL.md +127 -0
- package/packages/core/src/skills/bundled/web/web_research/SKILL.md +119 -0
- package/packages/core/src/skills/bundled-data.generated.ts +731 -2678
- package/packages/core/src/skills/skills.test.ts +52 -11
- package/packages/core/src/{harness → storage}/boot-id.ts +5 -2
- package/packages/core/src/storage/bootstrap.ts +151 -0
- package/packages/core/src/storage/causal-events.ts +84 -0
- package/packages/core/src/storage/collections.ts +680 -0
- package/packages/core/src/storage/crypto.ts +205 -74
- package/packages/core/src/{harness/db-helpers.ts → storage/hive.ts} +63 -7
- package/packages/core/src/storage/hivedb.ts +61 -0
- package/packages/core/src/storage/index.ts +111 -18
- package/packages/core/src/storage/model-id.ts +53 -0
- package/packages/core/src/storage/onboarding.ts +540 -972
- package/packages/core/src/storage/reconcile.ts +238 -0
- package/packages/core/src/storage/seed.ts +572 -406
- package/packages/core/src/storage/usage.ts +285 -225
- package/packages/core/src/storage/user-email.ts +11 -0
- package/packages/core/src/swarm/AgentExecutor.ts +1 -1
- package/packages/core/src/swarm/EventBridge.ts +1 -1
- package/packages/core/src/swarm/index.ts +12 -9
- package/packages/core/src/tool-runtime/index.ts +146 -23
- package/packages/core/src/tool-runtime/tool-worker.ts +2 -2
- package/packages/core/src/tool-runtime/worker-tools.ts +27 -0
- package/packages/core/src/{canvas/a2ui-tools.ts → tools/a2ui/index.ts} +17 -8
- package/packages/core/src/tools/agents/get-available-models.ts +36 -54
- package/packages/core/src/tools/agents/index.ts +784 -292
- package/packages/core/src/tools/api/api-request.test.ts +164 -0
- package/packages/core/src/tools/api/api-request.ts +174 -0
- package/packages/core/src/tools/api/index.ts +16 -0
- package/packages/core/src/tools/cli/index.ts +4 -0
- package/packages/core/src/tools/core/index.ts +281 -112
- package/packages/core/src/tools/cron/index.ts +121 -124
- package/packages/core/src/tools/index.ts +63 -78
- package/packages/core/src/tools/office/office-escribir-xlsx.ts +3 -1
- package/packages/core/src/tools/types.ts +3 -1
- package/packages/core/src/tools/web/artifact-inspect.ts +23 -0
- package/packages/core/src/tools/web/browser-backend.ts +129 -0
- package/packages/core/src/tools/web/browser-screenshot.ts +26 -5
- package/packages/core/src/tools/web/browser-service.ts +80 -35
- package/packages/core/src/tools/web/browser-type.ts +3 -8
- package/packages/core/src/tools/web/index.ts +4 -4
- package/packages/core/src/tools/web/webview-backend.ts +412 -0
- package/packages/core/src/voice/index.ts +89 -63
- package/packages/core/src/workers/agent.worker.ts +2 -2
- package/packages/core/src/workers/workers.test.ts +3 -10
- package/scripts/bump-version.ts +248 -0
- package/scripts/generate-skill-bundle.ts +108 -0
- package/test/acceptance-checks.test.ts +403 -0
- package/test/agent-loop-terminal-synthesis.test.ts +32 -0
- package/test/browser-backend.test.ts +308 -0
- package/test/catalog-agents-stay-enabled.test.ts +117 -0
- package/test/causal-events.test.ts +117 -0
- package/test/compaction.test.ts +105 -0
- package/test/context-compiler.test.ts +269 -0
- package/test/curator.test.ts +130 -0
- package/test/durable-queue.test.ts +114 -0
- package/test/harness-barrel.test.ts +64 -0
- package/test/hive-helpers.test.ts +130 -0
- package/test/hivedb-search.test.ts +189 -0
- package/test/internal-turns.test.ts +166 -0
- package/test/job-idempotency.test.ts +68 -0
- package/test/job-retry-backoff.test.ts +184 -0
- package/test/job-store.test.ts +381 -0
- package/test/llm-retry.test.ts +97 -0
- package/test/memory-perf.test.ts +774 -0
- package/test/minimal-loadout.test.ts +78 -0
- package/test/model-catalog.test.ts +105 -0
- package/test/preload.ts +12 -0
- package/test/reflector.test.ts +320 -0
- package/test/retention-cap.test.ts +91 -0
- package/test/retired-capabilities-pruned.test.ts +192 -0
- package/test/run-store.test.ts +355 -0
- package/test/scratchpad.test.ts +74 -0
- package/test/secrets-durability.test.ts +119 -0
- package/test/seed-model-reseed.test.ts +155 -0
- package/test/setup-agent-seed.test.ts +264 -0
- package/test/tool-inventory.test.ts +65 -0
- package/test/tool-runtime.test.ts +258 -0
- package/test/tool-selector-runtime-tools.test.ts +117 -0
- package/test/toon.test.ts +429 -0
- package/tsconfig.json +2 -0
- package/packages/core/src/ace/Curator.ts +0 -158
- package/packages/core/src/ace/Reflector.ts +0 -200
- package/packages/core/src/ace/index.ts +0 -4
- package/packages/core/src/agent/AgentRunner.ts +0 -711
- package/packages/core/src/agent/ContextCompiler.ts +0 -567
- package/packages/core/src/agent/ContextGuard.ts +0 -91
- package/packages/core/src/agent/ConversationStore.ts +0 -254
- package/packages/core/src/agent/Hooks.ts +0 -166
- package/packages/core/src/agent/StuckLoop.ts +0 -133
- package/packages/core/src/agent/providers/LLMClient.ts +0 -149
- package/packages/core/src/agent/providers/anthropic.ts +0 -212
- package/packages/core/src/agent/providers/openai-compat.ts +0 -231
- package/packages/core/src/agent/selectors/PlaybookSelector.ts +0 -121
- package/packages/core/src/agent/selectors/SkillSelector.ts +0 -322
- package/packages/core/src/agent/selectors/index.ts +0 -6
- package/packages/core/src/auth/auth.ts +0 -121
- package/packages/core/src/auth/index.ts +0 -1
- package/packages/core/src/canvas/CanvasManager.ts +0 -390
- package/packages/core/src/canvas/canvas-tools.ts +0 -448
- package/packages/core/src/harness/collections.ts +0 -98
- package/packages/core/src/harness/goal-verifier.ts +0 -141
- package/packages/core/src/harness/harness.test.ts +0 -236
- package/packages/core/src/harness/reconcile.ts +0 -149
- package/packages/core/src/mcp/MCPToolAdapter.ts +0 -176
- package/packages/core/src/multimodal/VisionService.ts +0 -293
- package/packages/core/src/scheduler/dag/AgentExecutor.ts +0 -53
- package/packages/core/src/scheduler/dag/DAGScheduler.ts +0 -250
- package/packages/core/src/scheduler/dag/EventBridge.ts +0 -122
- package/packages/core/src/scheduler/dag/TaskGraph.ts +0 -192
- package/packages/core/src/scheduler/dag/TaskNode.ts +0 -97
- package/packages/core/src/scheduler/dag/TaskResult.ts +0 -22
- package/packages/core/src/scheduler/dag/errors.ts +0 -37
- package/packages/core/src/scheduler/dag/index.ts +0 -26
- package/packages/core/src/scheduler/dag/presets/ResearchPreset.ts +0 -97
- package/packages/core/src/scheduler/dag/strategies/ParallelStrategy.ts +0 -21
- package/packages/core/src/scheduler/dag/strategies/PriorityStrategy.ts +0 -46
- package/packages/core/src/storage/HiveDBStorage.ts +0 -64
- package/packages/core/src/storage/SQLiteStorage.ts +0 -414
- package/packages/core/src/storage/hiveSeed.ts +0 -308
- package/packages/core/src/storage/hiveStorage.test.ts +0 -38
- package/packages/core/src/storage/schema.ts +0 -689
- package/packages/core/src/storage/storage.test.ts +0 -37
- package/packages/core/src/swarm/AgentBus.ts +0 -460
- package/packages/core/src/swarm/EventBus.ts +0 -169
- package/packages/core/src/swarm/WorkerPool.ts +0 -236
- package/packages/core/src/tools/bridge-events.ts +0 -26
- package/packages/core/src/tools/canvas/index.ts +0 -375
- package/packages/core/src/tools/codebridge/index.ts +0 -342
- package/packages/core/src/tools/meeting/index.ts +0 -353
- package/packages/core/src/tools/projects/index.ts +0 -37
- package/packages/core/src/tools/projects/project-create.ts +0 -94
- package/packages/core/src/tools/projects/project-done.ts +0 -66
- package/packages/core/src/tools/projects/project-fail.ts +0 -66
- package/packages/core/src/tools/projects/project-list.ts +0 -96
- package/packages/core/src/tools/projects/project-update.ts +0 -72
- package/packages/core/src/tools/projects/task-create.ts +0 -68
- package/packages/core/src/tools/projects/task-evaluate.ts +0 -93
- package/packages/core/src/tools/projects/task-update.ts +0 -93
- package/packages/core/src/tools/voice/index.ts +0 -104
- package/packages/core/src/tools/web/api-request.test.ts +0 -170
- package/packages/core/src/tools/web/api-request.ts +0 -239
- package/test/setup-db.ts +0 -216
- /package/packages/core/src/agent/{NativeTools.ts → native-tools.ts} +0 -0
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tracer — ACE Generator output.
|
|
3
3
|
*
|
|
4
|
-
* Records every agent execution to the `traces`
|
|
5
|
-
* Fire-and-forget (non-blocking). Also updates
|
|
6
|
-
*
|
|
4
|
+
* Records every agent execution to the `traces` collection.
|
|
5
|
+
* Fire-and-forget (non-blocking). Also updates the denormalized
|
|
6
|
+
* `agents.lastTraceAt` field used by the Curator's stale-worker detection.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { logger } from "../utils/logger
|
|
9
|
+
import { logger } from "../utils/logger"
|
|
10
|
+
import { col, nextId, updateDoc } from "../storage/hive"
|
|
11
|
+
import type { TraceDoc, AgentDoc } from "../storage/collections"
|
|
10
12
|
|
|
11
13
|
const log = logger.child("tracer")
|
|
12
14
|
|
|
@@ -21,6 +23,9 @@ export interface TraceInput {
|
|
|
21
23
|
errorMessage?: string | null
|
|
22
24
|
durationMs?: number
|
|
23
25
|
tokensUsed?: number
|
|
26
|
+
/** G9 causal stream id for this run, when the causal log is enabled. */
|
|
27
|
+
causalStreamId?: string | null
|
|
28
|
+
catalogAgentId?: string | null
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
/**
|
|
@@ -31,27 +36,32 @@ export function saveTrace(trace: TraceInput): void {
|
|
|
31
36
|
// Run asynchronously so it never blocks the caller
|
|
32
37
|
Promise.resolve().then(async () => {
|
|
33
38
|
try {
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
trace.
|
|
44
|
-
trace.
|
|
45
|
-
trace.
|
|
46
|
-
trace.
|
|
47
|
-
trace.
|
|
48
|
-
trace.
|
|
49
|
-
trace.
|
|
50
|
-
trace.
|
|
51
|
-
trace.
|
|
52
|
-
|
|
53
|
-
|
|
39
|
+
const tracesCol = await col<TraceDoc>("traces")
|
|
40
|
+
const id = await nextId("traces")
|
|
41
|
+
const now = Date.now()
|
|
42
|
+
const agentsCol = await col<AgentDoc>("agents")
|
|
43
|
+
const agentEntry = await agentsCol.get(trace.agentId)
|
|
44
|
+
const catalogAgentId = trace.catalogAgentId ?? (agentEntry?.doc.source === "catalog" ? agentEntry.doc.id : null)
|
|
45
|
+
await tracesCol.put(id, {
|
|
46
|
+
id,
|
|
47
|
+
thread_id: trace.threadId,
|
|
48
|
+
agent_id: trace.agentId,
|
|
49
|
+
agent_name: trace.agentName,
|
|
50
|
+
tool_used: trace.toolUsed ?? null,
|
|
51
|
+
input_summary: trace.inputSummary.substring(0, 500),
|
|
52
|
+
output_summary: trace.outputSummary.substring(0, 500),
|
|
53
|
+
success: trace.success,
|
|
54
|
+
error_message: trace.errorMessage ?? null,
|
|
55
|
+
duration_ms: trace.durationMs ?? null,
|
|
56
|
+
tokens_used: trace.tokensUsed ?? null,
|
|
57
|
+
created_at: now,
|
|
58
|
+
causal_stream_id: trace.causalStreamId ?? null,
|
|
59
|
+
catalog_agent_id: catalogAgentId ?? undefined,
|
|
60
|
+
})
|
|
54
61
|
|
|
62
|
+
// Denormalized field the Curator scans for stale-worker detection,
|
|
63
|
+
// avoiding a correlated MAX(created_at) query HiveDB has no primitive for.
|
|
64
|
+
await updateDoc<AgentDoc>("agents", trace.agentId, { lastTraceAt: now }).catch(() => { /* agent may not exist */ })
|
|
55
65
|
// Trigger reflector check in background
|
|
56
66
|
checkReflectorTrigger().catch(() => { /* ignore */ })
|
|
57
67
|
} catch (err) {
|
|
@@ -72,7 +82,7 @@ async function checkReflectorTrigger(): Promise<void> {
|
|
|
72
82
|
_tracesSinceLastReflection = 0
|
|
73
83
|
|
|
74
84
|
// Lazy import to avoid circular deps
|
|
75
|
-
const { runReflector } = await import("./
|
|
85
|
+
const { runReflector } = await import("./reflector")
|
|
76
86
|
runReflector().catch((err) => {
|
|
77
87
|
log.warn("[tracer] Reflector run failed:", err)
|
|
78
88
|
})
|
|
@@ -88,8 +98,8 @@ export function recordLLMUsage(opts: {
|
|
|
88
98
|
}): void {
|
|
89
99
|
Promise.resolve().then(async () => {
|
|
90
100
|
try {
|
|
91
|
-
const { recordUsage } = await import("../storage/usage
|
|
92
|
-
|
|
101
|
+
const { recordUsage } = await import("../storage/usage")
|
|
102
|
+
recordUsage({
|
|
93
103
|
provider: opts.provider,
|
|
94
104
|
model: opts.model,
|
|
95
105
|
inputTokens: opts.inputTokens,
|
|
@@ -1,19 +1,148 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `createAgent` persiste su configuración en la fila del agente.
|
|
3
|
+
*
|
|
4
|
+
* Hasta 0.1.5 aceptaba `provider`, `model`, `maxIterations`, `workspace` y
|
|
5
|
+
* `systemPrompt` y los descartaba: construía el loop global y corría con lo que
|
|
6
|
+
* hubiera en la base. Estos tests fijan que ahora sí lleguen.
|
|
7
|
+
*/
|
|
3
8
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
process.env.HIVE_DB_PATH = ":memory:";
|
|
10
|
+
|
|
11
|
+
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import { closeHiveDb } from "../storage/hivedb.ts";
|
|
14
|
+
import { ensureHiveDb } from "../storage/bootstrap.ts";
|
|
15
|
+
import { col, fromIndexable } from "../storage/hive.ts";
|
|
16
|
+
import { clearAppTools, createAllTools } from "../tools/index.ts";
|
|
17
|
+
import { selectTools } from "../agent/tool-selector.ts";
|
|
18
|
+
import { loadConfig } from "../config/loader.ts";
|
|
19
|
+
import type { AgentDoc, ModelDoc } from "../storage/collections.ts";
|
|
20
|
+
import { createAgent } from "./createAgent.ts";
|
|
21
|
+
import { defineTool } from "../tools/ToolRegistry.ts";
|
|
22
|
+
import { defineSkill } from "../skills/defineSkill.ts";
|
|
23
|
+
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
closeHiveDb();
|
|
26
|
+
clearAppTools();
|
|
27
|
+
await ensureHiveDb();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
clearAppTools();
|
|
32
|
+
closeHiveDb();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe("createAgent", () => {
|
|
36
|
+
it("persiste provider, modelo, prompt e iteraciones en la fila del agente", async () => {
|
|
37
|
+
const agent = await createAgent({
|
|
38
|
+
name: "Test Agent",
|
|
39
|
+
provider: "anthropic",
|
|
40
|
+
model: "claude-opus-5",
|
|
41
|
+
systemPrompt: "Sos un asistente de prueba.",
|
|
42
|
+
maxIterations: 7,
|
|
43
|
+
workspace: "/tmp/ws",
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
expect(agent.name).toBe("Test Agent");
|
|
47
|
+
expect(agent.id).toBe("test_agent");
|
|
48
|
+
|
|
49
|
+
const agentsCol = await col<AgentDoc>("agents");
|
|
50
|
+
const row = (await agentsCol.get("test_agent"))!.doc;
|
|
51
|
+
|
|
52
|
+
expect(fromIndexable(row.provider_id)).toBe("anthropic");
|
|
53
|
+
expect(fromIndexable(row.model_id)).toBe("claude-opus-5");
|
|
54
|
+
expect(row.system_prompt).toBe("Sos un asistente de prueba.");
|
|
55
|
+
expect(row.max_iterations).toBe(7);
|
|
56
|
+
expect(row.workspace).toBe("/tmp/ws");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("prefija el id del modelo cuando el provider es revendedor", async () => {
|
|
60
|
+
await createAgent({
|
|
61
|
+
name: "reseller",
|
|
62
|
+
provider: "modelscope",
|
|
63
|
+
model: "Qwen-Ambassador/Qwen3.8-Max",
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const agentsCol = await col<AgentDoc>("agents");
|
|
67
|
+
const row = (await agentsCol.get("reseller"))!.doc;
|
|
68
|
+
|
|
69
|
+
expect(fromIndexable(row.model_id)).toBe("modelscope/Qwen-Ambassador/Qwen3.8-Max");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("activa el modelo elegido, o resolveProviderConfig no encuentra su base_url", async () => {
|
|
73
|
+
await createAgent({ name: "activador", provider: "anthropic", model: "claude-opus-5" });
|
|
74
|
+
|
|
75
|
+
const modelsCol = await col<ModelDoc>("models");
|
|
76
|
+
const model = (await modelsCol.get("claude-opus-5"))!.doc;
|
|
77
|
+
|
|
78
|
+
expect(model.active).toBe(true);
|
|
79
|
+
expect(model.enabled).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("rechaza un modelo que no está en el catálogo", async () => {
|
|
83
|
+
await expect(
|
|
84
|
+
createAgent({ name: "fantasma", provider: "anthropic", model: "claude-que-no-existe" })
|
|
85
|
+
).rejects.toThrow(/no está en el catálogo/);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("pide provider cuando se especifica un modelo", async () => {
|
|
89
|
+
// El mismo modelo lo sirven varios providers y la clave del catálogo
|
|
90
|
+
// depende de cuál, así que adivinarlo sería elegir por el usuario.
|
|
91
|
+
await expect(createAgent({ name: "sin-provider", model: "claude-opus-5" })).rejects.toThrow(
|
|
92
|
+
/necesita también `provider`/
|
|
93
|
+
);
|
|
7
94
|
});
|
|
8
95
|
|
|
9
|
-
|
|
10
|
-
|
|
96
|
+
it("registra las tools de la app con su ejecutor, no sólo la declaración", async () => {
|
|
97
|
+
const greet = defineTool({
|
|
98
|
+
name: "greet_person",
|
|
99
|
+
description: "Saluda a alguien",
|
|
100
|
+
schema: z.object({ name: z.string().describe("a quién saludar") }),
|
|
101
|
+
execute: async (args: { name: string }) => `Hola ${args.name}`,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await createAgent({ name: "con-tools", tools: [greet] });
|
|
105
|
+
|
|
106
|
+
const registered = createAllTools(await loadConfig()).find((t) => t.name === "greet_person");
|
|
107
|
+
expect(registered, "la tool no llegó al registry que lee el context compiler").toBeDefined();
|
|
108
|
+
expect(registered!.parameters.properties).toHaveProperty("name");
|
|
109
|
+
expect(registered!.parameters.required).toEqual(["name"]);
|
|
110
|
+
expect(await registered!.execute({ name: "Ana" })).toBe("Hola Ana");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("deja la tool de la app descubrible por búsqueda de capacidad", async () => {
|
|
114
|
+
// El loadout inicial es mínimo a propósito; el resto se encuentra vía
|
|
115
|
+
// `search_knowledge`, que corre sobre el índice BM25. Si createAgent no
|
|
116
|
+
// siembra la fila en `tools` y no reindexa, la tool tiene ejecutor pero el
|
|
117
|
+
// modelo no se entera de que existe.
|
|
118
|
+
const weather = defineTool({
|
|
119
|
+
name: "get_weather",
|
|
120
|
+
description: "Consulta el clima actual de una ciudad. Sinónimos: tiempo, temperatura, pronóstico",
|
|
121
|
+
schema: z.object({ city: z.string() }),
|
|
122
|
+
execute: async (a: { city: string }) => `Soleado en ${a.city}`,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
await createAgent({ name: "descubrible", tools: [weather] });
|
|
126
|
+
|
|
127
|
+
const found = await selectTools("clima de una ciudad", undefined, 5);
|
|
128
|
+
expect(found.map((t) => t.name)).toContain("get_weather");
|
|
11
129
|
});
|
|
12
130
|
|
|
13
|
-
it("
|
|
14
|
-
const
|
|
15
|
-
const
|
|
131
|
+
it("reusa la fila al recrear un agente con el mismo nombre", async () => {
|
|
132
|
+
const first = await createAgent({ name: "estable", provider: "anthropic", model: "claude-opus-5" });
|
|
133
|
+
const second = await createAgent({ name: "estable", provider: "anthropic", model: "claude-sonnet-5" });
|
|
16
134
|
|
|
135
|
+
expect(second.id).toBe(first.id);
|
|
136
|
+
|
|
137
|
+
const agentsCol = await col<AgentDoc>("agents");
|
|
138
|
+
const all = (await agentsCol.scan({})).filter((e) => e.id === "estable");
|
|
139
|
+
expect(all).toHaveLength(1);
|
|
140
|
+
expect(fromIndexable(all[0].doc.model_id)).toBe("claude-sonnet-5");
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("defineTool / defineSkill", () => {
|
|
145
|
+
it("siguen siendo funciones de declaración puras", () => {
|
|
17
146
|
const tool = defineTool({
|
|
18
147
|
name: "greet",
|
|
19
148
|
description: "Says hello",
|
|
@@ -28,21 +157,4 @@ describe("createAgent API", () => {
|
|
|
28
157
|
});
|
|
29
158
|
expect(skill.name).toBe("greeting-skill");
|
|
30
159
|
});
|
|
31
|
-
|
|
32
|
-
it("createAgent builds an agent instance", async () => {
|
|
33
|
-
const { createAgent } = await import("./createAgent.ts");
|
|
34
|
-
const agent = await createAgent({
|
|
35
|
-
name: "test-agent",
|
|
36
|
-
provider: "openai",
|
|
37
|
-
model: "gpt-4o-mini",
|
|
38
|
-
});
|
|
39
|
-
expect(agent.name).toBe("test-agent");
|
|
40
|
-
expect(agent.config).toBeDefined();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("ToolRegistry can be used standalone", async () => {
|
|
44
|
-
const { ToolRegistry } = await import("../tools/ToolRegistry.ts");
|
|
45
|
-
const reg = new ToolRegistry();
|
|
46
|
-
expect(reg.size()).toBe(0);
|
|
47
|
-
});
|
|
48
160
|
});
|
|
@@ -1,13 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createAgent — la puerta de entrada del SDK.
|
|
3
|
+
*
|
|
4
|
+
* Hasta 0.1.5 esta función aceptaba `provider`, `model`, `maxIterations`,
|
|
5
|
+
* `skills` y `workspace` y los descartaba: construía el agent loop global y
|
|
6
|
+
* corría con lo que hubiera en la base. El agente terminaba respondiendo con un
|
|
7
|
+
* modelo que el llamador nunca eligió. Ahora la config se persiste en la fila
|
|
8
|
+
* del agente, que es de donde el loop resuelve provider y modelo.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { z } from "zod";
|
|
1
12
|
import type { ToolDefinition } from "../tools/ToolRegistry.ts";
|
|
2
13
|
import type { SkillDefinition } from "../skills/defineSkill.ts";
|
|
14
|
+
import type { Tool, ToolParameter } from "../tools/types.ts";
|
|
15
|
+
import type { Provider } from "../agent/providers/index.ts";
|
|
3
16
|
import { logger } from "../utils/logger.ts";
|
|
4
17
|
|
|
5
18
|
const log = logger.child("api");
|
|
6
19
|
|
|
7
20
|
export interface AgentConfig {
|
|
8
21
|
name: string;
|
|
22
|
+
/** Id del modelo tal como lo nombra su dueño (ej. "claude-opus-5", "Qwen-Ambassador/Qwen3.8-Max"). */
|
|
9
23
|
model?: string;
|
|
10
|
-
|
|
24
|
+
/** Cualquiera de los 16 providers del catálogo. */
|
|
25
|
+
provider?: Provider;
|
|
11
26
|
systemPrompt?: string;
|
|
12
27
|
tools?: ToolDefinition[];
|
|
13
28
|
skills?: SkillDefinition[];
|
|
@@ -18,6 +33,7 @@ export interface AgentConfig {
|
|
|
18
33
|
|
|
19
34
|
export interface Agent {
|
|
20
35
|
readonly name: string;
|
|
36
|
+
readonly id: string;
|
|
21
37
|
readonly config: AgentConfig;
|
|
22
38
|
chat(message: string, opts?: { threadId?: string; channel?: string }): AsyncGenerator<AgentEvent>;
|
|
23
39
|
run(task: string, opts?: { threadId?: string; channel?: string }): Promise<string>;
|
|
@@ -29,16 +45,54 @@ export type AgentEvent =
|
|
|
29
45
|
| { type: "tool_result"; name: string; result: unknown }
|
|
30
46
|
| { type: "done"; response: string };
|
|
31
47
|
|
|
48
|
+
/** Id estable derivado del nombre, para que dos `createAgent` con el mismo nombre compartan historial. */
|
|
49
|
+
function agentIdFrom(name: string): string {
|
|
50
|
+
const slug = name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
51
|
+
return slug || "agent";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Convierte una tool declarada con `defineTool` (schema de Zod) al shape que
|
|
56
|
+
* espera el runtime (JSON Schema). Sin `schema` queda sin parámetros.
|
|
57
|
+
*/
|
|
58
|
+
function toRuntimeTool(def: ToolDefinition): Tool {
|
|
59
|
+
let properties: Record<string, ToolParameter> = {};
|
|
60
|
+
let required: string[] = [];
|
|
61
|
+
|
|
62
|
+
if (def.schema) {
|
|
63
|
+
const json = z.toJSONSchema(def.schema) as {
|
|
64
|
+
properties?: Record<string, ToolParameter>;
|
|
65
|
+
required?: string[];
|
|
66
|
+
};
|
|
67
|
+
properties = json.properties ?? {};
|
|
68
|
+
required = json.required ?? [];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
name: def.name,
|
|
73
|
+
description: def.description,
|
|
74
|
+
parameters: { type: "object", properties, required },
|
|
75
|
+
execute: async (params, config) => def.execute(params, config),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
32
79
|
export async function createAgent(config: AgentConfig): Promise<Agent> {
|
|
33
|
-
const {
|
|
34
|
-
const {
|
|
80
|
+
const { ensureHiveDb } = await import("../storage/bootstrap.ts");
|
|
81
|
+
const { col, toIndexable } = await import("../storage/hive.ts");
|
|
82
|
+
const { catalogModelKey } = await import("../storage/model-id.ts");
|
|
83
|
+
const { registerAppTool } = await import("../tools/index.ts");
|
|
35
84
|
const { loadConfig } = await import("../config/loader.ts");
|
|
85
|
+
const { resolveUserId } = await import("../storage/onboarding.ts");
|
|
86
|
+
type AgentDoc = import("../storage/collections.ts").AgentDoc;
|
|
87
|
+
type ModelDoc = import("../storage/collections.ts").ModelDoc;
|
|
88
|
+
type ProviderDoc = import("../storage/collections.ts").ProviderDoc;
|
|
36
89
|
|
|
37
|
-
|
|
90
|
+
// Abre HiveDB, crea los índices y siembra el catálogo de providers/modelos.
|
|
91
|
+
await ensureHiveDb();
|
|
38
92
|
|
|
39
93
|
const coreConfig = await loadConfig();
|
|
40
94
|
|
|
41
|
-
//
|
|
95
|
+
// Browser automation (agent-browser) si está habilitado.
|
|
42
96
|
try {
|
|
43
97
|
const { initializeBrowserService } = await import("../tools/web/browser-service.ts");
|
|
44
98
|
const browserService = initializeBrowserService(coreConfig);
|
|
@@ -47,16 +101,114 @@ export async function createAgent(config: AgentConfig): Promise<Agent> {
|
|
|
47
101
|
log.warn(`Browser service initialization skipped: ${(err as Error).message}`);
|
|
48
102
|
}
|
|
49
103
|
|
|
50
|
-
|
|
104
|
+
// Las tools de la app necesitan dos cosas para ser usables, y hasta 0.1.5 no
|
|
105
|
+
// tenían ninguna:
|
|
106
|
+
// 1. un ejecutor en el registry que arma el context compiler, y
|
|
107
|
+
// 2. una fila en la colección `tools`, que es sobre la que corre la
|
|
108
|
+
// búsqueda por capacidad.
|
|
109
|
+
// Sin (2) la tool existe pero el modelo no la descubre nunca: el loadout
|
|
110
|
+
// inicial es mínimo a propósito y el resto se encuentra vía `search_knowledge`.
|
|
111
|
+
if (config.tools?.length) {
|
|
112
|
+
type ToolDoc = import("../storage/collections.ts").ToolDoc;
|
|
113
|
+
const toolsCol = await col<ToolDoc>("tools");
|
|
114
|
+
const ts = Date.now();
|
|
115
|
+
|
|
116
|
+
for (const tool of config.tools) {
|
|
117
|
+
registerAppTool(toRuntimeTool(tool));
|
|
118
|
+
await toolsCol.put(tool.name, {
|
|
119
|
+
id: tool.name,
|
|
120
|
+
name: tool.name,
|
|
121
|
+
description: tool.description,
|
|
122
|
+
category: tool.category ?? "app",
|
|
123
|
+
enabled: true,
|
|
124
|
+
active: true,
|
|
125
|
+
created_at: ts,
|
|
126
|
+
updated_at: ts,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ─── Provider y modelo ────────────────────────────────────────────────────
|
|
132
|
+
// El loop los lee de la fila del agente, así que hay que dejarlos escritos.
|
|
133
|
+
const providerId = config.provider ?? "";
|
|
134
|
+
let modelKey = "";
|
|
135
|
+
|
|
136
|
+
if (config.model) {
|
|
137
|
+
if (!providerId) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
`createAgent({ model: "${config.model}" }) necesita también \`provider\`: el mismo modelo lo sirven varios providers y la clave del catálogo depende de cuál.`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
modelKey = catalogModelKey(providerId, config.model);
|
|
143
|
+
|
|
144
|
+
const modelsCol = await col<ModelDoc>("models");
|
|
145
|
+
const modelEntry = await modelsCol.get(modelKey);
|
|
146
|
+
if (!modelEntry) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`El modelo "${config.model}" no está en el catálogo de ${providerId}. `
|
|
149
|
+
+ `Agregalo a SEED_DATA.models o elegí uno de los sembrados.`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
// Activarlo, o `resolveProviderConfig` no encuentra base_url ni la key.
|
|
153
|
+
await modelsCol.put(
|
|
154
|
+
modelKey,
|
|
155
|
+
{ ...modelEntry.doc, enabled: true, active: true },
|
|
156
|
+
{ expectedVersion: modelEntry.version }
|
|
157
|
+
);
|
|
51
158
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
159
|
+
const providersCol = await col<ProviderDoc>("providers");
|
|
160
|
+
const providerEntry = await providersCol.get(providerId);
|
|
161
|
+
if (providerEntry) {
|
|
162
|
+
await providersCol.put(
|
|
163
|
+
providerId,
|
|
164
|
+
{ ...providerEntry.doc, enabled: true, active: true },
|
|
165
|
+
{ expectedVersion: providerEntry.version }
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
57
169
|
|
|
58
|
-
|
|
170
|
+
// ─── Fila del agente ──────────────────────────────────────────────────────
|
|
171
|
+
const agentId = agentIdFrom(config.name);
|
|
172
|
+
const agentsCol = await col<AgentDoc>("agents");
|
|
173
|
+
const existing = await agentsCol.get(agentId);
|
|
174
|
+
const now = Date.now();
|
|
175
|
+
const userId = (await resolveUserId({})) || "default";
|
|
59
176
|
|
|
177
|
+
await agentsCol.put(
|
|
178
|
+
agentId,
|
|
179
|
+
{
|
|
180
|
+
...(existing?.doc ?? {}),
|
|
181
|
+
id: agentId,
|
|
182
|
+
user_id: existing?.doc.user_id ?? userId,
|
|
183
|
+
name: config.name,
|
|
184
|
+
description: existing?.doc.description ?? null,
|
|
185
|
+
system_prompt: config.systemPrompt ?? existing?.doc.system_prompt ?? null,
|
|
186
|
+
tone: existing?.doc.tone ?? null,
|
|
187
|
+
role: existing?.doc.role ?? "coordinator",
|
|
188
|
+
status: "idle",
|
|
189
|
+
enabled: true,
|
|
190
|
+
provider_id: toIndexable(providerId || null),
|
|
191
|
+
model_id: toIndexable(modelKey || null),
|
|
192
|
+
tools_json: existing?.doc.tools_json ?? null,
|
|
193
|
+
skills_json: existing?.doc.skills_json ?? null,
|
|
194
|
+
parent_id: toIndexable(null),
|
|
195
|
+
max_iterations: config.maxIterations ?? existing?.doc.max_iterations ?? 25,
|
|
196
|
+
workspace: config.workspace ?? existing?.doc.workspace ?? null,
|
|
197
|
+
lastTraceAt: existing?.doc.lastTraceAt ?? null,
|
|
198
|
+
created_at: existing?.doc.created_at ?? now,
|
|
199
|
+
updated_at: now,
|
|
200
|
+
} as AgentDoc,
|
|
201
|
+
existing ? { expectedVersion: existing.version } : undefined
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
// ─── Índice de capacidades ────────────────────────────────────────────────
|
|
205
|
+
// Sin esto el agente queda limitado al loadout mínimo para siempre: el resto
|
|
206
|
+
// de las tools y skills se descubren con `search_knowledge`, que corre sobre
|
|
207
|
+
// el índice BM25, y ese índice no se llena solo. En hive lo hace
|
|
208
|
+
// `gateway/initializer.ts` al arrancar; por la vía del SDK nadie lo llamaba.
|
|
209
|
+
await syncCapabilityIndexes();
|
|
210
|
+
|
|
211
|
+
// ─── MCP ──────────────────────────────────────────────────────────────────
|
|
60
212
|
let mcpManager = null;
|
|
61
213
|
if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
|
|
62
214
|
const { MCPClientManager } = await import("../mcp/index.ts");
|
|
@@ -79,54 +231,90 @@ export async function createAgent(config: AgentConfig): Promise<Agent> {
|
|
|
79
231
|
await mcpManager.initialize();
|
|
80
232
|
}
|
|
81
233
|
|
|
82
|
-
const
|
|
83
|
-
const { buildAgentLoop } = await import("../agent/AgentRunner.ts");
|
|
84
|
-
const agentLoop = buildAgentLoop({ mcpManager });
|
|
85
|
-
return agentLoop;
|
|
86
|
-
})();
|
|
234
|
+
const { runAgent } = await import("../agent/agent-loop.ts");
|
|
87
235
|
|
|
88
236
|
return {
|
|
89
237
|
name: config.name,
|
|
238
|
+
id: agentId,
|
|
90
239
|
config,
|
|
91
240
|
async *chat(message, opts) {
|
|
92
241
|
const threadId = opts?.threadId ?? crypto.randomUUID();
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
yield { type: "text" as const, content: msg.content };
|
|
108
|
-
}
|
|
109
|
-
if (msg.tool_calls) {
|
|
110
|
-
for (const tc of msg.tool_calls) {
|
|
111
|
-
yield { type: "tool_call" as const, name: tc.function?.name ?? tc.name ?? "unknown", args: typeof tc.function?.arguments === "string" ? JSON.parse(tc.function.arguments) : tc.function?.arguments ?? {} };
|
|
112
|
-
}
|
|
113
|
-
}
|
|
242
|
+
let response = "";
|
|
243
|
+
|
|
244
|
+
for await (const chunk of runAgent({
|
|
245
|
+
agentId,
|
|
246
|
+
userMessage: message,
|
|
247
|
+
threadId,
|
|
248
|
+
channel: opts?.channel ?? "cli",
|
|
249
|
+
mcpManager,
|
|
250
|
+
userId,
|
|
251
|
+
})) {
|
|
252
|
+
for (const msg of chunk.agent?.messages ?? []) {
|
|
253
|
+
if (typeof msg.content === "string" && msg.content) {
|
|
254
|
+
response = msg.content;
|
|
255
|
+
yield { type: "text" as const, content: msg.content };
|
|
114
256
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
257
|
+
for (const tc of msg.tool_calls ?? []) {
|
|
258
|
+
const raw = tc.function?.arguments;
|
|
259
|
+
yield {
|
|
260
|
+
type: "tool_call" as const,
|
|
261
|
+
name: tc.function?.name ?? "unknown",
|
|
262
|
+
args: typeof raw === "string" ? safeParse(raw) : (raw ?? {}),
|
|
263
|
+
};
|
|
119
264
|
}
|
|
120
265
|
}
|
|
266
|
+
for (const msg of chunk.tools?.messages ?? []) {
|
|
267
|
+
yield { type: "tool_result" as const, name: msg.name ?? "unknown", result: msg.content };
|
|
268
|
+
}
|
|
121
269
|
}
|
|
122
|
-
|
|
270
|
+
|
|
271
|
+
yield { type: "done" as const, response };
|
|
123
272
|
},
|
|
124
273
|
async run(task, opts) {
|
|
274
|
+
// El loop emite el texto acumulado del turno, no deltas: quedarse con el
|
|
275
|
+
// último evento evita duplicar la respuesta al concatenar.
|
|
125
276
|
let response = "";
|
|
126
277
|
for await (const event of this.chat(task, opts)) {
|
|
127
|
-
if (event.type === "text") response
|
|
278
|
+
if (event.type === "text") response = event.content;
|
|
279
|
+
if (event.type === "done" && event.response) response = event.response;
|
|
128
280
|
}
|
|
129
281
|
return response;
|
|
130
282
|
},
|
|
131
283
|
};
|
|
132
284
|
}
|
|
285
|
+
|
|
286
|
+
function safeParse(raw: string): Record<string, unknown> {
|
|
287
|
+
try {
|
|
288
|
+
return JSON.parse(raw);
|
|
289
|
+
} catch {
|
|
290
|
+
return {};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Llena el índice BM25 de capacidades (tools, skills, reglas de playbook,
|
|
296
|
+
* agentes del catálogo) sobre el que corre `search_knowledge`.
|
|
297
|
+
*
|
|
298
|
+
* Es el equivalente de lo que hace `gateway/initializer.ts` en hive al arrancar.
|
|
299
|
+
* Los errores no se propagan: sin índice el agente sigue funcionando con el
|
|
300
|
+
* loadout mínimo, y romper `createAgent` por una reindexación sería peor.
|
|
301
|
+
*/
|
|
302
|
+
export async function syncCapabilityIndexes(): Promise<void> {
|
|
303
|
+
const { syncToolsToIndex, syncSkillsToIndex, syncPlaybookToIndex } = await import(
|
|
304
|
+
"../agent/context-compiler.ts"
|
|
305
|
+
);
|
|
306
|
+
const { syncCatalogAgentsToIndex } = await import("../agent/catalog-selector.ts");
|
|
307
|
+
|
|
308
|
+
const results = await Promise.allSettled([
|
|
309
|
+
syncToolsToIndex(),
|
|
310
|
+
syncSkillsToIndex(),
|
|
311
|
+
syncPlaybookToIndex(),
|
|
312
|
+
syncCatalogAgentsToIndex(),
|
|
313
|
+
]);
|
|
314
|
+
|
|
315
|
+
for (const result of results) {
|
|
316
|
+
if (result.status === "rejected") {
|
|
317
|
+
log.warn(`Capability index sync failed: ${result.reason}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|