1
+ import { elizaLogger } from "@elizaos/core" ;
2
+ import {
3
+ Action ,
4
+ HandlerCallback ,
5
+ IAgentRuntime ,
6
+ Memory ,
7
+ State ,
8
+ } from "@elizaos/core" ;
9
+ import { generateWebSearch } from "@elizaos/core" ;
10
+ import { SearchResult } from "@elizaos/core" ;
11
+ import { encodingForModel , TiktokenModel } from "js-tiktoken" ;
12
+
13
+ const DEFAULT_MAX_WEB_SEARCH_TOKENS = 4000 ;
14
+ const DEFAULT_MODEL_ENCODING = "gpt-3.5-turbo" ;
15
+
16
+ function getTotalTokensFromString (
17
+ str : string ,
18
+ encodingName : TiktokenModel = DEFAULT_MODEL_ENCODING
19
+ ) {
20
+ const encoding = encodingForModel ( encodingName ) ;
21
+ return encoding . encode ( str ) . length ;
22
+ }
23
+
24
+ function MaxTokens (
25
+ data : string ,
26
+ maxTokens : number = DEFAULT_MAX_WEB_SEARCH_TOKENS
27
+ ) : string {
28
+ if ( getTotalTokensFromString ( data ) >= maxTokens ) {
29
+ return data . slice ( 0 , maxTokens ) ;
30
+ }
31
+ return data ;
32
+ }
33
+
34
+ export const webSearch : Action = {
35
+ name : "WEB_SEARCH" ,
36
+ similes : [
37
+ "SEARCH_WEB" ,
38
+ "INTERNET_SEARCH" ,
39
+ "LOOKUP" ,
40
+ "QUERY_WEB" ,
41
+ "FIND_ONLINE" ,
42
+ "SEARCH_ENGINE" ,
43
+ "WEB_LOOKUP" ,
44
+ "ONLINE_SEARCH" ,
45
+ "FIND_INFORMATION" ,
46
+ ] ,
47
+ suppressInitialMessage : true ,
48
+ description :
49
+ "Perform a web search to find information related to the message." ,
50
+ validate : async ( runtime : IAgentRuntime , message : Memory ) => {
51
+ const tavilyApiKeyOk = ! ! runtime . getSetting ( "TAVILY_API_KEY" ) ;
52
+
53
+ return tavilyApiKeyOk ;
54
+ } ,
55
+ handler : async (
56
+ runtime : IAgentRuntime ,
57
+ message : Memory ,
58
+ state : State ,
59
+ options : any ,
60
+ callback : HandlerCallback
61
+ ) => {
62
+ elizaLogger . log ( "Composing state for message:" , message ) ;
63
+ state = ( await runtime . composeState ( message ) ) as State ;
64
+ const userId = runtime . agentId ;
65
+ elizaLogger . log ( "User ID:" , userId ) ;
66
+
67
+ const webSearchPrompt = message . content . text ;
68
+ elizaLogger . log ( "web search prompt received:" , webSearchPrompt ) ;
69
+
70
+ elizaLogger . log ( "Generating image with prompt:" , webSearchPrompt ) ;
71
+ const searchResponse = await generateWebSearch (
72
+ webSearchPrompt ,
73
+ runtime
74
+ ) ;
75
+
76
+ if ( searchResponse && searchResponse . results . length ) {
77
+ const responseList = searchResponse . answer
78
+ ? `${ searchResponse . answer } ${
79
+ Array . isArray ( searchResponse . results ) &&
80
+ searchResponse . results . length > 0
81
+ ? `\n\nFor more details, you can check out these resources:\n${ searchResponse . results
82
+ . map (
83
+ ( result : SearchResult , index : number ) =>
84
+ `${ index + 1 } . [${ result . title } ](${ result . url } )`
85
+ )
86
+ . join ( "\n" ) } `
87
+ : ""
88
+ } `
89
+ : "" ;
90
+
91
+ callback ( {
92
+ text : MaxTokens ( responseList , DEFAULT_MAX_WEB_SEARCH_TOKENS ) ,
93
+ } ) ;
94
+ } else {
95
+ elizaLogger . error ( "search failed or returned no data." ) ;
96
+ }
97
+ } ,
98
+ examples : [
99
+ [
100
+ {
101
+ user : "{{user1}}" ,
102
+ content : {
103
+ text : "Find the latest news about SpaceX launches." ,
104
+ } ,
105
+ } ,
106
+ {
107
+ user : "{{agentName}}" ,
108
+ content : {
109
+ text : "Here is the latest news about SpaceX launches:" ,
110
+ action : "WEB_SEARCH" ,
111
+ } ,
112
+ } ,
113
+ ] ,
114
+ [
115
+ {
116
+ user : "{{user1}}" ,
117
+ content : {
118
+ text : "Can you find details about the iPhone 16 release?" ,
119
+ } ,
120
+ } ,
121
+ {
122
+ user : "{{agentName}}" ,
123
+ content : {
124
+ text : "Here are the details I found about the iPhone 16 release:" ,
125
+ action : "WEB_SEARCH" ,
126
+ } ,
127
+ } ,
128
+ ] ,
129
+ [
130
+ {
131
+ user : "{{user1}}" ,
132
+ content : {
133
+ text : "What is the schedule for the next FIFA World Cup?" ,
134
+ } ,
135
+ } ,
136
+ {
137
+ user : "{{agentName}}" ,
138
+ content : {
139
+ text : "Here is the schedule for the next FIFA World Cup:" ,
140
+ action : "WEB_SEARCH" ,
141
+ } ,
142
+ } ,
143
+ ] ,
144
+ [
145
+ {
146
+ user : "{{user1}}" ,
147
+ content : { text : "Check the latest stock price of Tesla." } ,
148
+ } ,
149
+ {
150
+ user : "{{agentName}}" ,
151
+ content : {
152
+ text : "Here is the latest stock price of Tesla I found:" ,
153
+ action : "WEB_SEARCH" ,
154
+ } ,
155
+ } ,
156
+ ] ,
157
+ [
158
+ {
159
+ user : "{{user1}}" ,
160
+ content : {
161
+ text : "What are the current trending movies in the US?" ,
162
+ } ,
163
+ } ,
164
+ {
165
+ user : "{{agentName}}" ,
166
+ content : {
167
+ text : "Here are the current trending movies in the US:" ,
168
+ action : "WEB_SEARCH" ,
169
+ } ,
170
+ } ,
171
+ ] ,
172
+ [
173
+ {
174
+ user : "{{user1}}" ,
175
+ content : {
176
+ text : "What is the latest score in the NBA finals?" ,
177
+ } ,
178
+ } ,
179
+ {
180
+ user : "{{agentName}}" ,
181
+ content : {
182
+ text : "Here is the latest score from the NBA finals:" ,
183
+ action : "WEB_SEARCH" ,
184
+ } ,
185
+ } ,
186
+ ] ,
187
+ [
188
+ {
189
+ user : "{{user1}}" ,
190
+ content : { text : "When is the next Apple keynote event?" } ,
191
+ } ,
192
+ {
193
+ user : "{{agentName}}" ,
194
+ content : {
195
+ text : "Here is the information about the next Apple keynote event:" ,
196
+ action : "WEB_SEARCH" ,
197
+ } ,
198
+ } ,
199
+ ] ,
200
+ ] ,
201
+ } as Action ;
0 commit comments