diff --git a/internal/server/work_checkpoint_eval_budget_test.go b/internal/server/work_checkpoint_eval_budget_test.go index 5bc35f9..393f60d 100644 --- a/internal/server/work_checkpoint_eval_budget_test.go +++ b/internal/server/work_checkpoint_eval_budget_test.go @@ -249,29 +249,32 @@ func TestEvaluationStopsAfterMalformedToolTerminal(t *testing.T) { func TestEvaluationTransportObservationSanitized(t *testing.T) { const maxTail, maxBytes = 10000, int64(32*1024*1024 + 1) + const maxFragments, maxArgumentBytes = 10000, 4*1024*1024 + 1 for _, tc := range []struct { - name string - input agentllm.TerminalObservation - wantTail int - wantBytes int64 - wantKind string - wantFields [3]string + name string + input agentllm.TerminalObservation + wantTail int + wantBytes int64 + wantFragments int + wantArgBytes int + wantKind string + wantFields [3]string }{ {"negative-tail-oversized-body", agentllm.TerminalObservation{ReadOutcome: "done_marker", - TailEventKind: "PRIVATE_TAIL_R06", TailEventCount: -5, + TailEventKind: "PRIVATE_TAIL_R06", TailEventCount: -5, ToolFragments: -3, ToolArgumentBytes: 1 << 30, BodyBoundary: &agentllm.BodyBoundaryObservation{ProtocolClass: "PRIVATE_HEADER_R06", FramingClass: "PRIVATE_FRAMING_R06", LengthRelation: "PRIVATE_LENGTH_R06", BytesRead: 1 << 40, DeclaredLengthKnown: true, BytesSaturated: true, EOFSeen: true, Uncompressed: true}}, - 0, maxBytes, "unknown", [3]string{"other", "unknown", "unknown"}}, + 0, maxBytes, 0, maxArgumentBytes, "unknown", [3]string{"other", "unknown", "unknown"}}, {"oversized-tail-negative-body", agentllm.TerminalObservation{ReadOutcome: "done_marker", - TailEventKind: "PRIVATE_TAIL_R06", TailEventCount: 1 << 20, + TailEventKind: "PRIVATE_TAIL_R06", TailEventCount: 1 << 20, ToolFragments: 1 << 20, ToolArgumentBytes: -9, BodyBoundary: &agentllm.BodyBoundaryObservation{ProtocolClass: "PRIVATE_HEADER_R06", FramingClass: "PRIVATE_FRAMING_R06", LengthRelation: "PRIVATE_LENGTH_R06", BytesRead: -7, DeclaredLengthKnown: true, BytesSaturated: true, EOFSeen: true, Uncompressed: true}}, - maxTail, 0, "unknown", [3]string{"other", "unknown", "unknown"}}, + maxTail, 0, maxFragments, 0, "unknown", [3]string{"other", "unknown", "unknown"}}, {"known-values-kept", agentllm.TerminalObservation{ReadOutcome: "done_marker", - TailEventKind: "comment", TailEventCount: 3, + TailEventKind: "comment", TailEventCount: 3, ToolFragments: 2, ToolArgumentBytes: 64, BodyBoundary: &agentllm.BodyBoundaryObservation{ProtocolClass: "http2", FramingClass: "chunked", LengthRelation: "match", BytesRead: 128, DeclaredLengthKnown: true, BytesSaturated: true, EOFSeen: true, Uncompressed: true}}, - 3, 128, "comment", [3]string{"http2", "chunked", "match"}}, + 3, 128, 2, 64, "comment", [3]string{"http2", "chunked", "match"}}, } { t.Run(tc.name, func(t *testing.T) { input := tc.input @@ -283,6 +286,7 @@ func TestEvaluationTransportObservationSanitized(t *testing.T) { } body := clean.BodyBoundary if clean.ReadOutcome != "done_marker" || clean.TailEventKind != tc.wantKind || clean.TailEventCount != tc.wantTail || + clean.ToolFragments != tc.wantFragments || clean.ToolArgumentBytes != tc.wantArgBytes || body.ProtocolClass != tc.wantFields[0] || body.FramingClass != tc.wantFields[1] || body.LengthRelation != tc.wantFields[2] || body.BytesRead != tc.wantBytes || !body.DeclaredLengthKnown || !body.BytesSaturated || !body.EOFSeen || !body.Uncompressed { t.Fatalf("unbounded observation: %+v body=%+v", clean, body) @@ -331,7 +335,8 @@ func TestEvaluationTransportObservationSanitized(t *testing.T) { t.Fatalf("sanitized record lost accounting: %s err=%v", raw, err) } got := record.Calls[0].Observation - if got.TailEventKind != tc.wantKind || got.TailEventCount != tc.wantTail || got.BodyBoundary.ProtocolClass != tc.wantFields[0] || + if got.TailEventKind != tc.wantKind || got.TailEventCount != tc.wantTail || got.ToolFragments != tc.wantFragments || + got.ToolArgumentBytes != tc.wantArgBytes || got.BodyBoundary.ProtocolClass != tc.wantFields[0] || got.BodyBoundary.FramingClass != tc.wantFields[1] || got.BodyBoundary.LengthRelation != tc.wantFields[2] || got.BodyBoundary.BytesRead != tc.wantBytes { t.Fatalf("unbounded persisted observation: %s", raw) diff --git a/internal/server/work_checkpoint_eval_test.go b/internal/server/work_checkpoint_eval_test.go index 71bd1c6..6c2b227 100644 --- a/internal/server/work_checkpoint_eval_test.go +++ b/internal/server/work_checkpoint_eval_test.go @@ -464,8 +464,10 @@ func evalFinishReasonClass(reason string) string { // Limits mirror Agent-Native's saturating observation counters. const ( - evalMaxTailEvents = 10000 - evalMaxBodyBytes = 32*1024*1024 + 1 + evalMaxTailEvents = 10000 + evalMaxBodyBytes = 32*1024*1024 + 1 + evalMaxToolFragments = 10000 + evalMaxToolArgumentBytes = 4*1024*1024 + 1 ) func evalLabel(value, fallback string, allowed ...string) string { @@ -496,8 +498,8 @@ func evalTerminalObservation(observation *agentllm.TerminalObservation) *agentll "done_marker", "clean_eof", "read_error", "cancelled", "invalid_frame", "provider_error", "transport_error"), LastFrameJSONComplete: observation.LastFrameJSONComplete, UsagePresent: observation.UsagePresent, - ToolFragments: observation.ToolFragments, - ToolArgumentBytes: observation.ToolArgumentBytes, + ToolFragments: int(clampCount(int64(observation.ToolFragments), evalMaxToolFragments)), + ToolArgumentBytes: int(clampCount(int64(observation.ToolArgumentBytes), evalMaxToolArgumentBytes)), ToolArgumentsValid: observation.ToolArgumentsValid, TailEventKind: evalLabel(observation.TailEventKind, "unknown", "done_literal", "json_frame", "comment", "empty_data", "partial_frame", "unknown_non_json", "unknown"),