mirror of
https://github.com/mudler/LocalAI.git
synced 2026-02-12 04:59:25 -06:00
* Initial plan * Add Anthropic Messages API support Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> * Fix code review comments: add error handling for JSON operations Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> * Fix test suite to use existing schema test runner Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> * Add Anthropic e2e tests using anthropic-sdk-go for streaming and non-streaming Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> * Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mudler <2420543+mudler@users.noreply.github.com>
164 lines
5.4 KiB
Go
164 lines
5.4 KiB
Go
package schema
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
)
|
|
|
|
// AnthropicRequest represents a request to the Anthropic Messages API
|
|
// https://docs.anthropic.com/claude/reference/messages_post
|
|
type AnthropicRequest struct {
|
|
Model string `json:"model"`
|
|
Messages []AnthropicMessage `json:"messages"`
|
|
MaxTokens int `json:"max_tokens"`
|
|
Metadata map[string]string `json:"metadata,omitempty"`
|
|
StopSequences []string `json:"stop_sequences,omitempty"`
|
|
Stream bool `json:"stream,omitempty"`
|
|
System string `json:"system,omitempty"`
|
|
Temperature *float64 `json:"temperature,omitempty"`
|
|
TopK *int `json:"top_k,omitempty"`
|
|
TopP *float64 `json:"top_p,omitempty"`
|
|
|
|
// Internal fields for request handling
|
|
Context context.Context `json:"-"`
|
|
Cancel context.CancelFunc `json:"-"`
|
|
}
|
|
|
|
// ModelName implements the LocalAIRequest interface
|
|
func (ar *AnthropicRequest) ModelName(s *string) string {
|
|
if s != nil {
|
|
ar.Model = *s
|
|
}
|
|
return ar.Model
|
|
}
|
|
|
|
// AnthropicMessage represents a message in the Anthropic format
|
|
type AnthropicMessage struct {
|
|
Role string `json:"role"`
|
|
Content interface{} `json:"content"`
|
|
}
|
|
|
|
// AnthropicContentBlock represents a content block in an Anthropic message
|
|
type AnthropicContentBlock struct {
|
|
Type string `json:"type"`
|
|
Text string `json:"text,omitempty"`
|
|
Source *AnthropicImageSource `json:"source,omitempty"`
|
|
ID string `json:"id,omitempty"`
|
|
Name string `json:"name,omitempty"`
|
|
Input map[string]interface{} `json:"input,omitempty"`
|
|
}
|
|
|
|
// AnthropicImageSource represents an image source in Anthropic format
|
|
type AnthropicImageSource struct {
|
|
Type string `json:"type"`
|
|
MediaType string `json:"media_type"`
|
|
Data string `json:"data"`
|
|
}
|
|
|
|
// AnthropicResponse represents a response from the Anthropic Messages API
|
|
type AnthropicResponse struct {
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
Role string `json:"role"`
|
|
Content []AnthropicContentBlock `json:"content"`
|
|
Model string `json:"model"`
|
|
StopReason *string `json:"stop_reason"`
|
|
StopSequence *string `json:"stop_sequence,omitempty"`
|
|
Usage AnthropicUsage `json:"usage"`
|
|
}
|
|
|
|
// AnthropicUsage represents token usage in Anthropic format
|
|
type AnthropicUsage struct {
|
|
InputTokens int `json:"input_tokens"`
|
|
OutputTokens int `json:"output_tokens"`
|
|
}
|
|
|
|
// AnthropicStreamEvent represents a streaming event from the Anthropic API
|
|
type AnthropicStreamEvent struct {
|
|
Type string `json:"type"`
|
|
Index int `json:"index,omitempty"`
|
|
ContentBlock *AnthropicContentBlock `json:"content_block,omitempty"`
|
|
Delta *AnthropicStreamDelta `json:"delta,omitempty"`
|
|
Message *AnthropicStreamMessage `json:"message,omitempty"`
|
|
Usage *AnthropicUsage `json:"usage,omitempty"`
|
|
}
|
|
|
|
// AnthropicStreamDelta represents the delta in a streaming response
|
|
type AnthropicStreamDelta struct {
|
|
Type string `json:"type,omitempty"`
|
|
Text string `json:"text,omitempty"`
|
|
StopReason *string `json:"stop_reason,omitempty"`
|
|
StopSequence *string `json:"stop_sequence,omitempty"`
|
|
}
|
|
|
|
// AnthropicStreamMessage represents the message object in streaming events
|
|
type AnthropicStreamMessage struct {
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
Role string `json:"role"`
|
|
Content []AnthropicContentBlock `json:"content"`
|
|
Model string `json:"model"`
|
|
StopReason *string `json:"stop_reason"`
|
|
StopSequence *string `json:"stop_sequence,omitempty"`
|
|
Usage AnthropicUsage `json:"usage"`
|
|
}
|
|
|
|
// AnthropicErrorResponse represents an error response from the Anthropic API
|
|
type AnthropicErrorResponse struct {
|
|
Type string `json:"type"`
|
|
Error AnthropicError `json:"error"`
|
|
}
|
|
|
|
// AnthropicError represents an error in the Anthropic format
|
|
type AnthropicError struct {
|
|
Type string `json:"type"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// GetStringContent extracts the string content from an AnthropicMessage
|
|
// Content can be either a string or an array of content blocks
|
|
func (m *AnthropicMessage) GetStringContent() string {
|
|
switch content := m.Content.(type) {
|
|
case string:
|
|
return content
|
|
case []interface{}:
|
|
var result string
|
|
for _, block := range content {
|
|
if blockMap, ok := block.(map[string]interface{}); ok {
|
|
if blockMap["type"] == "text" {
|
|
if text, ok := blockMap["text"].(string); ok {
|
|
result += text
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetContentBlocks extracts content blocks from an AnthropicMessage
|
|
func (m *AnthropicMessage) GetContentBlocks() []AnthropicContentBlock {
|
|
switch content := m.Content.(type) {
|
|
case string:
|
|
return []AnthropicContentBlock{{Type: "text", Text: content}}
|
|
case []interface{}:
|
|
var blocks []AnthropicContentBlock
|
|
for _, block := range content {
|
|
if blockMap, ok := block.(map[string]interface{}); ok {
|
|
cb := AnthropicContentBlock{}
|
|
data, err := json.Marshal(blockMap)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if err := json.Unmarshal(data, &cb); err != nil {
|
|
continue
|
|
}
|
|
blocks = append(blocks, cb)
|
|
}
|
|
}
|
|
return blocks
|
|
}
|
|
return nil
|
|
}
|