122 lines
3.6 KiB
Go
122 lines
3.6 KiB
Go
package responseschema
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// Key identifies one structured response schema used by Audita.
|
|
type Key string
|
|
|
|
const (
|
|
CorrectionSetKey Key = "correction_set"
|
|
ValidatorDecisionSetKey Key = "validator_decision_set"
|
|
correctionSetSchemaID = "audita.correction_set"
|
|
validatorDecisionSchemaID = "audita.validator_decision_set"
|
|
schemaVersionV1 = "v1"
|
|
)
|
|
|
|
// Schema describes one registered structured response schema.
|
|
type Schema struct {
|
|
ID string `json:"id"`
|
|
Version string `json:"version"`
|
|
Name string `json:"name"`
|
|
JSONSchema json.RawMessage `json:"json_schema"`
|
|
SHA256 string `json:"sha256"`
|
|
}
|
|
|
|
func (s Schema) DiagnosticsMap() map[string]any {
|
|
return map[string]any{
|
|
"id": s.ID,
|
|
"version": s.Version,
|
|
"name": s.Name,
|
|
"sha256": s.SHA256,
|
|
}
|
|
}
|
|
|
|
var registry = map[Key]Schema{
|
|
CorrectionSetKey: mustBuildSchema(
|
|
correctionSetSchemaID,
|
|
schemaVersionV1,
|
|
"audita_correction_set_v1",
|
|
[]byte(`{"type":"object","additionalProperties":false,"required":["corrections"],"properties":{"corrections":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["id","original_text","corrected_text","confidence"],"properties":{"id":{"type":"integer","minimum":1},"original_text":{"type":"string","minLength":1},"corrected_text":{"type":"string","minLength":1},"confidence":{"type":"number","minimum":0,"maximum":1}}}}}}`),
|
|
),
|
|
ValidatorDecisionSetKey: mustBuildSchema(
|
|
validatorDecisionSchemaID,
|
|
schemaVersionV1,
|
|
"audita_validator_decision_set_v1",
|
|
[]byte(`{"type":"object","additionalProperties":false,"required":["validations"],"properties":{"validations":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["correction_index","approved","confidence","reason"],"properties":{"correction_index":{"type":"integer","minimum":0},"approved":{"type":"boolean"},"confidence":{"type":"number","minimum":0,"maximum":1},"reason":{"type":"string"}}}}}}`),
|
|
),
|
|
}
|
|
|
|
func Registered() []Schema {
|
|
keys := make([]string, 0, len(registry))
|
|
for key := range registry {
|
|
keys = append(keys, string(key))
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
out := make([]Schema, 0, len(keys))
|
|
for _, key := range keys {
|
|
out = append(out, cloneSchema(registry[Key(key)]))
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Lookup returns a copy of the registered schema for the provided key.
|
|
func Lookup(key Key) (Schema, bool) {
|
|
schema, ok := registry[key]
|
|
if !ok {
|
|
return Schema{}, false
|
|
}
|
|
return cloneSchema(schema), true
|
|
}
|
|
|
|
// MustLookup returns a copy of the registered schema and panics when missing.
|
|
func MustLookup(key Key) Schema {
|
|
schema, ok := Lookup(key)
|
|
if !ok {
|
|
panic(fmt.Sprintf("unknown structured response schema key %q", key))
|
|
}
|
|
return schema
|
|
}
|
|
|
|
func cloneSchema(in Schema) Schema {
|
|
out := in
|
|
if in.JSONSchema != nil {
|
|
out.JSONSchema = append(json.RawMessage(nil), in.JSONSchema...)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func mustBuildSchema(id string, version string, name string, rawSchema []byte) Schema {
|
|
id = strings.TrimSpace(id)
|
|
version = strings.TrimSpace(version)
|
|
name = strings.TrimSpace(name)
|
|
if id == "" {
|
|
panic("schema id must not be empty")
|
|
}
|
|
if version == "" {
|
|
panic("schema version must not be empty")
|
|
}
|
|
if name == "" {
|
|
panic("schema name must not be empty")
|
|
}
|
|
if !json.Valid(rawSchema) {
|
|
panic(fmt.Sprintf("schema %s:%s is not valid JSON", id, version))
|
|
}
|
|
|
|
hash := sha256.Sum256(rawSchema)
|
|
return Schema{
|
|
ID: id,
|
|
Version: version,
|
|
Name: name,
|
|
JSONSchema: append(json.RawMessage(nil), rawSchema...),
|
|
SHA256: hex.EncodeToString(hash[:]),
|
|
}
|
|
}
|