Skip to content

Commit 3dbae74

Browse files
committed
Added news api
1 parent 54292c0 commit 3dbae74

File tree

2 files changed

+74
-15
lines changed

2 files changed

+74
-15
lines changed

cmd/api/newsapi.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func newsapiRegister(flags *Flags) {
3535
flags.Register(Cmd{
3636
Name: newsapiName,
3737
Description: "Obtain news headlines from https://newsapi.org/",
38-
Parse: inewsapiParse,
38+
Parse: newsapiParse,
3939
Fn: []Fn{
4040
{Name: "sources", Call: newsapiSources, Description: "Return sources of news"},
4141
{Name: "headlines", Call: newsapiHeadlines, Description: "Return top headlines from news sources"},
@@ -44,7 +44,7 @@ func newsapiRegister(flags *Flags) {
4444
})
4545
}
4646

47-
func inewsapiParse(flags *Flags, opts ...client.ClientOpt) error {
47+
func newsapiParse(flags *Flags, opts ...client.ClientOpt) error {
4848
apiKey := flags.GetString("newsapi-key")
4949
if apiKey == "" {
5050
return fmt.Errorf("missing -newsapi-key flag")

cmd/api/samantha.go

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@ import (
1212
"github.com/djthorpe/go-tablewriter"
1313
"github.com/mutablelogic/go-client"
1414
"github.com/mutablelogic/go-client/pkg/anthropic"
15+
"github.com/mutablelogic/go-client/pkg/newsapi"
1516
"github.com/mutablelogic/go-client/pkg/openai/schema"
1617
)
1718

1819
///////////////////////////////////////////////////////////////////////////////
1920
// GLOBALS
2021

2122
var (
22-
samName = "sam"
23-
samWeatherTool = schema.NewTool("get_weather", "Get the weather for a location")
24-
samSystemPrompt = "Your name is Samantha, you are a friendly AI assistant, here to help you with anything you need. Your responses should be short and to the point, and you should always be polite."
23+
samName = "sam"
24+
samWeatherTool = schema.NewTool("get_weather", "Get the weather for a location")
25+
samNewsHeadlinesTool = schema.NewTool("get_news_headlines", "Get the news headlines")
26+
samNewsSearchTool = schema.NewTool("search_news", "Search news articles")
27+
samSystemPrompt = `Your name is Samantha, you are a friendly AI assistant, here to help you with
28+
anything you need. Your responses should be short and to the point, and you should always be polite.`
2529
)
2630

2731
///////////////////////////////////////////////////////////////////////////////
@@ -30,7 +34,7 @@ var (
3034
func samRegister(flags *Flags) {
3135
flags.Register(Cmd{
3236
Name: samName,
33-
Description: "Interact with Samantha, a friendly AI assistant",
37+
Description: "Interact with Samantha, a friendly AI assistant, to query news and weather",
3438
Parse: samParse,
3539
Fn: []Fn{
3640
{Name: "chat", Call: samChat, Description: "Chat with Sam"},
@@ -43,6 +47,10 @@ func samParse(flags *Flags, opts ...client.ClientOpt) error {
4347
if err := weatherapiParse(flags, opts...); err != nil {
4448
return err
4549
}
50+
// Initialize news
51+
if err := newsapiParse(flags, opts...); err != nil {
52+
return err
53+
}
4654

4755
// Initialize anthropic
4856
opts = append(opts, client.OptHeader("Anthropic-Beta", "tools-2024-04-04"))
@@ -54,6 +62,12 @@ func samParse(flags *Flags, opts ...client.ClientOpt) error {
5462
if err := samWeatherTool.AddParameter("location", "The city to get the weather for", true); err != nil {
5563
return err
5664
}
65+
if err := samNewsHeadlinesTool.AddParameter("category", "The cateogry of news, which should be one of business, entertainment, general, health, science, sports or technology", true); err != nil {
66+
return err
67+
}
68+
if err := samNewsSearchTool.AddParameter("query", "The query with which to search news", true); err != nil {
69+
return err
70+
}
5771

5872
// Return success
5973
return nil
@@ -82,8 +96,21 @@ func samChat(ctx context.Context, w *tablewriter.Writer, _ []string) error {
8296
messages = append(messages, schema.NewMessage("user", schema.Text(strings.TrimSpace(text))))
8397
}
8498

99+
// Curtail requests to the last N history
100+
if len(messages) > 10 {
101+
messages = messages[len(messages)-10:]
102+
// First message must have role 'user'
103+
for {
104+
if len(messages) == 0 || messages[0].Role == "user" {
105+
break
106+
}
107+
messages = messages[1:]
108+
}
109+
// TODO: We must remove the first instance tool_result if there is no tool_use
110+
}
111+
85112
// Request -> Response
86-
responses, err := anthropicClient.Messages(ctx, messages, anthropic.OptSystem(samSystemPrompt), anthropic.OptTool(samWeatherTool))
113+
responses, err := anthropicClient.Messages(ctx, messages, anthropic.OptSystem(samSystemPrompt), anthropic.OptTool(samWeatherTool), anthropic.OptTool(samNewsHeadlinesTool), anthropic.OptTool(samNewsSearchTool))
87114
if err != nil {
88115
return err
89116
}
@@ -111,14 +138,46 @@ func samCall(_ context.Context, content schema.Content) *schema.Content {
111138
}
112139
switch content.Name {
113140
case samWeatherTool.Name:
114-
if location, exists := content.GetString(content.Name, "location"); exists {
115-
if weather, err := weatherapiClient.Current(location); err != nil {
116-
return schema.ToolResult(content.Id, fmt.Sprint("Unable to get the current weather, the error is ", err))
117-
} else if data, err := json.MarshalIndent(weather, "", " "); err != nil {
118-
return schema.ToolResult(content.Id, fmt.Sprint("Unable to marshal the weather data, the error is ", err))
119-
} else {
120-
return schema.ToolResult(content.Id, string(data))
121-
}
141+
var location string
142+
if v, exists := content.GetString(content.Name, "location"); exists {
143+
location = v
144+
} else {
145+
location = "auto:ip"
146+
}
147+
if weather, err := weatherapiClient.Current(location); err != nil {
148+
return schema.ToolResult(content.Id, fmt.Sprint("Unable to get the current weather, the error is ", err))
149+
} else if data, err := json.MarshalIndent(weather, "", " "); err != nil {
150+
return schema.ToolResult(content.Id, fmt.Sprint("Unable to marshal the weather data, the error is ", err))
151+
} else {
152+
return schema.ToolResult(content.Id, string(data))
153+
}
154+
case samNewsHeadlinesTool.Name:
155+
var category string
156+
if v, exists := content.GetString(content.Name, "category"); exists {
157+
category = v
158+
} else {
159+
category = "general"
160+
}
161+
if headlines, err := newsapiClient.Headlines(newsapi.OptCategory(category)); err != nil {
162+
return schema.ToolResult(content.Id, fmt.Sprint("Unable to get the news headlines, the error is ", err))
163+
} else if data, err := json.MarshalIndent(headlines, "", " "); err != nil {
164+
return schema.ToolResult(content.Id, fmt.Sprint("Unable to marshal the headlines data, the error is ", err))
165+
} else {
166+
return schema.ToolResult(content.Id, string(data))
167+
}
168+
case samNewsSearchTool.Name:
169+
var query string
170+
if v, exists := content.GetString(content.Name, "query"); exists {
171+
query = v
172+
} else {
173+
return schema.ToolResult(content.Id, "Unable to search news due to missing query")
174+
}
175+
if articles, err := newsapiClient.Articles(newsapi.OptQuery(query), newsapi.OptLimit(5)); err != nil {
176+
return schema.ToolResult(content.Id, fmt.Sprint("Unable to search news, the error is ", err))
177+
} else if data, err := json.MarshalIndent(articles, "", " "); err != nil {
178+
return schema.ToolResult(content.Id, fmt.Sprint("Unable to marshal the articles data, the error is ", err))
179+
} else {
180+
return schema.ToolResult(content.Id, string(data))
122181
}
123182
}
124183
return schema.ToolResult(content.Id, fmt.Sprint("unable to call:", content.Name))

0 commit comments

Comments
 (0)