Why: Headless runs need the pi tool names, walked context files, prompt includes, and a trust gate before project settings are loaded. Evidence: go test -count=1 ./runtime/tools/ ./runtime/resources/ ./runtime/skills/ Impact: Existing tool names stay registered. Aliases are added only when the underlying tool exists. Refs: feature/pi-headless N4 Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
2.0 KiB
Go
84 lines
2.0 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
)
|
|
|
|
// aliasTool exposes an existing tool under a pi-style name.
|
|
type aliasTool struct {
|
|
name string
|
|
inner Tool
|
|
}
|
|
|
|
func (a aliasTool) Name() string { return a.name }
|
|
func (a aliasTool) Description() string { return a.inner.Description() }
|
|
func (a aliasTool) Parameters() json.RawMessage { return a.inner.Parameters() }
|
|
func (a aliasTool) Execute(ctx context.Context, args json.RawMessage) (Result, error) {
|
|
return a.inner.Execute(ctx, args)
|
|
}
|
|
|
|
// piAliases maps the headless pi tool name onto the name already registered.
|
|
var piAliases = map[string]string{
|
|
"read": "read_file",
|
|
"write": "write_file",
|
|
"edit": "edit_file",
|
|
"bash": "run_command",
|
|
"grep": "grep",
|
|
"find": "glob",
|
|
"ls": "list_dir",
|
|
}
|
|
|
|
// RegisterPiAliases adds pi tool names beside the existing ones.
|
|
// A name is skipped when the underlying tool is not registered.
|
|
func (r *Registry) RegisterPiAliases() {
|
|
for alias, inner := range piAliases {
|
|
if alias == inner || r.Has(alias) || !r.Has(inner) {
|
|
continue
|
|
}
|
|
r.Register(aliasTool{name: alias, inner: r.tools[inner]})
|
|
}
|
|
}
|
|
|
|
// FilterOptions selects which tools stay visible.
|
|
type FilterOptions struct {
|
|
Tools []string
|
|
Exclude []string
|
|
NoBuiltin bool
|
|
}
|
|
|
|
// Filter applies an allow list, then exclusions. NoBuiltin drops the
|
|
// workspace tool names and their pi aliases.
|
|
func (r *Registry) Filter(opts FilterOptions) error {
|
|
if len(opts.Tools) > 0 {
|
|
if err := r.Restrict(opts.Tools); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
drop := map[string]bool{}
|
|
for _, name := range opts.Exclude {
|
|
drop[name] = true
|
|
}
|
|
if opts.NoBuiltin {
|
|
for _, name := range []string{"read_file", "write_file", "edit_file", "multi_edit", "list_dir", "grep", "glob", "run_command", "run_python"} {
|
|
drop[name] = true
|
|
}
|
|
for alias := range piAliases {
|
|
drop[alias] = true
|
|
}
|
|
}
|
|
if len(drop) == 0 {
|
|
return nil
|
|
}
|
|
var order []string
|
|
for _, name := range r.order {
|
|
if drop[name] {
|
|
delete(r.tools, name)
|
|
continue
|
|
}
|
|
order = append(order, name)
|
|
}
|
|
r.order = order
|
|
return nil
|
|
}
|