Repository: ollama/ollama
Pull request: openai: fix tool call mapping


Changed files:
filename: middleware/openai_test.go
patch: @@ -218,6 +218,7 @@ func TestChatMiddleware(t *testing.T) {
 						Role: "assistant",
 						ToolCalls: []api.ToolCall{
 							{
+								ID: "id",
 								Function: api.ToolCallFunction{
 									Name: "get_current_weather",
 									Arguments: map[string]any{
@@ -257,6 +258,7 @@ func TestChatMiddleware(t *testing.T) {
 						Content: "Let's see what the weather is like in Paris",
 						ToolCalls: []api.ToolCall{
 							{
+								ID: "id",
 								Function: api.ToolCallFunction{
 									Name: "get_current_weather",
 									Arguments: map[string]any{
@@ -295,6 +297,7 @@ func TestChatMiddleware(t *testing.T) {
 						Role: "assistant",
 						ToolCalls: []api.ToolCall{
 							{
+								ID: "id",
 								Function: api.ToolCallFunction{
 									Name: "get_current_weather",
 									Arguments: map[string]any{
@@ -334,6 +337,7 @@ func TestChatMiddleware(t *testing.T) {
 						Thinking: "Let's see what the weather is like in Paris",
 						ToolCalls: []api.ToolCall{
 							{
+								ID: "id",
 								Function: api.ToolCallFunction{
 									Name: "get_current_weather",
 									Arguments: map[string]any{
@@ -373,6 +377,7 @@ func TestChatMiddleware(t *testing.T) {
 						Role: "assistant",
 						ToolCalls: []api.ToolCall{
 							{
+								ID: "id_abc",
 								Function: api.ToolCallFunction{
 									Name: "get_current_weather",
 									Arguments: map[string]any{
@@ -384,9 +389,10 @@ func TestChatMiddleware(t *testing.T) {
 						},
 					},
 					{
-						Role:     "tool",
-						Content:  "The weather in Paris is 20 degrees Celsius",
-						ToolName: "get_current_weather",
+						Role:       "tool",
+						Content:    "The weather in Paris is 20 degrees Celsius",
+						ToolName:   "get_current_weather",
+						ToolCallID: "id_abc",
 					},
 				},
 				Options: map[string]any{
@@ -417,6 +423,7 @@ func TestChatMiddleware(t *testing.T) {
 						Role: "assistant",
 						ToolCalls: []api.ToolCall{
 							{
+								ID: "id",
 								Function: api.ToolCallFunction{
 									Name: "get_current_weather",
 									Arguments: map[string]any{

filename: openai/openai.go
patch: @@ -437,7 +437,7 @@ func FromChatRequest(r ChatCompletionRequest) (*api.ChatRequest, error) {
 			if err != nil {
 				return nil, err
 			}
-			messages = append(messages, api.Message{Role: msg.Role, Content: content, Thinking: msg.Reasoning, ToolCalls: toolCalls, ToolName: toolName})
+			messages = append(messages, api.Message{Role: msg.Role, Content: content, Thinking: msg.Reasoning, ToolCalls: toolCalls, ToolName: toolName, ToolCallID: msg.ToolCallID})
 		case []any:
 			for _, c := range content {
 				data, ok := c.(map[string]any)
@@ -501,9 +501,8 @@ func FromChatRequest(r ChatCompletionRequest) (*api.ChatRequest, error) {
 					return nil, err
 				}
 				messages[len(messages)-1].ToolCalls = toolCalls
-				if toolName != "" {
-					messages[len(messages)-1].ToolName = toolName
-				}
+				messages[len(messages)-1].ToolName = toolName
+				messages[len(messages)-1].ToolCallID = msg.ToolCallID
 				messages[len(messages)-1].Thinking = msg.Reasoning
 			}
 		default:
@@ -512,15 +511,11 @@ func FromChatRequest(r ChatCompletionRequest) (*api.ChatRequest, error) {
 				return nil, fmt.Errorf("invalid message content type: %T", content)
 			}
 
-			toolCalls := make([]api.ToolCall, len(msg.ToolCalls))
-			for i, tc := range msg.ToolCalls {
-				toolCalls[i].Function.Name = tc.Function.Name
-				err := json.Unmarshal([]byte(tc.Function.Arguments), &toolCalls[i].Function.Arguments)
-				if err != nil {
-					return nil, errors.New("invalid tool call arguments")
-				}
+			toolCalls, err := FromCompletionToolCall(msg.ToolCalls)
+			if err != nil {
+				return nil, err
 			}
-			messages = append(messages, api.Message{Role: msg.Role, Thinking: msg.Reasoning, ToolCalls: toolCalls})
+			messages = append(messages, api.Message{Role: msg.Role, Thinking: msg.Reasoning, ToolCalls: toolCalls, ToolCallID: msg.ToolCallID})
 		}
 	}
 
@@ -631,6 +626,7 @@ func nameFromToolCallID(messages []Message, toolCallID string) string {
 func FromCompletionToolCall(toolCalls []ToolCall) ([]api.ToolCall, error) {
 	apiToolCalls := make([]api.ToolCall, len(toolCalls))
 	for i, tc := range toolCalls {
+		apiToolCalls[i].ID = tc.ID
 		apiToolCalls[i].Function.Name = tc.Function.Name
 		err := json.Unmarshal([]byte(tc.Function.Arguments), &apiToolCalls[i].Function.Arguments)
 		if err != nil {