| 
									
										
										
										
											2024-03-14 04:29:40 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2024-08-02 05:52:15 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2024-03-14 04:29:40 +08:00
										 |  |  | 	"math" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/assert" | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestKeepAliveParsingFromJSON(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name string | 
					
						
							|  |  |  | 		req  string | 
					
						
							|  |  |  | 		exp  *Duration | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2025-08-28 02:51:25 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Unset", | 
					
						
							|  |  |  | 			req:  `{ }`, | 
					
						
							|  |  |  | 			exp:  nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2024-03-14 04:29:40 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Positive Integer", | 
					
						
							|  |  |  | 			req:  `{ "keep_alive": 42 }`, | 
					
						
							|  |  |  | 			exp:  &Duration{42 * time.Second}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2024-05-07 06:59:18 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Positive Float", | 
					
						
							|  |  |  | 			req:  `{ "keep_alive": 42.5 }`, | 
					
						
							| 
									
										
										
										
											2025-08-28 02:51:25 +08:00
										 |  |  | 			exp:  &Duration{42500 * time.Millisecond}, | 
					
						
							| 
									
										
										
										
											2024-05-07 06:59:18 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2024-03-14 04:29:40 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Positive Integer String", | 
					
						
							|  |  |  | 			req:  `{ "keep_alive": "42m" }`, | 
					
						
							|  |  |  | 			exp:  &Duration{42 * time.Minute}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Negative Integer", | 
					
						
							|  |  |  | 			req:  `{ "keep_alive": -1 }`, | 
					
						
							|  |  |  | 			exp:  &Duration{math.MaxInt64}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2024-05-07 06:59:18 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Negative Float", | 
					
						
							|  |  |  | 			req:  `{ "keep_alive": -3.14 }`, | 
					
						
							|  |  |  | 			exp:  &Duration{math.MaxInt64}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2024-03-14 04:29:40 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Negative Integer String", | 
					
						
							|  |  |  | 			req:  `{ "keep_alive": "-1m" }`, | 
					
						
							|  |  |  | 			exp:  &Duration{math.MaxInt64}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							|  |  |  | 		t.Run(test.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			var dec ChatRequest | 
					
						
							|  |  |  | 			err := json.Unmarshal([]byte(test.req), &dec) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			assert.Equal(t, test.exp, dec.KeepAlive) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-05-07 06:59:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestDurationMarshalUnmarshal(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name     string | 
					
						
							|  |  |  | 		input    time.Duration | 
					
						
							|  |  |  | 		expected time.Duration | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			"negative duration", | 
					
						
							|  |  |  | 			time.Duration(-1), | 
					
						
							|  |  |  | 			time.Duration(math.MaxInt64), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			"positive duration", | 
					
						
							| 
									
										
										
										
											2024-05-22 13:21:04 +08:00
										 |  |  | 			42 * time.Second, | 
					
						
							|  |  |  | 			42 * time.Second, | 
					
						
							| 
									
										
										
										
											2024-05-07 06:59:18 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			"another positive duration", | 
					
						
							| 
									
										
										
										
											2024-05-22 13:21:04 +08:00
										 |  |  | 			42 * time.Minute, | 
					
						
							|  |  |  | 			42 * time.Minute, | 
					
						
							| 
									
										
										
										
											2024-05-07 06:59:18 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			"zero duration", | 
					
						
							|  |  |  | 			time.Duration(0), | 
					
						
							|  |  |  | 			time.Duration(0), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			"max duration", | 
					
						
							|  |  |  | 			time.Duration(math.MaxInt64), | 
					
						
							|  |  |  | 			time.Duration(math.MaxInt64), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							|  |  |  | 		t.Run(test.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			b, err := json.Marshal(Duration{test.input}) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var d Duration | 
					
						
							|  |  |  | 			err = json.Unmarshal(b, &d) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			assert.Equal(t, test.expected, d.Duration, "input %v, marshalled %v, got %v", test.input, string(b), d.Duration) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-06-18 03:14:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestUseMmapParsingFromJSON(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 	tr := true | 
					
						
							|  |  |  | 	fa := false | 
					
						
							| 
									
										
										
										
											2024-06-18 03:14:42 +08:00
										 |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name string | 
					
						
							|  |  |  | 		req  string | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 		exp  *bool | 
					
						
							| 
									
										
										
										
											2024-06-18 03:14:42 +08:00
										 |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Undefined", | 
					
						
							|  |  |  | 			req:  `{ }`, | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 			exp:  nil, | 
					
						
							| 
									
										
										
										
											2024-06-18 03:14:42 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "True", | 
					
						
							|  |  |  | 			req:  `{ "use_mmap": true }`, | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 			exp:  &tr, | 
					
						
							| 
									
										
										
										
											2024-06-18 03:14:42 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "False", | 
					
						
							|  |  |  | 			req:  `{ "use_mmap": false }`, | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 			exp:  &fa, | 
					
						
							| 
									
										
										
										
											2024-06-18 03:14:42 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							|  |  |  | 		t.Run(test.name, func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2025-04-03 00:44:27 +08:00
										 |  |  | 			var oMap map[string]any | 
					
						
							| 
									
										
										
										
											2024-06-18 03:14:42 +08:00
										 |  |  | 			err := json.Unmarshal([]byte(test.req), &oMap) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			opts := DefaultOptions() | 
					
						
							|  |  |  | 			err = opts.FromMap(oMap) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			assert.Equal(t, test.exp, opts.UseMMap) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestUseMmapFormatParams(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 	tr := true | 
					
						
							|  |  |  | 	fa := false | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name string | 
					
						
							|  |  |  | 		req  map[string][]string | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 		exp  *bool | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 		err  error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "True", | 
					
						
							|  |  |  | 			req: map[string][]string{ | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 				"use_mmap": {"true"}, | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 			exp: &tr, | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			err: nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "False", | 
					
						
							|  |  |  | 			req: map[string][]string{ | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 				"use_mmap": {"false"}, | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 			exp: &fa, | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			err: nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Numeric True", | 
					
						
							|  |  |  | 			req: map[string][]string{ | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 				"use_mmap": {"1"}, | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 			exp: &tr, | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			err: nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Numeric False", | 
					
						
							|  |  |  | 			req: map[string][]string{ | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 				"use_mmap": {"0"}, | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 			exp: &fa, | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			err: nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "invalid string", | 
					
						
							|  |  |  | 			req: map[string][]string{ | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 				"use_mmap": {"foo"}, | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 			exp: nil, | 
					
						
							| 
									
										
										
										
											2024-08-02 05:52:15 +08:00
										 |  |  | 			err: errors.New("invalid bool value [foo]"), | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							|  |  |  | 		t.Run(test.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			resp, err := FormatParams(test.req) | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 			require.Equal(t, test.err, err) | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			respVal, ok := resp["use_mmap"] | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 			if test.exp != nil { | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 				assert.True(t, ok, "resp: %v", resp) | 
					
						
							| 
									
										
										
										
											2024-06-29 00:57:10 +08:00
										 |  |  | 				assert.Equal(t, *test.exp, *respVal.(*bool)) | 
					
						
							| 
									
										
										
										
											2024-06-22 03:27:19 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-07-16 04:55:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestMessage_UnmarshalJSON(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		input    string | 
					
						
							|  |  |  | 		expected string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{`{"role": "USER", "content": "Hello!"}`, "user"}, | 
					
						
							|  |  |  | 		{`{"role": "System", "content": "Initialization complete."}`, "system"}, | 
					
						
							|  |  |  | 		{`{"role": "assistant", "content": "How can I help you?"}`, "assistant"}, | 
					
						
							|  |  |  | 		{`{"role": "TOOl", "content": "Access granted."}`, "tool"}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							|  |  |  | 		var msg Message | 
					
						
							|  |  |  | 		if err := json.Unmarshal([]byte(test.input), &msg); err != nil { | 
					
						
							|  |  |  | 			t.Errorf("Unexpected error: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if msg.Role != test.expected { | 
					
						
							|  |  |  | 			t.Errorf("role not lowercased: got %v, expected %v", msg.Role, test.expected) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-04-08 05:27:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-09 06:05:38 +08:00
										 |  |  | func TestToolFunction_UnmarshalJSON(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name    string | 
					
						
							|  |  |  | 		input   string | 
					
						
							|  |  |  | 		wantErr string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "valid enum with same types", | 
					
						
							|  |  |  | 			input: `{ | 
					
						
							|  |  |  | 				"name": "test", | 
					
						
							|  |  |  | 				"description": "test function", | 
					
						
							|  |  |  | 				"parameters": { | 
					
						
							|  |  |  | 					"type": "object", | 
					
						
							|  |  |  | 					"required": ["test"], | 
					
						
							|  |  |  | 					"properties": { | 
					
						
							|  |  |  | 						"test": { | 
					
						
							|  |  |  | 							"type": "string", | 
					
						
							|  |  |  | 							"description": "test prop", | 
					
						
							|  |  |  | 							"enum": ["a", "b", "c"] | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}`, | 
					
						
							|  |  |  | 			wantErr: "", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "empty enum array", | 
					
						
							|  |  |  | 			input: `{ | 
					
						
							|  |  |  | 				"name": "test", | 
					
						
							|  |  |  | 				"description": "test function", | 
					
						
							|  |  |  | 				"parameters": { | 
					
						
							|  |  |  | 					"type": "object", | 
					
						
							|  |  |  | 					"required": ["test"], | 
					
						
							|  |  |  | 					"properties": { | 
					
						
							|  |  |  | 						"test": { | 
					
						
							|  |  |  | 							"type": "string", | 
					
						
							|  |  |  | 							"description": "test prop", | 
					
						
							|  |  |  | 							"enum": [] | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}`, | 
					
						
							|  |  |  | 			wantErr: "", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tt := range tests { | 
					
						
							|  |  |  | 		t.Run(tt.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			var tf ToolFunction | 
					
						
							|  |  |  | 			err := json.Unmarshal([]byte(tt.input), &tf) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if tt.wantErr != "" { | 
					
						
							|  |  |  | 				require.Error(t, err) | 
					
						
							|  |  |  | 				assert.Contains(t, err.Error(), tt.wantErr) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-08 05:27:01 +08:00
										 |  |  | func TestPropertyType_UnmarshalJSON(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name     string | 
					
						
							|  |  |  | 		input    string | 
					
						
							|  |  |  | 		expected PropertyType | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "string type", | 
					
						
							|  |  |  | 			input:    `"string"`, | 
					
						
							|  |  |  | 			expected: PropertyType{"string"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "array of types", | 
					
						
							|  |  |  | 			input:    `["string", "number"]`, | 
					
						
							|  |  |  | 			expected: PropertyType{"string", "number"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "array with single type", | 
					
						
							|  |  |  | 			input:    `["string"]`, | 
					
						
							|  |  |  | 			expected: PropertyType{"string"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							|  |  |  | 		t.Run(test.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			var pt PropertyType | 
					
						
							|  |  |  | 			if err := json.Unmarshal([]byte(test.input), &pt); err != nil { | 
					
						
							|  |  |  | 				t.Errorf("Unexpected error: %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if len(pt) != len(test.expected) { | 
					
						
							|  |  |  | 				t.Errorf("Length mismatch: got %v, expected %v", len(pt), len(test.expected)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for i, v := range pt { | 
					
						
							|  |  |  | 				if v != test.expected[i] { | 
					
						
							|  |  |  | 					t.Errorf("Value mismatch at index %d: got %v, expected %v", i, v, test.expected[i]) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestPropertyType_MarshalJSON(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name     string | 
					
						
							|  |  |  | 		input    PropertyType | 
					
						
							|  |  |  | 		expected string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "single type", | 
					
						
							|  |  |  | 			input:    PropertyType{"string"}, | 
					
						
							|  |  |  | 			expected: `"string"`, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "multiple types", | 
					
						
							|  |  |  | 			input:    PropertyType{"string", "number"}, | 
					
						
							|  |  |  | 			expected: `["string","number"]`, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:     "empty type", | 
					
						
							|  |  |  | 			input:    PropertyType{}, | 
					
						
							|  |  |  | 			expected: `[]`, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							|  |  |  | 		t.Run(test.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			data, err := json.Marshal(test.input) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Errorf("Unexpected error: %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if string(data) != test.expected { | 
					
						
							|  |  |  | 				t.Errorf("Marshaled data mismatch: got %v, expected %v", string(data), test.expected) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-05-29 10:38:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestThinking_UnmarshalJSON(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name             string | 
					
						
							|  |  |  | 		input            string | 
					
						
							| 
									
										
										
										
											2025-08-06 03:21:16 +08:00
										 |  |  | 		expectedThinking *ThinkValue | 
					
						
							| 
									
										
										
										
											2025-05-29 10:38:52 +08:00
										 |  |  | 		expectedError    bool | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:             "true", | 
					
						
							|  |  |  | 			input:            `{ "think": true }`, | 
					
						
							| 
									
										
										
										
											2025-08-06 03:21:16 +08:00
										 |  |  | 			expectedThinking: &ThinkValue{Value: true}, | 
					
						
							| 
									
										
										
										
											2025-05-29 10:38:52 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:             "false", | 
					
						
							|  |  |  | 			input:            `{ "think": false }`, | 
					
						
							| 
									
										
										
										
											2025-08-06 03:21:16 +08:00
										 |  |  | 			expectedThinking: &ThinkValue{Value: false}, | 
					
						
							| 
									
										
										
										
											2025-05-29 10:38:52 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:             "unset", | 
					
						
							|  |  |  | 			input:            `{ }`, | 
					
						
							|  |  |  | 			expectedThinking: nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2025-08-06 03:21:16 +08:00
										 |  |  | 			name:             "string_high", | 
					
						
							|  |  |  | 			input:            `{ "think": "high" }`, | 
					
						
							|  |  |  | 			expectedThinking: &ThinkValue{Value: "high"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:             "string_medium", | 
					
						
							|  |  |  | 			input:            `{ "think": "medium" }`, | 
					
						
							|  |  |  | 			expectedThinking: &ThinkValue{Value: "medium"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:             "string_low", | 
					
						
							|  |  |  | 			input:            `{ "think": "low" }`, | 
					
						
							|  |  |  | 			expectedThinking: &ThinkValue{Value: "low"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:             "invalid_string", | 
					
						
							|  |  |  | 			input:            `{ "think": "invalid" }`, | 
					
						
							| 
									
										
										
										
											2025-05-29 10:38:52 +08:00
										 |  |  | 			expectedThinking: nil, | 
					
						
							|  |  |  | 			expectedError:    true, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							|  |  |  | 		t.Run(test.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			var req GenerateRequest | 
					
						
							|  |  |  | 			err := json.Unmarshal([]byte(test.input), &req) | 
					
						
							|  |  |  | 			if test.expectedError { | 
					
						
							|  |  |  | 				require.Error(t, err) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2025-08-06 03:21:16 +08:00
										 |  |  | 				if test.expectedThinking == nil { | 
					
						
							|  |  |  | 					assert.Nil(t, req.Think) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					require.NotNil(t, req.Think) | 
					
						
							|  |  |  | 					assert.Equal(t, test.expectedThinking.Value, req.Think.Value) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2025-05-29 10:38:52 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-08-23 07:26:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestToolFunctionParameters_String(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name     string | 
					
						
							|  |  |  | 		params   ToolFunctionParameters | 
					
						
							|  |  |  | 		expected string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "simple object with string property", | 
					
						
							|  |  |  | 			params: ToolFunctionParameters{ | 
					
						
							|  |  |  | 				Type:     "object", | 
					
						
							|  |  |  | 				Required: []string{"name"}, | 
					
						
							|  |  |  | 				Properties: map[string]ToolProperty{ | 
					
						
							|  |  |  | 					"name": { | 
					
						
							|  |  |  | 						Type:        PropertyType{"string"}, | 
					
						
							|  |  |  | 						Description: "The name of the person", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expected: `{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"The name of the person"}}}`, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "marshal failure returns empty string", | 
					
						
							|  |  |  | 			params: ToolFunctionParameters{ | 
					
						
							|  |  |  | 				Type: "object", | 
					
						
							|  |  |  | 				Defs: func() any { | 
					
						
							|  |  |  | 					// Create a cycle that will cause json.Marshal to fail
 | 
					
						
							|  |  |  | 					type selfRef struct { | 
					
						
							|  |  |  | 						Self *selfRef | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					s := &selfRef{} | 
					
						
							|  |  |  | 					s.Self = s | 
					
						
							|  |  |  | 					return s | 
					
						
							|  |  |  | 				}(), | 
					
						
							|  |  |  | 				Properties: map[string]ToolProperty{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expected: "", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests { | 
					
						
							|  |  |  | 		t.Run(test.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			result := test.params.String() | 
					
						
							|  |  |  | 			assert.Equal(t, test.expected, result) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |