claude-haskell is an unofficial binding for Anthropic's Claude API. This project has not been reviewed or published as an official package.
This library provides Haskell functions to interact with the Claude API, including sending text messages, images, pdf documents, listing and retrieving model information, and create message batches. It includes utilities and types for building API requests and handling responses.
- Installation
- Usage
- Modules
- ClaudeAPI.Config
- ClaudeAPI.Chat
- ClaudeAPI.MessageBatches
- ClaudeAPI.Models
- ClaudeAPI.Types
- JSONResponse: parseResponse
- MediaSource
- RequestMessageContent
- RequestMessage
- ChatRequest
- ResponseMessage
- ChatResponse
- Usage
- ModelRequest
- ModelResponse
- CountTokenRequest
- CountTokenResponse
- MessageBatchRequest
- MessageBatchRequests
- MessageBatchRequestCount
- MessageBatchResponse
- ListMessageBatchRequest
- ListMessageBatchResponse
- MessageBatchResult
- RetrieveMessageBatchResult
- RetrieveMessageBatchResults
- ClaudeAPI.Utils
- Testing
- Contributing
- License
-
Create a new file
cabal.project
in the root directory of your cabal projectnew-project ├── CHANGELOG.md ├── LICENSE ├── app │ └── Main.hs ├── cabal.project └── new-project.cabal
-
Add claude-haskell as a package in
cabal.project
:source-repository-package type: git location: https://github.com/T0mLam/claude-haskell.git packages: ./<filename>.cabal
-
Update the
.cabal
configurations-- Other library packages from which modules are imported. build-depends: base ^>=4.17.2.1, claude-haskell
-
Set the API key and Anthropic version in the environment (
.env
) file:new-project ├── CHANGELOG.md ├── LICENSE ├── app │ └── Main.hs ├── cabal.project ├── .env # Create a new environment file └── new-project.cabal
.env
API_KEY=<api_key> ANTHROPIC_VERSION=<anthropic_version> # e.g. 2023-06-01
Below is a guide to the key functionalities and corresponding functions.
chat
defaultChatRequest
defaultIOMediaChatRequest
ChatRequest
chat :: ChatRequest -> IO (Either String ChatResponse)
defaultChatRequest
:: String -- Text message
-> ChatRequest
defaultIOMediaChatRequest
:: FilePath -- File path (i.e. local, URL)
-> String -- Instructions
-> IO (Either String ChatRequest)
data ChatRequest = ChatRequest
{ model :: String
, messages :: [RequestMessage]
, max_tokens :: Int
, stop_sequences :: Maybe String
, stream :: Maybe Bool
, system :: Maybe String
, temperature :: Maybe Double
}
Example:
Send text messages
main :: IO ()
main = do
-- Make a chat request to Claude
chatResponse <- chat $ defaultChatRequest "Where is the capital of China?"
case chatResponse of
Left err -> putStrLn $ "Error: " ++ err
Right resp -> do
-- Extract the message from the ChatResponse object
let botReply = responseText $ head $ responseContent resp
putStrLn $ "Bot: " ++ botReply
Send images or PDF documents
main :: IO ()
main = do
let imagePath = "https://thumbs.dreamstime.com/b/red-apple-isolated-clipping-path-19130134.jpg"
let instructions = "What is in this image?"
-- Encode the image into base64 format
result <- defaultIOImageChatRequest imagePath instructions
case result of
Left err -> return $ Left err
Right chatRequest -> do
-- Make a chat request to Claude
chatReponse <- chat chatRequest
case chatResponse of
Left err -> putStrLn $ "Error: " ++ err
Right resp -> do
-- Extract the message from the ChatResponse object
let botReply = responseText $ head $ responseContent resp
putStrLn $ "Bot: " ++ botReply
chatBot :: IO ()
Example:
main :: IO ()
main = chatBot
ghci> chatBot
Enter your first message (or type 'QUIT' to exit)
Claude:
-------
Hi! I'm happy to chat with you. How can I help?
You:
----
Where is the capital of China?
Claude:
-------
The capital of China is Beijing (formerly known as Peking). It has been China's capital city since 1949 when the People's Republic of China was established. Beijing is located in the northern part of the country and is one of China's four direct-administered municipalities.
You:
----
MEDIA: https://thumbs.dreamstime.com/b/red-apple-isolated-clipping-path-19130134.jpg
Instructions: What is in the image?
Claude:
-------
This image shows a fresh, bright red apple with a green leaf still attached to its stem. The apple appears to be a Red Delicious variety, given its deep red color and characteristic shape. The apple looks perfectly ripe and has a glossy, smooth skin with tiny light spots typical of this fruit. The image is shot against a pure white background, making the apple stand out clearly. The leaf appears fresh and vibrant green, showing the apple is recently picked or very fresh.
countToken
defaultCountTokenRequest
CountTokenRequest
countToken :: CountTokenRequest -> IO (Either String CountTokenResponse)
defaultCountTokenRequest :: String -> CountTokenRequest
data CountTokenRequest = CountTokenRequest
{ requestMessages :: [RequestMessage]
, model :: String
, system :: Maybe String
}
Example:
main :: IO ()
main = do
countTokenResp <- countToken $ defaultCountTokenRequest "Hello Claude"
case countTokenResp of
Left err -> putStrLn $ "Error: " ++ err
Right resp -> do
let tokenCount = inputTokens resp
putStrLn $ "Token count: " ++ tokenCount
Notes:
Create custom CountTokenRequest
for counting tokens for media requests.
listModels
defaultModelRequest
listModels :: ModelRequest -> IO (Either String ModelResponse)
defaultModelRequest :: ModelRequest
getModel :: String -> IO (Either String ModelData)
createMessageBatch
retrieveMessageBatch
listMessageBatch
cancelMessageBatch
retrieveMessageBatchResults
createMessageBatch
:: MessageBatchRequests
-> IO (Either String MessageBatchResponse)
retrieveMessageBatch
:: String -- Message batch ID, e.g. msg_...
-> IO (Either String MessageBatchResponse)
listMessageBatch
:: ListMessageBatchRequest
-> IO (Either String ListMessageBatchResponse)
cancelMessageBatch
:: String -- Message batch ID, e.g. msg_...
-> IO (Either String MessageBatchResponse)
retrieveMessageBatchResults
:: String -- Message batch ID, e.g. msg_...
-> IO (Either String RetrieveMessageBatchResults)
sendRequest
:: (ToJSON req, JSONResponse resp)
=> String -- request method
-> String -- endpoint
-> Maybe req
-> IO (Either String resp)
Example:
data ExampleReq = ExampleReq {...}
deriving (Show, Generic, ToJson)
-- JSONResponse is a subclass of FromJSON,
-- which determines how the content is decoded
-- to the data object (default=Data.Aeson.eitherDecode)
data ExampleResp = ExampleResp {...}
deriving (Show, Generic, JSONResponse)
exampleFunc :: ExampleReq -> IO (Either String ExampleResp)
exampleFunc req = sendRequest "POST" "/v1/messages" (Just req)
This module defines configuration constants for interacting with the Claude API, including the base URL and default model.
The base URL for the Claude API.
baseUrl :: String
- Description: Specifies the root endpoint for the API.
- Value:
"https://api.anthropic.com"
The default model to be used for requests to the Claude API.
defaultModel :: String
- Description: Specifies the default Claude model version for API calls.
- Value:
"claude-3-5-sonnet-20241022"
This module provides functionality for interacting with the Claude API to send messages, handle chat requests, and manage image-based requests.
Creates a default ChatRequest
with a specified message from the user. The model used is claude-3-5-sonnet-20241022
.
Type:
defaultChatRequest :: String -> ChatRequest
Example:
let req = defaultChatRequest "Hi Claude."
Sends a request to the Claude API using the specified HTTP method, endpoint, and request body.
Type:
sendRequest :: (ToJSON req, JSONResponse resp) => String -> String -> Maybe req -> IO (Either String resp)
Parameters:
requestMethod
: The HTTP method (e.g., "POST").endpoint
: The API endpoint (e.g., "/v1/messages").chatReq
: The request body, encoded as JSON.
Example:
resp <- sendRequest "POST" "/v1/messages" (Just myChatRequest)
Sends a chat request to the Claude API and returns a ChatResponse
.
Type:
chat :: ChatRequest -> IO (Either String ChatResponse)
Example:
let req = defaultChatRequest "Hello, Claude!"
resp <- chat req
Adds a new message to an existing ChatRequest
.
Type:
addMessageToChatRequest :: String -> String -> ChatRequest -> ChatRequest
Parameters:
r
: Role of the message sender (e.g., "user").m
: The message content.req
: The existingChatRequest
.
Example:
let updatedReq = addMessageToChatRequest "user" "Another message" req
Adds a response message to an existing ChatRequest
.
Type:
addResponseToChatRequest :: ChatRequest -> ChatResponse -> ChatRequest
Parameters:
req
: The existingChatRequest
.resp
: TheChatResponse
to extract the response message from.
Example:
let updatedReq = addResponseToChatRequest req chatResp
Creates a default CountTokenRequest
to estimate the token count for a given input.
Type:
defaultCountTokenRequest :: String -> CountTokenRequest
Example:
let tokenReq = defaultCountTokenRequest "Estimate token count for this text."
Sends a token count request to the Claude API.
Type:
countToken :: CountTokenRequest -> IO (Either String CountTokenResponse)
Example:
let req = defaultCountTokenRequest "Test string for token count."
resp <- countToken req
Encodes a media file (local or remote) to a Base64 string for use in requests.
Type:
encodeMediaToBase64 :: String -> IO (Either String Text)
Parameters:
mediaPath
: Path to the media file or URL.
Example:
encodedMedia <- encodeMediaToBase64 "path/to/image.jpg"
Creates a default ChatRequest
for media files (e.g., images or documents).
Type:
defaultIOMediaChatRequest :: FilePath -> String -> IO (Either String ChatRequest)
Parameters:
mediaPath
: Path to the media file.message
: Associated text message.
Example:
req <- defaultIOMediaChatRequest "path/to/image.jpg" "Describe this image."
Adds a media file and its associated message to an existing ChatRequest
.
Type:
addMediaToChatRequest :: String -> String -> ChatRequest -> IO (Either String ChatRequest)
Parameters:
mediaPath
: Path to the media file.message
: Associated text message.req
: The existingChatRequest
.
Example:
let req = defaultChatRequest "Initial message."
updatedReq <- addMediaToChatRequest "path/to/image.jpg" "Analyze this image" req
A simple interactive chatbot that communicates with the Claude API. It supports media uploads and maintains chat history.
Type:
chatBot :: IO ()
Usage: Run the function in the terminal to start the chatbot.
Example:
main :: IO ()
main = chatBot
This module provides functionality to manage message batches in the Claude API, including creating, retrieving, listing, and canceling message batches, as well as retrieving their results.
Creates a new message batch by sending a MessageBatchRequests
object to the Claude API.
Type:
createMessageBatch :: MessageBatchRequests -> IO (Either String MessageBatchResponse)
Example:
let batchRequest = MessageBatchRequests { ... }
response <- createMessageBatch batchRequest
case response of
Left err -> putStrLn $ "Error: " ++ err
Right result -> print result
Retrieves details of a specific message batch by its ID.
Type:
retrieveMessageBatch :: String -> IO (Either String MessageBatchResponse)
Example:
response <- retrieveMessageBatch "batch-id-1234"
case response of
Left err -> putStrLn $ "Error: " ++ err
Right batch -> print batch
Lists message batches based on the provided filtering and pagination parameters encapsulated in a ListMessageBatchRequest
.
Type:
listMessageBatch :: ListMessageBatchRequest -> IO (Either String ListMessageBatchResponse)
Example:
let listRequest = ListMessageBatchRequest { beforeID = Just "batch-id-5678", afterID = Nothing, limit = Just 10 }
response <- listMessageBatch listRequest
case response of
Left err -> putStrLn $ "Error: " ++ err
Right batches -> print batches
Cancels a specific message batch by its ID.
Type:
cancelMessageBatch :: String -> IO (Either String MessageBatchResponse)
Example:
response <- cancelMessageBatch "batch-id-1234"
case response of
Left err -> putStrLn $ "Error: " ++ err
Right result -> print result
Retrieves the results of a specific message batch by its ID.
Type:
retrieveMessageBatchResults :: String -> IO (Either String RetrieveMessageBatchResults)
Example:
response <- retrieveMessageBatchResults "batch-id-1234"
case response of
Left err -> putStrLn $ "Error: " ++ err
Right results -> print results
Defines how query parameters for ListMessageBatchRequest
are handled to build a query string for the API.
Methods:
getBeforeID
: Retrieves thebeforeID
parameter.getAfterID
: Retrieves theafterID
parameter.getLimit
: Retrieves thelimit
parameter.
Usage:
instance HasQueryParams ListMessageBatchRequest where
getBeforeID = beforeID
getAfterID = afterID
getLimit = limit
This module provides functionality for interacting with the Claude API to manage and retrieve model information, such as listing available models and retrieving details about a specific model.
A default ModelRequest
instance with no filters applied.
Type:
defaultModelRequest :: ModelRequest
Description:
- Creates a
ModelRequest
object with default parameters: nobeforeID
,afterID
, orlimit
specified.
Example:
let req = defaultModelRequest
Retrieves a list of models available via the Claude API.
Type:
listModels :: ModelRequest -> IO (Either String ModelResponse)
Parameters:
ModelRequest
: A request object specifying optional filters (beforeID
,afterID
, andlimit
).
Returns:
- Either an error message (
String
) or aModelResponse
object containing the list of available models.
Example:
let req = defaultModelRequest { limit = Just 10 }
response <- listModels req
case response of
Left err -> putStrLn $ "Error: " ++ err
Right models -> print models
Retrieves detailed information about a specific model.
Type:
getModel :: String -> IO (Either String ModelData)
Parameters:
modelId
: AString
representing the unique identifier of the model.
Returns:
- Either an error message (
String
) or aModelData
object containing details about the specified model.
Example:
response <- getModel "claude-v1"
case response of
Left err -> putStrLn $ "Error: " ++ err
Right modelData -> print modelData
Defines the HasQueryParams
instance for ModelRequest
to support query string generation for the Claude API.
Methods:
getBeforeID
: Retrieves thebeforeID
parameter.getAfterID
: Retrieves theafterID
parameter.getLimit
: Retrieves thelimit
parameter.
Description:
This instance allows ModelRequest
objects to seamlessly generate query strings when interacting with the Claude API.
This module defines the types used throughout the ClaudeAPI library. It provides data structures for requests and responses, JSON encoding/decoding, and utilities for interacting with the API.
class FromJSON a => JSONResponse a where
parseResponse :: BL.ByteString -> Either String a
A typeclass representing types that can be decoded from JSON responses. The default implementation uses eitherDecode
.
Represents metadata and data for media (e.g., images).
data MediaSource = MediaSource
{ encodingType :: String -- The encoding type (e.g., "base64").
, mediaType :: String -- The MIME type (e.g., "image/png").
, imageData :: Text -- The actual image data.
}
- JSON Serialization: Converts field names to API-compatible keys (
type
,media_type
,data
).
Represents the content of a message, which can be either text or media.
data RequestMessageContent =
MediaContent { msgType :: String, source :: MediaSource }
| TextContent { msgType :: String, text :: String }
- Variants:
MediaContent
: For messages with media content.TextContent
: For text messages.
- JSON Serialization: Converts
msgType
totype
.
Represents a request message with a role and content.
data RequestMessage = RequestMessage
{ role :: String -- The role of the sender (e.g., "user").
, content :: Either String [RequestMessageContent] -- Message content.
}
- JSON Serialization: Handles either plain string content or structured content.
Represents a chat request containing multiple messages and metadata.
data ChatRequest = ChatRequest
{ model :: String -- The name of the model to use.
, messages :: [RequestMessage] -- List of chat messages.
, maxTokens :: Int -- Maximum number of tokens to generate.
, stopSequences :: Maybe String -- Optional stop sequences.
, stream :: Maybe Bool -- Whether to stream responses.
, system :: Maybe String -- Optional system configurations.
, temperature :: Maybe Double -- Temperature parameter for responses.
}
- JSON Serialization: Converts camelCase fields to snake_case for API compatibility.
Represents a response message from the API.
data ResponseMessage = ResponseMessage
{ responseType :: String -- The type of the response (e.g., "text").
, responseText :: String -- The text of the response.
}
- JSON Parsing: Converts
type
andtext
from JSON.
Represents the full response from the API for a chat request.
data ChatResponse = ChatResponse
{ id :: String -- Unique identifier for the response.
, responseType :: String -- The type of response.
, responseRole :: String -- The role of the responder (e.g., "assistant").
, responseContent :: [ResponseMessage] -- The content of the response.
, responseModel :: String -- The model used to generate the response.
, stopReason :: String -- Reason for stopping response generation.
, stopSequence :: Maybe String -- Stop sequence, if any.
, usage :: Usage -- Token usage details.
}
- JSON Parsing: Maps field names to snake_case for compatibility.
Represents token usage details in a response.
data Usage = Usage
{ inputTokens :: Int -- Number of input tokens.
, cacheCreationInputTokens :: Int -- Tokens for cache creation.
, cacheReadInputTokens :: Int -- Tokens for cache reading.
, outputTokens :: Int -- Number of output tokens.
}
Defines request and response types for retrieving models.
data ModelRequest = ModelRequest
{ beforeID :: Maybe String -- ID for pagination (before).
, afterID :: Maybe String -- ID for pagination (after).
, limit :: Maybe Int -- Number of results to return.
}
data ModelResponse = ModelResponse
{ modelData :: [ModelData] -- List of models.
, hasMore :: Bool -- Whether there are more models.
, firstID :: Maybe String -- First model ID in the response.
, lastID :: Maybe String -- Last model ID in the response.
}
Defines request and response types for counting tokens in a message.
data CountTokenRequest = CountTokenRequest
{ requestMessages :: [RequestMessage]
, model :: String
, system :: Maybe String
}
newtype CountTokenResponse = CountTokenResponse { inputTokens :: Int }
Represents a single batch request for sending multiple chat messages.
data MessageBatchRequest = MessageBatchRequest
{ customID :: String -- A custom identifier for the batch request.
, params :: ChatRequest -- Parameters for the batch request (e.g., messages, model, etc.).
}
- Usage: Allows specifying a custom identifier and the chat request payload for batch operations.
- JSON Serialization: Converts
customID
tocustom_id
for API compatibility.
Encapsulates multiple batch requests for submission as a group.
newtype MessageBatchRequests =
MessageBatchRequests { requests :: [MessageBatchRequest] }
- Purpose: Enables sending multiple
MessageBatchRequest
objects as a single operation. - JSON Serialization: Encodes the list of requests into the required JSON structure.
Tracks the processing status of a batch request.
data MessageBatchRequestCount = MessageBatchRequestCount
{ processing :: Int -- Number of requests currently being processed.
, succeeded :: Int -- Number of successfully processed requests.
, errored :: Int -- Number of requests that resulted in errors.
, canceled :: Int -- Number of requests that were canceled.
, expired :: Int -- Number of requests that expired before completion.
}
- Purpose: Provides detailed counts for different states of batch processing.
- JSON Parsing: Automatically maps fields from JSON responses.
Represents the API response for a batch operation.
data MessageBatchResponse = MessageBatchResponse
{ id :: String -- Unique identifier for the batch.
, responseType :: String -- Type of the response (e.g., "batch").
, processingStatus :: String -- Current status of the batch (e.g., "completed").
, requestCounts :: MessageBatchRequestCount -- Details about the processing state.
, endedAt :: Maybe String -- Optional timestamp for when processing ended.
, createdAt :: String -- Timestamp for when the batch was created.
, expiresAt :: String -- Expiration timestamp for the batch.
, archivedAt :: Maybe String -- Optional timestamp for when the batch was archived.
, cancelInitiatedAt :: Maybe String -- Optional timestamp for when cancelation was initiated.
, resultsUrl :: Maybe String -- Optional URL for fetching detailed batch results.
}
- Purpose: Provides metadata and processing details about the batch operation.
- JSON Parsing: Handles snake_case to camelCase mapping for fields like
created_at
andresults_url
.
Defines a request to list batches with optional pagination.
data ListMessageBatchRequest = ListMessageBatchRequest
{ beforeID :: Maybe String -- List batches created before this ID.
, afterID :: Maybe String -- List batches created after this ID.
, limit :: Maybe Int -- Maximum number of results to return.
}
- Usage: Enables paginated retrieval of batches.
- JSON Serialization: Converts camelCase fields (
beforeID
,afterID
) to snake_case for the API.
Contains the response for a request to list message batches.
newtype ListMessageBatchResponse =
ListMessageBatchResponse { responseData :: [MessageBatchResponse] }
- Purpose: Provides a list of batches with their metadata.
- JSON Parsing: Maps
data
from the API response toresponseData
.
Represents a single result in a batch operation.
data MessageBatchResult = MessageBatchResult
{ resultType :: String -- Type of the result (e.g., "success" or "error").
, message :: ChatResponse -- The detailed response for the batch item.
}
- Usage: Provides detailed information for each batch request.
- JSON Parsing: Maps the fields as needed for internal use.
Represents a batch result identified by its custom ID.
data RetrieveMessageBatchResult = RetrieveMessageBatchResult
{ customID :: String -- The custom identifier for the batch item.
, result :: MessageBatchResult -- The result associated with the batch item.
}
- Purpose: Enables mapping results back to their originating requests using the custom ID.
- JSON Parsing: Converts snake_case fields (
custom_id
) to camelCase.
Encapsulates all results for a retrieved batch operation.
newtype RetrieveMessageBatchResults =
RetrieveMessageBatchResults [RetrieveMessageBatchResult]
- Purpose: Provides a unified structure for accessing all batch results.
- JSON Parsing: Supports parsing from multi-lines JSONL formats.
This module provides utility functions and type classes for handling query parameters and transforming strings, primarily for constructing API requests.
Defines a type class for types that can provide query parameters for HTTP requests.
class HasQueryParams a where
getBeforeID :: a -> Maybe String
-- ^ Retrieves the `before_id` query parameter, if present.
getAfterID :: a -> Maybe String
-- ^ Retrieves the `after_id` query parameter, if present.
getLimit :: a -> Maybe Int
-- ^ Retrieves the `limit` query parameter, if present.
- Purpose: Used for extracting query parameters from data structures.
Generates a query string from an object implementing the HasQueryParams
type class.
buildQueryString :: HasQueryParams a => a -> String
- Input: An object of type
a
that implements theHasQueryParams
type class. - Output: A query string (e.g.,
"?before_id=123&after_id=456&limit=10"
) or an empty string if no parameters are present. - Usage Example:
let query = buildQueryString myInstance -- Result: "?before_id=abc&limit=5"
Converts a camelCase string to snake_case.
camelToUnderscore :: String -> String
- Input: A camelCase string (e.g.,
"camelCaseString"
). - Output: A snake_case string (e.g.,
"camel_case_string"
). - Usage Example:
camelToUnderscore "camelCaseString" -- Result: "camel_case_string"
Run the tests using Cabal:
cabal test
Test examples can be found in test/Main.hs
and test/ClaudeAPI
.
Contributions are welcome! Please follow these steps:
- Fork the repository.
- Create a new branch for your feature or bugfix.
- Submit a pull request.
This library is licensed under the MIT License.