mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
Problem: Saved personas can fail when selected with inherited skills, extensions, or hooks. MCP startup failures lack structured server identity and guidance. Root cause: Ordinary discovery accepts linked sources but composition snapshot capture rejects them. MCP startup errors carry the server only in prose instead of the module metadata consumed by the localized refusal boundary. Fix: Flatten contained source links through rooted reads, retain strict snapshot verification, and preserve module identities and sanitized failure causes through HTTP and Chinese/English rendering. Keep required MCP failures blocking and preserve the original session on a failed selection. Verification: Full root Go tests, go vet, make lint, make check, frontend typecheck, and 198 relevant frontend tests pass. Browser fixtures cover failure, retry, management access, and light/dark wide/phone error presentation. Regressions cover source deletion and restart, prefix stability, revocation, containment, snapshot tampering, and credential redaction.
61 lines
1.7 KiB
Go
61 lines
1.7 KiB
Go
package boot
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"reasonix/internal/contract/agentcomposition"
|
|
"reasonix/internal/ext/skill"
|
|
"reasonix/internal/state/agentpreset"
|
|
)
|
|
|
|
func (b *builder) retainSkill(sk skill.Skill) (skill.Skill, error) {
|
|
if sk.Scope == skill.ScopeBuiltin || sk.Path == "" || sk.Path == "(builtin)" {
|
|
return sk.Complete(), nil
|
|
}
|
|
var asset agentpreset.DirectorySnapshot
|
|
var err error
|
|
if filepath.Base(sk.Path) == skill.SkillFile {
|
|
asset, err = agentpreset.CaptureDirectory(filepath.Dir(sk.Path))
|
|
} else {
|
|
var data []byte
|
|
data, err = os.ReadFile(sk.Path)
|
|
asset.Files = []agentpreset.AssetFile{{Path: filepath.Base(sk.Path), Data: data, Mode: 0o600}}
|
|
}
|
|
if err != nil {
|
|
return sk, err
|
|
}
|
|
if err := keepResource(b.opts.Composition, "skill-assets", sk.SlashName(), asset); err != nil {
|
|
return sk, err
|
|
}
|
|
root, err := agentpreset.New(b.roots.Home(), b.root).Materialize(asset)
|
|
if err != nil {
|
|
return sk, err
|
|
}
|
|
sk.Path = filepath.Join(root, filepath.Base(sk.Path))
|
|
return sk.Complete(), nil
|
|
}
|
|
|
|
func (b *builder) restoreSkills(skills []skill.Skill) error {
|
|
for i := range skills {
|
|
for _, r := range b.opts.Composition.Resources {
|
|
if r.Kind != "skill-assets" || r.ID != skills[i].SlashName() {
|
|
continue
|
|
}
|
|
var asset agentpreset.DirectorySnapshot
|
|
if err := jsonResource(r, &asset); err != nil {
|
|
return err
|
|
}
|
|
root, err := agentpreset.New(b.roots.Home(), b.root).Materialize(asset)
|
|
if err != nil {
|
|
return compositionResourceError("skill", skills[i].SlashName(), err)
|
|
}
|
|
skills[i].Path = filepath.Join(root, filepath.Base(skills[i].Path))
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func jsonResource(r agentcomposition.Resource, v any) error { return json.Unmarshal(r.Data, v) }
|