mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
33e18e7e64
* feat(skills): add effective skill resolution and actions * refactor(workspace): normalize skill-related env and prompt * chore(api): regenerate skills OpenAPI and SDK artifacts * feat(web): surface effective skill state in console * test(skills): cover API and runtime effective state * fix(web): show adopt action for discovered skills * fix(web): align skill header and show stateful visibility icon * refactor(web): compact skill metadata on narrow layouts * fix(web): constrain long skill text in cards * refactor(skills): narrow default discovery roots * fix(skills): harden managed skill path validation * feat: add path in the results of `use_skill` --------- Co-authored-by: Acbox <acbox0328@gmail.com>
70 lines
1.8 KiB
Go
70 lines
1.8 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
|
|
sdk "github.com/memohai/twilight-ai/sdk"
|
|
)
|
|
|
|
type SkillProvider struct {
|
|
logger *slog.Logger
|
|
}
|
|
|
|
func NewSkillProvider(log *slog.Logger) *SkillProvider {
|
|
if log == nil {
|
|
log = slog.Default()
|
|
}
|
|
return &SkillProvider{logger: log.With(slog.String("tool", "skill"))}
|
|
}
|
|
|
|
func (*SkillProvider) Tools(_ context.Context, session SessionContext) ([]sdk.Tool, error) {
|
|
if session.IsSubagent || len(session.Skills) == 0 {
|
|
return nil, nil
|
|
}
|
|
skills := session.Skills
|
|
return []sdk.Tool{
|
|
{
|
|
Name: "use_skill",
|
|
Description: "Activate a skill to get its full instructions. Call this when you think a skill is relevant to the current task.",
|
|
Parameters: map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"skillName": map[string]any{
|
|
"type": "string",
|
|
"description": "The name of the skill to activate",
|
|
},
|
|
"reason": map[string]any{
|
|
"type": "string",
|
|
"description": "Why this skill is relevant to the current task",
|
|
},
|
|
},
|
|
"required": []string{"skillName", "reason"},
|
|
},
|
|
Execute: func(_ *sdk.ToolExecContext, input any) (any, error) {
|
|
args := inputAsMap(input)
|
|
skillName := StringArg(args, "skillName")
|
|
if skillName == "" {
|
|
return nil, errors.New("skillName is required")
|
|
}
|
|
skill, ok := skills[skillName]
|
|
if !ok {
|
|
return map[string]any{
|
|
"success": false,
|
|
"error": fmt.Sprintf("skill %q not found — check available skills in the system prompt", skillName),
|
|
}, nil
|
|
}
|
|
return map[string]any{
|
|
"success": true,
|
|
"skillName": skillName,
|
|
"description": skill.Description,
|
|
"content": skill.Content,
|
|
"path": skill.Path,
|
|
}, nil
|
|
},
|
|
},
|
|
}, nil
|
|
}
|