Files
zero/internal/cli/exec_usage_cache_test.go
T
KRATOS 9f0ceba48c feat(cli): wire model discovery, proving and child scope to the live run
The hooks specialist declares, supplied from the two surfaces that own a
provider and a sandbox.

DISCOVERY FOLLOWS THE LIVE PROVIDER. It was bound once at startup, so a session
that switched provider with /model kept probing the one it began on: a run on
xai/grok-4.5 had its plan assigned from a nineteen-model Ollama list and the
provider refused every task. It now re-resolves through the same path a freshly
spawned child takes, config plus ZERO_PROVIDER, so discovery and child execution
read one source of truth rather than two kept in sync. The captured profile
still wins when the provider is unchanged, because --provider, --base-url and an
inline --api-key are applied on top of Resolve and re-resolving would discard
them.

A CHILD STANDS ON THE SAME GROUND AS ITS PARENT. A run granted a directory
outside its workspace could create it, populate it, and then watch every plan
task be refused at that same directory — a child rebuilds its sandbox from --cwd
alone and the grant lived only in the parent's engine. The run's roots now reach
the child as --add-dir, read at launch so a mid-session approval lands, and on
the resume path too: this file has already seen the resume path forget what the
fresh path carried.

PROVING, wired to the provider stack and exposed as `providers models --verify`
— which model this provider will actually run, as opposed to which it lists.
That is the difference the exclude list was being maintained by hand to express.

Origin-Session: local-de382f | Claude Code | 3 prompts
Origin-Snapshot: c28c274718fa
2026-08-16 09:22:42 +05:30

89 lines
3.0 KiB
Go

package cli
import (
"bytes"
"encoding/json"
"strings"
"testing"
"github.com/Gitlawb/zero/internal/agent"
)
// THE CHILD MUST PUBLISH WHAT MAKES ITS TURN PRICEABLE.
//
// This writer is the only channel a parent has. Its session record already keeps
// cachedInputTokens / cacheWriteTokens / reasoningTokens so a turn can be costed
// exactly; the stream carried prompt/completion/total alone, so every sub-agent
// turn rolled up to its parent was priced as if nothing had been cached.
//
// A measured plan task had 49,280 of 49,894 prompt tokens served from cache —
// 98.8%. Plan tasks are the ideal cache case: one large stable prompt, re-sent
// every turn.
func TestTheChildPublishesCacheAndReasoningTokensOnTheUsageStream(t *testing.T) {
var stdout, stderr bytes.Buffer
writer := execEventWriter{
stdout: &stdout,
stderr: &stderr,
format: execOutputStreamJSON,
runID: "run_usage",
streamedText: &strings.Builder{},
}
writer.usage(agent.Usage{
PromptTokens: 30000,
CompletionTokens: 500,
CachedInputTokens: 29000,
CacheWriteTokens: 1000,
ReasoningTokens: 120,
})
if writer.err != nil {
t.Fatalf("usage: %v", writer.err)
}
var payload map[string]any
if err := json.Unmarshal([]byte(strings.TrimSpace(stdout.String())), &payload); err != nil {
t.Fatalf("decode stream event %q: %v", stdout.String(), err)
}
for key, want := range map[string]float64{
"cachedInputTokens": 29000, "cacheWriteTokens": 1000, "reasoningTokens": 120,
} {
got, ok := payload[key]
if !ok {
t.Errorf("the stream omits %q, so a parent prices this turn as uncached: %v", key, payload)
continue
}
if number, ok := got.(float64); !ok || number != want {
t.Errorf("%s: want %v, got %v", key, want, got)
}
}
// The three original fields must be exactly as before.
for key, want := range map[string]float64{
"promptTokens": 30000, "completionTokens": 500, "totalTokens": 30500,
} {
if got, ok := payload[key].(float64); !ok || got != want {
t.Errorf("%s changed: want %v, got %v", key, want, payload[key])
}
}
}
// NON-ZERO ONLY, exactly like usage.EventUsagePayload. A provider reporting no
// cache must produce the same three-field event it always did, or every existing
// reader of this stream sees a shape it has never seen.
func TestAProviderWithNoCacheStillEmitsTheOriginalUsageShape(t *testing.T) {
var stdout, stderr bytes.Buffer
writer := execEventWriter{
stdout: &stdout, stderr: &stderr, format: execOutputStreamJSON,
runID: "run_usage", streamedText: &strings.Builder{},
}
writer.usage(agent.Usage{PromptTokens: 100, CompletionTokens: 10})
var payload map[string]any
if err := json.Unmarshal([]byte(strings.TrimSpace(stdout.String())), &payload); err != nil {
t.Fatalf("decode: %v", err)
}
for _, key := range []string{"cachedInputTokens", "cacheWriteTokens", "reasoningTokens"} {
if _, present := payload[key]; present {
t.Errorf("%q was emitted as a zero, widening the event for every provider that reports no cache", key)
}
}
}