P1 (part 1): move skilltools core -> tool/ (clean, verbatim)
executus CI / test (push) Successful in 36s
executus CI / test (push) Successful in 36s
The tool registry core (registry, permission model, Invocation, gated-tool wrapper, ssrf guard, hmac, encryption, argcoerce, helpers, rootrun, session_tools, webhook_rate_limit) had zero mort coupling — it imports only majordomo/llm + x/crypto/hkdf — so it moves verbatim with a package rename (skilltools -> tool). All same-package tests came along and pass; the SSRF, gated-wrapper, encryption and output-pattern invariants are re-anchored here. majordomo re-enters the module graph (now pinned to the latest, incl. the front-loaded-output fix). model/ + llmmeta + structured follow next. Docs: CLAUDE.md now requires README/examples to stay in sync with changes in the same commit; CI skips docs/example-only pushes via paths-ignore. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
package tool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
llm "gitea.stevedudenhoeffer.com/steve/majordomo/llm"
|
||||
)
|
||||
|
||||
// toolCall mirrors the legacy gollm-era test shape (string arguments) so the
|
||||
// pre-conversion test call sites keep their literal syntax. majordomo's
|
||||
// llm.ToolCall carries json.RawMessage arguments; execBox adapts.
|
||||
type toolCall struct {
|
||||
Name string
|
||||
Arguments string
|
||||
}
|
||||
|
||||
// execBox executes one call through a toolbox and adapts majordomo's
|
||||
// ToolResult to the (result, error) pair these tests assert against:
|
||||
// IsError results come back as a Go error carrying the result content
|
||||
// (which is how the agent-facing error text read in the legacy gollm era).
|
||||
func execBox(box *llm.Toolbox, call toolCall) (string, error) {
|
||||
res := box.Execute(context.Background(), llm.ToolCall{
|
||||
ID: "test-call",
|
||||
Name: call.Name,
|
||||
Arguments: json.RawMessage(call.Arguments),
|
||||
})
|
||||
if res.IsError {
|
||||
return "", errors.New(res.Content)
|
||||
}
|
||||
return res.Content, nil
|
||||
}
|
||||
|
||||
// execTool runs a single built llm.Tool's handler and serializes the
|
||||
// result the way llm.ExecuteTool does. Replaces the legacy gollm
|
||||
// Tool.Execute(ctx, argsJSON) method the original tests called.
|
||||
//
|
||||
// Why the handler directly (vs llm.ExecuteTool): ExecuteTool flattens
|
||||
// handler errors into IsError result text, but several tests assert
|
||||
// error IDENTITY (errors.Is against sentinel errors the handlers
|
||||
// wrap). Calling the handler preserves the error value, matching the
|
||||
// legacy gollm Execute contract these tests were written against.
|
||||
func execTool(ctx context.Context, t llm.Tool, args string) (string, error) {
|
||||
raw := json.RawMessage(args)
|
||||
if len(raw) == 0 {
|
||||
raw = json.RawMessage("{}")
|
||||
}
|
||||
out, err := t.Handler(ctx, raw)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch v := out.(type) {
|
||||
case nil:
|
||||
return "null", nil
|
||||
case string:
|
||||
return v, nil
|
||||
case json.RawMessage:
|
||||
return string(v), nil
|
||||
default:
|
||||
enc, mErr := json.Marshal(v)
|
||||
if mErr != nil {
|
||||
return "", mErr
|
||||
}
|
||||
return string(enc), nil
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user