Files
LocalAI/pkg/addons/contract/executionstatus.go
T
Ettore Di Giacinto 9fafea8fdf fix(chats): show the network switcher and say why execution status is unknown
The Network row of the Tools menu could never show the Off, Registries and
All switcher: the host stopped setting `applies` because isolation alone does
not prove network-policy enforcement, and nothing else set it.

Let the provider report enforcement in its typed execution status
(`networkPolicyEnforced`). The host sets `applies` only when that report is
true and the status is available and isolated. The Sandbox reports it for the
gVisor and KVM backends, whose guests reach the network only through the proxy
that asks the host. Providers that do not report it keep the "not enforced"
text.

When the host cannot read the status, give the unknown state a reason
(`unknown_reason`) in the API and the Tools menu: owner unreachable, not
reported, stale, invalid, not selected, no answer or reported unknown. Log the
class of each failure, rate limited. After a failure that a restart of the
add-on owner can cause, let a long turn bind and read again, at most once every
five seconds, instead of keeping the first failure for the whole turn.

The Sandbox now reports "unavailable" with a reason when it started without
settings, and explains a backend it does not know.

When the Sandbox document skills are hidden because the Sandbox is not known to
be isolated, say so in the skill list, in the turn note and in the
`load_skill` error, instead of "This chat has no skills now".

Assisted-by: Claude Code:claude-sonnet-5-5
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
2026-11-03 08:39:30 +00:00

61 lines
2.2 KiB
Go

// SPDX-License-Identifier: MIT
package contract
import (
"fmt"
"unicode/utf8"
)
const (
MaxExecutionStatusBytes = 2048
MaxExecutionExplanationChars = 200
)
// ExecutionStatus is provider-reported observation, not authority or a host
// isolation guarantee. Only DecodeExecutionStatus validates a wire payload.
type ExecutionStatus struct {
Readiness string `json:"readiness"`
Isolation string `json:"isolation"`
Explanation string `json:"explanation,omitempty"`
// NetworkPolicyEnforced is the provider's report that every network
// connection of its commands goes through the host's network policy. It is
// kept only for an available, isolated provider; the host still decides
// whether to rely on it.
NetworkPolicyEnforced bool `json:"networkPolicyEnforced,omitempty"`
}
// DecodeExecutionStatus decodes Result.Payload, never the result envelope.
// Unknown/duplicate/trailing fields (including outputs) are refused. On any
// error it returns unknown/unknown, not partially trusted provider data.
func DecodeExecutionStatus(b []byte) (ExecutionStatus, error) {
unknown := ExecutionStatus{Readiness: "unknown", Isolation: "unknown"}
var v ExecutionStatus
if !utf8.Valid(b) {
return unknown, fmt.Errorf("invalid execution status UTF-8")
}
fields, err := exactObjectFields(b, MaxExecutionStatusBytes, "readiness", "isolation", "explanation", "networkPolicyEnforced")
if err != nil {
return unknown, err
}
if err := strictJSON(b, &v, MaxExecutionStatusBytes); err != nil {
return unknown, err
}
if v.Readiness != "available" && v.Readiness != "unavailable" && v.Readiness != "unknown" {
return unknown, fmt.Errorf("invalid execution readiness")
}
if v.Isolation != "isolated" && v.Isolation != "host" && v.Isolation != "unknown" {
return unknown, fmt.Errorf("invalid execution isolation")
}
// Distinguish absent explanation from explicit null or empty text.
if _, present := fields["explanation"]; present && !ValidPlainText(v.Explanation, MaxExecutionExplanationChars) {
return unknown, fmt.Errorf("invalid execution explanation")
}
if v.Readiness != "available" {
v.Isolation = "unknown"
}
if v.Readiness != "available" || v.Isolation != "isolated" {
v.NetworkPolicyEnforced = false
}
return v, nil
}