Skip to content

Commit 2d99d05

Browse files
authored
feat: introduce workflows and tasks (#8)
1 parent 8dda467 commit 2d99d05

File tree

7 files changed

+210
-13
lines changed

7 files changed

+210
-13
lines changed

go.work.sum

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,40 @@ cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdi
22
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
33
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
44
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
5+
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
56
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
67
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
78
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
89
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
910
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
1011
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
12+
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
1113
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
1214
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
1315
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
1416
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
17+
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
1518
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
1619
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
1720
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
1821
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
22+
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
1923
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
2024
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
25+
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
2126
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
2227
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
2328
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
2429
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
2530
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
2631
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
32+
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
2733
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
34+
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
2835
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
36+
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
2937
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
38+
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
3039
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
3140
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
3241
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=

sample-app/main.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
tlp "github.com/traceloop/go-openllmetry/traceloop-sdk"
1111
)
1212

13-
func main() {
13+
func workflow_example() {
1414
ctx := context.Background()
1515

1616
traceloop, err := tlp.NewClient(ctx, tlp.Config{
@@ -47,9 +47,8 @@ func main() {
4747
Model: request.Model,
4848
Messages: promptMsgs,
4949
},
50-
tlp.TraceloopAttributes{
51-
WorkflowName: "example-workflow",
52-
EntityName: "example-entity",
50+
tlp.WorkflowAttributes{
51+
Name: "example-workflow",
5352
},
5453
)
5554
if err != nil {

sample-app/workflow_example.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"time"
8+
9+
"github.com/sashabaranov/go-openai"
10+
tlp "github.com/traceloop/go-openllmetry/traceloop-sdk"
11+
)
12+
13+
func main() {
14+
ctx := context.Background()
15+
16+
traceloop, err := tlp.NewClient(ctx, tlp.Config{
17+
BaseURL: "api-staging.traceloop.com",
18+
APIKey: os.Getenv("TRACELOOP_API_KEY"),
19+
})
20+
defer func() { traceloop.Shutdown(ctx) }()
21+
22+
if err != nil {
23+
fmt.Printf("NewClient error: %v\n", err)
24+
return
25+
}
26+
27+
wf := traceloop.NewWorkflow(ctx, tlp.WorkflowAttributes{
28+
Name: "history_generation",
29+
})
30+
defer wf.End()
31+
32+
factGenTask := wf.NewTask("current_date_fact_generation")
33+
defer factGenTask.End()
34+
35+
request, err := traceloop.GetOpenAIChatCompletionRequest("example-prompt", map[string]interface{}{ "date": time.Now().Format("01/02") })
36+
if err != nil {
37+
fmt.Printf("GetOpenAIChatCompletionRequest error: %v\n", err)
38+
return
39+
}
40+
41+
var promptMsgs []tlp.Message
42+
for i, message := range request.Messages {
43+
promptMsgs = append(promptMsgs, tlp.Message{
44+
Index: i,
45+
Content: message.Content,
46+
Role: message.Role,
47+
})
48+
}
49+
50+
llmSpan, err := factGenTask.LogPrompt(
51+
tlp.Prompt{
52+
Vendor: "openai",
53+
Mode: "chat",
54+
Model: request.Model,
55+
Messages: promptMsgs,
56+
},
57+
)
58+
if err != nil {
59+
fmt.Printf("LogPrompt error: %v\n", err)
60+
return
61+
}
62+
63+
client := openai.NewClient(os.Getenv("OPENAI_API_KEY"))
64+
resp, err := client.CreateChatCompletion(
65+
context.Background(),
66+
*request,
67+
)
68+
if err != nil {
69+
fmt.Printf("ChatCompletion error: %v\n", err)
70+
return
71+
}
72+
73+
var completionMsgs []tlp.Message
74+
for _, choice := range resp.Choices {
75+
completionMsgs = append(completionMsgs, tlp.Message{
76+
Index: choice.Index,
77+
Content: choice.Message.Content,
78+
Role: choice.Message.Role,
79+
})
80+
}
81+
82+
llmSpan.LogCompletion(ctx, tlp.Completion{
83+
Model: resp.Model,
84+
Messages: completionMsgs,
85+
}, tlp.Usage{
86+
TotalTokens: resp.Usage.TotalTokens,
87+
CompletionTokens: resp.Usage.CompletionTokens,
88+
PromptTokens: resp.Usage.PromptTokens,
89+
})
90+
91+
someOtherTask := wf.NewTask("some_other_task")
92+
defer someOtherTask.End()
93+
94+
otherPrompt, _ := someOtherTask.LogPrompt(tlp.Prompt{
95+
Vendor: "openai",
96+
Mode: "chat",
97+
Model: request.Model,
98+
Messages: []tlp.Message{
99+
{
100+
Index: 0,
101+
Content: "some other prompt",
102+
Role: "user",
103+
},
104+
},
105+
})
106+
107+
otherPrompt.LogCompletion(ctx, tlp.Completion{
108+
Model: resp.Model,
109+
Messages: completionMsgs,
110+
}, tlp.Usage{
111+
TotalTokens: resp.Usage.TotalTokens,
112+
CompletionTokens: resp.Usage.CompletionTokens,
113+
PromptTokens: resp.Usage.PromptTokens,
114+
})
115+
116+
fmt.Println(resp.Choices[0].Message.Content)
117+
}

traceloop-sdk/sdk.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package traceloop
33
import (
44
"context"
55
"fmt"
6+
"log"
67
"net/http"
78
"os"
89
"time"
@@ -62,7 +63,7 @@ func (instance *Traceloop) initialize(ctx context.Context) error {
6263
}
6364
}
6465

65-
fmt.Printf("Traceloop %s SDK initialized. Connecting to %s\n", Version(), instance.config.BaseURL)
66+
log.Printf("Traceloop %s SDK initialized. Connecting to %s\n", Version(), instance.config.BaseURL)
6667

6768
instance.pollPrompts()
6869
err := instance.initTracer(ctx, instance.config.ServiceName)
@@ -91,16 +92,19 @@ func (instance *Traceloop) tracerName() string {
9192
}
9293
}
9394

94-
func (instance *Traceloop) LogPrompt(ctx context.Context, prompt Prompt, traceloopAttrs TraceloopAttributes) (LLMSpan, error) {
95+
func (instance *Traceloop) getTracer() apitrace.Tracer {
96+
return (*instance.tracerProvider).Tracer(instance.tracerName())
97+
}
98+
99+
func (instance *Traceloop) LogPrompt(ctx context.Context, prompt Prompt, workflowAttrs WorkflowAttributes) (LLMSpan, error) {
95100
spanName := fmt.Sprintf("%s.%s", prompt.Vendor, prompt.Mode)
96-
_, span := (*instance.tracerProvider).Tracer(instance.tracerName()).Start(ctx, spanName)
101+
_, span := instance.getTracer().Start(ctx, spanName)
97102

98103
span.SetAttributes(
99104
semconvai.LLMVendor.String(prompt.Vendor),
100105
semconvai.LLMRequestModel.String(prompt.Model),
101106
semconvai.LLMRequestType.String(prompt.Mode),
102-
semconvai.TraceloopWorkflowName.String(traceloopAttrs.WorkflowName),
103-
semconvai.TraceloopEntityName.String(traceloopAttrs.EntityName),
107+
semconvai.TraceloopWorkflowName.String(workflowAttrs.Name),
104108
)
105109

106110
setMessagesAttribute(span, "llm.prompts", prompt.Messages)

traceloop-sdk/tracing_types.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ type Completion struct {
2323
Messages []Message `json:"messages"`
2424
}
2525

26-
type TraceloopAttributes struct {
27-
WorkflowName string `json:"workflow_name"`
28-
EntityName string `json:"entity_name"`
26+
type WorkflowAttributes struct {
27+
Name string `json:"workflow_name"`
2928
AssociationProperties map[string]string `json:"association_properties"`
3029
}
3130

traceloop-sdk/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ package traceloop
22

33
func Version() string {
44
return "0.0.2"
5-
}
5+
}

traceloop-sdk/workflow.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package traceloop
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
semconvai "github.com/traceloop/go-openllmetry/semconv-ai"
8+
"go.opentelemetry.io/otel/trace"
9+
)
10+
11+
type Workflow struct {
12+
sdk *Traceloop
13+
ctx context.Context
14+
Attributes WorkflowAttributes `json:"workflow_attributes"`
15+
}
16+
17+
type Task struct {
18+
workflow *Workflow
19+
ctx context.Context
20+
Name string `json:"name"`
21+
}
22+
23+
func (instance *Traceloop) NewWorkflow(ctx context.Context, attrs WorkflowAttributes) *Workflow {
24+
wCtx, span := instance.getTracer().Start(ctx, fmt.Sprintf("%s.workflow", attrs.Name), trace.WithNewRoot())
25+
26+
span.SetAttributes(
27+
semconvai.TraceloopWorkflowName.String(attrs.Name),
28+
semconvai.TraceloopSpanKind.String("workflow"),
29+
semconvai.TraceloopEntityName.String(attrs.Name),
30+
)
31+
32+
return &Workflow{
33+
sdk: instance,
34+
ctx: wCtx,
35+
Attributes: attrs,
36+
}
37+
}
38+
39+
func (workflow *Workflow) End() {
40+
trace.SpanFromContext(workflow.ctx).End()
41+
}
42+
43+
func (workflow *Workflow) LogPrompt(prompt Prompt) (LLMSpan, error) {
44+
return workflow.sdk.LogPrompt(workflow.ctx, prompt, workflow.Attributes)
45+
}
46+
47+
func (workflow *Workflow) NewTask(name string) *Task {
48+
tCtx, span := workflow.sdk.getTracer().Start(workflow.ctx, fmt.Sprintf("%s.task", name))
49+
50+
span.SetAttributes(
51+
semconvai.TraceloopWorkflowName.String(workflow.Attributes.Name),
52+
semconvai.TraceloopSpanKind.String("task"),
53+
semconvai.TraceloopEntityName.String(name),
54+
)
55+
56+
return &Task{
57+
workflow: workflow,
58+
ctx: tCtx,
59+
Name: name,
60+
}
61+
}
62+
63+
func (task *Task) End() {
64+
trace.SpanFromContext(task.ctx).End()
65+
}
66+
67+
func (task *Task) LogPrompt(prompt Prompt) (LLMSpan, error) {
68+
return task.workflow.sdk.LogPrompt(task.ctx, prompt, task.workflow.Attributes)
69+
}

0 commit comments

Comments
 (0)