Skip to content

Commit b202549

Browse files
authored
feat: add interception tracing (#63)
Adds tracing for interceptions, tool calls, recordings and mcp proxies initialization.
1 parent 4a00d06 commit b202549

23 files changed

+1273
-171
lines changed

bridge.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"cdr.dev/slog"
1111
"github.com/coder/aibridge/mcp"
12+
"go.opentelemetry.io/otel/trace"
1213

1314
"github.com/hashicorp/go-multierror"
1415
)
@@ -47,20 +48,20 @@ var _ http.Handler = &RequestBridge{}
4748
// A [Recorder] is also required to record prompt, tool, and token use.
4849
//
4950
// mcpProxy will be closed when the [RequestBridge] is closed.
50-
func NewRequestBridge(ctx context.Context, providers []Provider, recorder Recorder, mcpProxy mcp.ServerProxier, metrics *Metrics, logger slog.Logger) (*RequestBridge, error) {
51+
func NewRequestBridge(ctx context.Context, providers []Provider, recorder Recorder, mcpProxy mcp.ServerProxier, logger slog.Logger, metrics *Metrics, tracer trace.Tracer) (*RequestBridge, error) {
5152
mux := http.NewServeMux()
5253

5354
for _, provider := range providers {
5455
// Add the known provider-specific routes which are bridged (i.e. intercepted and augmented).
5556
for _, path := range provider.BridgedRoutes() {
56-
mux.HandleFunc(path, newInterceptionProcessor(provider, logger, recorder, mcpProxy, metrics))
57+
mux.HandleFunc(path, newInterceptionProcessor(provider, recorder, mcpProxy, logger, metrics, tracer))
5758
}
5859

5960
// Any requests which passthrough to this will be reverse-proxied to the upstream.
6061
//
6162
// We have to whitelist the known-safe routes because an API key with elevated privileges (i.e. admin) might be
6263
// configured, so we should just reverse-proxy known-safe routes.
63-
ftr := newPassthroughRouter(provider, logger.Named(fmt.Sprintf("passthrough.%s", provider.Name())), metrics)
64+
ftr := newPassthroughRouter(provider, logger.Named(fmt.Sprintf("passthrough.%s", provider.Name())), metrics, tracer)
6465
for _, path := range provider.PassthroughRoutes() {
6566
prefix := fmt.Sprintf("/%s", provider.Name())
6667
route := fmt.Sprintf("%s%s", prefix, path)

bridge_integration_test.go

Lines changed: 62 additions & 53 deletions
Large diffs are not rendered by default.

go.mod

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ require (
2626
github.com/openai/openai-go/v2 v2.7.0
2727
)
2828

29+
// Tracing-related libs.
30+
require (
31+
go.opentelemetry.io/otel v1.38.0
32+
go.opentelemetry.io/otel/sdk v1.38.0
33+
go.opentelemetry.io/otel/trace v1.38.0
34+
)
35+
2936
require (
3037
github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
3138
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect
@@ -46,6 +53,8 @@ require (
4653
github.com/cespare/xxhash/v2 v2.3.0 // indirect
4754
github.com/charmbracelet/lipgloss v0.7.1 // indirect
4855
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
56+
github.com/go-logr/logr v1.4.3 // indirect
57+
github.com/go-logr/stdr v1.2.2 // indirect
4958
github.com/hashicorp/errwrap v1.0.0 // indirect
5059
github.com/invopop/jsonschema v0.13.0 // indirect
5160
github.com/kylelemons/godebug v1.1.0 // indirect
@@ -61,14 +70,13 @@ require (
6170
github.com/prometheus/common v0.66.1 // indirect
6271
github.com/prometheus/procfs v0.16.1 // indirect
6372
github.com/rivo/uniseg v0.4.4 // indirect
64-
github.com/rogpeppe/go-internal v1.13.1 // indirect
6573
github.com/spf13/cast v1.7.1 // indirect
6674
github.com/tidwall/match v1.2.0 // indirect
6775
github.com/tidwall/pretty v1.2.1 // indirect
6876
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
6977
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
70-
go.opentelemetry.io/otel v1.33.0 // indirect
71-
go.opentelemetry.io/otel/trace v1.33.0 // indirect
78+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
79+
go.opentelemetry.io/otel/metric v1.38.0 // indirect
7280
go.yaml.in/yaml/v2 v2.4.2 // indirect
7381
golang.org/x/sys v0.35.0 // indirect
7482
golang.org/x/term v0.34.0 // indirect

go.sum

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
5353
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5454
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
5555
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
56-
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
57-
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
56+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
57+
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
58+
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
5859
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
5960
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
6061
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
@@ -130,14 +131,16 @@ github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zI
130131
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
131132
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
132133
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
133-
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
134-
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
135-
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
136-
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
137-
go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
138-
go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
139-
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
140-
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
134+
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
135+
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
136+
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
137+
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
138+
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
139+
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
140+
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
141+
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
142+
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
143+
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
141144
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
142145
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
143146
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=

intercept_anthropic_messages_base.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ import (
1515
"github.com/aws/aws-sdk-go-v2/config"
1616
"github.com/aws/aws-sdk-go-v2/credentials"
1717
"github.com/coder/aibridge/mcp"
18+
"github.com/coder/aibridge/tracing"
1819
"github.com/google/uuid"
20+
"go.opentelemetry.io/otel/attribute"
21+
"go.opentelemetry.io/otel/trace"
1922

2023
"cdr.dev/slog"
2124
)
@@ -27,6 +30,7 @@ type AnthropicMessagesInterceptionBase struct {
2730
cfg AnthropicConfig
2831
bedrockCfg *AWSBedrockConfig
2932

33+
tracer trace.Tracer
3034
logger slog.Logger
3135

3236
recorder Recorder
@@ -59,6 +63,18 @@ func (i *AnthropicMessagesInterceptionBase) Model() string {
5963
return string(i.req.Model)
6064
}
6165

66+
func (s *AnthropicMessagesInterceptionBase) baseTraceAttributes(r *http.Request, streaming bool) []attribute.KeyValue {
67+
return []attribute.KeyValue{
68+
attribute.String(tracing.RequestPath, r.URL.Path),
69+
attribute.String(tracing.InterceptionID, s.id.String()),
70+
attribute.String(tracing.InitiatorID, actorFromContext(r.Context()).id),
71+
attribute.String(tracing.Provider, ProviderAnthropic),
72+
attribute.String(tracing.Model, s.Model()),
73+
attribute.Bool(tracing.Streaming, streaming),
74+
attribute.Bool(tracing.IsBedrock, s.bedrockCfg != nil),
75+
}
76+
}
77+
6278
func (i *AnthropicMessagesInterceptionBase) injectTools() {
6379
if i.req == nil || i.mcpProxy == nil {
6480
return

intercept_anthropic_messages_blocking.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package aibridge
22

33
import (
4+
"context"
45
"fmt"
56
"net/http"
67
"time"
@@ -10,8 +11,11 @@ import (
1011
"github.com/google/uuid"
1112
mcplib "github.com/mark3labs/mcp-go/mcp" // TODO: abstract this away so callers need no knowledge of underlying lib.
1213
"github.com/tidwall/sjson"
14+
"go.opentelemetry.io/otel/attribute"
15+
"go.opentelemetry.io/otel/trace"
1316

1417
"github.com/coder/aibridge/mcp"
18+
"github.com/coder/aibridge/tracing"
1519

1620
"cdr.dev/slog"
1721
)
@@ -22,29 +26,35 @@ type AnthropicMessagesBlockingInterception struct {
2226
AnthropicMessagesInterceptionBase
2327
}
2428

25-
func NewAnthropicMessagesBlockingInterception(id uuid.UUID, req *MessageNewParamsWrapper, cfg AnthropicConfig, bedrockCfg *AWSBedrockConfig) *AnthropicMessagesBlockingInterception {
29+
func NewAnthropicMessagesBlockingInterception(id uuid.UUID, req *MessageNewParamsWrapper, cfg AnthropicConfig, bedrockCfg *AWSBedrockConfig, tracer trace.Tracer) *AnthropicMessagesBlockingInterception {
2630
return &AnthropicMessagesBlockingInterception{AnthropicMessagesInterceptionBase: AnthropicMessagesInterceptionBase{
2731
id: id,
2832
req: req,
2933
cfg: cfg,
3034
bedrockCfg: bedrockCfg,
35+
tracer: tracer,
3136
}}
3237
}
3338

34-
func (s *AnthropicMessagesBlockingInterception) Setup(logger slog.Logger, recorder Recorder, mcpProxy mcp.ServerProxier) {
35-
s.AnthropicMessagesInterceptionBase.Setup(logger.Named("blocking"), recorder, mcpProxy)
39+
func (i *AnthropicMessagesBlockingInterception) Setup(logger slog.Logger, recorder Recorder, mcpProxy mcp.ServerProxier) {
40+
i.AnthropicMessagesInterceptionBase.Setup(logger.Named("blocking"), recorder, mcpProxy)
41+
}
42+
43+
func (i *AnthropicMessagesBlockingInterception) TraceAttributes(r *http.Request) []attribute.KeyValue {
44+
return i.AnthropicMessagesInterceptionBase.baseTraceAttributes(r, false)
3645
}
3746

3847
func (s *AnthropicMessagesBlockingInterception) Streaming() bool {
3948
return false
4049
}
4150

42-
func (i *AnthropicMessagesBlockingInterception) ProcessRequest(w http.ResponseWriter, r *http.Request) error {
51+
func (i *AnthropicMessagesBlockingInterception) ProcessRequest(w http.ResponseWriter, r *http.Request) (outErr error) {
4352
if i.req == nil {
4453
return fmt.Errorf("developer error: req is nil")
4554
}
4655

47-
ctx := r.Context()
56+
ctx, span := i.tracer.Start(r.Context(), "Intercept.ProcessRequest", trace.WithAttributes(tracing.InterceptionAttributesFromContext(r.Context())...))
57+
defer tracing.EndSpanErr(span, &outErr)
4858

4959
i.injectTools()
5060

@@ -77,7 +87,8 @@ func (i *AnthropicMessagesBlockingInterception) ProcessRequest(w http.ResponseWr
7787
var cumulativeUsage anthropic.Usage
7888

7989
for {
80-
resp, err = svc.New(ctx, messages)
90+
// TODO add outer loop span (https://github.com/coder/aibridge/issues/67)
91+
resp, err = i.newMessage(ctx, svc, messages)
8192
if err != nil {
8293
if isConnError(err) {
8394
// Can't write a response, just error out.
@@ -166,7 +177,7 @@ func (i *AnthropicMessagesBlockingInterception) ProcessRequest(w http.ResponseWr
166177
continue
167178
}
168179

169-
res, err := tool.Call(ctx, tc.Input)
180+
res, err := tool.Call(ctx, tc.Input, i.tracer)
170181

171182
_ = i.recorder.RecordToolUsage(ctx, &ToolUsageRecord{
172183
InterceptionID: i.ID().String(),
@@ -286,3 +297,10 @@ func (i *AnthropicMessagesBlockingInterception) ProcessRequest(w http.ResponseWr
286297

287298
return nil
288299
}
300+
301+
func (i *AnthropicMessagesBlockingInterception) newMessage(ctx context.Context, svc anthropic.MessageService, msgParams anthropic.MessageNewParams) (_ *anthropic.Message, outErr error) {
302+
ctx, span := i.tracer.Start(ctx, "Intercept.ProcessRequest.Upstream", trace.WithAttributes(tracing.InterceptionAttributesFromContext(ctx)...))
303+
defer tracing.EndSpanErr(span, &outErr)
304+
305+
return svc.New(ctx, msgParams)
306+
}

intercept_anthropic_messages_streaming.go

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ import (
1111
"time"
1212

1313
"github.com/anthropics/anthropic-sdk-go"
14+
"github.com/anthropics/anthropic-sdk-go/packages/ssestream"
1415
"github.com/anthropics/anthropic-sdk-go/shared/constant"
1516
"github.com/coder/aibridge/mcp"
17+
"github.com/coder/aibridge/tracing"
1618
"github.com/google/uuid"
1719
mcplib "github.com/mark3labs/mcp-go/mcp"
1820
"github.com/tidwall/sjson"
21+
"go.opentelemetry.io/otel/attribute"
22+
"go.opentelemetry.io/otel/trace"
1923

2024
"cdr.dev/slog"
2125
)
@@ -26,12 +30,13 @@ type AnthropicMessagesStreamingInterception struct {
2630
AnthropicMessagesInterceptionBase
2731
}
2832

29-
func NewAnthropicMessagesStreamingInterception(id uuid.UUID, req *MessageNewParamsWrapper, cfg AnthropicConfig, bedrockCfg *AWSBedrockConfig) *AnthropicMessagesStreamingInterception {
33+
func NewAnthropicMessagesStreamingInterception(id uuid.UUID, req *MessageNewParamsWrapper, cfg AnthropicConfig, bedrockCfg *AWSBedrockConfig, tracer trace.Tracer) *AnthropicMessagesStreamingInterception {
3034
return &AnthropicMessagesStreamingInterception{AnthropicMessagesInterceptionBase: AnthropicMessagesInterceptionBase{
3135
id: id,
3236
req: req,
3337
cfg: cfg,
3438
bedrockCfg: bedrockCfg,
39+
tracer: tracer,
3540
}}
3641
}
3742

@@ -43,6 +48,10 @@ func (s *AnthropicMessagesStreamingInterception) Streaming() bool {
4348
return true
4449
}
4550

51+
func (s *AnthropicMessagesStreamingInterception) TraceAttributes(r *http.Request) []attribute.KeyValue {
52+
return s.AnthropicMessagesInterceptionBase.baseTraceAttributes(r, true)
53+
}
54+
4655
// ProcessRequest handles a request to /v1/messages.
4756
// This API has a state-machine behind it, which is described in https://docs.claude.com/en/docs/build-with-claude/streaming#event-types.
4857
//
@@ -62,13 +71,16 @@ func (s *AnthropicMessagesStreamingInterception) Streaming() bool {
6271
// b) if the tool is injected, it will be invoked by the [mcp.ServerProxier] in the remote MCP server, and its
6372
// results relayed to the SERVER. The response from the server will be handled synchronously, and this loop
6473
// can continue until all injected tool invocations are completed and the response is relayed to the client.
65-
func (i *AnthropicMessagesStreamingInterception) ProcessRequest(w http.ResponseWriter, r *http.Request) error {
74+
func (i *AnthropicMessagesStreamingInterception) ProcessRequest(w http.ResponseWriter, r *http.Request) (outErr error) {
6675
if i.req == nil {
6776
return fmt.Errorf("developer error: req is nil")
6877
}
6978

79+
ctx, span := i.tracer.Start(r.Context(), "Intercept.ProcessRequest", trace.WithAttributes(tracing.InterceptionAttributesFromContext(r.Context())...))
80+
defer tracing.EndSpanErr(span, &outErr)
81+
7082
// Allow us to interrupt watch via cancel.
71-
ctx, cancel := context.WithCancel(r.Context())
83+
ctx, cancel := context.WithCancel(ctx)
7284
defer cancel()
7385
r = r.WithContext(ctx) // Rewire context for SSE cancellation.
7486

@@ -118,12 +130,13 @@ func (i *AnthropicMessagesStreamingInterception) ProcessRequest(w http.ResponseW
118130
isFirst := true
119131
newStream:
120132
for {
133+
// TODO add outer loop span (https://github.com/coder/aibridge/issues/67)
121134
if err := streamCtx.Err(); err != nil {
122135
lastErr = fmt.Errorf("stream exit: %w", err)
123136
break
124137
}
125138

126-
stream := svc.NewStreaming(streamCtx, messages)
139+
stream := i.newStream(streamCtx, svc, messages)
127140

128141
var message anthropic.Message
129142
var lastToolName string
@@ -270,7 +283,7 @@ newStream:
270283
continue
271284
}
272285

273-
res, err := tool.Call(streamCtx, input)
286+
res, err := tool.Call(streamCtx, input, i.tracer)
274287

275288
_ = i.recorder.RecordToolUsage(streamCtx, &ToolUsageRecord{
276289
InterceptionID: i.ID().String(),
@@ -522,3 +535,11 @@ func (s *AnthropicMessagesStreamingInterception) encodeForStream(payload []byte,
522535
buf.WriteString("\n\n")
523536
return buf.Bytes()
524537
}
538+
539+
// newStream traces svc.NewStreaming(streamCtx, messages)
540+
func (s *AnthropicMessagesStreamingInterception) newStream(ctx context.Context, svc anthropic.MessageService, messages anthropic.MessageNewParams) *ssestream.Stream[anthropic.MessageStreamEventUnion] {
541+
_, span := s.tracer.Start(ctx, "Intercept.ProcessRequest.Upstream", trace.WithAttributes(tracing.InterceptionAttributesFromContext(ctx)...))
542+
defer span.End()
543+
544+
return svc.NewStreaming(ctx, messages)
545+
}

intercept_openai_chat_base.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,25 @@ import (
77
"strings"
88

99
"github.com/coder/aibridge/mcp"
10+
"github.com/coder/aibridge/tracing"
1011
"github.com/google/uuid"
1112
"github.com/openai/openai-go/v2"
1213
"github.com/openai/openai-go/v2/option"
1314
"github.com/openai/openai-go/v2/shared"
15+
"go.opentelemetry.io/otel/attribute"
16+
"go.opentelemetry.io/otel/trace"
1417

1518
"cdr.dev/slog"
1619
)
1720

1821
type OpenAIChatInterceptionBase struct {
19-
id uuid.UUID
20-
req *ChatCompletionNewParamsWrapper
22+
id uuid.UUID
23+
req *ChatCompletionNewParamsWrapper
24+
baseURL string
25+
key string
2126

22-
baseURL, key string
23-
logger slog.Logger
27+
logger slog.Logger
28+
tracer trace.Tracer
2429

2530
recorder Recorder
2631
mcpProxy mcp.ServerProxier
@@ -42,6 +47,17 @@ func (i *OpenAIChatInterceptionBase) Setup(logger slog.Logger, recorder Recorder
4247
i.mcpProxy = mcpProxy
4348
}
4449

50+
func (s *OpenAIChatInterceptionBase) baseTraceAttributes(r *http.Request, streaming bool) []attribute.KeyValue {
51+
return []attribute.KeyValue{
52+
attribute.String(tracing.RequestPath, r.URL.Path),
53+
attribute.String(tracing.InterceptionID, s.id.String()),
54+
attribute.String(tracing.InitiatorID, actorFromContext(r.Context()).id),
55+
attribute.String(tracing.Provider, ProviderOpenAI),
56+
attribute.String(tracing.Model, s.Model()),
57+
attribute.Bool(tracing.Streaming, streaming),
58+
}
59+
}
60+
4561
func (i *OpenAIChatInterceptionBase) Model() string {
4662
if i.req == nil {
4763
return "coder-aibridge-unknown"

0 commit comments

Comments
 (0)