Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
0646fa18
authored
Feb 26, 2025
by
1808837298@qq.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: gemini&claude tool call format #795 #766
parent
23de62ec
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
85 additions
and
89 deletions
+85
-89
dto/openai_request.go
+41
-39
dto/openai_response.go
+12
-12
relay/channel/claude/relay-claude.go
+8
-8
relay/channel/gemini/relay-gemini.go
+7
-7
relay/channel/ollama/dto.go
+16
-16
service/token_counter.go
+1
-7
No files found.
dto/openai_request.go
View file @
0646fa18
...
...
@@ -18,50 +18,52 @@ type FormatJsonSchema struct {
}
type
GeneralOpenAIRequest
struct
{
Model
string
`json:"model,omitempty"`
Messages
[]
Message
`json:"messages,omitempty"`
Prompt
any
`json:"prompt,omitempty"`
Prefix
any
`json:"prefix,omitempty"`
Suffix
any
`json:"suffix,omitempty"`
Stream
bool
`json:"stream,omitempty"`
StreamOptions
*
StreamOptions
`json:"stream_options,omitempty"`
MaxTokens
uint
`json:"max_tokens,omitempty"`
MaxCompletionTokens
uint
`json:"max_completion_tokens,omitempty"`
ReasoningEffort
string
`json:"reasoning_effort,omitempty"`
Temperature
*
float64
`json:"temperature,omitempty"`
TopP
float64
`json:"top_p,omitempty"`
TopK
int
`json:"top_k,omitempty"`
Stop
any
`json:"stop,omitempty"`
N
int
`json:"n,omitempty"`
Input
any
`json:"input,omitempty"`
Instruction
string
`json:"instruction,omitempty"`
Size
string
`json:"size,omitempty"`
Functions
any
`json:"functions,omitempty"`
FrequencyPenalty
float64
`json:"frequency_penalty,omitempty"`
PresencePenalty
float64
`json:"presence_penalty,omitempty"`
ResponseFormat
*
ResponseFormat
`json:"response_format,omitempty"`
EncodingFormat
any
`json:"encoding_format,omitempty"`
Seed
float64
`json:"seed,omitempty"`
Tools
[]
ToolCall
`json:"tools,omitempty"`
ToolChoice
any
`json:"tool_choice,omitempty"`
User
string
`json:"user,omitempty"`
LogProbs
bool
`json:"logprobs,omitempty"`
TopLogProbs
int
`json:"top_logprobs,omitempty"`
Dimensions
int
`json:"dimensions,omitempty"`
Modalities
any
`json:"modalities,omitempty"`
Audio
any
`json:"audio,omitempty"`
ExtraBody
any
`json:"extra_body,omitempty"`
Model
string
`json:"model,omitempty"`
Messages
[]
Message
`json:"messages,omitempty"`
Prompt
any
`json:"prompt,omitempty"`
Prefix
any
`json:"prefix,omitempty"`
Suffix
any
`json:"suffix,omitempty"`
Stream
bool
`json:"stream,omitempty"`
StreamOptions
*
StreamOptions
`json:"stream_options,omitempty"`
MaxTokens
uint
`json:"max_tokens,omitempty"`
MaxCompletionTokens
uint
`json:"max_completion_tokens,omitempty"`
ReasoningEffort
string
`json:"reasoning_effort,omitempty"`
Temperature
*
float64
`json:"temperature,omitempty"`
TopP
float64
`json:"top_p,omitempty"`
TopK
int
`json:"top_k,omitempty"`
Stop
any
`json:"stop,omitempty"`
N
int
`json:"n,omitempty"`
Input
any
`json:"input,omitempty"`
Instruction
string
`json:"instruction,omitempty"`
Size
string
`json:"size,omitempty"`
Functions
any
`json:"functions,omitempty"`
FrequencyPenalty
float64
`json:"frequency_penalty,omitempty"`
PresencePenalty
float64
`json:"presence_penalty,omitempty"`
ResponseFormat
*
ResponseFormat
`json:"response_format,omitempty"`
EncodingFormat
any
`json:"encoding_format,omitempty"`
Seed
float64
`json:"seed,omitempty"`
Tools
[]
ToolCall
Request
`json:"tools,omitempty"`
ToolChoice
any
`json:"tool_choice,omitempty"`
User
string
`json:"user,omitempty"`
LogProbs
bool
`json:"logprobs,omitempty"`
TopLogProbs
int
`json:"top_logprobs,omitempty"`
Dimensions
int
`json:"dimensions,omitempty"`
Modalities
any
`json:"modalities,omitempty"`
Audio
any
`json:"audio,omitempty"`
ExtraBody
any
`json:"extra_body,omitempty"`
}
type
OpenAITools
struct
{
Type
string
`json:"type"`
Function
OpenAIFunction
`json:"function"`
type
ToolCallRequest
struct
{
ID
string
`json:"id,omitempty"`
Type
string
`json:"type"`
Function
FunctionRequest
`json:"function"`
}
type
OpenAIFunction
struct
{
type
FunctionRequest
struct
{
Description
string
`json:"description,omitempty"`
Name
string
`json:"name"`
Parameters
any
`json:"parameters,omitempty"`
Arguments
string
`json:"arguments,omitempty"`
}
type
StreamOptions
struct
{
...
...
@@ -137,11 +139,11 @@ func (m *Message) SetPrefix(prefix bool) {
m
.
Prefix
=
&
prefix
}
func
(
m
*
Message
)
ParseToolCalls
()
[]
ToolCall
{
func
(
m
*
Message
)
ParseToolCalls
()
[]
ToolCall
Request
{
if
m
.
ToolCalls
==
nil
{
return
nil
}
var
toolCalls
[]
ToolCall
var
toolCalls
[]
ToolCall
Request
if
err
:=
json
.
Unmarshal
(
m
.
ToolCalls
,
&
toolCalls
);
err
==
nil
{
return
toolCalls
}
...
...
dto/openai_response.go
View file @
0646fa18
...
...
@@ -62,10 +62,10 @@ type ChatCompletionsStreamResponseChoice struct {
}
type
ChatCompletionsStreamResponseChoiceDelta
struct
{
Content
*
string
`json:"content,omitempty"`
ReasoningContent
*
string
`json:"reasoning_content,omitempty"`
Role
string
`json:"role,omitempty"`
ToolCalls
[]
ToolCall
`json:"tool_calls,omitempty"`
Content
*
string
`json:"content,omitempty"`
ReasoningContent
*
string
`json:"reasoning_content,omitempty"`
Role
string
`json:"role,omitempty"`
ToolCalls
[]
ToolCall
Response
`json:"tool_calls,omitempty"`
}
func
(
c
*
ChatCompletionsStreamResponseChoiceDelta
)
SetContentString
(
s
string
)
{
...
...
@@ -90,24 +90,24 @@ func (c *ChatCompletionsStreamResponseChoiceDelta) SetReasoningContent(s string)
c
.
ReasoningContent
=
&
s
}
type
ToolCall
struct
{
type
ToolCall
Response
struct
{
// Index is not nil only in chat completion chunk object
Index
*
int
`json:"index,omitempty"`
ID
string
`json:"id,omitempty"`
Type
any
`json:"type"`
Function
Function
Call
`json:"function"`
Index
*
int
`json:"index,omitempty"`
ID
string
`json:"id,omitempty"`
Type
any
`json:"type"`
Function
Function
Response
`json:"function"`
}
func
(
c
*
ToolCall
)
SetIndex
(
i
int
)
{
func
(
c
*
ToolCall
Response
)
SetIndex
(
i
int
)
{
c
.
Index
=
&
i
}
type
Function
Call
struct
{
type
Function
Response
struct
{
Description
string
`json:"description,omitempty"`
Name
string
`json:"name,omitempty"`
// call function with arguments in JSON format
Parameters
any
`json:"parameters,omitempty"`
// request
Arguments
string
`json:"arguments"`
Arguments
string
`json:"arguments"`
// response
}
type
ChatCompletionsStreamResponse
struct
{
...
...
relay/channel/claude/relay-claude.go
View file @
0646fa18
...
...
@@ -296,7 +296,7 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) (*
response
.
Object
=
"chat.completion.chunk"
response
.
Model
=
claudeResponse
.
Model
response
.
Choices
=
make
([]
dto
.
ChatCompletionsStreamResponseChoice
,
0
)
tools
:=
make
([]
dto
.
ToolCall
,
0
)
tools
:=
make
([]
dto
.
ToolCall
Response
,
0
)
var
choice
dto
.
ChatCompletionsStreamResponseChoice
if
reqMode
==
RequestModeCompletion
{
choice
.
Delta
.
SetContentString
(
claudeResponse
.
Completion
)
...
...
@@ -315,10 +315,10 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) (*
if
claudeResponse
.
ContentBlock
!=
nil
{
//choice.Delta.SetContentString(claudeResponse.ContentBlock.Text)
if
claudeResponse
.
ContentBlock
.
Type
==
"tool_use"
{
tools
=
append
(
tools
,
dto
.
ToolCall
{
tools
=
append
(
tools
,
dto
.
ToolCall
Response
{
ID
:
claudeResponse
.
ContentBlock
.
Id
,
Type
:
"function"
,
Function
:
dto
.
Function
Call
{
Function
:
dto
.
Function
Response
{
Name
:
claudeResponse
.
ContentBlock
.
Name
,
Arguments
:
""
,
},
...
...
@@ -333,8 +333,8 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) (*
choice
.
Delta
.
SetContentString
(
claudeResponse
.
Delta
.
Text
)
switch
claudeResponse
.
Delta
.
Type
{
case
"input_json_delta"
:
tools
=
append
(
tools
,
dto
.
ToolCall
{
Function
:
dto
.
Function
Call
{
tools
=
append
(
tools
,
dto
.
ToolCall
Response
{
Function
:
dto
.
Function
Response
{
Arguments
:
claudeResponse
.
Delta
.
PartialJson
,
},
})
...
...
@@ -382,7 +382,7 @@ func ResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) *dto.Ope
if
len
(
claudeResponse
.
Content
)
>
0
{
responseText
=
claudeResponse
.
Content
[
0
]
.
Text
}
tools
:=
make
([]
dto
.
ToolCall
,
0
)
tools
:=
make
([]
dto
.
ToolCall
Response
,
0
)
thinkingContent
:=
""
if
reqMode
==
RequestModeCompletion
{
...
...
@@ -403,10 +403,10 @@ func ResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) *dto.Ope
switch
message
.
Type
{
case
"tool_use"
:
args
,
_
:=
json
.
Marshal
(
message
.
Input
)
tools
=
append
(
tools
,
dto
.
ToolCall
{
tools
=
append
(
tools
,
dto
.
ToolCall
Response
{
ID
:
message
.
Id
,
Type
:
"function"
,
// compatible with other OpenAI derivative applications
Function
:
dto
.
Function
Call
{
Function
:
dto
.
Function
Response
{
Name
:
message
.
Name
,
Arguments
:
string
(
args
),
},
...
...
relay/channel/gemini/relay-gemini.go
View file @
0646fa18
...
...
@@ -43,7 +43,7 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) (*GeminiChatReque
// openaiContent.FuncToToolCalls()
if
textRequest
.
Tools
!=
nil
{
functions
:=
make
([]
dto
.
Function
Call
,
0
,
len
(
textRequest
.
Tools
))
functions
:=
make
([]
dto
.
Function
Request
,
0
,
len
(
textRequest
.
Tools
))
googleSearch
:=
false
codeExecution
:=
false
for
_
,
tool
:=
range
textRequest
.
Tools
{
...
...
@@ -338,7 +338,7 @@ func unescapeMapOrSlice(data interface{}) interface{} {
return
data
}
func
get
ToolCall
(
item
*
GeminiPart
)
*
dto
.
ToolCall
{
func
get
ResponseToolCall
(
item
*
GeminiPart
)
*
dto
.
ToolCallResponse
{
var
argsBytes
[]
byte
var
err
error
if
result
,
ok
:=
item
.
FunctionCall
.
Arguments
.
(
map
[
string
]
interface
{});
ok
{
...
...
@@ -350,10 +350,10 @@ func getToolCall(item *GeminiPart) *dto.ToolCall {
if
err
!=
nil
{
return
nil
}
return
&
dto
.
ToolCall
{
return
&
dto
.
ToolCall
Response
{
ID
:
fmt
.
Sprintf
(
"call_%s"
,
common
.
GetUUID
()),
Type
:
"function"
,
Function
:
dto
.
Function
Call
{
Function
:
dto
.
Function
Response
{
Arguments
:
string
(
argsBytes
),
Name
:
item
.
FunctionCall
.
FunctionName
,
},
...
...
@@ -380,11 +380,11 @@ func responseGeminiChat2OpenAI(response *GeminiChatResponse) *dto.OpenAITextResp
}
if
len
(
candidate
.
Content
.
Parts
)
>
0
{
var
texts
[]
string
var
toolCalls
[]
dto
.
ToolCall
var
toolCalls
[]
dto
.
ToolCall
Response
for
_
,
part
:=
range
candidate
.
Content
.
Parts
{
if
part
.
FunctionCall
!=
nil
{
choice
.
FinishReason
=
constant
.
FinishReasonToolCalls
if
call
:=
getToolCall
(
&
part
);
call
!=
nil
{
if
call
:=
get
Response
ToolCall
(
&
part
);
call
!=
nil
{
toolCalls
=
append
(
toolCalls
,
*
call
)
}
}
else
{
...
...
@@ -457,7 +457,7 @@ func streamResponseGeminiChat2OpenAI(geminiResponse *GeminiChatResponse) (*dto.C
for
_
,
part
:=
range
candidate
.
Content
.
Parts
{
if
part
.
FunctionCall
!=
nil
{
isTools
=
true
if
call
:=
getToolCall
(
&
part
);
call
!=
nil
{
if
call
:=
get
Response
ToolCall
(
&
part
);
call
!=
nil
{
call
.
SetIndex
(
len
(
choice
.
Delta
.
ToolCalls
))
choice
.
Delta
.
ToolCalls
=
append
(
choice
.
Delta
.
ToolCalls
,
*
call
)
}
...
...
relay/channel/ollama/dto.go
View file @
0646fa18
...
...
@@ -3,22 +3,22 @@ package ollama
import
"one-api/dto"
type
OllamaRequest
struct
{
Model
string
`json:"model,omitempty"`
Messages
[]
dto
.
Message
`json:"messages,omitempty"`
Stream
bool
`json:"stream,omitempty"`
Temperature
*
float64
`json:"temperature,omitempty"`
Seed
float64
`json:"seed,omitempty"`
Topp
float64
`json:"top_p,omitempty"`
TopK
int
`json:"top_k,omitempty"`
Stop
any
`json:"stop,omitempty"`
MaxTokens
uint
`json:"max_tokens,omitempty"`
Tools
[]
dto
.
ToolCall
`json:"tools,omitempty"`
ResponseFormat
any
`json:"response_format,omitempty"`
FrequencyPenalty
float64
`json:"frequency_penalty,omitempty"`
PresencePenalty
float64
`json:"presence_penalty,omitempty"`
Suffix
any
`json:"suffix,omitempty"`
StreamOptions
*
dto
.
StreamOptions
`json:"stream_options,omitempty"`
Prompt
any
`json:"prompt,omitempty"`
Model
string
`json:"model,omitempty"`
Messages
[]
dto
.
Message
`json:"messages,omitempty"`
Stream
bool
`json:"stream,omitempty"`
Temperature
*
float64
`json:"temperature,omitempty"`
Seed
float64
`json:"seed,omitempty"`
Topp
float64
`json:"top_p,omitempty"`
TopK
int
`json:"top_k,omitempty"`
Stop
any
`json:"stop,omitempty"`
MaxTokens
uint
`json:"max_tokens,omitempty"`
Tools
[]
dto
.
ToolCall
Request
`json:"tools,omitempty"`
ResponseFormat
any
`json:"response_format,omitempty"`
FrequencyPenalty
float64
`json:"frequency_penalty,omitempty"`
PresencePenalty
float64
`json:"presence_penalty,omitempty"`
Suffix
any
`json:"suffix,omitempty"`
StreamOptions
*
dto
.
StreamOptions
`json:"stream_options,omitempty"`
Prompt
any
`json:"prompt,omitempty"`
}
type
Options
struct
{
...
...
service/token_counter.go
View file @
0646fa18
package
service
import
(
"encoding/json"
"errors"
"fmt"
"image"
...
...
@@ -170,12 +169,7 @@ func CountTokenChatRequest(info *relaycommon.RelayInfo, request dto.GeneralOpenA
}
tkm
+=
msgTokens
if
request
.
Tools
!=
nil
{
toolsData
,
_
:=
json
.
Marshal
(
request
.
Tools
)
var
openaiTools
[]
dto
.
OpenAITools
err
:=
json
.
Unmarshal
(
toolsData
,
&
openaiTools
)
if
err
!=
nil
{
return
0
,
errors
.
New
(
fmt
.
Sprintf
(
"count_tools_token_fail: %s"
,
err
.
Error
()))
}
openaiTools
:=
request
.
Tools
countStr
:=
""
for
_
,
tool
:=
range
openaiTools
{
countStr
=
tool
.
Function
.
Name
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment