chore: initial commit
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAnthropicThinkingOutput(t *testing.T) {
|
||||
for _, tool := range []bool{false, true} {
|
||||
visible := `{"type":"text","text":"OK"}`
|
||||
initial := `{"type":"text","text":""}`
|
||||
delta := `{"type":"text_delta","text":"OK"}`
|
||||
finish := "end_turn"
|
||||
if tool {
|
||||
visible = `{"type":"tool_use","id":"call_1","name":"weather","input":{}}`
|
||||
initial = visible
|
||||
delta = `{"type":"input_json_delta","partial_json":"{}"}`
|
||||
finish = "tool_use"
|
||||
}
|
||||
hidden := `{"type":"thinking","thinking":"PRIVATE","signature":"SIGNATURE"}`
|
||||
redacted := `{"type":"redacted_thinking","data":"CIPHER"}`
|
||||
body := `{"id":"m","type":"message","role":"assistant","model":"m","content":[` + hidden + "," + redacted + "," + visible + `],"stop_reason":"` + finish + `","usage":{"input_tokens":9,"output_tokens":7}}`
|
||||
events := []string{
|
||||
`{"type":"message_start","message":{"id":"m","content":[],"usage":{"input_tokens":9,"output_tokens":0}}}`,
|
||||
`{"type":"content_block_start","index":0,"content_block":{"type":"thinking","thinking":"","signature":""}}`,
|
||||
`{"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"PRIVATE"}}`,
|
||||
`{"type":"content_block_delta","index":0,"delta":{"type":"signature_delta","signature":"SIGNATURE"}}`,
|
||||
`{"type":"content_block_stop","index":0}`,
|
||||
`{"type":"content_block_start","index":1,"content_block":` + redacted + "}",
|
||||
`{"type":"content_block_stop","index":1}`,
|
||||
`{"type":"content_block_start","index":2,"content_block":` + initial + "}",
|
||||
`{"type":"content_block_delta","index":2,"delta":` + delta + "}",
|
||||
`{"type":"content_block_stop","index":2}`,
|
||||
`{"type":"message_delta","delta":{"stop_reason":"` + finish + `"},"usage":{"output_tokens":7}}`,
|
||||
`{"type":"message_stop"}`,
|
||||
}
|
||||
src := reasoningSSE(events...)
|
||||
for _, target := range []Kind{Chat, Responses, Anthropic} {
|
||||
out, err := ConvertResponse(Anthropic, target, []byte(body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var dst bytes.Buffer
|
||||
u, err := Stream(context.Background(), &dst, strings.NewReader(src), Anthropic, target, "m")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !u.Known || u.Input != 9 || u.Output != 7 {
|
||||
t.Fatalf("usage %+v", u)
|
||||
}
|
||||
if target == Anthropic {
|
||||
if string(out) != body || dst.String() != src {
|
||||
t.Fatal("native bytes changed")
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, result := range []string{string(out), dst.String()} {
|
||||
for _, secret := range []string{"PRIVATE", "SIGNATURE", "CIPHER", "thinking"} {
|
||||
if strings.Contains(result, secret) {
|
||||
t.Fatal("thinking leaked")
|
||||
}
|
||||
}
|
||||
want := "OK"
|
||||
if tool {
|
||||
want = "weather"
|
||||
}
|
||||
if !strings.Contains(result, want) {
|
||||
t.Fatal("lost visible output")
|
||||
}
|
||||
}
|
||||
terminal := "[DONE]"
|
||||
if target == Responses {
|
||||
terminal = "response.completed"
|
||||
}
|
||||
if !strings.Contains(dst.String(), terminal) {
|
||||
t.Fatal("no terminal")
|
||||
}
|
||||
}
|
||||
for _, bad := range []string{
|
||||
strings.Replace(src, `{"type":"content_block_stop","index":0}`, `{"type":"ping"}`, 1),
|
||||
strings.Replace(src, `"type":"thinking_delta"`, `"type":"text_delta"`, 1),
|
||||
strings.Replace(src, `"index":2,"content_block"`, `"index":0,"content_block"`, 1),
|
||||
} {
|
||||
var dst bytes.Buffer
|
||||
if _, err := Stream(context.Background(), &dst, strings.NewReader(bad), Anthropic, Chat, "m"); err == nil {
|
||||
t.Fatal("accepted invalid thinking lifecycle")
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, block := range []object{
|
||||
{"type": "thinking", "thinking": true, "signature": ""},
|
||||
{"type": "thinking", "thinking": "", "signature": "", "unknown": true},
|
||||
{"type": "redacted_thinking", "data": nil},
|
||||
} {
|
||||
if _, err := anthropicThinking(block); err == nil {
|
||||
t.Fatal("accepted malformed thinking")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user