Skip to content

Commit 1240952

Browse files
committed
fix: add missing created field to text completion response
1 parent e2d60fe commit 1240952

9 files changed

Lines changed: 70 additions & 45 deletions

File tree

core/providers/anthropic/text.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package anthropic
33
import (
44
"fmt"
55
"strings"
6+
"time"
67

78
"github.com/maximhq/bifrost/core/providers/utils"
89
"github.com/maximhq/bifrost/core/schemas"
@@ -97,6 +98,7 @@ func (response *AnthropicTextResponse) ToBifrostTextCompletionResponse() *schema
9798
},
9899
},
99100
},
101+
Created: time.Now().Unix(),
100102
Usage: &schemas.BifrostLLMUsage{
101103
PromptTokens: response.Usage.InputTokens,
102104
CompletionTokens: response.Usage.OutputTokens,

core/providers/bedrock/text.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package bedrock
22

33
import (
44
"strings"
5+
"time"
56

67
"github.com/maximhq/bifrost/core/providers/anthropic"
78
"github.com/maximhq/bifrost/core/providers/utils"
@@ -126,6 +127,7 @@ func (response *BedrockAnthropicTextResponse) ToBifrostTextCompletionResponse()
126127
FinishReason: &response.StopReason,
127128
},
128129
},
130+
Created: time.Now().Unix(),
129131
ExtraFields: schemas.BifrostResponseExtraFields{
130132
RequestType: schemas.TextCompletionRequest,
131133
Provider: schemas.Bedrock,
@@ -153,6 +155,7 @@ func (response *BedrockMistralTextResponse) ToBifrostTextCompletionResponse() *s
153155
return &schemas.BifrostTextCompletionResponse{
154156
Object: "text_completion",
155157
Choices: choices,
158+
Created: time.Now().Unix(),
156159
ExtraFields: schemas.BifrostResponseExtraFields{
157160
RequestType: schemas.TextCompletionRequest,
158161
Provider: schemas.Bedrock,

core/providers/openai/openai.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ func HandleOpenAITextCompletionStreaming(
500500

501501
var finishReason *string
502502
var messageID string
503+
var created int64
503504
startTime := time.Now()
504505
lastChunkTime := startTime
505506

@@ -622,6 +623,11 @@ func HandleOpenAITextCompletionStreaming(
622623
response.Usage = nil
623624
}
624625

626+
// Track created timestamp from any chunk so final aggregated chunk is always populated.
627+
if response.Created > 0 {
628+
created = response.Created
629+
}
630+
625631
// Skip empty responses or responses without choices
626632
if len(response.Choices) == 0 {
627633
continue
@@ -675,7 +681,7 @@ func HandleOpenAITextCompletionStreaming(
675681
return
676682
}
677683

678-
response := providerUtils.CreateBifrostTextCompletionChunkResponse(messageID, usage, finishReason, chunkIndex, schemas.TextCompletionStreamRequest, providerName, request.Model)
684+
response := providerUtils.CreateBifrostTextCompletionChunkResponse(messageID, usage, finishReason, chunkIndex, created, schemas.TextCompletionStreamRequest, providerName, request.Model)
679685
if postResponseConverter != nil {
680686
response = postResponseConverter(response)
681687
if response == nil {

core/providers/replicate/replicate.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,8 @@ func (provider *ReplicateProvider) TextCompletionStream(ctx *schemas.BifrostCont
597597
var currentEvent ReplicateSSEEvent
598598
messageID := prediction.ID
599599

600+
created := time.Now().Unix()
601+
600602
for scanner.Scan() {
601603
// Check for context cancellation
602604
select {
@@ -637,6 +639,7 @@ func (provider *ReplicateProvider) TextCompletionStream(ctx *schemas.BifrostCont
637639
},
638640
},
639641
},
642+
Created: created,
640643
ExtraFields: schemas.BifrostResponseExtraFields{
641644
RequestType: schemas.TextCompletionStreamRequest,
642645
Provider: provider.GetProviderKey(),
@@ -720,6 +723,7 @@ func (provider *ReplicateProvider) TextCompletionStream(ctx *schemas.BifrostCont
720723
nil, // usage - not available in done event
721724
finishReason,
722725
chunkIndex,
726+
created,
723727
schemas.TextCompletionStreamRequest,
724728
provider.GetProviderKey(),
725729
request.Model,

core/providers/replicate/text.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ func (response *ReplicatePredictionResponse) ToBifrostTextCompletionResponse() *
132132

133133
bifrostResponse.Choices = []schemas.BifrostResponseChoice{choice}
134134

135+
bifrostResponse.Created = ParseReplicateTimestamp(response.CreatedAt)
136+
135137
// Extract usage information from logs
136138
if response.Logs != nil {
137139
inputTokens, outputTokens, totalTokens, found := parseTokenUsageFromLogs(response.Logs, schemas.TextCompletionRequest)

core/providers/utils/utils.go

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import (
66
"bufio"
77
"bytes"
88
"compress/gzip"
9-
"encoding/json"
109
"context"
1110
"crypto/tls"
1211
"crypto/x509"
12+
"encoding/json"
1313
"errors"
1414
"fmt"
1515
"io"
@@ -49,7 +49,7 @@ func MarshalSortedIndent(v interface{}, prefix, indent string) ([]byte, error) {
4949
}
5050

5151
const (
52-
sseInitialBufSize = 8 * 1024 // 8KB — sufficient for >99.9% of SSE lines
52+
sseInitialBufSize = 8 * 1024 // 8KB — sufficient for >99.9% of SSE lines
5353
sseMaxBufSize = 10 * 1024 * 1024 // 10MB — allow large tokens (tool calls, audio)
5454
)
5555

@@ -364,34 +364,34 @@ func filterHeaders(headers map[string][]string) map[string][]string {
364364
// providerResponseFilterHeaders are headers to exclude when forwarding provider response headers.
365365
// These are transport-level headers that don't apply when re-serving the response.
366366
var providerResponseFilterHeaders = map[string]bool{
367-
"content-length": true,
368-
"content-encoding": true,
369-
"transfer-encoding": true,
370-
"connection": true,
371-
"keep-alive": true,
372-
"proxy-connection": true,
373-
"proxy-authenticate": true,
374-
"proxy-authorization": true,
375-
"authorization": true,
376-
"cookie": true,
377-
"set-cookie": true,
378-
"set-cookie2": true,
379-
"www-authenticate": true,
380-
"te": true,
381-
"trailer": true,
382-
"upgrade": true,
383-
"host": true,
384-
"date": true,
385-
"server": true,
386-
"alt-svc": true,
387-
"strict-transport-security": true,
388-
"content-type": true,
389-
"access-control-allow-origin": true,
390-
"access-control-allow-methods": true,
391-
"access-control-allow-headers": true,
392-
"access-control-expose-headers": true,
393-
"access-control-allow-credentials": true,
394-
"access-control-max-age": true,
367+
"content-length": true,
368+
"content-encoding": true,
369+
"transfer-encoding": true,
370+
"connection": true,
371+
"keep-alive": true,
372+
"proxy-connection": true,
373+
"proxy-authenticate": true,
374+
"proxy-authorization": true,
375+
"authorization": true,
376+
"cookie": true,
377+
"set-cookie": true,
378+
"set-cookie2": true,
379+
"www-authenticate": true,
380+
"te": true,
381+
"trailer": true,
382+
"upgrade": true,
383+
"host": true,
384+
"date": true,
385+
"server": true,
386+
"alt-svc": true,
387+
"strict-transport-security": true,
388+
"content-type": true,
389+
"access-control-allow-origin": true,
390+
"access-control-allow-methods": true,
391+
"access-control-allow-headers": true,
392+
"access-control-expose-headers": true,
393+
"access-control-allow-credentials": true,
394+
"access-control-max-age": true,
395395
}
396396

397397
// ExtractProviderResponseHeaders extracts and filters response headers from a
@@ -1562,6 +1562,7 @@ func CreateBifrostTextCompletionChunkResponse(
15621562
usage *schemas.BifrostLLMUsage,
15631563
finishReason *string,
15641564
currentChunkIndex int,
1565+
created int64,
15651566
requestType schemas.RequestType,
15661567
providerName schemas.ModelProvider,
15671568
model string,
@@ -1576,6 +1577,7 @@ func CreateBifrostTextCompletionChunkResponse(
15761577
TextCompletionResponseChoice: &schemas.TextCompletionResponseChoice{}, // empty delta
15771578
},
15781579
},
1580+
Created: created,
15791581
ExtraFields: schemas.BifrostResponseExtraFields{
15801582
RequestType: requestType,
15811583
Provider: providerName,

core/schemas/chatcompletions.go

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ func (cr *BifrostChatRequest) GetExtraParams() map[string]interface{} {
2929

3030
// BifrostChatResponse represents the complete result from a chat completion request.
3131
type BifrostChatResponse struct {
32-
ID string `json:"id"`
33-
Choices []BifrostResponseChoice `json:"choices"`
34-
Created int `json:"created"` // The Unix timestamp (in seconds).
35-
Model string `json:"model"`
36-
Object string `json:"object"` // "chat.completion" or "chat.completion.chunk"
37-
ServiceTier *string `json:"service_tier,omitempty"`
38-
SystemFingerprint string `json:"system_fingerprint"`
39-
Usage *BifrostLLMUsage `json:"usage"`
40-
ExtraFields BifrostResponseExtraFields `json:"extra_fields"`
41-
ExtraParams map[string]interface{} `json:"-"`
32+
ID string `json:"id"`
33+
Choices []BifrostResponseChoice `json:"choices"`
34+
Created int `json:"created"` // The Unix timestamp (in seconds).
35+
Model string `json:"model"`
36+
Object string `json:"object"` // "chat.completion" or "chat.completion.chunk"
37+
ServiceTier *string `json:"service_tier,omitempty"`
38+
SystemFingerprint string `json:"system_fingerprint"`
39+
Usage *BifrostLLMUsage `json:"usage"`
40+
ExtraFields BifrostResponseExtraFields `json:"extra_fields"`
41+
ExtraParams map[string]interface{} `json:"-"`
4242

4343
// Perplexity-specific fields
4444
SearchResults []SearchResult `json:"search_results,omitempty"`
@@ -56,14 +56,15 @@ func (cr *BifrostChatResponse) ToTextCompletionResponse() *BifrostTextCompletion
5656
return &BifrostTextCompletionResponse{
5757
ID: cr.ID,
5858
Model: cr.Model,
59+
Created: int64(cr.Created),
5960
Object: "text_completion",
6061
SystemFingerprint: cr.SystemFingerprint,
6162
Usage: cr.Usage,
6263
ExtraFields: BifrostResponseExtraFields{
6364
RequestType: TextCompletionRequest,
6465
ChunkIndex: cr.ExtraFields.ChunkIndex,
6566
Provider: cr.ExtraFields.Provider,
66-
ModelRequested: cr.ExtraFields.ModelRequested,
67+
ModelRequested: cr.ExtraFields.ModelRequested,
6768
Latency: cr.ExtraFields.Latency,
6869
RawResponse: cr.ExtraFields.RawResponse,
6970
CacheDebug: cr.ExtraFields.CacheDebug,
@@ -79,6 +80,7 @@ func (cr *BifrostChatResponse) ToTextCompletionResponse() *BifrostTextCompletion
7980
return &BifrostTextCompletionResponse{
8081
ID: cr.ID,
8182
Model: cr.Model,
83+
Created: int64(cr.Created),
8284
Object: "text_completion",
8385
SystemFingerprint: cr.SystemFingerprint,
8486
Choices: []BifrostResponseChoice{
@@ -96,7 +98,7 @@ func (cr *BifrostChatResponse) ToTextCompletionResponse() *BifrostTextCompletion
9698
RequestType: TextCompletionRequest,
9799
ChunkIndex: cr.ExtraFields.ChunkIndex,
98100
Provider: cr.ExtraFields.Provider,
99-
ModelRequested: cr.ExtraFields.ModelRequested,
101+
ModelRequested: cr.ExtraFields.ModelRequested,
100102
Latency: cr.ExtraFields.Latency,
101103
RawResponse: cr.ExtraFields.RawResponse,
102104
CacheDebug: cr.ExtraFields.CacheDebug,
@@ -115,6 +117,7 @@ func (cr *BifrostChatResponse) ToTextCompletionResponse() *BifrostTextCompletion
115117
return &BifrostTextCompletionResponse{
116118
ID: cr.ID,
117119
Model: cr.Model,
120+
Created: int64(cr.Created),
118121
Object: "text_completion",
119122
SystemFingerprint: cr.SystemFingerprint,
120123
Choices: []BifrostResponseChoice{
@@ -132,7 +135,7 @@ func (cr *BifrostChatResponse) ToTextCompletionResponse() *BifrostTextCompletion
132135
RequestType: TextCompletionRequest,
133136
ChunkIndex: cr.ExtraFields.ChunkIndex,
134137
Provider: cr.ExtraFields.Provider,
135-
ModelRequested: cr.ExtraFields.ModelRequested,
138+
ModelRequested: cr.ExtraFields.ModelRequested,
136139
Latency: cr.ExtraFields.Latency,
137140
RawResponse: cr.ExtraFields.RawResponse,
138141
CacheDebug: cr.ExtraFields.CacheDebug,
@@ -145,6 +148,7 @@ func (cr *BifrostChatResponse) ToTextCompletionResponse() *BifrostTextCompletion
145148
return &BifrostTextCompletionResponse{
146149
ID: cr.ID,
147150
Model: cr.Model,
151+
Created: int64(cr.Created),
148152
Object: "text_completion",
149153
SystemFingerprint: cr.SystemFingerprint,
150154
Usage: cr.Usage,

core/schemas/textcompletions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ func (r *BifrostTextCompletionRequest) ToBifrostChatRequest() *BifrostChatReques
6767
type BifrostTextCompletionResponse struct {
6868
ID string `json:"id"`
6969
Choices []BifrostResponseChoice `json:"choices"`
70+
Created int64 `json:"created"`
7071
Model string `json:"model"`
7172
Object string `json:"object"` // "text_completion" (same for text completion stream)
7273
SystemFingerprint string `json:"system_fingerprint"`

framework/streaming/types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ func (p *ProcessedStreamResponse) ToBifrostResponse() *schemas.BifrostResponse {
261261
},
262262
},
263263
},
264-
Usage: p.Data.TokenUsage,
264+
Created: p.Data.StartTimestamp.Unix(),
265+
Usage: p.Data.TokenUsage,
265266
}
266267

267268
resp.TextCompletionResponse = textResp

0 commit comments

Comments
 (0)