Skip to content

Commit 735f968

Browse files
committed
build agent
1 parent eb0a973 commit 735f968

File tree

8 files changed

+378
-15
lines changed

8 files changed

+378
-15
lines changed

sample-app/main.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,19 @@ func main() {
2222
runToolCallingExample()
2323
return
2424
}
25-
25+
26+
if len(os.Args) > 1 && os.Args[1] == "recipe-agent" {
27+
runRecipeAgent()
28+
return
29+
}
30+
31+
if len(os.Args) > 1 && os.Args[1] == "joke-workflow" {
32+
runJokeWorkflow()
33+
return
34+
}
35+
2636
// Default to workflow example using prompt registry
27-
// workflowExample()
28-
runJokeWorkflow()
37+
workflowExample()
2938
}
3039

3140
func workflowExample() {
@@ -70,7 +79,7 @@ func workflowExample() {
7079
Model: request.Model,
7180
Messages: promptMsgs,
7281
},
73-
sdk.WorkflowAttributes{
82+
&sdk.WorkflowAttributes{
7483
Name: "example-workflow",
7584
AssociationProperties: map[string]string{
7685
"user_id": "demo-user",

sample-app/recipe_agent_example.go

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/sashabaranov/go-openai"
9+
sdk "github.com/traceloop/go-openllmetry/traceloop-sdk"
10+
)
11+
12+
// ingredientValidatorTool validates that requested ingredients are available/safe
13+
func ingredientValidatorTool(ctx context.Context, agent *sdk.Agent, client *openai.Client, ingredients string) (string, error) {
14+
tool := agent.NewTool("ingredient_validator", "function", sdk.ToolFunction{
15+
Name: "ingredient_validator",
16+
Description: "Validates that requested ingredients are available and safe to use",
17+
Parameters: map[string]interface{}{
18+
"type": "object",
19+
"properties": map[string]interface{}{
20+
"ingredients": map[string]string{
21+
"type": "string",
22+
"description": "Comma-separated list of ingredients to validate",
23+
},
24+
},
25+
},
26+
})
27+
defer tool.End()
28+
29+
prompt := sdk.Prompt{
30+
Vendor: "openai",
31+
Mode: "chat",
32+
Model: "gpt-3.5-turbo",
33+
Messages: []sdk.Message{
34+
{
35+
Index: 0,
36+
Role: "user",
37+
Content: fmt.Sprintf("Validate these ingredients are commonly available and safe: %s. Respond with 'Valid' or list any concerns.", ingredients),
38+
},
39+
},
40+
}
41+
42+
llmSpan := tool.LogPrompt(prompt)
43+
44+
// Make API call
45+
resp, err := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
46+
Model: "gpt-3.5-turbo",
47+
Messages: []openai.ChatCompletionMessage{
48+
{
49+
Role: "user",
50+
Content: prompt.Messages[0].Content,
51+
},
52+
},
53+
})
54+
if err != nil {
55+
return "", fmt.Errorf("CreateChatCompletion error: %w", err)
56+
}
57+
58+
// Log completion
59+
var completionMsgs []sdk.Message
60+
for _, choice := range resp.Choices {
61+
completionMsgs = append(completionMsgs, sdk.Message{
62+
Index: choice.Index,
63+
Content: choice.Message.Content,
64+
Role: choice.Message.Role,
65+
})
66+
}
67+
68+
llmSpan.LogCompletion(ctx, sdk.Completion{
69+
Model: resp.Model,
70+
Messages: completionMsgs,
71+
}, sdk.Usage{
72+
TotalTokens: resp.Usage.TotalTokens,
73+
CompletionTokens: resp.Usage.CompletionTokens,
74+
PromptTokens: resp.Usage.PromptTokens,
75+
})
76+
77+
return resp.Choices[0].Message.Content, nil
78+
}
79+
80+
// nutritionCalculatorTool calculates nutritional information for the recipe
81+
func nutritionCalculatorTool(ctx context.Context, agent *sdk.Agent, client *openai.Client, recipe string) (string, error) {
82+
tool := agent.NewTool("nutrition_calculator", "function", sdk.ToolFunction{
83+
Name: "nutrition_calculator",
84+
Description: "Calculates estimated nutritional information for a recipe",
85+
Parameters: map[string]interface{}{
86+
"type": "object",
87+
"properties": map[string]interface{}{
88+
"recipe": map[string]string{
89+
"type": "string",
90+
"description": "The recipe description",
91+
},
92+
},
93+
},
94+
})
95+
defer tool.End()
96+
97+
prompt := sdk.Prompt{
98+
Vendor: "openai",
99+
Mode: "chat",
100+
Model: "gpt-3.5-turbo",
101+
Messages: []sdk.Message{
102+
{
103+
Index: 0,
104+
Role: "user",
105+
Content: fmt.Sprintf("Estimate the nutritional information (calories, protein, carbs, fat) per serving for this recipe: %s", recipe),
106+
},
107+
},
108+
}
109+
110+
llmSpan := tool.LogPrompt(prompt)
111+
112+
// Make API call
113+
resp, err := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
114+
Model: "gpt-3.5-turbo",
115+
Messages: []openai.ChatCompletionMessage{
116+
{
117+
Role: "user",
118+
Content: prompt.Messages[0].Content,
119+
},
120+
},
121+
})
122+
if err != nil {
123+
return "", fmt.Errorf("CreateChatCompletion error: %w", err)
124+
}
125+
126+
// Log completion
127+
var completionMsgs []sdk.Message
128+
for _, choice := range resp.Choices {
129+
completionMsgs = append(completionMsgs, sdk.Message{
130+
Index: choice.Index,
131+
Content: choice.Message.Content,
132+
Role: choice.Message.Role,
133+
})
134+
}
135+
136+
llmSpan.LogCompletion(ctx, sdk.Completion{
137+
Model: resp.Model,
138+
Messages: completionMsgs,
139+
}, sdk.Usage{
140+
TotalTokens: resp.Usage.TotalTokens,
141+
CompletionTokens: resp.Usage.CompletionTokens,
142+
PromptTokens: resp.Usage.PromptTokens,
143+
})
144+
145+
return resp.Choices[0].Message.Content, nil
146+
}
147+
148+
// cookingTimeEstimatorTool estimates preparation and cooking time
149+
func cookingTimeEstimatorTool(ctx context.Context, agent *sdk.Agent, client *openai.Client, recipe string) (string, error) {
150+
tool := agent.NewTool("cooking_time_estimator", "function", sdk.ToolFunction{
151+
Name: "cooking_time_estimator",
152+
Description: "Estimates preparation and cooking time based on recipe complexity",
153+
Parameters: map[string]interface{}{
154+
"type": "object",
155+
"properties": map[string]interface{}{
156+
"recipe": map[string]string{
157+
"type": "string",
158+
"description": "The recipe description",
159+
},
160+
},
161+
},
162+
})
163+
defer tool.End()
164+
165+
prompt := sdk.Prompt{
166+
Vendor: "openai",
167+
Mode: "chat",
168+
Model: "gpt-3.5-turbo",
169+
Messages: []sdk.Message{
170+
{
171+
Index: 0,
172+
Role: "user",
173+
Content: fmt.Sprintf("Estimate the preparation time and cooking time for this recipe: %s", recipe),
174+
},
175+
},
176+
}
177+
178+
llmSpan := tool.LogPrompt(prompt)
179+
180+
// Make API call
181+
resp, err := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
182+
Model: "gpt-3.5-turbo",
183+
Messages: []openai.ChatCompletionMessage{
184+
{
185+
Role: "user",
186+
Content: prompt.Messages[0].Content,
187+
},
188+
},
189+
})
190+
if err != nil {
191+
return "", fmt.Errorf("CreateChatCompletion error: %w", err)
192+
}
193+
194+
// Log completion
195+
var completionMsgs []sdk.Message
196+
for _, choice := range resp.Choices {
197+
completionMsgs = append(completionMsgs, sdk.Message{
198+
Index: choice.Index,
199+
Content: choice.Message.Content,
200+
Role: choice.Message.Role,
201+
})
202+
}
203+
204+
llmSpan.LogCompletion(ctx, sdk.Completion{
205+
Model: resp.Model,
206+
Messages: completionMsgs,
207+
}, sdk.Usage{
208+
TotalTokens: resp.Usage.TotalTokens,
209+
CompletionTokens: resp.Usage.CompletionTokens,
210+
PromptTokens: resp.Usage.PromptTokens,
211+
})
212+
213+
return resp.Choices[0].Message.Content, nil
214+
}
215+
216+
func runRecipeAgent() {
217+
ctx := context.Background()
218+
219+
// Initialize Traceloop SDK
220+
traceloop, err := sdk.NewClient(ctx, sdk.Config{
221+
APIKey: os.Getenv("TRACELOOP_API_KEY"),
222+
})
223+
if err != nil {
224+
fmt.Printf("NewClient error: %v\n", err)
225+
return
226+
}
227+
defer func() { traceloop.Shutdown(ctx) }()
228+
229+
client := openai.NewClient(os.Getenv("OPENAI_API_KEY"))
230+
231+
// Create standalone agent with association properties
232+
agent := traceloop.NewAgent(ctx, "recipe_generator", map[string]string{
233+
"ab_testing_variant": "variant_a",
234+
"user_id": "user_67890",
235+
})
236+
defer agent.End()
237+
238+
// User request
239+
userRequest := "Create a healthy pasta dish with vegetables"
240+
fmt.Printf("User request: %s\n\n", userRequest)
241+
242+
// Agent generates initial recipe
243+
fmt.Println("Generating recipe...")
244+
recipePrompt := sdk.Prompt{
245+
Vendor: "openai",
246+
Mode: "chat",
247+
Model: "gpt-3.5-turbo",
248+
Messages: []sdk.Message{
249+
{
250+
Index: 0,
251+
Role: "user",
252+
Content: fmt.Sprintf("Create a detailed recipe for: %s. Include ingredients and instructions.", userRequest),
253+
},
254+
},
255+
}
256+
257+
llmSpan := agent.LogPrompt(recipePrompt)
258+
259+
resp, err := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
260+
Model: "gpt-3.5-turbo",
261+
Messages: []openai.ChatCompletionMessage{
262+
{
263+
Role: "user",
264+
Content: recipePrompt.Messages[0].Content,
265+
},
266+
},
267+
})
268+
if err != nil {
269+
fmt.Printf("Error generating recipe: %v\n", err)
270+
return
271+
}
272+
273+
// Log completion
274+
var completionMsgs []sdk.Message
275+
for _, choice := range resp.Choices {
276+
completionMsgs = append(completionMsgs, sdk.Message{
277+
Index: choice.Index,
278+
Content: choice.Message.Content,
279+
Role: choice.Message.Role,
280+
})
281+
}
282+
283+
llmSpan.LogCompletion(ctx, sdk.Completion{
284+
Model: resp.Model,
285+
Messages: completionMsgs,
286+
}, sdk.Usage{
287+
TotalTokens: resp.Usage.TotalTokens,
288+
CompletionTokens: resp.Usage.CompletionTokens,
289+
PromptTokens: resp.Usage.PromptTokens,
290+
})
291+
292+
recipe := resp.Choices[0].Message.Content
293+
fmt.Printf("\nGenerated Recipe:\n%s\n\n", recipe)
294+
295+
// Tool 1: Validate ingredients
296+
fmt.Println("Validating ingredients...")
297+
validation, err := ingredientValidatorTool(ctx, agent, client, "pasta, tomatoes, spinach, garlic, olive oil")
298+
if err != nil {
299+
fmt.Printf("Warning: ingredient validation error: %v\n", err)
300+
} else {
301+
fmt.Printf("Validation Result: %s\n\n", validation)
302+
}
303+
304+
// Tool 2: Calculate nutrition
305+
fmt.Println("Calculating nutrition...")
306+
nutrition, err := nutritionCalculatorTool(ctx, agent, client, recipe)
307+
if err != nil {
308+
fmt.Printf("Warning: nutrition calculation error: %v\n", err)
309+
} else {
310+
fmt.Printf("Nutrition Info:\n%s\n\n", nutrition)
311+
}
312+
313+
// Tool 3: Estimate cooking time
314+
fmt.Println("Estimating cooking time...")
315+
cookingTime, err := cookingTimeEstimatorTool(ctx, agent, client, recipe)
316+
if err != nil {
317+
fmt.Printf("Warning: cooking time estimation error: %v\n", err)
318+
} else {
319+
fmt.Printf("Time Estimate:\n%s\n\n", cookingTime)
320+
}
321+
322+
fmt.Println("=== Recipe Agent Complete ===")
323+
}

sample-app/tool_calling.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func runToolCallingExample() {
9191
fmt.Printf("User: %s\n", userPrompt)
9292

9393
// Log the prompt
94-
llmSpan := traceloop.LogPrompt(ctx, prompt, workflowAttrs)
94+
llmSpan := traceloop.LogPrompt(ctx, prompt, &workflowAttrs)
9595

9696
// Make API call to OpenAI
9797
startTime := time.Now()

traceloop-sdk/agent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ func (agent *Agent) End() {
2222

2323
func (agent *Agent) LogPrompt(prompt Prompt) LLMSpan {
2424
if agent.workflow != nil {
25-
return agent.sdk.LogPrompt(agent.ctx, prompt, agent.workflow.Attributes)
25+
return agent.sdk.LogPrompt(agent.ctx, prompt, &agent.workflow.Attributes)
2626
}
27-
return agent.sdk.LogPrompt(agent.ctx, prompt, WorkflowAttributes{})
27+
return agent.sdk.LogPrompt(agent.ctx, prompt, nil)
2828
}
2929

3030
func (agent *Agent) NewTool(name string, toolType string, toolFunction ToolFunction) *Tool {

0 commit comments

Comments
 (0)