Files
Agent-Native/runtime/llm/route_contract.go
T
agent-exec-transport 899fd70d27
ci / docker-checkout-hostgateway (pull_request) Successful in 12s
governance / governance (pull_request) Successful in 35s
ci / vet-and-test (pull_request) Successful in 1m24s
agent-exec transport e38bcf1cbe415c5d6a3e91773d811b0a/445c377b4484
2026-10-20 04:03:18 +00:00

165 lines
4.7 KiB
Go

package llm
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"net/http"
"net/url"
"strings"
"agent-native/runtime/argschema"
)
// Completion bases recorded on a successful OpenAI-chat message_end.
const (
CompletionDoneMarker = "done_marker"
CompletionRouteContractEOF = "route_contract_eof"
)
// RouteContractEOF lets one exact OpenAI-chat route release tool calls from a
// stream that ended without [DONE], when the HTTP body boundary and every
// frame prove the calls complete. The zero value is off. IdentitySHA256 must
// equal RouteContractIdentity(Model, BaseURL), and BaseURL must already be in
// NormalizeRouteBaseURL form.
type RouteContractEOF struct {
Model string
BaseURL string
IdentitySHA256 string
}
// RouteContractIdentity is the lowercase hex sha256 of
// "openai-chat\n" + model + "\n" + baseURL.
func RouteContractIdentity(model, baseURL string) string {
sum := sha256.Sum256([]byte("openai-chat\n" + model + "\n" + baseURL))
return hex.EncodeToString(sum[:])
}
// NormalizeRouteBaseURL returns the https base URL with lowercase scheme and
// host and no trailing '/'. Any other scheme, userinfo, query or fragment is
// not a match.
func NormalizeRouteBaseURL(raw string) (string, bool) {
if strings.ContainsAny(raw, "?#") {
return "", false
}
u, err := url.Parse(raw)
if err != nil || !strings.EqualFold(u.Scheme, "https") || u.Opaque != "" ||
u.User != nil || u.Host == "" || u.RawQuery != "" || u.ForceQuery || u.Fragment != "" {
return "", false
}
return "https://" + strings.ToLower(u.Host) + strings.TrimRight(u.EscapedPath(), "/"), true
}
func (rc *RouteContractEOF) off() bool {
return rc == nil || *rc == RouteContractEOF{}
}
// admits is condition C1 apart from the redirect check.
func (rc *RouteContractEOF) admits(protocol Protocol, model, base string) bool {
if protocol != "" && protocol != ProtocolOpenAIChat {
return false
}
if model != rc.Model {
return false
}
normalized, ok := NormalizeRouteBaseURL(base)
if !ok || normalized != rc.BaseURL {
return false
}
return RouteContractIdentity(rc.Model, rc.BaseURL) == rc.IdentitySHA256
}
// routeContract evaluates a configured RouteContractEOF for one response.
type routeContract struct {
active bool
tools []ToolDecl
}
// newRouteContract returns nil when the client has no contract configured.
func (c *Client) newRouteContract(model, base string, req *http.Request, resp *http.Response, tools []ToolDecl) *routeContract {
if c.RouteContract.off() {
return nil
}
return &routeContract{
active: c.RouteContract.admits(c.Protocol, model, base) && sameTarget(req, resp),
tools: tools,
}
}
// sameTarget rejects any redirect that changed scheme, host, port or path.
func sameTarget(req *http.Request, resp *http.Response) bool {
if req == nil || req.URL == nil || resp == nil || resp.Request == nil || resp.Request.URL == nil {
return false
}
sent, final := req.URL, resp.Request.URL
return strings.EqualFold(sent.Scheme, final.Scheme) &&
strings.EqualFold(sent.Hostname(), final.Hostname()) &&
sent.Port() == final.Port() &&
sent.EscapedPath() == final.EscapedPath()
}
// check returns the first failing condition id, or "" when all hold.
func (rc *routeContract) check(boundary *BodyBoundaryObservation, obs *TerminalObservation, facts sseFacts, calls []ToolCall) string {
switch {
case !rc.active:
return "C1"
case !boundaryProven(boundary):
return "C2"
case obs == nil || obs.ReadOutcome != "clean_eof":
return "C3"
case facts.finishChunks != 1 || facts.finishReason != "tool_calls" || facts.multiChoice:
return "C4"
case !obs.UsagePresent:
return "C5"
case facts.fragmentAfterFinish:
return "C6"
case !callsComplete(calls):
return "C7"
case !callsDeclared(calls, rc.tools):
return "C8"
case obs.TailEventKind != "json_frame" || !obs.LastFrameJSONComplete:
return "C9"
}
return ""
}
func boundaryProven(b *BodyBoundaryObservation) bool {
if b == nil {
return false
}
return (b.FramingClass == "http2_stream" && b.EOFSeen) ||
(b.FramingClass == "known_length" && b.LengthRelation == "match")
}
func callsComplete(calls []ToolCall) bool {
if len(calls) == 0 {
return false
}
for _, call := range calls {
var args map[string]json.RawMessage
if call.ID == "" || call.Name == "" {
return false
}
if err := json.Unmarshal([]byte(call.Arguments), &args); err != nil || args == nil {
return false
}
}
return true
}
func callsDeclared(calls []ToolCall, tools []ToolDecl) bool {
for _, call := range calls {
idx := -1
for i, decl := range tools {
if decl.Name == call.Name {
idx = i
break
}
}
if idx < 0 || argschema.Validate(tools[idx].Parameters, json.RawMessage(call.Arguments)) != nil {
return false
}
}
return true
}