@deepagents/toolbox 0.1.0 → 0.1.1
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/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +755 -5
- package/dist/index.js.map +4 -4
- package/dist/lib/hackernews-search.d.ts +237 -0
- package/dist/lib/hackernews-search.d.ts.map +1 -0
- package/package.json +5 -7
package/dist/index.js
CHANGED
|
@@ -503,6 +503,7 @@ var Agent = class _Agent {
|
|
|
503
503
|
handoffTool;
|
|
504
504
|
output;
|
|
505
505
|
temperature;
|
|
506
|
+
providerOptions;
|
|
506
507
|
constructor(config) {
|
|
507
508
|
this.model = config.model;
|
|
508
509
|
this.toolChoice = config.toolChoice || "auto";
|
|
@@ -512,6 +513,7 @@ var Agent = class _Agent {
|
|
|
512
513
|
this.output = config.output;
|
|
513
514
|
this.temperature = config.temperature;
|
|
514
515
|
this.internalName = snakecase(config.name);
|
|
516
|
+
this.providerOptions = config.providerOptions;
|
|
515
517
|
this.handoff = {
|
|
516
518
|
name: this.internalName,
|
|
517
519
|
instructions: config.prompt,
|
|
@@ -590,14 +592,24 @@ var Agent = class _Agent {
|
|
|
590
592
|
return tool4({
|
|
591
593
|
description: props?.toolDescription || this.handoff.handoffDescription,
|
|
592
594
|
inputSchema: z4.object({
|
|
593
|
-
input: z4.string()
|
|
595
|
+
input: z4.string(),
|
|
596
|
+
output: z4.string().optional().describe(
|
|
597
|
+
"Optional instructions on how the final output should be formatted. this would be passed to the underlying llm as part of the prompt."
|
|
598
|
+
)
|
|
594
599
|
}),
|
|
595
|
-
execute: async ({ input: input2 }, options) => {
|
|
600
|
+
execute: async ({ input: input2, output }, options) => {
|
|
596
601
|
try {
|
|
597
602
|
const result = await generateText2({
|
|
598
603
|
model: this.model,
|
|
599
604
|
system: this.#prepareInstructions(),
|
|
600
|
-
prompt:
|
|
605
|
+
prompt: `
|
|
606
|
+
<Input>
|
|
607
|
+
${input2}
|
|
608
|
+
</Input>
|
|
609
|
+
${output ? `<OutputInstructions>
|
|
610
|
+
${output}
|
|
611
|
+
</OutputInstructions>` : ""}
|
|
612
|
+
`,
|
|
601
613
|
temperature: 0,
|
|
602
614
|
tools: this.handoff.tools,
|
|
603
615
|
abortSignal: options.abortSignal,
|
|
@@ -624,7 +636,10 @@ var Agent = class _Agent {
|
|
|
624
636
|
return result.steps.map((it) => it.toolResults).flat();
|
|
625
637
|
} catch (error) {
|
|
626
638
|
console.error(error);
|
|
627
|
-
return `
|
|
639
|
+
return `An error thrown from a tool call.
|
|
640
|
+
<ErrorDetails>
|
|
641
|
+
${JSON.stringify(error)}
|
|
642
|
+
</ErrorDetails>`;
|
|
628
643
|
}
|
|
629
644
|
}
|
|
630
645
|
});
|
|
@@ -634,7 +649,7 @@ var Agent = class _Agent {
|
|
|
634
649
|
}
|
|
635
650
|
debug(prefix = "") {
|
|
636
651
|
console.log(
|
|
637
|
-
`Debug: ${chalk2.bgMagenta("Agent")}: ${chalk2.
|
|
652
|
+
`Debug: ${chalk2.bgMagenta("Agent")}: ${chalk2.dim.black(this.handoff.name)}`
|
|
638
653
|
);
|
|
639
654
|
const transferTools = this.toolsNames.filter((toolName) => toolName.startsWith("transfer_to")).map((toolName) => toolName.replace("transfer_to_", ""));
|
|
640
655
|
const agentTools = this.toolsNames.filter(
|
|
@@ -1039,6 +1054,726 @@ ${formatted}
|
|
|
1039
1054
|
Total stories recorded: ${context.userStories.length}`;
|
|
1040
1055
|
}
|
|
1041
1056
|
});
|
|
1057
|
+
|
|
1058
|
+
// packages/toolbox/src/lib/hackernews-search.ts
|
|
1059
|
+
import { tool as tool8 } from "ai";
|
|
1060
|
+
import { z as z8 } from "zod";
|
|
1061
|
+
function buildTags(options) {
|
|
1062
|
+
const tags = [];
|
|
1063
|
+
if (options.type && options.type !== "all") {
|
|
1064
|
+
tags.push(options.type);
|
|
1065
|
+
}
|
|
1066
|
+
if (options.author) {
|
|
1067
|
+
tags.push(`author_${options.author}`);
|
|
1068
|
+
}
|
|
1069
|
+
return tags.length > 0 ? tags.join(",") : void 0;
|
|
1070
|
+
}
|
|
1071
|
+
function buildNumericFilters(options) {
|
|
1072
|
+
const filters = [];
|
|
1073
|
+
if (options.timeFilter && options.timeFilter !== "all") {
|
|
1074
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1075
|
+
const timeMap = {
|
|
1076
|
+
d: 86400,
|
|
1077
|
+
// 1 day in seconds
|
|
1078
|
+
w: 604800,
|
|
1079
|
+
// 1 week
|
|
1080
|
+
m: 2592e3,
|
|
1081
|
+
// ~30 days
|
|
1082
|
+
y: 31536e3
|
|
1083
|
+
// ~365 days
|
|
1084
|
+
};
|
|
1085
|
+
const seconds = timeMap[options.timeFilter];
|
|
1086
|
+
const timestamp = now - seconds;
|
|
1087
|
+
filters.push(`created_at_i>${timestamp}`);
|
|
1088
|
+
}
|
|
1089
|
+
if (options.maxAgeHours !== void 0 && options.maxAgeHours > 0) {
|
|
1090
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1091
|
+
const seconds = options.maxAgeHours * 3600;
|
|
1092
|
+
const timestamp = now - seconds;
|
|
1093
|
+
filters.push(`created_at_i>${timestamp}`);
|
|
1094
|
+
}
|
|
1095
|
+
if (options.minPoints !== void 0 && options.minPoints > 0) {
|
|
1096
|
+
filters.push(`points>=${options.minPoints}`);
|
|
1097
|
+
}
|
|
1098
|
+
if (options.minComments !== void 0 && options.minComments > 0) {
|
|
1099
|
+
filters.push(`num_comments>=${options.minComments}`);
|
|
1100
|
+
}
|
|
1101
|
+
return filters.length > 0 ? filters.join(",") : void 0;
|
|
1102
|
+
}
|
|
1103
|
+
async function searchHackerNewsAPI(params) {
|
|
1104
|
+
const {
|
|
1105
|
+
query = "",
|
|
1106
|
+
tags,
|
|
1107
|
+
numericFilters,
|
|
1108
|
+
sortBy = "relevance",
|
|
1109
|
+
page = 0,
|
|
1110
|
+
hitsPerPage = 20
|
|
1111
|
+
} = params;
|
|
1112
|
+
const endpoint = sortBy === "date" ? "http://hn.algolia.com/api/v1/search_by_date" : "http://hn.algolia.com/api/v1/search";
|
|
1113
|
+
const urlParams = new URLSearchParams();
|
|
1114
|
+
if (query) {
|
|
1115
|
+
urlParams.set("query", query);
|
|
1116
|
+
}
|
|
1117
|
+
if (tags) {
|
|
1118
|
+
urlParams.set("tags", tags);
|
|
1119
|
+
}
|
|
1120
|
+
if (numericFilters) {
|
|
1121
|
+
urlParams.set("numericFilters", numericFilters);
|
|
1122
|
+
}
|
|
1123
|
+
urlParams.set("page", page.toString());
|
|
1124
|
+
urlParams.set("hitsPerPage", Math.min(hitsPerPage, 1e3).toString());
|
|
1125
|
+
const url = `${endpoint}?${urlParams.toString()}`;
|
|
1126
|
+
try {
|
|
1127
|
+
const response = await fetch(url, {
|
|
1128
|
+
headers: {
|
|
1129
|
+
"Content-Type": "application/json"
|
|
1130
|
+
}
|
|
1131
|
+
});
|
|
1132
|
+
if (!response.ok) {
|
|
1133
|
+
throw new Error(
|
|
1134
|
+
`HN API error: ${response.status} ${response.statusText}`
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
const data = await response.json();
|
|
1138
|
+
return data;
|
|
1139
|
+
} catch (error) {
|
|
1140
|
+
throw new Error(
|
|
1141
|
+
`Failed to search HackerNews: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
async function fetchHNItem(id) {
|
|
1146
|
+
const url = `http://hn.algolia.com/api/v1/items/${id}`;
|
|
1147
|
+
try {
|
|
1148
|
+
const response = await fetch(url, {
|
|
1149
|
+
headers: {
|
|
1150
|
+
"Content-Type": "application/json"
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
if (!response.ok) {
|
|
1154
|
+
throw new Error(
|
|
1155
|
+
`HN API error: ${response.status} ${response.statusText}`
|
|
1156
|
+
);
|
|
1157
|
+
}
|
|
1158
|
+
const data = await response.json();
|
|
1159
|
+
return data;
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
throw new Error(
|
|
1162
|
+
`Failed to fetch HN item: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
async function fetchHNUser(username) {
|
|
1167
|
+
const url = `http://hn.algolia.com/api/v1/users/${username}`;
|
|
1168
|
+
try {
|
|
1169
|
+
const response = await fetch(url, {
|
|
1170
|
+
headers: {
|
|
1171
|
+
"Content-Type": "application/json"
|
|
1172
|
+
}
|
|
1173
|
+
});
|
|
1174
|
+
if (!response.ok) {
|
|
1175
|
+
throw new Error(
|
|
1176
|
+
`HN API error: ${response.status} ${response.statusText}`
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
const data = await response.json();
|
|
1180
|
+
return data;
|
|
1181
|
+
} catch (error) {
|
|
1182
|
+
throw new Error(
|
|
1183
|
+
`Failed to fetch HN user: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
function formatDate(timestamp) {
|
|
1188
|
+
return new Date(timestamp * 1e3).toLocaleString();
|
|
1189
|
+
}
|
|
1190
|
+
function formatHNLink(id) {
|
|
1191
|
+
return `https://news.ycombinator.com/item?id=${id}`;
|
|
1192
|
+
}
|
|
1193
|
+
function truncateText(text, maxLength) {
|
|
1194
|
+
if (text.length <= maxLength) return text;
|
|
1195
|
+
return `${text.substring(0, maxLength)}...`;
|
|
1196
|
+
}
|
|
1197
|
+
function formatStoryItem(hit, index, page, hitsPerPage) {
|
|
1198
|
+
const lines = [];
|
|
1199
|
+
const itemNumber = page * hitsPerPage + index + 1;
|
|
1200
|
+
lines.push(`
|
|
1201
|
+
${itemNumber}. ${hit.title || "(No title)"}`);
|
|
1202
|
+
if (hit.url) {
|
|
1203
|
+
lines.push(` URL: ${hit.url}`);
|
|
1204
|
+
}
|
|
1205
|
+
if (hit.points !== null) {
|
|
1206
|
+
lines.push(
|
|
1207
|
+
` ${hit.points} points | by ${hit.author} | ${hit.num_comments || 0} comments`
|
|
1208
|
+
);
|
|
1209
|
+
} else {
|
|
1210
|
+
lines.push(` by ${hit.author}`);
|
|
1211
|
+
}
|
|
1212
|
+
lines.push(` Date: ${formatDate(hit.created_at_i)}`);
|
|
1213
|
+
if (hit.story_text) {
|
|
1214
|
+
lines.push(` Text: ${truncateText(hit.story_text, 200)}`);
|
|
1215
|
+
}
|
|
1216
|
+
lines.push(` HN Link: ${formatHNLink(hit.objectID)}`);
|
|
1217
|
+
return lines.join("\n");
|
|
1218
|
+
}
|
|
1219
|
+
function formatCommentItem(hit, index, page, hitsPerPage) {
|
|
1220
|
+
const lines = [];
|
|
1221
|
+
const itemNumber = page * hitsPerPage + index + 1;
|
|
1222
|
+
lines.push(`
|
|
1223
|
+
${itemNumber}. Comment by ${hit.author}`);
|
|
1224
|
+
if (hit.comment_text) {
|
|
1225
|
+
lines.push(` ${truncateText(hit.comment_text, 300)}`);
|
|
1226
|
+
}
|
|
1227
|
+
lines.push(` Date: ${formatDate(hit.created_at_i)}`);
|
|
1228
|
+
lines.push(` HN Link: ${formatHNLink(hit.objectID)}`);
|
|
1229
|
+
return lines.join("\n");
|
|
1230
|
+
}
|
|
1231
|
+
function formatMixedItem(hit, index, page, hitsPerPage) {
|
|
1232
|
+
const lines = [];
|
|
1233
|
+
const itemNumber = page * hitsPerPage + index + 1;
|
|
1234
|
+
const isStory = hit._tags.includes("story");
|
|
1235
|
+
const isComment = hit._tags.includes("comment");
|
|
1236
|
+
const type = isStory ? "Story" : "Comment";
|
|
1237
|
+
lines.push(`
|
|
1238
|
+
${itemNumber}. [${type}] ${hit.title || "Comment"}`);
|
|
1239
|
+
if (isStory) {
|
|
1240
|
+
if (hit.url) {
|
|
1241
|
+
lines.push(` URL: ${hit.url}`);
|
|
1242
|
+
}
|
|
1243
|
+
if (hit.points !== null) {
|
|
1244
|
+
lines.push(` ${hit.points} points | ${hit.num_comments || 0} comments`);
|
|
1245
|
+
}
|
|
1246
|
+
if (hit.story_text) {
|
|
1247
|
+
lines.push(` Text: ${truncateText(hit.story_text, 200)}`);
|
|
1248
|
+
}
|
|
1249
|
+
} else if (isComment && hit.comment_text) {
|
|
1250
|
+
lines.push(` ${truncateText(hit.comment_text, 200)}`);
|
|
1251
|
+
}
|
|
1252
|
+
lines.push(` Date: ${formatDate(hit.created_at_i)}`);
|
|
1253
|
+
lines.push(` HN Link: ${formatHNLink(hit.objectID)}`);
|
|
1254
|
+
return lines.join("\n");
|
|
1255
|
+
}
|
|
1256
|
+
function formatSearchResults(response, options) {
|
|
1257
|
+
const { hits, nbHits, page, nbPages } = response;
|
|
1258
|
+
const { itemType, emptyMessage } = options;
|
|
1259
|
+
if (hits.length === 0) {
|
|
1260
|
+
return emptyMessage;
|
|
1261
|
+
}
|
|
1262
|
+
const formatItem = (hit, index) => {
|
|
1263
|
+
switch (itemType) {
|
|
1264
|
+
case "story":
|
|
1265
|
+
return formatStoryItem(hit, index, page, response.hitsPerPage);
|
|
1266
|
+
case "comment":
|
|
1267
|
+
return formatCommentItem(hit, index, page, response.hitsPerPage);
|
|
1268
|
+
case "mixed":
|
|
1269
|
+
return formatMixedItem(hit, index, page, response.hitsPerPage);
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
const results = hits.map(formatItem);
|
|
1273
|
+
const typeLabel = itemType === "mixed" ? "results" : `${itemType === "story" ? "stories" : "comments"}`;
|
|
1274
|
+
const header = `Found ${nbHits} ${typeLabel} (showing page ${page + 1} of ${nbPages}):
|
|
1275
|
+
`;
|
|
1276
|
+
return header + results.join("\n");
|
|
1277
|
+
}
|
|
1278
|
+
function formatStoryResults(response) {
|
|
1279
|
+
return formatSearchResults(response, {
|
|
1280
|
+
itemType: "story",
|
|
1281
|
+
emptyMessage: `No stories found for query: "${response.query}"`
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
function formatCommentResults(response) {
|
|
1285
|
+
return formatSearchResults(response, {
|
|
1286
|
+
itemType: "comment",
|
|
1287
|
+
emptyMessage: `No comments found for query: "${response.query}"`
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
function formatAuthorResults(response) {
|
|
1291
|
+
return formatSearchResults(response, {
|
|
1292
|
+
itemType: "mixed",
|
|
1293
|
+
emptyMessage: "No results found for this author"
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
function formatItemDetails(item) {
|
|
1297
|
+
const lines = [];
|
|
1298
|
+
if (item.type === "story") {
|
|
1299
|
+
lines.push(`Story: ${item.title || "(No title)"}`);
|
|
1300
|
+
if (item.url) {
|
|
1301
|
+
lines.push(`URL: ${item.url}`);
|
|
1302
|
+
}
|
|
1303
|
+
lines.push(`By: ${item.author}`);
|
|
1304
|
+
if (item.points !== void 0) {
|
|
1305
|
+
lines.push(`Points: ${item.points}`);
|
|
1306
|
+
}
|
|
1307
|
+
lines.push(`Date: ${formatDate(item.created_at_i)}`);
|
|
1308
|
+
if (item.text) {
|
|
1309
|
+
lines.push(`
|
|
1310
|
+
Text:
|
|
1311
|
+
${item.text}`);
|
|
1312
|
+
}
|
|
1313
|
+
lines.push(`
|
|
1314
|
+
HN Link: ${formatHNLink(item.id)}`);
|
|
1315
|
+
} else if (item.type === "comment") {
|
|
1316
|
+
lines.push(`Comment by ${item.author}`);
|
|
1317
|
+
if (item.story_title) {
|
|
1318
|
+
lines.push(`On story: ${item.story_title}`);
|
|
1319
|
+
}
|
|
1320
|
+
lines.push(`Date: ${formatDate(item.created_at_i)}`);
|
|
1321
|
+
if (item.text) {
|
|
1322
|
+
lines.push(`
|
|
1323
|
+
${item.text}`);
|
|
1324
|
+
}
|
|
1325
|
+
lines.push(`
|
|
1326
|
+
HN Link: ${formatHNLink(item.id)}`);
|
|
1327
|
+
}
|
|
1328
|
+
return lines.join("\n");
|
|
1329
|
+
}
|
|
1330
|
+
function formatUserProfile(user) {
|
|
1331
|
+
const lines = [];
|
|
1332
|
+
lines.push(`User: ${user.username}`);
|
|
1333
|
+
lines.push(`Karma: ${user.karma.toLocaleString()}`);
|
|
1334
|
+
lines.push(`Member since: ${formatDate(user.created_at_i)}`);
|
|
1335
|
+
if (user.about) {
|
|
1336
|
+
lines.push(`
|
|
1337
|
+
About:
|
|
1338
|
+
${user.about}`);
|
|
1339
|
+
}
|
|
1340
|
+
lines.push(
|
|
1341
|
+
`
|
|
1342
|
+
Profile: https://news.ycombinator.com/user?id=${user.username}`
|
|
1343
|
+
);
|
|
1344
|
+
return lines.join("\n");
|
|
1345
|
+
}
|
|
1346
|
+
function formatJobItem(hit, index, page, hitsPerPage) {
|
|
1347
|
+
const lines = [];
|
|
1348
|
+
const itemNumber = page * hitsPerPage + index + 1;
|
|
1349
|
+
lines.push(`
|
|
1350
|
+
${itemNumber}. ${hit.title || "(No title)"}`);
|
|
1351
|
+
if (hit.url) {
|
|
1352
|
+
lines.push(` URL: ${hit.url}`);
|
|
1353
|
+
}
|
|
1354
|
+
lines.push(` Posted by: ${hit.author}`);
|
|
1355
|
+
lines.push(` Date: ${formatDate(hit.created_at_i)}`);
|
|
1356
|
+
if (hit.story_text) {
|
|
1357
|
+
lines.push(` Description: ${truncateText(hit.story_text, 300)}`);
|
|
1358
|
+
}
|
|
1359
|
+
lines.push(` HN Link: ${formatHNLink(hit.objectID)}`);
|
|
1360
|
+
return lines.join("\n");
|
|
1361
|
+
}
|
|
1362
|
+
function formatJobResults(response) {
|
|
1363
|
+
const { hits, nbHits, page, nbPages } = response;
|
|
1364
|
+
if (hits.length === 0) {
|
|
1365
|
+
return `No job postings found for query: "${response.query}"`;
|
|
1366
|
+
}
|
|
1367
|
+
const results = hits.map(
|
|
1368
|
+
(hit, index) => formatJobItem(hit, index, page, response.hitsPerPage)
|
|
1369
|
+
);
|
|
1370
|
+
const header = `Found ${nbHits} job postings (showing page ${page + 1} of ${nbPages}):
|
|
1371
|
+
`;
|
|
1372
|
+
return header + results.join("\n");
|
|
1373
|
+
}
|
|
1374
|
+
var search_by_query = tool8({
|
|
1375
|
+
description: "Tool to search HackerNews stories by keywords and filters. Use when you need to find HN stories matching specific search criteria, time periods, or popularity thresholds.",
|
|
1376
|
+
inputSchema: z8.object({
|
|
1377
|
+
query: z8.string().describe(
|
|
1378
|
+
'Search query for story titles and content. Examples: "artificial intelligence", "python"'
|
|
1379
|
+
),
|
|
1380
|
+
timeFilter: z8.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
1381
|
+
minPoints: z8.number().int().min(0).optional().describe("Minimum points threshold"),
|
|
1382
|
+
minComments: z8.number().int().min(0).optional().describe("Minimum comments threshold"),
|
|
1383
|
+
sortBy: z8.enum(["relevance", "date"]).default("relevance").describe("Sort results by relevance or date"),
|
|
1384
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1385
|
+
hitsPerPage: z8.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1386
|
+
}),
|
|
1387
|
+
execute: async (input, options) => {
|
|
1388
|
+
const context = toState(options);
|
|
1389
|
+
context.hackernews_sources ??= [];
|
|
1390
|
+
const numericFilters = buildNumericFilters({
|
|
1391
|
+
timeFilter: input.timeFilter,
|
|
1392
|
+
minPoints: input.minPoints,
|
|
1393
|
+
minComments: input.minComments
|
|
1394
|
+
});
|
|
1395
|
+
const response = await searchHackerNewsAPI({
|
|
1396
|
+
query: input.query,
|
|
1397
|
+
tags: "story",
|
|
1398
|
+
numericFilters,
|
|
1399
|
+
sortBy: input.sortBy,
|
|
1400
|
+
page: input.page,
|
|
1401
|
+
hitsPerPage: input.hitsPerPage
|
|
1402
|
+
});
|
|
1403
|
+
fillContext(context, response);
|
|
1404
|
+
return formatStoryResults(response);
|
|
1405
|
+
}
|
|
1406
|
+
});
|
|
1407
|
+
var search_by_author = tool8({
|
|
1408
|
+
description: "Tool to search HackerNews content by author username. Use when you need to find all stories, comments, or both by a specific HN user.",
|
|
1409
|
+
inputSchema: z8.object({
|
|
1410
|
+
author: z8.string().describe('HackerNews username to search for. Examples: "pg", "tptacek"'),
|
|
1411
|
+
type: z8.enum(["story", "comment", "all"]).default("all").describe("Type of content: story, comment, or all"),
|
|
1412
|
+
timeFilter: z8.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
1413
|
+
minComments: z8.number().int().min(0).optional().describe("Minimum comments threshold (for stories only)"),
|
|
1414
|
+
sortBy: z8.enum(["relevance", "date"]).default("date").describe("Sort results by relevance or date"),
|
|
1415
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1416
|
+
hitsPerPage: z8.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1417
|
+
}),
|
|
1418
|
+
execute: async (input, options) => {
|
|
1419
|
+
const context = toState(options);
|
|
1420
|
+
context.hackernews_sources ??= [];
|
|
1421
|
+
const tags = buildTags({ type: input.type, author: input.author });
|
|
1422
|
+
const numericFilters = buildNumericFilters({
|
|
1423
|
+
timeFilter: input.timeFilter,
|
|
1424
|
+
minComments: input.minComments
|
|
1425
|
+
});
|
|
1426
|
+
const response = await searchHackerNewsAPI({
|
|
1427
|
+
tags,
|
|
1428
|
+
numericFilters,
|
|
1429
|
+
sortBy: input.sortBy,
|
|
1430
|
+
page: input.page,
|
|
1431
|
+
hitsPerPage: input.hitsPerPage
|
|
1432
|
+
});
|
|
1433
|
+
fillContext(context, response);
|
|
1434
|
+
return formatAuthorResults(response);
|
|
1435
|
+
}
|
|
1436
|
+
});
|
|
1437
|
+
var get_story_item = tool8({
|
|
1438
|
+
description: "Tool to get detailed information about a specific HackerNews story by ID. Use when you need full details about a particular HN story including title, URL, author, points, and comments.",
|
|
1439
|
+
inputSchema: z8.object({
|
|
1440
|
+
storyId: z8.string().describe('HackerNews story ID. Example: "38709478"')
|
|
1441
|
+
}),
|
|
1442
|
+
execute: async (input, options) => {
|
|
1443
|
+
const context = toState(options);
|
|
1444
|
+
context.hackernews_sources ??= [];
|
|
1445
|
+
const item = await fetchHNItem(input.storyId);
|
|
1446
|
+
if (item.type !== "story") {
|
|
1447
|
+
throw new Error(
|
|
1448
|
+
`Item ${input.storyId} is not a story (type: ${item.type})`
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
context.hackernews_sources.push({
|
|
1452
|
+
title: item.title || "Untitled",
|
|
1453
|
+
hn_url: `https://news.ycombinator.com/item?id=${item.id}`,
|
|
1454
|
+
story_url: item.url || ""
|
|
1455
|
+
});
|
|
1456
|
+
return formatItemDetails(item);
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
var get_story_comment = tool8({
|
|
1460
|
+
description: "Tool to get detailed information about a specific HackerNews comment by ID. Use when you need full details about a particular comment including text, author, and parent story information.",
|
|
1461
|
+
inputSchema: z8.object({
|
|
1462
|
+
commentId: z8.string().describe('HackerNews comment ID. Example: "38710123"')
|
|
1463
|
+
}),
|
|
1464
|
+
execute: async (input) => {
|
|
1465
|
+
const item = await fetchHNItem(input.commentId);
|
|
1466
|
+
if (item.type !== "comment") {
|
|
1467
|
+
throw new Error(
|
|
1468
|
+
`Item ${input.commentId} is not a comment (type: ${item.type})`
|
|
1469
|
+
);
|
|
1470
|
+
}
|
|
1471
|
+
return formatItemDetails(item);
|
|
1472
|
+
}
|
|
1473
|
+
});
|
|
1474
|
+
var get_front_page_stories = tool8({
|
|
1475
|
+
description: "Tool to get current HackerNews front page stories. Use when you need to see the latest trending and popular stories on HN.",
|
|
1476
|
+
inputSchema: z8.object({
|
|
1477
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1478
|
+
hitsPerPage: z8.number().int().min(1).max(50).default(30).describe("Results per page (max 50)")
|
|
1479
|
+
}),
|
|
1480
|
+
execute: async (input, options) => {
|
|
1481
|
+
const context = toState(options);
|
|
1482
|
+
context.hackernews_sources ??= [];
|
|
1483
|
+
const response = await searchHackerNewsAPI({
|
|
1484
|
+
tags: "front_page",
|
|
1485
|
+
sortBy: "date",
|
|
1486
|
+
page: input.page,
|
|
1487
|
+
hitsPerPage: input.hitsPerPage
|
|
1488
|
+
});
|
|
1489
|
+
fillContext(context, response);
|
|
1490
|
+
return formatStoryResults(response);
|
|
1491
|
+
}
|
|
1492
|
+
});
|
|
1493
|
+
var get_story_comments = tool8({
|
|
1494
|
+
description: "Tool to get all comments for a specific HackerNews story. Use when you need to read the discussion and comments on a particular HN story.",
|
|
1495
|
+
inputSchema: z8.object({
|
|
1496
|
+
storyId: z8.string().describe('HackerNews story ID. Example: "38709478"'),
|
|
1497
|
+
sortBy: z8.enum(["relevance", "date"]).default("date").describe("Sort comments by relevance or date"),
|
|
1498
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1499
|
+
hitsPerPage: z8.number().int().min(1).max(1e3).default(50).describe("Results per page (max 1000)")
|
|
1500
|
+
}),
|
|
1501
|
+
execute: async (input) => {
|
|
1502
|
+
const response = await searchHackerNewsAPI({
|
|
1503
|
+
tags: `comment,story_${input.storyId}`,
|
|
1504
|
+
sortBy: input.sortBy,
|
|
1505
|
+
page: input.page,
|
|
1506
|
+
hitsPerPage: input.hitsPerPage
|
|
1507
|
+
});
|
|
1508
|
+
return formatCommentResults(response);
|
|
1509
|
+
}
|
|
1510
|
+
});
|
|
1511
|
+
var search_ask_hn = tool8({
|
|
1512
|
+
description: "Tool to search Ask HN posts - questions posed to the HackerNews community. Use when you need to find community questions and discussions on specific topics.",
|
|
1513
|
+
inputSchema: z8.object({
|
|
1514
|
+
query: z8.string().default("").describe(
|
|
1515
|
+
'Search query for Ask HN posts. Examples: "artificial intelligence", "career"'
|
|
1516
|
+
),
|
|
1517
|
+
timeFilter: z8.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
1518
|
+
minPoints: z8.number().int().min(0).optional().describe("Minimum points threshold"),
|
|
1519
|
+
minComments: z8.number().int().min(0).optional().describe("Minimum comments threshold"),
|
|
1520
|
+
sortBy: z8.enum(["relevance", "date"]).default("relevance").describe("Sort by relevance or date"),
|
|
1521
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1522
|
+
hitsPerPage: z8.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1523
|
+
}),
|
|
1524
|
+
execute: async (input, options) => {
|
|
1525
|
+
const context = toState(options);
|
|
1526
|
+
context.hackernews_sources ??= [];
|
|
1527
|
+
const numericFilters = buildNumericFilters({
|
|
1528
|
+
timeFilter: input.timeFilter,
|
|
1529
|
+
minPoints: input.minPoints,
|
|
1530
|
+
minComments: input.minComments
|
|
1531
|
+
});
|
|
1532
|
+
const response = await searchHackerNewsAPI({
|
|
1533
|
+
query: input.query,
|
|
1534
|
+
tags: "ask_hn",
|
|
1535
|
+
numericFilters,
|
|
1536
|
+
sortBy: input.sortBy,
|
|
1537
|
+
page: input.page,
|
|
1538
|
+
hitsPerPage: input.hitsPerPage
|
|
1539
|
+
});
|
|
1540
|
+
fillContext(context, response);
|
|
1541
|
+
return formatStoryResults(response);
|
|
1542
|
+
}
|
|
1543
|
+
});
|
|
1544
|
+
var search_show_hn = tool8({
|
|
1545
|
+
description: "Tool to search Show HN posts - projects and products shared with the HackerNews community. Use when you need to discover community projects, demos, or products on specific topics.",
|
|
1546
|
+
inputSchema: z8.object({
|
|
1547
|
+
query: z8.string().default("").describe(
|
|
1548
|
+
'Search query for Show HN posts. Examples: "web app", "open source"'
|
|
1549
|
+
),
|
|
1550
|
+
timeFilter: z8.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
1551
|
+
minPoints: z8.number().int().min(0).optional().describe("Minimum points threshold"),
|
|
1552
|
+
minComments: z8.number().int().min(0).optional().describe("Minimum comments threshold"),
|
|
1553
|
+
sortBy: z8.enum(["relevance", "date"]).default("relevance").describe("Sort by relevance or date"),
|
|
1554
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1555
|
+
hitsPerPage: z8.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1556
|
+
}),
|
|
1557
|
+
execute: async (input, options) => {
|
|
1558
|
+
const context = toState(options);
|
|
1559
|
+
context.hackernews_sources ??= [];
|
|
1560
|
+
const numericFilters = buildNumericFilters({
|
|
1561
|
+
timeFilter: input.timeFilter,
|
|
1562
|
+
minPoints: input.minPoints,
|
|
1563
|
+
minComments: input.minComments
|
|
1564
|
+
});
|
|
1565
|
+
const response = await searchHackerNewsAPI({
|
|
1566
|
+
query: input.query,
|
|
1567
|
+
tags: "show_hn",
|
|
1568
|
+
numericFilters,
|
|
1569
|
+
sortBy: input.sortBy,
|
|
1570
|
+
page: input.page,
|
|
1571
|
+
hitsPerPage: input.hitsPerPage
|
|
1572
|
+
});
|
|
1573
|
+
fillContext(context, response);
|
|
1574
|
+
return formatStoryResults(response);
|
|
1575
|
+
}
|
|
1576
|
+
});
|
|
1577
|
+
var search_jobs = tool8({
|
|
1578
|
+
description: "Tool to search HackerNews job postings. Use when you need to find tech job opportunities posted on HN.",
|
|
1579
|
+
inputSchema: z8.object({
|
|
1580
|
+
query: z8.string().default("").describe(
|
|
1581
|
+
'Search query for job postings. Examples: "remote", "machine learning"'
|
|
1582
|
+
),
|
|
1583
|
+
timeFilter: z8.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
1584
|
+
sortBy: z8.enum(["relevance", "date"]).default("date").describe("Sort by relevance or date"),
|
|
1585
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1586
|
+
hitsPerPage: z8.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1587
|
+
}),
|
|
1588
|
+
execute: async (input, options) => {
|
|
1589
|
+
const context = toState(options);
|
|
1590
|
+
context.hackernews_sources ??= [];
|
|
1591
|
+
const numericFilters = buildNumericFilters({
|
|
1592
|
+
timeFilter: input.timeFilter
|
|
1593
|
+
});
|
|
1594
|
+
const response = await searchHackerNewsAPI({
|
|
1595
|
+
query: input.query,
|
|
1596
|
+
tags: "job",
|
|
1597
|
+
numericFilters,
|
|
1598
|
+
sortBy: input.sortBy,
|
|
1599
|
+
page: input.page,
|
|
1600
|
+
hitsPerPage: input.hitsPerPage
|
|
1601
|
+
});
|
|
1602
|
+
fillContext(context, response);
|
|
1603
|
+
return formatJobResults(response);
|
|
1604
|
+
}
|
|
1605
|
+
});
|
|
1606
|
+
var search_polls = tool8({
|
|
1607
|
+
description: "Tool to search HackerNews polls - community surveys and voting. Use when you need to find community polls on various topics.",
|
|
1608
|
+
inputSchema: z8.object({
|
|
1609
|
+
query: z8.string().default("").describe('Search query for polls. Example: "programming language"'),
|
|
1610
|
+
timeFilter: z8.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
1611
|
+
sortBy: z8.enum(["relevance", "date"]).default("date").describe("Sort by relevance or date"),
|
|
1612
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1613
|
+
hitsPerPage: z8.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1614
|
+
}),
|
|
1615
|
+
execute: async (input, options) => {
|
|
1616
|
+
const context = toState(options);
|
|
1617
|
+
context.hackernews_sources ??= [];
|
|
1618
|
+
const numericFilters = buildNumericFilters({
|
|
1619
|
+
timeFilter: input.timeFilter
|
|
1620
|
+
});
|
|
1621
|
+
const response = await searchHackerNewsAPI({
|
|
1622
|
+
query: input.query,
|
|
1623
|
+
tags: "poll",
|
|
1624
|
+
numericFilters,
|
|
1625
|
+
sortBy: input.sortBy,
|
|
1626
|
+
page: input.page,
|
|
1627
|
+
hitsPerPage: input.hitsPerPage
|
|
1628
|
+
});
|
|
1629
|
+
fillContext(context, response);
|
|
1630
|
+
return formatStoryResults(response);
|
|
1631
|
+
}
|
|
1632
|
+
});
|
|
1633
|
+
var get_user_profile = tool8({
|
|
1634
|
+
description: "Tool to get HackerNews user profile information. Use when you need to view a user's karma, account creation date, and bio.",
|
|
1635
|
+
inputSchema: z8.object({
|
|
1636
|
+
username: z8.string().describe('HackerNews username. Example: "pg"')
|
|
1637
|
+
}),
|
|
1638
|
+
execute: async (input) => {
|
|
1639
|
+
const user = await fetchHNUser(input.username);
|
|
1640
|
+
return formatUserProfile(user);
|
|
1641
|
+
}
|
|
1642
|
+
});
|
|
1643
|
+
var search_by_domain = tool8({
|
|
1644
|
+
description: "Tool to search HackerNews stories from a specific domain or website. Use when you need to find all HN posts from a particular domain or track discussions about content from specific websites.",
|
|
1645
|
+
inputSchema: z8.object({
|
|
1646
|
+
domain: z8.string().describe('Domain to search. Examples: "github.com", "arxiv.org"'),
|
|
1647
|
+
timeFilter: z8.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
1648
|
+
minPoints: z8.number().int().min(0).optional().describe("Minimum points threshold"),
|
|
1649
|
+
minComments: z8.number().int().min(0).optional().describe("Minimum comments threshold"),
|
|
1650
|
+
sortBy: z8.enum(["relevance", "date"]).default("date").describe("Sort by relevance or date"),
|
|
1651
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1652
|
+
hitsPerPage: z8.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1653
|
+
}),
|
|
1654
|
+
execute: async (input, options) => {
|
|
1655
|
+
const context = toState(options);
|
|
1656
|
+
context.hackernews_sources ??= [];
|
|
1657
|
+
const numericFilters = buildNumericFilters({
|
|
1658
|
+
timeFilter: input.timeFilter,
|
|
1659
|
+
minPoints: input.minPoints,
|
|
1660
|
+
minComments: input.minComments
|
|
1661
|
+
});
|
|
1662
|
+
const urlParams = new URLSearchParams();
|
|
1663
|
+
urlParams.set("query", input.domain);
|
|
1664
|
+
urlParams.set("restrictSearchableAttributes", "url");
|
|
1665
|
+
urlParams.set("tags", "story");
|
|
1666
|
+
if (numericFilters) {
|
|
1667
|
+
urlParams.set("numericFilters", numericFilters);
|
|
1668
|
+
}
|
|
1669
|
+
urlParams.set("page", input.page.toString());
|
|
1670
|
+
urlParams.set("hitsPerPage", input.hitsPerPage.toString());
|
|
1671
|
+
const endpoint = input.sortBy === "date" ? "http://hn.algolia.com/api/v1/search_by_date" : "http://hn.algolia.com/api/v1/search";
|
|
1672
|
+
const url = `${endpoint}?${urlParams.toString()}`;
|
|
1673
|
+
const response = await fetch(url, {
|
|
1674
|
+
headers: { "Content-Type": "application/json" }
|
|
1675
|
+
});
|
|
1676
|
+
if (!response.ok) {
|
|
1677
|
+
throw new Error(
|
|
1678
|
+
`HN API error: ${response.status} ${response.statusText}`
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
const data = await response.json();
|
|
1682
|
+
fillContext(context, data);
|
|
1683
|
+
return formatStoryResults(data);
|
|
1684
|
+
}
|
|
1685
|
+
});
|
|
1686
|
+
var search_highly_discussed = tool8({
|
|
1687
|
+
description: "Tool to search for highly discussed HackerNews stories with many comments. Use when you need to find engaging or controversial discussions with significant community participation.",
|
|
1688
|
+
inputSchema: z8.object({
|
|
1689
|
+
minComments: z8.number().int().min(1).describe(
|
|
1690
|
+
"Minimum number of comments (required). Example: 100 for highly discussed stories"
|
|
1691
|
+
),
|
|
1692
|
+
query: z8.string().default("").describe('Optional search query. Example: "AI"'),
|
|
1693
|
+
timeFilter: z8.enum(["d", "w", "m", "y", "all"]).default("all").describe("Time filter: d=day, w=week, m=month, y=year, all=no filter"),
|
|
1694
|
+
minPoints: z8.number().int().min(0).optional().describe("Minimum points threshold"),
|
|
1695
|
+
sortBy: z8.enum(["relevance", "date"]).default("date").describe("Sort by relevance or date"),
|
|
1696
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1697
|
+
hitsPerPage: z8.number().int().min(1).max(1e3).default(20).describe("Results per page (max 1000)")
|
|
1698
|
+
}),
|
|
1699
|
+
execute: async (input, options) => {
|
|
1700
|
+
const context = toState(options);
|
|
1701
|
+
context.hackernews_sources ??= [];
|
|
1702
|
+
const numericFilters = buildNumericFilters({
|
|
1703
|
+
timeFilter: input.timeFilter,
|
|
1704
|
+
minPoints: input.minPoints,
|
|
1705
|
+
minComments: input.minComments
|
|
1706
|
+
});
|
|
1707
|
+
const response = await searchHackerNewsAPI({
|
|
1708
|
+
query: input.query,
|
|
1709
|
+
tags: "story",
|
|
1710
|
+
numericFilters,
|
|
1711
|
+
sortBy: input.sortBy,
|
|
1712
|
+
page: input.page,
|
|
1713
|
+
hitsPerPage: input.hitsPerPage
|
|
1714
|
+
});
|
|
1715
|
+
fillContext(context, response);
|
|
1716
|
+
return formatStoryResults(response);
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
var search_trending = tool8({
|
|
1720
|
+
description: "Tool to find currently trending HackerNews stories - recent posts with high engagement. Use when you need to discover what's hot right now on HN by combining recency with high points and comments.",
|
|
1721
|
+
inputSchema: z8.object({
|
|
1722
|
+
minPoints: z8.number().int().min(10).default(50).describe(
|
|
1723
|
+
"Minimum points threshold. Example: 100 for highly upvoted stories"
|
|
1724
|
+
),
|
|
1725
|
+
maxAgeHours: z8.number().int().min(1).max(72).default(24).describe("Maximum age in hours. Example: 24 for stories from today"),
|
|
1726
|
+
minComments: z8.number().int().min(0).default(10).describe("Minimum comments threshold"),
|
|
1727
|
+
sortBy: z8.enum(["relevance", "date"]).default("date").describe("Sort by relevance or date"),
|
|
1728
|
+
page: z8.number().int().min(0).default(0).describe("Page number (0-indexed)"),
|
|
1729
|
+
hitsPerPage: z8.number().int().min(1).max(100).default(30).describe("Results per page (max 100)")
|
|
1730
|
+
}),
|
|
1731
|
+
execute: async (input, options) => {
|
|
1732
|
+
const context = toState(options);
|
|
1733
|
+
context.hackernews_sources ??= [];
|
|
1734
|
+
const numericFilters = buildNumericFilters({
|
|
1735
|
+
maxAgeHours: input.maxAgeHours,
|
|
1736
|
+
minPoints: input.minPoints,
|
|
1737
|
+
minComments: input.minComments
|
|
1738
|
+
});
|
|
1739
|
+
const response = await searchHackerNewsAPI({
|
|
1740
|
+
tags: "story",
|
|
1741
|
+
numericFilters,
|
|
1742
|
+
sortBy: input.sortBy,
|
|
1743
|
+
page: input.page,
|
|
1744
|
+
hitsPerPage: input.hitsPerPage
|
|
1745
|
+
});
|
|
1746
|
+
fillContext(context, response);
|
|
1747
|
+
return formatStoryResults(response);
|
|
1748
|
+
}
|
|
1749
|
+
});
|
|
1750
|
+
function fillContext(context, result) {
|
|
1751
|
+
result.hits.forEach((hit) => {
|
|
1752
|
+
context.hackernews_sources.push({
|
|
1753
|
+
title: hit.title,
|
|
1754
|
+
hn_url: hit.objectID ? `https://news.ycombinator.com/item?id=${hit.objectID}` : void 0,
|
|
1755
|
+
story_url: hit.url,
|
|
1756
|
+
story_text: hit.story_text,
|
|
1757
|
+
comment_text: hit.comment_text
|
|
1758
|
+
});
|
|
1759
|
+
});
|
|
1760
|
+
}
|
|
1761
|
+
var hackernewsTools = {
|
|
1762
|
+
search_by_query,
|
|
1763
|
+
search_by_author,
|
|
1764
|
+
get_story_item,
|
|
1765
|
+
get_story_comment,
|
|
1766
|
+
get_front_page_stories,
|
|
1767
|
+
get_story_comments,
|
|
1768
|
+
search_ask_hn,
|
|
1769
|
+
search_show_hn,
|
|
1770
|
+
search_jobs,
|
|
1771
|
+
search_polls,
|
|
1772
|
+
get_user_profile,
|
|
1773
|
+
search_by_domain,
|
|
1774
|
+
search_highly_discussed,
|
|
1775
|
+
search_trending
|
|
1776
|
+
};
|
|
1042
1777
|
export {
|
|
1043
1778
|
GetWeatherSchema,
|
|
1044
1779
|
ddgSearchSchema,
|
|
@@ -1046,8 +1781,23 @@ export {
|
|
|
1046
1781
|
duckStocks,
|
|
1047
1782
|
execute_os_command,
|
|
1048
1783
|
getWeatherTool,
|
|
1784
|
+
get_front_page_stories,
|
|
1785
|
+
get_story_comment,
|
|
1786
|
+
get_story_comments,
|
|
1787
|
+
get_story_item,
|
|
1788
|
+
get_user_profile,
|
|
1789
|
+
hackernewsTools,
|
|
1049
1790
|
scratchpad_tool,
|
|
1050
1791
|
searchAgent,
|
|
1792
|
+
search_ask_hn,
|
|
1793
|
+
search_by_author,
|
|
1794
|
+
search_by_domain,
|
|
1795
|
+
search_by_query,
|
|
1796
|
+
search_highly_discussed,
|
|
1797
|
+
search_jobs,
|
|
1798
|
+
search_polls,
|
|
1799
|
+
search_show_hn,
|
|
1800
|
+
search_trending,
|
|
1051
1801
|
serp,
|
|
1052
1802
|
user_story_formatter_tool,
|
|
1053
1803
|
web_search_tool
|