Files
picoclaw/pkg/providers/claude_provider.go
T

153 lines
3.9 KiB
Go

package providers
import (
"context"
"fmt"
"github.com/sipeed/picoclaw/pkg/auth"
anthropicprovider "github.com/sipeed/picoclaw/pkg/providers/anthropic"
)
type ClaudeProvider struct {
delegate *anthropicprovider.Provider
}
func NewClaudeProvider(token string) *ClaudeProvider {
return &ClaudeProvider{
delegate: anthropicprovider.NewProvider(token),
}
}
func NewClaudeProviderWithTokenSource(token string, tokenSource func() (string, error)) *ClaudeProvider {
return &ClaudeProvider{
delegate: anthropicprovider.NewProviderWithTokenSource(token, tokenSource),
}
}
func newClaudeProviderWithDelegate(delegate *anthropicprovider.Provider) *ClaudeProvider {
return &ClaudeProvider{delegate: delegate}
}
func (p *ClaudeProvider) Chat(ctx context.Context, messages []Message, tools []ToolDefinition, model string, options map[string]interface{}) (*LLMResponse, error) {
resp, err := p.delegate.Chat(
ctx,
toAnthropicProviderMessages(messages),
toAnthropicProviderTools(tools),
model,
options,
)
if err != nil {
return nil, err
}
return fromAnthropicProviderResponse(resp), nil
}
func (p *ClaudeProvider) GetDefaultModel() string {
return p.delegate.GetDefaultModel()
}
func createClaudeTokenSource() func() (string, error) {
return func() (string, error) {
cred, err := auth.GetCredential("anthropic")
if err != nil {
return "", fmt.Errorf("loading auth credentials: %w", err)
}
if cred == nil {
return "", fmt.Errorf("no credentials for anthropic. Run: picoclaw auth login --provider anthropic")
}
return cred.AccessToken, nil
}
}
func toAnthropicProviderMessages(messages []Message) []anthropicprovider.Message {
out := make([]anthropicprovider.Message, 0, len(messages))
for _, msg := range messages {
out = append(out, anthropicprovider.Message{
Role: msg.Role,
Content: msg.Content,
ToolCalls: toAnthropicProviderToolCalls(msg.ToolCalls),
ToolCallID: msg.ToolCallID,
})
}
return out
}
func toAnthropicProviderTools(tools []ToolDefinition) []anthropicprovider.ToolDefinition {
out := make([]anthropicprovider.ToolDefinition, 0, len(tools))
for _, t := range tools {
out = append(out, anthropicprovider.ToolDefinition{
Type: t.Type,
Function: anthropicprovider.ToolFunctionDefinition{
Name: t.Function.Name,
Description: t.Function.Description,
Parameters: t.Function.Parameters,
},
})
}
return out
}
func toAnthropicProviderToolCalls(toolCalls []ToolCall) []anthropicprovider.ToolCall {
out := make([]anthropicprovider.ToolCall, 0, len(toolCalls))
for _, tc := range toolCalls {
var fn *anthropicprovider.FunctionCall
if tc.Function != nil {
fn = &anthropicprovider.FunctionCall{
Name: tc.Function.Name,
Arguments: tc.Function.Arguments,
}
}
out = append(out, anthropicprovider.ToolCall{
ID: tc.ID,
Type: tc.Type,
Function: fn,
Name: tc.Name,
Arguments: tc.Arguments,
})
}
return out
}
func fromAnthropicProviderResponse(resp *anthropicprovider.LLMResponse) *LLMResponse {
if resp == nil {
return &LLMResponse{}
}
var usage *UsageInfo
if resp.Usage != nil {
usage = &UsageInfo{
PromptTokens: resp.Usage.PromptTokens,
CompletionTokens: resp.Usage.CompletionTokens,
TotalTokens: resp.Usage.TotalTokens,
}
}
return &LLMResponse{
Content: resp.Content,
ToolCalls: fromAnthropicProviderToolCalls(resp.ToolCalls),
FinishReason: resp.FinishReason,
Usage: usage,
}
}
func fromAnthropicProviderToolCalls(toolCalls []anthropicprovider.ToolCall) []ToolCall {
out := make([]ToolCall, 0, len(toolCalls))
for _, tc := range toolCalls {
var fn *FunctionCall
if tc.Function != nil {
fn = &FunctionCall{
Name: tc.Function.Name,
Arguments: tc.Function.Arguments,
}
}
out = append(out, ToolCall{
ID: tc.ID,
Type: tc.Type,
Function: fn,
Name: tc.Name,
Arguments: tc.Arguments,
})
}
return out
}