@electric-ax/agents 0.4.13 → 0.4.14
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 +30 -17
- package/dist/index.cjs +29 -16
- package/dist/index.js +30 -17
- package/package.json +2 -2
package/dist/entrypoint.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Agent, cacheStores, interceptors, setGlobalDispatcher } from "undici";
|
|
|
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, completeWithLowCostModel, createEntityRegistry, createPullWakeRunner, createRuntimeHandler,
|
|
7
|
+
import { MOONSHOT_API_BASE_URL, MOONSHOT_PROVIDER, appendPathToUrl, buildSkillSlashCommands, completeWithLowCostModel, createContextSkillLoader, createEntityRegistry, createPullWakeRunner, createRuntimeHandler, createSkillsRegistry, db, detectAvailableProviders, getMoonshotApiKey, getMoonshotModel, getMoonshotModels, readCodexAccessToken, registerToolProvider, unregisterToolProvider } from "@electric-ax/agents-runtime";
|
|
8
8
|
import { braveSearchTool, createBashTool, createEditTool, createEventSourceTools, createFetchUrlTool, createReadFileTool, createSendTool, createWriteTool } from "@electric-ax/agents-runtime/tools";
|
|
9
9
|
import { chooseDefaultSandbox, isE2BAvailable, remoteSandbox } from "@electric-ax/agents-runtime/sandbox";
|
|
10
10
|
import { z } from "zod";
|
|
@@ -989,6 +989,8 @@ function modelInputSchemaDefs(catalog) {
|
|
|
989
989
|
//#region src/agents/horton.ts
|
|
990
990
|
const TITLE_SYSTEM_PROMPT = "You generate concise chat session titles in 3-5 words. Respond with only the title, no quotes, no punctuation, no preamble.";
|
|
991
991
|
const TITLE_USER_PROMPT = (userMessage) => `User request:\n${userMessage}`;
|
|
992
|
+
const TITLE_GENERATION_TIMEOUT_MS = 8e3;
|
|
993
|
+
const HORTON_SKILLS_SLASH_COMMAND_OWNER = `horton:skills`;
|
|
992
994
|
const TITLE_STOP_WORDS = new Set([
|
|
993
995
|
`a`,
|
|
994
996
|
`an`,
|
|
@@ -1068,6 +1070,17 @@ function createConfiguredTitleCall(catalog, modelConfig, logPrefix) {
|
|
|
1068
1070
|
maxTokens: 64
|
|
1069
1071
|
});
|
|
1070
1072
|
}
|
|
1073
|
+
function withTimeout(promise, ms, description) {
|
|
1074
|
+
let timeout;
|
|
1075
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
1076
|
+
timeout = setTimeout(() => {
|
|
1077
|
+
reject(new Error(`${description} timed out after ${ms}ms`));
|
|
1078
|
+
}, ms);
|
|
1079
|
+
});
|
|
1080
|
+
return Promise.race([promise, timeoutPromise]).finally(() => {
|
|
1081
|
+
if (timeout) clearTimeout(timeout);
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1071
1084
|
async function generateTitle(userMessage, llmCall, onFallback) {
|
|
1072
1085
|
try {
|
|
1073
1086
|
const raw = await llmCall(TITLE_USER_PROMPT(userMessage));
|
|
@@ -1197,8 +1210,12 @@ function payloadToTitleText(payload) {
|
|
|
1197
1210
|
if (typeof payload === `string`) return payload;
|
|
1198
1211
|
if (payload == null) return ``;
|
|
1199
1212
|
if (typeof payload === `object`) {
|
|
1200
|
-
const
|
|
1201
|
-
|
|
1213
|
+
const record = payload;
|
|
1214
|
+
const text = record.text;
|
|
1215
|
+
if (typeof text === `string`) return text;
|
|
1216
|
+
const source = record.source;
|
|
1217
|
+
if (typeof source === `string`) return source;
|
|
1218
|
+
return JSON.stringify(payload);
|
|
1202
1219
|
}
|
|
1203
1220
|
return String(payload);
|
|
1204
1221
|
}
|
|
@@ -1256,8 +1273,10 @@ async function readAgentsMd(sandbox) {
|
|
|
1256
1273
|
}
|
|
1257
1274
|
function createAssistantHandler(options) {
|
|
1258
1275
|
const { streamFn, docsSupport, docsSearchTool, skillsRegistry, modelCatalog, docsUrl } = options;
|
|
1259
|
-
const
|
|
1276
|
+
const skillLoader = createContextSkillLoader(skillsRegistry, { slashCommandOwner: HORTON_SKILLS_SLASH_COMMAND_OWNER });
|
|
1277
|
+
const hasSkills = skillLoader.hasSkills;
|
|
1260
1278
|
return async function assistantHandler(ctx, wake) {
|
|
1279
|
+
const loadedSkills = await skillLoader.load(ctx);
|
|
1261
1280
|
const readSet = new Set();
|
|
1262
1281
|
const modelConfig = resolveBuiltinModelConfig(modelCatalog, ctx.args);
|
|
1263
1282
|
const sourceBudget = resolveBuiltinModelSourceBudget(modelConfig);
|
|
@@ -1271,7 +1290,7 @@ function createAssistantHandler(options) {
|
|
|
1271
1290
|
modelCatalog,
|
|
1272
1291
|
logPrefix: `[horton ${ctx.entityUrl}]`
|
|
1273
1292
|
}),
|
|
1274
|
-
...
|
|
1293
|
+
...loadedSkills.tools,
|
|
1275
1294
|
...mcp.tools()
|
|
1276
1295
|
];
|
|
1277
1296
|
const hasEventSourceTools = tools.some((tool) => getToolName(tool) === `list_event_sources`);
|
|
@@ -1280,15 +1299,16 @@ function createAssistantHandler(options) {
|
|
|
1280
1299
|
if (!firstUserMessage) return;
|
|
1281
1300
|
let title = null;
|
|
1282
1301
|
try {
|
|
1283
|
-
const result = await generateTitle(firstUserMessage, createConfiguredTitleCall(modelCatalog, modelConfig, `[horton ${ctx.entityUrl}]`), (reason) => {
|
|
1302
|
+
const result = await generateTitle(firstUserMessage, (prompt) => withTimeout(createConfiguredTitleCall(modelCatalog, modelConfig, `[horton ${ctx.entityUrl}]`)(prompt), TITLE_GENERATION_TIMEOUT_MS, `title generation`), (reason) => {
|
|
1284
1303
|
serverLog.warn(`[horton ${ctx.entityUrl}] title generation fell back to local title: ${reason}`);
|
|
1285
1304
|
});
|
|
1286
1305
|
if (result.length > 0) title = result;
|
|
1287
1306
|
} catch (err) {
|
|
1288
1307
|
serverLog.warn(`[horton ${ctx.entityUrl}] title generation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1308
|
+
title = buildFallbackTitle(firstUserMessage);
|
|
1289
1309
|
}
|
|
1290
1310
|
if (title !== null) try {
|
|
1291
|
-
await ctx.setTag(`title`, title);
|
|
1311
|
+
await withTimeout(ctx.setTag(`title`, title), TITLE_GENERATION_TIMEOUT_MS, `set title tag`);
|
|
1292
1312
|
} catch (err) {
|
|
1293
1313
|
serverLog.warn(`[horton ${ctx.entityUrl}] setTag failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1294
1314
|
}
|
|
@@ -1315,21 +1335,13 @@ function createAssistantHandler(options) {
|
|
|
1315
1335
|
max: 2e4,
|
|
1316
1336
|
cache: `stable`
|
|
1317
1337
|
} } : {},
|
|
1318
|
-
...skillsRegistry && skillsRegistry.catalog.size > 0 ?
|
|
1319
|
-
content: () => skillsRegistry.renderCatalog(2e3),
|
|
1320
|
-
max: 2e3,
|
|
1321
|
-
cache: `stable`
|
|
1322
|
-
} } : {}
|
|
1338
|
+
...skillsRegistry && skillsRegistry.catalog.size > 0 ? loadedSkills.sources : {}
|
|
1323
1339
|
}
|
|
1324
1340
|
});
|
|
1325
1341
|
else if (skillsRegistry && skillsRegistry.catalog.size > 0) ctx.useContext({
|
|
1326
1342
|
sourceBudget,
|
|
1327
1343
|
sources: {
|
|
1328
|
-
|
|
1329
|
-
content: () => skillsRegistry.renderCatalog(2e3),
|
|
1330
|
-
max: 2e3,
|
|
1331
|
-
cache: `stable`
|
|
1332
|
-
},
|
|
1344
|
+
...loadedSkills.sources,
|
|
1333
1345
|
conversation: {
|
|
1334
1346
|
content: () => ctx.timelineMessages(),
|
|
1335
1347
|
cache: `volatile`
|
|
@@ -1408,6 +1420,7 @@ function registerHorton(registry, options) {
|
|
|
1408
1420
|
subject_value: `user`,
|
|
1409
1421
|
permission: `manage`
|
|
1410
1422
|
}],
|
|
1423
|
+
slashCommands: buildSkillSlashCommands(skillsRegistry),
|
|
1411
1424
|
handler: assistantHandler
|
|
1412
1425
|
});
|
|
1413
1426
|
return [`horton`];
|
package/dist/index.cjs
CHANGED
|
@@ -1002,6 +1002,8 @@ function modelInputSchemaDefs(catalog) {
|
|
|
1002
1002
|
const HORTON_MODEL = `claude-sonnet-4-6`;
|
|
1003
1003
|
const TITLE_SYSTEM_PROMPT = "You generate concise chat session titles in 3-5 words. Respond with only the title, no quotes, no punctuation, no preamble.";
|
|
1004
1004
|
const TITLE_USER_PROMPT = (userMessage) => `User request:\n${userMessage}`;
|
|
1005
|
+
const TITLE_GENERATION_TIMEOUT_MS = 8e3;
|
|
1006
|
+
const HORTON_SKILLS_SLASH_COMMAND_OWNER = `horton:skills`;
|
|
1005
1007
|
const TITLE_STOP_WORDS = new Set([
|
|
1006
1008
|
`a`,
|
|
1007
1009
|
`an`,
|
|
@@ -1081,6 +1083,17 @@ function createConfiguredTitleCall(catalog, modelConfig, logPrefix) {
|
|
|
1081
1083
|
maxTokens: 64
|
|
1082
1084
|
});
|
|
1083
1085
|
}
|
|
1086
|
+
function withTimeout(promise, ms, description) {
|
|
1087
|
+
let timeout;
|
|
1088
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
1089
|
+
timeout = setTimeout(() => {
|
|
1090
|
+
reject(new Error(`${description} timed out after ${ms}ms`));
|
|
1091
|
+
}, ms);
|
|
1092
|
+
});
|
|
1093
|
+
return Promise.race([promise, timeoutPromise]).finally(() => {
|
|
1094
|
+
if (timeout) clearTimeout(timeout);
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1084
1097
|
async function generateTitle(userMessage, llmCall, onFallback) {
|
|
1085
1098
|
try {
|
|
1086
1099
|
const raw = await llmCall(TITLE_USER_PROMPT(userMessage));
|
|
@@ -1210,8 +1223,12 @@ function payloadToTitleText(payload) {
|
|
|
1210
1223
|
if (typeof payload === `string`) return payload;
|
|
1211
1224
|
if (payload == null) return ``;
|
|
1212
1225
|
if (typeof payload === `object`) {
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1226
|
+
const record = payload;
|
|
1227
|
+
const text = record.text;
|
|
1228
|
+
if (typeof text === `string`) return text;
|
|
1229
|
+
const source = record.source;
|
|
1230
|
+
if (typeof source === `string`) return source;
|
|
1231
|
+
return JSON.stringify(payload);
|
|
1215
1232
|
}
|
|
1216
1233
|
return String(payload);
|
|
1217
1234
|
}
|
|
@@ -1269,8 +1286,10 @@ async function readAgentsMd(sandbox) {
|
|
|
1269
1286
|
}
|
|
1270
1287
|
function createAssistantHandler(options) {
|
|
1271
1288
|
const { streamFn, docsSupport, docsSearchTool, skillsRegistry, modelCatalog, docsUrl } = options;
|
|
1272
|
-
const
|
|
1289
|
+
const skillLoader = (0, __electric_ax_agents_runtime.createContextSkillLoader)(skillsRegistry, { slashCommandOwner: HORTON_SKILLS_SLASH_COMMAND_OWNER });
|
|
1290
|
+
const hasSkills = skillLoader.hasSkills;
|
|
1273
1291
|
return async function assistantHandler(ctx, wake) {
|
|
1292
|
+
const loadedSkills = await skillLoader.load(ctx);
|
|
1274
1293
|
const readSet = new Set();
|
|
1275
1294
|
const modelConfig = resolveBuiltinModelConfig(modelCatalog, ctx.args);
|
|
1276
1295
|
const sourceBudget = resolveBuiltinModelSourceBudget(modelConfig);
|
|
@@ -1284,7 +1303,7 @@ function createAssistantHandler(options) {
|
|
|
1284
1303
|
modelCatalog,
|
|
1285
1304
|
logPrefix: `[horton ${ctx.entityUrl}]`
|
|
1286
1305
|
}),
|
|
1287
|
-
...
|
|
1306
|
+
...loadedSkills.tools,
|
|
1288
1307
|
...__electric_ax_agents_mcp.mcp.tools()
|
|
1289
1308
|
];
|
|
1290
1309
|
const hasEventSourceTools = tools.some((tool) => getToolName(tool) === `list_event_sources`);
|
|
@@ -1293,15 +1312,16 @@ function createAssistantHandler(options) {
|
|
|
1293
1312
|
if (!firstUserMessage) return;
|
|
1294
1313
|
let title = null;
|
|
1295
1314
|
try {
|
|
1296
|
-
const result = await generateTitle(firstUserMessage, createConfiguredTitleCall(modelCatalog, modelConfig, `[horton ${ctx.entityUrl}]`), (reason) => {
|
|
1315
|
+
const result = await generateTitle(firstUserMessage, (prompt) => withTimeout(createConfiguredTitleCall(modelCatalog, modelConfig, `[horton ${ctx.entityUrl}]`)(prompt), TITLE_GENERATION_TIMEOUT_MS, `title generation`), (reason) => {
|
|
1297
1316
|
serverLog.warn(`[horton ${ctx.entityUrl}] title generation fell back to local title: ${reason}`);
|
|
1298
1317
|
});
|
|
1299
1318
|
if (result.length > 0) title = result;
|
|
1300
1319
|
} catch (err) {
|
|
1301
1320
|
serverLog.warn(`[horton ${ctx.entityUrl}] title generation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1321
|
+
title = buildFallbackTitle(firstUserMessage);
|
|
1302
1322
|
}
|
|
1303
1323
|
if (title !== null) try {
|
|
1304
|
-
await ctx.setTag(`title`, title);
|
|
1324
|
+
await withTimeout(ctx.setTag(`title`, title), TITLE_GENERATION_TIMEOUT_MS, `set title tag`);
|
|
1305
1325
|
} catch (err) {
|
|
1306
1326
|
serverLog.warn(`[horton ${ctx.entityUrl}] setTag failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1307
1327
|
}
|
|
@@ -1328,21 +1348,13 @@ function createAssistantHandler(options) {
|
|
|
1328
1348
|
max: 2e4,
|
|
1329
1349
|
cache: `stable`
|
|
1330
1350
|
} } : {},
|
|
1331
|
-
...skillsRegistry && skillsRegistry.catalog.size > 0 ?
|
|
1332
|
-
content: () => skillsRegistry.renderCatalog(2e3),
|
|
1333
|
-
max: 2e3,
|
|
1334
|
-
cache: `stable`
|
|
1335
|
-
} } : {}
|
|
1351
|
+
...skillsRegistry && skillsRegistry.catalog.size > 0 ? loadedSkills.sources : {}
|
|
1336
1352
|
}
|
|
1337
1353
|
});
|
|
1338
1354
|
else if (skillsRegistry && skillsRegistry.catalog.size > 0) ctx.useContext({
|
|
1339
1355
|
sourceBudget,
|
|
1340
1356
|
sources: {
|
|
1341
|
-
|
|
1342
|
-
content: () => skillsRegistry.renderCatalog(2e3),
|
|
1343
|
-
max: 2e3,
|
|
1344
|
-
cache: `stable`
|
|
1345
|
-
},
|
|
1357
|
+
...loadedSkills.sources,
|
|
1346
1358
|
conversation: {
|
|
1347
1359
|
content: () => ctx.timelineMessages(),
|
|
1348
1360
|
cache: `volatile`
|
|
@@ -1421,6 +1433,7 @@ function registerHorton(registry, options) {
|
|
|
1421
1433
|
subject_value: `user`,
|
|
1422
1434
|
permission: `manage`
|
|
1423
1435
|
}],
|
|
1436
|
+
slashCommands: (0, __electric_ax_agents_runtime.buildSkillSlashCommands)(skillsRegistry),
|
|
1424
1437
|
handler: assistantHandler
|
|
1425
1438
|
});
|
|
1426
1439
|
return [`horton`];
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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, completeWithLowCostModel, createEntityRegistry, createPullWakeRunner, createRuntimeHandler,
|
|
4
|
+
import { MOONSHOT_API_BASE_URL, MOONSHOT_PROVIDER, appendPathToUrl, buildSkillSlashCommands, completeWithLowCostModel, createContextSkillLoader, createEntityRegistry, createPullWakeRunner, createRuntimeHandler, createSkillsRegistry, db, detectAvailableProviders, getMoonshotApiKey, getMoonshotModel, getMoonshotModels, readCodexAccessToken, registerToolProvider, unregisterToolProvider } from "@electric-ax/agents-runtime";
|
|
5
5
|
import { braveSearchTool, braveSearchTool as braveSearchTool$1, createBashTool, createEditTool, createEventSourceTools, createFetchUrlTool, createReadFileTool, createSendTool, createWriteTool } from "@electric-ax/agents-runtime/tools";
|
|
6
6
|
import { chooseDefaultSandbox, isE2BAvailable, remoteSandbox } from "@electric-ax/agents-runtime/sandbox";
|
|
7
7
|
import fsSync from "node:fs";
|
|
@@ -978,6 +978,8 @@ function modelInputSchemaDefs(catalog) {
|
|
|
978
978
|
const HORTON_MODEL = `claude-sonnet-4-6`;
|
|
979
979
|
const TITLE_SYSTEM_PROMPT = "You generate concise chat session titles in 3-5 words. Respond with only the title, no quotes, no punctuation, no preamble.";
|
|
980
980
|
const TITLE_USER_PROMPT = (userMessage) => `User request:\n${userMessage}`;
|
|
981
|
+
const TITLE_GENERATION_TIMEOUT_MS = 8e3;
|
|
982
|
+
const HORTON_SKILLS_SLASH_COMMAND_OWNER = `horton:skills`;
|
|
981
983
|
const TITLE_STOP_WORDS = new Set([
|
|
982
984
|
`a`,
|
|
983
985
|
`an`,
|
|
@@ -1057,6 +1059,17 @@ function createConfiguredTitleCall(catalog, modelConfig, logPrefix) {
|
|
|
1057
1059
|
maxTokens: 64
|
|
1058
1060
|
});
|
|
1059
1061
|
}
|
|
1062
|
+
function withTimeout(promise, ms, description) {
|
|
1063
|
+
let timeout;
|
|
1064
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
1065
|
+
timeout = setTimeout(() => {
|
|
1066
|
+
reject(new Error(`${description} timed out after ${ms}ms`));
|
|
1067
|
+
}, ms);
|
|
1068
|
+
});
|
|
1069
|
+
return Promise.race([promise, timeoutPromise]).finally(() => {
|
|
1070
|
+
if (timeout) clearTimeout(timeout);
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1060
1073
|
async function generateTitle(userMessage, llmCall, onFallback) {
|
|
1061
1074
|
try {
|
|
1062
1075
|
const raw = await llmCall(TITLE_USER_PROMPT(userMessage));
|
|
@@ -1186,8 +1199,12 @@ function payloadToTitleText(payload) {
|
|
|
1186
1199
|
if (typeof payload === `string`) return payload;
|
|
1187
1200
|
if (payload == null) return ``;
|
|
1188
1201
|
if (typeof payload === `object`) {
|
|
1189
|
-
const
|
|
1190
|
-
|
|
1202
|
+
const record = payload;
|
|
1203
|
+
const text = record.text;
|
|
1204
|
+
if (typeof text === `string`) return text;
|
|
1205
|
+
const source = record.source;
|
|
1206
|
+
if (typeof source === `string`) return source;
|
|
1207
|
+
return JSON.stringify(payload);
|
|
1191
1208
|
}
|
|
1192
1209
|
return String(payload);
|
|
1193
1210
|
}
|
|
@@ -1245,8 +1262,10 @@ async function readAgentsMd(sandbox) {
|
|
|
1245
1262
|
}
|
|
1246
1263
|
function createAssistantHandler(options) {
|
|
1247
1264
|
const { streamFn, docsSupport, docsSearchTool, skillsRegistry, modelCatalog, docsUrl } = options;
|
|
1248
|
-
const
|
|
1265
|
+
const skillLoader = createContextSkillLoader(skillsRegistry, { slashCommandOwner: HORTON_SKILLS_SLASH_COMMAND_OWNER });
|
|
1266
|
+
const hasSkills = skillLoader.hasSkills;
|
|
1249
1267
|
return async function assistantHandler(ctx, wake) {
|
|
1268
|
+
const loadedSkills = await skillLoader.load(ctx);
|
|
1250
1269
|
const readSet = new Set();
|
|
1251
1270
|
const modelConfig = resolveBuiltinModelConfig(modelCatalog, ctx.args);
|
|
1252
1271
|
const sourceBudget = resolveBuiltinModelSourceBudget(modelConfig);
|
|
@@ -1260,7 +1279,7 @@ function createAssistantHandler(options) {
|
|
|
1260
1279
|
modelCatalog,
|
|
1261
1280
|
logPrefix: `[horton ${ctx.entityUrl}]`
|
|
1262
1281
|
}),
|
|
1263
|
-
...
|
|
1282
|
+
...loadedSkills.tools,
|
|
1264
1283
|
...mcp.tools()
|
|
1265
1284
|
];
|
|
1266
1285
|
const hasEventSourceTools = tools.some((tool) => getToolName(tool) === `list_event_sources`);
|
|
@@ -1269,15 +1288,16 @@ function createAssistantHandler(options) {
|
|
|
1269
1288
|
if (!firstUserMessage) return;
|
|
1270
1289
|
let title = null;
|
|
1271
1290
|
try {
|
|
1272
|
-
const result = await generateTitle(firstUserMessage, createConfiguredTitleCall(modelCatalog, modelConfig, `[horton ${ctx.entityUrl}]`), (reason) => {
|
|
1291
|
+
const result = await generateTitle(firstUserMessage, (prompt) => withTimeout(createConfiguredTitleCall(modelCatalog, modelConfig, `[horton ${ctx.entityUrl}]`)(prompt), TITLE_GENERATION_TIMEOUT_MS, `title generation`), (reason) => {
|
|
1273
1292
|
serverLog.warn(`[horton ${ctx.entityUrl}] title generation fell back to local title: ${reason}`);
|
|
1274
1293
|
});
|
|
1275
1294
|
if (result.length > 0) title = result;
|
|
1276
1295
|
} catch (err) {
|
|
1277
1296
|
serverLog.warn(`[horton ${ctx.entityUrl}] title generation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1297
|
+
title = buildFallbackTitle(firstUserMessage);
|
|
1278
1298
|
}
|
|
1279
1299
|
if (title !== null) try {
|
|
1280
|
-
await ctx.setTag(`title`, title);
|
|
1300
|
+
await withTimeout(ctx.setTag(`title`, title), TITLE_GENERATION_TIMEOUT_MS, `set title tag`);
|
|
1281
1301
|
} catch (err) {
|
|
1282
1302
|
serverLog.warn(`[horton ${ctx.entityUrl}] setTag failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1283
1303
|
}
|
|
@@ -1304,21 +1324,13 @@ function createAssistantHandler(options) {
|
|
|
1304
1324
|
max: 2e4,
|
|
1305
1325
|
cache: `stable`
|
|
1306
1326
|
} } : {},
|
|
1307
|
-
...skillsRegistry && skillsRegistry.catalog.size > 0 ?
|
|
1308
|
-
content: () => skillsRegistry.renderCatalog(2e3),
|
|
1309
|
-
max: 2e3,
|
|
1310
|
-
cache: `stable`
|
|
1311
|
-
} } : {}
|
|
1327
|
+
...skillsRegistry && skillsRegistry.catalog.size > 0 ? loadedSkills.sources : {}
|
|
1312
1328
|
}
|
|
1313
1329
|
});
|
|
1314
1330
|
else if (skillsRegistry && skillsRegistry.catalog.size > 0) ctx.useContext({
|
|
1315
1331
|
sourceBudget,
|
|
1316
1332
|
sources: {
|
|
1317
|
-
|
|
1318
|
-
content: () => skillsRegistry.renderCatalog(2e3),
|
|
1319
|
-
max: 2e3,
|
|
1320
|
-
cache: `stable`
|
|
1321
|
-
},
|
|
1333
|
+
...loadedSkills.sources,
|
|
1322
1334
|
conversation: {
|
|
1323
1335
|
content: () => ctx.timelineMessages(),
|
|
1324
1336
|
cache: `volatile`
|
|
@@ -1397,6 +1409,7 @@ function registerHorton(registry, options) {
|
|
|
1397
1409
|
subject_value: `user`,
|
|
1398
1410
|
permission: `manage`
|
|
1399
1411
|
}],
|
|
1412
|
+
slashCommands: buildSkillSlashCommands(skillsRegistry),
|
|
1400
1413
|
handler: assistantHandler
|
|
1401
1414
|
});
|
|
1402
1415
|
return [`horton`];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@electric-ax/agents",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.14",
|
|
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.2",
|
|
53
|
-
"@electric-ax/agents-runtime": "0.3.
|
|
53
|
+
"@electric-ax/agents-runtime": "0.3.10"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/better-sqlite3": "^7.6.13",
|