Skip to content

Commit 00b6303

Browse files
committed
feat(ai-statistics): add request_model to context
Signed-off-by: Xijun Dai <[email protected]>
1 parent b9d6343 commit 00b6303

File tree

4 files changed

+20
-26
lines changed

4 files changed

+20
-26
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ target/
1717
tools/hack/cluster.conf
1818
envoy/1.20
1919
istio/1.12
20+
go.work*

plugins/wasm-go/extensions/ai-statistics/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ toolchain go1.24.4
66

77
require (
88
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20250611100342-5654e89a7a80
9-
github.com/higress-group/wasm-go v1.0.2-0.20250729071413-2478fd585950
9+
github.com/higress-group/wasm-go v1.0.2-0.20250804091745-dbabcf425bb2
1010
github.com/tidwall/gjson v1.18.0
1111
)
1212

plugins/wasm-go/extensions/ai-statistics/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20250611100342-5654e89a7a80 h1
66
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20250611100342-5654e89a7a80/go.mod h1:tRI2LfMudSkKHhyv1uex3BWzcice2s/l8Ah8axporfA=
77
github.com/higress-group/wasm-go v1.0.2-0.20250729071413-2478fd585950 h1:X4a+wzGEuLkCcAX2XiDf/vcVOIdZWxtEo0YkT+F/mcM=
88
github.com/higress-group/wasm-go v1.0.2-0.20250729071413-2478fd585950/go.mod h1:9k7L730huS/q4V5iH9WLDgf5ZUHEtfhM/uXcegKDG/M=
9+
github.com/higress-group/wasm-go v1.0.2-0.20250804091745-dbabcf425bb2 h1:qYUeTPlWhVlpDrfISm0EArwZQC1Jl/uiD3l1h9PFjuA=
10+
github.com/higress-group/wasm-go v1.0.2-0.20250804091745-dbabcf425bb2/go.mod h1:9k7L730huS/q4V5iH9WLDgf5ZUHEtfhM/uXcegKDG/M=
911
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1012
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1113
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=

plugins/wasm-go/extensions/ai-statistics/main.go

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ const (
6868
LLMDurationCount = "llm_duration_count"
6969
LLMStreamDurationCount = "llm_stream_duration_count"
7070
ResponseType = "response_type"
71-
ChatID = "chat_id"
7271
ChatRound = "chat_round"
7372

7473
// Inner span attributes
@@ -285,6 +284,9 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config AIStatisticsConfig) ty
285284
if consumer, _ := proxywasm.GetHttpRequestHeader(ConsumerKey); consumer != "" {
286285
ctx.SetContext(ConsumerKey, consumer)
287286
}
287+
if requestModel, _ := proxywasm.GetHttpRequestHeader("x-higress-llm-model"); requestModel != "" {
288+
ctx.SetContext(tokenusage.CtxKeyRequestModel, requestModel)
289+
}
288290

289291
ctx.SetRequestBodyBufferLimit(defaultMaxBodyBytes)
290292

