@johpaz/hive-sdk 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +135 -0
- package/README.md +11 -1
- package/package.json +18 -2
- package/packages/core/src/agent/acceptance-checks.ts +9 -9
- package/packages/core/src/agent/agent-catalog.ts +3 -3
- package/packages/core/src/agent/agent-loop.ts +115 -26
- package/packages/core/src/agent/capability-search.ts +2 -2
- package/packages/core/src/agent/catalog-selector.ts +4 -4
- package/packages/core/src/agent/compaction.ts +10 -9
- package/packages/core/src/agent/context-compiler.ts +58 -34
- package/packages/core/src/agent/conversation-store.ts +31 -7
- package/packages/core/src/agent/curator.ts +4 -4
- package/packages/core/src/agent/delegation-runtime.ts +5 -5
- package/packages/core/src/agent/goal-runner.ts +9 -9
- package/packages/core/src/agent/index.ts +1 -0
- package/packages/core/src/agent/llm-client.ts +98 -37
- package/packages/core/src/agent/llm-providers/anthropic.ts +4 -4
- package/packages/core/src/agent/llm-providers/deepseek.ts +1 -1
- package/packages/core/src/agent/llm-providers/gemini.ts +4 -4
- package/packages/core/src/agent/llm-providers/groq.ts +1 -1
- package/packages/core/src/agent/llm-providers/hiveagents.ts +3 -3
- package/packages/core/src/agent/llm-providers/interface.ts +2 -2
- package/packages/core/src/agent/llm-providers/kimi.ts +1 -1
- package/packages/core/src/agent/llm-providers/minimax.ts +1 -1
- package/packages/core/src/agent/llm-providers/mistral.ts +1 -1
- package/packages/core/src/agent/llm-providers/modelscope.ts +1 -1
- package/packages/core/src/agent/llm-providers/nvidia.ts +1 -1
- package/packages/core/src/agent/llm-providers/ollama.ts +4 -4
- package/packages/core/src/agent/llm-providers/openai-compat-base.ts +9 -5
- package/packages/core/src/agent/llm-providers/openai.ts +1 -1
- package/packages/core/src/agent/llm-providers/opencode-go.ts +1 -1
- package/packages/core/src/agent/llm-providers/openrouter.ts +1 -1
- package/packages/core/src/agent/llm-providers/qwen.ts +1 -1
- package/packages/core/src/agent/llm-providers/z-ai.ts +1 -1
- package/packages/core/src/agent/mcp-result-normalizer.ts +192 -0
- package/packages/core/src/agent/playbook-selector.ts +4 -4
- package/packages/core/src/agent/prompt-builder.ts +5 -5
- package/packages/core/src/agent/proof-packet.ts +5 -5
- package/packages/core/src/agent/providers/index.ts +4 -4
- package/packages/core/src/agent/realtime-providers/gemini-live.ts +238 -0
- package/packages/core/src/agent/realtime-providers/index.ts +29 -0
- package/packages/core/src/agent/realtime-providers/interface.ts +108 -0
- package/packages/core/src/agent/reflector.ts +6 -6
- package/packages/core/src/agent/run-store.ts +8 -8
- package/packages/core/src/agent/service.ts +10 -10
- package/packages/core/src/agent/skill-selector.ts +6 -6
- package/packages/core/src/agent/thread-id.ts +71 -0
- package/packages/core/src/agent/thread-store.ts +250 -0
- package/packages/core/src/agent/tool-selector.ts +7 -5
- package/packages/core/src/agent/tracer.ts +5 -5
- package/packages/core/src/api/createAgent.ts +1 -1
- package/packages/core/src/artifacts/store.ts +84 -3
- package/packages/core/src/canvas/emitter.ts +2 -2
- package/packages/core/src/channels/telegram.ts +1 -1
- package/packages/core/src/channels/webchat.ts +1 -1
- package/packages/core/src/config/loader.ts +14 -5
- package/packages/core/src/events/agent-bus.ts +3 -3
- package/packages/core/src/events/channel-narration.ts +3 -3
- package/packages/core/src/events/event-bus.ts +1 -1
- package/packages/core/src/events/narration.ts +3 -3
- package/packages/core/src/gateway/delegation-groups.ts +4 -4
- package/packages/core/src/gateway/durable-queue.ts +5 -5
- package/packages/core/src/gateway/job-store.ts +5 -5
- package/packages/core/src/gateway/notification-inbox.ts +2 -2
- package/packages/core/src/gateway/server.ts +2 -2
- package/packages/core/src/mcp/MCPClient.ts +3 -3
- package/packages/core/src/mcp/hot-reload.ts +5 -5
- package/packages/core/src/mcp/tool-sync.ts +5 -5
- package/packages/core/src/mcp/transports/index.ts +2 -2
- package/packages/core/src/mcp/transports/sse.ts +1 -1
- package/packages/core/src/models/index.ts +36 -0
- package/packages/core/src/multimodal/index.ts +2 -2
- package/packages/core/src/multimodal/vision-service.ts +6 -6
- package/packages/core/src/plugins/loader.ts +4 -1
- package/packages/core/src/resilience/circuit-breaker.ts +16 -5
- package/packages/core/src/resilience/retry.ts +1 -1
- package/packages/core/src/scheduler/CronScheduler.ts +6 -6
- package/packages/core/src/scheduler/integration.ts +9 -9
- package/packages/core/src/sessions/index.ts +266 -0
- package/packages/core/src/storage/bootstrap.ts +34 -8
- package/packages/core/src/storage/causal-events.ts +1 -1
- package/packages/core/src/storage/collections.ts +32 -1
- package/packages/core/src/storage/crypto.ts +16 -2
- package/packages/core/src/storage/hive.ts +1 -1
- package/packages/core/src/storage/hivedb.ts +10 -1
- package/packages/core/src/storage/onboarding.ts +6 -6
- package/packages/core/src/storage/reconcile.ts +5 -5
- package/packages/core/src/storage/seed.ts +103 -13
- package/packages/core/src/storage/usage.ts +3 -3
- package/packages/core/src/swarm/AgentExecutor.ts +2 -2
- package/packages/core/src/swarm/Coordinator.ts +8 -8
- package/packages/core/src/swarm/EventBridge.ts +2 -2
- package/packages/core/src/swarm/RoleSwarm.ts +234 -0
- package/packages/core/src/swarm/TaskGraph.ts +2 -2
- package/packages/core/src/swarm/index.ts +7 -0
- package/packages/core/src/swarm/presets/HiveLearnPreset.ts +2 -2
- package/packages/core/src/swarm/presets/ResearchPreset.ts +2 -2
- package/packages/core/src/swarm/strategies/ParallelStrategy.ts +1 -1
- package/packages/core/src/swarm/strategies/PriorityStrategy.ts +3 -3
- package/packages/core/src/tools/ToolExecutor.ts +7 -3
- package/packages/core/src/tools/core/index.ts +2 -2
- package/packages/core/src/tools/cron/index.ts +4 -4
- package/packages/core/src/tools/web/artifact-inspect.ts +2 -2
- package/packages/core/src/tools/web/artifact-read.ts +162 -0
- package/packages/core/src/tools/web/browser-backend.ts +141 -44
- package/packages/core/src/tools/web/browser-click.ts +2 -2
- package/packages/core/src/tools/web/browser-extract.ts +2 -2
- package/packages/core/src/tools/web/browser-navigate.ts +2 -2
- package/packages/core/src/tools/web/browser-screenshot.ts +12 -5
- package/packages/core/src/tools/web/browser-script.ts +2 -2
- package/packages/core/src/tools/web/browser-service.ts +63 -384
- package/packages/core/src/tools/web/browser-session.ts +125 -0
- package/packages/core/src/tools/web/browser-type.ts +2 -2
- package/packages/core/src/tools/web/browser-wait.ts +2 -2
- package/packages/core/src/tools/web/computer-use.ts +553 -0
- package/packages/core/src/tools/web/index.ts +8 -1
- package/packages/core/src/tools/web/webview-backend.ts +460 -21
- package/packages/core/src/utils/index.ts +1 -0
- package/packages/core/src/utils/logger.ts +12 -4
- package/packages/core/src/utils/redact-binary.ts +17 -0
- package/packages/core/src/utils/toon.ts +1 -1
- package/packages/core/src/voice/index.ts +6 -6
- package/bun.lock +0 -859
- package/bunfig.toml +0 -9
- package/docs/API-AGENTS.md +0 -367
- package/docs/API-CONTEXT-COMPILER.md +0 -249
- package/docs/API-DAG-SCHEDULER.md +0 -273
- package/docs/API-TOOLS-SKILLS-CHANNELS.md +0 -446
- package/docs/API-WORKERS-EVENTS.md +0 -299
- package/docs/HIVE-HARNESS.md +0 -113
- package/docs/INDEX.md +0 -190
- package/docs/TEMPLATE-HIVE-APP.md +0 -360
- package/packages/cli/package.json +0 -17
- package/packages/cli/src/commands/create-app.test.ts +0 -180
- package/packages/core/package.json +0 -70
- package/packages/core/src/api/createAgent.test.ts +0 -160
- package/packages/core/src/canvas/canvas.test.ts +0 -36
- package/packages/core/src/channels/channels.test.ts +0 -18
- package/packages/core/src/ethics/EthicsGuard.test.ts +0 -108
- package/packages/core/src/gateway/gateway.test.ts +0 -38
- package/packages/core/src/memory/Scratchpad.test.ts +0 -68
- package/packages/core/src/scheduler/scheduler.test.ts +0 -15
- package/packages/core/src/skills/skills.test.ts +0 -62
- package/packages/core/src/swarm/swarm.test.ts +0 -24
- package/packages/core/src/tool-runtime/tool-runtime.test.ts +0 -99
- package/packages/core/src/tools/ToolRegistry.test.ts +0 -98
- package/packages/core/src/tools/api/api-request.test.ts +0 -164
- package/packages/core/src/tools/web/browser-service.test.ts +0 -83
- package/packages/core/src/workers/workers.test.ts +0 -41
- package/scripts/bump-version.ts +0 -248
- package/scripts/generate-skill-bundle.ts +0 -108
- package/test/acceptance-checks.test.ts +0 -403
- package/test/agent-loop-terminal-synthesis.test.ts +0 -32
- package/test/browser-backend.test.ts +0 -308
- package/test/catalog-agents-stay-enabled.test.ts +0 -117
- package/test/causal-events.test.ts +0 -117
- package/test/compaction.test.ts +0 -105
- package/test/context-compiler.test.ts +0 -269
- package/test/curator.test.ts +0 -130
- package/test/durable-queue.test.ts +0 -114
- package/test/harness-barrel.test.ts +0 -64
- package/test/hive-helpers.test.ts +0 -130
- package/test/hivedb-search.test.ts +0 -189
- package/test/internal-turns.test.ts +0 -166
- package/test/job-idempotency.test.ts +0 -68
- package/test/job-retry-backoff.test.ts +0 -184
- package/test/job-store.test.ts +0 -381
- package/test/llm-retry.test.ts +0 -97
- package/test/memory-perf.test.ts +0 -774
- package/test/minimal-loadout.test.ts +0 -78
- package/test/model-catalog.test.ts +0 -105
- package/test/preload.ts +0 -12
- package/test/reflector.test.ts +0 -320
- package/test/retention-cap.test.ts +0 -91
- package/test/retired-capabilities-pruned.test.ts +0 -192
- package/test/run-store.test.ts +0 -355
- package/test/scratchpad.test.ts +0 -74
- package/test/secrets-durability.test.ts +0 -119
- package/test/seed-model-reseed.test.ts +0 -155
- package/test/setup-agent-seed.test.ts +0 -264
- package/test/tool-inventory.test.ts +0 -65
- package/test/tool-runtime.test.ts +0 -258
- package/test/tool-selector-runtime-tools.test.ts +0 -117
- package/test/toon.test.ts +0 -429
- package/tsconfig.json +0 -42
|
@@ -21,27 +21,28 @@
|
|
|
21
21
|
* TODOS los datos se formatean en TOON para ahorro de tokens.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import { col, fromIndexable } from "../storage/hive"
|
|
25
|
-
import type { AgentDoc, ModelDoc } from "../storage/collections"
|
|
26
|
-
import { logger } from "../utils/logger"
|
|
27
|
-
import type { LLMMessage, LLMToolDef, ContentPart } from "./llm-client"
|
|
24
|
+
import { col, fromIndexable } from "../storage/hive.ts"
|
|
25
|
+
import type { AgentDoc, ModelDoc } from "../storage/collections.ts"
|
|
26
|
+
import { logger } from "../utils/logger.ts"
|
|
27
|
+
import type { LLMMessage, LLMToolDef, ContentPart } from "./llm-client.ts"
|
|
28
28
|
import type { MCPClientManager } from "../mcp/index.ts"
|
|
29
|
-
import { syncToolCatalogToIndex, mcpToolFullName } from "./tool-selector"
|
|
30
|
-
import { syncSkillsToIndex, getMinimalSkills, selectSkills, getSkillByName, type SkillDescriptor } from "./skill-selector"
|
|
31
|
-
import { syncPlaybookToIndex, selectPlaybookRules } from "./playbook-selector"
|
|
32
|
-
import { getRecentMessages, getSummary, getScratchpad, toAPIMessages } from "./conversation-store"
|
|
33
|
-
import { formatContext, estimateTokens } from "../utils/toon"
|
|
34
|
-
import { buildSystemPromptWithProjects } from "./prompt-builder"
|
|
29
|
+
import { syncToolCatalogToIndex, mcpToolFullName } from "./tool-selector.ts"
|
|
30
|
+
import { syncSkillsToIndex, getMinimalSkills, selectSkills, getSkillByName, type SkillDescriptor } from "./skill-selector.ts"
|
|
31
|
+
import { syncPlaybookToIndex, selectPlaybookRules } from "./playbook-selector.ts"
|
|
32
|
+
import { getRecentMessages, getSummary, getScratchpad, toAPIMessages } from "./conversation-store.ts"
|
|
33
|
+
import { formatContext, estimateTokens } from "../utils/toon.ts"
|
|
34
|
+
import { buildSystemPromptWithProjects } from "./prompt-builder.ts"
|
|
35
35
|
import { createAllTools } from "../tools/index.ts"
|
|
36
|
-
import { resolveUserId } from "../storage/onboarding"
|
|
37
|
-
import { getMCPManager as getSingletonMCPManager } from "../mcp/singleton"
|
|
38
|
-
import { syncMCPToolsToDB, syncMCPToolsToIndex } from "../mcp/tool-sync"
|
|
39
|
-
import { getUserDate, getUserTime } from "../utils/date"
|
|
40
|
-
import { loadConfig } from "../config/loader"
|
|
41
|
-
import { getHiveDb } from "../storage/hivedb"
|
|
42
|
-
import { listCatalogAgents, renderAgentRoutingCatalog } from "./catalog-selector"
|
|
43
|
-
import { expandToolAllowlist } from "./delegation-runtime"
|
|
44
|
-
import { MINIMAL_TOOLS } from "./minimal-loadout"
|
|
36
|
+
import { resolveUserId } from "../storage/onboarding.ts"
|
|
37
|
+
import { getMCPManager as getSingletonMCPManager } from "../mcp/singleton.ts"
|
|
38
|
+
import { syncMCPToolsToDB, syncMCPToolsToIndex } from "../mcp/tool-sync.ts"
|
|
39
|
+
import { getUserDate, getUserTime } from "../utils/date.ts"
|
|
40
|
+
import { loadConfig } from "../config/loader.ts"
|
|
41
|
+
import { getHiveDb } from "../storage/hivedb.ts"
|
|
42
|
+
import { listCatalogAgents, renderAgentRoutingCatalog } from "./catalog-selector.ts"
|
|
43
|
+
import { expandToolAllowlist } from "./delegation-runtime.ts"
|
|
44
|
+
import { MINIMAL_TOOLS } from "./minimal-loadout.ts"
|
|
45
|
+
import { normalizeMcpResult } from "./mcp-result-normalizer.ts"
|
|
45
46
|
|
|
46
47
|
const log = logger.child("context-compiler")
|
|
47
48
|
|
|
@@ -238,7 +239,7 @@ export async function compileContext(opts: {
|
|
|
238
239
|
|
|
239
240
|
if (effectiveMcpManager) {
|
|
240
241
|
try {
|
|
241
|
-
const mcpServersCol = await col<import("../storage/collections").McpServerDoc>("mcpServers")
|
|
242
|
+
const mcpServersCol = await col<import("../storage/collections.ts").McpServerDoc>("mcpServers")
|
|
242
243
|
const assignedMcpIds = new Set<string>([
|
|
243
244
|
...(agent.mcp_server_ids_json ? JSON.parse(agent.mcp_server_ids_json) : []),
|
|
244
245
|
...(agent.active_mcp_json ? JSON.parse(agent.active_mcp_json) : []),
|
|
@@ -293,10 +294,20 @@ export async function compileContext(opts: {
|
|
|
293
294
|
name: fullName,
|
|
294
295
|
description: mcpTool.description || `Tool from ${server.name}`,
|
|
295
296
|
parameters: mcpTool.inputSchema || { type: "object", properties: {} },
|
|
296
|
-
execute: async (params: Record<string, unknown>) => {
|
|
297
|
+
execute: async (params: Record<string, unknown>, config?: { configurable?: Record<string, unknown> }) => {
|
|
297
298
|
// Return raw JS value — agent-loop will TOON-encode via formatToolResult.
|
|
298
299
|
// Never pre-stringify here: formatToolResult(string) double-encodes.
|
|
299
|
-
|
|
300
|
+
const raw = await effectiveMcpManager.callTool(resolvedServerKey, mcpTool.name, params)
|
|
301
|
+
// MCP results can carry base64 image/audio/blob content blocks —
|
|
302
|
+
// normalize those into artifact_ref pointers so a large binary
|
|
303
|
+
// result never gets serialized whole into the LLM context (see
|
|
304
|
+
// mcp-result-normalizer.ts for the incident this prevents).
|
|
305
|
+
const configurable = config?.configurable ?? {}
|
|
306
|
+
return await normalizeMcpResult(raw, {
|
|
307
|
+
userId: configurable.user_id ? String(configurable.user_id) : undefined,
|
|
308
|
+
runId: configurable.run_id ? String(configurable.run_id) : null,
|
|
309
|
+
taskId: configurable.task_id ? String(configurable.task_id) : null,
|
|
310
|
+
})
|
|
300
311
|
},
|
|
301
312
|
})
|
|
302
313
|
|
|
@@ -352,17 +363,30 @@ export async function compileContext(opts: {
|
|
|
352
363
|
// Only native minimal tools in LLM context
|
|
353
364
|
// MCP tools are discovered dynamically via search_knowledge(type="mcp")
|
|
354
365
|
let filteredNativeTools: ContextTool[] = nativeTools.filter(t => MINIMAL_TOOLS.has(t.name))
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
366
|
+
|
|
367
|
+
// La lista blanca se aplica a `allTools`, no sólo al prompt inicial. Filtrar
|
|
368
|
+
// únicamente el loadout de arranque no restringe nada: `search_knowledge`
|
|
369
|
+
// busca contra el índice completo y agent-loop.ts inyecta lo que encuentre
|
|
370
|
+
// resolviéndolo contra `allTools`, así que un agente restringido llegaba
|
|
371
|
+
// igual a cualquier tool nativa por descubrimiento dinámico. Sacarla de
|
|
372
|
+
// `allTools` la vuelve irresoluble: se puede encontrar en el índice, pero no
|
|
373
|
+
// se puede cargar ni llamar.
|
|
374
|
+
//
|
|
375
|
+
// Antes esto dependía de `isCatalogAgent`, y los agentes creados por el
|
|
376
|
+
// usuario —que son los que un host multi-tenant define— quedaban sin límite.
|
|
377
|
+
// Ahora depende de que el agente declare una lista: el coordinador, que no
|
|
378
|
+
// declara ninguna, conserva el descubrimiento abierto.
|
|
379
|
+
const declaredAllowlist = agent.tool_allowlist_json
|
|
380
|
+
? expandToolAllowlist(
|
|
381
|
+
JSON.parse(agent.tool_allowlist_json),
|
|
382
|
+
nativeTools.map((tool) => tool.name),
|
|
365
383
|
)
|
|
384
|
+
: agent.tools_json
|
|
385
|
+
? (JSON.parse(agent.tools_json) as string[])
|
|
386
|
+
: null
|
|
387
|
+
|
|
388
|
+
if (declaredAllowlist) {
|
|
389
|
+
const allowedNames = new Set<string>(declaredAllowlist)
|
|
366
390
|
filteredNativeTools = nativeTools.filter((tool) => allowedNames.has(tool.name))
|
|
367
391
|
allTools = [...filteredNativeTools, ...mcpToolExecutors]
|
|
368
392
|
}
|
|
@@ -508,7 +532,7 @@ export async function compileContext(opts: {
|
|
|
508
532
|
}
|
|
509
533
|
|
|
510
534
|
// [STEP-10b] Inject current date/time (ENTORNO ACTUAL)
|
|
511
|
-
const usersCol = await col<import("../storage/collections").UserDoc>("users")
|
|
535
|
+
const usersCol = await col<import("../storage/collections.ts").UserDoc>("users")
|
|
512
536
|
const userRow = await usersCol.get(userId)
|
|
513
537
|
const userTimezone = userRow?.doc.timezone || "UTC"
|
|
514
538
|
const now = new Date()
|
|
@@ -585,7 +609,7 @@ export async function compileContext(opts: {
|
|
|
585
609
|
.filter((line): line is string => !!line)
|
|
586
610
|
|
|
587
611
|
if (causalLines.length > 0) {
|
|
588
|
-
systemPrompt += `\n\n# CAUSAL CONTEXT (decisiones y tool calls de este turno, previos a la compactación —
|
|
612
|
+
systemPrompt += `\n\n# CAUSAL CONTEXT (decisiones y tool calls de este turno, previos a la compactación — prioriza la conversación actual; úsalo solo para no repetir algo que ya funcionó o ya falló)\n${causalLines.join("\n")}\n`
|
|
589
613
|
log.info(`[context-compiler] [STEP-9d] ✅ Injected ${causalLines.length} causal context item(s)`)
|
|
590
614
|
}
|
|
591
615
|
} catch (err) {
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
* Also manages: summaries and scratchpad, both HiveDB document collections.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { col, nextId, bumpRollup } from "../storage/hive"
|
|
9
|
-
import { getHiveDb } from "../storage/hivedb"
|
|
10
|
-
import { logger } from "../utils/logger"
|
|
11
|
-
import type { LLMMessage, ContentPart } from "./llm-client"
|
|
12
|
-
import { estimateTokens } from "../utils/toon"
|
|
13
|
-
import type { ConversationDoc, SummaryDoc, MessageSource } from "../storage/collections"
|
|
8
|
+
import { col, nextId, bumpRollup } from "../storage/hive.ts"
|
|
9
|
+
import { getHiveDb } from "../storage/hivedb.ts"
|
|
10
|
+
import { logger } from "../utils/logger.ts"
|
|
11
|
+
import type { LLMMessage, ContentPart } from "./llm-client.ts"
|
|
12
|
+
import { estimateTokens } from "../utils/toon.ts"
|
|
13
|
+
import type { ConversationDoc, SummaryDoc, MessageSource } from "../storage/collections.ts"
|
|
14
|
+
import { touchThread } from "./thread-store.ts"
|
|
14
15
|
|
|
15
16
|
const log = logger.child("conv-store")
|
|
16
17
|
|
|
@@ -45,13 +46,26 @@ export interface StoredMessage {
|
|
|
45
46
|
// stays clean and the wording can evolve without a migration.
|
|
46
47
|
|
|
47
48
|
export const INTERNAL_SOURCES: ReadonlySet<string> =
|
|
48
|
-
new Set(["task_complete", "delegation_summary", "legacy_internal"])
|
|
49
|
+
new Set(["task_complete", "delegation_summary", "legacy_internal", "realtime_chat"])
|
|
49
50
|
|
|
50
51
|
export function isInternalSource(source: string | null | undefined): boolean {
|
|
51
52
|
return !!source && INTERNAL_SOURCES.has(source)
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
export function formatInternalEvent(source: string, content: string): string {
|
|
56
|
+
// La charla hablada sí salió del usuario, pero la sesión de voz ya la
|
|
57
|
+
// respondió: es contexto, no trabajo por hacer. Sin esta distinción el
|
|
58
|
+
// coordinador leía cada frase suelta de una llamada como un pedido nuevo y
|
|
59
|
+
// delegaba una tarea por cada una.
|
|
60
|
+
if (source === "realtime_chat") {
|
|
61
|
+
return `<hive:voice_context>\n` +
|
|
62
|
+
`Fragmento de una conversación hablada que la voz de Hive YA respondió en el momento. ` +
|
|
63
|
+
`Es contexto de lo que vinieron hablando, NO un pedido pendiente: no ejecutes ni delegues nada por esto. ` +
|
|
64
|
+
`El trabajo real llega siempre como un mensaje aparte y explícito.\n\n` +
|
|
65
|
+
`${content}\n` +
|
|
66
|
+
`</hive:voice_context>`
|
|
67
|
+
}
|
|
68
|
+
|
|
55
69
|
return `<hive:internal_event source="${source}">\n` +
|
|
56
70
|
`Evento interno del sistema — NO es un mensaje del usuario. No lo cites literalmente, no expongas IDs internos (task_id, worker_id) ni JSON crudo. Respondé al usuario de forma natural y breve.\n\n` +
|
|
57
71
|
`${content}\n` +
|
|
@@ -146,6 +160,16 @@ export async function addMessage(
|
|
|
146
160
|
bumpRollup("activityRollups", hour, { messageCount: 1 }).catch(() => {})
|
|
147
161
|
recentMessageTimestamps.push(now)
|
|
148
162
|
|
|
163
|
+
// Igual de opcional: el registro de conversaciones es el catálogo que alimenta la
|
|
164
|
+
// lista de la web (título, orden, contador). Se actualiza acá y no en cada llamador
|
|
165
|
+
// para que todo camino que escriba un mensaje —canales, webchat, API, voz— lo
|
|
166
|
+
// mantenga al día sin repetir la llamada.
|
|
167
|
+
touchThread(threadId, {
|
|
168
|
+
role,
|
|
169
|
+
text: textContent,
|
|
170
|
+
internal: isInternalSource(opts?.source),
|
|
171
|
+
}).catch(() => {})
|
|
172
|
+
|
|
149
173
|
return seq
|
|
150
174
|
}
|
|
151
175
|
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* (id="curator:lastReflection") instead of SQL's MAX(source_reflection_id).
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { logger } from "../utils/logger"
|
|
17
|
-
import { col, nextId, toIndexable, fromIndexable } from "../storage/hive"
|
|
16
|
+
import { logger } from "../utils/logger.ts"
|
|
17
|
+
import { col, nextId, toIndexable, fromIndexable } from "../storage/hive.ts"
|
|
18
18
|
import type {
|
|
19
19
|
ReflectionDoc,
|
|
20
20
|
PlaybookDoc,
|
|
@@ -22,7 +22,7 @@ import type {
|
|
|
22
22
|
CursorDoc,
|
|
23
23
|
AgentProposalDoc,
|
|
24
24
|
TraceDoc,
|
|
25
|
-
} from "../storage/collections"
|
|
25
|
+
} from "../storage/collections.ts"
|
|
26
26
|
|
|
27
27
|
const log = logger.child("curator")
|
|
28
28
|
|
|
@@ -149,7 +149,7 @@ async function curateAgentStructure(): Promise<void> {
|
|
|
149
149
|
})
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
const { syncCatalogAgentsToIndex } = await import("./catalog-selector")
|
|
152
|
+
const { syncCatalogAgentsToIndex } = await import("./catalog-selector.ts")
|
|
153
153
|
await syncCatalogAgentsToIndex()
|
|
154
154
|
}
|
|
155
155
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { col, toIndexable, fromIndexable, updateDoc } from "../storage/hive";
|
|
1
|
+
import { col, toIndexable, fromIndexable, updateDoc } from "../storage/hive.ts";
|
|
2
2
|
import type {
|
|
3
3
|
AgentDoc,
|
|
4
4
|
McpServerDoc,
|
|
@@ -6,11 +6,11 @@ import type {
|
|
|
6
6
|
ProviderDoc,
|
|
7
7
|
SkillDoc,
|
|
8
8
|
AgentModelOverride,
|
|
9
|
-
} from "../storage/collections";
|
|
10
|
-
import { createAllTools } from "../tools";
|
|
11
|
-
import { loadConfig } from "../config/loader";
|
|
9
|
+
} from "../storage/collections.ts";
|
|
10
|
+
import { createAllTools } from "../tools/index.ts";
|
|
11
|
+
import { loadConfig } from "../config/loader.ts";
|
|
12
12
|
import type { MCPClientManager } from "../mcp/index.ts";
|
|
13
|
-
import { logger } from "../utils/logger";
|
|
13
|
+
import { logger } from "../utils/logger.ts";
|
|
14
14
|
|
|
15
15
|
const log = logger.child("delegation-runtime");
|
|
16
16
|
const MCP_IDLE_TTL_MS = 2 * 60_000;
|
|
@@ -14,15 +14,15 @@
|
|
|
14
14
|
* entire run (not per-turn). This prevents endless loops.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { logger } from "../utils/logger";
|
|
18
|
-
import { callLLM, type LLMMessage } from "./llm-client";
|
|
19
|
-
import { createRun, type AcceptanceCriterion } from "./run-store";
|
|
20
|
-
import { clearOldToolResults } from "./compaction";
|
|
21
|
-
import { loadConfig } from "../config/loader";
|
|
17
|
+
import { logger } from "../utils/logger.ts";
|
|
18
|
+
import { callLLM, type LLMMessage } from "./llm-client.ts";
|
|
19
|
+
import { createRun, type AcceptanceCriterion } from "./run-store.ts";
|
|
20
|
+
import { clearOldToolResults } from "./compaction.ts";
|
|
21
|
+
import { loadConfig } from "../config/loader.ts";
|
|
22
22
|
import { getDurableQueue } from "../gateway/durable-queue.ts";
|
|
23
|
-
import { recordLLMUsage } from "./tracer";
|
|
23
|
+
import { recordLLMUsage } from "./tracer.ts";
|
|
24
24
|
|
|
25
|
-
export type { AcceptanceCriterion } from "./run-store";
|
|
25
|
+
export type { AcceptanceCriterion } from "./run-store.ts";
|
|
26
26
|
|
|
27
27
|
export interface AcceptanceResult {
|
|
28
28
|
id: string;
|
|
@@ -126,8 +126,8 @@ export async function runGoal(opts: GoalRunOptions): Promise<GoalRunResult> {
|
|
|
126
126
|
/** Runs a deterministic goal_check_tool, no LLM involved. */
|
|
127
127
|
async function runDeterministicCheck(checkTool: string, goal: string): Promise<{ met: boolean; reason: string } | null> {
|
|
128
128
|
try {
|
|
129
|
-
const { executeToolBatch } = await import("../tool-runtime");
|
|
130
|
-
const { createAllTools } = await import("../tools/index");
|
|
129
|
+
const { executeToolBatch } = await import("../tool-runtime/index.ts");
|
|
130
|
+
const { createAllTools } = await import("../tools/index.ts");
|
|
131
131
|
const allTools = createAllTools(loadConfig());
|
|
132
132
|
const toolDef = allTools.find((t) => t.name === checkTool);
|
|
133
133
|
if (!toolDef) {
|
|
@@ -11,26 +11,26 @@
|
|
|
11
11
|
* Public interface (LLMMessage, callLLM, resolveProviderConfig) is stable.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { logger } from "../utils/logger"
|
|
15
|
-
import { loadConfig } from "../config/loader"
|
|
16
|
-
import { withRetry, isRetryableError, type RetryPolicy } from "../resilience/retry"
|
|
17
|
-
import { GeminiProvider } from "./llm-providers/gemini"
|
|
18
|
-
import { AnthropicProvider } from "./llm-providers/anthropic"
|
|
19
|
-
import { OllamaProvider } from "./llm-providers/ollama"
|
|
20
|
-
import { OpenAIProvider } from "./llm-providers/openai"
|
|
21
|
-
import { GroqProvider } from "./llm-providers/groq"
|
|
22
|
-
import { MistralProvider } from "./llm-providers/mistral"
|
|
23
|
-
import { OpenRouterProvider } from "./llm-providers/openrouter"
|
|
24
|
-
import { DeepSeekProvider } from "./llm-providers/deepseek"
|
|
25
|
-
import { KimiProvider } from "./llm-providers/kimi"
|
|
26
|
-
import { NvidiaProvider } from "./llm-providers/nvidia"
|
|
27
|
-
import { QwenProvider } from "./llm-providers/qwen"
|
|
28
|
-
import { MiniMaxProvider } from "./llm-providers/minimax"
|
|
29
|
-
import { OpenCodeGoProvider } from "./llm-providers/opencode-go"
|
|
30
|
-
import { HiveAgentsProvider } from "./llm-providers/hiveagents"
|
|
31
|
-
import { ZaiProvider } from "./llm-providers/z-ai"
|
|
32
|
-
import { ModelScopeProvider } from "./llm-providers/modelscope"
|
|
33
|
-
import type { LLMProvider } from "./llm-providers/interface"
|
|
14
|
+
import { logger } from "../utils/logger.ts"
|
|
15
|
+
import { loadConfig } from "../config/loader.ts"
|
|
16
|
+
import { withRetry, isRetryableError, type RetryPolicy } from "../resilience/retry.ts"
|
|
17
|
+
import { GeminiProvider } from "./llm-providers/gemini.ts"
|
|
18
|
+
import { AnthropicProvider } from "./llm-providers/anthropic.ts"
|
|
19
|
+
import { OllamaProvider } from "./llm-providers/ollama.ts"
|
|
20
|
+
import { OpenAIProvider } from "./llm-providers/openai.ts"
|
|
21
|
+
import { GroqProvider } from "./llm-providers/groq.ts"
|
|
22
|
+
import { MistralProvider } from "./llm-providers/mistral.ts"
|
|
23
|
+
import { OpenRouterProvider } from "./llm-providers/openrouter.ts"
|
|
24
|
+
import { DeepSeekProvider } from "./llm-providers/deepseek.ts"
|
|
25
|
+
import { KimiProvider } from "./llm-providers/kimi.ts"
|
|
26
|
+
import { NvidiaProvider } from "./llm-providers/nvidia.ts"
|
|
27
|
+
import { QwenProvider } from "./llm-providers/qwen.ts"
|
|
28
|
+
import { MiniMaxProvider } from "./llm-providers/minimax.ts"
|
|
29
|
+
import { OpenCodeGoProvider } from "./llm-providers/opencode-go.ts"
|
|
30
|
+
import { HiveAgentsProvider } from "./llm-providers/hiveagents.ts"
|
|
31
|
+
import { ZaiProvider } from "./llm-providers/z-ai.ts"
|
|
32
|
+
import { ModelScopeProvider } from "./llm-providers/modelscope.ts"
|
|
33
|
+
import type { LLMProvider } from "./llm-providers/interface.ts"
|
|
34
34
|
|
|
35
35
|
const log = logger.child("llm-client")
|
|
36
36
|
|
|
@@ -182,20 +182,55 @@ export async function callLLM(options: LLMCallOptions): Promise<LLMResponse> {
|
|
|
182
182
|
const cleanModel = options.model.replace(new RegExp(`^${options.provider}\\/`), "")
|
|
183
183
|
const status = extractErrorStatus(err)
|
|
184
184
|
const modelUnavailable = status === 404 || status === 410
|
|
185
|
-
const msg =
|
|
186
|
-
? `El modelo "${cleanModel}" ya no existe en ${options.provider} (HTTP ${status}). `
|
|
187
|
-
+ `El proveedor lo retiró de su catálogo; reintentar no sirve. `
|
|
188
|
-
+ `Elegí otro modelo en Ajustes → Proveedores.`
|
|
189
|
-
: (err as Error).message
|
|
185
|
+
const msg = describeProviderFailure(err, status, options.provider, cleanModel)
|
|
190
186
|
log.error(`[llm-client] Error calling ${options.provider}/${cleanModel}: ${msg}`, err)
|
|
191
187
|
return {
|
|
192
|
-
content:
|
|
188
|
+
content: `${LLM_ERROR_PREFIX} ${msg}`,
|
|
193
189
|
stop_reason: "error",
|
|
194
190
|
error: { message: msg, status, modelUnavailable },
|
|
195
191
|
}
|
|
196
192
|
}
|
|
197
193
|
}
|
|
198
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Marks content that is a provider failure rather than something the agent
|
|
197
|
+
* said. webchat-turn.ts keys the failed-turn UI off this prefix, and
|
|
198
|
+
* agent-loop.ts keeps such content out of the conversation history.
|
|
199
|
+
*/
|
|
200
|
+
export const LLM_ERROR_PREFIX = "[LLM Error]"
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Turns a provider failure into something the user can act on.
|
|
204
|
+
*
|
|
205
|
+
* The raw SDK text is written for whoever is reading a stack trace: "429 status
|
|
206
|
+
* code (no body)" showed up verbatim in the chat and says nothing about what
|
|
207
|
+
* happened (the account hit its rate limit) or what to do about it. Statuses
|
|
208
|
+
* without a specific mapping keep the original message — a wrong explanation is
|
|
209
|
+
* worse than a technical one.
|
|
210
|
+
*/
|
|
211
|
+
export function describeProviderFailure(
|
|
212
|
+
err: unknown,
|
|
213
|
+
status: number | undefined,
|
|
214
|
+
provider: string,
|
|
215
|
+
cleanModel: string,
|
|
216
|
+
): string {
|
|
217
|
+
if (status === 404 || status === 410) {
|
|
218
|
+
return `El modelo "${cleanModel}" ya no existe en ${provider} (HTTP ${status}). `
|
|
219
|
+
+ `El proveedor lo retiró de su catálogo; reintentar no sirve. `
|
|
220
|
+
+ `Elige otro modelo en Ajustes → Proveedores.`
|
|
221
|
+
}
|
|
222
|
+
if (status === 429) {
|
|
223
|
+
return `${provider} está limitando las peticiones (HTTP 429) y los reintentos tampoco pasaron. `
|
|
224
|
+
+ `Es el límite de uso de tu cuenta, no un problema del modelo: esperá unos minutos, `
|
|
225
|
+
+ `revisa tu cuota con el proveedor, o cambiá de modelo en Ajustes → Proveedores.`
|
|
226
|
+
}
|
|
227
|
+
if (status === 401 || status === 403) {
|
|
228
|
+
return `${provider} rechazó la API key (HTTP ${status}). `
|
|
229
|
+
+ `Revisa que siga siendo válida y tenga acceso a "${cleanModel}" en Ajustes → Proveedores.`
|
|
230
|
+
}
|
|
231
|
+
return (err as Error).message
|
|
232
|
+
}
|
|
233
|
+
|
|
199
234
|
/** Provider SDKs disagree on where the HTTP status lands; check every shape we've seen. */
|
|
200
235
|
function extractErrorStatus(err: unknown): number | undefined {
|
|
201
236
|
const e = err as { status?: number; statusCode?: number; response?: { status?: number } }
|
|
@@ -208,10 +243,10 @@ function extractErrorStatus(err: unknown): number | undefined {
|
|
|
208
243
|
* Returns null when the DB has no usable LLM (e.g. fresh install before setup).
|
|
209
244
|
*/
|
|
210
245
|
export async function getDefaultLLM(): Promise<{ provider: string; model: string } | null> {
|
|
211
|
-
const { col, fromIndexable } = await import("../storage/hive")
|
|
212
|
-
const agentsCol = await col<import("../storage/collections").AgentDoc>("agents")
|
|
213
|
-
const modelsCol = await col<import("../storage/collections").ModelDoc>("models")
|
|
214
|
-
const providersCol = await col<import("../storage/collections").ProviderDoc>("providers")
|
|
246
|
+
const { col, fromIndexable } = await import("../storage/hive.ts")
|
|
247
|
+
const agentsCol = await col<import("../storage/collections.ts").AgentDoc>("agents")
|
|
248
|
+
const modelsCol = await col<import("../storage/collections.ts").ModelDoc>("models")
|
|
249
|
+
const providersCol = await col<import("../storage/collections.ts").ProviderDoc>("providers")
|
|
215
250
|
|
|
216
251
|
const coordinators = await agentsCol.findBy("role", "coordinator")
|
|
217
252
|
const coordinator = coordinators[0]
|
|
@@ -234,14 +269,34 @@ export async function getDefaultLLM(): Promise<{ provider: string; model: string
|
|
|
234
269
|
/**
|
|
235
270
|
* Resolve provider config from DB (decrypts API key).
|
|
236
271
|
*/
|
|
272
|
+
/**
|
|
273
|
+
* Credenciales y endpoint resueltos por quien llama, en vez de por el proceso.
|
|
274
|
+
*
|
|
275
|
+
* Sin esto, la única forma de elegir la key era el secret store de HiveDB o
|
|
276
|
+
* `process.env[PROVIDER_API_KEY]` — ambos globales al proceso. Un backend
|
|
277
|
+
* multi-tenant no tiene un proceso por inquilino: o mutaba `process.env` antes
|
|
278
|
+
* de cada llamada (y entonces dos workspaces concurrentes se pisaban la key), o
|
|
279
|
+
* levantaba un proceso por llamada sólo para aislarla. Pasar la credencial en la
|
|
280
|
+
* llamada elimina las dos cosas.
|
|
281
|
+
*
|
|
282
|
+
* Todo es opcional: lo que no venga acá se resuelve como siempre.
|
|
283
|
+
*/
|
|
284
|
+
export interface ProviderCredentials {
|
|
285
|
+
/** Reemplaza la key del secret store y la de `process.env`. */
|
|
286
|
+
apiKey?: string
|
|
287
|
+
/** Reemplaza el `base_url` de la fila del proveedor. */
|
|
288
|
+
baseUrl?: string
|
|
289
|
+
}
|
|
290
|
+
|
|
237
291
|
export async function resolveProviderConfig(
|
|
238
292
|
providerId: string,
|
|
239
|
-
modelId: string
|
|
293
|
+
modelId: string,
|
|
294
|
+
credentials?: ProviderCredentials
|
|
240
295
|
): Promise<Pick<LLMCallOptions, "provider" | "model" | "apiKey" | "baseUrl" | "numCtx" | "numGpu" | "contextWindow">> {
|
|
241
|
-
const { col } = await import("../storage/hive")
|
|
242
|
-
const { loadProviderApiKey } = await import("../storage/crypto")
|
|
243
|
-
const providersCol = await col<import("../storage/collections").ProviderDoc>("providers")
|
|
244
|
-
const modelsCol = await col<import("../storage/collections").ModelDoc>("models")
|
|
296
|
+
const { col } = await import("../storage/hive.ts")
|
|
297
|
+
const { loadProviderApiKey } = await import("../storage/crypto.ts")
|
|
298
|
+
const providersCol = await col<import("../storage/collections.ts").ProviderDoc>("providers")
|
|
299
|
+
const modelsCol = await col<import("../storage/collections.ts").ModelDoc>("models")
|
|
245
300
|
|
|
246
301
|
const providerEntry = await providersCol.get(providerId)
|
|
247
302
|
const providerRow = (providerEntry?.doc.enabled && providerEntry?.doc.active) ? providerEntry.doc : undefined
|
|
@@ -249,7 +304,13 @@ export async function resolveProviderConfig(
|
|
|
249
304
|
// Load model's context window for token budget management
|
|
250
305
|
const modelEntry = await modelsCol.get(modelId)
|
|
251
306
|
|
|
252
|
-
|
|
307
|
+
// La credencial de la llamada gana, y corta acá: si vino una key explícita no
|
|
308
|
+
// se consulta el secret store ni el entorno, así que un fallback global no
|
|
309
|
+
// puede colarse en el lugar de la del inquilino.
|
|
310
|
+
let apiKey = credentials?.apiKey
|
|
311
|
+
if (!apiKey) {
|
|
312
|
+
apiKey = await loadProviderApiKey(providerId)
|
|
313
|
+
}
|
|
253
314
|
if (!apiKey) {
|
|
254
315
|
apiKey = process.env[`${providerId.toUpperCase()}_API_KEY`] || ""
|
|
255
316
|
}
|
|
@@ -258,7 +319,7 @@ export async function resolveProviderConfig(
|
|
|
258
319
|
provider: providerId,
|
|
259
320
|
model: modelId,
|
|
260
321
|
apiKey,
|
|
261
|
-
baseUrl: providerRow?.base_url || undefined,
|
|
322
|
+
baseUrl: credentials?.baseUrl || providerRow?.base_url || undefined,
|
|
262
323
|
numCtx: providerRow?.num_ctx ?? undefined,
|
|
263
324
|
numGpu: providerRow?.num_gpu ?? undefined,
|
|
264
325
|
contextWindow: modelEntry?.doc.context_window ?? undefined,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { logger } from "../../utils/logger"
|
|
2
|
-
import { normalizeToolName, resolveMaxTokens, ensureArrayItems } from "./interface"
|
|
3
|
-
import type { LLMCallOptions, LLMProvider, LLMResponse, LLMToolCall, ThinkingBlock } from "./interface"
|
|
4
|
-
import type { ContentPart, LLMMessage } from "../llm-client"
|
|
1
|
+
import { logger } from "../../utils/logger.ts"
|
|
2
|
+
import { normalizeToolName, resolveMaxTokens, ensureArrayItems } from "./interface.ts"
|
|
3
|
+
import type { LLMCallOptions, LLMProvider, LLMResponse, LLMToolCall, ThinkingBlock } from "./interface.ts"
|
|
4
|
+
import type { ContentPart, LLMMessage } from "../llm-client.ts"
|
|
5
5
|
|
|
6
6
|
const log = logger.child("llm-client")
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { logger } from "../../utils/logger"
|
|
2
|
-
import { sanitizeMessages, resolveMaxTokens, ensureArrayItems } from "./interface"
|
|
3
|
-
import type { LLMCallOptions, LLMProvider, LLMResponse, LLMToolCall } from "./interface"
|
|
4
|
-
import type { ContentPart, LLMMessage } from "../llm-client"
|
|
1
|
+
import { logger } from "../../utils/logger.ts"
|
|
2
|
+
import { sanitizeMessages, resolveMaxTokens, ensureArrayItems } from "./interface.ts"
|
|
3
|
+
import type { LLMCallOptions, LLMProvider, LLMResponse, LLMToolCall } from "./interface.ts"
|
|
4
|
+
import type { ContentPart, LLMMessage } from "../llm-client.ts"
|
|
5
5
|
|
|
6
6
|
const log = logger.child("llm-client")
|
|
7
7
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { logger } from "../../utils/logger"
|
|
2
|
-
import { OpenAICompatBase } from "./openai-compat-base"
|
|
3
|
-
import type { LLMCallOptions, LLMResponse } from "./interface"
|
|
1
|
+
import { logger } from "../../utils/logger.ts"
|
|
2
|
+
import { OpenAICompatBase } from "./openai-compat-base.ts"
|
|
3
|
+
import type { LLMCallOptions, LLMResponse } from "./interface.ts"
|
|
4
4
|
|
|
5
5
|
const log = logger.child("llm-client")
|
|
6
6
|
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Shared types and utilities for LLM providers.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { LLMCallOptions, LLMMessage, LLMResponse, LLMToolCall, ContentPart, ThinkingBlock } from "../llm-client"
|
|
5
|
+
import type { LLMCallOptions, LLMMessage, LLMResponse, LLMToolCall, ContentPart, ThinkingBlock } from "../llm-client.ts"
|
|
6
6
|
export type { LLMCallOptions, LLMMessage, LLMResponse, LLMToolCall, ContentPart, ThinkingBlock }
|
|
7
7
|
|
|
8
|
-
import { logger } from "../../utils/logger"
|
|
8
|
+
import { logger } from "../../utils/logger.ts"
|
|
9
9
|
const log = logger.child("llm-client")
|
|
10
10
|
|
|
11
11
|
// ─── Provider interface ────────────────────────────────────────────────────────
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { logger } from "../../utils/logger"
|
|
2
|
-
import { sanitizeMessages, resolveMaxTokens, ensureArrayItems } from "./interface"
|
|
3
|
-
import type { LLMCallOptions, LLMProvider, LLMResponse, LLMToolCall } from "./interface"
|
|
4
|
-
import type { ContentPart, LLMMessage } from "../llm-client"
|
|
1
|
+
import { logger } from "../../utils/logger.ts"
|
|
2
|
+
import { sanitizeMessages, resolveMaxTokens, ensureArrayItems } from "./interface.ts"
|
|
3
|
+
import type { LLMCallOptions, LLMProvider, LLMResponse, LLMToolCall } from "./interface.ts"
|
|
4
|
+
import type { ContentPart, LLMMessage } from "../llm-client.ts"
|
|
5
5
|
|
|
6
6
|
const log = logger.child("llm-client")
|
|
7
7
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { logger } from "../../utils/logger"
|
|
1
|
+
import { logger } from "../../utils/logger.ts"
|
|
2
2
|
import {
|
|
3
3
|
sanitizeMessages, requiresTemperature1, OPENAI_COMPAT_BASE_URLS,
|
|
4
4
|
getProviderProfile, modelSupportsTools, normalizeToolName, normalizeToolSchema,
|
|
5
5
|
resolveMaxTokens,
|
|
6
|
-
} from "./interface"
|
|
7
|
-
import type { LLMCallOptions, LLMProvider, LLMResponse, LLMToolCall } from "./interface"
|
|
8
|
-
import type { ContentPart, LLMMessage } from "../llm-client"
|
|
6
|
+
} from "./interface.ts"
|
|
7
|
+
import type { LLMCallOptions, LLMProvider, LLMResponse, LLMToolCall } from "./interface.ts"
|
|
8
|
+
import type { ContentPart, LLMMessage } from "../llm-client.ts"
|
|
9
9
|
|
|
10
10
|
const log = logger.child("llm-client")
|
|
11
11
|
|
|
@@ -44,7 +44,11 @@ function compactBodyForContextOverflow(body: any, err: any): void {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
export abstract class OpenAICompatBase implements LLMProvider {
|
|
47
|
-
|
|
47
|
+
protected readonly providerName: string
|
|
48
|
+
|
|
49
|
+
constructor(providerName: string) {
|
|
50
|
+
this.providerName = providerName
|
|
51
|
+
}
|
|
48
52
|
|
|
49
53
|
/** Override to true when the provider requires reasoning_content to be round-tripped. */
|
|
50
54
|
protected needsReasoningRoundtrip(): boolean { return false }
|