Files
zero/internal/cli/exec_writer_test.go
PierrunoYTandClaude Opus 5.5 13e2596b2e chore: move repository references to Twigpine/zero (#1105)
Update the Go module path, imports, install scripts, docs, workflows,
packaging and action defaults from Gitlawb/zero to Twigpine/zero. The npm
scope (already @twigpine/zero on main, with its @gitlawb/zero migration
notes), LICENSE, action author, the OpenGateway provider and historical
CHANGELOG links are unchanged.

The X-AIMLAPI-Integration-Repo header keeps Gitlawb/zero: it is what
AIMLAPI sees for attribution, so changing it needs a maintainer's yes.
docs/INSTALL.md keeps `go install github.com/Gitlawb/zero/...`, because
every tagged release so far declares that module path. The Homebrew
formula comment names the Twigpine/homebrew-tap tap.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-17 07:13:21 +08:00

91 lines
2.7 KiB
Go

package cli
import (
"bytes"
"encoding/json"
"strings"
"testing"
"github.com/Twigpine/zero/internal/agent"
"github.com/Twigpine/zero/internal/tools"
)
// escalate_model is a control-only tool (SideEffectNone). The stream-json tool
// call must report sideEffect "none", not "unknown", so automation sees the
// promised value.
func TestStreamJSONSideEffectReportsNoneForControlTool(t *testing.T) {
registry := tools.NewRegistry()
registry.Register(tools.NewEscalateModelTool())
if got := streamJSONSideEffect("escalate_model", registry); got != "none" {
t.Fatalf("streamJSONSideEffect(escalate_model) = %q, want none", got)
}
}
func TestExecWriterPropagatesToolResultTruncation(t *testing.T) {
for _, format := range []execOutputFormat{execOutputJSON, execOutputStreamJSON} {
t.Run(string(format), func(t *testing.T) {
var stdout, stderr bytes.Buffer
writer := execEventWriter{
stdout: &stdout,
stderr: &stderr,
format: format,
runID: "run_budget",
streamedText: &strings.Builder{},
}
writer.toolResult(agent.ToolResult{
ToolCallID: "call_budget",
Name: "read_file",
Status: tools.StatusOK,
Output: "bounded output",
Truncated: true,
})
if writer.err != nil {
t.Fatalf("toolResult: %v", writer.err)
}
var payload map[string]any
if err := json.Unmarshal(bytes.TrimSpace(stdout.Bytes()), &payload); err != nil {
t.Fatalf("decode output %q: %v", stdout.String(), err)
}
if payload["truncated"] != true {
t.Fatalf("truncated = %#v, want true; payload=%#v", payload["truncated"], payload)
}
})
}
}
func TestExecWriterPropagatesCacheUsage(t *testing.T) {
for _, format := range []execOutputFormat{execOutputJSON, execOutputStreamJSON} {
t.Run(string(format), func(t *testing.T) {
var stdout bytes.Buffer
writer := execEventWriter{
stdout: &stdout,
format: format,
runID: "run_usage",
streamedText: &strings.Builder{},
}
writer.usage(agent.Usage{
InputTokens: 100,
OutputTokens: 20,
PromptTokens: 100,
CompletionTokens: 20,
CachedInputTokens: 60,
CacheWriteTokens: 10,
})
if writer.err != nil {
t.Fatalf("usage: %v", writer.err)
}
var payload map[string]any
if err := json.Unmarshal(bytes.TrimSpace(stdout.Bytes()), &payload); err != nil {
t.Fatalf("decode output %q: %v", stdout.String(), err)
}
cachedKey, writeKey := "cached_input_tokens", "cache_write_tokens"
if format == execOutputStreamJSON {
cachedKey, writeKey = "cachedInputTokens", "cacheWriteTokens"
}
if payload[cachedKey] != float64(60) || payload[writeKey] != float64(10) {
t.Fatalf("cache usage missing from payload: %#v", payload)
}
})
}
}