@@ -312,14 +314,15 @@ func onHttpRequestBody(ctx wrapper.HttpContext, config AIStatisticsConfig, body
312314
requestModel = model.String()
313315
} else {
314316
requestPath := ctx.GetStringContext(RequestPath, "")
315-
if strings.Contains(requestPath, "generateContent") || strings.Contains(requestPath, "streamGenerateContent") { // Google Gemini GenerateContent
316-
reg := regexp.MustCompile(`^.*/(?P<api_version>[^/]+)/models/(?P<model>[^:]+):\w+Content$`)
317+
if strings.Contains(requestPath, "generateContent") || strings.Contains(requestPath, "streamGenerateContent") || strings.Contains(requestPath, "countTokens") || strings.Contains(requestPath, "predictLongRunning") { // Google Gemini
318+
reg := regexp.MustCompile(`^.*/(?P<api_version>[^/]+)/models/(?P<model>[^:]+):(\w+Content|countTokens|predictLongRunning)$`)
317319
matches := reg.FindStringSubmatch(requestPath)
318320
if len(matches) == 3 {
319321
requestModel = matches[2]
320322
}
321323
}
322324
}
325+
ctx.SetContext(tokenusage.CtxKeyRequestModel, requestModel)
323326
setSpanAttribute(ArmsRequestModel, requestModel)
324327
// Set the number of conversation rounds
325328

@@ -383,14 +386,8 @@ func onHttpStreamingBody(ctx wrapper.HttpContext, config AIStatisticsConfig, dat
383386
}
384387

385388
ctx.SetUserAttribute(ResponseType, "stream")
386-
if chatID := wrapper.GetValueFromBody(data, []string{
387-
"id",
388-
"response.id",
389-
"responseId", // Gemini generateContent
390-
"message.id", // anthropic messages
391-
}); chatID != nil {
392-
ctx.SetUserAttribute(ChatID, chatID.String())
393-
}
389+
390+
tokenusage.ExtractChatId(ctx, data)
394391

395392
// Get requestStartTime from http context
396393
requestStartTime, ok := ctx.GetContext(StatisticsRequestStartTime).(int64)
@@ -452,14 +449,8 @@ func onHttpResponseBody(ctx wrapper.HttpContext, config AIStatisticsConfig, body
452449
ctx.SetUserAttribute(LLMServiceDuration, responseEndTime-requestStartTime)
453450

454451
ctx.SetUserAttribute(ResponseType, "normal")
455-
if chatID := wrapper.GetValueFromBody(body, []string{
456-
"id",
457-
"response.id",
458-
"responseId", // Gemini generateContent
459-
"message.id", // anthropic messages
460-
}); chatID != nil {
461-
ctx.SetUserAttribute(ChatID, chatID.String())
462-
}
452+
453+
tokenusage.ExtractChatId(ctx, body)
463454

464455
// Set information about this request
465456
if !config.disableOpenaiUsage {
@@ -489,7 +480,7 @@ func onHttpResponseBody(ctx wrapper.HttpContext, config AIStatisticsConfig, body
489480
func setAttributeBySource(ctx wrapper.HttpContext, config AIStatisticsConfig, source string, body []byte) {
490481
for _, attribute := range config.attributes {
491482
var key string
492-
var value interface{}
483+
var value any
493484
if source == attribute.ValueSource {
494485
key = attribute.Key
495486
switch source {
@@ -538,9 +529,9 @@ func setAttributeBySource(ctx wrapper.HttpContext, config AIStatisticsConfig, so
538529
}
539530
}
540531

541-
func extractStreamingBodyByJsonPath(data []byte, jsonPath string, rule string) interface{} {
532+
func extractStreamingBodyByJsonPath(data []byte, jsonPath string, rule string) any {
542533
chunks := bytes.Split(bytes.TrimSpace(wrapper.UnifySSEChunk(data)), []byte("\n\n"))
543-
var value interface{}
534+
var value any
544535
if rule == RuleFirst {
545536
for _, chunk := range chunks {
546537
jsonObj := gjson.GetBytes(chunk, jsonPath)
@@ -573,10 +564,10 @@ func extractStreamingBodyByJsonPath(data []byte, jsonPath string, rule string) i
573564
}
574565

575566
// Set the tracing span with value.
576-
func setSpanAttribute(key string, value interface{}) {
567+
func setSpanAttribute(key string, value any) {
577568
if value != "" {
578569
traceSpanTag := wrapper.TraceSpanTagPrefix + key
579-
if e := proxywasm.SetProperty([]string{traceSpanTag}, []byte(fmt.Sprint(value))); e != nil {
570+
if e := proxywasm.SetProperty([]string{traceSpanTag}, fmt.Append(nil, value)); e != nil {
580571
log.Warnf("failed to set %s in filter state: %v", traceSpanTag, e)
581572
}
582573
} else {
@@ -652,7 +643,7 @@ func writeMetric(ctx wrapper.HttpContext, config AIStatisticsConfig) {
652643
}
653644
}
654645

655-
func convertToUInt(val interface{}) (uint64, bool) {
646+
func convertToUInt(val any) (uint64, bool) {
656647
switch v := val.(type) {
657648
case float32:
658649
return uint64(v), true

0 commit comments

Comments
 (0)