hackernews.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import { tool } from "ai";
  2. import { z } from "zod";
  3. /**
  4. * Get top stories from Hacker News.
  5. * Uses the official HN Firebase API. Free, no auth required.
  6. * https://github.com/HackerNewsAPI/API
  7. */
  8. export const getHackerNewsTop = tool({
  9. description:
  10. "Get the current top stories from Hacker News, including title, score, author, URL, and comment count.",
  11. inputSchema: z.object({
  12. count: z
  13. .number()
  14. .min(1)
  15. .max(30)
  16. .describe("Number of top stories to fetch (1-30)"),
  17. }),
  18. execute: async ({ count }) => {
  19. const topUrl =
  20. "https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty";
  21. const topRes = await fetch(topUrl);
  22. if (!topRes.ok) {
  23. return { error: "Failed to fetch Hacker News top stories" };
  24. }
  25. const topIds = (await topRes.json()) as number[];
  26. const storyIds = topIds.slice(0, count);
  27. const stories = await Promise.all(
  28. storyIds.map(async (id) => {
  29. const storyRes = await fetch(
  30. `https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`,
  31. );
  32. if (!storyRes.ok) return null;
  33. const story = (await storyRes.json()) as {
  34. id: number;
  35. title: string;
  36. url?: string;
  37. score: number;
  38. by: string;
  39. time: number;
  40. descendants?: number;
  41. type: string;
  42. };
  43. return {
  44. id: story.id,
  45. title: story.title,
  46. url: story.url ?? `https://news.ycombinator.com/item?id=${story.id}`,
  47. score: story.score,
  48. author: story.by,
  49. comments: story.descendants ?? 0,
  50. postedAt: new Date(story.time * 1000).toISOString(),
  51. hnUrl: `https://news.ycombinator.com/item?id=${story.id}`,
  52. };
  53. }),
  54. );
  55. return {
  56. stories: stories.filter(Boolean),
  57. fetchedAt: new Date().toISOString(),
  58. };
  59. },
  60. });