tools: two-tier discovery (surface listing + on-demand prompt)

BuildRuntime now appends a compact surface listing (name + one-liner)
to the preamble instead of full tool prompts. Full prompts are
available on-demand via ToolPrompt(name) for the /net/dns pattern.

- DiscoverTools: extracts short description from first content line
- BuildRuntime: appends "# Available Tools" with name + description
- ToolPrompt(name): returns full ollie:prompt for a specific tool
This commit is contained in:
ollie 2026-07-21 13:36:16 +02:00
parent 41eedb0c27
commit 3c2bf3eb40
2 changed files with 41 additions and 12 deletions

View File

@ -163,16 +163,17 @@ func BuildRuntime(cfg *config.Config, d tools.Dispatcher, cwd string, env []stri
}
}
// Append tool prompts discovered from script headers.
var toolPrompts strings.Builder
// Append compact tool surface listing (name + description).
// Full prompts are available on-demand via /tools write (net/dns pattern).
var toolListing strings.Builder
for _, ti := range allToolInfos {
if ti.Prompt != "" {
toolPrompts.WriteString(ti.Prompt)
toolPrompts.WriteByte('\n')
if ti.Description != "" && ti.Server == "" {
// Only named tool scripts (Server==""), not built-in executors
fmt.Fprintf(&toolListing, "- **%s** — %s\n", ti.Name, ti.Description)
}
}
if toolPrompts.Len() > 0 {
preamble += "\n" + toolPrompts.String()
if toolListing.Len() > 0 {
preamble += "\n# Available Tools\n\n" + toolListing.String()
}
return &Runtime{

View File

@ -210,8 +210,7 @@ func ExtractPrompt(script string) string {
}
// DiscoverTools scans the tools directory and returns metadata for all scripts,
// including their ollie:prompt blocks. Used to populate the /tools file and
// inject tool prompts into the system prompt.
// including their ollie:prompt blocks and short descriptions.
func DiscoverTools() []tools.ToolInfo {
dir := ToolsPath()
entries, err := os.ReadDir(dir)
@ -227,15 +226,44 @@ func DiscoverTools() []tools.ToolInfo {
if err != nil {
continue
}
prompt := ExtractPrompt(string(data))
script := string(data)
prompt := ExtractPrompt(script)
desc := extractShortDescription(prompt)
infos = append(infos, tools.ToolInfo{
Name: e.Name(),
Prompt: prompt,
Name: e.Name(),
Description: desc,
Prompt: prompt,
})
}
return infos
}
// extractShortDescription gets the first non-heading, non-empty line from a prompt.
func extractShortDescription(prompt string) string {
for _, line := range strings.Split(prompt, "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
return line
}
return ""
}
// ToolPrompt returns the full ollie:prompt content for a named tool.
// Returns "" if the tool has no prompt or doesn't exist.
func ToolPrompt(name string) string {
if strings.Contains(name, "/") || strings.Contains(name, "..") {
return ""
}
path := filepath.Join(ToolsPath(), name)
data, err := os.ReadFile(path)
if err != nil {
return ""
}
return ExtractPrompt(string(data))
}
// ReadTool reads a named tool script from the tools directory.
func ReadTool(name string) (string, error) {
if strings.Contains(name, "/") || strings.Contains(name, "..") {