Files
executus/tool/exec_helpers_test.go
T
steve dc28b63ad8
executus CI / test (push) Successful in 36s
P1 (part 1): move skilltools core -> tool/ (clean, verbatim)
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>
2026-06-26 19:31:47 -04:00

68 lines
2.0 KiB
Go

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
}
}