mirror of
https://github.com/mudler/LocalAI.git
synced 2026-03-31 21:25:59 -04:00
Always populate ORItemParam.Summary (#9049)
* fix(openresponses): do not omit required fields summary and id * fix(openresponses): ensure ORItemParam.Summary is never null Normalize Summary to an empty slice at serialization chokepoints (sendSSEEvent, bufferEvent, buildORResponse) so it always serializes as [] instead of null. Closes #9047
This commit is contained in:
@@ -1332,6 +1332,7 @@ func handleBackgroundStream(ctx context.Context, store *ResponseStore, responseI
|
||||
|
||||
// bufferEvent stores an SSE event in the response store for streaming resume
|
||||
func bufferEvent(store *ResponseStore, responseID string, event *schema.ORStreamEvent) {
|
||||
normalizeORStreamEvent(event)
|
||||
if err := store.AppendEvent(responseID, event); err != nil {
|
||||
xlog.Error("Failed to buffer event", "response_id", responseID, "error", err)
|
||||
}
|
||||
@@ -2605,6 +2606,7 @@ func handleOpenResponsesStream(c echo.Context, responseID string, createdAt int6
|
||||
|
||||
// sendSSEEvent sends a Server-Sent Event
|
||||
func sendSSEEvent(c echo.Context, event *schema.ORStreamEvent) {
|
||||
normalizeORStreamEvent(event)
|
||||
data, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
xlog.Error("Failed to marshal SSE event", "error", err)
|
||||
@@ -2613,6 +2615,13 @@ func sendSSEEvent(c echo.Context, event *schema.ORStreamEvent) {
|
||||
fmt.Fprintf(c.Response().Writer, "event: %s\ndata: %s\n\n", event.Type, string(data))
|
||||
}
|
||||
|
||||
// normalizeORStreamEvent ensures required fields like Summary are never null.
|
||||
func normalizeORStreamEvent(event *schema.ORStreamEvent) {
|
||||
if event.Item != nil && event.Item.Summary == nil {
|
||||
event.Item.Summary = []schema.ORContentPart{}
|
||||
}
|
||||
}
|
||||
|
||||
// getTopLogprobs returns the top_logprobs value, defaulting to 0 if nil
|
||||
func getTopLogprobs(topLogprobs *int) int {
|
||||
if topLogprobs != nil {
|
||||
@@ -2693,6 +2702,13 @@ func buildORResponse(responseID string, createdAt int64, completedAt *int64, sta
|
||||
outputItems = []schema.ORItemField{}
|
||||
}
|
||||
|
||||
// Ensure Summary is never null on any output item
|
||||
for i := range outputItems {
|
||||
if outputItems[i].Summary == nil {
|
||||
outputItems[i].Summary = []schema.ORContentPart{}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure tools is never null - always an array
|
||||
tools := input.Tools
|
||||
if tools == nil {
|
||||
|
||||
@@ -86,7 +86,7 @@ type ORReasoningParam struct {
|
||||
// ORItemParam represents an input/output item (discriminated union by type)
|
||||
type ORItemParam struct {
|
||||
Type string `json:"type"` // message|function_call|function_call_output|reasoning|item_reference
|
||||
ID string `json:"id,omitempty"` // Present for all output items
|
||||
ID string `json:"id"` // Present for all output items
|
||||
Status string `json:"status,omitempty"` // in_progress|completed|incomplete
|
||||
|
||||
// Message fields
|
||||
@@ -102,8 +102,8 @@ type ORItemParam struct {
|
||||
Output interface{} `json:"output,omitempty"` // string or []ORContentPart
|
||||
|
||||
// Reasoning fields (for type == "reasoning")
|
||||
Summary []ORContentPart `json:"summary,omitempty"` // Array of summary parts
|
||||
EncryptedContent *string `json:"encrypted_content,omitempty"` // Provider-specific encrypted content
|
||||
Summary []ORContentPart `json:"summary"` // Array of summary parts
|
||||
EncryptedContent *string `json:"encrypted_content,omitempty"` // Provider-specific encrypted content
|
||||
|
||||
// Note: For item_reference type, use the ID field above to reference the item
|
||||
// Note: For reasoning type, Content field (from message fields) contains the raw reasoning content
|
||||
|
||||
Reference in New Issue
Block a user