iop/apps/edge/internal/openai/json_field_patch.go
toki d182eafeff feat: stream evidence gate core - full implementation
- Stream evidence gate routing in edge config and runtime
- Ingress snapshot and allocation
- Recovery coordinator and plan
- Runtime contract for gate filters
- OpenAI-compatible request rebuilder and stream gate dispatcher
- Comprehensive tests for all new components
- Updated contracts and roadmap milestones
2026-07-26 20:48:53 +09:00

273 lines
6.7 KiB
Go

package openai
import (
"encoding/json"
"fmt"
"sort"
)
// topLevelJSONPatch is a request-local instruction for one top-level JSON
// member. A nil value removes the member; a non-nil value replaces it or is
// appended when the member is absent.
type topLevelJSONPatch struct {
name string
value []byte
}
type topLevelJSONFieldSpan struct {
name string
memberFrom int
memberTo int
valueFrom int
valueTo int
}
type jsonByteEdit struct {
from int
to int
replacement []byte
}
type topLevelJSONPatchPlan struct {
body []byte
edits []jsonByteEdit
outputSize int
}
func planTopLevelJSONPatches(body []byte, patches []topLevelJSONPatch) (topLevelJSONPatchPlan, error) {
if len(patches) == 0 {
return topLevelJSONPatchPlan{body: body, outputSize: len(body)}, nil
}
fields, objectEnd, err := scanTopLevelJSONObject(body)
if err != nil {
return topLevelJSONPatchPlan{}, err
}
patchByName := make(map[string]topLevelJSONPatch, len(patches))
for _, patch := range patches {
if patch.name == "" {
return topLevelJSONPatchPlan{}, fmt.Errorf("JSON patch field is required")
}
if patch.value != nil && !json.Valid(patch.value) {
return topLevelJSONPatchPlan{}, fmt.Errorf("invalid JSON patch for %s", patch.name)
}
patchByName[patch.name] = patch
}
found := make(map[string]bool, len(patchByName))
edits := make([]jsonByteEdit, 0, len(patches))
for index, field := range fields {
patch, ok := patchByName[field.name]
if !ok {
continue
}
found[field.name] = true
if patch.value != nil {
edits = append(edits, jsonByteEdit{from: field.valueFrom, to: field.valueTo, replacement: patch.value})
continue
}
// Removing a target member also removes exactly one adjacent comma. The
// untouched members and all bytes outside this local span remain intact.
from, to := field.memberFrom, field.memberTo
if index+1 < len(fields) {
to = fields[index+1].memberFrom
} else if index > 0 {
from = fields[index-1].memberTo
}
edits = append(edits, jsonByteEdit{from: from, to: to})
}
var insertion []byte
memberCount := len(fields)
for _, patch := range patches {
if found[patch.name] || patch.value == nil {
continue
}
nameJSON, err := json.Marshal(patch.name)
if err != nil {
return topLevelJSONPatchPlan{}, err
}
if memberCount > 0 {
insertion = append(insertion, ',')
}
insertion = append(insertion, nameJSON...)
insertion = append(insertion, ':')
insertion = append(insertion, patch.value...)
memberCount++
}
if len(insertion) > 0 {
edits = append(edits, jsonByteEdit{from: objectEnd, to: objectEnd, replacement: insertion})
}
sort.SliceStable(edits, func(i, j int) bool { return edits[i].from < edits[j].from })
outputSize := len(body)
lastTo := 0
for _, edit := range edits {
if edit.from < lastTo || edit.from < 0 || edit.to < edit.from || edit.to > len(body) {
return topLevelJSONPatchPlan{}, fmt.Errorf("overlapping JSON field patches")
}
outputSize += len(edit.replacement) - (edit.to - edit.from)
if outputSize < 0 {
return topLevelJSONPatchPlan{}, fmt.Errorf("JSON patch output size overflow")
}
lastTo = edit.to
}
return topLevelJSONPatchPlan{body: body, edits: edits, outputSize: outputSize}, nil
}
func (p topLevelJSONPatchPlan) apply() []byte {
if len(p.edits) == 0 {
return p.body
}
out := make([]byte, 0, p.outputSize)
last := 0
for _, edit := range p.edits {
out = append(out, p.body[last:edit.from]...)
out = append(out, edit.replacement...)
last = edit.to
}
out = append(out, p.body[last:]...)
return out
}
func scanTopLevelJSONObject(body []byte) ([]topLevelJSONFieldSpan, int, error) {
if !json.Valid(body) {
return nil, 0, fmt.Errorf("invalid JSON request")
}
i := skipJSONSpace(body, 0)
if i >= len(body) || body[i] != '{' {
return nil, 0, fmt.Errorf("JSON request must be an object")
}
i++
fields := make([]topLevelJSONFieldSpan, 0, 8)
for {
i = skipJSONSpace(body, i)
if i >= len(body) {
return nil, 0, fmt.Errorf("invalid JSON request")
}
if body[i] == '}' {
return fields, i, nil
}
memberFrom := i
keyTo, err := scanJSONString(body, i)
if err != nil {
return nil, 0, fmt.Errorf("invalid JSON request")
}
var name string
if err := json.Unmarshal(body[i:keyTo], &name); err != nil {
return nil, 0, fmt.Errorf("invalid JSON request")
}
i = skipJSONSpace(body, keyTo)
if i >= len(body) || body[i] != ':' {
return nil, 0, fmt.Errorf("invalid JSON request")
}
i = skipJSONSpace(body, i+1)
valueFrom := i
valueTo, err := scanJSONValue(body, i)
if err != nil {
return nil, 0, fmt.Errorf("invalid JSON request")
}
i = skipJSONSpace(body, valueTo)
memberTo := i
fields = append(fields, topLevelJSONFieldSpan{
name: name, memberFrom: memberFrom, memberTo: memberTo,
valueFrom: valueFrom, valueTo: valueTo,
})
if i >= len(body) {
return nil, 0, fmt.Errorf("invalid JSON request")
}
switch body[i] {
case ',':
i++
case '}':
return fields, i, nil
default:
return nil, 0, fmt.Errorf("invalid JSON request")
}
}
}
func scanJSONString(body []byte, start int) (int, error) {
if start >= len(body) || body[start] != '"' {
return 0, fmt.Errorf("JSON string expected")
}
escaped := false
for i := start + 1; i < len(body); i++ {
if escaped {
escaped = false
continue
}
switch body[i] {
case '\\':
escaped = true
case '"':
return i + 1, nil
}
}
return 0, fmt.Errorf("unterminated JSON string")
}
func scanJSONValue(body []byte, start int) (int, error) {
if start >= len(body) {
return 0, fmt.Errorf("JSON value expected")
}
if body[start] == '"' {
return scanJSONString(body, start)
}
if body[start] == '{' || body[start] == '[' {
stack := []byte{body[start]}
inString, escaped := false, false
for i := start + 1; i < len(body); i++ {
ch := body[i]
if inString {
if escaped {
escaped = false
} else if ch == '\\' {
escaped = true
} else if ch == '"' {
inString = false
}
continue
}
switch ch {
case '"':
inString = true
case '{', '[':
stack = append(stack, ch)
case '}', ']':
open := stack[len(stack)-1]
if (open == '{' && ch != '}') || (open == '[' && ch != ']') {
return 0, fmt.Errorf("mismatched JSON container")
}
stack = stack[:len(stack)-1]
if len(stack) == 0 {
return i + 1, nil
}
}
}
return 0, fmt.Errorf("unterminated JSON container")
}
for i := start; i < len(body); i++ {
switch body[i] {
case ' ', '\t', '\r', '\n', ',', '}', ']':
if i == start {
return 0, fmt.Errorf("JSON value expected")
}
return i, nil
}
}
return len(body), nil
}
func skipJSONSpace(body []byte, i int) int {
for i < len(body) {
switch body[i] {
case ' ', '\t', '\r', '\n':
i++
default:
return i
}
}
return i
}