Skip to content

Commit 15e33ba

Browse files
committed
news-plugin
1 parent 81d0273 commit 15e33ba

File tree

11 files changed

+251
-0
lines changed

11 files changed

+251
-0
lines changed

.env.example

+3
Original file line numberDiff line numberDiff line change
@@ -325,3 +325,6 @@ STORY_PRIVATE_KEY= # Story private key
325325
STORY_API_BASE_URL= # Story API base URL
326326
STORY_API_KEY= # Story API key
327327
PINATA_JWT= # Pinata JWT for uploading files to IPFS
328+
329+
# News API Key
330+
NEWS_API_KEY=

agent/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"@ai16z/plugin-multiversx": "workspace:*",
5151
"@ai16z/plugin-near": "workspace:*",
5252
"@ai16z/plugin-zksync-era": "workspace:*",
53+
"@ai16z/plugin-news": "workspace:*",
5354
"readline": "1.3.0",
5455
"ws": "8.18.0",
5556
"yargs": "17.7.2"

agent/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
stringToUuid,
2626
validateCharacterConfig,
2727
} from "@ai16z/eliza";
28+
import { newsPlugin } from "@ai16z/plugin-news";
2829
import { zgPlugin } from "@ai16z/plugin-0g";
2930
import { bootstrapPlugin } from "@ai16z/plugin-bootstrap";
3031
import createGoatPlugin from "@ai16z/plugin-goat";
@@ -482,6 +483,7 @@ export async function createAgent(
482483
// character.plugins are handled when clients are added
483484
plugins: [
484485
bootstrapPlugin,
486+
newsPlugin,
485487
getSecret(character, "CONFLUX_CORE_PRIVATE_KEY")
486488
? confluxPlugin
487489
: null,

packages/plugin-news/.npmignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*
2+
3+
!dist/**
4+
!package.json
5+
!readme.md
6+
!tsup.config.ts
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import eslintGlobalConfig from "../../eslint.config.mjs";
2+
3+
export default [...eslintGlobalConfig];

packages/plugin-news/package.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "@ai16z/plugin-news",
3+
"version": "0.1.5-alpha.5",
4+
"main": "dist/index.js",
5+
"type": "module",
6+
"types": "dist/index.d.ts",
7+
"dependencies": {
8+
"@ai16z/eliza": "workspace:*",
9+
"tsup": "8.3.5"
10+
},
11+
"scripts": {
12+
"build": "tsup --format esm --dts",
13+
"dev": "tsup --format esm --dts --watch",
14+
"lint": "eslint . --fix"
15+
},
16+
"peerDependencies": {
17+
"whatwg-url": "7.1.0"
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./news.ts";
2+
+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import {
2+
ActionExample,
3+
Content,
4+
generateText,
5+
HandlerCallback,
6+
IAgentRuntime,
7+
Memory,
8+
ModelClass,
9+
State,
10+
type Action,
11+
} from "@ai16z/eliza";
12+
13+
14+
export const currentNewsAction: Action = {
15+
name: "CURRENT_NEWS",
16+
similes: ["NEWS", "GET_NEWS", "GET_CURRENT_NEWS"],
17+
validate: async (_runtime: IAgentRuntime, _message: Memory) => {
18+
return true;
19+
},
20+
description:
21+
"Get the latest news about a specific topic if asked by the user.",
22+
handler: async (
23+
_runtime: IAgentRuntime,
24+
_message: Memory,
25+
_state: State,
26+
_options: { [key: string]: unknown; },
27+
_callback: HandlerCallback,
28+
): Promise<boolean> => {
29+
async function getCurrentNews(searchTerm: string) {
30+
try {
31+
const apiKey = process.env.NEWS_API_KEY;
32+
if (!apiKey) {
33+
throw new Error('NEWS_API_KEY environment variable is not set');
34+
}
35+
36+
const response = await fetch(`https://newsapi.org/v2/everything?q=${searchTerm}&sortBy=publishedAt&apiKey=${apiKey}`);
37+
const data = await response.json();
38+
39+
if (!data.articles || !Array.isArray(data.articles)) {
40+
return "No news articles found.";
41+
}
42+
43+
return data.articles.slice(0, 5).map(article => {
44+
const content = article.content || article.description || "No content available";
45+
return `${article.title || "No title"}\n${article.description || "No description"}\n${article.url || ""}\n${content.slice(0, 1000)}`;
46+
}).join("\n\n");
47+
} catch (error) {
48+
console.error("Error fetching news:", error);
49+
return "Sorry, there was an error fetching the news.";
50+
}
51+
}
52+
53+
const context = `Extract the search term from the {{userName}} message. The message is: ${_message.content.text}. Only return the search term, no other text.`
54+
55+
const searchTerm = await generateText({
56+
runtime: _runtime,
57+
context,
58+
modelClass: ModelClass.SMALL,
59+
stop: ["\n"],
60+
});
61+
62+
const currentNews = await getCurrentNews(searchTerm);
63+
const responseText = ` *protocol droid noises*\n\n${currentNews}`;
64+
65+
66+
const newMemory: Memory = {
67+
userId: _message.agentId,
68+
agentId: _message.agentId,
69+
roomId: _message.roomId,
70+
content: {
71+
text: responseText,
72+
action: "CURRENT_NEWS_RESPONSE",
73+
source: _message.content?.source,
74+
} as Content,
75+
};
76+
77+
await _runtime.messageManager.createMemory(newMemory);
78+
79+
_callback(newMemory.content);
80+
return true;
81+
82+
},
83+
examples: [
84+
[
85+
{
86+
user: "{{user1}}",
87+
content: { text: "what's the latest news about <searchTerm>?" },
88+
},
89+
{
90+
user: "{{user2}}",
91+
content: { text: "", action: "CURRENT NEWS" },
92+
},
93+
],
94+
95+
[
96+
{
97+
user: "{{user1}}",
98+
content: { text: "can you show me the latest news about <searchTerm>?" },
99+
},
100+
{
101+
user: "{{user2}}",
102+
content: { text: "", action: "CURRENT NEWS" },
103+
},
104+
],
105+
106+
[
107+
{
108+
user: "{{user1}}",
109+
content: { text: "what's in the <searchTerm> news today?" },
110+
},
111+
{
112+
user: "{{user2}}",
113+
content: { text: "", action: "CURRENT NEWS" },
114+
},
115+
],
116+
117+
[
118+
{
119+
user: "{{user1}}",
120+
content: { text: "show me current events about <searchTerm>?" },
121+
},
122+
{
123+
user: "{{user2}}",
124+
content: { text: "", action: "CURRENT NEWS" },
125+
},
126+
],
127+
128+
[
129+
{
130+
user: "{{user1}}",
131+
content: { text: "what's going on in the world of <searchTerm>?" },
132+
},
133+
{
134+
user: "{{user2}}",
135+
content: { text: "", action: "CURRENT NEWS" },
136+
},
137+
],
138+
139+
[
140+
{
141+
user: "{{user1}}",
142+
content: { text: "give me the latest headlines about <searchTerm>?" },
143+
},
144+
{
145+
user: "{{user2}}",
146+
content: { text: "", action: "CURRENT NEWS" },
147+
},
148+
],
149+
150+
[
151+
{
152+
user: "{{user1}}",
153+
content: { text: "show me news updates about <searchTerm>?" },
154+
},
155+
{
156+
user: "{{user2}}",
157+
content: { text: "", action: "CURRENT NEWS" },
158+
},
159+
],
160+
161+
[
162+
{
163+
user: "{{user1}}",
164+
content: { text: "what are today's top stories about <searchTerm>?" },
165+
},
166+
{
167+
user: "{{user2}}",
168+
content: { text: "", action: "CURRENT NEWS" },
169+
},
170+
],
171+
] as ActionExample[][],
172+
} as Action;

packages/plugin-news/src/index.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Plugin } from "@ai16z/eliza";
2+
import { currentNewsAction } from "./actions/news.ts";
3+
4+
export * as actions from "./actions";
5+
6+
export const newsPlugin: Plugin = {
7+
name: "news",
8+
description: "Get the latest news about a specific topic if asked by the user.",
9+
actions: [currentNewsAction],
10+
};

packages/plugin-news/tsconfig.json

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"extends": "../core/tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "dist",
5+
"rootDir": "src",
6+
"types": [
7+
"node"
8+
]
9+
},
10+
"include": [
11+
"src/**/*.ts"
12+
]
13+
}

packages/plugin-news/tsup.config.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { defineConfig } from "tsup";
2+
3+
export default defineConfig({
4+
entry: ["src/index.ts"],
5+
outDir: "dist",
6+
sourcemap: true,
7+
clean: true,
8+
format: ["esm"], // Ensure you're targeting CommonJS
9+
external: [
10+
"dotenv", // Externalize dotenv to prevent bundling
11+
"fs", // Externalize fs to use Node.js built-in module
12+
"path", // Externalize other built-ins if necessary
13+
"@reflink/reflink",
14+
"@node-llama-cpp",
15+
"https",
16+
"http",
17+
"agentkeepalive",
18+
// Add other modules you want to externalize
19+
],
20+
});

0 commit comments

Comments
 (0)