@electric-ax/agents 0.4.16 → 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 +306 -35
- package/dist/index.cjs +305 -33
- package/dist/index.d.cts +75 -31
- package/dist/index.d.ts +75 -31
- package/dist/index.js +307 -36
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -818,6 +818,69 @@ function createSpawnWorkerTool(ctx, modelConfig) {
|
|
|
818
818
|
};
|
|
819
819
|
}
|
|
820
820
|
|
|
821
|
+
//#endregion
|
|
822
|
+
//#region src/tools/observe-pg-sync.ts
|
|
823
|
+
function asToolResult(value) {
|
|
824
|
+
return {
|
|
825
|
+
content: [{
|
|
826
|
+
type: `text`,
|
|
827
|
+
text: typeof value === `string` ? value : JSON.stringify(value, null, 2)
|
|
828
|
+
}],
|
|
829
|
+
details: {}
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
const PgSyncOperation = __sinclair_typebox.Type.Union([
|
|
833
|
+
__sinclair_typebox.Type.Literal(`insert`),
|
|
834
|
+
__sinclair_typebox.Type.Literal(`update`),
|
|
835
|
+
__sinclair_typebox.Type.Literal(`delete`)
|
|
836
|
+
]);
|
|
837
|
+
function createObservePgSyncTool(ctx) {
|
|
838
|
+
return {
|
|
839
|
+
name: `observe_pg_sync`,
|
|
840
|
+
label: `Observe Postgres Sync`,
|
|
841
|
+
description: `Observe an Electric Postgres shape stream and wake this agent when matching row changes arrive.`,
|
|
842
|
+
parameters: __sinclair_typebox.Type.Object({
|
|
843
|
+
url: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.String({ description: `Optional Electric shape endpoint URL. Defaults to the server-configured pg-sync URL.` })),
|
|
844
|
+
table: __sinclair_typebox.Type.String({
|
|
845
|
+
minLength: 1,
|
|
846
|
+
pattern: `\\S`,
|
|
847
|
+
description: `Postgres table name to observe.`
|
|
848
|
+
}),
|
|
849
|
+
columns: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.Array(__sinclair_typebox.Type.String(), { description: `Optional list of columns to include in the shape.` })),
|
|
850
|
+
where: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.String({ description: `Optional Electric shape WHERE clause.` })),
|
|
851
|
+
params: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.Union([__sinclair_typebox.Type.Array(__sinclair_typebox.Type.String()), __sinclair_typebox.Type.Record(__sinclair_typebox.Type.String(), __sinclair_typebox.Type.String())])),
|
|
852
|
+
replica: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.Union([__sinclair_typebox.Type.Literal(`default`), __sinclair_typebox.Type.Literal(`full`)])),
|
|
853
|
+
wake: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.Object({
|
|
854
|
+
ops: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.Array(PgSyncOperation)),
|
|
855
|
+
debounceMs: __sinclair_typebox.Type.Optional(__sinclair_typebox.Type.Number())
|
|
856
|
+
}, { additionalProperties: false }))
|
|
857
|
+
}),
|
|
858
|
+
execute: async (_toolCallId, params) => {
|
|
859
|
+
const args = params;
|
|
860
|
+
if (typeof args.table !== `string` || args.table.trim().length === 0) throw new Error(`table is required`);
|
|
861
|
+
const source = (0, __electric_ax_agents_runtime.pgSync)({
|
|
862
|
+
url: args.url,
|
|
863
|
+
table: args.table,
|
|
864
|
+
columns: args.columns,
|
|
865
|
+
where: args.where,
|
|
866
|
+
params: args.params,
|
|
867
|
+
replica: args.replica
|
|
868
|
+
});
|
|
869
|
+
const wake = {
|
|
870
|
+
on: `change`,
|
|
871
|
+
...args.wake?.ops ? { ops: args.wake.ops } : {},
|
|
872
|
+
...args.wake?.debounceMs !== void 0 ? { debounceMs: args.wake.debounceMs } : {}
|
|
873
|
+
};
|
|
874
|
+
await ctx.observe(source, { wake });
|
|
875
|
+
return asToolResult({
|
|
876
|
+
sourceRef: source.sourceRef,
|
|
877
|
+
streamUrl: source.streamUrl,
|
|
878
|
+
wake
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
|
|
821
884
|
//#endregion
|
|
822
885
|
//#region src/tools/fork.ts
|
|
823
886
|
function createForkTool(ctx) {
|
|
@@ -872,6 +935,49 @@ Omit 'entityUrl' to fork your own session. Pass a different session's URL to for
|
|
|
872
935
|
};
|
|
873
936
|
}
|
|
874
937
|
|
|
938
|
+
//#endregion
|
|
939
|
+
//#region src/tools/set-title.ts
|
|
940
|
+
function createSetTitleTool(ctx) {
|
|
941
|
+
return {
|
|
942
|
+
name: `set_title`,
|
|
943
|
+
label: `Set Title`,
|
|
944
|
+
description: `Set the chat session title shown in the UI. Use this when the current title is missing, stale, misleading, or the user asks to rename the session. Provide a concise, human-readable title.`,
|
|
945
|
+
parameters: __sinclair_typebox.Type.Object({ title: __sinclair_typebox.Type.String({ description: `New session title. Whitespace is trimmed and the title must not be empty.` }) }),
|
|
946
|
+
execute: async (_toolCallId, params) => {
|
|
947
|
+
const { title } = params;
|
|
948
|
+
const trimmedTitle = typeof title === `string` ? title.trim() : ``;
|
|
949
|
+
if (trimmedTitle.length === 0) return {
|
|
950
|
+
content: [{
|
|
951
|
+
type: `text`,
|
|
952
|
+
text: `Error: title must be a non-empty string.`
|
|
953
|
+
}],
|
|
954
|
+
details: { updated: false }
|
|
955
|
+
};
|
|
956
|
+
try {
|
|
957
|
+
await ctx.setTag(`title`, trimmedTitle);
|
|
958
|
+
return {
|
|
959
|
+
content: [{
|
|
960
|
+
type: `text`,
|
|
961
|
+
text: `Session title set to “${trimmedTitle}”.`
|
|
962
|
+
}],
|
|
963
|
+
details: {
|
|
964
|
+
updated: true,
|
|
965
|
+
title: trimmedTitle
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
} catch (err) {
|
|
969
|
+
return {
|
|
970
|
+
content: [{
|
|
971
|
+
type: `text`,
|
|
972
|
+
text: `Error setting session title: ${err instanceof Error ? err.message : `Unknown error`}`
|
|
973
|
+
}],
|
|
974
|
+
details: { updated: false }
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
|
|
875
981
|
//#endregion
|
|
876
982
|
//#region src/model-catalog.ts
|
|
877
983
|
const MODEL_INPUTS_SCHEMA_DEF = `electricModelInputs`;
|
|
@@ -987,25 +1093,66 @@ function filterChoicesByEnabledModels(choices, values) {
|
|
|
987
1093
|
const filtered = choices.filter((choice) => enabled.has(choice.value));
|
|
988
1094
|
return filtered.length > 0 ? filtered : choices;
|
|
989
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
|
+
};
|
|
990
1114
|
function withProviderPayloadDefaults(config, choice, reasoningEffort) {
|
|
991
|
-
if (
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
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;
|
|
1009
1156
|
}
|
|
1010
1157
|
function parseReasoningEffort(value) {
|
|
1011
1158
|
return value === `minimal` || value === `low` || value === `medium` || value === `high` ? value : null;
|
|
@@ -1054,7 +1201,7 @@ function modelInputSchemaDefs(catalog) {
|
|
|
1054
1201
|
//#endregion
|
|
1055
1202
|
//#region src/agents/horton.ts
|
|
1056
1203
|
const HORTON_MODEL = `claude-sonnet-4-6`;
|
|
1057
|
-
const TITLE_SYSTEM_PROMPT = "You generate concise chat session
|
|
1204
|
+
const TITLE_SYSTEM_PROMPT = "You generate a concise 3-5 word chat session title from the user's first message. Respond with only the title — no quotes, punctuation, preamble, or explanation. The user may reference images, files, or attachments you cannot see; infer a title from their intent anyway. Never apologize or say anything is missing — always output a short title.";
|
|
1058
1205
|
const TITLE_USER_PROMPT = (userMessage) => `User request:\n${userMessage}`;
|
|
1059
1206
|
const TITLE_GENERATION_TIMEOUT_MS = 8e3;
|
|
1060
1207
|
const HORTON_SKILLS_SLASH_COMMAND_OWNER = `horton:skills`;
|
|
@@ -1148,12 +1295,16 @@ function withTimeout(promise, ms, description) {
|
|
|
1148
1295
|
if (timeout) clearTimeout(timeout);
|
|
1149
1296
|
});
|
|
1150
1297
|
}
|
|
1298
|
+
function looksLikeNonTitle(title) {
|
|
1299
|
+
if (title.split(/\s+/).filter(Boolean).length > 8) return true;
|
|
1300
|
+
return /[!?,]/.test(title);
|
|
1301
|
+
}
|
|
1151
1302
|
async function generateTitle(userMessage, llmCall, onFallback) {
|
|
1152
1303
|
try {
|
|
1153
1304
|
const raw = await llmCall(TITLE_USER_PROMPT(userMessage));
|
|
1154
1305
|
const title = raw.trim();
|
|
1155
|
-
if (title.length > 0) return title;
|
|
1156
|
-
onFallback?.(`empty LLM title response`);
|
|
1306
|
+
if (title.length > 0 && !looksLikeNonTitle(title)) return title;
|
|
1307
|
+
onFallback?.(title.length === 0 ? `empty LLM title response` : `non-title LLM response`);
|
|
1157
1308
|
return buildFallbackTitle(userMessage);
|
|
1158
1309
|
} catch (err) {
|
|
1159
1310
|
onFallback?.(err instanceof Error ? err.message : String(err));
|
|
@@ -1163,6 +1314,7 @@ async function generateTitle(userMessage, llmCall, onFallback) {
|
|
|
1163
1314
|
function buildHortonSystemPrompt(workingDirectory, opts = {}) {
|
|
1164
1315
|
const docsTools = opts.hasDocsSupport ? `\n- search_electric_agents_docs: hybrid search over the built-in Electric Agents docs index` : ``;
|
|
1165
1316
|
const eventSourceTools = opts.hasEventSourceTools ? `\n- list_event_sources: list external webhook/event feeds you can subscribe to, including available buckets and parameters\n- subscribe_event_source: subscribe yourself to one of those feeds or buckets so matching future events wake you\n- list_event_source_subscriptions: list your active event source subscriptions\n- unsubscribe_event_source: remove one of your event source subscriptions by id` : ``;
|
|
1317
|
+
const titleTool = `\n- set_title: set or rename this chat session's UI title`;
|
|
1166
1318
|
const scheduleTools = opts.hasScheduleTools ? `\n- upsert_cron_schedule: create or update a recurring cron wake for yourself. Always include payload with the concrete instruction/message you should receive when the cron fires.\n- delete_schedule: delete one of your cron or future-send schedules by stable id\n- list_schedules: list your manifest-backed cron and future-send schedules` : ``;
|
|
1167
1319
|
const skillsTools = opts.hasSkills ? `\n- use_skill: load a skill (knowledge, instructions, or a tutorial) into your context to help with the user's request\n- remove_skill: unload a skill from context when you're done with it` : ``;
|
|
1168
1320
|
const docsGuidance = opts.hasDocsSupport ? `\n- For ANY question about Electric Agents or this framework, ALWAYS use search_electric_agents_docs FIRST. Do not use web_search or fetch_url for Electric Agents topics unless the docs search returns no useful results.\n- The search tool returns chunk content directly — you do not need to read the source files.\n- Use repo read/bash tools only for non-doc files or when you need to inspect exact implementation code in the workspace.` : ``;
|
|
@@ -1218,8 +1370,9 @@ When a user opens with a greeting ("hi", "hello", "hey", etc.) or a broad statem
|
|
|
1218
1370
|
- fetch_url: fetch and convert a URL to markdown
|
|
1219
1371
|
- spawn_worker: dispatch a subagent for an isolated task
|
|
1220
1372
|
- fork: spawn a child session that inherits this conversation's history up to the latest completed response. Same parent-ownership model as spawn_worker — when the fork's next run finishes, you'll wake with its response.
|
|
1373
|
+
- observe_pg_sync: observe an Electric Postgres sync stream and wake on matching changes
|
|
1221
1374
|
- send: send a message to an Electric Agent/entity. To schedule future work for yourself, call send with self: true and afterMs.
|
|
1222
|
-
${eventSourceTools}${scheduleTools}${docsTools}${skillsTools}
|
|
1375
|
+
${eventSourceTools}${titleTool}${scheduleTools}${docsTools}${skillsTools}
|
|
1223
1376
|
|
|
1224
1377
|
# Working with files
|
|
1225
1378
|
- Prefer edit over write when modifying existing files.
|
|
@@ -1264,7 +1417,18 @@ Workflow when forking yourself for parallel exploration:
|
|
|
1264
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.
|
|
1265
1418
|
|
|
1266
1419
|
Working directory: ${workingDirectory}
|
|
1267
|
-
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.`;
|
|
1268
1432
|
}
|
|
1269
1433
|
function getToolName(tool) {
|
|
1270
1434
|
if (typeof tool !== `object` || tool === null) return null;
|
|
@@ -1286,7 +1450,10 @@ function createHortonTools(sandbox, ctx, readSet, opts = {}) {
|
|
|
1286
1450
|
})] : [(0, __electric_ax_agents_runtime_tools.createFetchUrlTool)(sandbox)],
|
|
1287
1451
|
createSpawnWorkerTool(ctx, opts.modelConfig),
|
|
1288
1452
|
createForkTool(ctx),
|
|
1453
|
+
createObservePgSyncTool(ctx),
|
|
1454
|
+
createSetTitleTool(ctx),
|
|
1289
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)] : [],
|
|
1290
1457
|
...opts.docsSearchTool ? [opts.docsSearchTool] : []
|
|
1291
1458
|
];
|
|
1292
1459
|
}
|
|
@@ -1355,11 +1522,58 @@ async function readAgentsMd(sandbox) {
|
|
|
1355
1522
|
return null;
|
|
1356
1523
|
}
|
|
1357
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
|
+
}
|
|
1358
1571
|
function createAssistantHandler(options) {
|
|
1359
1572
|
const { streamFn, docsSupport, docsSearchTool, skillsRegistry, modelCatalog, docsUrl } = options;
|
|
1360
1573
|
const skillLoader = (0, __electric_ax_agents_runtime.createContextSkillLoader)(skillsRegistry, { slashCommandOwner: HORTON_SKILLS_SLASH_COMMAND_OWNER });
|
|
1361
1574
|
const hasSkills = skillLoader.hasSkills;
|
|
1362
1575
|
return async function assistantHandler(ctx, wake) {
|
|
1576
|
+
if (await tryHandleSlashCommand(ctx, wake)) return;
|
|
1363
1577
|
const loadedSkills = await skillLoader.load(ctx);
|
|
1364
1578
|
const readSet = new Set();
|
|
1365
1579
|
const modelConfig = resolveBuiltinModelConfig(modelCatalog, ctx.args);
|
|
@@ -1452,6 +1666,26 @@ function createAssistantHandler(options) {
|
|
|
1452
1666
|
}
|
|
1453
1667
|
}
|
|
1454
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;
|
|
1455
1689
|
ctx.useAgent({
|
|
1456
1690
|
systemPrompt: buildHortonSystemPrompt(sandboxCwd, {
|
|
1457
1691
|
hasDocsSupport: Boolean(docsSupport),
|
|
@@ -1460,13 +1694,26 @@ function createAssistantHandler(options) {
|
|
|
1460
1694
|
modelProvider: modelConfig.provider,
|
|
1461
1695
|
modelId: String(modelConfig.model),
|
|
1462
1696
|
hasEventSourceTools,
|
|
1463
|
-
hasScheduleTools
|
|
1697
|
+
hasScheduleTools,
|
|
1698
|
+
...activeGoalPromptInfo && { activeGoal: activeGoalPromptInfo }
|
|
1464
1699
|
}),
|
|
1465
1700
|
...modelConfig,
|
|
1466
1701
|
tools,
|
|
1467
|
-
...streamFn && { streamFn }
|
|
1702
|
+
...streamFn && { streamFn },
|
|
1703
|
+
...onStepEnd && { onStepEnd }
|
|
1468
1704
|
});
|
|
1469
|
-
|
|
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
|
+
}
|
|
1470
1717
|
await titlePromise;
|
|
1471
1718
|
};
|
|
1472
1719
|
}
|
|
@@ -1506,7 +1753,8 @@ function registerHorton(registry, options) {
|
|
|
1506
1753
|
subject_value: `user`,
|
|
1507
1754
|
permission: `manage`
|
|
1508
1755
|
}],
|
|
1509
|
-
|
|
1756
|
+
state: { comments: __electric_ax_agents_runtime.commentsCollection },
|
|
1757
|
+
slashCommands: [__electric_ax_agents_runtime.GOAL_SLASH_COMMAND, ...(0, __electric_ax_agents_runtime.buildSkillSlashCommands)(skillsRegistry)],
|
|
1510
1758
|
handler: assistantHandler
|
|
1511
1759
|
});
|
|
1512
1760
|
return [`horton`];
|
|
@@ -1690,6 +1938,7 @@ function registerWorker(registry, options) {
|
|
|
1690
1938
|
subject_value: `user`,
|
|
1691
1939
|
permission: `manage`
|
|
1692
1940
|
}],
|
|
1941
|
+
state: { comments: __electric_ax_agents_runtime.commentsCollection },
|
|
1693
1942
|
async handler(ctx) {
|
|
1694
1943
|
const args = parseWorkerArgs(ctx.args);
|
|
1695
1944
|
const readSet = new Set();
|
|
@@ -1742,7 +1991,7 @@ function createBuiltinElectricTools(custom) {
|
|
|
1742
1991
|
};
|
|
1743
1992
|
}
|
|
1744
1993
|
async function createBuiltinAgentHandler(options) {
|
|
1745
|
-
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;
|
|
1746
1995
|
const modelCatalog = await createBuiltinModelCatalog({
|
|
1747
1996
|
allowMockFallback: Boolean(streamFn),
|
|
1748
1997
|
enabledModelValues
|
|
@@ -1778,7 +2027,7 @@ async function createBuiltinAgentHandler(options) {
|
|
|
1778
2027
|
modelCatalog
|
|
1779
2028
|
});
|
|
1780
2029
|
typeNames.push(`worker`);
|
|
1781
|
-
const { profiles: sandboxProfiles, shutdownSandboxes } = await buildBuiltinSandboxProfiles(cwd);
|
|
2030
|
+
const { profiles: sandboxProfiles, shutdownSandboxes } = await buildBuiltinSandboxProfiles(cwd, dockerSandboxOpts);
|
|
1782
2031
|
const runtime = (0, __electric_ax_agents_runtime.createRuntimeHandler)({
|
|
1783
2032
|
baseUrl: agentServerUrl,
|
|
1784
2033
|
serveEndpoint,
|
|
@@ -1798,7 +2047,8 @@ async function createBuiltinAgentHandler(options) {
|
|
|
1798
2047
|
registry,
|
|
1799
2048
|
typeNames,
|
|
1800
2049
|
skillsRegistry,
|
|
1801
|
-
shutdownSandboxes
|
|
2050
|
+
shutdownSandboxes,
|
|
2051
|
+
modelCatalog
|
|
1802
2052
|
};
|
|
1803
2053
|
}
|
|
1804
2054
|
async function createAgentHandler(agentServerUrl, workingDirectory, streamFn, createElectricTools, serveEndpoint) {
|
|
@@ -1827,6 +2077,21 @@ function sweepOrphanedDockerSandboxesOnce(sweep) {
|
|
|
1827
2077
|
return dockerBootSweep;
|
|
1828
2078
|
}
|
|
1829
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
|
+
/**
|
|
1830
2095
|
* Built-in sandbox profiles. `local` is always available. `docker` is
|
|
1831
2096
|
* gated on Docker being reachable so a user without Docker installed
|
|
1832
2097
|
* sees only what works — the UI never offers a non-functional choice.
|
|
@@ -1836,7 +2101,7 @@ function sweepOrphanedDockerSandboxesOnce(sweep) {
|
|
|
1836
2101
|
* server must run on shutdown (the providers' debounced idle teardowns die
|
|
1837
2102
|
* with the process).
|
|
1838
2103
|
*/
|
|
1839
|
-
async function buildBuiltinSandboxProfiles(workingDirectory) {
|
|
2104
|
+
async function buildBuiltinSandboxProfiles(workingDirectory, dockerOpts) {
|
|
1840
2105
|
const profiles = [{
|
|
1841
2106
|
name: `local`,
|
|
1842
2107
|
label: `Local`,
|
|
@@ -1861,11 +2126,11 @@ async function buildBuiltinSandboxProfiles(workingDirectory) {
|
|
|
1861
2126
|
workingDirectory: `/work`,
|
|
1862
2127
|
factory: () => dockerSandbox({
|
|
1863
2128
|
initialNetworkPolicy: { mode: `allow-all` },
|
|
1864
|
-
|
|
2129
|
+
...resolveDockerSandboxOpts(cwd ? {
|
|
1865
2130
|
hostPath: cwd,
|
|
1866
2131
|
containerPath: `/work`,
|
|
1867
2132
|
readOnly: false
|
|
1868
|
-
}
|
|
2133
|
+
} : void 0, dockerOpts),
|
|
1869
2134
|
sandboxKey,
|
|
1870
2135
|
persistent,
|
|
1871
2136
|
owner,
|
|
@@ -1912,13 +2177,19 @@ function resolveCwd(args, fallback) {
|
|
|
1912
2177
|
//#endregion
|
|
1913
2178
|
//#region src/durable-streams-cache.ts
|
|
1914
2179
|
const MEMORY_CACHE_SIZE_BYTES = 100 * 1024 * 1024;
|
|
2180
|
+
let installed = false;
|
|
1915
2181
|
function installDurableStreamsFetchCache(options = {}) {
|
|
1916
2182
|
if (options === false) return;
|
|
2183
|
+
if (installed) {
|
|
2184
|
+
console.warn(`[agents] installDurableStreamsFetchCache called more than once; ignoring`);
|
|
2185
|
+
return;
|
|
2186
|
+
}
|
|
1917
2187
|
const store = options.store === `sqlite` || options.sqliteLocation ? new undici.cacheStores.SqliteCacheStore({
|
|
1918
2188
|
location: options.sqliteLocation,
|
|
1919
2189
|
maxCount: options.maxCount
|
|
1920
2190
|
}) : new undici.cacheStores.MemoryCacheStore({ maxSize: MEMORY_CACHE_SIZE_BYTES });
|
|
1921
2191
|
(0, undici.setGlobalDispatcher)((0, undici.getGlobalDispatcher)().compose(undici.interceptors.cache({ store })));
|
|
2192
|
+
installed = true;
|
|
1922
2193
|
}
|
|
1923
2194
|
|
|
1924
2195
|
//#endregion
|
|
@@ -2271,4 +2542,5 @@ exports.registerBuiltinAgentTypes = registerBuiltinAgentTypes
|
|
|
2271
2542
|
exports.registerHorton = registerHorton
|
|
2272
2543
|
exports.registerWorker = registerWorker
|
|
2273
2544
|
exports.resolveBuiltinAgentsEntrypointOptions = resolveBuiltinAgentsEntrypointOptions
|
|
2545
|
+
exports.resolveBuiltinModelConfig = resolveBuiltinModelConfig
|
|
2274
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 };
|