@@ -21,6 +21,7 @@ import (
2121 "fmt"
2222
2323 openaiserverapi "github.com/llm-d/llm-d-inference-sim/pkg/openai-server-api"
24+ "github.com/openai/openai-go/v3/packages/param"
2425 "github.com/santhosh-tekuri/jsonschema/v5"
2526)
2627
@@ -52,24 +53,88 @@ var fakeStringArguments = []string{
5253 `lifetime` ,
5354}
5455
55- // CreateToolCalls creates and returns response payload based on this request
56- // (tool calls or nothing in case we randomly choose not to generate calls),
57- // and the number of generated completion token sand the finish reason
58- func CreateToolCalls (tools []openaiserverapi.Tool , toolChoice string , config * Configuration ) ([]openaiserverapi.ToolCall , int , error ) {
59- // This function is called if tool choice is either 'required' or 'auto'.
60- // In case of 'required' at least one tool call has to be created, and we randomly choose
61- // the number of calls starting from one. Otherwise, we start from 0, and in case we randomly
62- // choose the number of calls to be 0, response text will be generated instead of a tool call.
56+ // IsToolChoiceNone checks if the tool_choice is set to "none".
57+ func IsToolChoiceNone (toolChoice openaiserverapi.ToolChoice ) bool {
58+ if ! param .IsOmitted (toolChoice .OfAuto ) {
59+ val := toolChoice .OfAuto .Or ("" )
60+ return val == ToolChoiceNone
61+ }
62+ return false
63+ }
64+
65+ // CreateToolCalls creates and returns tool calls based on the request's tool
66+ // definitions and tool_choice parameter.
67+ // The tool_choice parameter controls how the model responds to function calls:
68+ // - "none": The model does not call any tools. This case should be handled
69+ // before calling this function.
70+ // - "auto": The model can choose to either generate a message or call one or
71+ // more tools. This is the default behavior.
72+ // - "required": The model must call one or more tools.
73+ // - Specific function: A specific tool can be forced by providing an object
74+ // like `{"type": "function", "function": {"name": "my_function"}}`. The
75+ // model will be constrained to call that exact tool.
76+ //
77+ // This function returns the generated tool calls, the number of completion
78+ // tokens used, and an error if one occurs (e.g., if a specified tool is not found).
79+ func CreateToolCalls (
80+ tools []openaiserverapi.Tool ,
81+ toolChoice openaiserverapi.ToolChoice ,
82+ config * Configuration ,
83+ ) ([]openaiserverapi.ToolCall , int , error ) {
84+ // If a specific function is required.
85+ if functionChoice := toolChoice .GetFunction (); functionChoice != nil {
86+ requiredFuncName := functionChoice .Name
87+ var targetTool * openaiserverapi.Tool
88+
89+ // Find the specified tool in the list of available tools.
90+ for i , tool := range tools {
91+ if tool .Function .Name == requiredFuncName {
92+ targetTool = & tools [i ]
93+ break
94+ }
95+ }
96+
97+ if targetTool == nil {
98+ return nil , 0 , fmt .Errorf ("tool with name '%s' requested in tool_choice but not found in the tools list" , requiredFuncName )
99+ }
100+
101+ // Generate arguments for the specific tool.
102+ args , err := generateToolArguments (* targetTool , config )
103+ if err != nil {
104+ return nil , 0 , err
105+ }
106+ argsJson , err := json .Marshal (args )
107+ if err != nil {
108+ return nil , 0 , err
109+ }
110+
111+ call := openaiserverapi.ToolCall {
112+ Function : openaiserverapi.FunctionCall {
113+ Arguments : string (argsJson ),
114+ TokenizedArguments : Tokenize (string (argsJson )),
115+ Name : & targetTool .Function .Name ,
116+ },
117+ ID : "chatcmpl-tool-" + RandomNumericString (10 ),
118+ Type : "function" ,
119+ Index : 0 ,
120+ }
121+ calls := []openaiserverapi.ToolCall {call }
122+ return calls , CountTokensForToolCalls (calls ), nil
123+ }
124+
125+ // Tool choice is 'auto' or 'required'.
126+ // In 'required' mode, at least one tool call must be created.
127+ // In 'auto' mode, the number of calls can be zero, leading to a text response instead.
63128 min := 0
64- if toolChoice == ToolChoiceRequired {
129+ if ! param . IsOmitted ( toolChoice . OfAuto ) && toolChoice . OfAuto . Or ( "" ) == ToolChoiceRequired {
65130 min = 1
66131 }
67132 numberOfCalls := RandomInt (min , len (tools ))
68133 if numberOfCalls == 0 {
69134 return nil , 0 , nil
70135 }
71136
72- calls := make ([]openaiserverapi.ToolCall , 0 )
137+ calls := make ([]openaiserverapi.ToolCall , 0 , numberOfCalls )
73138 for i := range numberOfCalls {
74139 // Randomly choose which tools to call. We may call the same tool more than once.
75140 index := RandomInt (0 , len (tools )- 1 )
0 commit comments