remove built-in skill handlers, replace with external tools
skill_list and skill_load are now external shell scripts (data/tools/). Removed from builtins: SkillList, SkillLoad, SkillActive. Removed: toolsrv/skills.go, tools/builtin/skill.go, WithSkillsRegistry, SkillsRegistry accessor, ListSkillsTools. ollie-remote no longer initializes a skills registry. The demarcation: built-ins mutate agent internals (tool schema, context injection). Skills are just file reads — no special treatment needed.
This commit is contained in:
parent
9f8a1130cf
commit
7eb022faba
|
|
@ -29,7 +29,6 @@ import (
|
|||
"sync"
|
||||
"syscall"
|
||||
|
||||
"ollie/skills"
|
||||
"ollie/toolsrv"
|
||||
"ollie/tools/builtin"
|
||||
)
|
||||
|
|
@ -82,7 +81,6 @@ func main() {
|
|||
|
||||
// Build the tool server with builtins and registries.
|
||||
toolReg, _ := toolsrv.NewRegistry()
|
||||
skillsReg := skills.NewRegistry()
|
||||
agentID := fmt.Sprintf("agent-%d", os.Getpid())
|
||||
|
||||
var opts []toolsrv.Option
|
||||
|
|
@ -94,7 +92,6 @@ func main() {
|
|||
if toolReg != nil {
|
||||
opts = append(opts, toolsrv.WithToolRegistry(toolReg, agentID))
|
||||
}
|
||||
opts = append(opts, toolsrv.WithSkillsRegistry(skillsReg))
|
||||
server := toolsrv.New(*cwd)
|
||||
for _, o := range opts {
|
||||
o(server)
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
# Placeholder — real config copied during build (just ollie-remote)
|
||||
|
|
@ -5,13 +5,18 @@ for cmd in mcp-to-command mcp-remote; do
|
|||
command -v "$cmd" >/dev/null 2>&1 || { echo "Error: Missing required command: $cmd" >&2; exit 1; }
|
||||
done
|
||||
|
||||
if [ -z "$OLLIE_LOGSEQ_TOKEN" ]; then
|
||||
echo "Error: OLLIE_LOGSEQ_TOKEN not set" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LOGSEQ_MCP_URL="${LOGSEQ_MCP_URL:-http://127.0.0.1:12315}"
|
||||
|
||||
have_timeout=
|
||||
command -v timeout >/dev/null 2>&1 && have_timeout=1
|
||||
|
||||
if [ -n "$have_timeout" ]; then
|
||||
exec timeout 30 mcp-to-command mcp-remote "$LOGSEQ_MCP_URL/mcp" --transport http-first -- "$@" || {
|
||||
exec timeout 30 mcp-to-command mcp-remote "$LOGSEQ_MCP_URL/mcp" --transport http-first --header "Authorization: Bearer $OLLIE_LOGSEQ_TOKEN" -- "$@" || {
|
||||
if [ $? -eq 124 ]; then
|
||||
echo "Error: timeout exceeded, may want to retry" >&2
|
||||
exit 124
|
||||
|
|
@ -21,4 +26,4 @@ if [ -n "$have_timeout" ]; then
|
|||
}
|
||||
fi
|
||||
|
||||
exec mcp-to-command mcp-remote "$LOGSEQ_MCP_URL/mcp" --transport http-first -- "$@"
|
||||
exec mcp-to-command mcp-remote "$LOGSEQ_MCP_URL/mcp" --transport http-first --header "Authorization: Bearer $OLLIE_LOGSEQ_TOKEN" -- "$@"
|
||||
|
|
|
|||
|
|
@ -12,8 +12,5 @@ func Builtins() map[string]toolsrv.Handler {
|
|||
"tool_list": ToolList,
|
||||
"tool_load": ToolLoad,
|
||||
"tool_active": ToolActive,
|
||||
"skill_list": SkillList,
|
||||
"skill_load": SkillLoad,
|
||||
"skill_active": SkillActive,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"ollie/toolsrv"
|
||||
)
|
||||
|
||||
// SkillList lists all available skills from the global registry.
|
||||
func SkillList(ctx context.Context, srv *toolsrv.Server, args json.RawMessage) (string, error) {
|
||||
reg := srv.SkillsRegistry()
|
||||
if reg == nil {
|
||||
return "", fmt.Errorf("skill_list: no skills registry available")
|
||||
}
|
||||
summaries := reg.Summaries()
|
||||
if len(summaries) == 0 {
|
||||
return "(no skills found)", nil
|
||||
}
|
||||
var out strings.Builder
|
||||
for _, s := range summaries {
|
||||
out.WriteString(s.Name)
|
||||
if s.Description != "" {
|
||||
out.WriteString(" — ")
|
||||
out.WriteString(s.Description)
|
||||
}
|
||||
out.WriteString("\n")
|
||||
}
|
||||
return strings.TrimRight(out.String(), "\n"), nil
|
||||
}
|
||||
|
||||
// SkillLoad loads a skill into the current session.
|
||||
func SkillLoad(ctx context.Context, srv *toolsrv.Server, args json.RawMessage) (string, error) {
|
||||
var a struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
if err := json.Unmarshal(args, &a); err != nil {
|
||||
return "", fmt.Errorf("skill_load: bad args: %w", err)
|
||||
}
|
||||
if a.Name == "" {
|
||||
return "", fmt.Errorf("skill_load: name is required")
|
||||
}
|
||||
reg := srv.SkillsRegistry()
|
||||
sid := srv.SessionID()
|
||||
if reg == nil || sid == "" {
|
||||
return "", fmt.Errorf("skill_load: no session registry")
|
||||
}
|
||||
if err := reg.Load(sid, a.Name); err != nil {
|
||||
return "", fmt.Errorf("skill_load: %w", err)
|
||||
}
|
||||
content, err := reg.SkillContent(a.Name)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("skill_load: %w", err)
|
||||
}
|
||||
injectMsg := fmt.Sprintf("[system: loaded skill %s]\n\n%s", a.Name, content)
|
||||
srv.InjectContent(injectMsg)
|
||||
return fmt.Sprintf("loaded: %s (%d bytes)", a.Name, len(content)), nil
|
||||
}
|
||||
|
||||
// SkillActive lists skills currently loaded in this session.
|
||||
func SkillActive(ctx context.Context, srv *toolsrv.Server, args json.RawMessage) (string, error) {
|
||||
reg := srv.SkillsRegistry()
|
||||
sid := srv.SessionID()
|
||||
if reg == nil || sid == "" {
|
||||
return "(no skills loaded)", nil
|
||||
}
|
||||
loaded := reg.Loaded(sid)
|
||||
if len(loaded) == 0 {
|
||||
return "(no skills loaded)", nil
|
||||
}
|
||||
var out strings.Builder
|
||||
for _, s := range loaded {
|
||||
out.WriteString(s.Name)
|
||||
if s.Description != "" {
|
||||
out.WriteString(" — ")
|
||||
out.WriteString(s.Description)
|
||||
}
|
||||
out.WriteString("\n")
|
||||
}
|
||||
return strings.TrimRight(out.String(), "\n"), nil
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ package toolsrv
|
|||
|
||||
import (
|
||||
"context"
|
||||
"ollie/skills"
|
||||
)
|
||||
|
||||
// --- Exported accessors for builtin tool handlers ---
|
||||
|
|
@ -20,9 +19,6 @@ func (e *Server) ToolRegistry() *Registry { return e.toolRegistry }
|
|||
// SessionID returns the session ID associated with this server.
|
||||
func (e *Server) SessionID() string { return e.sessionID }
|
||||
|
||||
// SkillsRegistry returns the attached skills registry, or nil.
|
||||
func (e *Server) SkillsRegistry() *skills.Registry { return e.skillsRegistry }
|
||||
|
||||
// InjectContent calls the OnInjection hook if set.
|
||||
func (e *Server) InjectContent(content string) {
|
||||
if e.OnInjection != nil {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
|
||||
"ollie/detach"
|
||||
"ollie/paths"
|
||||
"ollie/skills"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -62,7 +61,6 @@ type Server struct {
|
|||
builtins map[string]Handler
|
||||
|
||||
toolRegistry *Registry
|
||||
skillsRegistry *skills.Registry
|
||||
sessionID string
|
||||
|
||||
// OnInjection is called when a skill is loaded and its content
|
||||
|
|
@ -145,11 +143,6 @@ func WithToolRegistry(r *Registry, sessionID string) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// WithSkillsRegistry attaches a skills registry to the Server.
|
||||
func WithSkillsRegistry(r *skills.Registry) Option {
|
||||
return func(s *Server) { s.skillsRegistry = r }
|
||||
}
|
||||
|
||||
|
||||
// ListTools implements Server, returning shell plus any
|
||||
// tools promoted in the session's tool registry.
|
||||
|
|
@ -228,9 +221,6 @@ Returns tools with descriptions, one per line.`,
|
|||
if e.toolRegistry != nil && e.sessionID != "" {
|
||||
all = append(all, e.toolRegistry.Loaded(e.sessionID)...)
|
||||
}
|
||||
// Append skill tools if skills registry is available
|
||||
skillTools := ListSkillsTools(e.skillsRegistry, e.sessionID)
|
||||
all = append(all, skillTools...)
|
||||
return all, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
package toolsrv
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"ollie/skills"
|
||||
)
|
||||
|
||||
// SetSkillsRegistry attaches a skills registry to the execute server.
|
||||
// The server uses it to serve skill_list, skill_load, and skill_active.
|
||||
func (e *Server) SetSkillsRegistry(r *skills.Registry) {
|
||||
e.skillsRegistry = r
|
||||
}
|
||||
|
||||
// ListSkillsTools returns ToolInfo entries for the skill_* built-ins.
|
||||
// These are included alongside the standard tool_* tools.
|
||||
func ListSkillsTools(skillsReg *skills.Registry, sessionID string) []ToolInfo {
|
||||
if skillsReg == nil {
|
||||
return nil
|
||||
}
|
||||
tools := []ToolInfo{
|
||||
{
|
||||
Name: "skill_list",
|
||||
Description: `List available skill modules with name and description.
|
||||
|
||||
Usage: {"name": "skillname"} — if name is provided, loads that skill.
|
||||
Otherwise lists all skills with descriptions.`,
|
||||
InputSchema: json.RawMessage(`{
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}`),
|
||||
},
|
||||
{
|
||||
Name: "skill_load",
|
||||
Description: `Load a skill module into the current session's context.
|
||||
|
||||
Usage: {"name": "skillname"}
|
||||
|
||||
The skill content (SKILL.md body) is injected into the agent's context
|
||||
and persists across turns.`,
|
||||
InputSchema: json.RawMessage(`{
|
||||
"type": "object",
|
||||
"required": ["name"],
|
||||
"properties": {
|
||||
"name": {"type": "string", "description": "Skill name to load."}
|
||||
}
|
||||
}`),
|
||||
},
|
||||
{
|
||||
Name: "skill_active",
|
||||
Description: `List skills currently loaded in this session.
|
||||
|
||||
Usage: (no arguments)
|
||||
|
||||
Returns loaded skill names, one per line.`,
|
||||
InputSchema: json.RawMessage(`{
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}`),
|
||||
},
|
||||
}
|
||||
return tools
|
||||
}
|
||||
|
||||
// dispatchSkillList lists all available skills from the global registry.
|
||||
Loading…
Reference in New Issue