Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ namespace DeepInfra
typeof(global::DeepInfra.JsonConverters.AnyOfJsonConverter<global::DeepInfra.ModelPricingTime, global::DeepInfra.ModelPricingTokens, global::DeepInfra.ModelPricingInputLength, global::DeepInfra.ModelPricingInputTokens, global::DeepInfra.ModelPricingUptime, global::DeepInfra.ModelPricingInputCharacterLength, global::DeepInfra.ModelPricingImageUnits, global::DeepInfra.ModelPricingOutputLength>),
typeof(global::DeepInfra.JsonConverters.AnyOfJsonConverter<global::DeepInfra.ChatCompletionToolMessage, global::DeepInfra.ChatCompletionAssistantMessage, global::DeepInfra.ChatCompletionUserMessage, global::DeepInfra.ChatCompletionSystemMessage>),
typeof(global::DeepInfra.JsonConverters.AnyOfJsonConverter<string, global::System.Collections.Generic.IList<string>>),
typeof(global::DeepInfra.JsonConverters.AnyOfJsonConverter<string, global::DeepInfra.ChatTools>),
typeof(global::DeepInfra.JsonConverters.AnyOfJsonConverter<string, global::System.Collections.Generic.IList<string>>),
typeof(global::DeepInfra.JsonConverters.AnyOfJsonConverter<global::System.Collections.Generic.IList<string>, string>),
typeof(global::DeepInfra.JsonConverters.UnixTimestampJsonConverter),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ partial void ProcessOpenaiChatCompletionsResponseContent(
/// A list of tools the model may call. Currently, only functions are supported as a tool.
/// </param>
/// <param name="toolChoice">
/// Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. specifying a particular function choice is not supported currently.none is the default when no functions are present. auto is the default if functions are present.
/// Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. required means the model must call a function. defined tool means the model must call that specific tool. none is the default when no functions are present. auto is the default if functions are present.
/// </param>
/// <param name="responseFormat"></param>
/// <param name="repetitionPenalty">
Expand Down Expand Up @@ -325,7 +325,7 @@ partial void ProcessOpenaiChatCompletionsResponseContent(
double? presencePenalty = default,
double? frequencyPenalty = default,
global::System.Collections.Generic.IList<global::DeepInfra.ChatTools>? tools = default,
string? toolChoice = default,
global::DeepInfra.AnyOf<string, global::DeepInfra.ChatTools>? toolChoice = default,
global::DeepInfra.ResponseFormat? responseFormat = default,
double? repetitionPenalty = default,
string? user = default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public partial interface IDeepInfraClient
/// A list of tools the model may call. Currently, only functions are supported as a tool.
/// </param>
/// <param name="toolChoice">
/// Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. specifying a particular function choice is not supported currently.none is the default when no functions are present. auto is the default if functions are present.
/// Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. required means the model must call a function. defined tool means the model must call that specific tool. none is the default when no functions are present. auto is the default if functions are present.
/// </param>
/// <param name="responseFormat"></param>
/// <param name="repetitionPenalty">
Expand Down Expand Up @@ -115,7 +115,7 @@ public partial interface IDeepInfraClient
double? presencePenalty = default,
double? frequencyPenalty = default,
global::System.Collections.Generic.IList<global::DeepInfra.ChatTools>? tools = default,
string? toolChoice = default,
global::DeepInfra.AnyOf<string, global::DeepInfra.ChatTools>? toolChoice = default,
global::DeepInfra.ResponseFormat? responseFormat = default,
double? repetitionPenalty = default,
string? user = default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -686,166 +686,170 @@ public sealed partial class JsonSerializerContextTypes
/// <summary>
///
/// </summary>
public global::DeepInfra.ResponseFormat? Type165 { get; set; }
public global::DeepInfra.AnyOf<string, global::DeepInfra.ChatTools>? Type165 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.ResponseFormatType? Type166 { get; set; }
public global::DeepInfra.ResponseFormat? Type166 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.StreamOptions? Type167 { get; set; }
public global::DeepInfra.ResponseFormatType? Type167 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAIChatCompletionsInReasoningEffort? Type168 { get; set; }
public global::DeepInfra.StreamOptions? Type168 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAICompletionsIn? Type169 { get; set; }
public global::DeepInfra.OpenAIChatCompletionsInReasoningEffort? Type169 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAIEmbeddingsIn? Type170 { get; set; }
public global::DeepInfra.OpenAICompletionsIn? Type170 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.ServiceTier? Type171 { get; set; }
public global::DeepInfra.OpenAIEmbeddingsIn? Type171 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.AnyOf<global::System.Collections.Generic.IList<string>, string>? Type172 { get; set; }
public global::DeepInfra.ServiceTier? Type172 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAIEmbeddingsInEncodingFormat? Type173 { get; set; }
public global::DeepInfra.AnyOf<global::System.Collections.Generic.IList<string>, string>? Type173 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAIImageData? Type174 { get; set; }
public global::DeepInfra.OpenAIEmbeddingsInEncodingFormat? Type174 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAIImagesGenerationsIn? Type175 { get; set; }
public global::DeepInfra.OpenAIImageData? Type175 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAIImagesResponseFormat? Type176 { get; set; }
public global::DeepInfra.OpenAIImagesGenerationsIn? Type176 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAIImagesOut? Type177 { get; set; }
public global::DeepInfra.OpenAIImagesResponseFormat? Type177 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.OpenAIImageData>? Type178 { get; set; }
public global::DeepInfra.OpenAIImagesOut? Type178 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAIImagesVariationsIn? Type179 { get; set; }
public global::System.Collections.Generic.IList<global::DeepInfra.OpenAIImageData>? Type179 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAIModelOut? Type180 { get; set; }
public global::DeepInfra.OpenAIImagesVariationsIn? Type180 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAIModelsOut? Type181 { get; set; }
public global::DeepInfra.OpenAIModelOut? Type181 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.OpenAIModelOut>? Type182 { get; set; }
public global::DeepInfra.OpenAIModelsOut? Type182 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenAITextToSpeechIn? Type183 { get; set; }
public global::System.Collections.Generic.IList<global::DeepInfra.OpenAIModelOut>? Type183 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenRouterDatacenter? Type184 { get; set; }
public global::DeepInfra.OpenAITextToSpeechIn? Type184 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenRouterModelData? Type185 { get; set; }
public global::DeepInfra.OpenRouterDatacenter? Type185 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenRouterPricing? Type186 { get; set; }
public global::DeepInfra.OpenRouterModelData? Type186 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.Dictionary<string, string>? Type187 { get; set; }
public global::DeepInfra.OpenRouterPricing? Type187 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.OpenRouterDatacenter>? Type188 { get; set; }
public global::System.Collections.Generic.Dictionary<string, string>? Type188 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.OpenRouterModelsOut? Type189 { get; set; }
public global::System.Collections.Generic.IList<global::DeepInfra.OpenRouterDatacenter>? Type189 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.OpenRouterModelData>? Type190 { get; set; }
public global::DeepInfra.OpenRouterModelsOut? Type190 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.RateLimitOut? Type191 { get; set; }
public global::System.Collections.Generic.IList<global::DeepInfra.OpenRouterModelData>? Type191 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.RateLimitRequestIn? Type192 { get; set; }
public global::DeepInfra.RateLimitOut? Type192 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.SchemaOut? Type193 { get; set; }
public global::DeepInfra.RateLimitRequestIn? Type193 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.ScopedJWTIn? Type194 { get; set; }
public global::DeepInfra.SchemaOut? Type194 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.ScopedJWTOut? Type195 { get; set; }
public global::DeepInfra.ScopedJWTIn? Type195 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.SshKeyIn? Type196 { get; set; }
public global::DeepInfra.ScopedJWTOut? Type196 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.SshKeyOut? Type197 { get; set; }
public global::DeepInfra.SshKeyIn? Type197 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.UpdateLoraApiRequest? Type198 { get; set; }
public global::DeepInfra.SshKeyOut? Type198 { get; set; }
/// <summary>
///
/// </summary>
public global::DeepInfra.ContainerRentalsListV1ContainersGetState? Type199 { get; set; }
public global::DeepInfra.UpdateLoraApiRequest? Type199 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.DeploymentOut>? Type200 { get; set; }
public global::DeepInfra.ContainerRentalsListV1ContainersGetState? Type200 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.ModelOut>? Type201 { get; set; }
public global::System.Collections.Generic.IList<global::DeepInfra.DeploymentOut>? Type201 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.ModelVersionOut>? Type202 { get; set; }
public global::System.Collections.Generic.IList<global::DeepInfra.ModelOut>? Type202 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.ContainerRentalOut>? Type203 { get; set; }
public global::System.Collections.Generic.IList<global::DeepInfra.ModelVersionOut>? Type203 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.ApiToken>? Type204 { get; set; }
public global::System.Collections.Generic.IList<global::DeepInfra.ContainerRentalOut>? Type204 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.SshKeyOut>? Type205 { get; set; }
public global::System.Collections.Generic.IList<global::DeepInfra.ApiToken>? Type205 { get; set; }
/// <summary>
///
/// </summary>
public global::System.Collections.Generic.IList<global::DeepInfra.SshKeyOut>? Type206 { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@ public sealed partial class OpenAIChatCompletionsIn
public global::System.Collections.Generic.IList<global::DeepInfra.ChatTools>? Tools { get; set; }

/// <summary>
/// Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. specifying a particular function choice is not supported currently.none is the default when no functions are present. auto is the default if functions are present.
/// Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. required means the model must call a function. defined tool means the model must call that specific tool. none is the default when no functions are present. auto is the default if functions are present.
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("tool_choice")]
public string? ToolChoice { get; set; }
[global::System.Text.Json.Serialization.JsonConverter(typeof(global::DeepInfra.JsonConverters.AnyOfJsonConverter<string, global::DeepInfra.ChatTools>))]
public global::DeepInfra.AnyOf<string, global::DeepInfra.ChatTools>? ToolChoice { get; set; }

/// <summary>
///
Expand Down Expand Up @@ -211,7 +212,7 @@ public sealed partial class OpenAIChatCompletionsIn
/// A list of tools the model may call. Currently, only functions are supported as a tool.
/// </param>
/// <param name="toolChoice">
/// Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. specifying a particular function choice is not supported currently.none is the default when no functions are present. auto is the default if functions are present.
/// Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. required means the model must call a function. defined tool means the model must call that specific tool. none is the default when no functions are present. auto is the default if functions are present.
/// </param>
/// <param name="responseFormat"></param>
/// <param name="repetitionPenalty">
Expand Down Expand Up @@ -248,7 +249,7 @@ public OpenAIChatCompletionsIn(
double? presencePenalty,
double? frequencyPenalty,
global::System.Collections.Generic.IList<global::DeepInfra.ChatTools>? tools,
string? toolChoice,
global::DeepInfra.AnyOf<string, global::DeepInfra.ChatTools>? toolChoice,
global::DeepInfra.ResponseFormat? responseFormat,
double? repetitionPenalty,
string? user,
Expand Down
6 changes: 4 additions & 2 deletions src/libs/DeepInfra/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6398,8 +6398,10 @@ components:
nullable: true
tool_choice:
title: Tool Choice
type: string
description: Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. specifying a particular function choice is not supported currently.none is the default when no functions are present. auto is the default if functions are present.
anyOf:
- type: string
- $ref: '#/components/schemas/ChatTools'
description: Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. required means the model must call a function. defined tool means the model must call that specific tool. none is the default when no functions are present. auto is the default if functions are present.
Comment on lines +6401 to +6404
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid reusing ChatTools in tool_choice; introduce a selector object that only needs a function name

Using ChatTools here invites redefining a tool and duplicating/contradicting entries in tools[]. OpenAI-style selection only needs the function name. Define a minimal selector object and reference that from tool_choice.

Add these schemas under components/schemas (outside this hunk):

ToolChoiceFunction:
  title: ToolChoiceFunction
  required: [type, function]
  type: object
  properties:
    type:
      title: Type
      type: string
      enum: [function]
      default: function
    function:
      $ref: '#/components/schemas/ToolChoiceFunctionName'

ToolChoiceFunctionName:
  title: ToolChoiceFunctionName
  required: [name]
  type: object
  properties:
    name:
      title: Name
      type: string
      description: Name of the function to call. Must match one of tools[].function.name.

This keeps tools[] for full definitions (parameters, descriptions) and tool_choice for selection only.


🛠️ Refactor suggestion

Constrain tool_choice to valid values and prefer oneOf for disjoint types

Right now any string is accepted, which weakens validation and SDK typings. Since object vs. string are disjoint, oneOf is a better fit and the string branch should enumerate the only allowed literals.

Apply this diff within this block:

-          anyOf:
-            - type: string
-            - $ref: '#/components/schemas/ChatTools'
+          oneOf:
+            - type: string
+              enum: [none, auto, required]
+            - $ref: '#/components/schemas/ToolChoiceFunction'

And add the supporting schema below in components/schemas (example provided in a separate block in the next comment).

🤖 Prompt for AI Agents
In src/libs/DeepInfra/openapi.yaml around lines 6401-6404, replace the anyOf
block with a oneOf that distinguishes a literal enum string branch and an object
branch referencing ChatTools, and constrain the string branch to the allowed
literals (none, auto, required, <tool-name> not allowed here — only the
enumerated keywords). Then add a new components/schemas entry (e.g.,
ToolChoiceString) that defines the enum of allowed string values and update the
oneOf to reference that schema alongside the existing ChatTools ref; ensure the
description is preserved and the oneOf usage reflects disjoint types for correct
validation and SDK typing.

💡 Verification agent

❓ Verification inconclusive

Validate the updated spec and sample payloads

Run a quick spec validation and probe example payloads for the new oneOf branch to avoid regressions.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Validate OpenAPI (Python validator)
pip -q install openapi-spec-validator==0.7.1 prance==23.6.21 >/dev/null

python - <<'PY'
from openapi_spec_validator import validate_spec
from prance import ResolvingParser
import sys, json

spec_path = "src/libs/DeepInfra/openapi.yaml"
parser = ResolvingParser(spec_path, resolve_types=ResolvingParser.RESOLVE_INTERNAL)
validate_spec(parser.specification)
print("OpenAPI spec validated OK")

# Sanity-check the tool_choice schema shape
oc = parser.specification["components"]["schemas"]["OpenAIChatCompletionsIn"]["properties"]["tool_choice"]
print("tool_choice schema keys:", list(oc.keys()))
PY

# 2) Optional: spot-check common generators parse it (no generation, just presence)
rg -nC2 'tool_choice' src/libs/DeepInfra/openapi.yaml || true

Length of output: 686


Validate the updated OpenAPI spec with a YAML-based loader

I’ve adjusted the validation approach to avoid the ResolvingParser API mismatch and directly load the YAML. Please run the following to confirm there are no schema errors and that the new anyOf branch for tool_choice is correctly recognized:

– Verify that the anyOf array includes both the string type and the ChatTools $ref.
– Spot-check any code generators or clients (e.g., your OpenAPI-driven SDKs) to ensure they parse the updated tool_choice property without errors.
– Manually craft and send a sample payload covering each anyOf option (plain string, ChatTools object) to your service endpoint to confirm runtime handling.


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Install validator and YAML parser
pip install -q openapi-spec-validator==0.7.1 pyyaml==6.0 >/dev/null

# Validate the full spec and inspect the tool_choice schema
python3 - <<'PY'
import yaml
from openapi_spec_validator import validate_spec

spec_path = "src/libs/DeepInfra/openapi.yaml"
with open(spec_path, "r") as f:
    spec = yaml.safe_load(f)

# 1) Validate the overall OpenAPI document
validate_spec(spec)
print("✅ OpenAPI spec validated OK")

# 2) Sanity-check the new anyOf branch on tool_choice
tool_choice = spec["components"]["schemas"]["OpenAIChatCompletionsIn"]["properties"]["tool_choice"]
print("tool_choice schema keys:", list(tool_choice.keys()))
print("tool_choice anyOf entries:", tool_choice.get("anyOf"))
PY

Length of output: 1101


Critical: Fix invalid parameter schema in OpenAPI spec

The OpenAPI validation failed due to an invalid cookie parameter definition for session in the /payment/checklist GET operation. The schema uses type: 'String' (capital “S”), which isn’t a valid OpenAPI primitive. It must be lowercase string. Please correct this and re-validate.

• Location to fix (in src/libs/DeepInfra/openapi.yaml):

paths:
  /payment/checklist:
    get:
      parameters:
        - name: session
          in: cookie
          schema:
            type: string    # lowercase “string” instead of “String”

After updating, rerun the validation:

pip install -q openapi-spec-validator pyyaml
python3 - <<'PY'
import yaml
from openapi_spec_validator import validate_spec

spec = yaml.safe_load(open("src/libs/DeepInfra/openapi.yaml"))
validate_spec(spec)
print("✅ OpenAPI spec validated OK")
PY

Once that’s green, you can then proceed to spot-check the new tool_choice anyOf branch and sample payloads.

🤖 Prompt for AI Agents
In src/libs/DeepInfra/openapi.yaml around lines 6401-6404 (and specifically in
the /payment/checklist GET parameters), the cookie parameter "session" uses an
invalid OpenAPI primitive type "String" (capital S); change it to lowercase
"string" in the parameter's schema, save the file, then re-run the OpenAPI
validator (install openapi-spec-validator and pyyaml if needed) and run the
provided python validation snippet to ensure the spec is valid; after
validation, spot-check the new tool_choice anyOf branch and sample payloads for
any remaining schema issues.

nullable: true
response_format:
$ref: '#/components/schemas/ResponseFormat'
Expand Down