mirror of
https://github.com/vercel-labs/json-render.git
synced 2026-09-14 13:41:32 +08:00
ddae61805e
* ai sdk * chat * move more to lib * fixes * refactor * fixes * streamdown * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * data-spec * fixes * sortable * github * tools * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * tables * fixes * fixes * rename to chat * fixes docs * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fix lint * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes
68 lines
1.9 KiB
TypeScript
68 lines
1.9 KiB
TypeScript
import { tool } from "ai";
|
|
import { z } from "zod";
|
|
|
|
/**
|
|
* Get top stories from Hacker News.
|
|
* Uses the official HN Firebase API. Free, no auth required.
|
|
* https://github.com/HackerNewsAPI/API
|
|
*/
|
|
export const getHackerNewsTop = tool({
|
|
description:
|
|
"Get the current top stories from Hacker News, including title, score, author, URL, and comment count.",
|
|
inputSchema: z.object({
|
|
count: z
|
|
.number()
|
|
.min(1)
|
|
.max(30)
|
|
.describe("Number of top stories to fetch (1-30)"),
|
|
}),
|
|
execute: async ({ count }) => {
|
|
const topUrl =
|
|
"https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty";
|
|
const topRes = await fetch(topUrl);
|
|
|
|
if (!topRes.ok) {
|
|
return { error: "Failed to fetch Hacker News top stories" };
|
|
}
|
|
|
|
const topIds = (await topRes.json()) as number[];
|
|
const storyIds = topIds.slice(0, count);
|
|
|
|
const stories = await Promise.all(
|
|
storyIds.map(async (id) => {
|
|
const storyRes = await fetch(
|
|
`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`,
|
|
);
|
|
if (!storyRes.ok) return null;
|
|
|
|
const story = (await storyRes.json()) as {
|
|
id: number;
|
|
title: string;
|
|
url?: string;
|
|
score: number;
|
|
by: string;
|
|
time: number;
|
|
descendants?: number;
|
|
type: string;
|
|
};
|
|
|
|
return {
|
|
id: story.id,
|
|
title: story.title,
|
|
url: story.url ?? `https://news.ycombinator.com/item?id=${story.id}`,
|
|
score: story.score,
|
|
author: story.by,
|
|
comments: story.descendants ?? 0,
|
|
postedAt: new Date(story.time * 1000).toISOString(),
|
|
hnUrl: `https://news.ycombinator.com/item?id=${story.id}`,
|
|
};
|
|
}),
|
|
);
|
|
|
|
return {
|
|
stories: stories.filter(Boolean),
|
|
fetchedAt: new Date().toISOString(),
|
|
};
|
|
},
|
|
});
|