Files
picoclaw/pkg/providers/http_provider.go
T

131 lines
3.3 KiB
Go

// PicoClaw - Ultra-lightweight personal AI agent
// Inspired by and based on nanobot: https://github.com/HKUDS/nanobot
// License: MIT
//
// Copyright (c) 2026 PicoClaw contributors
package providers
import (
"context"
"github.com/sipeed/picoclaw/pkg/providers/openai_compat"
)
type HTTPProvider struct {
delegate *openai_compat.Provider
}
func NewHTTPProvider(apiKey, apiBase string, proxy ...string) *HTTPProvider {
proxyURL := ""
if len(proxy) > 0 {
proxyURL = proxy[0]
}
return &HTTPProvider{
delegate: openai_compat.NewProvider(apiKey, apiBase, proxyURL),
}
}
func (p *HTTPProvider) Chat(ctx context.Context, messages []Message, tools []ToolDefinition, model string, options map[string]interface{}) (*LLMResponse, error) {
compatResp, err := p.delegate.Chat(ctx, toOpenAICompatMessages(messages), toOpenAICompatTools(tools), model, options)
if err != nil {
return nil, err
}
return fromOpenAICompatResponse(compatResp), nil
}
func (p *HTTPProvider) GetDefaultModel() string {
return ""
}
func toOpenAICompatMessages(messages []Message) []openai_compat.Message {
out := make([]openai_compat.Message, 0, len(messages))
for _, msg := range messages {
out = append(out, openai_compat.Message{
Role: msg.Role,
Content: msg.Content,
ToolCalls: toOpenAICompatToolCalls(msg.ToolCalls),
ToolCallID: msg.ToolCallID,
})
}
return out
}
func toOpenAICompatTools(tools []ToolDefinition) []openai_compat.ToolDefinition {
out := make([]openai_compat.ToolDefinition, 0, len(tools))
for _, t := range tools {
out = append(out, openai_compat.ToolDefinition{
Type: t.Type,
Function: openai_compat.ToolFunctionDefinition{
Name: t.Function.Name,
Description: t.Function.Description,
Parameters: t.Function.Parameters,
},
})
}
return out
}
func toOpenAICompatToolCalls(toolCalls []ToolCall) []openai_compat.ToolCall {
out := make([]openai_compat.ToolCall, 0, len(toolCalls))
for _, tc := range toolCalls {
var fn *openai_compat.FunctionCall
if tc.Function != nil {
fn = &openai_compat.FunctionCall{
Name: tc.Function.Name,
Arguments: tc.Function.Arguments,
}
}
out = append(out, openai_compat.ToolCall{
ID: tc.ID,
Type: tc.Type,
Function: fn,
Name: tc.Name,
Arguments: tc.Arguments,
})
}
return out
}
func fromOpenAICompatResponse(resp *openai_compat.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: fromOpenAICompatToolCalls(resp.ToolCalls),
FinishReason: resp.FinishReason,
Usage: usage,
}
}
func fromOpenAICompatToolCalls(toolCalls []openai_compat.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
}