Address #130 review: one toolCaller helper for the tool tests
Build image / build-and-push (push) Successful in 7s
Build image / build-and-push (push) Successful in 7s
The call/mustCall closures were copied between TestRecordKeepingTools and TestCatalogAndGardenTools; both now use a file-level toolCaller. The other notes are left as they are: the 'nothing to change' guard enumerates the args on purpose (it is the tool's own contract, next to the struct it checks), and wrapping a sentinel with %w is how every readable refusal in this package is built. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
@@ -123,6 +123,34 @@ func TestToolboxScenario(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// toolCaller returns the two ways a test drives a toolbox: call executes a
|
||||||
|
// tool with JSON-encoded args and hands back the raw result (for asserting on
|
||||||
|
// refusals), and mustCall fails the test on a tool error and decodes the
|
||||||
|
// result into `into` when one is given.
|
||||||
|
func toolCaller(t *testing.T, ctx context.Context, box *llm.Toolbox) (
|
||||||
|
call func(name string, args any) llm.ToolResult,
|
||||||
|
mustCall func(name string, args any, into any),
|
||||||
|
) {
|
||||||
|
t.Helper()
|
||||||
|
call = func(name string, args any) llm.ToolResult {
|
||||||
|
t.Helper()
|
||||||
|
return box.Execute(ctx, llm.ToolCall{ID: "1", Name: name, Arguments: mustJSON(t, args)})
|
||||||
|
}
|
||||||
|
mustCall = func(name string, args any, into any) {
|
||||||
|
t.Helper()
|
||||||
|
res := call(name, args)
|
||||||
|
if res.IsError {
|
||||||
|
t.Fatalf("%s: %s", name, res.Content)
|
||||||
|
}
|
||||||
|
if into != nil {
|
||||||
|
if err := json.Unmarshal([]byte(res.Content), into); err != nil {
|
||||||
|
t.Fatalf("decode %s: %v (%s)", name, err, res.Content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return call, mustCall
|
||||||
|
}
|
||||||
|
|
||||||
func mustJSON(t *testing.T, v any) json.RawMessage {
|
func mustJSON(t *testing.T, v any) json.RawMessage {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
b, err := json.Marshal(v)
|
b, err := json.Marshal(v)
|
||||||
@@ -750,22 +778,7 @@ func TestRecordKeepingTools(t *testing.T) {
|
|||||||
svc, owner := newAgentTestService(t)
|
svc, owner := newAgentTestService(t)
|
||||||
box := NewToolbox(svc, owner, "2026-08-23")
|
box := NewToolbox(svc, owner, "2026-08-23")
|
||||||
|
|
||||||
call := func(name string, args any) llm.ToolResult {
|
call, mustCall := toolCaller(t, ctx, box)
|
||||||
t.Helper()
|
|
||||||
return box.Execute(ctx, llm.ToolCall{ID: "1", Name: name, Arguments: mustJSON(t, args)})
|
|
||||||
}
|
|
||||||
mustCall := func(name string, args any, into any) {
|
|
||||||
t.Helper()
|
|
||||||
res := call(name, args)
|
|
||||||
if res.IsError {
|
|
||||||
t.Fatalf("%s: %s", name, res.Content)
|
|
||||||
}
|
|
||||||
if into != nil {
|
|
||||||
if err := json.Unmarshal([]byte(res.Content), into); err != nil {
|
|
||||||
t.Fatalf("decode %s: %v (%s)", name, err, res.Content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g, err := svc.CreateGarden(ctx, owner, service.GardenInput{Name: "Home", WidthCM: 1200, HeightCM: 800, Notes: "Zone 6a."})
|
g, err := svc.CreateGarden(ctx, owner, service.GardenInput{Name: "Home", WidthCM: 1200, HeightCM: 800, Notes: "Zone 6a."})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -940,22 +953,7 @@ func TestCatalogAndGardenTools(t *testing.T) {
|
|||||||
svc, owner := newAgentTestService(t)
|
svc, owner := newAgentTestService(t)
|
||||||
box := NewToolbox(svc, owner, "2026-08-23")
|
box := NewToolbox(svc, owner, "2026-08-23")
|
||||||
|
|
||||||
call := func(name string, args any) llm.ToolResult {
|
call, mustCall := toolCaller(t, ctx, box)
|
||||||
t.Helper()
|
|
||||||
return box.Execute(ctx, llm.ToolCall{ID: "1", Name: name, Arguments: mustJSON(t, args)})
|
|
||||||
}
|
|
||||||
mustCall := func(name string, args any, into any) {
|
|
||||||
t.Helper()
|
|
||||||
res := call(name, args)
|
|
||||||
if res.IsError {
|
|
||||||
t.Fatalf("%s: %s", name, res.Content)
|
|
||||||
}
|
|
||||||
if into != nil {
|
|
||||||
if err := json.Unmarshal([]byte(res.Content), into); err != nil {
|
|
||||||
t.Fatalf("decode %s: %v (%s)", name, err, res.Content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- create_garden: defaults, then an imperial one with notes.
|
// --- create_garden: defaults, then an imperial one with notes.
|
||||||
var g domain.Garden
|
var g domain.Garden
|
||||||
|
|||||||
Reference in New Issue
Block a user