feat: add workspace-isolated toolhost runtime and capability-gap skill loop

This commit is contained in:
2026-02-28 17:48:33 +08:00
parent ce9346e350
commit 7d6cf6b435
28 changed files with 2223 additions and 143 deletions

View File

@@ -0,0 +1,109 @@
package runtimews
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
const envWorkspaceDir = "AGENT_WORKSPACE_DIR"
func PrepareFromEnv() (string, error) {
workspaceDir := strings.TrimSpace(os.Getenv(envWorkspaceDir))
if workspaceDir == "" {
workspaceDir = filepath.Join(".", "workspace", "agent_runtime")
}
absWorkspace, err := filepath.Abs(workspaceDir)
if err != nil {
return "", err
}
if err := os.MkdirAll(absWorkspace, 0o755); err != nil {
return "", err
}
if err := seedRuntimeWorkspace(absWorkspace); err != nil {
return "", err
}
if err := os.Setenv(envWorkspaceDir, absWorkspace); err != nil {
return "", err
}
_ = os.Setenv("CONFIG_ENV_FILE", filepath.Join(absWorkspace, "configs", "env"))
return absWorkspace, nil
}
func seedRuntimeWorkspace(workspaceRoot string) error {
seedDirs := []string{"configs", "data", "bot_context", "skills"}
for _, name := range seedDirs {
src := filepath.Join(".", name)
dst := filepath.Join(workspaceRoot, name)
if err := copyDirIfMissing(src, dst); err != nil {
return fmt.Errorf("seed %s failed: %w", name, err)
}
}
if err := os.MkdirAll(filepath.Join(workspaceRoot, "workspace"), 0o755); err != nil {
return err
}
return nil
}
func copyDirIfMissing(src, dst string) error {
info, err := os.Stat(src)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
if !info.IsDir() {
return nil
}
if err := os.MkdirAll(dst, 0o755); err != nil {
return err
}
return filepath.WalkDir(src, func(path string, d os.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
rel, err := filepath.Rel(src, path)
if err != nil {
return err
}
target := filepath.Join(dst, rel)
if d.IsDir() {
return os.MkdirAll(target, 0o755)
}
if _, err := os.Stat(target); err == nil {
return nil
}
if err := copyFile(path, target); err != nil {
return err
}
return nil
})
}
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
return err
}
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
if _, err := io.Copy(out, in); err != nil {
return err
}
return out.Sync()
}