mirror of
https://github.com/dogkeeper886/ollama37.git
synced 2025-12-17 19:27:00 +00:00
Sync with upstream ollama/ollama and restore Tesla K80 (compute 3.7) support
This commit represents a complete rework after pulling the latest changes from official ollama/ollama repository and re-applying Tesla K80 compatibility patches. ## Key Changes ### CUDA Compute Capability 3.7 Support (Tesla K80) - Added sm_37 (compute 3.7) to CMAKE_CUDA_ARCHITECTURES in CMakeLists.txt - Updated CMakePresets.json to include compute 3.7 in "CUDA 11" preset - Using 37-virtual (PTX with JIT compilation) for maximum compatibility ### Legacy Toolchain Compatibility - **NVIDIA Driver**: 470.256.02 (last version supporting Kepler/K80) - **CUDA Version**: 11.4.4 (last CUDA 11.x supporting compute 3.7) - **GCC Version**: 10.5.0 (required by CUDA 11.4 host_config.h) ### CPU Architecture Trade-offs Due to GCC 10.5 limitation, sacrificed newer CPU optimizations: - Alderlake CPU variant enabled WITHOUT AVX_VNNI (requires GCC 11+) - Still supports: SSE4.2, AVX, F16C, AVX2, BMI2, FMA - Performance impact: ~3-7% on newer CPUs (acceptable for K80 compatibility) ### Build System Updates - Modified ml/backend/ggml/ggml/src/ggml-cuda/CMakeLists.txt for compute 3.7 - Added -Wno-deprecated-gpu-targets flag to suppress warnings - Updated ml/backend/ggml/ggml/src/CMakeLists.txt for Alderlake without AVX_VNNI ### Upstream Sync Merged latest llama.cpp changes including: - Enhanced KV cache management with ISWA and hybrid memory support - Improved multi-modal support (mtmd framework) - New model architectures (Gemma3, Llama4, Qwen3, etc.) - GPU backend improvements for CUDA, Metal, and ROCm - Updated quantization support and GGUF format handling ### Documentation - Updated CLAUDE.md with comprehensive build instructions - Documented toolchain constraints and CPU architecture trade-offs - Removed outdated CI/CD workflows (tesla-k80-*.yml) - Cleaned up temporary development artifacts ## Rationale This fork maintains Tesla K80 GPU support (compute 3.7) which was dropped in official Ollama due to legacy driver/CUDA requirements. The toolchain constraint creates a deadlock: - K80 → Driver 470 → CUDA 11.4 → GCC 10 → No AVX_VNNI We accept the loss of cutting-edge CPU optimizations to enable running modern LLMs on legacy but still capable Tesla K80 hardware (12GB VRAM per GPU). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
@@ -40,13 +41,7 @@ func TestParser(t *testing.T) {
|
||||
Function: api.ToolFunction{
|
||||
Name: "get_temperature",
|
||||
Description: "Retrieve the temperature for a given location",
|
||||
Parameters: struct {
|
||||
Type string `json:"type"`
|
||||
Defs any `json:"$defs,omitempty"`
|
||||
Items any `json:"items,omitempty"`
|
||||
Required []string `json:"required"`
|
||||
Properties map[string]api.ToolProperty `json:"properties"`
|
||||
}{
|
||||
Parameters: api.ToolFunctionParameters{
|
||||
Type: "object",
|
||||
Required: []string{"city"},
|
||||
Properties: map[string]api.ToolProperty{
|
||||
@@ -68,13 +63,7 @@ func TestParser(t *testing.T) {
|
||||
Function: api.ToolFunction{
|
||||
Name: "get_conditions",
|
||||
Description: "Retrieve the current weather conditions for a given location",
|
||||
Parameters: struct {
|
||||
Type string `json:"type"`
|
||||
Defs any `json:"$defs,omitempty"`
|
||||
Items any `json:"items,omitempty"`
|
||||
Required []string `json:"required"`
|
||||
Properties map[string]api.ToolProperty `json:"properties"`
|
||||
}{
|
||||
Parameters: api.ToolFunctionParameters{
|
||||
Type: "object",
|
||||
Properties: map[string]api.ToolProperty{
|
||||
"location": {
|
||||
@@ -104,13 +93,7 @@ func TestParser(t *testing.T) {
|
||||
Function: api.ToolFunction{
|
||||
Name: "get_address",
|
||||
Description: "Get the address of a given location",
|
||||
Parameters: struct {
|
||||
Type string `json:"type"`
|
||||
Defs any `json:"$defs,omitempty"`
|
||||
Items any `json:"items,omitempty"`
|
||||
Required []string `json:"required"`
|
||||
Properties map[string]api.ToolProperty `json:"properties"`
|
||||
}{
|
||||
Parameters: api.ToolFunctionParameters{
|
||||
Type: "object",
|
||||
Properties: map[string]api.ToolProperty{
|
||||
"location": {
|
||||
@@ -126,13 +109,7 @@ func TestParser(t *testing.T) {
|
||||
Function: api.ToolFunction{
|
||||
Name: "add",
|
||||
Description: "Add two numbers",
|
||||
Parameters: struct {
|
||||
Type string `json:"type"`
|
||||
Defs any `json:"$defs,omitempty"`
|
||||
Items any `json:"items,omitempty"`
|
||||
Required []string `json:"required"`
|
||||
Properties map[string]api.ToolProperty `json:"properties"`
|
||||
}{
|
||||
Parameters: api.ToolFunctionParameters{
|
||||
Type: "object",
|
||||
Properties: map[string]api.ToolProperty{
|
||||
"a": {
|
||||
@@ -1056,6 +1033,7 @@ func TestFindArguments(t *testing.T) {
|
||||
name string
|
||||
buffer []byte
|
||||
want map[string]any
|
||||
tool string
|
||||
}{
|
||||
{
|
||||
name: "empty string",
|
||||
@@ -1140,16 +1118,202 @@ func TestFindArguments(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "deepseek",
|
||||
buffer: []byte(`", "arguments": {"location": "Tokyo"}}</tool_call>`),
|
||||
buffer: []byte(`"arguments": {"location": "Tokyo"}}</tool_call>`),
|
||||
want: map[string]any{
|
||||
"location": "Tokyo",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string with braces",
|
||||
buffer: []byte(`{"name": "process_code", "arguments": {"code": "if (x > 0) { return true; }"}}`),
|
||||
want: map[string]any{
|
||||
"code": "if (x > 0) { return true; }",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string with nested json",
|
||||
buffer: []byte(`{"name": "send_data", "arguments": {"payload": "{\"nested\": {\"key\": \"value\"}}"}}`),
|
||||
want: map[string]any{
|
||||
"payload": `{"nested": {"key": "value"}}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string with escaped quotes and braces",
|
||||
buffer: []byte(`{"name": "analyze", "arguments": {"text": "The JSON is: {\"key\": \"val{ue}\"}"}}`),
|
||||
want: map[string]any{
|
||||
"text": `The JSON is: {"key": "val{ue}"}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple objects with string containing braces",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"query": "find } in text"}} {"name": "other"}`),
|
||||
want: map[string]any{
|
||||
"query": "find } in text",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unmatched closing brace in string",
|
||||
buffer: []byte(`{"name": "search", "arguments": {"pattern": "regex: }"}}`),
|
||||
want: map[string]any{
|
||||
"pattern": "regex: }",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "complex nested with mixed braces",
|
||||
buffer: []byte(`{"name": "analyze", "arguments": {"data": "{\"items\": [{\"value\": \"}\"}, {\"code\": \"if (x) { return y; }\"}]}"}}`),
|
||||
want: map[string]any{
|
||||
"data": `{"items": [{"value": "}"}, {"code": "if (x) { return y; }"}]}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string with newline and braces",
|
||||
buffer: []byte(`{"name": "format", "arguments": {"template": "{\n \"key\": \"value\"\n}"}}`),
|
||||
want: map[string]any{
|
||||
"template": "{\n \"key\": \"value\"\n}",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string with unicode escape",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"text": "Unicode: \u007B and \u007D"}}`),
|
||||
want: map[string]any{
|
||||
"text": "Unicode: { and }",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "array arguments",
|
||||
buffer: []byte(`{"name": "batch", "arguments": ["item1", "item2", "{\"nested\": true}"]}`),
|
||||
want: nil, // This should return nil because arguments is not a map
|
||||
},
|
||||
{
|
||||
name: "escaped backslash before quote",
|
||||
buffer: []byte(`{"name": "path", "arguments": {"dir": "C:\\Program Files\\{App}\\"}}`),
|
||||
want: map[string]any{
|
||||
"dir": `C:\Program Files\{App}\`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single quotes not treated as string delimiters",
|
||||
buffer: []byte(`{"name": "query", "arguments": {"sql": "SELECT * FROM users WHERE name = '{admin}'"}}`),
|
||||
want: map[string]any{
|
||||
"sql": "SELECT * FROM users WHERE name = '{admin}'",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "incomplete json at buffer end",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"data": "some {"`),
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "multiple escaped quotes",
|
||||
buffer: []byte(`{"name": "echo", "arguments": {"msg": "He said \"Hello {World}\" loudly"}}`),
|
||||
want: map[string]any{
|
||||
"msg": `He said "Hello {World}" loudly`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "json with comments style string",
|
||||
buffer: []byte(`{"name": "code", "arguments": {"snippet": "// This is a comment with { and }"}}`),
|
||||
want: map[string]any{
|
||||
"snippet": "// This is a comment with { and }",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "consecutive escaped backslashes",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"path": "C:\\\\{folder}\\\\"}}`),
|
||||
want: map[string]any{
|
||||
"path": `C:\\{folder}\\`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty string with braces after",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"a": "", "b": "{value}"}}`),
|
||||
want: map[string]any{
|
||||
"a": "",
|
||||
"b": "{value}",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unicode in key names",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"key{": "value", "key}": "value2"}}`),
|
||||
want: map[string]any{
|
||||
"key{": "value",
|
||||
"key}": "value2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "very long string with braces",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"data": "` + strings.Repeat("a{b}c", 100) + `"}}`),
|
||||
want: map[string]any{
|
||||
"data": strings.Repeat("a{b}c", 100),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "tab characters and braces",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"code": "\tif (true) {\n\t\treturn;\n\t}"}}`),
|
||||
want: map[string]any{
|
||||
"code": "\tif (true) {\n\t\treturn;\n\t}",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "null byte in string",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"data": "before\u0000{after}"}}`),
|
||||
want: map[string]any{
|
||||
"data": "before\x00{after}",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "escaped quote at end of string",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"data": "text with quote at end\\\""}}`),
|
||||
want: map[string]any{
|
||||
"data": `text with quote at end\"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mixed array and object in arguments",
|
||||
buffer: []byte(`{"name": "test", "arguments": {"items": ["{", "}", {"key": "value"}]}}`),
|
||||
want: map[string]any{
|
||||
"items": []any{"{", "}", map[string]any{"key": "value"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stringified arguments",
|
||||
buffer: []byte(`{"name": "get_temperature", "arguments": "{\"format\": \"fahrenheit\", \"location\": \"San Francisco, CA\"}"}`),
|
||||
want: map[string]any{
|
||||
"format": "fahrenheit",
|
||||
"location": "San Francisco, CA",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stringified parameters",
|
||||
buffer: []byte(`{"name": "get_temperature", "parameters": "{\"format\": \"fahrenheit\", \"location\": \"San Francisco, CA\"}"}`),
|
||||
want: map[string]any{
|
||||
"format": "fahrenheit",
|
||||
"location": "San Francisco, CA",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "simple tool call",
|
||||
tool: "get_temperature",
|
||||
buffer: []byte(`{"get_temperature": {"format": "fahrenheit", "location": "San Francisco, CA"}}`),
|
||||
want: map[string]any{
|
||||
"format": "fahrenheit",
|
||||
"location": "San Francisco, CA",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stringified simple tool call",
|
||||
tool: "get_temperature",
|
||||
buffer: []byte(`{"get_temperature": "{\"format\": \"fahrenheit\", \"location\": \"San Francisco, CA\"}"}`),
|
||||
want: map[string]any{
|
||||
"format": "fahrenheit",
|
||||
"location": "San Francisco, CA",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, _ := findArguments(tt.buffer)
|
||||
got, _ := findArguments(&api.Tool{Function: api.ToolFunction{Name: tt.tool}}, tt.buffer)
|
||||
|
||||
if diff := cmp.Diff(got, tt.want); diff != "" {
|
||||
t.Errorf("scanArguments() args mismatch (-got +want):\n%s", diff)
|
||||
|
||||
Reference in New Issue
Block a user