mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-06 04:23:15 -05:00
The four document skill names were code in the contract, the hint for binary files kept its own list of formats and libraries, and the chat boundary rewrote the old arguments of one add-on by its ID. A skill that shadows a name can now declare the slot it serves: kind, file extensions, name words and a library hint. A tool can declare legacyArgs, the arguments it refuses now, each with a hint. Both need manifest api 2. The four default slots move to a data file that the contract reads, so a manifest that declares nothing keeps working. The host takes the replaceable names, the files a skill covers and the hint for a script from the skills the add-ons list. It compares no format or add-on ID. A guard spec fails when it does again. The Office manifest declares its slots and legacy arguments and accepts api 2. Assisted-by: Claude:claude-sonnet-5-5 go gofmt
109 lines
3.9 KiB
Go
109 lines
3.9 KiB
Go
// SPDX-License-Identifier: MIT
|
|
package contract
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
)
|
|
|
|
// MinExecutionAPI is the first manifest API version that knows the execution
|
|
// descriptor. A manifest that declares one must accept it.
|
|
const MinExecutionAPI uint64 = 2
|
|
|
|
// ExecutionClassCommands is the class of a tool that runs shell commands and
|
|
// code: the tool that shadows bash.
|
|
const ExecutionClassCommands = "commands"
|
|
|
|
// Kinds of skills a commands provider can supply the runtime for.
|
|
const (
|
|
// SkillKindDocuments are the skills of the document slots (see
|
|
// DocumentSkill). They need a provider that reports isolated execution.
|
|
SkillKindDocuments = "documents"
|
|
)
|
|
|
|
// Limits of the text the host shows for an execution provider.
|
|
const (
|
|
MaxExecutionTitleChars = 40
|
|
MaxExecutionNoteChars = 600
|
|
)
|
|
|
|
// ExecutionDescriptor is what an add-on declares about the tool that runs
|
|
// commands. It carries no authority. Whether commands are ready and isolated
|
|
// is what the provider reports at run time (ExecutionStatus); the host decides
|
|
// from that report and never from the add-on's ID.
|
|
type ExecutionDescriptor struct {
|
|
// Class is ExecutionClassCommands.
|
|
Class string `json:"class"`
|
|
// Title names the provider in the text the host shows the person and the
|
|
// model, for example "Sandbox". It falls back to the add-on's title.
|
|
Title string `json:"title,omitempty"`
|
|
// Note is one plain sentence for the model when the provider reports
|
|
// isolated execution, such as the programs its environment has.
|
|
Note string `json:"note,omitempty"`
|
|
// Skills says which skills run on this provider.
|
|
Skills *ExecutionSkills `json:"skills,omitempty"`
|
|
}
|
|
|
|
// ExecutionSkills declares the skills whose runtime the provider supplies.
|
|
type ExecutionSkills struct {
|
|
// ProvidesRuntimeFor lists skill kinds (SkillKindDocuments). The host
|
|
// offers the add-on's skills of those kinds only while the provider
|
|
// reports isolated execution.
|
|
ProvidesRuntimeFor []string `json:"providesRuntimeFor,omitempty"`
|
|
}
|
|
|
|
// validate checks the descriptor of tool d. A nil descriptor is valid.
|
|
func (e *ExecutionDescriptor) validate(d ToolDefinition) error {
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
if e.Class != ExecutionClassCommands || d.Shadows != "bash" {
|
|
return fmt.Errorf("tool %s: an execution descriptor has class %q and belongs to a tool that shadows bash", d.Name, ExecutionClassCommands)
|
|
}
|
|
if e.Title != "" && !plainText(e.Title, MaxExecutionTitleChars) {
|
|
return fmt.Errorf("tool %s: invalid execution title", d.Name)
|
|
}
|
|
if e.Note != "" && !plainText(e.Note, MaxExecutionNoteChars) {
|
|
return fmt.Errorf("tool %s: invalid execution note", d.Name)
|
|
}
|
|
if e.Skills != nil {
|
|
for _, k := range e.Skills.ProvidesRuntimeFor {
|
|
if k != SkillKindDocuments {
|
|
return fmt.Errorf("tool %s: unknown skill kind %q", d.Name, k)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CommandsTool returns the tool of the definitions that shadows bash.
|
|
func CommandsTool(defs []ToolDefinition) (ToolDefinition, bool) {
|
|
i := slices.IndexFunc(defs, func(d ToolDefinition) bool { return d.Shadows == "bash" && ValidateShadow(d) == nil })
|
|
if i < 0 {
|
|
return ToolDefinition{}, false
|
|
}
|
|
return defs[i], true
|
|
}
|
|
|
|
// IsolatedSkills lists the skills of an add-on that need its own commands
|
|
// provider to report isolated execution: the document-slot skills of an
|
|
// add-on with a commands tool, unless its descriptor says it does not provide
|
|
// the runtime for documents. A commands tool without a descriptor (a manifest
|
|
// of API 1) counts as providing it, so such an add-on keeps the check.
|
|
func IsolatedSkills(defs []ToolDefinition, skills []SkillDefinition) []string {
|
|
tool, ok := CommandsTool(defs)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
if e := tool.Execution; e != nil && (e.Skills == nil || !slices.Contains(e.Skills.ProvidesRuntimeFor, SkillKindDocuments)) {
|
|
return nil
|
|
}
|
|
var out []string
|
|
for _, s := range SlotsOf(skills) {
|
|
if s.Kind == SlotKindDocuments {
|
|
out = append(out, s.Name)
|
|
}
|
|
}
|
|
return out
|
|
}
|