@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,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `api_request` cambió de contrato en 0.1.5.
|
|
3
|
+
*
|
|
4
|
+
* El tool anterior (`tools/web/api-request.ts`) tenía helpers de autenticación
|
|
5
|
+
* (`auth: { type: "bearer" | "basic" | "api_key" }`), aceptaba `body` como
|
|
6
|
+
* objeto y devolvía `{ ok, status, data }`. El de hive es más chato: la
|
|
7
|
+
* autenticación va como un header más, `body` es string, y la respuesta expone
|
|
8
|
+
* `body` + `contentType` en vez de `data`.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
|
12
|
+
import { apiRequestTool } from "./api-request.ts";
|
|
13
|
+
|
|
14
|
+
describe("apiRequestTool", () => {
|
|
15
|
+
let originalFetch: typeof fetch;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
originalFetch = globalThis.fetch;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
globalThis.fetch = originalFetch;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function stubFetch(handler: (url: string, init: RequestInit) => Response) {
|
|
26
|
+
globalThis.fetch = Object.assign(
|
|
27
|
+
async (url: any, init?: any) => handler(url.toString(), init ?? {}),
|
|
28
|
+
{ preconnect: async () => undefined }
|
|
29
|
+
) as typeof fetch;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function jsonResponse(body: unknown, init: ResponseInit = {}) {
|
|
33
|
+
return new Response(JSON.stringify(body), {
|
|
34
|
+
status: init.status ?? 200,
|
|
35
|
+
statusText: init.statusText ?? "OK",
|
|
36
|
+
headers: { "content-type": "application/json" },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
it("ejecuta un GET simple y parsea el JSON", async () => {
|
|
41
|
+
let capturedUrl = "";
|
|
42
|
+
let capturedInit: RequestInit = {};
|
|
43
|
+
stubFetch((url, init) => {
|
|
44
|
+
capturedUrl = url;
|
|
45
|
+
capturedInit = init;
|
|
46
|
+
return jsonResponse({ hello: "world" });
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const result = await apiRequestTool.execute({
|
|
50
|
+
method: "GET",
|
|
51
|
+
url: "https://api.example.com/data",
|
|
52
|
+
}) as any;
|
|
53
|
+
|
|
54
|
+
expect(capturedUrl).toBe("https://api.example.com/data");
|
|
55
|
+
expect(capturedInit.method).toBe("GET");
|
|
56
|
+
expect(result.ok).toBe(true);
|
|
57
|
+
expect(result.status).toBe(200);
|
|
58
|
+
expect(result.body).toEqual({ hello: "world" });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("manda POST con el body tal cual y los headers dados", async () => {
|
|
62
|
+
let capturedInit: RequestInit = {};
|
|
63
|
+
stubFetch((_url, init) => {
|
|
64
|
+
capturedInit = init;
|
|
65
|
+
return jsonResponse({ id: 1 }, { status: 201, statusText: "Created" });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const result = await apiRequestTool.execute({
|
|
69
|
+
method: "POST",
|
|
70
|
+
url: "https://api.example.com/items",
|
|
71
|
+
body: JSON.stringify({ name: "test" }),
|
|
72
|
+
headers: { "Content-Type": "application/json", Authorization: "Bearer tok" },
|
|
73
|
+
}) as any;
|
|
74
|
+
|
|
75
|
+
expect(capturedInit.method).toBe("POST");
|
|
76
|
+
expect(capturedInit.body).toBe('{"name":"test"}');
|
|
77
|
+
expect((capturedInit.headers as Record<string, string>).Authorization).toBe("Bearer tok");
|
|
78
|
+
expect(result.status).toBe(201);
|
|
79
|
+
expect(result.body).toEqual({ id: 1 });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("codifica query_params en la URL", async () => {
|
|
83
|
+
let capturedUrl = "";
|
|
84
|
+
stubFetch((url) => {
|
|
85
|
+
capturedUrl = url;
|
|
86
|
+
return jsonResponse({});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await apiRequestTool.execute({
|
|
90
|
+
method: "GET",
|
|
91
|
+
url: "https://api.example.com/search",
|
|
92
|
+
query_params: { q: "hola mundo", limit: "10" },
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
expect(capturedUrl).toContain("q=hola+mundo");
|
|
96
|
+
expect(capturedUrl).toContain("limit=10");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("devuelve texto plano sin intentar parsearlo", async () => {
|
|
100
|
+
stubFetch(() => new Response("hello world", {
|
|
101
|
+
status: 200,
|
|
102
|
+
statusText: "OK",
|
|
103
|
+
headers: { "content-type": "text/plain" },
|
|
104
|
+
}));
|
|
105
|
+
|
|
106
|
+
const result = await apiRequestTool.execute({
|
|
107
|
+
method: "GET",
|
|
108
|
+
url: "https://api.example.com/text",
|
|
109
|
+
}) as any;
|
|
110
|
+
|
|
111
|
+
expect(result.ok).toBe(true);
|
|
112
|
+
expect(result.body).toBe("hello world");
|
|
113
|
+
expect(result.contentType).toContain("text/plain");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("marca ok:false en un HTTP no exitoso sin lanzar", async () => {
|
|
117
|
+
stubFetch(() => jsonResponse({ error: "not found" }, { status: 404, statusText: "Not Found" }));
|
|
118
|
+
|
|
119
|
+
const result = await apiRequestTool.execute({
|
|
120
|
+
method: "GET",
|
|
121
|
+
url: "https://api.example.com/missing",
|
|
122
|
+
}) as any;
|
|
123
|
+
|
|
124
|
+
expect(result.ok).toBe(false);
|
|
125
|
+
expect(result.status).toBe(404);
|
|
126
|
+
expect(result.statusText).toBe("Not Found");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("rechaza un método no permitido antes de tocar la red", async () => {
|
|
130
|
+
let called = false;
|
|
131
|
+
stubFetch(() => { called = true; return jsonResponse({}); });
|
|
132
|
+
|
|
133
|
+
const result = await apiRequestTool.execute({
|
|
134
|
+
method: "TRACE",
|
|
135
|
+
url: "https://api.example.com/data",
|
|
136
|
+
}) as any;
|
|
137
|
+
|
|
138
|
+
expect(called).toBe(false);
|
|
139
|
+
expect(result.ok).toBe(false);
|
|
140
|
+
expect(result.error).toContain("Invalid HTTP method");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("exige url", async () => {
|
|
144
|
+
const result = await apiRequestTool.execute({ method: "GET" }) as any;
|
|
145
|
+
|
|
146
|
+
expect(result.ok).toBe(false);
|
|
147
|
+
expect(result.error).toContain("url");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("devuelve el error de red como resultado, no como excepción", async () => {
|
|
151
|
+
globalThis.fetch = Object.assign(
|
|
152
|
+
async () => { throw new Error("ECONNREFUSED"); },
|
|
153
|
+
{ preconnect: async () => undefined }
|
|
154
|
+
) as typeof fetch;
|
|
155
|
+
|
|
156
|
+
const result = await apiRequestTool.execute({
|
|
157
|
+
method: "GET",
|
|
158
|
+
url: "https://api.example.com/down",
|
|
159
|
+
}) as any;
|
|
160
|
+
|
|
161
|
+
expect(result.ok).toBe(false);
|
|
162
|
+
expect(result.error).toContain("ECONNREFUSED");
|
|
163
|
+
});
|
|
164
|
+
});
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api_request - Make HTTP requests to REST APIs (curl-like)
|
|
3
|
+
*
|
|
4
|
+
* Supports: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
|
|
5
|
+
* Features: custom headers, JSON/form body, query params, timeout
|
|
6
|
+
*
|
|
7
|
+
* @category api
|
|
8
|
+
* @seedId api_request
|
|
9
|
+
* @spanish llamar api, petición http, curl, post a api, put api, delete api
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { Tool } from "../types.ts";
|
|
13
|
+
import { logger } from "../../utils/logger.ts";
|
|
14
|
+
|
|
15
|
+
const log = logger.child("api-request");
|
|
16
|
+
|
|
17
|
+
const ALLOWED_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"];
|
|
18
|
+
|
|
19
|
+
export const apiRequestTool: Tool = {
|
|
20
|
+
name: "api_request",
|
|
21
|
+
description:
|
|
22
|
+
"Make an HTTP request to a REST API endpoint. Supports GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS with custom headers, body, and query parameters. " +
|
|
23
|
+
"Spanish: llamar api, petición http, curl, post a api, put api, delete api, consumir servicio rest",
|
|
24
|
+
parameters: {
|
|
25
|
+
type: "object",
|
|
26
|
+
properties: {
|
|
27
|
+
method: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "HTTP method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS",
|
|
30
|
+
enum: ALLOWED_METHODS,
|
|
31
|
+
},
|
|
32
|
+
url: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Full URL of the API endpoint (including query string, or use query_params)",
|
|
35
|
+
},
|
|
36
|
+
headers: {
|
|
37
|
+
type: "object",
|
|
38
|
+
description: "Optional HTTP headers as key-value pairs. Example: {\"Content-Type\": \"application/json\", \"Authorization\": \"Bearer token\"}",
|
|
39
|
+
additionalProperties: { type: "string" },
|
|
40
|
+
},
|
|
41
|
+
body: {
|
|
42
|
+
type: "string",
|
|
43
|
+
description: "Optional request body as a string. For JSON APIs, pass a JSON string. For form data, pass URL-encoded string.",
|
|
44
|
+
},
|
|
45
|
+
query_params: {
|
|
46
|
+
type: "object",
|
|
47
|
+
description: "Optional query parameters as key-value pairs. Will be URL-encoded and appended to the URL.",
|
|
48
|
+
additionalProperties: { type: "string" },
|
|
49
|
+
},
|
|
50
|
+
timeout_ms: {
|
|
51
|
+
type: "number",
|
|
52
|
+
description: "Request timeout in milliseconds. Default: 30000 (30s). Max: 120000 (2 min).",
|
|
53
|
+
minimum: 1000,
|
|
54
|
+
maximum: 120000,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
required: ["method", "url"],
|
|
58
|
+
},
|
|
59
|
+
execute: async (params: Record<string, unknown>) => {
|
|
60
|
+
const method = (params.method as string)?.toUpperCase().trim() || "GET";
|
|
61
|
+
let url = params.url as string;
|
|
62
|
+
const headers = (params.headers as Record<string, string>) || {};
|
|
63
|
+
const body = params.body as string | undefined;
|
|
64
|
+
const queryParams = (params.query_params as Record<string, string>) || {};
|
|
65
|
+
const timeoutMs = (params.timeout_ms as number) || 30000;
|
|
66
|
+
|
|
67
|
+
if (!ALLOWED_METHODS.includes(method)) {
|
|
68
|
+
return {
|
|
69
|
+
ok: false,
|
|
70
|
+
error: `Invalid HTTP method: ${method}. Allowed: ${ALLOWED_METHODS.join(", ")}`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!url || typeof url !== "string") {
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
error: "Missing required parameter: url",
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Append query params to URL
|
|
82
|
+
if (Object.keys(queryParams).length > 0) {
|
|
83
|
+
const urlObj = new URL(url);
|
|
84
|
+
for (const [key, value] of Object.entries(queryParams)) {
|
|
85
|
+
urlObj.searchParams.append(key, value);
|
|
86
|
+
}
|
|
87
|
+
url = urlObj.toString();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
log.info(`[api_request] ${method} ${url}`);
|
|
91
|
+
|
|
92
|
+
const fetchOptions: RequestInit = {
|
|
93
|
+
method,
|
|
94
|
+
headers: {
|
|
95
|
+
"User-Agent": "HiveAgent/1.0",
|
|
96
|
+
...headers,
|
|
97
|
+
},
|
|
98
|
+
// @ts-ignore — Bun supports timeout
|
|
99
|
+
timeout: timeoutMs,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
if (body !== undefined && body !== null && body !== "") {
|
|
103
|
+
// Auto-set Content-Type to application/json if body looks like JSON
|
|
104
|
+
if (
|
|
105
|
+
!headers["Content-Type"] &&
|
|
106
|
+
!headers["content-type"] &&
|
|
107
|
+
typeof body === "string" &&
|
|
108
|
+
(body.trim().startsWith("{") || body.trim().startsWith("["))
|
|
109
|
+
) {
|
|
110
|
+
(fetchOptions.headers as Record<string, string>)["Content-Type"] = "application/json";
|
|
111
|
+
}
|
|
112
|
+
fetchOptions.body = body;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
const response = await fetch(url, fetchOptions);
|
|
117
|
+
|
|
118
|
+
// For HEAD requests, don't read body
|
|
119
|
+
if (method === "HEAD") {
|
|
120
|
+
const responseHeaders: Record<string, string> = {};
|
|
121
|
+
response.headers.forEach((value, key) => {
|
|
122
|
+
responseHeaders[key] = value;
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
ok: response.ok,
|
|
126
|
+
status: response.status,
|
|
127
|
+
statusText: response.statusText,
|
|
128
|
+
headers: responseHeaders,
|
|
129
|
+
url: response.url,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const contentType = response.headers.get("content-type") || "";
|
|
134
|
+
let responseBody: string | object;
|
|
135
|
+
const rawText = await response.text();
|
|
136
|
+
|
|
137
|
+
if (contentType.includes("application/json")) {
|
|
138
|
+
try {
|
|
139
|
+
responseBody = JSON.parse(rawText);
|
|
140
|
+
} catch {
|
|
141
|
+
responseBody = rawText;
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
responseBody = rawText;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const responseHeaders: Record<string, string> = {};
|
|
148
|
+
response.headers.forEach((value, key) => {
|
|
149
|
+
responseHeaders[key] = value;
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
log.info(`[api_request] ${method} ${url} → ${response.status} ${response.statusText}`);
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
ok: response.ok,
|
|
156
|
+
status: response.status,
|
|
157
|
+
statusText: response.statusText,
|
|
158
|
+
headers: responseHeaders,
|
|
159
|
+
body: responseBody,
|
|
160
|
+
contentType,
|
|
161
|
+
url: response.url,
|
|
162
|
+
};
|
|
163
|
+
} catch (error) {
|
|
164
|
+
const msg = (error as Error).message;
|
|
165
|
+
log.error(`[api_request] ${method} ${url} failed: ${msg}`);
|
|
166
|
+
return {
|
|
167
|
+
ok: false,
|
|
168
|
+
error: `HTTP request failed: ${msg}`,
|
|
169
|
+
url,
|
|
170
|
+
method,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Tools - HTTP client for REST APIs (curl-like)
|
|
3
|
+
*
|
|
4
|
+
* Makes requests to external APIs with full control over method, headers, body.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Tool } from "../types.ts";
|
|
8
|
+
import { apiRequestTool } from "./api-request.ts";
|
|
9
|
+
|
|
10
|
+
export function createTools(): Tool[] {
|
|
11
|
+
return [
|
|
12
|
+
apiRequestTool,
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { apiRequestTool } from "./api-request.ts";
|
|
@@ -30,6 +30,10 @@ const BLOCKED_PATTERNS: Array<{ pattern: RegExp; reason: string }> = [
|
|
|
30
30
|
|
|
31
31
|
export const cliExecTool: Tool = {
|
|
32
32
|
name: "cli_exec",
|
|
33
|
+
// Long-running commands need a generous runtime ceiling (the tool allows
|
|
34
|
+
// its own per-call `timeout` up to 300s, so the harness timeout must be
|
|
35
|
+
// above that to avoid the worker killing a still-running command).
|
|
36
|
+
timeoutMs: 330000,
|
|
33
37
|
description: "Execute shell/bash commands in the agent workspace. NOTE: do NOT use for scheduling tasks, use cron.create instead. Spanish: ejecutar comando, terminal, bash, script, consola",
|
|
34
38
|
parameters: {
|
|
35
39
|
type: "object",
|