@electric-ax/agents 0.4.17 → 0.4.18
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/dist/entrypoint.js +182 -31
- package/dist/index.cjs +181 -29
- package/dist/index.d.cts +75 -31
- package/dist/index.d.ts +75 -31
- package/dist/index.js +183 -32
- package/package.json +2 -2
package/dist/entrypoint.js
CHANGED
|
@@ -4,8 +4,8 @@ import { cacheStores, getGlobalDispatcher, interceptors, setGlobalDispatcher } f
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import pino from "pino";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import { MOONSHOT_API_BASE_URL, MOONSHOT_PROVIDER, appendPathToUrl, buildSkillSlashCommands, completeWithLowCostModel, createContextSkillLoader, createEntityRegistry, createPullWakeRunner, createRuntimeHandler, createSkillsRegistry, db, detectAvailableProviders, getMoonshotApiKey, getMoonshotModel, getMoonshotModels, pgSync, readCodexAccessToken, registerToolProvider, unregisterToolProvider } from "@electric-ax/agents-runtime";
|
|
8
|
-
import { braveSearchTool, createBashTool, createEditTool, createEventSourceTools, createFetchUrlTool, createReadFileTool, createScheduleTools, createSendTool, createWriteTool } from "@electric-ax/agents-runtime/tools";
|
|
7
|
+
import { GOAL_SLASH_COMMAND, MOONSHOT_API_BASE_URL, MOONSHOT_PROVIDER, appendPathToUrl, buildSkillSlashCommands, commentsCollection, completeWithLowCostModel, createContextSkillLoader, createEntityRegistry, createPullWakeRunner, createRuntimeHandler, createSkillsRegistry, db, detectAvailableProviders, dispatchGoalCommand, formatTokenCount, getMoonshotApiKey, getMoonshotModel, getMoonshotModels, isGoalCommandText, parseGoalCommand, pgSync, readCodexAccessToken, registerToolProvider, unregisterToolProvider } from "@electric-ax/agents-runtime";
|
|
8
|
+
import { braveSearchTool, createBashTool, createEditTool, createEventSourceTools, createFetchUrlTool, createMarkGoalCompleteTool, createReadFileTool, createScheduleTools, createSendTool, createWriteTool } from "@electric-ax/agents-runtime/tools";
|
|
9
9
|
import { chooseDefaultSandbox, isE2BAvailable, lazySandbox, remoteSandbox } from "@electric-ax/agents-runtime/sandbox";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import { createHash } from "node:crypto";
|
|
@@ -1087,25 +1087,66 @@ function filterChoicesByEnabledModels(choices, values) {
|
|
|
1087
1087
|
const filtered = choices.filter((choice) => enabled.has(choice.value));
|
|
1088
1088
|
return filtered.length > 0 ? filtered : choices;
|
|
1089
1089
|
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Anthropic-specific budget mapping for `reasoningEffort`.
|
|
1092
|
+
*
|
|
1093
|
+
* Anthropic's `thinking.budget_tokens` is a hard cap on tokens spent
|
|
1094
|
+
* inside the thinking block before the model must commit to its
|
|
1095
|
+
* answer. Docs require ≥ 1024; we scale from there. Numbers tuned so
|
|
1096
|
+
* `medium` is the spot most "show your work" requests land, and
|
|
1097
|
+
* `high` covers tougher reasoning without uncapped spend.
|
|
1098
|
+
*
|
|
1099
|
+
* Keep in sync with provider doc updates — Anthropic has shifted the
|
|
1100
|
+
* minimum once already (older models capped lower).
|
|
1101
|
+
*/
|
|
1102
|
+
const ANTHROPIC_THINKING_BUDGET_BY_EFFORT = {
|
|
1103
|
+
minimal: 1024,
|
|
1104
|
+
low: 2048,
|
|
1105
|
+
medium: 8192,
|
|
1106
|
+
high: 24576
|
|
1107
|
+
};
|
|
1090
1108
|
function withProviderPayloadDefaults(config, choice, reasoningEffort) {
|
|
1091
|
-
if (
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
+
if (!choice.reasoning) return config;
|
|
1110
|
+
if (choice.provider === `openai` || choice.provider === `openai-codex`) {
|
|
1111
|
+
const defaultEffort = choice.provider === `openai-codex` ? `low` : `minimal`;
|
|
1112
|
+
const effort = reasoningEffort === `minimal` && choice.provider === `openai-codex` ? `low` : reasoningEffort ?? defaultEffort;
|
|
1113
|
+
return {
|
|
1114
|
+
...config,
|
|
1115
|
+
onPayload: (payload) => {
|
|
1116
|
+
if (typeof payload !== `object` || payload === null) return void 0;
|
|
1117
|
+
const body = payload;
|
|
1118
|
+
const existingReasoning = typeof body.reasoning === `object` && body.reasoning !== null ? body.reasoning : {};
|
|
1119
|
+
return {
|
|
1120
|
+
...body,
|
|
1121
|
+
reasoning: {
|
|
1122
|
+
...existingReasoning,
|
|
1123
|
+
effort
|
|
1124
|
+
}
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
if (choice.provider === `anthropic`) {
|
|
1130
|
+
const effectiveEffort = reasoningEffort ?? `minimal`;
|
|
1131
|
+
const budgetTokens = ANTHROPIC_THINKING_BUDGET_BY_EFFORT[effectiveEffort];
|
|
1132
|
+
return {
|
|
1133
|
+
...config,
|
|
1134
|
+
onPayload: (payload) => {
|
|
1135
|
+
if (typeof payload !== `object` || payload === null) return void 0;
|
|
1136
|
+
const body = payload;
|
|
1137
|
+
const existingThinking = typeof body.thinking === `object` && body.thinking !== null ? body.thinking : {};
|
|
1138
|
+
return {
|
|
1139
|
+
...body,
|
|
1140
|
+
thinking: {
|
|
1141
|
+
...existingThinking,
|
|
1142
|
+
type: `enabled`,
|
|
1143
|
+
budget_tokens: budgetTokens
|
|
1144
|
+
}
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
return config;
|
|
1109
1150
|
}
|
|
1110
1151
|
function parseReasoningEffort(value) {
|
|
1111
1152
|
return value === `minimal` || value === `low` || value === `medium` || value === `high` ? value : null;
|
|
@@ -1369,7 +1410,18 @@ Workflow when forking yourself for parallel exploration:
|
|
|
1369
1410
|
Report outcomes faithfully. If a command failed, say so with the relevant output. If you didn't run a verification step, say that rather than implying you did. Don't hedge confirmed results with unnecessary disclaimers.
|
|
1370
1411
|
|
|
1371
1412
|
Working directory: ${workingDirectory}
|
|
1372
|
-
The current year is ${new Date().getFullYear()}
|
|
1413
|
+
The current year is ${new Date().getFullYear()}.${buildGoalGuidance(opts.activeGoal)}`;
|
|
1414
|
+
}
|
|
1415
|
+
function buildGoalGuidance(goal) {
|
|
1416
|
+
if (!goal) return ``;
|
|
1417
|
+
const budgetLine = goal.tokenBudget === null ? `unlimited` : `${goal.tokensUsed} / ${goal.tokenBudget} tokens used`;
|
|
1418
|
+
return `
|
|
1419
|
+
|
|
1420
|
+
# Active goal
|
|
1421
|
+
- Objective: ${goal.objective}
|
|
1422
|
+
- Token budget: ${budgetLine}
|
|
1423
|
+
|
|
1424
|
+
The user set this goal with /goal set. Work autonomously toward it: do NOT ask the user clarifying questions or pause for confirmation — make reasonable assumptions and proceed. When you believe the goal is met, call the \`mark_goal_complete\` tool. If you hit a blocker that genuinely requires the user (e.g. credentials, a destructive action), call \`mark_goal_complete\` with a summary explaining what's needed. The runtime will abort this run automatically if you exceed the token budget.`;
|
|
1373
1425
|
}
|
|
1374
1426
|
function getToolName(tool) {
|
|
1375
1427
|
if (typeof tool !== `object` || tool === null) return null;
|
|
@@ -1394,6 +1446,7 @@ function createHortonTools(sandbox, ctx, readSet, opts = {}) {
|
|
|
1394
1446
|
createObservePgSyncTool(ctx),
|
|
1395
1447
|
createSetTitleTool(ctx),
|
|
1396
1448
|
createSendTool(ctx.send, { selfEntityUrl: ctx.entityUrl }),
|
|
1449
|
+
...ctx.getGoal()?.status === `active` ? [createMarkGoalCompleteTool(ctx)] : [],
|
|
1397
1450
|
...opts.docsSearchTool ? [opts.docsSearchTool] : []
|
|
1398
1451
|
];
|
|
1399
1452
|
}
|
|
@@ -1462,11 +1515,58 @@ async function readAgentsMd(sandbox) {
|
|
|
1462
1515
|
return null;
|
|
1463
1516
|
}
|
|
1464
1517
|
}
|
|
1518
|
+
function extractWakeText(wake) {
|
|
1519
|
+
if (wake.type !== `inbox`) return null;
|
|
1520
|
+
const payload = wake.payload;
|
|
1521
|
+
if (typeof payload === `string`) return payload;
|
|
1522
|
+
if (payload && typeof payload === `object`) {
|
|
1523
|
+
const record = payload;
|
|
1524
|
+
if (typeof record.text === `string`) return record.text;
|
|
1525
|
+
if (typeof record.source === `string`) return record.source;
|
|
1526
|
+
}
|
|
1527
|
+
return null;
|
|
1528
|
+
}
|
|
1529
|
+
async function tryHandleSlashCommand(ctx, wake) {
|
|
1530
|
+
const text = extractWakeText(wake);
|
|
1531
|
+
if (text === null) return false;
|
|
1532
|
+
if (isGoalCommandText(text)) {
|
|
1533
|
+
const command = parseGoalCommand(text);
|
|
1534
|
+
const result = dispatchGoalCommand(ctx, command);
|
|
1535
|
+
if (result.message) {
|
|
1536
|
+
serverLog.info(`[horton ${ctx.entityUrl}] ${result.message}`);
|
|
1537
|
+
writeSlashCommandReply(ctx, result.message);
|
|
1538
|
+
}
|
|
1539
|
+
if (command.kind === `set`) await kickoffGoalRun(ctx);
|
|
1540
|
+
return result.handled;
|
|
1541
|
+
}
|
|
1542
|
+
return false;
|
|
1543
|
+
}
|
|
1544
|
+
const GOAL_KICKOFF_TEXT = `Start working toward the active goal now. Call \`mark_goal_complete\` when you believe it is done.`;
|
|
1545
|
+
async function kickoffGoalRun(ctx) {
|
|
1546
|
+
const goal = ctx.getGoal();
|
|
1547
|
+
if (!goal || goal.status !== `active`) return;
|
|
1548
|
+
try {
|
|
1549
|
+
await ctx.send(ctx.entityUrl, {
|
|
1550
|
+
kind: `goal_kickoff`,
|
|
1551
|
+
text: GOAL_KICKOFF_TEXT
|
|
1552
|
+
}, { type: `inbox` });
|
|
1553
|
+
} catch (err) {
|
|
1554
|
+
serverLog.warn(`[horton ${ctx.entityUrl}] failed to enqueue goal kickoff: ${err instanceof Error ? err.message : String(err)}`);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
function writeSlashCommandReply(ctx, text) {
|
|
1558
|
+
try {
|
|
1559
|
+
ctx.replyText(text);
|
|
1560
|
+
} catch (err) {
|
|
1561
|
+
serverLog.warn(`[horton ${ctx.entityUrl}] failed to render slash command reply: ${err instanceof Error ? err.message : String(err)}`);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1465
1564
|
function createAssistantHandler(options) {
|
|
1466
1565
|
const { streamFn, docsSupport, docsSearchTool, skillsRegistry, modelCatalog, docsUrl } = options;
|
|
1467
1566
|
const skillLoader = createContextSkillLoader(skillsRegistry, { slashCommandOwner: HORTON_SKILLS_SLASH_COMMAND_OWNER });
|
|
1468
1567
|
const hasSkills = skillLoader.hasSkills;
|
|
1469
1568
|
return async function assistantHandler(ctx, wake) {
|
|
1569
|
+
if (await tryHandleSlashCommand(ctx, wake)) return;
|
|
1470
1570
|
const loadedSkills = await skillLoader.load(ctx);
|
|
1471
1571
|
const readSet = new Set();
|
|
1472
1572
|
const modelConfig = resolveBuiltinModelConfig(modelCatalog, ctx.args);
|
|
@@ -1559,6 +1659,26 @@ function createAssistantHandler(options) {
|
|
|
1559
1659
|
}
|
|
1560
1660
|
}
|
|
1561
1661
|
});
|
|
1662
|
+
const goal = ctx.getGoal();
|
|
1663
|
+
const enforcedGoal = goal && goal.status === `active` ? goal : void 0;
|
|
1664
|
+
const activeGoalPromptInfo = enforcedGoal ? {
|
|
1665
|
+
objective: enforcedGoal.objective,
|
|
1666
|
+
tokenBudget: enforcedGoal.tokenBudget,
|
|
1667
|
+
tokensUsed: enforcedGoal.tokensUsed
|
|
1668
|
+
} : void 0;
|
|
1669
|
+
const budgetAbort = new AbortController();
|
|
1670
|
+
let runTokensUsed = enforcedGoal?.tokensUsed ?? 0;
|
|
1671
|
+
let budgetTripped = false;
|
|
1672
|
+
const onStepEnd = enforcedGoal ? (stats) => {
|
|
1673
|
+
if (budgetTripped) return;
|
|
1674
|
+
runTokensUsed += stats.uncachedInput + stats.output;
|
|
1675
|
+
ctx.updateGoalUsage(runTokensUsed);
|
|
1676
|
+
if (enforcedGoal.tokenBudget !== null && runTokensUsed >= enforcedGoal.tokenBudget) {
|
|
1677
|
+
budgetTripped = true;
|
|
1678
|
+
serverLog.info(`[horton ${ctx.entityUrl}] goal budget exhausted (${runTokensUsed} tokens) — aborting run`);
|
|
1679
|
+
budgetAbort.abort();
|
|
1680
|
+
}
|
|
1681
|
+
} : void 0;
|
|
1562
1682
|
ctx.useAgent({
|
|
1563
1683
|
systemPrompt: buildHortonSystemPrompt(sandboxCwd, {
|
|
1564
1684
|
hasDocsSupport: Boolean(docsSupport),
|
|
@@ -1567,13 +1687,26 @@ function createAssistantHandler(options) {
|
|
|
1567
1687
|
modelProvider: modelConfig.provider,
|
|
1568
1688
|
modelId: String(modelConfig.model),
|
|
1569
1689
|
hasEventSourceTools,
|
|
1570
|
-
hasScheduleTools
|
|
1690
|
+
hasScheduleTools,
|
|
1691
|
+
...activeGoalPromptInfo && { activeGoal: activeGoalPromptInfo }
|
|
1571
1692
|
}),
|
|
1572
1693
|
...modelConfig,
|
|
1573
1694
|
tools,
|
|
1574
|
-
...streamFn && { streamFn }
|
|
1695
|
+
...streamFn && { streamFn },
|
|
1696
|
+
...onStepEnd && { onStepEnd }
|
|
1575
1697
|
});
|
|
1576
|
-
|
|
1698
|
+
try {
|
|
1699
|
+
await ctx.agent.run(void 0, budgetAbort.signal);
|
|
1700
|
+
} catch (err) {
|
|
1701
|
+
if (!budgetTripped) throw err;
|
|
1702
|
+
serverLog.info(`[horton ${ctx.entityUrl}] agent.run aborted by budget enforcement`);
|
|
1703
|
+
}
|
|
1704
|
+
if (enforcedGoal) ctx.updateGoalUsage(runTokensUsed, budgetTripped ? { status: `budget_limited` } : void 0);
|
|
1705
|
+
if (budgetTripped && enforcedGoal && enforcedGoal.tokenBudget !== null) {
|
|
1706
|
+
const budget = enforcedGoal.tokenBudget;
|
|
1707
|
+
const suggestedNext = Math.max(budget * 2, budget + 1e4);
|
|
1708
|
+
writeSlashCommandReply(ctx, `⚠️ Stopped — goal hit the token budget (${formatTokenCount(runTokensUsed)} / ${formatTokenCount(budget)} tokens used). Raise the budget with \`/goal set "..." --tokens ${formatTokenCount(suggestedNext)}\`, or call \`/goal complete\` to finalize.`);
|
|
1709
|
+
}
|
|
1577
1710
|
await titlePromise;
|
|
1578
1711
|
};
|
|
1579
1712
|
}
|
|
@@ -1613,7 +1746,8 @@ function registerHorton(registry, options) {
|
|
|
1613
1746
|
subject_value: `user`,
|
|
1614
1747
|
permission: `manage`
|
|
1615
1748
|
}],
|
|
1616
|
-
|
|
1749
|
+
state: { comments: commentsCollection },
|
|
1750
|
+
slashCommands: [GOAL_SLASH_COMMAND, ...buildSkillSlashCommands(skillsRegistry)],
|
|
1617
1751
|
handler: assistantHandler
|
|
1618
1752
|
});
|
|
1619
1753
|
return [`horton`];
|
|
@@ -1797,6 +1931,7 @@ function registerWorker(registry, options) {
|
|
|
1797
1931
|
subject_value: `user`,
|
|
1798
1932
|
permission: `manage`
|
|
1799
1933
|
}],
|
|
1934
|
+
state: { comments: commentsCollection },
|
|
1800
1935
|
async handler(ctx) {
|
|
1801
1936
|
const args = parseWorkerArgs(ctx.args);
|
|
1802
1937
|
const readSet = new Set();
|
|
@@ -1848,7 +1983,7 @@ function createBuiltinElectricTools(custom) {
|
|
|
1848
1983
|
};
|
|
1849
1984
|
}
|
|
1850
1985
|
async function createBuiltinAgentHandler(options) {
|
|
1851
|
-
const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, enabledModelValues, createElectricTools, publicUrl, runtimeName, baseSkillsDir: baseSkillsDirOverride, serverHeaders, defaultDispatchPolicyForType } = options;
|
|
1986
|
+
const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, enabledModelValues, createElectricTools, publicUrl, runtimeName, baseSkillsDir: baseSkillsDirOverride, serverHeaders, defaultDispatchPolicyForType, dockerSandbox: dockerSandboxOpts } = options;
|
|
1852
1987
|
const modelCatalog = await createBuiltinModelCatalog({
|
|
1853
1988
|
allowMockFallback: Boolean(streamFn),
|
|
1854
1989
|
enabledModelValues
|
|
@@ -1884,7 +2019,7 @@ async function createBuiltinAgentHandler(options) {
|
|
|
1884
2019
|
modelCatalog
|
|
1885
2020
|
});
|
|
1886
2021
|
typeNames.push(`worker`);
|
|
1887
|
-
const { profiles: sandboxProfiles, shutdownSandboxes } = await buildBuiltinSandboxProfiles(cwd);
|
|
2022
|
+
const { profiles: sandboxProfiles, shutdownSandboxes } = await buildBuiltinSandboxProfiles(cwd, dockerSandboxOpts);
|
|
1888
2023
|
const runtime = createRuntimeHandler({
|
|
1889
2024
|
baseUrl: agentServerUrl,
|
|
1890
2025
|
serveEndpoint,
|
|
@@ -1904,7 +2039,8 @@ async function createBuiltinAgentHandler(options) {
|
|
|
1904
2039
|
registry,
|
|
1905
2040
|
typeNames,
|
|
1906
2041
|
skillsRegistry,
|
|
1907
|
-
shutdownSandboxes
|
|
2042
|
+
shutdownSandboxes,
|
|
2043
|
+
modelCatalog
|
|
1908
2044
|
};
|
|
1909
2045
|
}
|
|
1910
2046
|
async function registerBuiltinAgentTypes(bootstrap) {
|
|
@@ -1923,6 +2059,21 @@ function sweepOrphanedDockerSandboxesOnce(sweep) {
|
|
|
1923
2059
|
return dockerBootSweep;
|
|
1924
2060
|
}
|
|
1925
2061
|
/**
|
|
2062
|
+
* Merge the profile's working-directory mount with embedder docker options
|
|
2063
|
+
* into the option fragment spread into `dockerSandbox()`. An internal helper:
|
|
2064
|
+
* exported from this module so the unit test can import it, but intentionally
|
|
2065
|
+
* not re-exported from `index.ts` (not part of the package's public API).
|
|
2066
|
+
*/
|
|
2067
|
+
function resolveDockerSandboxOpts(cwdMount, custom) {
|
|
2068
|
+
const extraMounts = [...cwdMount ? [cwdMount] : [], ...custom?.extraMounts ?? []];
|
|
2069
|
+
return {
|
|
2070
|
+
...custom?.image !== void 0 && { image: custom.image },
|
|
2071
|
+
...custom?.allowFloatingTag !== void 0 && { allowFloatingTag: custom.allowFloatingTag },
|
|
2072
|
+
...custom?.env !== void 0 && { env: custom.env },
|
|
2073
|
+
...extraMounts.length > 0 && { extraMounts }
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
/**
|
|
1926
2077
|
* Built-in sandbox profiles. `local` is always available. `docker` is
|
|
1927
2078
|
* gated on Docker being reachable so a user without Docker installed
|
|
1928
2079
|
* sees only what works — the UI never offers a non-functional choice.
|
|
@@ -1932,7 +2083,7 @@ function sweepOrphanedDockerSandboxesOnce(sweep) {
|
|
|
1932
2083
|
* server must run on shutdown (the providers' debounced idle teardowns die
|
|
1933
2084
|
* with the process).
|
|
1934
2085
|
*/
|
|
1935
|
-
async function buildBuiltinSandboxProfiles(workingDirectory) {
|
|
2086
|
+
async function buildBuiltinSandboxProfiles(workingDirectory, dockerOpts) {
|
|
1936
2087
|
const profiles = [{
|
|
1937
2088
|
name: `local`,
|
|
1938
2089
|
label: `Local`,
|
|
@@ -1957,11 +2108,11 @@ async function buildBuiltinSandboxProfiles(workingDirectory) {
|
|
|
1957
2108
|
workingDirectory: `/work`,
|
|
1958
2109
|
factory: () => dockerSandbox({
|
|
1959
2110
|
initialNetworkPolicy: { mode: `allow-all` },
|
|
1960
|
-
|
|
2111
|
+
...resolveDockerSandboxOpts(cwd ? {
|
|
1961
2112
|
hostPath: cwd,
|
|
1962
2113
|
containerPath: `/work`,
|
|
1963
2114
|
readOnly: false
|
|
1964
|
-
}
|
|
2115
|
+
} : void 0, dockerOpts),
|
|
1965
2116
|
sandboxKey,
|
|
1966
2117
|
persistent,
|
|
1967
2118
|
owner,
|
package/dist/index.cjs
CHANGED
|
@@ -1093,25 +1093,66 @@ function filterChoicesByEnabledModels(choices, values) {
|
|
|
1093
1093
|
const filtered = choices.filter((choice) => enabled.has(choice.value));
|
|
1094
1094
|
return filtered.length > 0 ? filtered : choices;
|
|
1095
1095
|
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Anthropic-specific budget mapping for `reasoningEffort`.
|
|
1098
|
+
*
|
|
1099
|
+
* Anthropic's `thinking.budget_tokens` is a hard cap on tokens spent
|
|
1100
|
+
* inside the thinking block before the model must commit to its
|
|
1101
|
+
* answer. Docs require ≥ 1024; we scale from there. Numbers tuned so
|
|
1102
|
+
* `medium` is the spot most "show your work" requests land, and
|
|
1103
|
+
* `high` covers tougher reasoning without uncapped spend.
|
|
1104
|
+
*
|
|
1105
|
+
* Keep in sync with provider doc updates — Anthropic has shifted the
|
|
1106
|
+
* minimum once already (older models capped lower).
|
|
1107
|
+
*/
|
|
1108
|
+
const ANTHROPIC_THINKING_BUDGET_BY_EFFORT = {
|
|
1109
|
+
minimal: 1024,
|
|
1110
|
+
low: 2048,
|
|
1111
|
+
medium: 8192,
|
|
1112
|
+
high: 24576
|
|
1113
|
+
};
|
|
1096
1114
|
function withProviderPayloadDefaults(config, choice, reasoningEffort) {
|
|
1097
|
-
if (
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
+
if (!choice.reasoning) return config;
|
|
1116
|
+
if (choice.provider === `openai` || choice.provider === `openai-codex`) {
|
|
1117
|
+
const defaultEffort = choice.provider === `openai-codex` ? `low` : `minimal`;
|
|
1118
|
+
const effort = reasoningEffort === `minimal` && choice.provider === `openai-codex` ? `low` : reasoningEffort ?? defaultEffort;
|
|
1119
|
+
return {
|
|
1120
|
+
...config,
|
|
1121
|
+
onPayload: (payload) => {
|
|
1122
|
+
if (typeof payload !== `object` || payload === null) return void 0;
|
|
1123
|
+
const body = payload;
|
|
1124
|
+
const existingReasoning = typeof body.reasoning === `object` && body.reasoning !== null ? body.reasoning : {};
|
|
1125
|
+
return {
|
|
1126
|
+
...body,
|
|
1127
|
+
reasoning: {
|
|
1128
|
+
...existingReasoning,
|
|
1129
|
+
effort
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
if (choice.provider === `anthropic`) {
|
|
1136
|
+
const effectiveEffort = reasoningEffort ?? `minimal`;
|
|
1137
|
+
const budgetTokens = ANTHROPIC_THINKING_BUDGET_BY_EFFORT[effectiveEffort];
|
|
1138
|
+
return {
|
|
1139
|
+
...config,
|
|
1140
|
+
onPayload: (payload) => {
|
|
1141
|
+
if (typeof payload !== `object` || payload === null) return void 0;
|
|
1142
|
+
const body = payload;
|
|
1143
|
+
const existingThinking = typeof body.thinking === `object` && body.thinking !== null ? body.thinking : {};
|
|
1144
|
+
return {
|
|
1145
|
+
...body,
|
|
1146
|
+
thinking: {
|
|
1147
|
+
...existingThinking,
|
|
1148
|
+
type: `enabled`,
|
|
1149
|
+
budget_tokens: budgetTokens
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
return config;
|
|
1115
1156
|
}
|
|
1116
1157
|
function parseReasoningEffort(value) {
|
|
1117
1158
|
return value === `minimal` || value === `low` || value === `medium` || value === `high` ? value : null;
|
|
@@ -1376,7 +1417,18 @@ Workflow when forking yourself for parallel exploration:
|
|
|
1376
1417
|
Report outcomes faithfully. If a command failed, say so with the relevant output. If you didn't run a verification step, say that rather than implying you did. Don't hedge confirmed results with unnecessary disclaimers.
|
|
1377
1418
|
|
|
1378
1419
|
Working directory: ${workingDirectory}
|
|
1379
|
-
The current year is ${new Date().getFullYear()}
|
|
1420
|
+
The current year is ${new Date().getFullYear()}.${buildGoalGuidance(opts.activeGoal)}`;
|
|
1421
|
+
}
|
|
1422
|
+
function buildGoalGuidance(goal) {
|
|
1423
|
+
if (!goal) return ``;
|
|
1424
|
+
const budgetLine = goal.tokenBudget === null ? `unlimited` : `${goal.tokensUsed} / ${goal.tokenBudget} tokens used`;
|
|
1425
|
+
return `
|
|
1426
|
+
|
|
1427
|
+
# Active goal
|
|
1428
|
+
- Objective: ${goal.objective}
|
|
1429
|
+
- Token budget: ${budgetLine}
|
|
1430
|
+
|
|
1431
|
+
The user set this goal with /goal set. Work autonomously toward it: do NOT ask the user clarifying questions or pause for confirmation — make reasonable assumptions and proceed. When you believe the goal is met, call the \`mark_goal_complete\` tool. If you hit a blocker that genuinely requires the user (e.g. credentials, a destructive action), call \`mark_goal_complete\` with a summary explaining what's needed. The runtime will abort this run automatically if you exceed the token budget.`;
|
|
1380
1432
|
}
|
|
1381
1433
|
function getToolName(tool) {
|
|
1382
1434
|
if (typeof tool !== `object` || tool === null) return null;
|
|
@@ -1401,6 +1453,7 @@ function createHortonTools(sandbox, ctx, readSet, opts = {}) {
|
|
|
1401
1453
|
createObservePgSyncTool(ctx),
|
|
1402
1454
|
createSetTitleTool(ctx),
|
|
1403
1455
|
(0, __electric_ax_agents_runtime_tools.createSendTool)(ctx.send, { selfEntityUrl: ctx.entityUrl }),
|
|
1456
|
+
...ctx.getGoal()?.status === `active` ? [(0, __electric_ax_agents_runtime_tools.createMarkGoalCompleteTool)(ctx)] : [],
|
|
1404
1457
|
...opts.docsSearchTool ? [opts.docsSearchTool] : []
|
|
1405
1458
|
];
|
|
1406
1459
|
}
|
|
@@ -1469,11 +1522,58 @@ async function readAgentsMd(sandbox) {
|
|
|
1469
1522
|
return null;
|
|
1470
1523
|
}
|
|
1471
1524
|
}
|
|
1525
|
+
function extractWakeText(wake) {
|
|
1526
|
+
if (wake.type !== `inbox`) return null;
|
|
1527
|
+
const payload = wake.payload;
|
|
1528
|
+
if (typeof payload === `string`) return payload;
|
|
1529
|
+
if (payload && typeof payload === `object`) {
|
|
1530
|
+
const record = payload;
|
|
1531
|
+
if (typeof record.text === `string`) return record.text;
|
|
1532
|
+
if (typeof record.source === `string`) return record.source;
|
|
1533
|
+
}
|
|
1534
|
+
return null;
|
|
1535
|
+
}
|
|
1536
|
+
async function tryHandleSlashCommand(ctx, wake) {
|
|
1537
|
+
const text = extractWakeText(wake);
|
|
1538
|
+
if (text === null) return false;
|
|
1539
|
+
if ((0, __electric_ax_agents_runtime.isGoalCommandText)(text)) {
|
|
1540
|
+
const command = (0, __electric_ax_agents_runtime.parseGoalCommand)(text);
|
|
1541
|
+
const result = (0, __electric_ax_agents_runtime.dispatchGoalCommand)(ctx, command);
|
|
1542
|
+
if (result.message) {
|
|
1543
|
+
serverLog.info(`[horton ${ctx.entityUrl}] ${result.message}`);
|
|
1544
|
+
writeSlashCommandReply(ctx, result.message);
|
|
1545
|
+
}
|
|
1546
|
+
if (command.kind === `set`) await kickoffGoalRun(ctx);
|
|
1547
|
+
return result.handled;
|
|
1548
|
+
}
|
|
1549
|
+
return false;
|
|
1550
|
+
}
|
|
1551
|
+
const GOAL_KICKOFF_TEXT = `Start working toward the active goal now. Call \`mark_goal_complete\` when you believe it is done.`;
|
|
1552
|
+
async function kickoffGoalRun(ctx) {
|
|
1553
|
+
const goal = ctx.getGoal();
|
|
1554
|
+
if (!goal || goal.status !== `active`) return;
|
|
1555
|
+
try {
|
|
1556
|
+
await ctx.send(ctx.entityUrl, {
|
|
1557
|
+
kind: `goal_kickoff`,
|
|
1558
|
+
text: GOAL_KICKOFF_TEXT
|
|
1559
|
+
}, { type: `inbox` });
|
|
1560
|
+
} catch (err) {
|
|
1561
|
+
serverLog.warn(`[horton ${ctx.entityUrl}] failed to enqueue goal kickoff: ${err instanceof Error ? err.message : String(err)}`);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
function writeSlashCommandReply(ctx, text) {
|
|
1565
|
+
try {
|
|
1566
|
+
ctx.replyText(text);
|
|
1567
|
+
} catch (err) {
|
|
1568
|
+
serverLog.warn(`[horton ${ctx.entityUrl}] failed to render slash command reply: ${err instanceof Error ? err.message : String(err)}`);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1472
1571
|
function createAssistantHandler(options) {
|
|
1473
1572
|
const { streamFn, docsSupport, docsSearchTool, skillsRegistry, modelCatalog, docsUrl } = options;
|
|
1474
1573
|
const skillLoader = (0, __electric_ax_agents_runtime.createContextSkillLoader)(skillsRegistry, { slashCommandOwner: HORTON_SKILLS_SLASH_COMMAND_OWNER });
|
|
1475
1574
|
const hasSkills = skillLoader.hasSkills;
|
|
1476
1575
|
return async function assistantHandler(ctx, wake) {
|
|
1576
|
+
if (await tryHandleSlashCommand(ctx, wake)) return;
|
|
1477
1577
|
const loadedSkills = await skillLoader.load(ctx);
|
|
1478
1578
|
const readSet = new Set();
|
|
1479
1579
|
const modelConfig = resolveBuiltinModelConfig(modelCatalog, ctx.args);
|
|
@@ -1566,6 +1666,26 @@ function createAssistantHandler(options) {
|
|
|
1566
1666
|
}
|
|
1567
1667
|
}
|
|
1568
1668
|
});
|
|
1669
|
+
const goal = ctx.getGoal();
|
|
1670
|
+
const enforcedGoal = goal && goal.status === `active` ? goal : void 0;
|
|
1671
|
+
const activeGoalPromptInfo = enforcedGoal ? {
|
|
1672
|
+
objective: enforcedGoal.objective,
|
|
1673
|
+
tokenBudget: enforcedGoal.tokenBudget,
|
|
1674
|
+
tokensUsed: enforcedGoal.tokensUsed
|
|
1675
|
+
} : void 0;
|
|
1676
|
+
const budgetAbort = new AbortController();
|
|
1677
|
+
let runTokensUsed = enforcedGoal?.tokensUsed ?? 0;
|
|
1678
|
+
let budgetTripped = false;
|
|
1679
|
+
const onStepEnd = enforcedGoal ? (stats) => {
|
|
1680
|
+
if (budgetTripped) return;
|
|
1681
|
+
runTokensUsed += stats.uncachedInput + stats.output;
|
|
1682
|
+
ctx.updateGoalUsage(runTokensUsed);
|
|
1683
|
+
if (enforcedGoal.tokenBudget !== null && runTokensUsed >= enforcedGoal.tokenBudget) {
|
|
1684
|
+
budgetTripped = true;
|
|
1685
|
+
serverLog.info(`[horton ${ctx.entityUrl}] goal budget exhausted (${runTokensUsed} tokens) — aborting run`);
|
|
1686
|
+
budgetAbort.abort();
|
|
1687
|
+
}
|
|
1688
|
+
} : void 0;
|
|
1569
1689
|
ctx.useAgent({
|
|
1570
1690
|
systemPrompt: buildHortonSystemPrompt(sandboxCwd, {
|
|
1571
1691
|
hasDocsSupport: Boolean(docsSupport),
|
|
@@ -1574,13 +1694,26 @@ function createAssistantHandler(options) {
|
|
|
1574
1694
|
modelProvider: modelConfig.provider,
|
|
1575
1695
|
modelId: String(modelConfig.model),
|
|
1576
1696
|
hasEventSourceTools,
|
|
1577
|
-
hasScheduleTools
|
|
1697
|
+
hasScheduleTools,
|
|
1698
|
+
...activeGoalPromptInfo && { activeGoal: activeGoalPromptInfo }
|
|
1578
1699
|
}),
|
|
1579
1700
|
...modelConfig,
|
|
1580
1701
|
tools,
|
|
1581
|
-
...streamFn && { streamFn }
|
|
1702
|
+
...streamFn && { streamFn },
|
|
1703
|
+
...onStepEnd && { onStepEnd }
|
|
1582
1704
|
});
|
|
1583
|
-
|
|
1705
|
+
try {
|
|
1706
|
+
await ctx.agent.run(void 0, budgetAbort.signal);
|
|
1707
|
+
} catch (err) {
|
|
1708
|
+
if (!budgetTripped) throw err;
|
|
1709
|
+
serverLog.info(`[horton ${ctx.entityUrl}] agent.run aborted by budget enforcement`);
|
|
1710
|
+
}
|
|
1711
|
+
if (enforcedGoal) ctx.updateGoalUsage(runTokensUsed, budgetTripped ? { status: `budget_limited` } : void 0);
|
|
1712
|
+
if (budgetTripped && enforcedGoal && enforcedGoal.tokenBudget !== null) {
|
|
1713
|
+
const budget = enforcedGoal.tokenBudget;
|
|
1714
|
+
const suggestedNext = Math.max(budget * 2, budget + 1e4);
|
|
1715
|
+
writeSlashCommandReply(ctx, `⚠️ Stopped — goal hit the token budget (${(0, __electric_ax_agents_runtime.formatTokenCount)(runTokensUsed)} / ${(0, __electric_ax_agents_runtime.formatTokenCount)(budget)} tokens used). Raise the budget with \`/goal set "..." --tokens ${(0, __electric_ax_agents_runtime.formatTokenCount)(suggestedNext)}\`, or call \`/goal complete\` to finalize.`);
|
|
1716
|
+
}
|
|
1584
1717
|
await titlePromise;
|
|
1585
1718
|
};
|
|
1586
1719
|
}
|
|
@@ -1620,7 +1753,8 @@ function registerHorton(registry, options) {
|
|
|
1620
1753
|
subject_value: `user`,
|
|
1621
1754
|
permission: `manage`
|
|
1622
1755
|
}],
|
|
1623
|
-
|
|
1756
|
+
state: { comments: __electric_ax_agents_runtime.commentsCollection },
|
|
1757
|
+
slashCommands: [__electric_ax_agents_runtime.GOAL_SLASH_COMMAND, ...(0, __electric_ax_agents_runtime.buildSkillSlashCommands)(skillsRegistry)],
|
|
1624
1758
|
handler: assistantHandler
|
|
1625
1759
|
});
|
|
1626
1760
|
return [`horton`];
|
|
@@ -1804,6 +1938,7 @@ function registerWorker(registry, options) {
|
|
|
1804
1938
|
subject_value: `user`,
|
|
1805
1939
|
permission: `manage`
|
|
1806
1940
|
}],
|
|
1941
|
+
state: { comments: __electric_ax_agents_runtime.commentsCollection },
|
|
1807
1942
|
async handler(ctx) {
|
|
1808
1943
|
const args = parseWorkerArgs(ctx.args);
|
|
1809
1944
|
const readSet = new Set();
|
|
@@ -1856,7 +1991,7 @@ function createBuiltinElectricTools(custom) {
|
|
|
1856
1991
|
};
|
|
1857
1992
|
}
|
|
1858
1993
|
async function createBuiltinAgentHandler(options) {
|
|
1859
|
-
const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, enabledModelValues, createElectricTools, publicUrl, runtimeName, baseSkillsDir: baseSkillsDirOverride, serverHeaders, defaultDispatchPolicyForType } = options;
|
|
1994
|
+
const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, enabledModelValues, createElectricTools, publicUrl, runtimeName, baseSkillsDir: baseSkillsDirOverride, serverHeaders, defaultDispatchPolicyForType, dockerSandbox: dockerSandboxOpts } = options;
|
|
1860
1995
|
const modelCatalog = await createBuiltinModelCatalog({
|
|
1861
1996
|
allowMockFallback: Boolean(streamFn),
|
|
1862
1997
|
enabledModelValues
|
|
@@ -1892,7 +2027,7 @@ async function createBuiltinAgentHandler(options) {
|
|
|
1892
2027
|
modelCatalog
|
|
1893
2028
|
});
|
|
1894
2029
|
typeNames.push(`worker`);
|
|
1895
|
-
const { profiles: sandboxProfiles, shutdownSandboxes } = await buildBuiltinSandboxProfiles(cwd);
|
|
2030
|
+
const { profiles: sandboxProfiles, shutdownSandboxes } = await buildBuiltinSandboxProfiles(cwd, dockerSandboxOpts);
|
|
1896
2031
|
const runtime = (0, __electric_ax_agents_runtime.createRuntimeHandler)({
|
|
1897
2032
|
baseUrl: agentServerUrl,
|
|
1898
2033
|
serveEndpoint,
|
|
@@ -1912,7 +2047,8 @@ async function createBuiltinAgentHandler(options) {
|
|
|
1912
2047
|
registry,
|
|
1913
2048
|
typeNames,
|
|
1914
2049
|
skillsRegistry,
|
|
1915
|
-
shutdownSandboxes
|
|
2050
|
+
shutdownSandboxes,
|
|
2051
|
+
modelCatalog
|
|
1916
2052
|
};
|
|
1917
2053
|
}
|
|
1918
2054
|
async function createAgentHandler(agentServerUrl, workingDirectory, streamFn, createElectricTools, serveEndpoint) {
|
|
@@ -1941,6 +2077,21 @@ function sweepOrphanedDockerSandboxesOnce(sweep) {
|
|
|
1941
2077
|
return dockerBootSweep;
|
|
1942
2078
|
}
|
|
1943
2079
|
/**
|
|
2080
|
+
* Merge the profile's working-directory mount with embedder docker options
|
|
2081
|
+
* into the option fragment spread into `dockerSandbox()`. An internal helper:
|
|
2082
|
+
* exported from this module so the unit test can import it, but intentionally
|
|
2083
|
+
* not re-exported from `index.ts` (not part of the package's public API).
|
|
2084
|
+
*/
|
|
2085
|
+
function resolveDockerSandboxOpts(cwdMount, custom) {
|
|
2086
|
+
const extraMounts = [...cwdMount ? [cwdMount] : [], ...custom?.extraMounts ?? []];
|
|
2087
|
+
return {
|
|
2088
|
+
...custom?.image !== void 0 && { image: custom.image },
|
|
2089
|
+
...custom?.allowFloatingTag !== void 0 && { allowFloatingTag: custom.allowFloatingTag },
|
|
2090
|
+
...custom?.env !== void 0 && { env: custom.env },
|
|
2091
|
+
...extraMounts.length > 0 && { extraMounts }
|
|
2092
|
+
};
|
|
2093
|
+
}
|
|
2094
|
+
/**
|
|
1944
2095
|
* Built-in sandbox profiles. `local` is always available. `docker` is
|
|
1945
2096
|
* gated on Docker being reachable so a user without Docker installed
|
|
1946
2097
|
* sees only what works — the UI never offers a non-functional choice.
|
|
@@ -1950,7 +2101,7 @@ function sweepOrphanedDockerSandboxesOnce(sweep) {
|
|
|
1950
2101
|
* server must run on shutdown (the providers' debounced idle teardowns die
|
|
1951
2102
|
* with the process).
|
|
1952
2103
|
*/
|
|
1953
|
-
async function buildBuiltinSandboxProfiles(workingDirectory) {
|
|
2104
|
+
async function buildBuiltinSandboxProfiles(workingDirectory, dockerOpts) {
|
|
1954
2105
|
const profiles = [{
|
|
1955
2106
|
name: `local`,
|
|
1956
2107
|
label: `Local`,
|
|
@@ -1975,11 +2126,11 @@ async function buildBuiltinSandboxProfiles(workingDirectory) {
|
|
|
1975
2126
|
workingDirectory: `/work`,
|
|
1976
2127
|
factory: () => dockerSandbox({
|
|
1977
2128
|
initialNetworkPolicy: { mode: `allow-all` },
|
|
1978
|
-
|
|
2129
|
+
...resolveDockerSandboxOpts(cwd ? {
|
|
1979
2130
|
hostPath: cwd,
|
|
1980
2131
|
containerPath: `/work`,
|
|
1981
2132
|
readOnly: false
|
|
1982
|
-
}
|
|
2133
|
+
} : void 0, dockerOpts),
|
|
1983
2134
|
sandboxKey,
|
|
1984
2135
|
persistent,
|
|
1985
2136
|
owner,
|
|
@@ -2391,4 +2542,5 @@ exports.registerBuiltinAgentTypes = registerBuiltinAgentTypes
|
|
|
2391
2542
|
exports.registerHorton = registerHorton
|
|
2392
2543
|
exports.registerWorker = registerWorker
|
|
2393
2544
|
exports.resolveBuiltinAgentsEntrypointOptions = resolveBuiltinAgentsEntrypointOptions
|
|
2545
|
+
exports.resolveBuiltinModelConfig = resolveBuiltinModelConfig
|
|
2394
2546
|
exports.runBuiltinAgentsEntrypoint = runBuiltinAgentsEntrypoint
|
package/dist/index.d.cts
CHANGED
|
@@ -6,6 +6,36 @@ import { Sandbox } from "@electric-ax/agents-runtime/sandbox";
|
|
|
6
6
|
import { ChangeEvent } from "@durable-streams/state";
|
|
7
7
|
import { braveSearchTool } from "@electric-ax/agents-runtime/tools";
|
|
8
8
|
|
|
9
|
+
//#region src/model-catalog.d.ts
|
|
10
|
+
type BuiltinModelProvider = AvailableProvider;
|
|
11
|
+
type BuiltinModelInput = `text` | `image`;
|
|
12
|
+
interface BuiltinModelChoice {
|
|
13
|
+
provider: BuiltinModelProvider;
|
|
14
|
+
id: string;
|
|
15
|
+
label: string;
|
|
16
|
+
value: string;
|
|
17
|
+
reasoning: boolean;
|
|
18
|
+
input: Array<BuiltinModelInput>;
|
|
19
|
+
}
|
|
20
|
+
interface BuiltinModelCatalog {
|
|
21
|
+
choices: Array<BuiltinModelChoice>;
|
|
22
|
+
defaultChoice: BuiltinModelChoice;
|
|
23
|
+
}
|
|
24
|
+
interface BuiltinModelCatalogOptions {
|
|
25
|
+
allowMockFallback?: boolean;
|
|
26
|
+
enabledModelValues?: ReadonlyArray<string> | null;
|
|
27
|
+
}
|
|
28
|
+
declare const REASONING_EFFORT_VALUES: readonly ["auto", "minimal", "low", "medium", "high"];
|
|
29
|
+
type BuiltinReasoningEffort = (typeof REASONING_EFFORT_VALUES)[number];
|
|
30
|
+
type ExplicitReasoningEffort = Exclude<BuiltinReasoningEffort, `auto`>;
|
|
31
|
+
type BuiltinAgentModelConfig = Pick<AgentConfig, `model` | `provider` | `onPayload` | `getApiKey`> & {
|
|
32
|
+
reasoningEffort?: ExplicitReasoningEffort;
|
|
33
|
+
};
|
|
34
|
+
declare function builtinModelProviderLabel(provider: BuiltinModelProvider): string;
|
|
35
|
+
declare function listBuiltinModelChoices(providers: ReadonlyArray<BuiltinModelProvider>): Array<BuiltinModelChoice>;
|
|
36
|
+
declare function resolveBuiltinModelConfig(catalog: BuiltinModelCatalog, args: Readonly<Record<string, unknown>>): BuiltinAgentModelConfig;
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
9
39
|
//#region src/bootstrap.d.ts
|
|
10
40
|
declare const DEFAULT_BUILTIN_AGENT_HANDLER_PATH = "/_electric/builtin-agent-handler";
|
|
11
41
|
interface AgentHandlerResult {
|
|
@@ -21,8 +51,38 @@ interface AgentHandlerResult {
|
|
|
21
51
|
* die with the process, which would leave containers running.
|
|
22
52
|
*/
|
|
23
53
|
shutdownSandboxes: (() => Promise<void>) | null;
|
|
54
|
+
/**
|
|
55
|
+
* Model catalog the built-in agents resolve `model` args against — lets
|
|
56
|
+
* embedders register sibling agent types with the same model resolution.
|
|
57
|
+
*/
|
|
58
|
+
modelCatalog: BuiltinModelCatalog;
|
|
24
59
|
}
|
|
25
60
|
type BuiltinElectricToolsFactory = NonNullable<ProcessWakeConfig[`createElectricTools`]>;
|
|
61
|
+
/** Mount spec mirroring `DockerSandboxOpts['extraMounts']` items. */
|
|
62
|
+
interface BuiltinDockerSandboxMount {
|
|
63
|
+
hostPath: string;
|
|
64
|
+
containerPath: string;
|
|
65
|
+
readOnly?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Embedder customization for the built-in `docker` sandbox profile.
|
|
69
|
+
* Threads straight into `dockerSandbox()` (which already supports these);
|
|
70
|
+
* custom `extraMounts` are appended after the working-directory mount.
|
|
71
|
+
* These are embedder/operator-trust inputs: `extraMounts` is subject to the
|
|
72
|
+
* runtime's docker-socket guard, and `env` is passed verbatim into the
|
|
73
|
+
* container.
|
|
74
|
+
*
|
|
75
|
+
* Note: custom `extraMounts` must not target the working-directory container
|
|
76
|
+
* path (`/work`) — it collides with the cwd mount and fails at container-create
|
|
77
|
+
* time with an opaque docker error.
|
|
78
|
+
*/
|
|
79
|
+
interface BuiltinDockerSandboxOptions {
|
|
80
|
+
/** Digest-pinned image unless `allowFloatingTag` is set. */
|
|
81
|
+
image?: string;
|
|
82
|
+
allowFloatingTag?: boolean;
|
|
83
|
+
env?: Record<string, string>;
|
|
84
|
+
extraMounts?: Array<BuiltinDockerSandboxMount>;
|
|
85
|
+
}
|
|
26
86
|
interface BuiltinAgentHandlerOptions {
|
|
27
87
|
agentServerUrl: string;
|
|
28
88
|
serveEndpoint?: string;
|
|
@@ -36,6 +96,8 @@ interface BuiltinAgentHandlerOptions {
|
|
|
36
96
|
serverHeaders?: HeadersProvider;
|
|
37
97
|
defaultDispatchPolicyForType?: (typeName: string) => DispatchPolicy | undefined;
|
|
38
98
|
createElectricTools?: BuiltinElectricToolsFactory;
|
|
99
|
+
/** Customize the built-in `docker` sandbox profile (image, env, mounts). */
|
|
100
|
+
dockerSandbox?: BuiltinDockerSandboxOptions;
|
|
39
101
|
}
|
|
40
102
|
declare function createBuiltinElectricTools(custom?: BuiltinElectricToolsFactory): BuiltinElectricToolsFactory;
|
|
41
103
|
declare function createBuiltinAgentHandler(options: BuiltinAgentHandlerOptions): Promise<AgentHandlerResult | null>;
|
|
@@ -45,6 +107,12 @@ declare const registerAgentTypes: typeof registerBuiltinAgentTypes;
|
|
|
45
107
|
|
|
46
108
|
//#endregion
|
|
47
109
|
//#region src/durable-streams-cache.d.ts
|
|
110
|
+
/**
|
|
111
|
+
* Merge the profile's working-directory mount with embedder docker options
|
|
112
|
+
* into the option fragment spread into `dockerSandbox()`. An internal helper:
|
|
113
|
+
* exported from this module so the unit test can import it, but intentionally
|
|
114
|
+
* not re-exported from `index.ts` (not part of the package's public API).
|
|
115
|
+
*/
|
|
48
116
|
type DurableStreamsFetchCacheOptions = false | {
|
|
49
117
|
store?: `memory` | `sqlite`;
|
|
50
118
|
sqliteLocation?: string;
|
|
@@ -160,40 +228,15 @@ declare function runBuiltinAgentsEntrypoint({
|
|
|
160
228
|
url: string;
|
|
161
229
|
}>;
|
|
162
230
|
|
|
163
|
-
//#endregion
|
|
164
|
-
//#region src/model-catalog.d.ts
|
|
165
|
-
type BuiltinModelProvider = AvailableProvider;
|
|
166
|
-
type BuiltinModelInput = `text` | `image`;
|
|
167
|
-
interface BuiltinModelChoice {
|
|
168
|
-
provider: BuiltinModelProvider;
|
|
169
|
-
id: string;
|
|
170
|
-
label: string;
|
|
171
|
-
value: string;
|
|
172
|
-
reasoning: boolean;
|
|
173
|
-
input: Array<BuiltinModelInput>;
|
|
174
|
-
}
|
|
175
|
-
interface BuiltinModelCatalog {
|
|
176
|
-
choices: Array<BuiltinModelChoice>;
|
|
177
|
-
defaultChoice: BuiltinModelChoice;
|
|
178
|
-
}
|
|
179
|
-
interface BuiltinModelCatalogOptions {
|
|
180
|
-
allowMockFallback?: boolean;
|
|
181
|
-
enabledModelValues?: ReadonlyArray<string> | null;
|
|
182
|
-
}
|
|
183
|
-
declare const REASONING_EFFORT_VALUES: readonly ["auto", "minimal", "low", "medium", "high"];
|
|
184
|
-
type BuiltinReasoningEffort = (typeof REASONING_EFFORT_VALUES)[number];
|
|
185
|
-
type ExplicitReasoningEffort = Exclude<BuiltinReasoningEffort, `auto`>;
|
|
186
|
-
type BuiltinAgentModelConfig = Pick<AgentConfig, `model` | `provider` | `onPayload` | `getApiKey`> & {
|
|
187
|
-
reasoningEffort?: ExplicitReasoningEffort;
|
|
188
|
-
};
|
|
189
|
-
declare function builtinModelProviderLabel(provider: BuiltinModelProvider): string;
|
|
190
|
-
declare function listBuiltinModelChoices(providers: ReadonlyArray<BuiltinModelProvider>): Array<BuiltinModelChoice>;
|
|
191
|
-
declare function resolveBuiltinModelConfig(catalog: BuiltinModelCatalog, args: Readonly<Record<string, unknown>>): BuiltinAgentModelConfig;
|
|
192
|
-
|
|
193
231
|
//#endregion
|
|
194
232
|
//#region src/agents/horton.d.ts
|
|
195
233
|
declare const HORTON_MODEL = "claude-sonnet-4-6";
|
|
196
234
|
declare function generateTitle(userMessage: string, llmCall: (prompt: string) => Promise<string>, onFallback?: (reason: string) => void): Promise<string>;
|
|
235
|
+
interface ActiveGoalPromptInfo {
|
|
236
|
+
objective: string;
|
|
237
|
+
tokenBudget: number | null;
|
|
238
|
+
tokensUsed: number;
|
|
239
|
+
}
|
|
197
240
|
declare function buildHortonSystemPrompt(workingDirectory: string, opts?: {
|
|
198
241
|
hasDocsSupport?: boolean;
|
|
199
242
|
hasEventSourceTools?: boolean;
|
|
@@ -202,6 +245,7 @@ declare function buildHortonSystemPrompt(workingDirectory: string, opts?: {
|
|
|
202
245
|
docsUrl?: string;
|
|
203
246
|
modelProvider?: string;
|
|
204
247
|
modelId?: string;
|
|
248
|
+
activeGoal?: ActiveGoalPromptInfo;
|
|
205
249
|
}): string;
|
|
206
250
|
declare function createHortonTools(sandbox: Sandbox, ctx: HandlerContext, readSet: Set<string>, opts?: {
|
|
207
251
|
docsSearchTool?: AgentTool$1;
|
|
@@ -254,4 +298,4 @@ declare function createHortonDocsSupport(workingDirectory: string, opts?: {
|
|
|
254
298
|
}): HortonDocsSupport | null;
|
|
255
299
|
|
|
256
300
|
//#endregion
|
|
257
|
-
export { AgentHandlerResult, BuiltinAgentHandlerOptions, BuiltinAgentsEntrypointOptions, BuiltinAgentsEntrypointServer, BuiltinAgentsServer, BuiltinAgentsServerOptions, BuiltinElectricToolsFactory, BuiltinModelCatalogOptions, BuiltinModelChoice, BuiltinModelProvider, DEFAULT_BUILTIN_AGENT_HANDLER_PATH, HORTON_MODEL, McpConfig, McpListedEntry, McpRegistry, McpServerConfig, RegistrySnapshot, RegistrySubscriber, RunBuiltinAgentsEntrypointOptions, WORKER_TOOL_NAMES, WorkerToolName, braveSearchTool, buildHortonSystemPrompt, builtinModelProviderLabel, createAgentHandler, createBuiltinAgentHandler, createBuiltinElectricTools, createForkTool, createHortonDocsSupport, createHortonTools, createSpawnWorkerTool, generateTitle, listBuiltinModelChoices, registerAgentTypes, registerBuiltinAgentTypes, registerHorton, registerWorker, resolveBuiltinAgentsEntrypointOptions, runBuiltinAgentsEntrypoint };
|
|
301
|
+
export { AgentHandlerResult, BuiltinAgentHandlerOptions, BuiltinAgentModelConfig, BuiltinAgentsEntrypointOptions, BuiltinAgentsEntrypointServer, BuiltinAgentsServer, BuiltinAgentsServerOptions, BuiltinDockerSandboxMount, BuiltinDockerSandboxOptions, BuiltinElectricToolsFactory, BuiltinModelCatalog, BuiltinModelCatalogOptions, BuiltinModelChoice, BuiltinModelProvider, DEFAULT_BUILTIN_AGENT_HANDLER_PATH, HORTON_MODEL, McpConfig, McpListedEntry, McpRegistry, McpServerConfig, RegistrySnapshot, RegistrySubscriber, RunBuiltinAgentsEntrypointOptions, WORKER_TOOL_NAMES, WorkerToolName, braveSearchTool, buildHortonSystemPrompt, builtinModelProviderLabel, createAgentHandler, createBuiltinAgentHandler, createBuiltinElectricTools, createForkTool, createHortonDocsSupport, createHortonTools, createSpawnWorkerTool, generateTitle, listBuiltinModelChoices, registerAgentTypes, registerBuiltinAgentTypes, registerHorton, registerWorker, resolveBuiltinAgentsEntrypointOptions, resolveBuiltinModelConfig, runBuiltinAgentsEntrypoint };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,36 @@ import { AgentTool as AgentTool$1, StreamFn } from "@mariozechner/pi-agent-core"
|
|
|
6
6
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
7
7
|
import { ChangeEvent } from "@durable-streams/state";
|
|
8
8
|
|
|
9
|
+
//#region src/model-catalog.d.ts
|
|
10
|
+
type BuiltinModelProvider = AvailableProvider;
|
|
11
|
+
type BuiltinModelInput = `text` | `image`;
|
|
12
|
+
interface BuiltinModelChoice {
|
|
13
|
+
provider: BuiltinModelProvider;
|
|
14
|
+
id: string;
|
|
15
|
+
label: string;
|
|
16
|
+
value: string;
|
|
17
|
+
reasoning: boolean;
|
|
18
|
+
input: Array<BuiltinModelInput>;
|
|
19
|
+
}
|
|
20
|
+
interface BuiltinModelCatalog {
|
|
21
|
+
choices: Array<BuiltinModelChoice>;
|
|
22
|
+
defaultChoice: BuiltinModelChoice;
|
|
23
|
+
}
|
|
24
|
+
interface BuiltinModelCatalogOptions {
|
|
25
|
+
allowMockFallback?: boolean;
|
|
26
|
+
enabledModelValues?: ReadonlyArray<string> | null;
|
|
27
|
+
}
|
|
28
|
+
declare const REASONING_EFFORT_VALUES: readonly ["auto", "minimal", "low", "medium", "high"];
|
|
29
|
+
type BuiltinReasoningEffort = (typeof REASONING_EFFORT_VALUES)[number];
|
|
30
|
+
type ExplicitReasoningEffort = Exclude<BuiltinReasoningEffort, `auto`>;
|
|
31
|
+
type BuiltinAgentModelConfig = Pick<AgentConfig, `model` | `provider` | `onPayload` | `getApiKey`> & {
|
|
32
|
+
reasoningEffort?: ExplicitReasoningEffort;
|
|
33
|
+
};
|
|
34
|
+
declare function builtinModelProviderLabel(provider: BuiltinModelProvider): string;
|
|
35
|
+
declare function listBuiltinModelChoices(providers: ReadonlyArray<BuiltinModelProvider>): Array<BuiltinModelChoice>;
|
|
36
|
+
declare function resolveBuiltinModelConfig(catalog: BuiltinModelCatalog, args: Readonly<Record<string, unknown>>): BuiltinAgentModelConfig;
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
9
39
|
//#region src/bootstrap.d.ts
|
|
10
40
|
declare const DEFAULT_BUILTIN_AGENT_HANDLER_PATH = "/_electric/builtin-agent-handler";
|
|
11
41
|
interface AgentHandlerResult {
|
|
@@ -21,8 +51,38 @@ interface AgentHandlerResult {
|
|
|
21
51
|
* die with the process, which would leave containers running.
|
|
22
52
|
*/
|
|
23
53
|
shutdownSandboxes: (() => Promise<void>) | null;
|
|
54
|
+
/**
|
|
55
|
+
* Model catalog the built-in agents resolve `model` args against — lets
|
|
56
|
+
* embedders register sibling agent types with the same model resolution.
|
|
57
|
+
*/
|
|
58
|
+
modelCatalog: BuiltinModelCatalog;
|
|
24
59
|
}
|
|
25
60
|
type BuiltinElectricToolsFactory = NonNullable<ProcessWakeConfig[`createElectricTools`]>;
|
|
61
|
+
/** Mount spec mirroring `DockerSandboxOpts['extraMounts']` items. */
|
|
62
|
+
interface BuiltinDockerSandboxMount {
|
|
63
|
+
hostPath: string;
|
|
64
|
+
containerPath: string;
|
|
65
|
+
readOnly?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Embedder customization for the built-in `docker` sandbox profile.
|
|
69
|
+
* Threads straight into `dockerSandbox()` (which already supports these);
|
|
70
|
+
* custom `extraMounts` are appended after the working-directory mount.
|
|
71
|
+
* These are embedder/operator-trust inputs: `extraMounts` is subject to the
|
|
72
|
+
* runtime's docker-socket guard, and `env` is passed verbatim into the
|
|
73
|
+
* container.
|
|
74
|
+
*
|
|
75
|
+
* Note: custom `extraMounts` must not target the working-directory container
|
|
76
|
+
* path (`/work`) — it collides with the cwd mount and fails at container-create
|
|
77
|
+
* time with an opaque docker error.
|
|
78
|
+
*/
|
|
79
|
+
interface BuiltinDockerSandboxOptions {
|
|
80
|
+
/** Digest-pinned image unless `allowFloatingTag` is set. */
|
|
81
|
+
image?: string;
|
|
82
|
+
allowFloatingTag?: boolean;
|
|
83
|
+
env?: Record<string, string>;
|
|
84
|
+
extraMounts?: Array<BuiltinDockerSandboxMount>;
|
|
85
|
+
}
|
|
26
86
|
interface BuiltinAgentHandlerOptions {
|
|
27
87
|
agentServerUrl: string;
|
|
28
88
|
serveEndpoint?: string;
|
|
@@ -36,6 +96,8 @@ interface BuiltinAgentHandlerOptions {
|
|
|
36
96
|
serverHeaders?: HeadersProvider;
|
|
37
97
|
defaultDispatchPolicyForType?: (typeName: string) => DispatchPolicy | undefined;
|
|
38
98
|
createElectricTools?: BuiltinElectricToolsFactory;
|
|
99
|
+
/** Customize the built-in `docker` sandbox profile (image, env, mounts). */
|
|
100
|
+
dockerSandbox?: BuiltinDockerSandboxOptions;
|
|
39
101
|
}
|
|
40
102
|
declare function createBuiltinElectricTools(custom?: BuiltinElectricToolsFactory): BuiltinElectricToolsFactory;
|
|
41
103
|
declare function createBuiltinAgentHandler(options: BuiltinAgentHandlerOptions): Promise<AgentHandlerResult | null>;
|
|
@@ -45,6 +107,12 @@ declare const registerAgentTypes: typeof registerBuiltinAgentTypes;
|
|
|
45
107
|
|
|
46
108
|
//#endregion
|
|
47
109
|
//#region src/durable-streams-cache.d.ts
|
|
110
|
+
/**
|
|
111
|
+
* Merge the profile's working-directory mount with embedder docker options
|
|
112
|
+
* into the option fragment spread into `dockerSandbox()`. An internal helper:
|
|
113
|
+
* exported from this module so the unit test can import it, but intentionally
|
|
114
|
+
* not re-exported from `index.ts` (not part of the package's public API).
|
|
115
|
+
*/
|
|
48
116
|
type DurableStreamsFetchCacheOptions = false | {
|
|
49
117
|
store?: `memory` | `sqlite`;
|
|
50
118
|
sqliteLocation?: string;
|
|
@@ -160,40 +228,15 @@ declare function runBuiltinAgentsEntrypoint({
|
|
|
160
228
|
url: string;
|
|
161
229
|
}>;
|
|
162
230
|
|
|
163
|
-
//#endregion
|
|
164
|
-
//#region src/model-catalog.d.ts
|
|
165
|
-
type BuiltinModelProvider = AvailableProvider;
|
|
166
|
-
type BuiltinModelInput = `text` | `image`;
|
|
167
|
-
interface BuiltinModelChoice {
|
|
168
|
-
provider: BuiltinModelProvider;
|
|
169
|
-
id: string;
|
|
170
|
-
label: string;
|
|
171
|
-
value: string;
|
|
172
|
-
reasoning: boolean;
|
|
173
|
-
input: Array<BuiltinModelInput>;
|
|
174
|
-
}
|
|
175
|
-
interface BuiltinModelCatalog {
|
|
176
|
-
choices: Array<BuiltinModelChoice>;
|
|
177
|
-
defaultChoice: BuiltinModelChoice;
|
|
178
|
-
}
|
|
179
|
-
interface BuiltinModelCatalogOptions {
|
|
180
|
-
allowMockFallback?: boolean;
|
|
181
|
-
enabledModelValues?: ReadonlyArray<string> | null;
|
|
182
|
-
}
|
|
183
|
-
declare const REASONING_EFFORT_VALUES: readonly ["auto", "minimal", "low", "medium", "high"];
|
|
184
|
-
type BuiltinReasoningEffort = (typeof REASONING_EFFORT_VALUES)[number];
|
|
185
|
-
type ExplicitReasoningEffort = Exclude<BuiltinReasoningEffort, `auto`>;
|
|
186
|
-
type BuiltinAgentModelConfig = Pick<AgentConfig, `model` | `provider` | `onPayload` | `getApiKey`> & {
|
|
187
|
-
reasoningEffort?: ExplicitReasoningEffort;
|
|
188
|
-
};
|
|
189
|
-
declare function builtinModelProviderLabel(provider: BuiltinModelProvider): string;
|
|
190
|
-
declare function listBuiltinModelChoices(providers: ReadonlyArray<BuiltinModelProvider>): Array<BuiltinModelChoice>;
|
|
191
|
-
declare function resolveBuiltinModelConfig(catalog: BuiltinModelCatalog, args: Readonly<Record<string, unknown>>): BuiltinAgentModelConfig;
|
|
192
|
-
|
|
193
231
|
//#endregion
|
|
194
232
|
//#region src/agents/horton.d.ts
|
|
195
233
|
declare const HORTON_MODEL = "claude-sonnet-4-6";
|
|
196
234
|
declare function generateTitle(userMessage: string, llmCall: (prompt: string) => Promise<string>, onFallback?: (reason: string) => void): Promise<string>;
|
|
235
|
+
interface ActiveGoalPromptInfo {
|
|
236
|
+
objective: string;
|
|
237
|
+
tokenBudget: number | null;
|
|
238
|
+
tokensUsed: number;
|
|
239
|
+
}
|
|
197
240
|
declare function buildHortonSystemPrompt(workingDirectory: string, opts?: {
|
|
198
241
|
hasDocsSupport?: boolean;
|
|
199
242
|
hasEventSourceTools?: boolean;
|
|
@@ -202,6 +245,7 @@ declare function buildHortonSystemPrompt(workingDirectory: string, opts?: {
|
|
|
202
245
|
docsUrl?: string;
|
|
203
246
|
modelProvider?: string;
|
|
204
247
|
modelId?: string;
|
|
248
|
+
activeGoal?: ActiveGoalPromptInfo;
|
|
205
249
|
}): string;
|
|
206
250
|
declare function createHortonTools(sandbox: Sandbox, ctx: HandlerContext, readSet: Set<string>, opts?: {
|
|
207
251
|
docsSearchTool?: AgentTool$1;
|
|
@@ -254,4 +298,4 @@ declare function createHortonDocsSupport(workingDirectory: string, opts?: {
|
|
|
254
298
|
}): HortonDocsSupport | null;
|
|
255
299
|
|
|
256
300
|
//#endregion
|
|
257
|
-
export { AgentHandlerResult, BuiltinAgentHandlerOptions, BuiltinAgentsEntrypointOptions, BuiltinAgentsEntrypointServer, BuiltinAgentsServer, BuiltinAgentsServerOptions, BuiltinElectricToolsFactory, BuiltinModelCatalogOptions, BuiltinModelChoice, BuiltinModelProvider, DEFAULT_BUILTIN_AGENT_HANDLER_PATH, HORTON_MODEL, McpConfig, McpListedEntry, McpRegistry, McpServerConfig, RegistrySnapshot, RegistrySubscriber, RunBuiltinAgentsEntrypointOptions, WORKER_TOOL_NAMES, WorkerToolName, braveSearchTool, buildHortonSystemPrompt, builtinModelProviderLabel, createAgentHandler, createBuiltinAgentHandler, createBuiltinElectricTools, createForkTool, createHortonDocsSupport, createHortonTools, createSpawnWorkerTool, generateTitle, listBuiltinModelChoices, registerAgentTypes, registerBuiltinAgentTypes, registerHorton, registerWorker, resolveBuiltinAgentsEntrypointOptions, runBuiltinAgentsEntrypoint };
|
|
301
|
+
export { AgentHandlerResult, BuiltinAgentHandlerOptions, BuiltinAgentModelConfig, BuiltinAgentsEntrypointOptions, BuiltinAgentsEntrypointServer, BuiltinAgentsServer, BuiltinAgentsServerOptions, BuiltinDockerSandboxMount, BuiltinDockerSandboxOptions, BuiltinElectricToolsFactory, BuiltinModelCatalog, BuiltinModelCatalogOptions, BuiltinModelChoice, BuiltinModelProvider, DEFAULT_BUILTIN_AGENT_HANDLER_PATH, HORTON_MODEL, McpConfig, McpListedEntry, McpRegistry, McpServerConfig, RegistrySnapshot, RegistrySubscriber, RunBuiltinAgentsEntrypointOptions, WORKER_TOOL_NAMES, WorkerToolName, braveSearchTool, buildHortonSystemPrompt, builtinModelProviderLabel, createAgentHandler, createBuiltinAgentHandler, createBuiltinElectricTools, createForkTool, createHortonDocsSupport, createHortonTools, createSpawnWorkerTool, generateTitle, listBuiltinModelChoices, registerAgentTypes, registerBuiltinAgentTypes, registerHorton, registerWorker, resolveBuiltinAgentsEntrypointOptions, resolveBuiltinModelConfig, runBuiltinAgentsEntrypoint };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { mergeElectricPrincipalHeader } from "./server-headers-KD5yHFYT.js";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { MOONSHOT_API_BASE_URL, MOONSHOT_PROVIDER, appendPathToUrl, buildSkillSlashCommands, completeWithLowCostModel, createContextSkillLoader, createEntityRegistry, createPullWakeRunner, createRuntimeHandler, createSkillsRegistry, db, detectAvailableProviders, getMoonshotApiKey, getMoonshotModel, getMoonshotModels, pgSync, readCodexAccessToken, registerToolProvider, unregisterToolProvider } from "@electric-ax/agents-runtime";
|
|
5
|
-
import { braveSearchTool, braveSearchTool as braveSearchTool$1, createBashTool, createEditTool, createEventSourceTools, createFetchUrlTool, createReadFileTool, createScheduleTools, createSendTool, createWriteTool } from "@electric-ax/agents-runtime/tools";
|
|
4
|
+
import { GOAL_SLASH_COMMAND, MOONSHOT_API_BASE_URL, MOONSHOT_PROVIDER, appendPathToUrl, buildSkillSlashCommands, commentsCollection, completeWithLowCostModel, createContextSkillLoader, createEntityRegistry, createPullWakeRunner, createRuntimeHandler, createSkillsRegistry, db, detectAvailableProviders, dispatchGoalCommand, formatTokenCount, getMoonshotApiKey, getMoonshotModel, getMoonshotModels, isGoalCommandText, parseGoalCommand, pgSync, readCodexAccessToken, registerToolProvider, unregisterToolProvider } from "@electric-ax/agents-runtime";
|
|
5
|
+
import { braveSearchTool, braveSearchTool as braveSearchTool$1, createBashTool, createEditTool, createEventSourceTools, createFetchUrlTool, createMarkGoalCompleteTool, createReadFileTool, createScheduleTools, createSendTool, createWriteTool } from "@electric-ax/agents-runtime/tools";
|
|
6
6
|
import { chooseDefaultSandbox, isE2BAvailable, lazySandbox, remoteSandbox } from "@electric-ax/agents-runtime/sandbox";
|
|
7
7
|
import fsSync from "node:fs";
|
|
8
8
|
import pino from "pino";
|
|
@@ -1069,25 +1069,66 @@ function filterChoicesByEnabledModels(choices, values) {
|
|
|
1069
1069
|
const filtered = choices.filter((choice) => enabled.has(choice.value));
|
|
1070
1070
|
return filtered.length > 0 ? filtered : choices;
|
|
1071
1071
|
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Anthropic-specific budget mapping for `reasoningEffort`.
|
|
1074
|
+
*
|
|
1075
|
+
* Anthropic's `thinking.budget_tokens` is a hard cap on tokens spent
|
|
1076
|
+
* inside the thinking block before the model must commit to its
|
|
1077
|
+
* answer. Docs require ≥ 1024; we scale from there. Numbers tuned so
|
|
1078
|
+
* `medium` is the spot most "show your work" requests land, and
|
|
1079
|
+
* `high` covers tougher reasoning without uncapped spend.
|
|
1080
|
+
*
|
|
1081
|
+
* Keep in sync with provider doc updates — Anthropic has shifted the
|
|
1082
|
+
* minimum once already (older models capped lower).
|
|
1083
|
+
*/
|
|
1084
|
+
const ANTHROPIC_THINKING_BUDGET_BY_EFFORT = {
|
|
1085
|
+
minimal: 1024,
|
|
1086
|
+
low: 2048,
|
|
1087
|
+
medium: 8192,
|
|
1088
|
+
high: 24576
|
|
1089
|
+
};
|
|
1072
1090
|
function withProviderPayloadDefaults(config, choice, reasoningEffort) {
|
|
1073
|
-
if (
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
+
if (!choice.reasoning) return config;
|
|
1092
|
+
if (choice.provider === `openai` || choice.provider === `openai-codex`) {
|
|
1093
|
+
const defaultEffort = choice.provider === `openai-codex` ? `low` : `minimal`;
|
|
1094
|
+
const effort = reasoningEffort === `minimal` && choice.provider === `openai-codex` ? `low` : reasoningEffort ?? defaultEffort;
|
|
1095
|
+
return {
|
|
1096
|
+
...config,
|
|
1097
|
+
onPayload: (payload) => {
|
|
1098
|
+
if (typeof payload !== `object` || payload === null) return void 0;
|
|
1099
|
+
const body = payload;
|
|
1100
|
+
const existingReasoning = typeof body.reasoning === `object` && body.reasoning !== null ? body.reasoning : {};
|
|
1101
|
+
return {
|
|
1102
|
+
...body,
|
|
1103
|
+
reasoning: {
|
|
1104
|
+
...existingReasoning,
|
|
1105
|
+
effort
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
if (choice.provider === `anthropic`) {
|
|
1112
|
+
const effectiveEffort = reasoningEffort ?? `minimal`;
|
|
1113
|
+
const budgetTokens = ANTHROPIC_THINKING_BUDGET_BY_EFFORT[effectiveEffort];
|
|
1114
|
+
return {
|
|
1115
|
+
...config,
|
|
1116
|
+
onPayload: (payload) => {
|
|
1117
|
+
if (typeof payload !== `object` || payload === null) return void 0;
|
|
1118
|
+
const body = payload;
|
|
1119
|
+
const existingThinking = typeof body.thinking === `object` && body.thinking !== null ? body.thinking : {};
|
|
1120
|
+
return {
|
|
1121
|
+
...body,
|
|
1122
|
+
thinking: {
|
|
1123
|
+
...existingThinking,
|
|
1124
|
+
type: `enabled`,
|
|
1125
|
+
budget_tokens: budgetTokens
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
return config;
|
|
1091
1132
|
}
|
|
1092
1133
|
function parseReasoningEffort(value) {
|
|
1093
1134
|
return value === `minimal` || value === `low` || value === `medium` || value === `high` ? value : null;
|
|
@@ -1352,7 +1393,18 @@ Workflow when forking yourself for parallel exploration:
|
|
|
1352
1393
|
Report outcomes faithfully. If a command failed, say so with the relevant output. If you didn't run a verification step, say that rather than implying you did. Don't hedge confirmed results with unnecessary disclaimers.
|
|
1353
1394
|
|
|
1354
1395
|
Working directory: ${workingDirectory}
|
|
1355
|
-
The current year is ${new Date().getFullYear()}
|
|
1396
|
+
The current year is ${new Date().getFullYear()}.${buildGoalGuidance(opts.activeGoal)}`;
|
|
1397
|
+
}
|
|
1398
|
+
function buildGoalGuidance(goal) {
|
|
1399
|
+
if (!goal) return ``;
|
|
1400
|
+
const budgetLine = goal.tokenBudget === null ? `unlimited` : `${goal.tokensUsed} / ${goal.tokenBudget} tokens used`;
|
|
1401
|
+
return `
|
|
1402
|
+
|
|
1403
|
+
# Active goal
|
|
1404
|
+
- Objective: ${goal.objective}
|
|
1405
|
+
- Token budget: ${budgetLine}
|
|
1406
|
+
|
|
1407
|
+
The user set this goal with /goal set. Work autonomously toward it: do NOT ask the user clarifying questions or pause for confirmation — make reasonable assumptions and proceed. When you believe the goal is met, call the \`mark_goal_complete\` tool. If you hit a blocker that genuinely requires the user (e.g. credentials, a destructive action), call \`mark_goal_complete\` with a summary explaining what's needed. The runtime will abort this run automatically if you exceed the token budget.`;
|
|
1356
1408
|
}
|
|
1357
1409
|
function getToolName(tool) {
|
|
1358
1410
|
if (typeof tool !== `object` || tool === null) return null;
|
|
@@ -1377,6 +1429,7 @@ function createHortonTools(sandbox, ctx, readSet, opts = {}) {
|
|
|
1377
1429
|
createObservePgSyncTool(ctx),
|
|
1378
1430
|
createSetTitleTool(ctx),
|
|
1379
1431
|
createSendTool(ctx.send, { selfEntityUrl: ctx.entityUrl }),
|
|
1432
|
+
...ctx.getGoal()?.status === `active` ? [createMarkGoalCompleteTool(ctx)] : [],
|
|
1380
1433
|
...opts.docsSearchTool ? [opts.docsSearchTool] : []
|
|
1381
1434
|
];
|
|
1382
1435
|
}
|
|
@@ -1445,11 +1498,58 @@ async function readAgentsMd(sandbox) {
|
|
|
1445
1498
|
return null;
|
|
1446
1499
|
}
|
|
1447
1500
|
}
|
|
1501
|
+
function extractWakeText(wake) {
|
|
1502
|
+
if (wake.type !== `inbox`) return null;
|
|
1503
|
+
const payload = wake.payload;
|
|
1504
|
+
if (typeof payload === `string`) return payload;
|
|
1505
|
+
if (payload && typeof payload === `object`) {
|
|
1506
|
+
const record = payload;
|
|
1507
|
+
if (typeof record.text === `string`) return record.text;
|
|
1508
|
+
if (typeof record.source === `string`) return record.source;
|
|
1509
|
+
}
|
|
1510
|
+
return null;
|
|
1511
|
+
}
|
|
1512
|
+
async function tryHandleSlashCommand(ctx, wake) {
|
|
1513
|
+
const text = extractWakeText(wake);
|
|
1514
|
+
if (text === null) return false;
|
|
1515
|
+
if (isGoalCommandText(text)) {
|
|
1516
|
+
const command = parseGoalCommand(text);
|
|
1517
|
+
const result = dispatchGoalCommand(ctx, command);
|
|
1518
|
+
if (result.message) {
|
|
1519
|
+
serverLog.info(`[horton ${ctx.entityUrl}] ${result.message}`);
|
|
1520
|
+
writeSlashCommandReply(ctx, result.message);
|
|
1521
|
+
}
|
|
1522
|
+
if (command.kind === `set`) await kickoffGoalRun(ctx);
|
|
1523
|
+
return result.handled;
|
|
1524
|
+
}
|
|
1525
|
+
return false;
|
|
1526
|
+
}
|
|
1527
|
+
const GOAL_KICKOFF_TEXT = `Start working toward the active goal now. Call \`mark_goal_complete\` when you believe it is done.`;
|
|
1528
|
+
async function kickoffGoalRun(ctx) {
|
|
1529
|
+
const goal = ctx.getGoal();
|
|
1530
|
+
if (!goal || goal.status !== `active`) return;
|
|
1531
|
+
try {
|
|
1532
|
+
await ctx.send(ctx.entityUrl, {
|
|
1533
|
+
kind: `goal_kickoff`,
|
|
1534
|
+
text: GOAL_KICKOFF_TEXT
|
|
1535
|
+
}, { type: `inbox` });
|
|
1536
|
+
} catch (err) {
|
|
1537
|
+
serverLog.warn(`[horton ${ctx.entityUrl}] failed to enqueue goal kickoff: ${err instanceof Error ? err.message : String(err)}`);
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
function writeSlashCommandReply(ctx, text) {
|
|
1541
|
+
try {
|
|
1542
|
+
ctx.replyText(text);
|
|
1543
|
+
} catch (err) {
|
|
1544
|
+
serverLog.warn(`[horton ${ctx.entityUrl}] failed to render slash command reply: ${err instanceof Error ? err.message : String(err)}`);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1448
1547
|
function createAssistantHandler(options) {
|
|
1449
1548
|
const { streamFn, docsSupport, docsSearchTool, skillsRegistry, modelCatalog, docsUrl } = options;
|
|
1450
1549
|
const skillLoader = createContextSkillLoader(skillsRegistry, { slashCommandOwner: HORTON_SKILLS_SLASH_COMMAND_OWNER });
|
|
1451
1550
|
const hasSkills = skillLoader.hasSkills;
|
|
1452
1551
|
return async function assistantHandler(ctx, wake) {
|
|
1552
|
+
if (await tryHandleSlashCommand(ctx, wake)) return;
|
|
1453
1553
|
const loadedSkills = await skillLoader.load(ctx);
|
|
1454
1554
|
const readSet = new Set();
|
|
1455
1555
|
const modelConfig = resolveBuiltinModelConfig(modelCatalog, ctx.args);
|
|
@@ -1542,6 +1642,26 @@ function createAssistantHandler(options) {
|
|
|
1542
1642
|
}
|
|
1543
1643
|
}
|
|
1544
1644
|
});
|
|
1645
|
+
const goal = ctx.getGoal();
|
|
1646
|
+
const enforcedGoal = goal && goal.status === `active` ? goal : void 0;
|
|
1647
|
+
const activeGoalPromptInfo = enforcedGoal ? {
|
|
1648
|
+
objective: enforcedGoal.objective,
|
|
1649
|
+
tokenBudget: enforcedGoal.tokenBudget,
|
|
1650
|
+
tokensUsed: enforcedGoal.tokensUsed
|
|
1651
|
+
} : void 0;
|
|
1652
|
+
const budgetAbort = new AbortController();
|
|
1653
|
+
let runTokensUsed = enforcedGoal?.tokensUsed ?? 0;
|
|
1654
|
+
let budgetTripped = false;
|
|
1655
|
+
const onStepEnd = enforcedGoal ? (stats) => {
|
|
1656
|
+
if (budgetTripped) return;
|
|
1657
|
+
runTokensUsed += stats.uncachedInput + stats.output;
|
|
1658
|
+
ctx.updateGoalUsage(runTokensUsed);
|
|
1659
|
+
if (enforcedGoal.tokenBudget !== null && runTokensUsed >= enforcedGoal.tokenBudget) {
|
|
1660
|
+
budgetTripped = true;
|
|
1661
|
+
serverLog.info(`[horton ${ctx.entityUrl}] goal budget exhausted (${runTokensUsed} tokens) — aborting run`);
|
|
1662
|
+
budgetAbort.abort();
|
|
1663
|
+
}
|
|
1664
|
+
} : void 0;
|
|
1545
1665
|
ctx.useAgent({
|
|
1546
1666
|
systemPrompt: buildHortonSystemPrompt(sandboxCwd, {
|
|
1547
1667
|
hasDocsSupport: Boolean(docsSupport),
|
|
@@ -1550,13 +1670,26 @@ function createAssistantHandler(options) {
|
|
|
1550
1670
|
modelProvider: modelConfig.provider,
|
|
1551
1671
|
modelId: String(modelConfig.model),
|
|
1552
1672
|
hasEventSourceTools,
|
|
1553
|
-
hasScheduleTools
|
|
1673
|
+
hasScheduleTools,
|
|
1674
|
+
...activeGoalPromptInfo && { activeGoal: activeGoalPromptInfo }
|
|
1554
1675
|
}),
|
|
1555
1676
|
...modelConfig,
|
|
1556
1677
|
tools,
|
|
1557
|
-
...streamFn && { streamFn }
|
|
1678
|
+
...streamFn && { streamFn },
|
|
1679
|
+
...onStepEnd && { onStepEnd }
|
|
1558
1680
|
});
|
|
1559
|
-
|
|
1681
|
+
try {
|
|
1682
|
+
await ctx.agent.run(void 0, budgetAbort.signal);
|
|
1683
|
+
} catch (err) {
|
|
1684
|
+
if (!budgetTripped) throw err;
|
|
1685
|
+
serverLog.info(`[horton ${ctx.entityUrl}] agent.run aborted by budget enforcement`);
|
|
1686
|
+
}
|
|
1687
|
+
if (enforcedGoal) ctx.updateGoalUsage(runTokensUsed, budgetTripped ? { status: `budget_limited` } : void 0);
|
|
1688
|
+
if (budgetTripped && enforcedGoal && enforcedGoal.tokenBudget !== null) {
|
|
1689
|
+
const budget = enforcedGoal.tokenBudget;
|
|
1690
|
+
const suggestedNext = Math.max(budget * 2, budget + 1e4);
|
|
1691
|
+
writeSlashCommandReply(ctx, `⚠️ Stopped — goal hit the token budget (${formatTokenCount(runTokensUsed)} / ${formatTokenCount(budget)} tokens used). Raise the budget with \`/goal set "..." --tokens ${formatTokenCount(suggestedNext)}\`, or call \`/goal complete\` to finalize.`);
|
|
1692
|
+
}
|
|
1560
1693
|
await titlePromise;
|
|
1561
1694
|
};
|
|
1562
1695
|
}
|
|
@@ -1596,7 +1729,8 @@ function registerHorton(registry, options) {
|
|
|
1596
1729
|
subject_value: `user`,
|
|
1597
1730
|
permission: `manage`
|
|
1598
1731
|
}],
|
|
1599
|
-
|
|
1732
|
+
state: { comments: commentsCollection },
|
|
1733
|
+
slashCommands: [GOAL_SLASH_COMMAND, ...buildSkillSlashCommands(skillsRegistry)],
|
|
1600
1734
|
handler: assistantHandler
|
|
1601
1735
|
});
|
|
1602
1736
|
return [`horton`];
|
|
@@ -1780,6 +1914,7 @@ function registerWorker(registry, options) {
|
|
|
1780
1914
|
subject_value: `user`,
|
|
1781
1915
|
permission: `manage`
|
|
1782
1916
|
}],
|
|
1917
|
+
state: { comments: commentsCollection },
|
|
1783
1918
|
async handler(ctx) {
|
|
1784
1919
|
const args = parseWorkerArgs(ctx.args);
|
|
1785
1920
|
const readSet = new Set();
|
|
@@ -1832,7 +1967,7 @@ function createBuiltinElectricTools(custom) {
|
|
|
1832
1967
|
};
|
|
1833
1968
|
}
|
|
1834
1969
|
async function createBuiltinAgentHandler(options) {
|
|
1835
|
-
const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, enabledModelValues, createElectricTools, publicUrl, runtimeName, baseSkillsDir: baseSkillsDirOverride, serverHeaders, defaultDispatchPolicyForType } = options;
|
|
1970
|
+
const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, enabledModelValues, createElectricTools, publicUrl, runtimeName, baseSkillsDir: baseSkillsDirOverride, serverHeaders, defaultDispatchPolicyForType, dockerSandbox: dockerSandboxOpts } = options;
|
|
1836
1971
|
const modelCatalog = await createBuiltinModelCatalog({
|
|
1837
1972
|
allowMockFallback: Boolean(streamFn),
|
|
1838
1973
|
enabledModelValues
|
|
@@ -1868,7 +2003,7 @@ async function createBuiltinAgentHandler(options) {
|
|
|
1868
2003
|
modelCatalog
|
|
1869
2004
|
});
|
|
1870
2005
|
typeNames.push(`worker`);
|
|
1871
|
-
const { profiles: sandboxProfiles, shutdownSandboxes } = await buildBuiltinSandboxProfiles(cwd);
|
|
2006
|
+
const { profiles: sandboxProfiles, shutdownSandboxes } = await buildBuiltinSandboxProfiles(cwd, dockerSandboxOpts);
|
|
1872
2007
|
const runtime = createRuntimeHandler({
|
|
1873
2008
|
baseUrl: agentServerUrl,
|
|
1874
2009
|
serveEndpoint,
|
|
@@ -1888,7 +2023,8 @@ async function createBuiltinAgentHandler(options) {
|
|
|
1888
2023
|
registry,
|
|
1889
2024
|
typeNames,
|
|
1890
2025
|
skillsRegistry,
|
|
1891
|
-
shutdownSandboxes
|
|
2026
|
+
shutdownSandboxes,
|
|
2027
|
+
modelCatalog
|
|
1892
2028
|
};
|
|
1893
2029
|
}
|
|
1894
2030
|
async function createAgentHandler(agentServerUrl, workingDirectory, streamFn, createElectricTools, serveEndpoint) {
|
|
@@ -1917,6 +2053,21 @@ function sweepOrphanedDockerSandboxesOnce(sweep) {
|
|
|
1917
2053
|
return dockerBootSweep;
|
|
1918
2054
|
}
|
|
1919
2055
|
/**
|
|
2056
|
+
* Merge the profile's working-directory mount with embedder docker options
|
|
2057
|
+
* into the option fragment spread into `dockerSandbox()`. An internal helper:
|
|
2058
|
+
* exported from this module so the unit test can import it, but intentionally
|
|
2059
|
+
* not re-exported from `index.ts` (not part of the package's public API).
|
|
2060
|
+
*/
|
|
2061
|
+
function resolveDockerSandboxOpts(cwdMount, custom) {
|
|
2062
|
+
const extraMounts = [...cwdMount ? [cwdMount] : [], ...custom?.extraMounts ?? []];
|
|
2063
|
+
return {
|
|
2064
|
+
...custom?.image !== void 0 && { image: custom.image },
|
|
2065
|
+
...custom?.allowFloatingTag !== void 0 && { allowFloatingTag: custom.allowFloatingTag },
|
|
2066
|
+
...custom?.env !== void 0 && { env: custom.env },
|
|
2067
|
+
...extraMounts.length > 0 && { extraMounts }
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2070
|
+
/**
|
|
1920
2071
|
* Built-in sandbox profiles. `local` is always available. `docker` is
|
|
1921
2072
|
* gated on Docker being reachable so a user without Docker installed
|
|
1922
2073
|
* sees only what works — the UI never offers a non-functional choice.
|
|
@@ -1926,7 +2077,7 @@ function sweepOrphanedDockerSandboxesOnce(sweep) {
|
|
|
1926
2077
|
* server must run on shutdown (the providers' debounced idle teardowns die
|
|
1927
2078
|
* with the process).
|
|
1928
2079
|
*/
|
|
1929
|
-
async function buildBuiltinSandboxProfiles(workingDirectory) {
|
|
2080
|
+
async function buildBuiltinSandboxProfiles(workingDirectory, dockerOpts) {
|
|
1930
2081
|
const profiles = [{
|
|
1931
2082
|
name: `local`,
|
|
1932
2083
|
label: `Local`,
|
|
@@ -1951,11 +2102,11 @@ async function buildBuiltinSandboxProfiles(workingDirectory) {
|
|
|
1951
2102
|
workingDirectory: `/work`,
|
|
1952
2103
|
factory: () => dockerSandbox({
|
|
1953
2104
|
initialNetworkPolicy: { mode: `allow-all` },
|
|
1954
|
-
|
|
2105
|
+
...resolveDockerSandboxOpts(cwd ? {
|
|
1955
2106
|
hostPath: cwd,
|
|
1956
2107
|
containerPath: `/work`,
|
|
1957
2108
|
readOnly: false
|
|
1958
|
-
}
|
|
2109
|
+
} : void 0, dockerOpts),
|
|
1959
2110
|
sandboxKey,
|
|
1960
2111
|
persistent,
|
|
1961
2112
|
owner,
|
|
@@ -2341,4 +2492,4 @@ async function runBuiltinAgentsEntrypoint({ env = process.env, cwd = process.cwd
|
|
|
2341
2492
|
}
|
|
2342
2493
|
|
|
2343
2494
|
//#endregion
|
|
2344
|
-
export { BuiltinAgentsServer, DEFAULT_BUILTIN_AGENT_HANDLER_PATH, HORTON_MODEL, WORKER_TOOL_NAMES, braveSearchTool, buildHortonSystemPrompt, builtinModelProviderLabel, createAgentHandler, createBuiltinAgentHandler, createBuiltinElectricTools, createForkTool, createHortonDocsSupport, createHortonTools, createSpawnWorkerTool, generateTitle, listBuiltinModelChoices, registerAgentTypes, registerBuiltinAgentTypes, registerHorton, registerWorker, resolveBuiltinAgentsEntrypointOptions, runBuiltinAgentsEntrypoint };
|
|
2495
|
+
export { BuiltinAgentsServer, DEFAULT_BUILTIN_AGENT_HANDLER_PATH, HORTON_MODEL, WORKER_TOOL_NAMES, braveSearchTool, buildHortonSystemPrompt, builtinModelProviderLabel, createAgentHandler, createBuiltinAgentHandler, createBuiltinElectricTools, createForkTool, createHortonDocsSupport, createHortonTools, createSpawnWorkerTool, generateTitle, listBuiltinModelChoices, registerAgentTypes, registerBuiltinAgentTypes, registerHorton, registerWorker, resolveBuiltinAgentsEntrypointOptions, resolveBuiltinModelConfig, runBuiltinAgentsEntrypoint };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@electric-ax/agents",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.18",
|
|
4
4
|
"description": "Built-in Electric Agents runtimes such as Horton and worker",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"undici": "^7.24.7",
|
|
51
51
|
"zod": "^4.3.6",
|
|
52
52
|
"@electric-ax/agents-mcp": "0.2.3",
|
|
53
|
-
"@electric-ax/agents-runtime": "0.
|
|
53
|
+
"@electric-ax/agents-runtime": "0.4.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/better-sqlite3": "^7.6.13",
|