Parameter descriptions lost when using optional fields in tools, etc.

### Description

When using `z.string().optional()`, the parameter's description is lost during schema generation. This occurs because the type is being converted to a nullable type (`["string", "null"]`) without preserving the metadata from the Zod schema. The description should be maintained regardless of whether a field is optional or required.

```json
{
  "model": "gpt-4o",
  "temperature": 0,
  "messages": [
    {
      "role": "user",
      "content": "What's the weather in San Francisco?"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "weather",
        "description": "Get the current weather in a city",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {
              "type": "string",
              "description": "The city to get the weather for"
            }
          },
          "required": [
            "city"
          ],
          "additionalProperties": false,
          "$schema": "https://json-schema.org/draft/2019-09/schema#"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "weatherOptional",
        "description": "Get the current weather in a city",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {
              "type": [
                "string",
                "null"
              ]
              // where is the description?
            }
          },
          "required": [
            "city"
          ],
          "additionalProperties": false,
          "$schema": "https://json-schema.org/draft/2019-09/schema#"
        }
      }
    }
  ],
  "tool_choice": "auto"
}
```

### Code example

```typescript
import { createOpenAI } from "@ai-sdk/openai";
import { generateText, tool } from "ai";
import { z } from "zod";

const logFetch = (input: RequestInfo | URL, init?: RequestInit) => {
  const url = input.toString();
  console.log(`Fetching ${url}...`);
  if (init?.body) {
    console.log(
      "Body prettier:",
      JSON.stringify(JSON.parse(init.body as string), null, 2),
    );
  }
  return fetch(input, init);
};

const openai = createOpenAI({
  fetch: logFetch,
});

const main = async () => {
  const { text } = await generateText({
    model: openai("gpt-4o"),
    maxSteps: 10,
    tools: {
      weather: tool({
        description: "Get the current weather in a city",
        parameters: z.object({
          city: z.string().describe("The city to get the weather for"),
        }),
        execute: async ({ city }) => {
          return "It's pleasant in " + city;
        },
      }),
      weatherOptional: tool({
        description: "Get the current weather in a city",
        parameters: z.object({
          city: z
            .string()
            .optional() // note the optional here
            .describe("The city to get the weather for"),
        }),
        execute: async ({ city }) => {
          return "It's pleasant in " + city;
        },
      }),
    },
    prompt: "What's the weather in San Francisco?",
  });

  console.log(text);
};

main().catch(console.error);
```

### AI provider

ai@4.0.36 and @ai-sdk/openai@1.0.19

### Additional context

_No response_

Labels: bug
State: closed