Files
Agent-System-Backend/internal/app/compiled.go
T
weichen cb26e4c947
ci / vet-and-test (pull_request) Successful in 41s
Add EXT-1 inproc plugin command handler with owner-scoped host handle
Why: 进程内插件命令此前只登记规格不绑处理器,分发即 "no host handler bound",
且插件无 owner 凭证(H4);EXT-1 最小集补上处理器绑定与 owner 作用域宿主句柄。
Evidence: pkg/extension 新增 Request/Handler/Host + Registry.AddCommandHandler(surface.txt 12→15);
cmdbus.RegisterPluginCommand 三例测试(committed/未绑 rejected/高危确认卡先拦);
rag.IndexChunks 抽出并两例直测;internal/app hostcaps+inprocHost 复用 hostapi owner 作用域实现,
applyCompiled 携 caps,inproc_host_test 双 owner 隔离 + provider=hash 向量写入均通过;go test ./... 29 包全绿。
Impact: 公开面依赖从零外部模块变为 +agent-system-core(声明式 go.mod 需按 compat-policy §4 加 core require+replace);
既有路径语义不变,SurfaceVersion 保持 2.0.0-experimental。
Refs: documents 提案 2026-10-05-ext-1-inproc-command-handler.md;V1.2 方案批注 1。
2026-10-05 11:39:25 +00:00

109 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package app
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
agentcommand "agent-command"
"agent-system-backend/internal/cmdbus"
"agent-system-backend/pkg/extension"
core "agent-system-core"
)
type compiledRegistry struct {
skillsRoot string
bus *cmdbus.Bus
}
// pluginRegistry 携带插件身份与宿主能力,per-InProc 构造:
// AddCommandHandler 绑定的处理器在分发时按请求 Owner 构造 inprocHost(EXT-1)。
type pluginRegistry struct {
compiledRegistry
pluginID string
caps hostcaps
}
func (r pluginRegistry) AddCommandHandler(spec json.RawMessage, h extension.Handler) error {
if r.bus == nil {
return nil
}
if h == nil {
return fmt.Errorf("extension: %s: nil command handler", r.pluginID)
}
var s agentcommand.CommandSpec
if err := json.Unmarshal(spec, &s); err != nil {
return fmt.Errorf("extension: command spec: %w", err)
}
return r.bus.RegisterPluginCommand(s, func(ctx context.Context, req cmdbus.Request) (any, error) {
host := inprocHost{caps: r.caps, pluginID: r.pluginID, owner: req.Owner}
return h(ctx, host, extension.Request{
ID: req.ID, Params: req.Params, Entrance: req.Entrance,
Actor: req.Actor, Owner: req.Owner, ConversationID: req.ConversationID,
})
})
}
func (r compiledRegistry) AddSkill(name, markdown string) error {
if r.skillsRoot == "" || name == "" {
return nil
}
dest := filepath.Join(r.skillsRoot, "compiled", name)
if err := os.MkdirAll(dest, 0o755); err != nil {
return err
}
return os.WriteFile(filepath.Join(dest, "SKILL.md"), []byte(markdown), 0o644)
}
func (r compiledRegistry) AddCommand(spec json.RawMessage) error {
if r.bus == nil {
return nil
}
return r.bus.RegisterPluginCommands([]json.RawMessage{spec})
}
func (r compiledRegistry) Note(kind, name string, payload json.RawMessage) error {
log.Printf("extension: note %s %s (%d bytes)", kind, name, len(payload))
return nil
}
func applyCompiled(skillsRoot string, bus *cmdbus.Bus, caps hostcaps) {
base := compiledRegistry{skillsRoot: skillsRoot, bus: bus}
for _, e := range extension.Compiled() {
if e.Register == nil {
continue
}
reg := pluginRegistry{compiledRegistry: base, pluginID: e.ID, caps: caps}
if err := e.Register(reg); err != nil {
log.Printf("extension: %s: %v", e.ID, err)
}
}
}
func mergeMCPServers(raw string, extra []core.PluginMCPServer) string {
var base []json.RawMessage
if raw != "" {
if err := json.Unmarshal([]byte(raw), &base); err != nil {
return raw
}
}
for _, s := range extra {
b, err := json.Marshal(s)
if err != nil {
continue
}
base = append(base, b)
}
if len(base) == 0 {
return ""
}
out, err := json.Marshal(base)
if err != nil {
return raw
}
return string(out)
}