packages feed

ollama-haskell 0.1.3.0 → 0.2.0.0

raw patch · 27 files changed

+3500/−1425 lines, 27 filesdep +http-client-tlsdep +mtldep +scientificdep ~aesondep ~base64-bytestringdep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: http-client-tls, mtl, scientific, stm

Dependency ranges changed: aeson, base64-bytestring, bytestring, containers, directory, filepath, http-client, http-types, tasty, text, time

API changes (from Hackage documentation)

- Data.Ollama.Chat: [responseTimeOut] :: ChatOps -> Maybe Int
- Data.Ollama.Chat: chatJson :: (FromJSON jsonResult, ToJSON jsonResult) => ChatOps -> jsonResult -> Maybe Int -> IO (Either String jsonResult)
- Data.Ollama.Chat: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Chat.ChatResponse
- Data.Ollama.Chat: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Chat.Message
- Data.Ollama.Chat: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Chat.Role
- Data.Ollama.Chat: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Chat.Message
- Data.Ollama.Chat: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Chat.Role
- Data.Ollama.Chat: instance GHC.Classes.Eq Data.Ollama.Chat.ChatResponse
- Data.Ollama.Chat: instance GHC.Classes.Eq Data.Ollama.Chat.Message
- Data.Ollama.Chat: instance GHC.Classes.Eq Data.Ollama.Chat.Role
- Data.Ollama.Chat: instance GHC.Generics.Generic Data.Ollama.Chat.Message
- Data.Ollama.Chat: instance GHC.Show.Show Data.Ollama.Chat.ChatResponse
- Data.Ollama.Chat: instance GHC.Show.Show Data.Ollama.Chat.Message
- Data.Ollama.Chat: instance GHC.Show.Show Data.Ollama.Chat.Role
- Data.Ollama.Chat: schemaFromType :: ToJSON a => a -> ByteString
- Data.Ollama.Common.Types: OllamaClient :: Text -> OllamaClient
- Data.Ollama.Common.Types: [$sel:families:ModelDetails] :: ModelDetails -> [Text]
- Data.Ollama.Common.Types: [$sel:familiy:ModelDetails] :: ModelDetails -> Text
- Data.Ollama.Common.Types: [$sel:format:ModelDetails] :: ModelDetails -> Text
- Data.Ollama.Common.Types: [$sel:host:OllamaClient] :: OllamaClient -> Text
- Data.Ollama.Common.Types: [$sel:parameterSize:ModelDetails] :: ModelDetails -> Text
- Data.Ollama.Common.Types: [$sel:parentModel:ModelDetails] :: ModelDetails -> Maybe Text
- Data.Ollama.Common.Types: [$sel:quantizationLevel:ModelDetails] :: ModelDetails -> Text
- Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.OllamaClient
- Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.OllamaClient
- Data.Ollama.Common.Types: newtype OllamaClient
- Data.Ollama.Common.Utils: OllamaClient :: Text -> OllamaClient
- Data.Ollama.Common.Utils: [$sel:host:OllamaClient] :: OllamaClient -> Text
- Data.Ollama.Common.Utils: defaultOllamaUrl :: Text
- Data.Ollama.Common.Utils: newtype OllamaClient
- Data.Ollama.Create: createModelOps :: Text -> Maybe Text -> Maybe Bool -> Maybe FilePath -> IO ()
- Data.Ollama.Embeddings: [$sel:embedding_:EmbeddingResp] :: EmbeddingResp -> [[Float]]
- Data.Ollama.Embeddings: [$sel:input:EmbeddingOps] :: EmbeddingOps -> Text
- Data.Ollama.Embeddings: [$sel:keepAlive:EmbeddingOps] :: EmbeddingOps -> Maybe Text
- Data.Ollama.Embeddings: [$sel:model:EmbeddingOps] :: EmbeddingOps -> Text
- Data.Ollama.Embeddings: [$sel:model:EmbeddingResp] :: EmbeddingResp -> Text
- Data.Ollama.Embeddings: [$sel:truncate:EmbeddingOps] :: EmbeddingOps -> Maybe Bool
- Data.Ollama.Generate: [$sel:createdAt:GenerateResponse] :: GenerateResponse -> UTCTime
- Data.Ollama.Generate: [$sel:done:GenerateResponse] :: GenerateResponse -> Bool
- Data.Ollama.Generate: [$sel:evalCount:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Data.Ollama.Generate: [$sel:evalDuration:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Data.Ollama.Generate: [$sel:format:GenerateOps] :: GenerateOps -> Maybe Format
- Data.Ollama.Generate: [$sel:hostUrl:GenerateOps] :: GenerateOps -> Maybe Text
- Data.Ollama.Generate: [$sel:images:GenerateOps] :: GenerateOps -> Maybe [Text]
- Data.Ollama.Generate: [$sel:keepAlive:GenerateOps] :: GenerateOps -> Maybe Text
- Data.Ollama.Generate: [$sel:loadDuration:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Data.Ollama.Generate: [$sel:model:GenerateResponse] :: GenerateResponse -> Text
- Data.Ollama.Generate: [$sel:modelName:GenerateOps] :: GenerateOps -> Text
- Data.Ollama.Generate: [$sel:options:GenerateOps] :: GenerateOps -> Maybe Value
- Data.Ollama.Generate: [$sel:prompt:GenerateOps] :: GenerateOps -> Text
- Data.Ollama.Generate: [$sel:promptEvalCount:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Data.Ollama.Generate: [$sel:promptEvalDuration:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Data.Ollama.Generate: [$sel:raw:GenerateOps] :: GenerateOps -> Maybe Bool
- Data.Ollama.Generate: [$sel:responseTimeOut:GenerateOps] :: GenerateOps -> Maybe Int
- Data.Ollama.Generate: [$sel:response_:GenerateResponse] :: GenerateResponse -> Text
- Data.Ollama.Generate: [$sel:stream:GenerateOps] :: GenerateOps -> Maybe (GenerateResponse -> IO (), IO ())
- Data.Ollama.Generate: [$sel:suffix:GenerateOps] :: GenerateOps -> Maybe Text
- Data.Ollama.Generate: [$sel:system:GenerateOps] :: GenerateOps -> Maybe Text
- Data.Ollama.Generate: [$sel:template:GenerateOps] :: GenerateOps -> Maybe Text
- Data.Ollama.Generate: [$sel:totalDuration:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Data.Ollama.Generate: generateJson :: (ToJSON jsonResult, FromJSON jsonResult) => GenerateOps -> jsonResult -> Maybe Int -> IO (Either String jsonResult)
- Data.Ollama.Generate: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Generate.GenerateResponse
- Data.Ollama.Generate: instance GHC.Classes.Eq Data.Ollama.Generate.GenerateResponse
- Data.Ollama.Generate: instance GHC.Show.Show Data.Ollama.Generate.GenerateResponse
- Data.Ollama.Push: pushOps :: Text -> Maybe Bool -> Maybe Bool -> IO ()
- Data.Ollama.Show: [$sel:details:ShowModelResponse] :: ShowModelResponse -> ModelDetails
- Data.Ollama.Show: [$sel:modelFile:ShowModelResponse] :: ShowModelResponse -> Text
- Data.Ollama.Show: [$sel:modelInfo:ShowModelResponse] :: ShowModelResponse -> ModelInfo
- Data.Ollama.Show: [$sel:parameters:ShowModelResponse] :: ShowModelResponse -> Text
- Data.Ollama.Show: [$sel:template:ShowModelResponse] :: ShowModelResponse -> Text
- Data.Ollama.Show: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Show.ModelDetails
- Data.Ollama.Show: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Show.ModelInfo
- Data.Ollama.Show: instance GHC.Classes.Eq Data.Ollama.Show.ModelDetails
- Data.Ollama.Show: instance GHC.Classes.Eq Data.Ollama.Show.ModelInfo
- Data.Ollama.Show: instance GHC.Show.Show Data.Ollama.Show.ModelDetails
- Data.Ollama.Show: instance GHC.Show.Show Data.Ollama.Show.ModelInfo
- Ollama: [$sel:createdAt:GenerateResponse] :: GenerateResponse -> UTCTime
- Ollama: [$sel:details:ShowModelResponse] :: ShowModelResponse -> ModelDetails
- Ollama: [$sel:done:GenerateResponse] :: GenerateResponse -> Bool
- Ollama: [$sel:embedding_:EmbeddingResp] :: EmbeddingResp -> [[Float]]
- Ollama: [$sel:evalCount:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Ollama: [$sel:evalDuration:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Ollama: [$sel:format:GenerateOps] :: GenerateOps -> Maybe Format
- Ollama: [$sel:hostUrl:GenerateOps] :: GenerateOps -> Maybe Text
- Ollama: [$sel:images:GenerateOps] :: GenerateOps -> Maybe [Text]
- Ollama: [$sel:input:EmbeddingOps] :: EmbeddingOps -> Text
- Ollama: [$sel:keepAlive:EmbeddingOps] :: EmbeddingOps -> Maybe Text
- Ollama: [$sel:keepAlive:GenerateOps] :: GenerateOps -> Maybe Text
- Ollama: [$sel:loadDuration:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Ollama: [$sel:model:EmbeddingOps] :: EmbeddingOps -> Text
- Ollama: [$sel:model:EmbeddingResp] :: EmbeddingResp -> Text
- Ollama: [$sel:model:GenerateResponse] :: GenerateResponse -> Text
- Ollama: [$sel:modelFile:ShowModelResponse] :: ShowModelResponse -> Text
- Ollama: [$sel:modelInfo:ShowModelResponse] :: ShowModelResponse -> ModelInfo
- Ollama: [$sel:modelName:GenerateOps] :: GenerateOps -> Text
- Ollama: [$sel:options:GenerateOps] :: GenerateOps -> Maybe Value
- Ollama: [$sel:parameters:ShowModelResponse] :: ShowModelResponse -> Text
- Ollama: [$sel:prompt:GenerateOps] :: GenerateOps -> Text
- Ollama: [$sel:promptEvalCount:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Ollama: [$sel:promptEvalDuration:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Ollama: [$sel:raw:GenerateOps] :: GenerateOps -> Maybe Bool
- Ollama: [$sel:responseTimeOut:GenerateOps] :: GenerateOps -> Maybe Int
- Ollama: [$sel:response_:GenerateResponse] :: GenerateResponse -> Text
- Ollama: [$sel:stream:GenerateOps] :: GenerateOps -> Maybe (GenerateResponse -> IO (), IO ())
- Ollama: [$sel:suffix:GenerateOps] :: GenerateOps -> Maybe Text
- Ollama: [$sel:system:GenerateOps] :: GenerateOps -> Maybe Text
- Ollama: [$sel:template:GenerateOps] :: GenerateOps -> Maybe Text
- Ollama: [$sel:template:ShowModelResponse] :: ShowModelResponse -> Text
- Ollama: [$sel:totalDuration:GenerateResponse] :: GenerateResponse -> Maybe Int64
- Ollama: [$sel:truncate:EmbeddingOps] :: EmbeddingOps -> Maybe Bool
- Ollama: [responseTimeOut] :: ChatOps -> Maybe Int
- Ollama: chatJson :: (FromJSON jsonResult, ToJSON jsonResult) => ChatOps -> jsonResult -> Maybe Int -> IO (Either String jsonResult)
- Ollama: createModelOps :: Text -> Maybe Text -> Maybe Bool -> Maybe FilePath -> IO ()
- Ollama: generateJson :: (ToJSON jsonResult, FromJSON jsonResult) => GenerateOps -> jsonResult -> Maybe Int -> IO (Either String jsonResult)
- Ollama: pushOps :: Text -> Maybe Bool -> Maybe Bool -> IO ()
+ Data.Ollama.Chat: ApiError :: Text -> OllamaError
+ Data.Ollama.Chat: DecodeError :: DecodingErrorMessage -> DecodingFailedValue -> OllamaError
+ Data.Ollama.Chat: FileError :: IOException -> OllamaError
+ Data.Ollama.Chat: FunctionDef :: Text -> Maybe Text -> Maybe FunctionParameters -> Maybe Bool -> FunctionDef
+ Data.Ollama.Chat: FunctionParameters :: Text -> Maybe (Map Text FunctionParameters) -> Maybe [Text] -> Maybe Bool -> FunctionParameters
+ Data.Ollama.Chat: HttpError :: HttpException -> OllamaError
+ Data.Ollama.Chat: InputTool :: Text -> FunctionDef -> InputTool
+ Data.Ollama.Chat: InvalidRequest :: String -> OllamaError
+ Data.Ollama.Chat: JsonSchemaError :: String -> OllamaError
+ Data.Ollama.Chat: ModelOptions :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Bool -> Maybe [Text] -> Maybe Bool -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Bool -> Maybe Int -> ModelOptions
+ Data.Ollama.Chat: OllamaConfig :: Text -> Int -> Maybe (IO ()) -> Maybe (IO ()) -> Maybe (IO ()) -> Maybe Int -> Maybe Int -> Maybe Manager -> OllamaConfig
+ Data.Ollama.Chat: OutputFunction :: Text -> Map Text Value -> OutputFunction
+ Data.Ollama.Chat: TimeoutError :: String -> OllamaError
+ Data.Ollama.Chat: ToolCall :: OutputFunction -> ToolCall
+ Data.Ollama.Chat: [additionalProperties] :: FunctionParameters -> Maybe Bool
+ Data.Ollama.Chat: [arguments] :: OutputFunction -> Map Text Value
+ Data.Ollama.Chat: [commonManager] :: OllamaConfig -> Maybe Manager
+ Data.Ollama.Chat: [frequencyPenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Chat: [functionDescription] :: FunctionDef -> Maybe Text
+ Data.Ollama.Chat: [functionName] :: FunctionDef -> Text
+ Data.Ollama.Chat: [functionParameters] :: FunctionDef -> Maybe FunctionParameters
+ Data.Ollama.Chat: [functionStrict] :: FunctionDef -> Maybe Bool
+ Data.Ollama.Chat: [function] :: InputTool -> FunctionDef
+ Data.Ollama.Chat: [mainGpu] :: ModelOptions -> Maybe Int
+ Data.Ollama.Chat: [minP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Chat: [numBatch] :: ModelOptions -> Maybe Int
+ Data.Ollama.Chat: [numCtx] :: ModelOptions -> Maybe Int
+ Data.Ollama.Chat: [numGpu] :: ModelOptions -> Maybe Int
+ Data.Ollama.Chat: [numKeep] :: ModelOptions -> Maybe Int
+ Data.Ollama.Chat: [numPredict] :: ModelOptions -> Maybe Int
+ Data.Ollama.Chat: [numThread] :: ModelOptions -> Maybe Int
+ Data.Ollama.Chat: [numa] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Chat: [onModelError] :: OllamaConfig -> Maybe (IO ())
+ Data.Ollama.Chat: [onModelFinish] :: OllamaConfig -> Maybe (IO ())
+ Data.Ollama.Chat: [onModelStart] :: OllamaConfig -> Maybe (IO ())
+ Data.Ollama.Chat: [outputFunctionName] :: OutputFunction -> Text
+ Data.Ollama.Chat: [outputFunction] :: ToolCall -> OutputFunction
+ Data.Ollama.Chat: [parameterProperties] :: FunctionParameters -> Maybe (Map Text FunctionParameters)
+ Data.Ollama.Chat: [parameterType] :: FunctionParameters -> Text
+ Data.Ollama.Chat: [penalizeNewline] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Chat: [presencePenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Chat: [repeatLastN] :: ModelOptions -> Maybe Int
+ Data.Ollama.Chat: [repeatPenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Chat: [requiredParams] :: FunctionParameters -> Maybe [Text]
+ Data.Ollama.Chat: [retryCount] :: OllamaConfig -> Maybe Int
+ Data.Ollama.Chat: [retryDelay] :: OllamaConfig -> Maybe Int
+ Data.Ollama.Chat: [seed] :: ModelOptions -> Maybe Int
+ Data.Ollama.Chat: [stop] :: ModelOptions -> Maybe [Text]
+ Data.Ollama.Chat: [temperature] :: ModelOptions -> Maybe Double
+ Data.Ollama.Chat: [think] :: ChatOps -> !Maybe Bool
+ Data.Ollama.Chat: [thinking] :: Message -> !Maybe Text
+ Data.Ollama.Chat: [timeout] :: OllamaConfig -> Int
+ Data.Ollama.Chat: [toolType] :: InputTool -> Text
+ Data.Ollama.Chat: [topK] :: ModelOptions -> Maybe Int
+ Data.Ollama.Chat: [topP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Chat: [typicalP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Chat: [useMmap] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Chat: assistantMessage :: Text -> Message
+ Data.Ollama.Chat: chatM :: MonadIO m => ChatOps -> Maybe OllamaConfig -> m (Either OllamaError ChatResponse)
+ Data.Ollama.Chat: data FunctionDef
+ Data.Ollama.Chat: data FunctionParameters
+ Data.Ollama.Chat: data InputTool
+ Data.Ollama.Chat: data ModelOptions
+ Data.Ollama.Chat: data OllamaConfig
+ Data.Ollama.Chat: data OllamaError
+ Data.Ollama.Chat: data OutputFunction
+ Data.Ollama.Chat: defaultModelOptions :: ModelOptions
+ Data.Ollama.Chat: defaultOllamaConfig :: OllamaConfig
+ Data.Ollama.Chat: genMessage :: Role -> Text -> Message
+ Data.Ollama.Chat: newtype ToolCall
+ Data.Ollama.Chat: systemMessage :: Text -> Message
+ Data.Ollama.Chat: toolMessage :: Text -> Message
+ Data.Ollama.Chat: userMessage :: Text -> Message
+ Data.Ollama.Common.Config: OllamaConfig :: Text -> Int -> Maybe (IO ()) -> Maybe (IO ()) -> Maybe (IO ()) -> Maybe Int -> Maybe Int -> Maybe Manager -> OllamaConfig
+ Data.Ollama.Common.Config: [commonManager] :: OllamaConfig -> Maybe Manager
+ Data.Ollama.Common.Config: [hostUrl] :: OllamaConfig -> Text
+ Data.Ollama.Common.Config: [onModelError] :: OllamaConfig -> Maybe (IO ())
+ Data.Ollama.Common.Config: [onModelFinish] :: OllamaConfig -> Maybe (IO ())
+ Data.Ollama.Common.Config: [onModelStart] :: OllamaConfig -> Maybe (IO ())
+ Data.Ollama.Common.Config: [retryCount] :: OllamaConfig -> Maybe Int
+ Data.Ollama.Common.Config: [retryDelay] :: OllamaConfig -> Maybe Int
+ Data.Ollama.Common.Config: [timeout] :: OllamaConfig -> Int
+ Data.Ollama.Common.Config: data OllamaConfig
+ Data.Ollama.Common.Config: defaultOllamaConfig :: OllamaConfig
+ Data.Ollama.Common.Config: instance GHC.Generics.Generic Data.Ollama.Common.Config.OllamaConfig
+ Data.Ollama.Common.Config: withOnModelError :: IO () -> OllamaConfig -> OllamaConfig
+ Data.Ollama.Common.Config: withOnModelFinish :: IO () -> OllamaConfig -> OllamaConfig
+ Data.Ollama.Common.Config: withOnModelStart :: IO () -> OllamaConfig -> OllamaConfig
+ Data.Ollama.Common.Error: ApiError :: Text -> OllamaError
+ Data.Ollama.Common.Error: DecodeError :: DecodingErrorMessage -> DecodingFailedValue -> OllamaError
+ Data.Ollama.Common.Error: FileError :: IOException -> OllamaError
+ Data.Ollama.Common.Error: HttpError :: HttpException -> OllamaError
+ Data.Ollama.Common.Error: InvalidRequest :: String -> OllamaError
+ Data.Ollama.Common.Error: JsonSchemaError :: String -> OllamaError
+ Data.Ollama.Common.Error: TimeoutError :: String -> OllamaError
+ Data.Ollama.Common.Error: data OllamaError
+ Data.Ollama.Common.Error: instance GHC.Classes.Eq Data.Ollama.Common.Error.OllamaError
+ Data.Ollama.Common.Error: instance GHC.Exception.Type.Exception Data.Ollama.Common.Error.OllamaError
+ Data.Ollama.Common.Error: instance GHC.Generics.Generic Data.Ollama.Common.Error.OllamaError
+ Data.Ollama.Common.Error: instance GHC.Show.Show Data.Ollama.Common.Error.OllamaError
+ Data.Ollama.Common.Error: type DecodingErrorMessage = String
+ Data.Ollama.Common.Error: type DecodingFailedValue = String
+ Data.Ollama.Common.SchemaBuilder: (|!!) :: SchemaBuilder -> [Text] -> SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: (|!) :: SchemaBuilder -> Text -> SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: (|+) :: SchemaBuilder -> (Text, JsonType) -> SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: (|++) :: SchemaBuilder -> (Text, Schema) -> SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: JArray :: JsonType -> JsonType
+ Data.Ollama.Common.SchemaBuilder: JBoolean :: JsonType
+ Data.Ollama.Common.SchemaBuilder: JInteger :: JsonType
+ Data.Ollama.Common.SchemaBuilder: JNull :: JsonType
+ Data.Ollama.Common.SchemaBuilder: JNumber :: JsonType
+ Data.Ollama.Common.SchemaBuilder: JObject :: Schema -> JsonType
+ Data.Ollama.Common.SchemaBuilder: JString :: JsonType
+ Data.Ollama.Common.SchemaBuilder: Property :: JsonType -> Property
+ Data.Ollama.Common.SchemaBuilder: Schema :: Map Text Property -> [Text] -> Schema
+ Data.Ollama.Common.SchemaBuilder: [schemaProperties] :: Schema -> Map Text Property
+ Data.Ollama.Common.SchemaBuilder: [schemaRequired] :: Schema -> [Text]
+ Data.Ollama.Common.SchemaBuilder: addObjectProperty :: Text -> Schema -> SchemaBuilder -> SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: addProperty :: Text -> JsonType -> SchemaBuilder -> SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: arrayOf :: JsonType -> JsonType
+ Data.Ollama.Common.SchemaBuilder: buildSchema :: SchemaBuilder -> Schema
+ Data.Ollama.Common.SchemaBuilder: data JsonType
+ Data.Ollama.Common.SchemaBuilder: data Schema
+ Data.Ollama.Common.SchemaBuilder: emptyObject :: SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: infixl 6 |!!
+ Data.Ollama.Common.SchemaBuilder: infixl 7 |++
+ Data.Ollama.Common.SchemaBuilder: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.SchemaBuilder.JsonType
+ Data.Ollama.Common.SchemaBuilder: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.SchemaBuilder.Property
+ Data.Ollama.Common.SchemaBuilder: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.SchemaBuilder.Schema
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Classes.Eq Data.Ollama.Common.SchemaBuilder.JsonType
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Classes.Eq Data.Ollama.Common.SchemaBuilder.Property
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Classes.Eq Data.Ollama.Common.SchemaBuilder.Schema
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Classes.Eq Data.Ollama.Common.SchemaBuilder.SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Generics.Generic Data.Ollama.Common.SchemaBuilder.JsonType
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Generics.Generic Data.Ollama.Common.SchemaBuilder.Property
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Generics.Generic Data.Ollama.Common.SchemaBuilder.Schema
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Show.Show Data.Ollama.Common.SchemaBuilder.JsonType
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Show.Show Data.Ollama.Common.SchemaBuilder.Property
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Show.Show Data.Ollama.Common.SchemaBuilder.Schema
+ Data.Ollama.Common.SchemaBuilder: instance GHC.Show.Show Data.Ollama.Common.SchemaBuilder.SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: newtype Property
+ Data.Ollama.Common.SchemaBuilder: objectOf :: SchemaBuilder -> JsonType
+ Data.Ollama.Common.SchemaBuilder: printSchema :: Schema -> IO ()
+ Data.Ollama.Common.SchemaBuilder: requireField :: Text -> SchemaBuilder -> SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: requireFields :: [Text] -> SchemaBuilder -> SchemaBuilder
+ Data.Ollama.Common.SchemaBuilder: toOllamaFormat :: Schema -> Value
+ Data.Ollama.Common.Types: Assistant :: Role
+ Data.Ollama.Common.Types: ChatResponse :: !Text -> !UTCTime -> !Maybe Message -> !Bool -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> ChatResponse
+ Data.Ollama.Common.Types: FunctionDef :: Text -> Maybe Text -> Maybe FunctionParameters -> Maybe Bool -> FunctionDef
+ Data.Ollama.Common.Types: FunctionParameters :: Text -> Maybe (Map Text FunctionParameters) -> Maybe [Text] -> Maybe Bool -> FunctionParameters
+ Data.Ollama.Common.Types: GenerateResponse :: !Text -> !UTCTime -> !Text -> !Bool -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Text -> GenerateResponse
+ Data.Ollama.Common.Types: InputTool :: Text -> FunctionDef -> InputTool
+ Data.Ollama.Common.Types: Message :: !Role -> !Text -> !Maybe [Text] -> !Maybe [ToolCall] -> !Maybe Text -> Message
+ Data.Ollama.Common.Types: ModelOptions :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Bool -> Maybe [Text] -> Maybe Bool -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Bool -> Maybe Int -> ModelOptions
+ Data.Ollama.Common.Types: OutputFunction :: Text -> Map Text Value -> OutputFunction
+ Data.Ollama.Common.Types: System :: Role
+ Data.Ollama.Common.Types: Tool :: Role
+ Data.Ollama.Common.Types: ToolCall :: OutputFunction -> ToolCall
+ Data.Ollama.Common.Types: User :: Role
+ Data.Ollama.Common.Types: Version :: Text -> Version
+ Data.Ollama.Common.Types: [additionalProperties] :: FunctionParameters -> Maybe Bool
+ Data.Ollama.Common.Types: [arguments] :: OutputFunction -> Map Text Value
+ Data.Ollama.Common.Types: [content] :: Message -> !Text
+ Data.Ollama.Common.Types: [createdAt] :: ChatResponse -> !UTCTime
+ Data.Ollama.Common.Types: [done] :: ChatResponse -> !Bool
+ Data.Ollama.Common.Types: [evalCount] :: ChatResponse -> !Maybe Int64
+ Data.Ollama.Common.Types: [evalDuration] :: ChatResponse -> !Maybe Int64
+ Data.Ollama.Common.Types: [families] :: ModelDetails -> ![Text]
+ Data.Ollama.Common.Types: [family] :: ModelDetails -> !Text
+ Data.Ollama.Common.Types: [format] :: ModelDetails -> !Text
+ Data.Ollama.Common.Types: [frequencyPenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Common.Types: [functionDescription] :: FunctionDef -> Maybe Text
+ Data.Ollama.Common.Types: [functionName] :: FunctionDef -> Text
+ Data.Ollama.Common.Types: [functionParameters] :: FunctionDef -> Maybe FunctionParameters
+ Data.Ollama.Common.Types: [functionStrict] :: FunctionDef -> Maybe Bool
+ Data.Ollama.Common.Types: [function] :: InputTool -> FunctionDef
+ Data.Ollama.Common.Types: [genResponse] :: GenerateResponse -> !Text
+ Data.Ollama.Common.Types: [images] :: Message -> !Maybe [Text]
+ Data.Ollama.Common.Types: [loadDuration] :: ChatResponse -> !Maybe Int64
+ Data.Ollama.Common.Types: [mainGpu] :: ModelOptions -> Maybe Int
+ Data.Ollama.Common.Types: [message] :: ChatResponse -> !Maybe Message
+ Data.Ollama.Common.Types: [minP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Common.Types: [model] :: ChatResponse -> !Text
+ Data.Ollama.Common.Types: [numBatch] :: ModelOptions -> Maybe Int
+ Data.Ollama.Common.Types: [numCtx] :: ModelOptions -> Maybe Int
+ Data.Ollama.Common.Types: [numGpu] :: ModelOptions -> Maybe Int
+ Data.Ollama.Common.Types: [numKeep] :: ModelOptions -> Maybe Int
+ Data.Ollama.Common.Types: [numPredict] :: ModelOptions -> Maybe Int
+ Data.Ollama.Common.Types: [numThread] :: ModelOptions -> Maybe Int
+ Data.Ollama.Common.Types: [numa] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Common.Types: [outputFunctionName] :: OutputFunction -> Text
+ Data.Ollama.Common.Types: [outputFunction] :: ToolCall -> OutputFunction
+ Data.Ollama.Common.Types: [parameterProperties] :: FunctionParameters -> Maybe (Map Text FunctionParameters)
+ Data.Ollama.Common.Types: [parameterSize] :: ModelDetails -> !Text
+ Data.Ollama.Common.Types: [parameterType] :: FunctionParameters -> Text
+ Data.Ollama.Common.Types: [parentModel] :: ModelDetails -> !Maybe Text
+ Data.Ollama.Common.Types: [penalizeNewline] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Common.Types: [presencePenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Common.Types: [promptEvalCount] :: ChatResponse -> !Maybe Int64
+ Data.Ollama.Common.Types: [promptEvalDuration] :: ChatResponse -> !Maybe Int64
+ Data.Ollama.Common.Types: [quantizationLevel] :: ModelDetails -> Text
+ Data.Ollama.Common.Types: [repeatLastN] :: ModelOptions -> Maybe Int
+ Data.Ollama.Common.Types: [repeatPenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Common.Types: [requiredParams] :: FunctionParameters -> Maybe [Text]
+ Data.Ollama.Common.Types: [role] :: Message -> !Role
+ Data.Ollama.Common.Types: [seed] :: ModelOptions -> Maybe Int
+ Data.Ollama.Common.Types: [stop] :: ModelOptions -> Maybe [Text]
+ Data.Ollama.Common.Types: [temperature] :: ModelOptions -> Maybe Double
+ Data.Ollama.Common.Types: [thinking] :: Message -> !Maybe Text
+ Data.Ollama.Common.Types: [toolType] :: InputTool -> Text
+ Data.Ollama.Common.Types: [tool_calls] :: Message -> !Maybe [ToolCall]
+ Data.Ollama.Common.Types: [topK] :: ModelOptions -> Maybe Int
+ Data.Ollama.Common.Types: [topP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Common.Types: [totalDuration] :: ChatResponse -> !Maybe Int64
+ Data.Ollama.Common.Types: [typicalP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Common.Types: [useMmap] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Common.Types: class HasDone a
+ Data.Ollama.Common.Types: data ChatResponse
+ Data.Ollama.Common.Types: data FunctionDef
+ Data.Ollama.Common.Types: data FunctionParameters
+ Data.Ollama.Common.Types: data GenerateResponse
+ Data.Ollama.Common.Types: data InputTool
+ Data.Ollama.Common.Types: data Message
+ Data.Ollama.Common.Types: data ModelOptions
+ Data.Ollama.Common.Types: data OutputFunction
+ Data.Ollama.Common.Types: data Role
+ Data.Ollama.Common.Types: getDone :: HasDone a => a -> Bool
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Common.Types.ChatResponse
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Common.Types.FunctionDef
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Common.Types.FunctionParameters
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Common.Types.GenerateResponse
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Common.Types.InputTool
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Common.Types.Message
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Common.Types.OutputFunction
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Common.Types.Role
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Common.Types.ToolCall
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Common.Types.Version
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.Types.FunctionDef
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.Types.FunctionParameters
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.Types.InputTool
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.Types.Message
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.Types.ModelOptions
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.Types.OutputFunction
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.Types.Role
+ Data.Ollama.Common.Types: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Common.Types.ToolCall
+ Data.Ollama.Common.Types: instance Data.Ollama.Common.Types.HasDone Data.Ollama.Common.Types.ChatResponse
+ Data.Ollama.Common.Types: instance Data.Ollama.Common.Types.HasDone Data.Ollama.Common.Types.GenerateResponse
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.ChatResponse
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.FunctionDef
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.FunctionParameters
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.GenerateResponse
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.InputTool
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.Message
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.ModelOptions
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.OutputFunction
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.Role
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.ToolCall
+ Data.Ollama.Common.Types: instance GHC.Classes.Eq Data.Ollama.Common.Types.Version
+ Data.Ollama.Common.Types: instance GHC.Generics.Generic Data.Ollama.Common.Types.FunctionDef
+ Data.Ollama.Common.Types: instance GHC.Generics.Generic Data.Ollama.Common.Types.InputTool
+ Data.Ollama.Common.Types: instance GHC.Generics.Generic Data.Ollama.Common.Types.Message
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.ChatResponse
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.FunctionDef
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.FunctionParameters
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.GenerateResponse
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.InputTool
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.Message
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.ModelOptions
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.OutputFunction
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.Role
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.ToolCall
+ Data.Ollama.Common.Types: instance GHC.Show.Show Data.Ollama.Common.Types.Version
+ Data.Ollama.Common.Types: newtype ToolCall
+ Data.Ollama.Common.Types: newtype Version
+ Data.Ollama.Common.Utils: commonNonStreamingHandler :: FromJSON a => Response BodyReader -> IO (Either OllamaError a)
+ Data.Ollama.Common.Utils: commonStreamHandler :: (HasDone a, FromJSON a) => (a -> IO ()) -> IO () -> Response BodyReader -> IO (Either OllamaError a)
+ Data.Ollama.Common.Utils: defaultModelOptions :: ModelOptions
+ Data.Ollama.Common.Utils: getVersion :: IO (Either OllamaError Version)
+ Data.Ollama.Common.Utils: nonJsonHandler :: Response BodyReader -> IO (Either OllamaError ByteString)
+ Data.Ollama.Common.Utils: withOllamaRequest :: ToJSON payload => Text -> ByteString -> Maybe payload -> Maybe OllamaConfig -> (Response BodyReader -> IO (Either OllamaError response)) -> IO (Either OllamaError response)
+ Data.Ollama.Common.Utils: withRetry :: Int -> Int -> IO (Either OllamaError a) -> IO (Either OllamaError a)
+ Data.Ollama.Conversation: Conversation :: !Text -> ![Message] -> !Text -> !UTCTime -> !UTCTime -> Conversation
+ Data.Ollama.Conversation: ConvoM :: ReaderT InMemoryStore IO a -> ConvoM a
+ Data.Ollama.Conversation: InMemoryStore :: TVar (Map Text Conversation) -> InMemoryStore
+ Data.Ollama.Conversation: [conversationId] :: Conversation -> !Text
+ Data.Ollama.Conversation: [createdAt] :: Conversation -> !UTCTime
+ Data.Ollama.Conversation: [lastUpdated] :: Conversation -> !UTCTime
+ Data.Ollama.Conversation: [messages] :: Conversation -> ![Message]
+ Data.Ollama.Conversation: [model] :: Conversation -> !Text
+ Data.Ollama.Conversation: [runConvoM] :: ConvoM a -> ReaderT InMemoryStore IO a
+ Data.Ollama.Conversation: class Monad m => ConversationStore (m :: Type -> Type)
+ Data.Ollama.Conversation: data Conversation
+ Data.Ollama.Conversation: deleteConversation :: ConversationStore m => Text -> m Bool
+ Data.Ollama.Conversation: initInMemoryStore :: IO InMemoryStore
+ Data.Ollama.Conversation: instance Control.Monad.IO.Class.MonadIO Data.Ollama.Conversation.ConvoM
+ Data.Ollama.Conversation: instance Control.Monad.Reader.Class.MonadReader Data.Ollama.Conversation.InMemoryStore Data.Ollama.Conversation.ConvoM
+ Data.Ollama.Conversation: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Conversation.Conversation
+ Data.Ollama.Conversation: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Conversation.Conversation
+ Data.Ollama.Conversation: instance Data.Ollama.Conversation.ConversationStore Data.Ollama.Conversation.ConvoM
+ Data.Ollama.Conversation: instance GHC.Base.Applicative Data.Ollama.Conversation.ConvoM
+ Data.Ollama.Conversation: instance GHC.Base.Functor Data.Ollama.Conversation.ConvoM
+ Data.Ollama.Conversation: instance GHC.Base.Monad Data.Ollama.Conversation.ConvoM
+ Data.Ollama.Conversation: instance GHC.Classes.Eq Data.Ollama.Conversation.Conversation
+ Data.Ollama.Conversation: instance GHC.Generics.Generic Data.Ollama.Conversation.Conversation
+ Data.Ollama.Conversation: instance GHC.Show.Show Data.Ollama.Conversation.Conversation
+ Data.Ollama.Conversation: listConversations :: ConversationStore m => m [Conversation]
+ Data.Ollama.Conversation: loadConversation :: ConversationStore m => Text -> m (Maybe Conversation)
+ Data.Ollama.Conversation: newtype ConvoM a
+ Data.Ollama.Conversation: newtype InMemoryStore
+ Data.Ollama.Conversation: runInMemoryConvo :: InMemoryStore -> ConvoM a -> IO a
+ Data.Ollama.Conversation: saveConversation :: ConversationStore m => Conversation -> m ()
+ Data.Ollama.Conversation: validateConversation :: Conversation -> Either Text Conversation
+ Data.Ollama.Copy: copyModelM :: MonadIO m => Text -> Text -> Maybe OllamaConfig -> m (Either OllamaError ())
+ Data.Ollama.Create: createModelM :: MonadIO m => Text -> Maybe Text -> Maybe Bool -> Maybe FilePath -> Maybe OllamaConfig -> m ()
+ Data.Ollama.Create: instance Data.Ollama.Common.Types.HasDone Data.Ollama.Create.CreateModelResp
+ Data.Ollama.Delete: deleteModelM :: MonadIO m => Text -> Maybe OllamaConfig -> m (Either OllamaError ())
+ Data.Ollama.Embeddings: ModelOptions :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Bool -> Maybe [Text] -> Maybe Bool -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Bool -> Maybe Int -> ModelOptions
+ Data.Ollama.Embeddings: [frequencyPenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Embeddings: [input] :: EmbeddingOps -> ![Text]
+ Data.Ollama.Embeddings: [keepAliveEmbed] :: EmbeddingOps -> !Maybe Int
+ Data.Ollama.Embeddings: [mainGpu] :: ModelOptions -> Maybe Int
+ Data.Ollama.Embeddings: [minP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Embeddings: [modelOptions] :: EmbeddingOps -> !Maybe ModelOptions
+ Data.Ollama.Embeddings: [model] :: EmbeddingOps -> !Text
+ Data.Ollama.Embeddings: [numBatch] :: ModelOptions -> Maybe Int
+ Data.Ollama.Embeddings: [numCtx] :: ModelOptions -> Maybe Int
+ Data.Ollama.Embeddings: [numGpu] :: ModelOptions -> Maybe Int
+ Data.Ollama.Embeddings: [numKeep] :: ModelOptions -> Maybe Int
+ Data.Ollama.Embeddings: [numPredict] :: ModelOptions -> Maybe Int
+ Data.Ollama.Embeddings: [numThread] :: ModelOptions -> Maybe Int
+ Data.Ollama.Embeddings: [numa] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Embeddings: [penalizeNewline] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Embeddings: [presencePenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Embeddings: [repeatLastN] :: ModelOptions -> Maybe Int
+ Data.Ollama.Embeddings: [repeatPenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Embeddings: [respondedEmbeddings] :: EmbeddingResp -> ![[Float]]
+ Data.Ollama.Embeddings: [respondedModel] :: EmbeddingResp -> !Text
+ Data.Ollama.Embeddings: [seed] :: ModelOptions -> Maybe Int
+ Data.Ollama.Embeddings: [stop] :: ModelOptions -> Maybe [Text]
+ Data.Ollama.Embeddings: [temperature] :: ModelOptions -> Maybe Double
+ Data.Ollama.Embeddings: [topK] :: ModelOptions -> Maybe Int
+ Data.Ollama.Embeddings: [topP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Embeddings: [truncateInput] :: EmbeddingOps -> !Maybe Bool
+ Data.Ollama.Embeddings: [typicalP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Embeddings: [useMmap] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Embeddings: data ModelOptions
+ Data.Ollama.Embeddings: defaultEmbeddingOps :: EmbeddingOps
+ Data.Ollama.Embeddings: defaultModelOptions :: ModelOptions
+ Data.Ollama.Embeddings: embeddingM :: MonadIO m => Text -> [Text] -> m (Either OllamaError EmbeddingResp)
+ Data.Ollama.Embeddings: embeddingOpsM :: MonadIO m => Text -> [Text] -> Maybe Bool -> Maybe Int -> Maybe ModelOptions -> Maybe OllamaConfig -> m (Either OllamaError EmbeddingResp)
+ Data.Ollama.Generate: ApiError :: Text -> OllamaError
+ Data.Ollama.Generate: DecodeError :: DecodingErrorMessage -> DecodingFailedValue -> OllamaError
+ Data.Ollama.Generate: FileError :: IOException -> OllamaError
+ Data.Ollama.Generate: HttpError :: HttpException -> OllamaError
+ Data.Ollama.Generate: InvalidRequest :: String -> OllamaError
+ Data.Ollama.Generate: JsonFormat :: Format
+ Data.Ollama.Generate: JsonSchemaError :: String -> OllamaError
+ Data.Ollama.Generate: ModelOptions :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Bool -> Maybe [Text] -> Maybe Bool -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Bool -> Maybe Int -> ModelOptions
+ Data.Ollama.Generate: OllamaConfig :: Text -> Int -> Maybe (IO ()) -> Maybe (IO ()) -> Maybe (IO ()) -> Maybe Int -> Maybe Int -> Maybe Manager -> OllamaConfig
+ Data.Ollama.Generate: SchemaFormat :: Schema -> Format
+ Data.Ollama.Generate: TimeoutError :: String -> OllamaError
+ Data.Ollama.Generate: [commonManager] :: OllamaConfig -> Maybe Manager
+ Data.Ollama.Generate: [createdAt] :: GenerateResponse -> !UTCTime
+ Data.Ollama.Generate: [done] :: GenerateResponse -> !Bool
+ Data.Ollama.Generate: [evalCount] :: GenerateResponse -> !Maybe Int64
+ Data.Ollama.Generate: [evalDuration] :: GenerateResponse -> !Maybe Int64
+ Data.Ollama.Generate: [format] :: GenerateOps -> !Maybe Format
+ Data.Ollama.Generate: [frequencyPenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Generate: [genResponse] :: GenerateResponse -> !Text
+ Data.Ollama.Generate: [hostUrl] :: OllamaConfig -> Text
+ Data.Ollama.Generate: [images] :: GenerateOps -> !Maybe [Text]
+ Data.Ollama.Generate: [keepAlive] :: GenerateOps -> !Maybe Int
+ Data.Ollama.Generate: [loadDuration] :: GenerateResponse -> !Maybe Int64
+ Data.Ollama.Generate: [mainGpu] :: ModelOptions -> Maybe Int
+ Data.Ollama.Generate: [minP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Generate: [modelName] :: GenerateOps -> !Text
+ Data.Ollama.Generate: [model] :: GenerateResponse -> !Text
+ Data.Ollama.Generate: [numBatch] :: ModelOptions -> Maybe Int
+ Data.Ollama.Generate: [numCtx] :: ModelOptions -> Maybe Int
+ Data.Ollama.Generate: [numGpu] :: ModelOptions -> Maybe Int
+ Data.Ollama.Generate: [numKeep] :: ModelOptions -> Maybe Int
+ Data.Ollama.Generate: [numPredict] :: ModelOptions -> Maybe Int
+ Data.Ollama.Generate: [numThread] :: ModelOptions -> Maybe Int
+ Data.Ollama.Generate: [numa] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Generate: [onModelError] :: OllamaConfig -> Maybe (IO ())
+ Data.Ollama.Generate: [onModelFinish] :: OllamaConfig -> Maybe (IO ())
+ Data.Ollama.Generate: [onModelStart] :: OllamaConfig -> Maybe (IO ())
+ Data.Ollama.Generate: [options] :: GenerateOps -> !Maybe ModelOptions
+ Data.Ollama.Generate: [penalizeNewline] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Generate: [presencePenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Generate: [promptEvalCount] :: GenerateResponse -> !Maybe Int64
+ Data.Ollama.Generate: [promptEvalDuration] :: GenerateResponse -> !Maybe Int64
+ Data.Ollama.Generate: [prompt] :: GenerateOps -> !Text
+ Data.Ollama.Generate: [raw] :: GenerateOps -> !Maybe Bool
+ Data.Ollama.Generate: [repeatLastN] :: ModelOptions -> Maybe Int
+ Data.Ollama.Generate: [repeatPenalty] :: ModelOptions -> Maybe Double
+ Data.Ollama.Generate: [retryCount] :: OllamaConfig -> Maybe Int
+ Data.Ollama.Generate: [retryDelay] :: OllamaConfig -> Maybe Int
+ Data.Ollama.Generate: [seed] :: ModelOptions -> Maybe Int
+ Data.Ollama.Generate: [stop] :: ModelOptions -> Maybe [Text]
+ Data.Ollama.Generate: [stream] :: GenerateOps -> !Maybe (GenerateResponse -> IO (), IO ())
+ Data.Ollama.Generate: [suffix] :: GenerateOps -> Maybe Text
+ Data.Ollama.Generate: [system] :: GenerateOps -> !Maybe Text
+ Data.Ollama.Generate: [temperature] :: ModelOptions -> Maybe Double
+ Data.Ollama.Generate: [template] :: GenerateOps -> !Maybe Text
+ Data.Ollama.Generate: [think] :: GenerateOps -> !Maybe Bool
+ Data.Ollama.Generate: [thinking] :: GenerateResponse -> !Maybe Text
+ Data.Ollama.Generate: [timeout] :: OllamaConfig -> Int
+ Data.Ollama.Generate: [topK] :: ModelOptions -> Maybe Int
+ Data.Ollama.Generate: [topP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Generate: [totalDuration] :: GenerateResponse -> !Maybe Int64
+ Data.Ollama.Generate: [typicalP] :: ModelOptions -> Maybe Double
+ Data.Ollama.Generate: [useMmap] :: ModelOptions -> Maybe Bool
+ Data.Ollama.Generate: data Format
+ Data.Ollama.Generate: data ModelOptions
+ Data.Ollama.Generate: data OllamaConfig
+ Data.Ollama.Generate: data OllamaError
+ Data.Ollama.Generate: defaultModelOptions :: ModelOptions
+ Data.Ollama.Generate: defaultOllamaConfig :: OllamaConfig
+ Data.Ollama.Generate: generateM :: MonadIO m => GenerateOps -> Maybe OllamaConfig -> m (Either OllamaError GenerateResponse)
+ Data.Ollama.Generate: validateGenerateOps :: GenerateOps -> Either OllamaError GenerateOps
+ Data.Ollama.List: listM :: MonadIO m => Maybe OllamaConfig -> m (Either OllamaError Models)
+ Data.Ollama.Load: loadGenModel :: Text -> IO (Either OllamaError ())
+ Data.Ollama.Load: loadGenModelM :: MonadIO m => Text -> m (Either OllamaError ())
+ Data.Ollama.Load: unloadGenModel :: Text -> IO (Either OllamaError ())
+ Data.Ollama.Load: unloadGenModelM :: MonadIO m => Text -> m (Either OllamaError ())
+ Data.Ollama.Ps: psM :: MonadIO m => Maybe OllamaConfig -> m (Either OllamaError RunningModels)
+ Data.Ollama.Pull: instance Data.Ollama.Common.Types.HasDone Data.Ollama.Pull.PullResp
+ Data.Ollama.Pull: pullM :: MonadIO m => Text -> m (Either OllamaError PullResp)
+ Data.Ollama.Pull: pullOpsM :: MonadIO m => Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> m (Either OllamaError PullResp)
+ Data.Ollama.Push: instance Data.Ollama.Common.Types.HasDone Data.Ollama.Push.PushResp
+ Data.Ollama.Push: pushM :: MonadIO m => Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> m ()
+ Data.Ollama.Show: ModelDetails :: !Maybe Text -> !Text -> !Text -> ![Text] -> !Text -> Text -> ModelDetails
+ Data.Ollama.Show: ShowModelInfo :: !Maybe Text -> !Maybe Int -> !Maybe Int64 -> !Maybe Int -> !Maybe Int -> !Maybe Int -> !Maybe Float -> !Maybe Int -> !Maybe Int -> !Maybe Int -> !Maybe Int -> !Maybe Int -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int -> !Maybe Int -> !Maybe [Text] -> !Maybe Text -> !Maybe Text -> !Maybe [Text] -> !Maybe [Text] -> ShowModelInfo
+ Data.Ollama.Show: [capabilities] :: ShowModelResponse -> Maybe [Text]
+ Data.Ollama.Show: [details] :: ShowModelResponse -> !ModelDetails
+ Data.Ollama.Show: [families] :: ModelDetails -> ![Text]
+ Data.Ollama.Show: [family] :: ModelDetails -> !Text
+ Data.Ollama.Show: [format] :: ModelDetails -> !Text
+ Data.Ollama.Show: [generalArchitecture] :: ShowModelInfo -> !Maybe Text
+ Data.Ollama.Show: [generalFileType] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [generalParameterCount] :: ShowModelInfo -> !Maybe Int64
+ Data.Ollama.Show: [generalQuantizationVersion] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [license] :: ShowModelResponse -> !Maybe Text
+ Data.Ollama.Show: [llamaAttentionHeadCountKV] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [llamaAttentionHeadCount] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [llamaAttentionLayerNormRMSEpsilon] :: ShowModelInfo -> !Maybe Float
+ Data.Ollama.Show: [llamaBlockCount] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [llamaContextLength] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [llamaEmbeddingLength] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [llamaFeedForwardLength] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [llamaRopeDimensionCount] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [llamaRopeFreqBase] :: ShowModelInfo -> !Maybe Int64
+ Data.Ollama.Show: [llamaVocabSize] :: ShowModelInfo -> !Maybe Int64
+ Data.Ollama.Show: [modelFile] :: ShowModelResponse -> !Text
+ Data.Ollama.Show: [modelInfo] :: ShowModelResponse -> !ShowModelInfo
+ Data.Ollama.Show: [parameterSize] :: ModelDetails -> !Text
+ Data.Ollama.Show: [parameters] :: ShowModelResponse -> !Maybe Text
+ Data.Ollama.Show: [parentModel] :: ModelDetails -> !Maybe Text
+ Data.Ollama.Show: [quantizationLevel] :: ModelDetails -> Text
+ Data.Ollama.Show: [template] :: ShowModelResponse -> !Maybe Text
+ Data.Ollama.Show: [tokenizerGgmlBosToken_id] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [tokenizerGgmlEosToken_id] :: ShowModelInfo -> !Maybe Int
+ Data.Ollama.Show: [tokenizerGgmlMerges] :: ShowModelInfo -> !Maybe [Text]
+ Data.Ollama.Show: [tokenizerGgmlMode] :: ShowModelInfo -> !Maybe Text
+ Data.Ollama.Show: [tokenizerGgmlPre] :: ShowModelInfo -> !Maybe Text
+ Data.Ollama.Show: [tokenizerGgmlTokenType] :: ShowModelInfo -> !Maybe [Text]
+ Data.Ollama.Show: [tokenizerGgmlTokens] :: ShowModelInfo -> !Maybe [Text]
+ Data.Ollama.Show: data ModelDetails
+ Data.Ollama.Show: data ShowModelInfo
+ Data.Ollama.Show: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Show.ShowModelInfo
+ Data.Ollama.Show: instance GHC.Classes.Eq Data.Ollama.Show.ShowModelInfo
+ Data.Ollama.Show: instance GHC.Show.Show Data.Ollama.Show.ShowModelInfo
+ Data.Ollama.Show: showModelM :: MonadIO m => Text -> m (Either OllamaError ShowModelResponse)
+ Data.Ollama.Show: showModelOpsM :: MonadIO m => Text -> Maybe Bool -> Maybe OllamaConfig -> m (Either OllamaError ShowModelResponse)
+ Ollama: ApiError :: Text -> OllamaError
+ Ollama: DecodeError :: DecodingErrorMessage -> DecodingFailedValue -> OllamaError
+ Ollama: FileError :: IOException -> OllamaError
+ Ollama: FunctionDef :: Text -> Maybe Text -> Maybe FunctionParameters -> Maybe Bool -> FunctionDef
+ Ollama: FunctionParameters :: Text -> Maybe (Map Text FunctionParameters) -> Maybe [Text] -> Maybe Bool -> FunctionParameters
+ Ollama: HttpError :: HttpException -> OllamaError
+ Ollama: InputTool :: Text -> FunctionDef -> InputTool
+ Ollama: InvalidRequest :: String -> OllamaError
+ Ollama: JsonSchemaError :: String -> OllamaError
+ Ollama: ModelDetails :: !Maybe Text -> !Text -> !Text -> ![Text] -> !Text -> Text -> ModelDetails
+ Ollama: ModelOptions :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Int -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Double -> Maybe Bool -> Maybe [Text] -> Maybe Bool -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Bool -> Maybe Int -> ModelOptions
+ Ollama: OllamaConfig :: Text -> Int -> Maybe (IO ()) -> Maybe (IO ()) -> Maybe (IO ()) -> Maybe Int -> Maybe Int -> Maybe Manager -> OllamaConfig
+ Ollama: OutputFunction :: Text -> Map Text Value -> OutputFunction
+ Ollama: ShowModelInfo :: !Maybe Text -> !Maybe Int -> !Maybe Int64 -> !Maybe Int -> !Maybe Int -> !Maybe Int -> !Maybe Float -> !Maybe Int -> !Maybe Int -> !Maybe Int -> !Maybe Int -> !Maybe Int -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int -> !Maybe Int -> !Maybe [Text] -> !Maybe Text -> !Maybe Text -> !Maybe [Text] -> !Maybe [Text] -> ShowModelInfo
+ Ollama: TimeoutError :: String -> OllamaError
+ Ollama: ToolCall :: OutputFunction -> ToolCall
+ Ollama: Version :: Text -> Version
+ Ollama: [additionalProperties] :: FunctionParameters -> Maybe Bool
+ Ollama: [arguments] :: OutputFunction -> Map Text Value
+ Ollama: [capabilities] :: ShowModelResponse -> Maybe [Text]
+ Ollama: [commonManager] :: OllamaConfig -> Maybe Manager
+ Ollama: [families] :: ModelDetails -> ![Text]
+ Ollama: [family] :: ModelDetails -> !Text
+ Ollama: [frequencyPenalty] :: ModelOptions -> Maybe Double
+ Ollama: [functionDescription] :: FunctionDef -> Maybe Text
+ Ollama: [functionName] :: FunctionDef -> Text
+ Ollama: [functionParameters] :: FunctionDef -> Maybe FunctionParameters
+ Ollama: [functionStrict] :: FunctionDef -> Maybe Bool
+ Ollama: [function] :: InputTool -> FunctionDef
+ Ollama: [genResponse] :: GenerateResponse -> !Text
+ Ollama: [generalArchitecture] :: ShowModelInfo -> !Maybe Text
+ Ollama: [generalFileType] :: ShowModelInfo -> !Maybe Int
+ Ollama: [generalParameterCount] :: ShowModelInfo -> !Maybe Int64
+ Ollama: [generalQuantizationVersion] :: ShowModelInfo -> !Maybe Int
+ Ollama: [input] :: EmbeddingOps -> ![Text]
+ Ollama: [keepAliveEmbed] :: EmbeddingOps -> !Maybe Int
+ Ollama: [license] :: ShowModelResponse -> !Maybe Text
+ Ollama: [llamaAttentionHeadCountKV] :: ShowModelInfo -> !Maybe Int
+ Ollama: [llamaAttentionHeadCount] :: ShowModelInfo -> !Maybe Int
+ Ollama: [llamaAttentionLayerNormRMSEpsilon] :: ShowModelInfo -> !Maybe Float
+ Ollama: [llamaBlockCount] :: ShowModelInfo -> !Maybe Int
+ Ollama: [llamaContextLength] :: ShowModelInfo -> !Maybe Int
+ Ollama: [llamaEmbeddingLength] :: ShowModelInfo -> !Maybe Int
+ Ollama: [llamaFeedForwardLength] :: ShowModelInfo -> !Maybe Int
+ Ollama: [llamaRopeDimensionCount] :: ShowModelInfo -> !Maybe Int
+ Ollama: [llamaRopeFreqBase] :: ShowModelInfo -> !Maybe Int64
+ Ollama: [llamaVocabSize] :: ShowModelInfo -> !Maybe Int64
+ Ollama: [mainGpu] :: ModelOptions -> Maybe Int
+ Ollama: [minP] :: ModelOptions -> Maybe Double
+ Ollama: [modelFile] :: ShowModelResponse -> !Text
+ Ollama: [modelInfo] :: ShowModelResponse -> !ShowModelInfo
+ Ollama: [modelOptions] :: EmbeddingOps -> !Maybe ModelOptions
+ Ollama: [numBatch] :: ModelOptions -> Maybe Int
+ Ollama: [numCtx] :: ModelOptions -> Maybe Int
+ Ollama: [numGpu] :: ModelOptions -> Maybe Int
+ Ollama: [numKeep] :: ModelOptions -> Maybe Int
+ Ollama: [numPredict] :: ModelOptions -> Maybe Int
+ Ollama: [numThread] :: ModelOptions -> Maybe Int
+ Ollama: [numa] :: ModelOptions -> Maybe Bool
+ Ollama: [onModelError] :: OllamaConfig -> Maybe (IO ())
+ Ollama: [onModelFinish] :: OllamaConfig -> Maybe (IO ())
+ Ollama: [onModelStart] :: OllamaConfig -> Maybe (IO ())
+ Ollama: [outputFunctionName] :: OutputFunction -> Text
+ Ollama: [outputFunction] :: ToolCall -> OutputFunction
+ Ollama: [parameterProperties] :: FunctionParameters -> Maybe (Map Text FunctionParameters)
+ Ollama: [parameterSize] :: ModelDetails -> !Text
+ Ollama: [parameterType] :: FunctionParameters -> Text
+ Ollama: [parameters] :: ShowModelResponse -> !Maybe Text
+ Ollama: [parentModel] :: ModelDetails -> !Maybe Text
+ Ollama: [penalizeNewline] :: ModelOptions -> Maybe Bool
+ Ollama: [presencePenalty] :: ModelOptions -> Maybe Double
+ Ollama: [prompt] :: GenerateOps -> !Text
+ Ollama: [quantizationLevel] :: ModelDetails -> Text
+ Ollama: [raw] :: GenerateOps -> !Maybe Bool
+ Ollama: [repeatLastN] :: ModelOptions -> Maybe Int
+ Ollama: [repeatPenalty] :: ModelOptions -> Maybe Double
+ Ollama: [requiredParams] :: FunctionParameters -> Maybe [Text]
+ Ollama: [respondedEmbeddings] :: EmbeddingResp -> ![[Float]]
+ Ollama: [respondedModel] :: EmbeddingResp -> !Text
+ Ollama: [retryCount] :: OllamaConfig -> Maybe Int
+ Ollama: [retryDelay] :: OllamaConfig -> Maybe Int
+ Ollama: [seed] :: ModelOptions -> Maybe Int
+ Ollama: [stop] :: ModelOptions -> Maybe [Text]
+ Ollama: [suffix] :: GenerateOps -> Maybe Text
+ Ollama: [system] :: GenerateOps -> !Maybe Text
+ Ollama: [temperature] :: ModelOptions -> Maybe Double
+ Ollama: [template] :: ShowModelResponse -> !Maybe Text
+ Ollama: [think] :: ChatOps -> !Maybe Bool
+ Ollama: [thinking] :: Message -> !Maybe Text
+ Ollama: [timeout] :: OllamaConfig -> Int
+ Ollama: [tokenizerGgmlBosToken_id] :: ShowModelInfo -> !Maybe Int
+ Ollama: [tokenizerGgmlEosToken_id] :: ShowModelInfo -> !Maybe Int
+ Ollama: [tokenizerGgmlMerges] :: ShowModelInfo -> !Maybe [Text]
+ Ollama: [tokenizerGgmlMode] :: ShowModelInfo -> !Maybe Text
+ Ollama: [tokenizerGgmlPre] :: ShowModelInfo -> !Maybe Text
+ Ollama: [tokenizerGgmlTokenType] :: ShowModelInfo -> !Maybe [Text]
+ Ollama: [tokenizerGgmlTokens] :: ShowModelInfo -> !Maybe [Text]
+ Ollama: [toolType] :: InputTool -> Text
+ Ollama: [topK] :: ModelOptions -> Maybe Int
+ Ollama: [topP] :: ModelOptions -> Maybe Double
+ Ollama: [truncateInput] :: EmbeddingOps -> !Maybe Bool
+ Ollama: [typicalP] :: ModelOptions -> Maybe Double
+ Ollama: [useMmap] :: ModelOptions -> Maybe Bool
+ Ollama: chatM :: MonadIO m => ChatOps -> Maybe OllamaConfig -> m (Either OllamaError ChatResponse)
+ Ollama: copyModelM :: MonadIO m => Text -> Text -> Maybe OllamaConfig -> m (Either OllamaError ())
+ Ollama: createModelM :: MonadIO m => Text -> Maybe Text -> Maybe Bool -> Maybe FilePath -> Maybe OllamaConfig -> m ()
+ Ollama: data FunctionDef
+ Ollama: data FunctionParameters
+ Ollama: data InputTool
+ Ollama: data ModelDetails
+ Ollama: data ModelOptions
+ Ollama: data OllamaConfig
+ Ollama: data OllamaError
+ Ollama: data OutputFunction
+ Ollama: data ShowModelInfo
+ Ollama: defaultModelOptions :: ModelOptions
+ Ollama: defaultOllamaConfig :: OllamaConfig
+ Ollama: deleteModelM :: MonadIO m => Text -> Maybe OllamaConfig -> m (Either OllamaError ())
+ Ollama: embeddingM :: MonadIO m => Text -> [Text] -> m (Either OllamaError EmbeddingResp)
+ Ollama: embeddingOpsM :: MonadIO m => Text -> [Text] -> Maybe Bool -> Maybe Int -> Maybe ModelOptions -> Maybe OllamaConfig -> m (Either OllamaError EmbeddingResp)
+ Ollama: encodeImage :: FilePath -> IO (Maybe Text)
+ Ollama: generateM :: MonadIO m => GenerateOps -> Maybe OllamaConfig -> m (Either OllamaError GenerateResponse)
+ Ollama: getVersion :: IO (Either OllamaError Version)
+ Ollama: loadGenModel :: Text -> IO (Either OllamaError ())
+ Ollama: loadGenModelM :: MonadIO m => Text -> m (Either OllamaError ())
+ Ollama: newtype ToolCall
+ Ollama: newtype Version
+ Ollama: psM :: MonadIO m => Maybe OllamaConfig -> m (Either OllamaError RunningModels)
+ Ollama: pullM :: MonadIO m => Text -> m (Either OllamaError PullResp)
+ Ollama: pullOpsM :: MonadIO m => Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> m (Either OllamaError PullResp)
+ Ollama: pushM :: MonadIO m => Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> m ()
+ Ollama: showModelM :: MonadIO m => Text -> m (Either OllamaError ShowModelResponse)
+ Ollama: showModelOpsM :: MonadIO m => Text -> Maybe Bool -> Maybe OllamaConfig -> m (Either OllamaError ShowModelResponse)
+ Ollama: unloadGenModel :: Text -> IO (Either OllamaError ())
+ Ollama: unloadGenModelM :: MonadIO m => Text -> m (Either OllamaError ())
+ Ollama: withOllamaRequest :: ToJSON payload => Text -> ByteString -> Maybe payload -> Maybe OllamaConfig -> (Response BodyReader -> IO (Either OllamaError response)) -> IO (Either OllamaError response)
+ Ollama: withOnModelError :: IO () -> OllamaConfig -> OllamaConfig
+ Ollama: withOnModelFinish :: IO () -> OllamaConfig -> OllamaConfig
+ Ollama: withOnModelStart :: IO () -> OllamaConfig -> OllamaConfig
- Data.Ollama.Chat: ChatOps :: Text -> NonEmpty Message -> Maybe [Value] -> Maybe Format -> Maybe (ChatResponse -> IO (), IO ()) -> Maybe Text -> Maybe Text -> Maybe Int -> Maybe Value -> ChatOps
+ Data.Ollama.Chat: ChatOps :: !Text -> !NonEmpty Message -> !Maybe [InputTool] -> !Maybe Format -> !Maybe (ChatResponse -> IO (), IO ()) -> !Maybe Int -> !Maybe ModelOptions -> !Maybe Bool -> ChatOps
- Data.Ollama.Chat: ChatResponse :: Text -> UTCTime -> Maybe Message -> Bool -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> ChatResponse
+ Data.Ollama.Chat: ChatResponse :: !Text -> !UTCTime -> !Maybe Message -> !Bool -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> ChatResponse
- Data.Ollama.Chat: Message :: Role -> Text -> Maybe [Text] -> Maybe [Value] -> Message
+ Data.Ollama.Chat: Message :: !Role -> !Text -> !Maybe [Text] -> !Maybe [ToolCall] -> !Maybe Text -> Message
- Data.Ollama.Chat: SchemaFormat :: Value -> Format
+ Data.Ollama.Chat: SchemaFormat :: Schema -> Format
- Data.Ollama.Chat: [chatModelName] :: ChatOps -> Text
+ Data.Ollama.Chat: [chatModelName] :: ChatOps -> !Text
- Data.Ollama.Chat: [content] :: Message -> Text
+ Data.Ollama.Chat: [content] :: Message -> !Text
- Data.Ollama.Chat: [createdAt] :: ChatResponse -> UTCTime
+ Data.Ollama.Chat: [createdAt] :: ChatResponse -> !UTCTime
- Data.Ollama.Chat: [done] :: ChatResponse -> Bool
+ Data.Ollama.Chat: [done] :: ChatResponse -> !Bool
- Data.Ollama.Chat: [evalCount] :: ChatResponse -> Maybe Int64
+ Data.Ollama.Chat: [evalCount] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: [evalDuration] :: ChatResponse -> Maybe Int64
+ Data.Ollama.Chat: [evalDuration] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: [format] :: ChatOps -> Maybe Format
+ Data.Ollama.Chat: [format] :: ChatOps -> !Maybe Format
- Data.Ollama.Chat: [hostUrl] :: ChatOps -> Maybe Text
+ Data.Ollama.Chat: [hostUrl] :: OllamaConfig -> Text
- Data.Ollama.Chat: [images] :: Message -> Maybe [Text]
+ Data.Ollama.Chat: [images] :: Message -> !Maybe [Text]
- Data.Ollama.Chat: [keepAlive] :: ChatOps -> Maybe Text
+ Data.Ollama.Chat: [keepAlive] :: ChatOps -> !Maybe Int
- Data.Ollama.Chat: [loadDuration] :: ChatResponse -> Maybe Int64
+ Data.Ollama.Chat: [loadDuration] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: [message] :: ChatResponse -> Maybe Message
+ Data.Ollama.Chat: [message] :: ChatResponse -> !Maybe Message
- Data.Ollama.Chat: [messages] :: ChatOps -> NonEmpty Message
+ Data.Ollama.Chat: [messages] :: ChatOps -> !NonEmpty Message
- Data.Ollama.Chat: [model] :: ChatResponse -> Text
+ Data.Ollama.Chat: [model] :: ChatResponse -> !Text
- Data.Ollama.Chat: [options] :: ChatOps -> Maybe Value
+ Data.Ollama.Chat: [options] :: ChatOps -> !Maybe ModelOptions
- Data.Ollama.Chat: [promptEvalCount] :: ChatResponse -> Maybe Int64
+ Data.Ollama.Chat: [promptEvalCount] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: [promptEvalDuration] :: ChatResponse -> Maybe Int64
+ Data.Ollama.Chat: [promptEvalDuration] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: [role] :: Message -> Role
+ Data.Ollama.Chat: [role] :: Message -> !Role
- Data.Ollama.Chat: [stream] :: ChatOps -> Maybe (ChatResponse -> IO (), IO ())
+ Data.Ollama.Chat: [stream] :: ChatOps -> !Maybe (ChatResponse -> IO (), IO ())
- Data.Ollama.Chat: [tool_calls] :: Message -> Maybe [Value]
+ Data.Ollama.Chat: [tool_calls] :: Message -> !Maybe [ToolCall]
- Data.Ollama.Chat: [tools] :: ChatOps -> Maybe [Value]
+ Data.Ollama.Chat: [tools] :: ChatOps -> !Maybe [InputTool]
- Data.Ollama.Chat: [totalDuration] :: ChatResponse -> Maybe Int64
+ Data.Ollama.Chat: [totalDuration] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: chat :: ChatOps -> IO (Either String ChatResponse)
+ Data.Ollama.Chat: chat :: ChatOps -> Maybe OllamaConfig -> IO (Either OllamaError ChatResponse)
- Data.Ollama.Common.Types: ModelDetails :: Maybe Text -> Text -> Text -> [Text] -> Text -> Text -> ModelDetails
+ Data.Ollama.Common.Types: ModelDetails :: !Maybe Text -> !Text -> !Text -> ![Text] -> !Text -> Text -> ModelDetails
- Data.Ollama.Common.Types: SchemaFormat :: Value -> Format
+ Data.Ollama.Common.Types: SchemaFormat :: Schema -> Format
- Data.Ollama.Copy: copyModel :: Text -> Text -> IO ()
+ Data.Ollama.Copy: copyModel :: Text -> Text -> Maybe OllamaConfig -> IO (Either OllamaError ())
- Data.Ollama.Create: createModel :: Text -> Maybe Text -> Maybe FilePath -> IO ()
+ Data.Ollama.Create: createModel :: Text -> Maybe Text -> Maybe Bool -> Maybe FilePath -> Maybe OllamaConfig -> IO ()
- Data.Ollama.Delete: deleteModel :: Text -> IO ()
+ Data.Ollama.Delete: deleteModel :: Text -> Maybe OllamaConfig -> IO (Either OllamaError ())
- Data.Ollama.Embeddings: EmbeddingOps :: Text -> Text -> Maybe Bool -> Maybe Text -> EmbeddingOps
+ Data.Ollama.Embeddings: EmbeddingOps :: !Text -> ![Text] -> !Maybe Bool -> !Maybe Int -> !Maybe ModelOptions -> EmbeddingOps
- Data.Ollama.Embeddings: EmbeddingResp :: Text -> [[Float]] -> EmbeddingResp
+ Data.Ollama.Embeddings: EmbeddingResp :: !Text -> ![[Float]] -> EmbeddingResp
- Data.Ollama.Embeddings: embedding :: Text -> Text -> IO (Either String EmbeddingResp)
+ Data.Ollama.Embeddings: embedding :: Text -> [Text] -> IO (Either OllamaError EmbeddingResp)
- Data.Ollama.Embeddings: embeddingOps :: Text -> Text -> Maybe Bool -> Maybe Text -> IO (Either String EmbeddingResp)
+ Data.Ollama.Embeddings: embeddingOps :: Text -> [Text] -> Maybe Bool -> Maybe Int -> Maybe ModelOptions -> Maybe OllamaConfig -> IO (Either OllamaError EmbeddingResp)
- Data.Ollama.Generate: GenerateOps :: Text -> Text -> Maybe Text -> Maybe [Text] -> Maybe Format -> Maybe Text -> Maybe Text -> Maybe (GenerateResponse -> IO (), IO ()) -> Maybe Bool -> Maybe Text -> Maybe Text -> Maybe Int -> Maybe Value -> GenerateOps
+ Data.Ollama.Generate: GenerateOps :: !Text -> !Text -> Maybe Text -> !Maybe [Text] -> !Maybe Format -> !Maybe Text -> !Maybe Text -> !Maybe (GenerateResponse -> IO (), IO ()) -> !Maybe Bool -> !Maybe Int -> !Maybe ModelOptions -> !Maybe Bool -> GenerateOps
- Data.Ollama.Generate: GenerateResponse :: Text -> UTCTime -> Text -> Bool -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> GenerateResponse
+ Data.Ollama.Generate: GenerateResponse :: !Text -> !UTCTime -> !Text -> !Bool -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Text -> GenerateResponse
- Data.Ollama.Generate: generate :: GenerateOps -> IO (Either String GenerateResponse)
+ Data.Ollama.Generate: generate :: GenerateOps -> Maybe OllamaConfig -> IO (Either OllamaError GenerateResponse)
- Data.Ollama.List: ModelInfo :: Text -> UTCTime -> Int64 -> Text -> ModelDetails -> ModelInfo
+ Data.Ollama.List: ModelInfo :: !Text -> !UTCTime -> !Int64 -> !Text -> !ModelDetails -> ModelInfo
- Data.Ollama.List: [details] :: ModelInfo -> ModelDetails
+ Data.Ollama.List: [details] :: ModelInfo -> !ModelDetails
- Data.Ollama.List: [digest] :: ModelInfo -> Text
+ Data.Ollama.List: [digest] :: ModelInfo -> !Text
- Data.Ollama.List: [modifiedAt] :: ModelInfo -> UTCTime
+ Data.Ollama.List: [modifiedAt] :: ModelInfo -> !UTCTime
- Data.Ollama.List: [name] :: ModelInfo -> Text
+ Data.Ollama.List: [name] :: ModelInfo -> !Text
- Data.Ollama.List: [size] :: ModelInfo -> Int64
+ Data.Ollama.List: [size] :: ModelInfo -> !Int64
- Data.Ollama.List: list :: IO (Maybe Models)
+ Data.Ollama.List: list :: Maybe OllamaConfig -> IO (Either OllamaError Models)
- Data.Ollama.Ps: RunningModel :: Text -> Text -> Int64 -> Text -> ModelDetails -> UTCTime -> Int64 -> RunningModel
+ Data.Ollama.Ps: RunningModel :: !Text -> !Text -> !Int64 -> !Text -> !ModelDetails -> !UTCTime -> !Int64 -> RunningModel
- Data.Ollama.Ps: [expiresAt] :: RunningModel -> UTCTime
+ Data.Ollama.Ps: [expiresAt] :: RunningModel -> !UTCTime
- Data.Ollama.Ps: [modelDetails] :: RunningModel -> ModelDetails
+ Data.Ollama.Ps: [modelDetails] :: RunningModel -> !ModelDetails
- Data.Ollama.Ps: [modelDigest] :: RunningModel -> Text
+ Data.Ollama.Ps: [modelDigest] :: RunningModel -> !Text
- Data.Ollama.Ps: [modelName] :: RunningModel -> Text
+ Data.Ollama.Ps: [modelName] :: RunningModel -> !Text
- Data.Ollama.Ps: [name_] :: RunningModel -> Text
+ Data.Ollama.Ps: [name_] :: RunningModel -> !Text
- Data.Ollama.Ps: [sizeVRam] :: RunningModel -> Int64
+ Data.Ollama.Ps: [sizeVRam] :: RunningModel -> !Int64
- Data.Ollama.Ps: [size_] :: RunningModel -> Int64
+ Data.Ollama.Ps: [size_] :: RunningModel -> !Int64
- Data.Ollama.Ps: ps :: IO (Maybe RunningModels)
+ Data.Ollama.Ps: ps :: Maybe OllamaConfig -> IO (Either OllamaError RunningModels)
- Data.Ollama.Pull: pull :: Text -> IO ()
+ Data.Ollama.Pull: pull :: Text -> IO (Either OllamaError PullResp)
- Data.Ollama.Pull: pullOps :: Text -> Maybe Bool -> Maybe Bool -> IO ()
+ Data.Ollama.Pull: pullOps :: Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> IO (Either OllamaError PullResp)
- Data.Ollama.Push: push :: Text -> IO ()
+ Data.Ollama.Push: push :: Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> IO ()
- Data.Ollama.Show: ShowModelResponse :: Text -> Text -> Text -> ModelDetails -> ModelInfo -> ShowModelResponse
+ Data.Ollama.Show: ShowModelResponse :: !Text -> !Maybe Text -> !Maybe Text -> !ModelDetails -> !ShowModelInfo -> !Maybe Text -> Maybe [Text] -> ShowModelResponse
- Data.Ollama.Show: showModel :: Text -> IO (Maybe ShowModelResponse)
+ Data.Ollama.Show: showModel :: Text -> IO (Either OllamaError ShowModelResponse)
- Data.Ollama.Show: showModelOps :: Text -> Maybe Bool -> IO (Maybe ShowModelResponse)
+ Data.Ollama.Show: showModelOps :: Text -> Maybe Bool -> Maybe OllamaConfig -> IO (Either OllamaError ShowModelResponse)
- Ollama: ChatOps :: Text -> NonEmpty Message -> Maybe [Value] -> Maybe Format -> Maybe (ChatResponse -> IO (), IO ()) -> Maybe Text -> Maybe Text -> Maybe Int -> Maybe Value -> ChatOps
+ Ollama: ChatOps :: !Text -> !NonEmpty Message -> !Maybe [InputTool] -> !Maybe Format -> !Maybe (ChatResponse -> IO (), IO ()) -> !Maybe Int -> !Maybe ModelOptions -> !Maybe Bool -> ChatOps
- Ollama: ChatResponse :: Text -> UTCTime -> Maybe Message -> Bool -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> ChatResponse
+ Ollama: ChatResponse :: !Text -> !UTCTime -> !Maybe Message -> !Bool -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> ChatResponse
- Ollama: EmbeddingOps :: Text -> Text -> Maybe Bool -> Maybe Text -> EmbeddingOps
+ Ollama: EmbeddingOps :: !Text -> ![Text] -> !Maybe Bool -> !Maybe Int -> !Maybe ModelOptions -> EmbeddingOps
- Ollama: EmbeddingResp :: Text -> [[Float]] -> EmbeddingResp
+ Ollama: EmbeddingResp :: !Text -> ![[Float]] -> EmbeddingResp
- Ollama: GenerateOps :: Text -> Text -> Maybe Text -> Maybe [Text] -> Maybe Format -> Maybe Text -> Maybe Text -> Maybe (GenerateResponse -> IO (), IO ()) -> Maybe Bool -> Maybe Text -> Maybe Text -> Maybe Int -> Maybe Value -> GenerateOps
+ Ollama: GenerateOps :: !Text -> !Text -> Maybe Text -> !Maybe [Text] -> !Maybe Format -> !Maybe Text -> !Maybe Text -> !Maybe (GenerateResponse -> IO (), IO ()) -> !Maybe Bool -> !Maybe Int -> !Maybe ModelOptions -> !Maybe Bool -> GenerateOps
- Ollama: GenerateResponse :: Text -> UTCTime -> Text -> Bool -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> GenerateResponse
+ Ollama: GenerateResponse :: !Text -> !UTCTime -> !Text -> !Bool -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Text -> GenerateResponse
- Ollama: Message :: Role -> Text -> Maybe [Text] -> Maybe [Value] -> Message
+ Ollama: Message :: !Role -> !Text -> !Maybe [Text] -> !Maybe [ToolCall] -> !Maybe Text -> Message
- Ollama: ModelInfo :: Text -> UTCTime -> Int64 -> Text -> ModelDetails -> ModelInfo
+ Ollama: ModelInfo :: !Text -> !UTCTime -> !Int64 -> !Text -> !ModelDetails -> ModelInfo
- Ollama: RunningModel :: Text -> Text -> Int64 -> Text -> ModelDetails -> UTCTime -> Int64 -> RunningModel
+ Ollama: RunningModel :: !Text -> !Text -> !Int64 -> !Text -> !ModelDetails -> !UTCTime -> !Int64 -> RunningModel
- Ollama: SchemaFormat :: Value -> Format
+ Ollama: SchemaFormat :: Schema -> Format
- Ollama: ShowModelResponse :: Text -> Text -> Text -> ModelDetails -> ModelInfo -> ShowModelResponse
+ Ollama: ShowModelResponse :: !Text -> !Maybe Text -> !Maybe Text -> !ModelDetails -> !ShowModelInfo -> !Maybe Text -> Maybe [Text] -> ShowModelResponse
- Ollama: [chatModelName] :: ChatOps -> Text
+ Ollama: [chatModelName] :: ChatOps -> !Text
- Ollama: [content] :: Message -> Text
+ Ollama: [content] :: Message -> !Text
- Ollama: [createdAt] :: ChatResponse -> UTCTime
+ Ollama: [createdAt] :: ChatResponse -> !UTCTime
- Ollama: [details] :: ModelInfo -> ModelDetails
+ Ollama: [details] :: ModelInfo -> !ModelDetails
- Ollama: [digest] :: ModelInfo -> Text
+ Ollama: [digest] :: ModelInfo -> !Text
- Ollama: [done] :: ChatResponse -> Bool
+ Ollama: [done] :: ChatResponse -> !Bool
- Ollama: [evalCount] :: ChatResponse -> Maybe Int64
+ Ollama: [evalCount] :: ChatResponse -> !Maybe Int64
- Ollama: [evalDuration] :: ChatResponse -> Maybe Int64
+ Ollama: [evalDuration] :: ChatResponse -> !Maybe Int64
- Ollama: [expiresAt] :: RunningModel -> UTCTime
+ Ollama: [expiresAt] :: RunningModel -> !UTCTime
- Ollama: [format] :: ChatOps -> Maybe Format
+ Ollama: [format] :: ModelDetails -> !Text
- Ollama: [hostUrl] :: ChatOps -> Maybe Text
+ Ollama: [hostUrl] :: OllamaConfig -> Text
- Ollama: [images] :: Message -> Maybe [Text]
+ Ollama: [images] :: Message -> !Maybe [Text]
- Ollama: [keepAlive] :: ChatOps -> Maybe Text
+ Ollama: [keepAlive] :: ChatOps -> !Maybe Int
- Ollama: [loadDuration] :: ChatResponse -> Maybe Int64
+ Ollama: [loadDuration] :: ChatResponse -> !Maybe Int64
- Ollama: [message] :: ChatResponse -> Maybe Message
+ Ollama: [message] :: ChatResponse -> !Maybe Message
- Ollama: [messages] :: ChatOps -> NonEmpty Message
+ Ollama: [messages] :: ChatOps -> !NonEmpty Message
- Ollama: [modelDetails] :: RunningModel -> ModelDetails
+ Ollama: [modelDetails] :: RunningModel -> !ModelDetails
- Ollama: [modelDigest] :: RunningModel -> Text
+ Ollama: [modelDigest] :: RunningModel -> !Text
- Ollama: [modelName] :: RunningModel -> Text
+ Ollama: [modelName] :: RunningModel -> !Text
- Ollama: [model] :: ChatResponse -> Text
+ Ollama: [model] :: EmbeddingOps -> !Text
- Ollama: [modifiedAt] :: ModelInfo -> UTCTime
+ Ollama: [modifiedAt] :: ModelInfo -> !UTCTime
- Ollama: [name] :: ModelInfo -> Text
+ Ollama: [name] :: ModelInfo -> !Text
- Ollama: [name_] :: RunningModel -> Text
+ Ollama: [name_] :: RunningModel -> !Text
- Ollama: [options] :: ChatOps -> Maybe Value
+ Ollama: [options] :: ChatOps -> !Maybe ModelOptions
- Ollama: [promptEvalCount] :: ChatResponse -> Maybe Int64
+ Ollama: [promptEvalCount] :: ChatResponse -> !Maybe Int64
- Ollama: [promptEvalDuration] :: ChatResponse -> Maybe Int64
+ Ollama: [promptEvalDuration] :: ChatResponse -> !Maybe Int64
- Ollama: [role] :: Message -> Role
+ Ollama: [role] :: Message -> !Role
- Ollama: [sizeVRam] :: RunningModel -> Int64
+ Ollama: [sizeVRam] :: RunningModel -> !Int64
- Ollama: [size] :: ModelInfo -> Int64
+ Ollama: [size] :: ModelInfo -> !Int64
- Ollama: [size_] :: RunningModel -> Int64
+ Ollama: [size_] :: RunningModel -> !Int64
- Ollama: [stream] :: ChatOps -> Maybe (ChatResponse -> IO (), IO ())
+ Ollama: [stream] :: ChatOps -> !Maybe (ChatResponse -> IO (), IO ())
- Ollama: [tool_calls] :: Message -> Maybe [Value]
+ Ollama: [tool_calls] :: Message -> !Maybe [ToolCall]
- Ollama: [tools] :: ChatOps -> Maybe [Value]
+ Ollama: [tools] :: ChatOps -> !Maybe [InputTool]
- Ollama: [totalDuration] :: ChatResponse -> Maybe Int64
+ Ollama: [totalDuration] :: ChatResponse -> !Maybe Int64
- Ollama: chat :: ChatOps -> IO (Either String ChatResponse)
+ Ollama: chat :: ChatOps -> Maybe OllamaConfig -> IO (Either OllamaError ChatResponse)
- Ollama: copyModel :: Text -> Text -> IO ()
+ Ollama: copyModel :: Text -> Text -> Maybe OllamaConfig -> IO (Either OllamaError ())
- Ollama: createModel :: Text -> Maybe Text -> Maybe FilePath -> IO ()
+ Ollama: createModel :: Text -> Maybe Text -> Maybe Bool -> Maybe FilePath -> Maybe OllamaConfig -> IO ()
- Ollama: deleteModel :: Text -> IO ()
+ Ollama: deleteModel :: Text -> Maybe OllamaConfig -> IO (Either OllamaError ())
- Ollama: embedding :: Text -> Text -> IO (Either String EmbeddingResp)
+ Ollama: embedding :: Text -> [Text] -> IO (Either OllamaError EmbeddingResp)
- Ollama: embeddingOps :: Text -> Text -> Maybe Bool -> Maybe Text -> IO (Either String EmbeddingResp)
+ Ollama: embeddingOps :: Text -> [Text] -> Maybe Bool -> Maybe Int -> Maybe ModelOptions -> Maybe OllamaConfig -> IO (Either OllamaError EmbeddingResp)
- Ollama: generate :: GenerateOps -> IO (Either String GenerateResponse)
+ Ollama: generate :: GenerateOps -> Maybe OllamaConfig -> IO (Either OllamaError GenerateResponse)
- Ollama: list :: IO (Maybe Models)
+ Ollama: list :: Maybe OllamaConfig -> IO (Either OllamaError Models)
- Ollama: ps :: IO (Maybe RunningModels)
+ Ollama: ps :: Maybe OllamaConfig -> IO (Either OllamaError RunningModels)
- Ollama: pull :: Text -> IO ()
+ Ollama: pull :: Text -> IO (Either OllamaError PullResp)
- Ollama: pullOps :: Text -> Maybe Bool -> Maybe Bool -> IO ()
+ Ollama: pullOps :: Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> IO (Either OllamaError PullResp)
- Ollama: push :: Text -> IO ()
+ Ollama: push :: Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> IO ()
- Ollama: showModel :: Text -> IO (Maybe ShowModelResponse)
+ Ollama: showModel :: Text -> IO (Either OllamaError ShowModelResponse)
- Ollama: showModelOps :: Text -> Maybe Bool -> IO (Maybe ShowModelResponse)
+ Ollama: showModelOps :: Text -> Maybe Bool -> Maybe OllamaConfig -> IO (Either OllamaError ShowModelResponse)

Files

CHANGELOG.md view
@@ -1,5 +1,28 @@ # Revision history for ollama-haskell +## Unreleased++## 0.2.0.0 -- 2025-06-05++* Added stack matrix to ensure lib is buildable from lts-19.33+* Made parameters & template fields optional in `ShowModelResponse`.+* Added extra parameters fields in `ModelInfo`.+* Added strict annotations for all fields.+* Fixed ToJSON instance for delete model request body.+* Removed duplicate code by using unified `withOllamaRequest` function for all API calls.+* Added unified config type `OllamaConfig` to hold common configuration options.+* Added validation for generate and chat functions to ensure required fields are present.+* Added convience functions for generating Message and ToolCall types.+* Added thinking field for chat and generate function.+* Added ModelOptions type to encapsulate model options.+* Added get ollama version function.+* Added Common Manager, Callback functions and retry option in OllamaConfig.+* Fixed tool_calls.+* Added MonadIO versions of api functions.+* Added more comprehensive error handling for API calls.+* Added more comprehensive test cases for all functions.+* Added schema builder for passing json format for structured output.+ ## 0.1.3.0 -- 2025-03-25  * Added options, tools and tool_calls fields in chat and generate.
README.md view
@@ -1,74 +1,98 @@-# Ollama-haskell+# 🦙 Ollama Haskell -**ollama-haskell** is an unofficial Haskell binding for [Ollama](https://ollama.com), similar to [`ollama-python`](https://github.com/ollama/ollama-python). +**`ollama-haskell`** is an unofficial Haskell client for [Ollama](https://ollama.com), inspired by [`ollama-python`](https://github.com/ollama/ollama-python). It enables interaction with locally running LLMs through the Ollama HTTP API — directly from Haskell. -This library allows you to interact with Ollama, a tool that lets you run large language models (LLMs) locally, from within your Haskell projects. +--- -## Examples+## ✨ Features +* 💬 Chat with models+* ✍️ Text generation (with streaming)+* ✅ Chat with structured messages and tools+* 🧠 Embeddings+* 🧰 Model management (list, pull, push, show, delete)+* 🗃️ In-memory conversation history+* ⚙️ Configurable timeouts, retries, streaming handlers++---++## ⚡ Quick Example+ ```haskell {-# LANGUAGE OverloadedStrings #-}-module Lib where+module Main where -import Ollama (GenerateOps(..), defaultGenerateOps, generate)+import Data.Ollama.Generate+import qualified Data.Text.IO as T  main :: IO () main = do-    void $-      generate+  let ops =         defaultGenerateOps-          { modelName = "llama3.2"-          , prompt = "what is functional programming?"-          , stream = Just (T.putStr . Ollama.response_, pure ())+          { modelName = "gemma3"+          , prompt = "What is the meaning of life?"           }+  eRes <- generate ops Nothing+  case eRes of+    Left err -> putStrLn $ "Something went wrong: " ++ show err+    Right r -> do+      putStr "LLM response: "+      T.putStrLn (genResponse r) ``` -### Output--```bash-ghci> import Lib-ghci> main+--- -Whether Haskell is a "good" language depends on what you're looking for in a programming language and your personal preferences. Here are some points to consider:+## 📦 Installation -**Pros:**+Add to your `.cabal` file: -1. **Strongly typed**: Haskell's type system ensures that you catch errors early, which leads to fewer bugs and easier maintenance.-2. **Functional programming paradigm**: Haskell encourages declarative coding, making it easier to reason about code and write correct programs.-3. **Garbage collection**: Haskell handles memory management automatically, freeing you from worries about manual memory deallocation.+```cabal+build-depends:+  base >=4.7 && <5,+  ollama-haskell ``` -You can find practical examples demonstrating how to use the library in the `examples/OllamaExamples.hs` file. +Or use with `stack`/`nix-shell`. -## Prerequisite+--- -Make sure you have [Ollama](https://ollama.com) installed and running on your local machine. You can download it from [here](https://ollama.com/download).+## 📚 More Examples -## How to Use It+See [`examples/OllamaExamples.hs`](examples/OllamaExamples.hs) for: -1. Include the `ollama-haskell` package in your `.cabal` file:-   ```cabal-   build-depends:-       base >= 4.7 && < 5,-       ollama-haskell-   ```+* Chat with conversation memory+* Structured JSON output+* Embeddings+* Tool/function calling+* Multimodal input+* Streaming and non-streaming variants -3. Import the `Ollama` module and start integrating with your local LLM.+--- -## Future Updates+## 🛠 Prerequisite -- [x] Improve documentation-- [x] Add tests.-- [x] Add examples.-- [x] Add CI/CD pipeline.-- [ ] `options` parameter in `generate`.+Make sure you have [Ollama installed and running locally](https://ollama.com/download). Run `ollama pull llama3` to download a model. -Stay tuned for future updates and improvements!+--- -## Author+## 🧪 Dev & Nix Support -This library is developed and maintained by [Tushar](https://github.com/tusharad). Feel free to reach out for any questions or suggestions!+Use Nix: -## Contributions+```bash+nix-shell+``` -Contributions are welcome! If you'd like to improve the library, please submit a pull request or open an issue. Whether it's fixing bugs, adding new features, or improving documentation, all contributions are greatly appreciated.+This will install `stack` and Ollama.++---++## 👨‍💻 Author++Created and maintained by [@tusharad](https://github.com/tusharad). PRs and feedback are welcome!++---++## 🤝 Contributing++Have ideas or improvements? Feel free to [open an issue](https://github.com/tusharad/ollama-haskell/issues) or submit a PR!
ollama-haskell.cabal view
@@ -1,12 +1,12 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.37.0.+-- This file has been generated from package.yaml by hpack version 0.38.0. -- -- see: https://github.com/sol/hpack  name:           ollama-haskell-version:        0.1.3.0-synopsis:       Haskell bindings for ollama.+version:        0.2.0.0+synopsis:       Haskell client for ollama. description:    Ollama client for Haskell category:       Web homepage:       https://github.com/tusharad/ollama-haskell#readme@@ -28,14 +28,19 @@ library   exposed-modules:       Data.Ollama.Chat+      Data.Ollama.Common.Config+      Data.Ollama.Common.Error+      Data.Ollama.Common.SchemaBuilder       Data.Ollama.Common.Types       Data.Ollama.Common.Utils+      Data.Ollama.Conversation       Data.Ollama.Copy       Data.Ollama.Create       Data.Ollama.Delete       Data.Ollama.Embeddings       Data.Ollama.Generate       Data.Ollama.List+      Data.Ollama.Load       Data.Ollama.Ps       Data.Ollama.Pull       Data.Ollama.Push@@ -49,23 +54,30 @@       ImportQualifiedPost   ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints   build-depends:-      aeson+      aeson ==2.*     , base >=4.7 && <5-    , base64-bytestring-    , bytestring-    , containers-    , directory-    , filepath-    , http-client-    , http-types-    , text-    , time+    , base64-bytestring ==1.*+    , bytestring >=0.10 && <0.13+    , containers >=0.6 && <0.9+    , directory >=1 && <1.4+    , filepath >=1 && <1.6+    , http-client >=0.6 && <0.8+    , http-client-tls >=0.2 && <0.4+    , http-types >=0.7 && <0.13+    , mtl ==2.*+    , stm ==2.*+    , text >=1 && <3+    , time ==1.*   default-language: Haskell2010  test-suite ollama-haskell-test   type: exitcode-stdio-1.0   main-is: Main.hs   other-modules:+      Test.Ollama.Chat+      Test.Ollama.Embedding+      Test.Ollama.Generate+      Test.Ollama.Show       Paths_ollama_haskell   hs-source-dirs:       test@@ -75,17 +87,21 @@   build-depends:       aeson     , base >=4.7 && <5-    , base64-bytestring-    , bytestring-    , containers-    , directory-    , filepath-    , http-client-    , http-types+    , base64-bytestring ==1.*+    , bytestring >=0.10 && <0.13+    , containers >=0.6 && <0.9+    , directory >=1 && <1.4+    , filepath >=1 && <1.6+    , http-client >=0.6 && <0.8+    , http-client-tls >=0.2 && <0.4+    , http-types >=0.7 && <0.13+    , mtl ==2.*     , ollama-haskell+    , scientific     , silently-    , tasty+    , stm ==2.*+    , tasty >=1.5     , tasty-hunit     , text-    , time+    , time ==1.*   default-language: Haskell2010
src/Data/Ollama/Chat.hs view
@@ -1,110 +1,220 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} +{- |+Module      : Data.Ollama.Chat+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Chat functionality for interacting with the Ollama API.++This module provides functions and types for initiating and managing chat interactions with an Ollama model.+It includes APIs for sending chat requests, constructing messages with different roles, and configuring chat+operations. The module supports both streaming and non-streaming responses, as well as optional tools and+structured output formats.++The primary functions are 'chat' and 'chatM' for sending chat requests, and helper functions like+'systemMessage', 'userMessage', 'assistantMessage', and 'toolMessage' for constructing messages.+The 'ChatOps' type allows customization of chat parameters, and 'defaultChatOps' provides a convenient+starting point for configuration.++Example:++>>> let ops = defaultChatOps { chatModelName = "customModel", messages = userMessage "Hello!" :| [] }+>>> chat ops Nothing+Either OllamaError ChatResponse+-} module Data.Ollama.Chat   ( -- * Chat APIs     chat-  , chatJson+  , chatM++    -- * Message Types   , Message (..)   , Role (..)+  , systemMessage+  , userMessage+  , assistantMessage+  , toolMessage+  , genMessage++    -- * Chat Configuration   , defaultChatOps   , ChatOps (..)++    -- * Response Types   , ChatResponse (..)   , Format (..)-  , schemaFromType ++    -- * Configuration and Error Types+  , OllamaConfig (..)+  , defaultOllamaConfig+  , OllamaError (..)+  , ModelOptions (..)+  , defaultModelOptions++    -- * Tool and Function Types+  , InputTool (..)+  , FunctionDef (..)+  , FunctionParameters (..)+  , OutputFunction (..)+  , ToolCall (..)   ) where -import Control.Exception (try)+import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson-import qualified Data.ByteString.Char8 as BS-import qualified Data.ByteString.Lazy.Char8 as BSL import Data.List.NonEmpty as NonEmpty-import Data.Maybe (fromMaybe, isNothing)+import Data.Maybe (isNothing)+import Data.Ollama.Common.Config+import Data.Ollama.Common.Error (OllamaError (..))+import Data.Ollama.Common.Types+  ( ChatResponse (..)+  , Format (..)+  , FunctionDef (..)+  , FunctionParameters (..)+  , InputTool (..)+  , Message (..)+  , ModelOptions (..)+  , OutputFunction (..)+  , Role (..)+  , ToolCall (..)+  ) import Data.Ollama.Common.Utils as CU-import Data.Ollama.Common.Types (Format(..)) import Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Text.Encoding as T-import Data.Time (UTCTime)-import GHC.Generics-import GHC.Int (Int64)-import Network.HTTP.Client-import qualified Data.Aeson.KeyMap as HM+import Data.Text qualified as T --- | Enumerated roles that can participate in a chat.-data Role = System | User | Assistant | Tool-  deriving (Show, Eq)+{- | Constructs a 'Message' with the specified role and content. -instance ToJSON Role where-  toJSON System = String "system"-  toJSON User = String "user"-  toJSON Assistant = String "assistant"-  toJSON Tool = String "tool"+Creates a 'Message' with the given 'Role' and textual content, setting optional fields+('images', 'tool_calls', 'thinking') to 'Nothing'. -instance FromJSON Role where-  parseJSON (String "system") = pure System-  parseJSON (String "user") = pure User-  parseJSON (String "assistant") = pure Assistant-  parseJSON (String "tool") = pure Tool-  parseJSON _ = fail "Invalid Role value"+Example: --- TODO : Add tool_calls parameter+>>> genMessage User "What's the weather like?"+Message {role = User, content = "What's the weather like?", images = Nothing, tool_calls = Nothing, thinking = Nothing}+-}+genMessage :: Role -> Text -> Message+genMessage r c =+  Message+    { role = r+    , content = c+    , images = Nothing+    , tool_calls = Nothing+    , thinking = Nothing+    } --- | Represents a message within a chat, including its role and content.-data Message = Message-  { role :: Role-  -- ^ The role of the entity sending the message (e.g., 'User', 'Assistant').-  , content :: Text-  -- ^ The textual content of the message.-  , images :: Maybe [Text]-  -- ^ Optional list of base64 encoded images that accompany the message.-  , tool_calls :: Maybe [Value]-  -- ^ a list of tools in JSON that the model wants to use-  -- ^ Since 0.1.3.0-  }-  deriving (Show, Eq, Generic, ToJSON, FromJSON)+{- | Creates a 'Message' with the 'System' role. --- TODO: Add Options parameter+Example:++>>> systemMessage "You are a helpful assistant."+Message {role = System, content = "You are a helpful assistant.", images = Nothing, tool_calls = Nothing, thinking = Nothing}+-}+systemMessage :: Text -> Message+systemMessage c = genMessage System c++{- | Creates a 'Message' with the 'User' role.++Example:++>>> userMessage "What's 2+2?"+Message {role = User, content = "What's 2+2?", images = Nothing, tool_calls = Nothing, thinking = Nothing}+-}+userMessage :: Text -> Message+userMessage c = genMessage User c++{- | Creates a 'Message' with the 'Assistant' role.++Example:++>>> assistantMessage "2+2 equals 4."+Message {role = Assistant, content = "2+2 equals 4.", images = Nothing, tool_calls = Nothing, thinking = Nothing}+-}+assistantMessage :: Text -> Message+assistantMessage c = genMessage Assistant c++{- | Creates a 'Message' with the 'Tool' role.++Example:++>>> toolMessage "Tool output: success"+Message {role = Tool, content = "Tool output: success", images = Nothing, tool_calls = Nothing, thinking = Nothing}+-}+toolMessage :: Text -> Message+toolMessage c = genMessage Tool c++{- | Validates 'ChatOps' to ensure required fields are non-empty.++Checks that the 'chatModelName' is not empty and that no 'Message' in 'messages' has empty content.+Returns 'Right' with the validated 'ChatOps' or 'Left' with an 'OllamaError' if validation fails.+--+-- @since 0.2.0.0+-}+validateChatOps :: ChatOps -> Either OllamaError ChatOps+validateChatOps ops+  | T.null (chatModelName ops) = Left $ InvalidRequest "Chat model name cannot be empty"+  | any (T.null . content) (messages ops) =+      Left $ InvalidRequest "Messages cannot have empty content"+  | otherwise = Right ops++{- | Configuration for initiating a chat with an Ollama model.++Defines the parameters for a chat request, including the model name, messages, and optional settings+for tools, response format, streaming, timeout, and model options.+-} data ChatOps = ChatOps-  { chatModelName :: Text-  -- ^ The name of the chat model to be used.-  , messages :: NonEmpty Message+  { chatModelName :: !Text+  -- ^ The name of the chat model to be used (e.g., "gemma3").+  , messages :: !(NonEmpty Message)   -- ^ A non-empty list of messages forming the conversation context.-  , tools :: Maybe [Value]+  , tools :: !(Maybe [InputTool])   -- ^ Optional tools that may be used in the chat.-  , format :: Maybe Format-  -- ^ An optional format for the chat response (json or JSON schema).-  -- ^ Since 0.1.3.0-  , stream :: Maybe (ChatResponse -> IO (), IO ())-  -- ^ Optional streaming functions where the first handles each chunk of the response, and the second flushes the stream.-  , keepAlive :: Maybe Text-  -- ^ Optional text to specify keep-alive behavior.-  , hostUrl :: Maybe Text-  -- ^ Override default Ollama host url. Default url = "http://127.0.0.1:11434"-  , responseTimeOut :: Maybe Int-  -- ^ Override default response timeout in minutes. Default = 15 minutes-  , options :: Maybe Value-  -- ^ additional model parameters listed in the documentation for the Modelfile such as temperature-  -- ^ Since 0.1.3.0+  , format :: !(Maybe Format)+  -- ^ Optional format for the chat response (e.g., JSON or JSON schema).+  --+  -- @since 0.1.3.0+  , stream :: !(Maybe (ChatResponse -> IO (), IO ()))+  -- ^ Optional streaming functions: the first handles each response chunk, the second flushes the stream.+  , keepAlive :: !(Maybe Int)+  -- ^ Optional override for the response timeout in minutes (default: 15 minutes).+  , options :: !(Maybe ModelOptions)+  -- ^ Optional model parameters (e.g., temperature) as specified in the Modelfile.+  --+  -- @since 0.1.3.0+  , think :: !(Maybe Bool)+  -- ^ Optional flag to enable thinking mode.+  --+  -- @since 0.2.0.0   }  instance Show ChatOps where-  show (ChatOps {chatModelName = m, messages = ms, tools = t, format = f, keepAlive = ka}) =-    let messagesStr = show (toList ms)-        toolsStr = show t-        formatStr = show f-        keepAliveStr = show ka-     in T.unpack m-          ++ "\nMessages:\n"-          ++ messagesStr-          ++ "\n"-          ++ toolsStr-          ++ "\n"-          ++ formatStr-          ++ "\n"-          ++ keepAliveStr+  show+    ( ChatOps+        { chatModelName = m+        , messages = ms+        , tools = t+        , format = f+        , keepAlive = ka+        , think = th+        }+      ) =+      let messagesStr = show (toList ms)+          toolsStr = show t+          formatStr = show f+          keepAliveStr = show ka+          thinkStr = show th+       in T.unpack m+            ++ "\nMessages:\n"+            ++ messagesStr+            ++ "\n"+            ++ toolsStr+            ++ "\n"+            ++ formatStr+            ++ "\n"+            ++ keepAliveStr+            ++ "\n"+            ++ thinkStr  instance Eq ChatOps where   (==) a b =@@ -114,32 +224,8 @@       && format a == format b       && keepAlive a == keepAlive b -data ChatResponse = ChatResponse-  { model :: Text-  -- ^ The name of the model that generated this response.-  , createdAt :: UTCTime-  -- ^ The timestamp when the response was created.-  , message :: Maybe Message-  -- ^ The message content of the response, if any.-  , done :: Bool-  -- ^ Indicates whether the chat process has completed.-  , totalDuration :: Maybe Int64-  -- ^ Optional total duration in milliseconds for the chat process.-  , loadDuration :: Maybe Int64-  -- ^ Optional load duration in milliseconds for loading the model.-  , promptEvalCount :: Maybe Int64-  -- ^ Optional count of prompt evaluations during the chat process.-  , promptEvalDuration :: Maybe Int64-  -- ^ Optional duration in milliseconds for evaluating the prompt.-  , evalCount :: Maybe Int64-  -- ^ Optional count of evaluations during the chat process.-  , evalDuration :: Maybe Int64-  -- ^ Optional duration in milliseconds for evaluations during the chat process.-  }-  deriving (Show, Eq)- instance ToJSON ChatOps where-  toJSON (ChatOps model_ messages_ tools_ format_ stream_ keepAlive_ _ _ options) =+  toJSON (ChatOps model_ messages_ tools_ format_ stream_ keepAlive_ options think_) =     object       [ "model" .= model_       , "messages" .= messages_@@ -148,254 +234,65 @@       , "stream" .= if isNothing stream_ then Just False else Just True       , "keep_alive" .= keepAlive_       , "options" .= options+      , "think" .= think_       ] -instance FromJSON ChatResponse where-  parseJSON = withObject "ChatResponse" $ \v ->-    ChatResponse-      <$> v .: "model"-      <*> v .: "created_at"-      <*> v .: "message"-      <*> v .: "done"-      <*> v .:? "total_duration"-      <*> v .:? "load_duration"-      <*> v .:? "prompt_eval_count"-      <*> v .:? "prompt_eval_duration"-      <*> v .:? "eval_count"-      <*> v .:? "eval_duration"+{- | Default configuration for initiating a chat. -{- |-A default configuration for initiating a chat with a model.-This can be used as a starting point and modified as needed.+Provides a default 'ChatOps' with the "gemma3" model and a sample user message ("What is 2+2?").+Can be customized by modifying fields as needed.  Example: -> let ops = defaultChatOps { chatModelName = "customModel" }-> chat ops+>>> let ops = defaultChatOps { chatModelName = "customModel", messages = userMessage "Hello!" :| [] }+>>> chat ops Nothing+Either OllamaError ChatResponse -} defaultChatOps :: ChatOps defaultChatOps =   ChatOps-    { chatModelName = "llama3.2"-    , messages = Message User "What is 2+2?" Nothing Nothing :| []+    { chatModelName = "gemma3"+    , messages = userMessage "What is 2+2?" :| []     , tools = Nothing     , format = Nothing     , stream = Nothing     , keepAlive = Nothing-    , hostUrl = Nothing-    , responseTimeOut = Nothing     , options = Nothing+    , think = Nothing     } -{- |-Initiates a chat session with the specified 'ChatOps' configuration and returns either-a 'ChatResponse' or an error message.+{- | Sends a chat request to the Ollama API. -This function sends a request to the Ollama chat API with the given options.+Validates the 'ChatOps' configuration and sends a POST request to the "/api//chat" endpoint.+Supports both streaming and non-streaming responses based on the 'stream' field in 'ChatOps'.+Returns an 'Either' containing an 'OllamaError' on failure or a 'ChatResponse' on success.  Example: -> let ops = defaultChatOps-> result <- chat ops-> case result of->   Left errorMsg -> putStrLn ("Error: " ++ errorMsg)->   Right response -> print response--To request a JSON format response:--> let ops = defaultChatOps { format = Just JsonFormat }-> result <- chat ops--To request a structured output with a JSON schema:--> import Data.Aeson (object, (.=))-> let ops = defaultChatOps { format = Just (SchemaFormat schema) }-> result <- chat ops--}-chat :: ChatOps -> IO (Either String ChatResponse)-chat cOps = do-  let url = fromMaybe defaultOllamaUrl (hostUrl cOps)-      responseTimeout = fromMaybe 15 (responseTimeOut cOps)-  manager <--    newManager-      defaultManagerSettings -- Setting response timeout to 5 minutes, since llm takes time-        { managerResponseTimeout = responseTimeoutMicro (responseTimeout * 60 * 1000000)-        }-  eInitialRequest <- try $ parseRequest $ T.unpack (url <> "/api/chat") :: IO (Either HttpException Request)-  case eInitialRequest of-    Left e -> return $ Left $ "Failed to parse host url: " <> show e-    Right initialRequest -> do-      let reqBody = cOps-          request =-            initialRequest-              { method = "POST"-              , requestBody = RequestBodyLBS $ encode reqBody-              }-      eRes <--        try (withResponse request manager $ handleRequest cOps) ::-          IO (Either HttpException (Either String ChatResponse))-      case eRes of-        Left e -> return $ Left $ "HTTP error occured: " <> show e-        Right r -> do -            return r--handleRequest :: ChatOps -> Response BodyReader -> IO (Either String ChatResponse)-handleRequest cOps response = do-  let streamResponse sendChunk flush = do-        bs <- brRead $ responseBody response-        if BS.null bs-          then putStrLn "" >> pure (Left "")-          else do-            let eRes = eitherDecode (BSL.fromStrict bs) :: Either String ChatResponse-            case eRes of-              Left e -> pure (Left e)-              Right r -> do-                _ <- sendChunk r-                _ <- flush-                if done r then pure (Left "") else streamResponse sendChunk flush-  let genResponse op = do-        bs <- brRead $ responseBody response-        if BS.null bs-          then do-            let eRes = eitherDecode (BSL.fromStrict op) :: Either String ChatResponse-            case eRes of-              Left e -> pure (Left e)-              Right r -> pure (Right r)-          else genResponse (op <> bs)-  case stream cOps of-    Nothing -> genResponse ""-    Just (sendChunk, flush) -> streamResponse sendChunk flush--{- |- chatJson is a higher level function that takes ChatOps (similar to chat) and also takes- a Haskell type (that has To and From JSON instance) and returns the response in provided type.-- This function simply calls chat with extra prompt appended to it, telling LLM to return the- response in certain JSON format and serializes the response. This function will be helpful when you- want to use the LLM to do something programmatic.-- Note: This function predates the format parameter in the API. For new code, consider using- the `format` parameter with a SchemaFormat instead, which leverages the model's native- JSON output capabilities.-- For Example:-  > let expectedJsonStrucutre = Example {-  >   sortedList = ["sorted List here"]-  > , wasListAlreadSorted = False-  > }-  > let msg0 = Ollama.Message User "Sort given list: [4, 2 , 3, 67]. Also tell whether list was already sorted or not." Nothing-  > eRes3 <--  >  chatJson-  >   defaultChatOps-  >    { Chat.chatModelName = "llama3.2"-  >      , Chat.messages = msg0 :| []-  >   }-  >      expectedJsonStrucutre-  >      (Just 2)-  > print eRes3- Output:-  > Example {sortedList = ["1","2","3","4"], wasListAlreadSorted = False}--Note: While Passing the type, construct the type that will help LLM understand the field better.- For example, in the above example, the sortedList's value is written as "Sorted List here". This- will help LLM understand context better.-- You can also provide number of retries in case the LLM field to return the response in correct JSON- in first attempt.+>>> let ops = defaultChatOps { chatModelName = "gemma3", messages = userMessage "What's the capital of France?" :| [] }+>>> chat ops Nothing+Either OllamaError ChatResponse -}-chatJson ::-  (FromJSON jsonResult, ToJSON jsonResult) =>-  ChatOps ->-  -- | Haskell type that you want your result in-  jsonResult ->-  -- | Max retries-  Maybe Int ->-  IO (Either String jsonResult)-chatJson cOps@ChatOps {..} jsonStructure mMaxRetries = do-  -- For models that support the format parameter, use that directly-  --let jsonSchema = encode jsonStructure-  let useNativeFormat = False  -- Set to True to use the native format parameter when appropriate-  -  if useNativeFormat-    then do-      let formattedOps = cOps { format = Just (SchemaFormat (Object $ HM.fromList [("schema", Object $ HM.fromList [("type", String "object")])])) }-      chatResponse <- chat formattedOps-      case chatResponse of-        Left err -> return $ Left err-        Right r -> do-          let mMessage = message r-          case mMessage of-            Nothing -> return $ Left "Something went wrong"-            Just res -> case decode (BSL.fromStrict . T.encodeUtf8 $ content res) of-              Nothing -> return $ Left "Decoding Failed :("-              Just resultInType -> return $ Right resultInType-    else do-      -- Fall back to the original implementation using prompts-      let lastMessage = NonEmpty.last messages-          jsonHelperPrompt =-            "You are an AI that returns only JSON object. \n"-              <> "* Your output should be a JSON object that matches the following schema: \n"-              <> T.decodeUtf8 (BSL.toStrict $ encode jsonStructure)-              <> content lastMessage-              <> "\n"-              <> "# How to treat the task:\n"-              <> "* Stricly follow the schema for the output.\n"-              <> "* Never return anything other than a JSON object.\n"-              <> "* Do not talk to the user.\n"-      chatResponse <--        chat-          cOps-            { messages =-                NonEmpty.fromList $-                  lastMessage {content = jsonHelperPrompt} : NonEmpty.init messages-            }-      case chatResponse of-        Left err -> return $ Left err-        Right r -> do-          let mMessage = message r-          case mMessage of-            Nothing -> return $ Left "Something went wrong"-            Just res -> do-              case decode (BSL.fromStrict . T.encodeUtf8 $ content res) of-                Nothing -> do-                  case mMaxRetries of-                    Nothing -> return $ Left "Decoding Failed :("-                    Just n -> if n < 1 then return $ Left "Decoding Failed :(" else chatJson cOps jsonStructure (Just (n - 1))-                Just resultInType -> return $ Right resultInType+chat :: ChatOps -> Maybe OllamaConfig -> IO (Either OllamaError ChatResponse)+chat ops mbConfig =+  case validateChatOps ops of+    Left err -> return $ Left err+    Right _ -> withOllamaRequest "/api//chat" "POST" (Just ops) mbConfig handler+  where+    handler = case stream ops of+      Nothing -> commonNonStreamingHandler+      Just (sc, fl) -> commonStreamHandler sc fl --- | Helper function to create a JSON schema from a Haskell type-schemaFromType :: ToJSON a => a -> BSL.ByteString-schemaFromType = encode  -- This is a simplified version; a real implementation would generate a JSON Schema+{- | MonadIO version of 'chat' for use in monadic contexts. -{- |-   Example usage of 'Ollama.chat' with a JSON schema format and options field.+Lifts the 'chat' function into a 'MonadIO' context, allowing it to be used in monadic computations. -   The first example sends a message requesting a JSON response conforming to a given schema.-   The second example uses an alternative JSON format (here, @JsonFormat@).+Example: -   >>> import Data.Aeson (Value, object, (.=))-   >>> import Data.List.NonEmpty (NonEmpty(..))-   >>> import Ollama (defaultChatOps, Message(..), SchemaFormat, JsonFormat)-   >>> let x :: Value-   ...     x = object [ "type" .= ("object" :: String)-   ...                , "properties" .= object [ "age" .= object ["type" .= ("integer" :: String)] ]-   ...                ]-   >>> let msg = Message User "Ollama is 22 years old and is busy saving the world. Respond using JSON" Nothing-   >>> let opts = object ["option" .= ("some value" :: String)]-   >>> res <- chat defaultChatOps-   ...   { chatModelName = "llama3.2"-   ...   , messages = msg :| []-   ...   , format = Just (SchemaFormat x)-   ...   , options = opts-   ...   }-   >>> print (message res)-   Just (Message {role = Assistant, content = "{\n    \"age\": 22\n}", images = Nothing})-   >>> res2 <- chat defaultChatOps-   ...   { chatModelName = "llama3.2"-   ...   , messages = msg :| []-   ...   , format = Just JsonFormat-   ...   , options = object ["option" .= ("other value" :: String)]-   ...   }-   >>> print (message res2)-   Just (Message {role = Assistant, content = "{ \"Name\": \"Ollama\", \"Age\": 22, \"Occupation\": \"World Savior\", \"Goals\": [\"Save humanity from alien invasion\", \"Unite warring nations\", \"Protect the environment\"] }", images = Nothing})+>>> import Control.Monad.IO.Class+>>> let ops = defaultChatOps { chatModelName = "gemma3", messages = userMessage "Hello!" :| [] }+>>> runReaderT (chatM ops Nothing) someContext+Either OllamaError ChatResponse -}+chatM :: MonadIO m => ChatOps -> Maybe OllamaConfig -> m (Either OllamaError ChatResponse)+chatM ops mbCfg = liftIO $ chat ops mbCfg
+ src/Data/Ollama/Common/Config.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}++{- |+Module      : Data.Ollama.Common.Config+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : A unified configuration type for controlling Ollama client behavior.++== Overview++This module defines the core configuration record used throughout the Ollama Haskell client.++Use 'defaultOllamaConfig' as a starting point and customize it with helper functions+like 'withOnModelStart', 'withOnModelFinish', or 'withOnModelError'.++Includes settings for base URL, timeout, retry logic, and custom HTTP managers.+-}+module Data.Ollama.Common.Config+  ( -- * Configuration Type+    OllamaConfig (..)++    -- * Default Config+  , defaultOllamaConfig++    -- * Hook Helpers+  , withOnModelStart+  , withOnModelFinish+  , withOnModelError+  ) where++import Data.Text (Text)+import GHC.Generics+import Network.HTTP.Client++{- | Configuration for the Ollama client.+Used across all requests to customize behavior such as timeouts, retries,+custom HTTP manager, and lifecycle hooks.+--+-- @since 0.2.0.0+-}+data OllamaConfig = OllamaConfig+  { hostUrl :: Text+  -- ^ Base URL for the Ollama server (default: @http://127.0.0.1:11434@)+  , timeout :: Int+  -- ^ Timeout in seconds for API requests (ignored if 'commonManager' is set)+  , onModelStart :: Maybe (IO ())+  -- ^ Callback executed when a model starts+  , onModelError :: Maybe (IO ())+  -- ^ Callback executed if a model encounters an error+  , onModelFinish :: Maybe (IO ())+  -- ^ Callback executed when a model finishes (not called on error)+  , retryCount :: Maybe Int+  -- ^ Number of retries on failure (default: @0@ if 'Nothing')+  , retryDelay :: Maybe Int+  -- ^ Delay between retries in seconds (if applicable)+  , commonManager :: Maybe Manager+  -- ^ Shared HTTP manager; disables timeout and retry settings+  }+  deriving (Generic)++{- | A default configuration pointing to @localhost:11434@ with 90s timeout+and no hooks or retry logic.+-}+defaultOllamaConfig :: OllamaConfig+defaultOllamaConfig =+  OllamaConfig+    { hostUrl = "http://127.0.0.1:11434"+    , timeout = 90+    , onModelStart = Nothing+    , onModelError = Nothing+    , onModelFinish = Nothing+    , retryCount = Nothing+    , retryDelay = Nothing+    , commonManager = Nothing+    }++-- | Add a callback to be executed when a model starts.+withOnModelStart :: IO () -> OllamaConfig -> OllamaConfig+withOnModelStart f cfg = cfg {onModelStart = Just f}++-- | Add a callback to be executed when a model errors.+withOnModelError :: IO () -> OllamaConfig -> OllamaConfig+withOnModelError f cfg = cfg {onModelError = Just f}++-- | Add a callback to be executed when a model finishes successfully.+withOnModelFinish :: IO () -> OllamaConfig -> OllamaConfig+withOnModelFinish f cfg = cfg {onModelFinish = Just f}
+ src/Data/Ollama/Common/Error.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE DeriveGeneric #-}++{- |+Module      : Data.Ollama.Common.Error+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Unified error type for handling failures across the Ollama client.++== Overview++Defines the core 'OllamaError' type that wraps all potential errors+encountered while interacting with the Ollama API, including HTTP errors,+JSON decoding failures, API-specific errors, file I/O errors, and timeouts.+-}+module Data.Ollama.Common.Error+  ( -- * Error Types+    OllamaError (..)++    -- * Decoding Utilities+  , DecodingErrorMessage+  , DecodingFailedValue+  ) where++import Control.Exception (Exception, IOException)+import Data.Text (Text)+import GHC.Generics+import Network.HTTP.Client (HttpException)++-- | Type alias for a decoding error message string.+type DecodingErrorMessage = String++-- | Type alias for the value that failed to decode.+type DecodingFailedValue = String++-- | Represents all possible errors that may occur when using the Ollama client.+--+-- @since 0.2.0.0+data OllamaError+  = -- | Low-level HTTP exception (connection failure, etc.)+    HttpError HttpException+  | -- | Failure to decode a JSON response, includes message and raw value+    DecodeError DecodingErrorMessage DecodingFailedValue+  | -- | Error returned from Ollama's HTTP API+    ApiError Text+  | -- | Error during file operations (e.g., loading an image)+    FileError IOException+  | -- | Mismatch in expected JSON schema or structure+    JsonSchemaError String+  | -- | Request timed out+    TimeoutError String+  | -- | Request is malformed or violates input constraints+    InvalidRequest String+  deriving (Show, Generic)++instance Eq OllamaError where+  (HttpError _) == (HttpError _) = True+  x == y = eqOllamaError x y+    where+      eqOllamaError :: OllamaError -> OllamaError -> Bool+      eqOllamaError = (==)++instance Exception OllamaError
+ src/Data/Ollama/Common/SchemaBuilder.hs view
@@ -0,0 +1,191 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}++{- |+Module      : Data.Ollama.Common.SchemaBuilder+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : DSL for constructing structured JSON Schemas for Ollama's structured output API.++== Overview++This module defines a simple schema builder DSL for programmatically constructing+JSON Schemas compatible with the structured output features in the Ollama API.++It supports nested objects, arrays, required fields, and custom types, and+provides infix operators for a fluent and expressive syntax.++== Example++@+import Data.Ollama.Common.SchemaBuilder++let schema =+      emptyObject+        |+ ("name", JString)+        |+ ("age", JInteger)+        |++ ("address", buildSchema $+              emptyObject+                |+ ("city", JString)+                |+ ("zip", JInteger)+                |! "city"+            )+        |!! ["name", "age"]+        & buildSchema++printSchema schema+@+-}+module Data.Ollama.Common.SchemaBuilder+  ( -- * Core Types+    JsonType (..)+  , Property (..)+  , Schema (..)++    -- * Schema Construction+  , emptyObject+  , addProperty+  , addObjectProperty+  , requireField+  , requireFields+  , buildSchema++    -- * Schema Utilities+  , objectOf+  , arrayOf+  , toOllamaFormat+  , printSchema++    -- * Infix Schema DSL+  , (|+)+  , (|++)+  , (|!)+  , (|!!)+  ) where++import Data.Aeson+import Data.Map.Strict qualified as HM+import Data.Text (Text)+import Data.Text qualified as T+import Data.Text.Lazy qualified as TL+import Data.Text.Lazy.Encoding qualified as T+import GHC.Generics++-- | Supported JSON types for schema generation.+data JsonType+  = JString+  | JNumber+  | JInteger+  | JBoolean+  | JNull+  | -- | Array of a specific type+    JArray JsonType+  | -- | Nested object schema+    JObject Schema+  deriving (Show, Eq, Generic)++instance ToJSON JsonType where+  toJSON JString = "string"+  toJSON JNumber = "number"+  toJSON JInteger = "integer"+  toJSON JBoolean = "boolean"+  toJSON JNull = "null"+  toJSON (JArray _) = "array"+  toJSON (JObject _) = "object"++-- | A named property with a given type (supports nested values).+newtype Property = Property JsonType+  deriving (Show, Eq, Generic)++instance ToJSON Property where+  toJSON (Property (JArray itemType)) =+    object ["type" .= ("array" :: Text), "items" .= Property itemType]+  toJSON (Property (JObject schema)) = toJSON schema+  toJSON (Property typ) = object ["type" .= typ]++-- | Complete schema representation.+--+-- @since 0.2.0.0+data Schema = Schema+  { schemaProperties :: HM.Map Text Property+  , schemaRequired :: [Text]+  }+  deriving (Show, Eq, Generic)++instance ToJSON Schema where+  toJSON (Schema props req) =+    object+      [ "type" .= ("object" :: Text)+      , "properties" .= props+      , "required" .= req+      ]++-- | Internal builder for schema DSL.+newtype SchemaBuilder = SchemaBuilder Schema+  deriving (Show, Eq)++-- | Create an empty schema object.+emptyObject :: SchemaBuilder+emptyObject = SchemaBuilder $ Schema HM.empty []++-- | Add a simple field with a given name and type.+addProperty :: Text -> JsonType -> SchemaBuilder -> SchemaBuilder+addProperty name typ (SchemaBuilder s) =+  SchemaBuilder $ s {schemaProperties = HM.insert name (Property typ) (schemaProperties s)}++-- | Add a nested object field with its own schema.+addObjectProperty :: Text -> Schema -> SchemaBuilder -> SchemaBuilder+addObjectProperty name nestedSchema (SchemaBuilder s) =+  SchemaBuilder $+    s {schemaProperties = HM.insert name (Property (JObject nestedSchema)) (schemaProperties s)}++-- | Mark a field as required.+requireField :: Text -> SchemaBuilder -> SchemaBuilder+requireField name (SchemaBuilder s) =+  SchemaBuilder $ s {schemaRequired = name : schemaRequired s}++-- | Mark multiple fields as required.+requireFields :: [Text] -> SchemaBuilder -> SchemaBuilder+requireFields names builder = foldr requireField builder names++-- | Finalize the schema from a builder.+buildSchema :: SchemaBuilder -> Schema+buildSchema (SchemaBuilder s) = s++-- | Wrap a 'SchemaBuilder' as a nested object type.+objectOf :: SchemaBuilder -> JsonType+objectOf builder = JObject (buildSchema builder)++-- | Create an array of a given JSON type.+arrayOf :: JsonType -> JsonType+arrayOf = JArray++-- | Convert schema into a JSON 'Value' suitable for API submission.+toOllamaFormat :: Schema -> Value+toOllamaFormat = toJSON++-- | Pretty print a schema as formatted JSON.+printSchema :: Schema -> IO ()+printSchema = putStrLn . T.unpack . TL.toStrict . T.decodeUtf8 . encode++-- | Infix alias for 'addProperty'.+(|+) :: SchemaBuilder -> (Text, JsonType) -> SchemaBuilder+builder |+ (name, typ) = addProperty name typ builder++-- | Infix alias for 'addObjectProperty'.+(|++) :: SchemaBuilder -> (Text, Schema) -> SchemaBuilder+builder |++ (name, schema) = addObjectProperty name schema builder++-- | Infix alias for 'requireField'.+(|!) :: SchemaBuilder -> Text -> SchemaBuilder+builder |! name = requireField name builder++-- | Infix alias for 'requireFields'.+(|!!) :: SchemaBuilder -> [Text] -> SchemaBuilder+builder |!! names = requireFields names builder++infixl 7 |+, |+++infixl 6 |!, |!!
src/Data/Ollama/Common/Types.hs view
@@ -1,22 +1,82 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-} +{- |+Module      : Data.Ollama.Common.Types+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Shared data types for request and response structures used throughout the Ollama client.++== 📋 Overview++This module defines common types for working with Ollama's API, including:++- Chat messages and roles+- Text generation responses+- Structured function/tool calling+- Model metadata+- Streaming handling+- Custom model parameters++These types are consumed and returned by higher-level modules+like `Data.Ollama.Chat`, `Data.Ollama.Generate`, and others.++== Includes++- Chat message structure and roles+- Generate and chat response records+- ModelOptions and advanced config+- Structured function/tool call interfaces+- JSON format hints and schema wrapping+- Helper class 'HasDone' for streaming termination++Most types implement `ToJSON`/`FromJSON` for direct API interaction.+-} module Data.Ollama.Common.Types   ( ModelDetails (..)-  , OllamaClient (..)   , Format (..)+  , GenerateResponse (..)+  , Message (..)+  , Role (..)+  , ChatResponse (..)+  , HasDone (..)+  , ModelOptions (..)+  , InputTool (..)+  , FunctionDef (..)+  , FunctionParameters (..)+  , ToolCall (..)+  , OutputFunction (..)+  , Version (..)   ) where  import Data.Aeson+import Data.Map qualified as HM+import Data.Maybe (catMaybes)+import Data.Ollama.Common.SchemaBuilder import Data.Text (Text)+import Data.Time (UTCTime)+import GHC.Generics+import GHC.Int (Int64) +-- | Metadata describing a specific model's identity and configuration. data ModelDetails = ModelDetails-  { parentModel :: Maybe Text-  , format :: Text-  , familiy :: Text-  , families :: [Text]-  , parameterSize :: Text+  { parentModel :: !(Maybe Text)+  -- ^ The parent model from which this model was derived, if any.+  , format :: !Text+  -- ^ The format used for the model (e.g., "gguf").+  , family :: !Text+  -- ^ The family name of the model (e.g., "llama", "mistral").+  , families :: ![Text]+  -- ^ Alternative or related family identifiers.+  , parameterSize :: !Text+  -- ^ The size of the model's parameters, typically expressed as a string (e.g., "7B").   , quantizationLevel :: Text+  -- ^ The quantization level used (e.g., "Q4", "Q8").   }   deriving (Eq, Show) @@ -30,35 +90,358 @@       <*> v .: "parameter_size"       <*> v .: "quantization_level" -newtype OllamaClient = OllamaClient-  { host :: Text+{- | Format specification for the chat output.++@since 0.1.3.0+-}+data Format = JsonFormat | SchemaFormat Schema+  deriving (Show, Eq)++instance ToJSON Format where+  toJSON JsonFormat = String "json"+  toJSON (SchemaFormat schema) = toJSON schema++{- |+Result type for 'generate' function containing the model's response and meta-information.+-}+data GenerateResponse = GenerateResponse+  { model :: !Text+  -- ^ The name of the model that generated the response.+  , createdAt :: !UTCTime+  -- ^ The timestamp when the response was created.+  , genResponse :: !Text+  -- ^ The generated response from the model.+  , done :: !Bool+  -- ^ A flag indicating whether the generation process is complete.+  , totalDuration :: !(Maybe Int64)+  -- ^ Optional total duration in milliseconds for the generation process.+  , loadDuration :: !(Maybe Int64)+  -- ^ Optional load duration in milliseconds for loading the model.+  , promptEvalCount :: !(Maybe Int64)+  -- ^ Optional count of prompt evaluations during the generation process.+  , promptEvalDuration :: !(Maybe Int64)+  -- ^ Optional duration in milliseconds for evaluating the prompt.+  , evalCount :: !(Maybe Int64)+  -- ^ Optional count of evaluations during the generation process.+  , evalDuration :: !(Maybe Int64)+  -- ^ Optional duration in milliseconds for evaluations during the generation process.+  , thinking :: !(Maybe Text)+  -- ^ Thinking of reasoning models; if think is set to true+  --+  -- @since 0.2.0.0   }+  deriving (Show, Eq)++instance FromJSON GenerateResponse where+  parseJSON = withObject "GenerateResponse" $ \v ->+    GenerateResponse+      <$> v .: "model"+      <*> v .: "created_at"+      <*> v .: "response"+      <*> v .: "done"+      <*> v .:? "total_duration"+      <*> v .:? "load_duration"+      <*> v .:? "prompt_eval_count"+      <*> v .:? "prompt_eval_duration"+      <*> v .:? "eval_count"+      <*> v .:? "eval_duration"+      <*> v .:? "thinking"++-- | Enumerated roles that can participate in a chat.+data Role = System | User | Assistant | Tool+  deriving (Show, Eq)++instance ToJSON Role where+  toJSON System = String "system"+  toJSON User = String "user"+  toJSON Assistant = String "assistant"+  toJSON Tool = String "tool"++instance FromJSON Role where+  parseJSON = withText "Role" $ \t ->+    case t of+      "system" -> pure System+      "user" -> pure User+      "assistant" -> pure Assistant+      "tool" -> pure Tool+      _ -> fail $ "Invalid Role value: " <> show t++-- | Represents a message within a chat, including its role and content.+data Message = Message+  { role :: !Role+  -- ^ The role of the entity sending the message (e.g., 'User', 'Assistant').+  , content :: !Text+  -- ^ The textual content of the message.+  , images :: !(Maybe [Text])+  -- ^ Optional list of base64 encoded images that accompany the message.+  , tool_calls :: !(Maybe [ToolCall])+  -- ^ a list of tools in JSON that the model wants to use+  --+  -- @since 0.1.3.0+  , thinking :: !(Maybe Text)+  --+  -- @since 0.2.0.0+  }+  deriving (Show, Eq, Generic, ToJSON, FromJSON)++data ChatResponse = ChatResponse+  { model :: !Text+  -- ^ The name of the model that generated this response.+  , createdAt :: !UTCTime+  -- ^ The timestamp when the response was created.+  , message :: !(Maybe Message)+  -- ^ The message content of the response, if any.+  , done :: !Bool+  -- ^ Indicates whether the chat process has completed.+  , totalDuration :: !(Maybe Int64)+  -- ^ Optional total duration in milliseconds for the chat process.+  , loadDuration :: !(Maybe Int64)+  -- ^ Optional load duration in milliseconds for loading the model.+  , promptEvalCount :: !(Maybe Int64)+  -- ^ Optional count of prompt evaluations during the chat process.+  , promptEvalDuration :: !(Maybe Int64)+  -- ^ Optional duration in milliseconds for evaluating the prompt.+  , evalCount :: !(Maybe Int64)+  -- ^ Optional count of evaluations during the chat process.+  , evalDuration :: !(Maybe Int64)+  -- ^ Optional duration in milliseconds for evaluations during the chat process.+  }+  deriving (Show, Eq)++instance FromJSON ChatResponse where+  parseJSON = withObject "ChatResponse" $ \v ->+    ChatResponse+      <$> v .: "model"+      <*> v .: "created_at"+      <*> v .: "message"+      <*> v .: "done"+      <*> v .:? "total_duration"+      <*> v .:? "load_duration"+      <*> v .:? "prompt_eval_count"+      <*> v .:? "prompt_eval_duration"+      <*> v .:? "eval_count"+      <*> v .:? "eval_duration"++-- | A workaround to use done field within commonStreamHandler+class HasDone a where+  getDone :: a -> Bool++instance HasDone GenerateResponse where+  getDone GenerateResponse {..} = done++instance HasDone ChatResponse where+  getDone ChatResponse {..} = done++-- | Optional model tuning parameters that influence generation behavior.+--+-- @since 0.2.0.0+data ModelOptions = ModelOptions+  { numKeep :: Maybe Int+  , -- \^ Number of tokens to keep from the previous context.+    seed :: Maybe Int+  , -- \^ Random seed for reproducibility.+    numPredict :: Maybe Int+  , -- \^ Maximum number of tokens to predict.+    topK :: Maybe Int+  , -- \^ Top-K sampling parameter.+    topP :: Maybe Double+  , -- \^ Top-P (nucleus) sampling parameter.+    minP :: Maybe Double+  , -- \^ Minimum probability for nucleus sampling.+    typicalP :: Maybe Double+  , -- \^ Typical sampling probability.+    repeatLastN :: Maybe Int+  , -- \^ Number of tokens to consider for repetition penalty.+    temperature :: Maybe Double+  , -- \^ Sampling temperature. Higher = more randomness.+    repeatPenalty :: Maybe Double+  , -- \^ Penalty for repeating the same tokens.+    presencePenalty :: Maybe Double+  , -- \^ Penalty for introducing new tokens.+    frequencyPenalty :: Maybe Double+  , -- \^ Penalty for frequent tokens.+    penalizeNewline :: Maybe Bool+  , -- \^ Whether to penalize newline tokens.+    stop :: Maybe [Text]+  , -- \^ List of stop sequences to end generation.+    numa :: Maybe Bool+  , -- \^ Whether to enable NUMA-aware optimizations.+    numCtx :: Maybe Int+  , -- \^ Number of context tokens.+    numBatch :: Maybe Int+  , -- \^ Batch size used during generation.+    numGpu :: Maybe Int+  , -- \^ Number of GPUs to use.+    mainGpu :: Maybe Int+  , -- \^ Index of the primary GPU to use.+    useMmap :: Maybe Bool+  , -- \^ Whether to memory-map the model.+    numThread :: Maybe Int+  }+  -- \^ Number of threads to use for inference.++  deriving (Show, Eq)++-- | Custom ToJSON instance for Options+instance ToJSON ModelOptions where+  toJSON opts =+    object $+      catMaybes+        [ ("num_keep" .=) <$> numKeep opts+        , ("seed" .=) <$> seed opts+        , ("num_predict" .=) <$> numPredict opts+        , ("top_k" .=) <$> topK opts+        , ("top_p" .=) <$> topP opts+        , ("min_p" .=) <$> minP opts+        , ("typical_p" .=) <$> typicalP opts+        , ("repeat_last_n" .=) <$> repeatLastN opts+        , ("temperature" .=) <$> temperature opts+        , ("repeat_penalty" .=) <$> repeatPenalty opts+        , ("presence_penalty" .=) <$> presencePenalty opts+        , ("frequency_penalty" .=) <$> frequencyPenalty opts+        , ("penalize_newline" .=) <$> penalizeNewline opts+        , ("stop" .=) <$> stop opts+        , ("numa" .=) <$> numa opts+        , ("num_ctx" .=) <$> numCtx opts+        , ("num_batch" .=) <$> numBatch opts+        , ("num_gpu" .=) <$> numGpu opts+        , ("main_gpu" .=) <$> mainGpu opts+        , ("use_mmap" .=) <$> useMmap opts+        , ("num_thread" .=) <$> numThread opts+        ]++-- | A wrapper for the Ollama engine version string.+newtype Version = Version Text   deriving (Eq, Show) +instance FromJSON Version where+  parseJSON = withObject "version" $ \v -> do+    Version <$> v .: "version" -{-|-E.g SchemaFormat-{-    "type": "object",-    "properties": {-      "age": {-        "type": "integer"-      },-      "available": {-        "type": "boolean"-      }-    },-    "required": [-      "age",-      "available"-    ]+-- | Represents a tool that can be used in the conversation.+--+-- @since 0.2.0.0+data InputTool = InputTool+  { toolType :: Text+  -- ^ The type of the tool+  , function :: FunctionDef+  -- ^ The function associated with the tool   }-|-}--- | Format specification for the chat output--- | Since 0.1.3.0-data Format = JsonFormat | SchemaFormat Value+  deriving (Show, Eq, Generic)++instance ToJSON InputTool where+  toJSON InputTool {..} =+    object+      [ "type" .= toolType+      , "function" .= function+      ]++instance FromJSON InputTool where+  parseJSON = withObject "Tool" $ \v ->+    InputTool+      <$> v .: "type"+      <*> v .: "function"++-- | Represents a function that can be called by the model.+--+-- @since 0.2.0.0+data FunctionDef = FunctionDef+  { functionName :: Text+  -- ^ The name of the function+  , functionDescription :: Maybe Text+  -- ^ Optional description of the function+  , functionParameters :: Maybe FunctionParameters+  -- ^ Optional parameters for the function+  , functionStrict :: Maybe Bool+  -- ^ Optional strictness flag+  }+  deriving (Show, Eq, Generic)++instance ToJSON FunctionDef where+  toJSON FunctionDef {..} =+    object $+      [ "name" .= functionName+      ]+        ++ maybe [] (\d -> ["description" .= d]) functionDescription+        ++ maybe [] (\p -> ["parameters" .= p]) functionParameters+        ++ maybe [] (\s -> ["strict" .= s]) functionStrict++instance FromJSON FunctionDef where+  parseJSON = withObject "Function" $ \v ->+    FunctionDef+      <$> v .: "name"+      <*> v .:? "description"+      <*> v .:? "parameters"+      <*> v .:? "strict"++-- | Parameters definition for a function call used in structured output or tool calls.+--+-- @since 0.2.0.0+data FunctionParameters = FunctionParameters+  { parameterType :: Text+  -- ^ Type of the parameter (usually "object").+  , parameterProperties :: Maybe (HM.Map Text FunctionParameters)+  -- ^ Optional nested parameters as a property map.+  , requiredParams :: Maybe [Text]+  -- ^ List of required parameter names.+  , additionalProperties :: Maybe Bool+  -- ^ Whether additional (unspecified) parameters are allowed.+  }   deriving (Show, Eq) -instance ToJSON Format where-  toJSON JsonFormat = String "json"-  toJSON (SchemaFormat schema) = schema+instance ToJSON FunctionParameters where+  toJSON FunctionParameters {..} =+    object+      [ "type" .= parameterType+      , "properties" .= parameterProperties+      , "required" .= requiredParams+      , "additionalProperties" .= additionalProperties+      ]++instance FromJSON FunctionParameters where+  parseJSON = withObject "parameters" $ \v ->+    FunctionParameters+      <$> v .: "type"+      <*> v .: "properties"+      <*> v .: "required"+      <*> v .: "additionalProperties"++-- | A single tool call returned from the model, containing the function to be invoked.+--+-- @since 0.2.0.0+newtype ToolCall = ToolCall+  { outputFunction :: OutputFunction+  -- ^ The function the model intends to call, with arguments.+  }+  deriving (Show, Eq)++-- | Output representation of a function to be called, including its name and arguments.+--+-- @since 0.2.0.0+data OutputFunction = OutputFunction+  { outputFunctionName :: Text+  -- ^ The name of the function to invoke.+  , arguments :: HM.Map Text Value+  -- ^ A key-value map of argument names to values (JSON values).+  }+  deriving (Eq, Show)++instance ToJSON OutputFunction where+  toJSON OutputFunction {..} =+    object+      [ "name" .= outputFunctionName+      , "arguments" .= arguments+      ]++instance FromJSON OutputFunction where+  parseJSON = withObject "function" $ \v ->+    OutputFunction+      <$> v .: "name"+      <*> v .: "arguments"++instance ToJSON ToolCall where+  toJSON ToolCall {..} = object ["function" .= outputFunction]++instance FromJSON ToolCall where+  parseJSON = withObject "tool_calls" $ \v ->+    ToolCall <$> v .: "function"
src/Data/Ollama/Common/Utils.hs view
@@ -1,26 +1,71 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-} -module Data.Ollama.Common.Utils (defaultOllamaUrl, OllamaClient (..), encodeImage) where+{- |+Module      : Data.Ollama.Common.Utils+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Utility functions for interacting with the Ollama API, including image encoding, HTTP request handling, and retry logic. +This module provides helper functions for common tasks in the Ollama client, such as encoding images to Base64,+sending HTTP requests to the Ollama API, handling streaming and non-streaming responses, and managing retries for failed requests.+It also includes a default model options configuration and a function to retrieve the Ollama server version.++The functions in this module are used internally by other modules like 'Data.Ollama.Chat' and 'Data.Ollama.Generate' but can also be used directly for custom API interactions.+-}+module Data.Ollama.Common.Utils+  ( -- * Image Encoding+    encodeImage++    -- * HTTP Request Handling+  , withOllamaRequest+  , commonNonStreamingHandler+  , commonStreamHandler+  , nonJsonHandler++    -- * Model Options+  , defaultModelOptions++    -- * Retry Logic+  , withRetry++    -- * Version Retrieval+  , getVersion+  ) where++import Control.Concurrent (threadDelay) import Control.Exception (IOException, try)+import Data.Aeson import Data.ByteString qualified as BS import Data.ByteString.Base64 qualified as Base64+import Data.ByteString.Lazy qualified as BSL import Data.Char (toLower)+import Data.Maybe (fromMaybe)+import Data.Ollama.Common.Config+import Data.Ollama.Common.Error+import Data.Ollama.Common.Error qualified as Error import Data.Ollama.Common.Types import Data.Text (Text)+import Data.Text qualified as T import Data.Text.Encoding qualified as TE+import Network.HTTP.Client+import Network.HTTP.Client.TLS+import Network.HTTP.Types (Status (statusCode)) import System.Directory import System.FilePath -defaultOllamaUrl :: Text-defaultOllamaUrl = "http://127.0.0.1:11434"-+-- | List of supported image file extensions for 'encodeImage'. supportedExtensions :: [String] supportedExtensions = [".jpg", ".jpeg", ".png"] +-- | Safely read a file, returning an 'Either' with an 'IOException' on failure. safeReadFile :: FilePath -> IO (Either IOException BS.ByteString) safeReadFile = try . BS.readFile +-- | Read a file if it exists, returning 'Nothing' if it does not. asPath :: FilePath -> IO (Maybe BS.ByteString) asPath filePath = do   exists <- doesFileExist filePath@@ -28,13 +73,15 @@     then either (const Nothing) Just <$> safeReadFile filePath     else return Nothing +-- | Check if a file has a supported image extension. isSupportedExtension :: FilePath -> Bool-isSupportedExtension path = map toLower (takeExtension path) `elem` supportedExtensions+isSupportedExtension p = map toLower (takeExtension p) `elem` supportedExtensions -{- |-  encodeImage is a utility function that takes an image file path (jpg, jpeg, png) and-  returns the image data in Base64 encoded format. Since GenerateOps' images field-  expects image data in base64. It is helper function that we are providing out of the box.+{- | Encodes an image file to Base64 format.++Takes a file path to an image (jpg, jpeg, or png) and returns its data encoded as a Base64 'Text'.+Returns 'Nothing' if the file extension is unsupported or the file cannot be read.+This is useful for including images in API requests that expect Base64-encoded data, such as 'GenerateOps' images field. -} encodeImage :: FilePath -> IO (Maybe Text) encodeImage filePath = do@@ -43,3 +90,217 @@     else do       maybeContent <- asPath filePath       return $ fmap (TE.decodeUtf8 . Base64.encode) maybeContent++{- | Executes an action with retry logic for recoverable errors.++Retries the given action up to the specified number of times with a delay (in seconds) between attempts.+Only retries on recoverable errors such as HTTP errors, timeouts, JSON schema errors, or decoding errors.+-}+withRetry ::+  -- | Number of retries+  Int ->+  -- | Delay between retries in seconds+  Int ->+  -- | Action to execute, returning 'Either' 'OllamaError' or a result+  IO (Either OllamaError a) ->+  IO (Either OllamaError a)+withRetry 0 _ action = action+withRetry retries delaySeconds action = do+  result <- action+  case result of+    Left err | isRetryableError err -> do+      threadDelay (delaySeconds * 1000000) -- Convert to microseconds+      withRetry (retries - 1) delaySeconds action+    _ -> return result+  where+    isRetryableError (HttpError _) = True+    isRetryableError (TimeoutError _) = True+    isRetryableError (JsonSchemaError _) = True+    isRetryableError (DecodeError _ _) = True+    isRetryableError _ = False++{- | Sends an HTTP request to the Ollama API.++A unified function for making API requests to the Ollama server. Supports both GET and POST methods,+customizable payloads, and optional configuration. The response is processed by the provided handler.+-}+withOllamaRequest ::+  forall payload response.+  (ToJSON payload) =>+  -- | API endpoint+  Text ->+  -- | HTTP method ("GET" or "POST")+  BS.ByteString ->+  -- | Optional request payload (must implement 'ToJSON')+  Maybe payload ->+  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig')+  Maybe OllamaConfig ->+  -- | Response handler to process the HTTP response+  (Response BodyReader -> IO (Either OllamaError response)) ->+  IO (Either OllamaError response)+withOllamaRequest endpoint reqMethod mbPayload mbOllamaConfig handler = do+  let OllamaConfig {..} = fromMaybe defaultOllamaConfig mbOllamaConfig+      fullUrl = T.unpack $ hostUrl <> endpoint+      timeoutMicros = timeout * 1000000+  manager <- case commonManager of+    Nothing ->+      newTlsManagerWith+        tlsManagerSettings {managerResponseTimeout = responseTimeoutMicro timeoutMicros}+    Just m -> pure m+  eRequest <- try $ parseRequest fullUrl+  case eRequest of+    Left ex -> return $ Left $ Error.HttpError ex+    Right req -> do+      let request =+            req+              { method = reqMethod+              , requestBody =+                  maybe mempty (\x -> RequestBodyLBS $ encode x) mbPayload+              }+          retryCnt = fromMaybe 0 retryCount+          retryDelay_ = fromMaybe 1 retryDelay+      withRetry retryCnt retryDelay_ $ do+        fromMaybe (pure ()) onModelStart+        eResponse <- try $ withResponse request manager handler+        case eResponse of+          Left ex -> do+            fromMaybe (pure ()) onModelError+            case ex of+              (HttpExceptionRequest _ ResponseTimeout) ->+                return $ Left $ Error.TimeoutError "No response from LLM yet"+              _ -> return $ Left $ Error.HttpError ex+          Right result -> do+            fromMaybe (pure ()) onModelFinish+            return result++{- | Handles non-streaming API responses.++Processes an HTTP response, accumulating all chunks until EOF and decoding the result as JSON.+Returns an 'Either' with an 'OllamaError' on failure or the decoded response on success.+Suitable for APIs that return a single JSON response.+-}+commonNonStreamingHandler ::+  FromJSON a =>+  Response BodyReader ->+  IO (Either OllamaError a)+commonNonStreamingHandler resp = do+  let bodyReader = responseBody resp+      respStatus = statusCode $ responseStatus resp+  if respStatus >= 200 && respStatus < 300+    then do+      finalBs <- readFullBuff BS.empty bodyReader+      case eitherDecode (BSL.fromStrict finalBs) of+        Left err -> pure . Left $ Error.DecodeError err (show finalBs)+        Right decoded -> pure . Right $ decoded+    else Left . ApiError . TE.decodeUtf8 <$> brRead bodyReader++{- | Accumulates response chunks into a single ByteString.++Internal helper function to read all chunks from a 'BodyReader' until EOF.+-}+readFullBuff :: BS.ByteString -> BodyReader -> IO BS.ByteString+readFullBuff acc reader = do+  chunk <- brRead reader+  if BS.null chunk+    then pure acc+    else readFullBuff (acc `BS.append` chunk) reader++{- | Handles streaming API responses.++Processes a streaming HTTP response, decoding each chunk as JSON and passing it to the provided+'sendChunk' function. The 'flush' function is called after each chunk. Stops when the response+indicates completion (via 'HasDone'). Returns the final decoded response or an error.+-}+commonStreamHandler ::+  (HasDone a, FromJSON a) =>+  -- | Function to handle each decoded chunk+  (a -> IO ()) ->+  -- | Function to flush after each chunk+  IO () ->+  Response BodyReader ->+  IO (Either OllamaError a)+commonStreamHandler sendChunk flush resp = go mempty+  where+    go acc = do+      bs <- brRead $ responseBody resp+      if BS.null bs+        then do+          case eitherDecode (BSL.fromStrict acc) of+            Left err -> pure $ Left $ Error.DecodeError err (show acc)+            Right decoded -> pure $ Right decoded+        else do+          let chunk = BSL.fromStrict bs+          case eitherDecode chunk of+            Left err -> return $ Left $ Error.DecodeError err (show acc)+            Right res -> do+              sendChunk res+              flush+              if getDone res then return (Right res) else go (acc <> bs)++{- | Handles non-JSON API responses.++Processes an HTTP response, accumulating all chunks into a 'ByteString'. Returns the accumulated+data on success (HTTP status 2xx) or an 'ApiError' on failure.+-}+nonJsonHandler :: Response BodyReader -> IO (Either OllamaError BS.ByteString)+nonJsonHandler resp = do+  let bodyReader = responseBody resp+      respStatus = statusCode $ responseStatus resp+  if respStatus >= 200 && respStatus < 300+    then Right <$> readFullBuff BS.empty bodyReader+    else Left . ApiError . TE.decodeUtf8 <$> brRead bodyReader++{- | Default model options for API requests.++Provides a default 'ModelOptions' configuration with all fields set to 'Nothing',+suitable as a starting point for customizing model parameters like temperature or token limits.++Example:++>>> let opts = defaultModelOptions { temperature = Just 0.7 }+-}+defaultModelOptions :: ModelOptions+defaultModelOptions =+  ModelOptions+    { numKeep = Nothing+    , seed = Nothing+    , numPredict = Nothing+    , topK = Nothing+    , topP = Nothing+    , minP = Nothing+    , typicalP = Nothing+    , repeatLastN = Nothing+    , temperature = Nothing+    , repeatPenalty = Nothing+    , presencePenalty = Nothing+    , frequencyPenalty = Nothing+    , penalizeNewline = Nothing+    , stop = Nothing+    , numa = Nothing+    , numCtx = Nothing+    , numBatch = Nothing+    , numGpu = Nothing+    , mainGpu = Nothing+    , useMmap = Nothing+    , numThread = Nothing+    }++{- | Retrieves the Ollama server version.++Sends a GET request to the "/api//version" endpoint and returns the server version+as a 'Version' wrapped in an 'Either' 'OllamaError'.++Example:++>>> getVersion+--+-- @since 0.2.0.0+-}+getVersion :: IO (Either OllamaError Version)+getVersion = do+  withOllamaRequest+    "/api//version"+    "GET"+    (Nothing :: Maybe Value)+    Nothing+    commonNonStreamingHandler
+ src/Data/Ollama/Conversation.hs view
@@ -0,0 +1,186 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}++{- |+Module      : Data.Ollama.Conversation+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Conversation management for the Ollama client, including storage and retrieval of chat sessions.++This module provides types and functions for managing conversations in the Ollama client. It defines+a 'Conversation' type to represent a chat session, a 'ConversationStore' typeclass for storage operations,+and an in-memory implementation using 'InMemoryStore' and 'ConvoM'. The module supports saving, loading,+listing, and deleting conversations, with thread-safe operations using STM (Software Transactional Memory).++The 'Conversation' type includes metadata such as a unique ID, messages, model name, and timestamps.+The 'ConversationStore' typeclass defines a generic interface for conversation storage, while 'InMemoryStore'+provides a concrete in-memory implementation. The 'ConvoM' monad integrates with 'InMemoryStore' for+monadic operations.++Example:++>>> store <- initInMemoryStore+>>> let conv = Conversation "conv1" [userMessage "Hello!"] "gemma3" <$> getCurrentTime <*> getCurrentTime+>>> runInMemoryConvo store $ saveConversation conv+>>> runInMemoryConvo store $ loadConversation "conv1"+Just (Conversation ...)+-}+module Data.Ollama.Conversation+  ( -- * Conversation Types+    Conversation (..)+  , ConversationStore (..)++    -- * In-Memory Store+  , InMemoryStore (..)+  , ConvoM (..)+  , initInMemoryStore+  , runInMemoryConvo++    -- * Validation+  , validateConversation+  ) where++import Control.Concurrent.STM+import Control.Monad.Reader+import Data.Aeson (FromJSON, ToJSON)+import Data.Map.Strict (Map)+import Data.Map.Strict qualified as Map+import Data.Ollama.Common.Types+import Data.Text (Text)+import Data.Text qualified as T+import Data.Time (UTCTime, getCurrentTime)+import GHC.Generics (Generic)++{- | Represents a chat session with metadata and messages.++Stores a conversation's unique identifier, list of messages, model name, creation time, and last updated time.+-}+data Conversation = Conversation+  { conversationId :: !Text+  -- ^ Unique identifier for the conversation.+  , messages :: ![Message]+  -- ^ List of messages in the conversation.+  , model :: !Text+  -- ^ Name of the model used in the conversation (e.g., "gemma3").+  , createdAt :: !UTCTime+  -- ^ Timestamp when the conversation was created.+  , lastUpdated :: !UTCTime+  -- ^ Timestamp when the conversation was last updated.+  }+  deriving (Show, Eq, Generic)++instance ToJSON Conversation+instance FromJSON Conversation++{- | Typeclass defining operations for storing and managing conversations.++Provides methods for saving, loading, listing, and deleting conversations in a monadic context.+--+-- @since 0.2.0.0+-}+class Monad m => ConversationStore m where+  -- | Saves a conversation to the store.+  --+  -- Validates the conversation and updates its 'lastUpdated' timestamp before saving.+  saveConversation :: Conversation -> m ()++  -- | Loads a conversation by its ID.+  --+  -- Returns 'Just' the conversation if found, or 'Nothing' if not.+  loadConversation :: Text -> m (Maybe Conversation)++  -- | Lists all conversations in the store.+  listConversations :: m [Conversation]++  -- | Deletes a conversation by its ID.+  --+  -- Returns 'True' if the conversation was found and deleted, 'False' otherwise.+  deleteConversation :: Text -> m Bool++{- | In-memory conversation store using a 'TVar' for thread-safe operations.++Stores conversations in a 'Map' keyed by conversation IDs, wrapped in a 'TVar' for concurrent access.+-}+newtype InMemoryStore = InMemoryStore (TVar (Map Text Conversation))++{- | Monad for operations with 'InMemoryStore'.++A wrapper around 'ReaderT' that provides access to an 'InMemoryStore' in a monadic context.+-}+newtype ConvoM a = ConvoM {runConvoM :: ReaderT InMemoryStore IO a}+  deriving (Functor, Applicative, Monad, MonadIO, MonadReader InMemoryStore)++{- | Runs a 'ConvoM' action with the given 'InMemoryStore'.++Executes a monadic computation in the context of an in-memory store.++Example:++>>> store <- initInMemoryStore+>>> runInMemoryConvo store $ saveConversation conv+-}+runInMemoryConvo :: InMemoryStore -> ConvoM a -> IO a+runInMemoryConvo store = flip runReaderT store . runConvoM++instance ConversationStore ConvoM where+  saveConversation conv = do+    case validateConversation conv of+      Left err -> liftIO $ putStrLn ("Validation error: " <> T.unpack err)+      Right validConv -> do+        now <- liftIO getCurrentTime+        let updatedConv = validConv {lastUpdated = now}+        InMemoryStore ref <- ask+        liftIO . atomically $ modifyTVar' ref (Map.insert (conversationId updatedConv) updatedConv)++  loadConversation cid = do+    InMemoryStore ref <- ask+    convs <- liftIO $ readTVarIO ref+    return $ Map.lookup cid convs++  listConversations = do+    InMemoryStore ref <- ask+    convs <- liftIO $ readTVarIO ref+    return $ Map.elems convs++  deleteConversation cid = do+    InMemoryStore ref <- ask+    liftIO . atomically $ do+      convs <- readTVar ref+      if Map.member cid convs+        then do+          writeTVar ref (Map.delete cid convs)+          return True+        else return False++{- | Validates a 'Conversation' to ensure required fields are non-empty.++Checks that the 'conversationId' is not empty and that the 'messages' list contains at least one message.+Returns 'Right' with the validated conversation or 'Left' with an error message.++Example:++>>> let conv = Conversation "" [] "gemma3" time time+>>> validateConversation conv+Left "Conversation ID cannot be empty"+-}+validateConversation :: Conversation -> Either Text Conversation+validateConversation conv+  | T.null (conversationId conv) = Left "Conversation ID cannot be empty"+  | null (messages conv) = Left "Conversation must have at least one message"+  | otherwise = Right conv++{- | Creates a new empty in-memory conversation store.++Initializes an 'InMemoryStore' with an empty 'Map' wrapped in a 'TVar' for thread-safe operations.++Example:++>>> store <- initInMemoryStore+>>> runInMemoryConvo store $ listConversations+[]+-}+initInMemoryStore :: IO InMemoryStore+initInMemoryStore = InMemoryStore <$> newTVarIO Map.empty
src/Data/Ollama/Copy.hs view
@@ -3,53 +3,84 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE OverloadedStrings #-} +{- |+Module      : Data.Ollama.Copy+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Functionality for copying models in the Ollama client.++This module provides functions to copy a model from a source name to a destination name using the Ollama API.+It includes both an IO-based function ('copyModel') and a monadic version ('copyModelM') for use in+'MonadIO' contexts. The copy operation is performed via a POST request to the "/api//copy" endpoint.++Example:++>>> copyModel "gemma3" "gemma3-copy" Nothing+Right ()+-} module Data.Ollama.Copy   ( -- * Copy Model API     copyModel+  , copyModelM   ) where -import Control.Monad (when)+import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson-import Data.Ollama.Common.Utils qualified as CU+import Data.Ollama.Common.Config (OllamaConfig (..))+import Data.Ollama.Common.Error (OllamaError)+import Data.Ollama.Common.Utils (nonJsonHandler, withOllamaRequest) import Data.Text (Text)-import Data.Text qualified as T import GHC.Generics-import Network.HTTP.Client-import Network.HTTP.Types.Status (status404) --- TODO: Add Options parameter--- TODO: Add Context parameter+-- | Configuration for copying a model. data CopyModelOps = CopyModelOps-  { source :: Text-  , destination :: Text+  { source :: !Text+  -- ^ The name of the source model to copy.+  , destination :: !Text+  -- ^ The name of the destination model.   }   deriving (Show, Eq, Generic, ToJSON) --- | Copy model from source to destination+{- | Copies a model from a source name to a destination name.++Sends a POST request to the "/api//copy" endpoint with the source and destination model names.+Returns 'Right ()' on success or 'Left' with an 'OllamaError' on failure.+Example:++>>> copyModel "gemma3" "gemma3-copy" Nothing+Right ()+-} copyModel ::-  -- | Source model+  -- | Source model name   Text ->-  -- | Destination model+  -- | Destination model name   Text ->-  IO ()+  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')+  Maybe OllamaConfig ->+  IO (Either OllamaError ()) copyModel   source_-  destination_ =-    do-      let url = CU.defaultOllamaUrl-      manager <- newManager defaultManagerSettings-      initialRequest <- parseRequest $ T.unpack (url <> "/api/copy")-      let reqBody =-            CopyModelOps-              { source = source_-              , destination = destination_-              }-          request =-            initialRequest-              { method = "POST"-              , requestBody = RequestBodyLBS $ encode reqBody-              }-      response <- httpLbs request manager-      when-        (responseStatus response == status404)-        (putStrLn "Source Model does not exist")+  destination_+  mbConfig = do+    let reqBody = CopyModelOps {source = source_, destination = destination_}+    withOllamaRequest+      "/api//copy"+      "POST"+      (Just reqBody)+      mbConfig+      (fmap ((const ()) <$>) . nonJsonHandler)++{- | MonadIO version of 'copyModel' for use in monadic contexts.++Lifts the 'copyModel' function into a 'MonadIO' context, allowing it to be used in monadic computations.++Example:++>>> import Control.Monad.IO.Class+>>> runReaderT (copyModelM "gemma3" "gemma3-copy" Nothing) someContext+Right ()+-}+copyModelM :: MonadIO m => Text -> Text -> Maybe OllamaConfig -> m (Either OllamaError ())+copyModelM s d mbCfg = liftIO $ copyModel s d mbCfg
src/Data/Ollama/Create.hs view
@@ -1,35 +1,64 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-} +{- |+Module      : Data.Ollama.Create+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Functionality for creating new models in the Ollama client.++This module provides functions to create a new model in the Ollama API using either a model file+content or a file path. It includes both an IO-based function ('createModel') and a monadic version+('createModelM') for use in 'MonadIO' contexts. The create operation is performed via a POST request+to the "/api//pull" endpoint, with streaming support for progress updates.++Note: If both 'modelFile' and 'path' are provided, 'modelFile' takes precedence.++Example:++>>> createModel "myModel" (Just "FROM llama3\nPARAMETER temperature 0.8") (Just True) Nothing Nothing+Creating model...+Completed+-} module Data.Ollama.Create   ( -- * Create Model API     createModel-  , createModelOps+  , createModelM   ) where -import Control.Monad (unless)+import Control.Monad (void)+import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson-import Data.ByteString.Lazy.Char8 qualified as BSL+import Data.Ollama.Common.Config (OllamaConfig)+import Data.Ollama.Common.Types (HasDone (getDone)) import Data.Ollama.Common.Utils as CU import Data.Text (Text)-import Data.Text qualified as T-import Data.Text.IO qualified as T-import Network.HTTP.Client --- TODO: Add Options parameter--- TODO: Add Context parameter+-- | Configuration for creating a new model. data CreateModelOps = CreateModelOps-  { name :: Text-  , modelFile :: Maybe Text-  , stream :: Maybe Bool-  , path :: Maybe FilePath+  { name :: !Text+  -- ^ The name of the model to create.+  , modelFile :: !(Maybe Text)+  -- ^ Optional model file content (e.g., Modelfile text). Takes precedence over 'path'.+  , stream :: !(Maybe Bool)+  -- ^ Optional flag to enable streaming progress updates.+  , path :: !(Maybe FilePath)+  -- ^ Optional file path to a Modelfile.   }   deriving (Show, Eq) --- TODO: Add Context Param-newtype CreateModelResp = CreateModelResp {status :: Text}+-- | Response type for model creation.+newtype CreateModelResp+  = -- | The status of the create operation (e.g., "success").+    CreateModelResp {status :: Text}   deriving (Show, Eq) +instance HasDone CreateModelResp where+  getDone CreateModelResp {..} = status /= "success"+ instance ToJSON CreateModelOps where   toJSON     ( CreateModelOps@@ -50,71 +79,63 @@     CreateModelResp       <$> v .: "status" -{- | Create a new model either from ModelFile or Path-Please note, if you specify both ModelFile and Path, ModelFile will be used.+{- | Creates a new model using either model file content or a file path.++Sends a POST request to the "/api//pull" endpoint to create a model with the specified name.+The model can be defined either by 'modelFile' (Modelfile content as text) or 'path' (file path to a Modelfile).+If both are provided, 'modelFile' is used. Supports streaming progress updates if 'stream' is 'Just True'.+Prints progress messages to the console during creation. -}-createModelOps ::-  -- | Model Name+createModel ::+  -- | Model name   Text ->-  -- | Model File+  -- | Optional model file content   Maybe Text ->-  -- | Stream+  -- | Optional streaming flag   Maybe Bool ->-  -- | Path+  -- | Optional file path to a Modelfile   Maybe FilePath ->+  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')+  Maybe OllamaConfig ->   IO ()-createModelOps+createModel   modelName   modelFile_   stream_-  path_ =-    do-      let url = defaultOllamaUrl-      manager <- newManager defaultManagerSettings-      initialRequest <- parseRequest $ T.unpack (url <> "/api/create")-      let reqBody =+  path_+  mbConfig =+    void $+      withOllamaRequest+        "/api//pull"+        "POST"+        ( Just $             CreateModelOps               { name = modelName               , modelFile = modelFile_               , stream = stream_               , path = path_               }-          request =-            initialRequest-              { method = "POST"-              , requestBody = RequestBodyLBS $ encode reqBody-              }-      withResponse request manager $ \response -> do-        let go = do-              bs <- brRead $ responseBody response-              let eRes =-                    eitherDecode (BSL.fromStrict bs) ::-                      Either String CreateModelResp-              case eRes of-                Left err -> do-                  putStrLn $ "Error: " <> err-                Right res -> do-                  unless-                    (status res /= "success")-                    ( do-                        T.putStr $ status res-                        go-                    )-        go+        )+        mbConfig+        (commonStreamHandler onToken onComplete)+    where+      onToken :: CreateModelResp -> IO ()+      onToken _ = do+        putStrLn "Creating model..." -{- | Create a new model-| Please note, if you specify both ModelFile and Path, ModelFile will be used.+      onComplete :: IO ()+      onComplete = putStrLn "Completed"++{- | MonadIO version of 'createModel' for use in monadic contexts.++Lifts the 'createModel' function into a 'MonadIO' context, allowing it to be used in monadic computations. -}-createModel ::-  -- | Model Name+createModelM ::+  MonadIO m =>   Text ->-  -- | Model File   Maybe Text ->-  -- | Path+  Maybe Bool ->   Maybe FilePath ->-  IO ()-createModel modelName modelFile_ =-  createModelOps-    modelName-    modelFile_-    Nothing+  Maybe OllamaConfig ->+  m ()+createModelM m mf s p mbCfg = liftIO $ createModel m mf s p mbCfg
src/Data/Ollama/Delete.hs view
@@ -3,42 +3,69 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} +{- |+Module      : Data.Ollama.Delete+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Functionality for deleting models in the Ollama client.++This module provides functions to delete a model from the Ollama server using its name. It includes+both an IO-based function ('deleteModel') and a monadic version ('deleteModelM') for use in+'MonadIO' contexts. The delete operation is performed via a DELETE request to the "/api//delete" endpoint.++Example:++>>> deleteModel "gemma3" Nothing+Right ()+-} module Data.Ollama.Delete-  ( -- * Delete downloaded Models+  ( -- * Delete Model API     deleteModel+  , deleteModelM   ) where -import Control.Monad (when)+import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson-import Data.Ollama.Common.Utils qualified as CU+import Data.Ollama.Common.Config (OllamaConfig (..))+import Data.Ollama.Common.Error (OllamaError)+import Data.Ollama.Common.Utils (nonJsonHandler, withOllamaRequest) import Data.Text (Text)-import Data.Text qualified as T-import Network.HTTP.Client-import Network.HTTP.Types.Status (status404) --- TODO: Add Options parameter--- TODO: Add Context parameter-newtype DeleteModelReq = DeleteModelReq {name :: Text}-  deriving newtype (Show, Eq, ToJSON)+-- | Request payload for deleting a model.+newtype DeleteModelReq+  = -- | The name of the model to delete.+    DeleteModelReq {name :: Text}+  deriving newtype (Show, Eq) --- | Delete a model+instance ToJSON DeleteModelReq where+  toJSON (DeleteModelReq name_) = object ["name" .= name_]++{- | Deletes a model from the Ollama server.++Sends a DELETE request to the "/api//delete" endpoint with the specified model name.+Returns 'Right ()' on success or 'Left' with an 'OllamaError' on failure.+-} deleteModel ::-  -- | Model name+  -- | Model name to delete   Text ->-  IO ()-deleteModel modelName =-  do-    let url = CU.defaultOllamaUrl-    manager <- newManager defaultManagerSettings-    initialRequest <- parseRequest $ T.unpack (url <> "/api/delete")-    let reqBody =-          DeleteModelReq {name = modelName}-        request =-          initialRequest-            { method = "DELETE"-            , requestBody = RequestBodyLBS $ encode reqBody-            }-    response <- httpLbs request manager-    when-      (responseStatus response == status404)-      (putStrLn "Model does not exist")+  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')+  Maybe OllamaConfig ->+  IO (Either OllamaError ())+deleteModel modelName mbConfig = do+  let reqBody = DeleteModelReq {name = modelName}+  withOllamaRequest+    "/api//delete"+    "DELETE"+    (Just reqBody)+    mbConfig+    (fmap ((const ()) <$>) . nonJsonHandler)++{- | MonadIO version of 'deleteModel' for use in monadic contexts.++Lifts the 'deleteModel' function into a  context,+allowing it to be used in monadic computations.+-}+deleteModelM :: MonadIO m => Text -> Maybe OllamaConfig -> m (Either OllamaError ())+deleteModelM t mbCfg = liftIO $ deleteModel t mbCfg
src/Data/Ollama/Embeddings.hs view
@@ -1,102 +1,180 @@-{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE OverloadedStrings #-} +{- |+Module      : Data.Ollama.Embeddings+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Functionality for generating text embeddings using the Ollama API.++This module provides functions to generate text embeddings from an Ollama model. It includes both+high-level ('embedding', 'embeddingM') and low-level ('embeddingOps', 'embeddingOpsM') APIs for+generating embeddings, with support for customizing model options, truncation, and keep-alive settings.+The embeddings are returned as a list of float vectors, suitable for tasks like semantic search or+text similarity analysis.++The 'EmbeddingOps' type configures the embedding request, and 'EmbeddingResp' represents the response+containing the model name and the generated embeddings. The 'defaultEmbeddingOps' provides a default+configuration for convenience.++Example:++>>> embedding "llama3.2" ["Hello, world!"]+Right (EmbeddingResp "llama3.2" [[0.1, 0.2, ...]])+-} module Data.Ollama.Embeddings   ( -- * Embedding API     embedding   , embeddingOps+  , embeddingM+  , embeddingOpsM++    -- * Configuration and Response Types+  , defaultEmbeddingOps   , EmbeddingOps (..)   , EmbeddingResp (..)++    -- * Model Options+  , ModelOptions (..)+  , defaultModelOptions   ) where +import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson+import Data.Ollama.Common.Config (OllamaConfig)+import Data.Ollama.Common.Error (OllamaError)+import Data.Ollama.Common.Types (ModelOptions (..)) import Data.Ollama.Common.Utils as CU import Data.Text (Text)-import Data.Text qualified as T-import Network.HTTP.Client-import Control.Exception (try)-import Data.ByteString.Lazy.Char8 (ByteString) --- TODO: Add Options parameter+{- | Default configuration for embedding requests.++Provides a default 'EmbeddingOps' with the "llama3.2" model, an empty input list, and no additional options.+Can be customized by modifying fields as needed.+-}+defaultEmbeddingOps :: EmbeddingOps+defaultEmbeddingOps =+  EmbeddingOps+    { model = "llama3.2"+    , input = []+    , truncateInput = Nothing+    , keepAliveEmbed = Nothing+    , modelOptions = Nothing+    }++-- | Configuration for an embedding request. data EmbeddingOps = EmbeddingOps-  { model :: Text-  , input :: Text-  , truncate :: Maybe Bool-  , keepAlive :: Maybe Text+  { model :: !Text+  -- ^ The name of the model to use for generating embeddings (e.g., "llama3.2").+  , input :: ![Text]+  -- ^ List of input texts to generate embeddings for.+  , truncateInput :: !(Maybe Bool)+  -- ^ Optional flag to truncate input if it exceeds model limits.+  , keepAliveEmbed :: !(Maybe Int)+  -- ^ Optional override for the keep-alive timeout in minutes.+  , modelOptions :: !(Maybe ModelOptions)+  -- ^ Optional model parameters (e.g., temperature) as specified in the Modelfile.+  --+  -- @since 0.2.0.0   }   deriving (Show, Eq) +-- | Response type for an embedding request. data EmbeddingResp = EmbeddingResp-  { model :: Text-  , embedding_ :: [[Float]]+  { respondedModel :: !Text+  -- ^ The name of the model that generated the embeddings.+  , respondedEmbeddings :: ![[Float]]+  -- ^ List of embedding vectors, one for each input text.   }   deriving (Show, Eq)  instance FromJSON EmbeddingResp where-  parseJSON = withObject "EmbeddingResp" $ \v -> EmbeddingResp-        <$> v .: "model"-        <*> v .: "embeddings"+  parseJSON = withObject "EmbeddingResp" $ \v ->+    EmbeddingResp+      <$> v .: "model"+      <*> v .: "embeddings"  instance ToJSON EmbeddingOps where-  toJSON (EmbeddingOps model_ input_ truncate' keepAlive_) =+  toJSON (EmbeddingOps model_ input_ truncate' keepAlive_ ops) =     object       [ "model" .= model_       , "input" .= input_       , "truncate" .= truncate'       , "keep_alive" .= keepAlive_+      , "options" .= ops       ] --- TODO: Add Options parameter+{- | Generates embeddings for a list of input texts with full configuration. --- | Embedding API+Sends a POST request to the "/api//embed" endpoint to generate embeddings for the provided inputs.+Allows customization of truncation, keep-alive settings, model options, and Ollama configuration.+Returns 'Right' with an 'EmbeddingResp' on success or 'Left' with an 'OllamaError' on failure.+-} embeddingOps ::-  -- | Model-  Text ->-  -- | Input+  -- | Model name   Text ->-  -- | Truncate+  -- | List of input texts+  [Text] ->+  -- | Optional truncation flag   Maybe Bool ->-  -- | Keep Alive-  Maybe Text ->-  IO (Either String EmbeddingResp)-embeddingOps modelName input_ mTruncate mKeepAlive = do-  let url = defaultOllamaUrl-  manager <- newManager defaultManagerSettings-  --einitialRequest <- parseRequest $ T.unpack (url <> "/api/embed")-  eInitialRequest <--    try $ parseRequest $ T.unpack (url <> "/api/embed") :: IO (Either HttpException Request)-  case eInitialRequest of-    Left e -> do-      return $ Left $ show e-    Right initialRequest -> do-      let reqBody =-            EmbeddingOps-              { model = modelName-              , input = input_-              , truncate = mTruncate-              , keepAlive = mKeepAlive-              }-          request =-            initialRequest-              { method = "POST"-              , requestBody = RequestBodyLBS $ encode reqBody-              }-      eResp <- try $ httpLbs request manager :: IO (Either HttpException (Response ByteString))-      case eResp of-        Left err -> return $ Left (show err)-        Right resp -> -          case decode (responseBody resp) of-            Nothing -> return $ Left $ "Couldn't decode response: " <> show (responseBody resp)-            Just r -> return $ Right r+  -- | Optional keep-alive timeout in minutes+  Maybe Int ->+  -- | Optional model options+  Maybe ModelOptions ->+  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')+  Maybe OllamaConfig ->+  IO (Either OllamaError EmbeddingResp)+embeddingOps modelName input_ mTruncate mKeepAlive mbOptions mbConfig = do+  withOllamaRequest+    "/api//embed"+    "POST"+    ( Just $+        EmbeddingOps+          { model = modelName+          , input = input_+          , truncateInput = mTruncate+          , keepAliveEmbed = mKeepAlive+          , modelOptions = mbOptions+          }+    )+    mbConfig+    commonNonStreamingHandler --- Higher level binding that only takes important params+{- | Simplified API for generating embeddings. --- | Embedding API+A higher-level function that generates embeddings using default settings for truncation, keep-alive,+model options, and Ollama configuration. Suitable for basic use cases.+-} embedding ::-  -- | Model-  Text ->-  -- | Input+  -- | Model name   Text ->-  IO (Either String EmbeddingResp)+  -- | List of input texts+  [Text] ->+  IO (Either OllamaError EmbeddingResp) embedding modelName input_ =-  embeddingOps modelName input_ Nothing Nothing+  embeddingOps modelName input_ Nothing Nothing Nothing Nothing++{- | MonadIO version of 'embedding' for use in monadic contexts.++Lifts the 'embedding' function into a 'MonadIO' context, allowing it to be used in monadic computations.+-}+embeddingM :: MonadIO m => Text -> [Text] -> m (Either OllamaError EmbeddingResp)+embeddingM m ip = liftIO $ embedding m ip++{- | MonadIO version of 'embeddingOps' for use in monadic contexts.++Lifts the 'embeddingOps' function into a 'MonadIO' context, allowing it to be used in monadic computations+with full configuration options.+-}+embeddingOpsM ::+  MonadIO m =>+  Text ->+  [Text] ->+  Maybe Bool ->+  Maybe Int ->+  Maybe ModelOptions ->+  Maybe OllamaConfig ->+  m (Either OllamaError EmbeddingResp)+embeddingOpsM m ip mbTruncate mbKeepAlive mbOptions mbCfg =+  liftIO $ embeddingOps m ip mbTruncate mbKeepAlive mbOptions mbCfg
src/Data/Ollama/Generate.hs view
@@ -2,80 +2,111 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} +{- |+Module      : Data.Ollama.Generate+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Text generation functionality for the Ollama client.++This module provides functions and types for generating text using an Ollama model. It includes APIs+for sending generation requests, both in IO ('generate') and monadic ('generateM') contexts, with+support for streaming and non-streaming responses. The 'GenerateOps' type configures the generation+request, allowing customization of the model, prompt, images, format, and other parameters. The+'defaultGenerateOps' provides a convenient starting point for configuration.++The module supports advanced features like Base64-encoded images, custom templates, and model-specific+options (e.g., temperature). It also includes validation to ensure required fields are non-empty.++Example:++>>> let ops = defaultGenerateOps { modelName = "gemma3", prompt = "Write a poem." }+>>> generate ops Nothing+Right (GenerateResponse ...)+-} module Data.Ollama.Generate   ( -- * Generate Texts     generate+  , generateM++    -- * Configuration   , defaultGenerateOps-  , generateJson   , GenerateOps (..)+  , validateGenerateOps++    -- * Response and Configuration Types   , GenerateResponse (..)+  , Format (..)+  , OllamaConfig (..)+  , defaultOllamaConfig+  , ModelOptions (..)+  , defaultModelOptions++    -- * Error Types+  , OllamaError (..)   ) where -import Control.Exception (try)+import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson-import Data.ByteString.Char8 qualified as BS-import Data.ByteString.Lazy.Char8 qualified as BSL import Data.Maybe+import Data.Ollama.Common.Config (OllamaConfig (..), defaultOllamaConfig)+import Data.Ollama.Common.Error (OllamaError (..))+import Data.Ollama.Common.Types (Format (..), GenerateResponse (..), ModelOptions (..)) import Data.Ollama.Common.Utils as CU-import Data.Ollama.Common.Types (Format(..)) import Data.Text (Text) import Data.Text qualified as T-import Data.Text.Encoding qualified as T-import Data.Time (UTCTime)-import GHC.Int (Int64)-import Network.HTTP.Client --- TODO: Add Options parameter--- TODO: Add Context parameter+{- | Validates 'GenerateOps' to ensure required fields are non-empty. -{- |-  Input type for generate functions. This data type represents all possible configurations-  that you can pass to the Ollama generate API.+Checks that the 'modelName' and 'prompt' fields are not empty. Returns 'Right' with the validated+'GenerateOps' or 'Left' with an 'OllamaError' if validation fails. -  Example:+Example: -  > let ops = GenerateOps-  >         { modelName = "llama3.2"-  >         , prompt = "What is the meaning of life?"-  >         , suffix = Nothing-  >         , images = Nothing-  >         , format = Just "text"-  >         , system = Nothing-  >         , template = Nothing-  >         , stream = Nothing-  >         , raw = Just False-  >         , keepAlive = Just "yes"-  >         }+>>> validateGenerateOps defaultGenerateOps+Left (InvalidRequest "Prompt cannot be empty")+--+-- @since 0.2.0.0 -}+validateGenerateOps :: GenerateOps -> Either OllamaError GenerateOps+validateGenerateOps ops+  | T.null (modelName ops) = Left $ InvalidRequest "Model name cannot be empty"+  | T.null (prompt ops) = Left $ InvalidRequest "Prompt cannot be empty"+  | otherwise = Right ops++-- | Configuration for a text generation request. data GenerateOps = GenerateOps-  { modelName :: Text-  -- ^ The name of the model to be used for generation.-  , prompt :: Text-  -- ^ The prompt text that will be provided to the model for generating a response.+  { modelName :: !Text+  -- ^ The name of the model to use for generation (e.g., "gemma3").+  , prompt :: !Text+  -- ^ The prompt text to provide to the model for generating a response.   , suffix :: Maybe Text-  -- ^ An optional suffix to append to the generated text.-  , images :: Maybe [Text]-  -- ^ Optional list of base64 encoded images to include with the request.-  , format :: Maybe Format-  -- ^ An optional format specifier for the response.-  -- ^ Since 0.1.3.0-  , system :: Maybe Text-  -- ^ Optional system text that can be included in the generation context.-  , template :: Maybe Text-  -- ^ An optional template to format the response.-  , stream :: Maybe (GenerateResponse -> IO (), IO ())-  -- ^ An optional streaming function where the first function handles each chunk of response, and the second flushes the stream.-  , raw :: Maybe Bool-  -- ^ An optional flag to return the raw response.-  , keepAlive :: Maybe Text-  -- ^ Optional text to specify keep-alive behavior.-  , hostUrl :: Maybe Text-  -- ^ Override default Ollama host url. Default url = "http://127.0.0.1:11434"-  , responseTimeOut :: Maybe Int-  -- ^ Override default response timeout in minutes. Default = 15 minutes-  , options :: Maybe Value-  -- ^ additional model parameters listed in the documentation for the Modelfile such as temperature-  -- ^ Since 0.1.3.0+  -- ^ Optional suffix to append to the generated text (not supported by all models).+  , images :: !(Maybe [Text])+  -- ^ Optional list of Base64-encoded images to include with the request.+  , format :: !(Maybe Format)+  -- ^ Optional format specifier for the response (e.g., JSON).+  --+  -- @since 0.1.3.0+  , system :: !(Maybe Text)+  -- ^ Optional system text to include in the generation context.+  , template :: !(Maybe Text)+  -- ^ Optional template to format the response.+  , stream :: !(Maybe (GenerateResponse -> IO (), IO ()))+  -- ^ Optional streaming functions: the first handles each response chunk, the second flushes the stream.+  , raw :: !(Maybe Bool)+  -- ^ Optional flag to return the raw response.+  , keepAlive :: !(Maybe Int)+  -- ^ Optional override for how long (in minutes) the model stays loaded in memory (default: 5 minutes).+  , options :: !(Maybe ModelOptions)+  -- ^ Optional model parameters (e.g., temperature) as specified in the Modelfile.+  --+  -- @since 0.1.3.0+  , think :: !(Maybe Bool)+  -- ^ Optional flag to enable thinking mode.+  --+  -- @since 0.2.0.0   }  instance Show GenerateOps where@@ -103,6 +134,8 @@       <> show keepAlive       <> ", options : "       <> show options+      <> ", think: "+      <> show think  instance Eq GenerateOps where   (==) a b =@@ -116,35 +149,7 @@       && raw a == raw b       && keepAlive a == keepAlive b       && options a == options b---- TODO: Add Context Param--{- |-Result type for generate function containing the model's response and meta-information.--}-data GenerateResponse = GenerateResponse-  { model :: Text-  -- ^ The name of the model that generated the response.-  , createdAt :: UTCTime-  -- ^ The timestamp when the response was created.-  , response_ :: Text-  -- ^ The generated response from the model.-  , done :: Bool-  -- ^ A flag indicating whether the generation process is complete.-  , totalDuration :: Maybe Int64-  -- ^ Optional total duration in milliseconds for the generation process.-  , loadDuration :: Maybe Int64-  -- ^ Optional load duration in milliseconds for loading the model.-  , promptEvalCount :: Maybe Int64-  -- ^ Optional count of prompt evaluations during the generation process.-  , promptEvalDuration :: Maybe Int64-  -- ^ Optional duration in milliseconds for evaluating the prompt.-  , evalCount :: Maybe Int64-  -- ^ Optional count of evaluations during the generation process.-  , evalDuration :: Maybe Int64-  -- ^ Optional duration in milliseconds for evaluations during the generation process.-  }-  deriving (Show, Eq)+      && think a == think b  instance ToJSON GenerateOps where   toJSON@@ -159,9 +164,8 @@         stream         raw         keepAlive-        _ -- Host url-        _ -- Response timeout-        options +        options+        think       ) =       object         [ "model" .= model@@ -175,37 +179,24 @@         , "raw" .= raw         , "keep_alive" .= keepAlive         , "options" .= options+        , "think" .= think         ] -instance FromJSON GenerateResponse where-  parseJSON = withObject "GenerateResponse" $ \v ->-    GenerateResponse-      <$> v .: "model"-      <*> v .: "created_at"-      <*> v .: "response"-      <*> v .: "done"-      <*> v .:? "total_duration"-      <*> v .:? "load_duration"-      <*> v .:? "prompt_eval_count"-      <*> v .:? "prompt_eval_duration"-      <*> v .:? "eval_count"-      <*> v .:? "eval_duration"+{- | Default configuration for text generation. -{- |-A function to create a default 'GenerateOps' type with preset values.+Provides a default 'GenerateOps' with the "gemma3" model and an empty prompt. Other fields are set+to 'Nothing' or default values. Can be customized by modifying fields as needed.  Example: -> let ops = defaultGenerateOps-> generate ops--This will generate a response using the default configuration.+>>> let ops = defaultGenerateOps { modelName = "customModel", prompt = "Hello!" }+>>> generate ops Nothing -} defaultGenerateOps :: GenerateOps defaultGenerateOps =   GenerateOps-    { modelName = "llama3.2"-    , prompt = "what is 2+2"+    { modelName = "gemma3"+    , prompt = ""     , suffix = Nothing     , images = Nothing     , format = Nothing@@ -214,197 +205,44 @@     , stream = Nothing     , raw = Nothing     , keepAlive = Nothing-    , hostUrl = Nothing-    , responseTimeOut = Nothing     , options = Nothing+    , think = Nothing     } -{- |-Generate function that returns either a 'GenerateResponse' type or an error message.-It takes a 'GenerateOps' configuration and performs a request to the Ollama generate API.--Examples:--Basic usage without streaming:--> let ops = GenerateOps->         { modelName = "llama3.2"->         , prompt = "Tell me a joke."->         , suffix = Nothing->         , images = Nothing->         , format = Nothing->         , system = Nothing->         , template = Nothing->         , stream = Nothing->         , raw = Nothing->         , keepAlive = Nothing->         }-> result <- generate ops-> case result of->   Left errorMsg -> putStrLn ("Error: " ++ errorMsg)->   Right response -> print response--Usage with streaming to print responses to the console:--> void $->   generate->     defaultGenerateOps->       { modelName = "llama3.2"->       , prompt = "what is functional programming?"->       , stream = Just (T.putStr . response_, pure ())->       }--In this example, the first function in the 'stream' tuple processes each chunk of response by printing it,-and the second function is a simple no-op flush.generate :: GenerateOps -> IO (Either String GenerateResponse)--}-generate :: GenerateOps -> IO (Either String GenerateResponse)-generate genOps = do-  let url = fromMaybe defaultOllamaUrl (hostUrl genOps)-      responseTimeout = fromMaybe 15 (responseTimeOut genOps)-  manager <--    newManager -- Setting response timeout to 5 minutes, since llm takes time-      defaultManagerSettings-        { managerResponseTimeout = responseTimeoutMicro (responseTimeout * 60 * 1000000)-        }-  eInitialRequest <--    try $ parseRequest $ T.unpack (url <> "/api/generate") :: IO (Either HttpException Request)-  case eInitialRequest of-    Left e -> do-      return $ Left $ show e-    Right initialRequest -> do-      let reqBody = genOps-          request =-            initialRequest-              { method = "POST"-              , requestBody = RequestBodyLBS $ encode reqBody-              }-      eRes <--        try (withResponse request manager $ handleRequest genOps) ::-          IO (Either HttpException (Either String GenerateResponse))-      case eRes of-        Left e -> do-          return $ Left $ "HTTP error occured: " <> show e-        Right r -> return r--handleRequest :: GenerateOps -> Response BodyReader -> IO (Either String GenerateResponse)-handleRequest genOps response = do-  let streamResponse sendChunk flush = do-        bs <- brRead $ responseBody response-        if BS.null bs-          then putStrLn "" >> pure (Left "")-          else do-            let eRes = eitherDecode (BSL.fromStrict bs) :: Either String GenerateResponse-            case eRes of-              Left e -> pure (Left e)-              Right r -> do-                _ <- sendChunk r-                _ <- flush-                if done r then pure (Right r) else streamResponse sendChunk flush-  let genResponse op = do-        bs <- brRead $ responseBody response-        if bs == ""-          then do-            let eRes0 = eitherDecode (BSL.fromStrict op) :: Either String GenerateResponse-            case eRes0 of-              Left e -> pure (Left e)-              Right r -> pure (Right r)-          else genResponse (op <> bs)-  case stream genOps of-    Nothing -> genResponse ""-    Just (sendChunk, flush) -> streamResponse sendChunk flush--{- |- generateJson is a higher level function that takes generateOps (similar to generate) and also takes- a Haskell type (that has To and From JSON instance) and returns the response in provided type.-- This function simply calls generate with extra prompt appended to it, telling LLM to return the- response in certain JSON format and serializes the response. This function will be helpful when you- want to use the LLM to do something programmatic.-- For Example:-  > let expectedJsonStrucutre = Example {-  >   sortedList = ["sorted List here"]-  > , wasListAlreadSorted = False-  > }-  > eRes2 <- generateJson-  >     defaultGenerateOps-  >      { modelName = "llama3.2"-  >     , prompt = "Sort given list: [4, 2 , 3, 67]. Also tell whether list was already sorted or not."-  >       }-  >     expectedJsonStrucutre-  >     Nothing-  > case eRes2 of-  >   Left e -> putStrLn e-  >   Right r -> print ("JSON response: " :: String, r)+{- | Generates text using the specified model and configuration. -Output:-  > ("JSON response: ",Example {sortedList = ["1","2","3","4"], wasListAlreadSorted = False})+Validates the 'GenerateOps' configuration and sends a POST request to the "/api//generate" endpoint.+Supports both streaming and non-streaming responses based on the 'stream' field in 'GenerateOps'.+Returns 'Right' with a 'GenerateResponse' on success or 'Left' with an 'OllamaError' on failure. -Note: While Passing the type, construct the type that will help LLM understand the field better.- For example, in the above example, the sortedList's value is written as "Sorted List here". This- will help LLM understand context better.+Example: - You can also provide number of retries in case the LLM field to return the response in correct JSON- in first attempt.+>>> let ops = defaultGenerateOps { modelName = "gemma3", prompt = "Write a short poem." }+>>> generate ops Nothing+Right (GenerateResponse ...) -}-generateJson ::-  (ToJSON jsonResult, FromJSON jsonResult) =>-  GenerateOps ->-  -- | Haskell type that you want your result in-  jsonResult ->-  -- | Max retries-  Maybe Int ->-  IO (Either String jsonResult)-generateJson genOps@GenerateOps {..} jsonStructure mMaxRetries = do-  let jsonHelperPrompt =-        "You are an AI that returns only JSON object. \n"-          <> "* Your output should be a JSON object that matches the following schema: \n"-          <> T.decodeUtf8 (BSL.toStrict $ encode jsonStructure)-          <> prompt-          <> "\n"-          <> "# How to treat the task:\n"-          <> "* Stricly follow the schema for the output.\n"-          <> "* Never return anything other than a JSON object.\n"-          <> "* Do not talk to the user.\n"-  generatedResponse <- generate genOps {prompt = jsonHelperPrompt}-  case generatedResponse of-    Left err -> return $ Left err-    Right r -> do-      case decode (BSL.fromStrict . T.encodeUtf8 $ response_ r) of-        Nothing -> do-          case mMaxRetries of-            Nothing -> return $ Left "Decoding Failed :("-            Just n ->-              if n < 1-                then return $ Left "Decoding failed :("-                else generateJson genOps jsonStructure (Just (n - 1))-        Just resultInType -> return $ Right resultInType+generate :: GenerateOps -> Maybe OllamaConfig -> IO (Either OllamaError GenerateResponse)+generate ops mbConfig =+  case validateGenerateOps ops of+    Left err -> pure $ Left err+    Right _ -> withOllamaRequest "/api//generate" "POST" (Just ops) mbConfig handler+  where+    handler = case stream ops of+      Nothing -> commonNonStreamingHandler+      Just (sc, fl) -> commonStreamHandler sc fl +{- | MonadIO version of 'generate' for use in monadic contexts. -{- |-   Example usage of 'Ollama.generate' with a JSON schema format and options field.+Lifts the 'generate' function into a 'MonadIO' context, allowing it to be used in monadic computations. -   In this example we pass a JSON schema that expects an object with an integer field @age@.-   The options field is supplied as a JSON value.+Example: -   >>> import Data.Aeson (Value, object, (.=))-   >>> import Ollama (GenerateOps, defaultGenerateOps, SchemaFormat)-   >>> let x :: Value-   ...     x = object [ "type" .= ("object" :: String)-   ...                , "properties" .= object [ "age" .= object ["type" .= ("integer" :: String)] ]-   ...                ]-   >>> let opts :: Value-   ...     opts = object ["option" .= ("some value" :: String)]-   >>> generate defaultGenerateOps-   ...   { modelName = "llama3.2"-   ...   , prompt = "Ollama is 22 years old and is busy saving the world. Respond using JSON"-   ...   , format = Just (SchemaFormat x)-   ...   , options = opts-   ...   }-   Right (GenerateResponse {model = "llama3.2", createdAt = 2025-03-25 09:34:15.853417157 UTC,-                            response_ = "{\n    \"age\": 22\n}", done = True,-                            totalDuration = Just 6625631744, loadDuration = Just 2578791966,-                            promptEvalCount = Just 43, promptEvalDuration = Just 2983000000,-                            evalCount = Just 10, evalDuration = Just 1061000000})+>>> import Control.Monad.IO.Class+>>> let ops = defaultGenerateOps { modelName = "gemma3", prompt = "Hello!" }+>>> runReaderT (generateM ops Nothing) someContext+Right (GenerateResponse ...) -}-+generateM ::+  MonadIO m =>+  GenerateOps -> Maybe OllamaConfig -> m (Either OllamaError GenerateResponse)+generateM ops mbCfg = liftIO $ generate ops mbCfg
src/Data/Ollama/List.hs view
@@ -1,39 +1,69 @@+-- |+-- Module      : Data.Ollama.List+-- Copyright   : (c) 2025 Tushar Adhatrao+-- License     : MIT+-- Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+-- Stability   : experimental+-- Description : Functionality for listing available models in the Ollama client.+--+-- This module provides functions to retrieve a list of models available on the Ollama server.+-- It includes both an IO-based function ('list') and a monadic version ('listM') for use in+-- 'MonadIO' contexts. The list operation is performed via a GET request to the "/api//tags" endpoint,+-- returning a 'Models' type containing a list of 'ModelInfo' records with details about each model.+--+-- Example:+--+-- >>> list Nothing+-- Right (Models [ModelInfo ...])+-- {-# LANGUAGE OverloadedStrings #-}  module Data.Ollama.List   ( -- * List Models API-    list-  , Models (..)-  , ModelInfo (..)-  )-where+    list,+    listM, +    -- * Model Types+    Models (..),+    ModelInfo (..)+  ) where++import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson+import Data.Ollama.Common.Config (OllamaConfig)+import Data.Ollama.Common.Error (OllamaError) import Data.Ollama.Common.Types as CT import Data.Ollama.Common.Utils as CU import Data.Text (Text)-import Data.Text qualified as T import Data.Time import GHC.Int (Int64)-import Network.HTTP.Client-import Network.HTTP.Types.Status (statusCode) +-- | A wrapper type containing a list of available models.+-- newtype Models = Models [ModelInfo]+  -- ^ List of 'ModelInfo' records describing available models.   deriving (Eq, Show) +-- | Details about a specific model.+-- data ModelInfo = ModelInfo-  { name :: Text-  , modifiedAt :: UTCTime-  , size :: Int64-  , digest :: Text-  , details :: ModelDetails-  }-  deriving (Eq, Show)+  { name :: !Text+    -- ^ The name of the model.+  , modifiedAt :: !UTCTime+    -- ^ The timestamp when the model was last modified.+  , size :: !Int64+    -- ^ The size of the model in bytes.+  , digest :: !Text+    -- ^ The digest (hash) of the model.+  , details :: !ModelDetails+    -- ^ Additional details about the model (e.g., format, family, parameters).+  } deriving (Eq, Show) --- Instances+-- | JSON parsing instance for 'Models'. instance FromJSON Models where   parseJSON = withObject "Models" $ \v -> Models <$> v .: "models" +-- | JSON parsing instance for 'ModelInfo'. instance FromJSON ModelInfo where   parseJSON = withObject "ModelInfo" $ \v ->     ModelInfo@@ -43,17 +73,31 @@       <*> v .: "digest"       <*> v .: "details" --- | List all models from local-list :: IO (Maybe Models)-list = do-  let url = defaultOllamaUrl-  manager <- newManager defaultManagerSettings-  request <- parseRequest $ T.unpack (url <> "/api/tags")-  response <- httpLbs request manager-  if statusCode (responseStatus response) /= 200-    then pure Nothing-    else do-      let res = decode (responseBody response) :: Maybe Models-      case res of-        Nothing -> pure Nothing-        Just l -> pure $ Just l+-- | Retrieves a list of available models from the Ollama server.+--+-- Sends a GET request to the "/api//tags" endpoint to fetch the list of models.+-- Returns 'Right' with a 'Models' containing the list of 'ModelInfo' on success,+-- or 'Left' with an 'OllamaError' on failure.+list ::+  Maybe OllamaConfig -> -- ^ Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')+  IO (Either OllamaError Models)+list mbConfig = do+  withOllamaRequest+    "/api//tags"+    "GET"+    (Nothing :: Maybe Value)+    mbConfig+    commonNonStreamingHandler++-- | MonadIO version of 'list' for use in monadic contexts.+--+-- Lifts the 'list' function into a 'MonadIO' context, allowing it to be used in monadic computations.+--+-- Example:+--+-- >>> import Control.Monad.IO.Class+-- >>> runReaderT (listM Nothing) someContext+-- Right (Models [ModelInfo ...])+--+listM :: MonadIO m => Maybe OllamaConfig -> m (Either OllamaError Models)+listM mbCfg = liftIO $ list mbCfg
+ src/Data/Ollama/Load.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE OverloadedStrings #-}++{- |+Module      : Data.Ollama.Load+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : High-level functions for loading and unloading models in the Ollama client.++This module provides functions to load and unload generative models in the Ollama server.+It includes both IO-based functions ('loadGenModel', 'unloadGenModel') and monadic versions+('loadGenModelM', 'unloadGenModelM') for use in 'MonadIO' contexts. The operations are+performed via POST requests to the "/api//generate" endpoint, leveraging the 'GenerateOps'+configuration from the 'Data.Ollama.Generate' module.++Loading a model keeps it in memory for faster subsequent requests, while unloading frees+up memory by setting the keep-alive duration to zero.++Example:++>>> loadGenModel "gemma3"+Right ()+>>> unloadGenModel "gemma3"+Right ()+-}+module Data.Ollama.Load+  ( -- * Load and Unload Model APIs+    loadGenModel+  , unloadGenModel+  , loadGenModelM+  , unloadGenModelM+  ) where++import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.Ollama.Common.Error+import Data.Ollama.Common.Utils (commonNonStreamingHandler, withOllamaRequest)+import Data.Ollama.Generate qualified as Gen+import Data.Text (Text)++{- | Loads a generative model into memory.++Sends a POST request to the "/api//generate" endpoint to load the specified model into+memory, ensuring faster response times for subsequent requests. Returns 'Right ()' on+success or 'Left' with an 'OllamaError' on failure.+--+-- @since 0.2.0.0+-}+loadGenModel ::+  -- |  Model name (e.g., "gemma3")+  Text ->+  IO (Either OllamaError ())+loadGenModel m = do+  let ops = Gen.defaultGenerateOps {Gen.modelName = m}+  withOllamaRequest "/api//generate" "POST" (Just ops) Nothing commonNonStreamingHandler++{- | Unloads a generative model from memory.++Sends a POST request to the "/api//generate" endpoint with a keep-alive duration of zero+to unload the specified model from memory, freeing up resources. Returns 'Right ()' on+success or 'Left' with an 'OllamaError' on failure.+--+-- @since 0.2.0.0+-}+unloadGenModel ::+  -- | Model name (e.g., "gemma3")+  Text ->+  IO (Either OllamaError ())+unloadGenModel m = do+  let ops = Gen.defaultGenerateOps {Gen.modelName = m, Gen.keepAlive = Just 0}+  withOllamaRequest "/api//generate" "POST" (Just ops) Nothing commonNonStreamingHandler++{- | MonadIO version of 'loadGenModel' for use in monadic contexts.++Lifts the 'loadGenModel' function into a 'MonadIO' context, allowing it to be used in+monadic computations.++Example:++>>> import Control.Monad.IO.Class+>>> runReaderT (loadGenModelM "gemma3") someContext+Right ()+--+-- @since 0.2.0.0+-}+loadGenModelM :: MonadIO m => Text -> m (Either OllamaError ())+loadGenModelM t = liftIO $ loadGenModel t++{- | MonadIO version of 'unloadGenModel' for use in monadic contexts.++Lifts the 'unloadGenModel' function into a 'MonadIO' context, allowing it to be used in+monadic computations.++Example:++>>> import Control.Monad.IO.Class+>>> runReaderT (unloadGenModelM "gemma3") someContext+Right ()+--+-- @since 0.2.0.0+-}+unloadGenModelM :: MonadIO m => Text -> m (Either OllamaError ())+unloadGenModelM t = liftIO $ unloadGenModel t
src/Data/Ollama/Ps.hs view
@@ -1,39 +1,73 @@ {-# LANGUAGE OverloadedStrings #-} +{- |+Module      : Data.Ollama.Ps+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Functionality for listing running models in the Ollama client.++This module provides functions to retrieve a list of models currently running on the Ollama server.+It includes both an IO-based function ('ps') and a monadic version ('psM') for use in 'MonadIO'+contexts. The operation is performed via a GET request to the "/api//ps" endpoint, returning a+'RunningModels' type containing a list of 'RunningModel' records with details about each running model.++Example:++>>> ps Nothing+Right (RunningModels [RunningModel ...])+-} module Data.Ollama.Ps-  ( ps+  ( -- * List Running Models API+    ps+  , psM++    -- * Model Types   , RunningModels (..)   , RunningModel (..)   ) where +import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson+import Data.Ollama.Common.Config (OllamaConfig)+import Data.Ollama.Common.Error (OllamaError) import Data.Ollama.Common.Types as CT import Data.Ollama.Common.Utils as CU import Data.Text (Text)-import Data.Text qualified as T import Data.Time import GHC.Int (Int64)-import Network.HTTP.Client-import Network.HTTP.Types.Status (statusCode) --- Types for Ps API-newtype RunningModels = RunningModels [RunningModel]+-- | A wrapper type containing a list of running models.+newtype RunningModels+  = -- | List of 'RunningModel' records describing currently running models.+    RunningModels [RunningModel]   deriving (Eq, Show) +-- | Details about a specific running model. data RunningModel = RunningModel-  { name_ :: Text-  , modelName :: Text-  , size_ :: Int64-  , modelDigest :: Text-  , modelDetails :: ModelDetails-  , expiresAt :: UTCTime-  , sizeVRam :: Int64+  { name_ :: !Text+  -- ^ The name of the running model instance.+  , modelName :: !Text+  -- ^ The base model name (e.g., "gemma3").+  , size_ :: !Int64+  -- ^ The size of the model in bytes.+  , modelDigest :: !Text+  -- ^ The digest (hash) of the model.+  , modelDetails :: !ModelDetails+  -- ^ Additional details about the model (e.g., format, family, parameters).+  , expiresAt :: !UTCTime+  -- ^ The timestamp when the model's memory allocation expires.+  , sizeVRam :: !Int64+  -- ^ The size of the model's VRAM usage in bytes.   }   deriving (Eq, Show) +-- | JSON parsing instance for 'RunningModels'. instance FromJSON RunningModels where   parseJSON = withObject "Models" $ \v -> RunningModels <$> v .: "models" +-- | JSON parsing instance for 'RunningModel'. instance FromJSON RunningModel where   parseJSON = withObject "RunningModel" $ \v ->     RunningModel@@ -45,17 +79,31 @@       <*> v .: "expires_at"       <*> v .: "size_vram" --- | List running models-ps :: IO (Maybe RunningModels)-ps = do-  let url = defaultOllamaUrl-  manager <- newManager defaultManagerSettings-  request <- parseRequest $ T.unpack (url <> "/api/ps")-  response <- httpLbs request manager-  if statusCode (responseStatus response) /= 200-    then pure Nothing-    else do-      let res = decode (responseBody response) :: Maybe RunningModels-      case res of-        Nothing -> pure Nothing-        Just l -> pure $ Just l+{- | Retrieves a list of currently running models from the Ollama server.++Sends a GET request to the "/api//ps" endpoint to fetch the list of running models.+Returns 'Right' with a 'RunningModels' containing the list of 'RunningModel' on success,+or 'Left' with an 'OllamaError' on failure.+Example:++>>> ps Nothing+Right (RunningModels [RunningModel {name_ = "gemma3:instance1", modelName = "gemma3", ...}])+-}+ps ::+  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')+  Maybe OllamaConfig ->+  IO (Either OllamaError RunningModels)+ps mbConfig = do+  withOllamaRequest+    "/api//ps"+    "GET"+    (Nothing :: Maybe Value)+    mbConfig+    commonNonStreamingHandler++{- | MonadIO version of 'ps' for use in monadic contexts.++Lifts the 'ps' function into a 'MonadIO' context, allowing it to be used in monadic computations.+-}+psM :: MonadIO m => Maybe OllamaConfig -> m (Either OllamaError RunningModels)+psM mbCfg = liftIO $ ps mbCfg
src/Data/Ollama/Pull.hs view
@@ -2,113 +2,155 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-} +{- |+Module      : Data.Ollama.Pull+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Functionality for pulling models in the Ollama client.++This module provides functions to pull (download) models from the Ollama server. It includes both+high-level ('pull', 'pullM') and low-level ('pullOps', 'pullOpsM') APIs for pulling models, with+support for streaming progress updates and insecure connections. The 'PullOps' type configures the+pull request, and 'PullResp' represents the response containing the status and progress details.++The pull operation is performed via a POST request to the "/api//pull" endpoint. Streaming mode,+when enabled, provides real-time progress updates by printing the remaining bytes to the console.++Example:++>>> pull "gemma3"+Remaining bytes: 123456789+...+Completed+Right (PullResp {status = "success", ...})+-} module Data.Ollama.Pull-  ( -- * Downloaded Models+  ( -- * Pull Model API     pull   , pullOps+  , pullM+  , pullOpsM   ) where +import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson-import Data.ByteString.Lazy.Char8 qualified as BSL import Data.Maybe (fromMaybe)+import Data.Ollama.Common.Config (OllamaConfig)+import Data.Ollama.Common.Error (OllamaError)+import Data.Ollama.Common.Types (HasDone (..)) import Data.Ollama.Common.Utils as CU import Data.Text (Text)-import Data.Text qualified as T import GHC.Generics import GHC.Int (Int64)-import Network.HTTP.Client --- TODO: Add Options parameter- -- | Configuration options for pulling a model. data PullOps = PullOps-  { name :: Text-  -- ^ The name of the model to pull.-  , insecure :: Maybe Bool-  -- ^ Option to allow insecure connections.-  -- If set to 'Just True', the pull operation will allow insecure connections.-  , stream :: Maybe Bool-  -- ^ Option to enable streaming of the download.-  -- If set to 'Just True', the download will be streamed.+  { name :: !Text+  -- ^ The name of the model to pull (e.g., "gemma3").+  , insecure :: !(Maybe Bool)+  -- ^ Optional flag to allow insecure connections. If 'Just True', insecure connections are permitted.+  , stream :: !(Maybe Bool)+  -- ^ Optional flag to enable streaming of the download. If 'Just True', progress updates are streamed.   }   deriving (Show, Eq, Generic, ToJSON)  -- | Response data from a pull operation. data PullResp = PullResp-  { status :: Text-  -- ^ The status of the pull operation, e.g., "success" or "failure".-  , digest :: Maybe Text-  -- ^ The digest of the model, if available.-  , total :: Maybe Int64+  { status :: !Text+  -- ^ The status of the pull operation (e.g., "success" or "failure").+  , digest :: !(Maybe Text)+  -- ^ The digest (hash) of the model, if available.+  , total :: !(Maybe Int64)   -- ^ The total size of the model in bytes, if available.-  , completed :: Maybe Int64-  -- ^ The number of bytes completed, if available.+  , completed :: !(Maybe Int64)+  -- ^ The number of bytes downloaded, if available.   }   deriving (Show, Eq, Generic, FromJSON) -{- |-Pull a model with additional options for insecure connections and streaming.-This function interacts directly with the Ollama API to download the specified model.--Example:+instance HasDone PullResp where+  getDone PullResp {..} = status /= "success" -> pullOps "myModel" (Just True) (Just True)+{- | Pulls a model with full configuration. -This will attempt to pull "myModel" with insecure connections allowed and enable streaming.+Sends a POST request to the "/api//pull" endpoint to download the specified model. Supports+streaming progress updates (if 'stream' is 'Just True') and insecure connections (if 'insecure'+is 'Just True'). Prints remaining bytes during streaming and "Completed" when finished.+Returns 'Right' with a 'PullResp' on success or 'Left' with an 'OllamaError' on failure. -} pullOps ::-  -- | Model Name+  -- | Model name   Text ->-  -- | Insecure+  -- | Optional insecure connection flag   Maybe Bool ->-  -- | Stream+  -- | Optional streaming flag   Maybe Bool ->-  IO ()-pullOps modelName mInsecure mStream = do-  let url = defaultOllamaUrl-  manager <- newManager defaultManagerSettings-  initialRequest <- parseRequest $ T.unpack (url <> "/api/pull")-  let reqBody =-        PullOps-          { name = modelName-          , insecure = mInsecure-          , stream = mStream-          }-      request =-        initialRequest-          { method = "POST"-          , requestBody = RequestBodyLBS $ encode reqBody-          }-  withResponse request manager $ \response -> do-    let go = do-          bs <- brRead $ responseBody response-          let eRes = decode (BSL.fromStrict bs) :: Maybe PullResp-          case eRes of-            Nothing -> putStrLn "Something went wrong"-            Just res -> do-              if status res /= "success"-                then do-                  let completed' = fromMaybe 0 (completed res)-                  let total' = fromMaybe 0 (total res)-                  putStrLn $ "Remaining bytes: " <> show (total' - completed')-                  go-                else do-                  putStrLn "Completed"-    go+  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')+  Maybe OllamaConfig ->+  IO (Either OllamaError PullResp)+pullOps modelName mInsecure mStream mbConfig = do+  withOllamaRequest+    "/api//pull"+    "POST"+    (Just $ PullOps {name = modelName, insecure = mInsecure, stream = mStream})+    mbConfig+    (commonStreamHandler onToken onComplete)+  where+    onToken :: PullResp -> IO ()+    onToken res = do+      let completed' = fromMaybe 0 (completed res)+      let total' = fromMaybe 0 (total res)+      putStrLn $ "Remaining bytes: " <> show (total' - completed') -{- |-Pull a model using default options. This simplifies the pull operation by-not requiring additional options.+    onComplete :: IO ()+    onComplete = putStrLn "Completed" +{- | Simplified API for pulling a model.++A higher-level function that pulls a model using default settings for insecure connections,+streaming, and Ollama configuration. Suitable for basic use cases.+-}+pull ::+  -- | Model name+  Text ->+  IO (Either OllamaError PullResp)+pull modelName = pullOps modelName Nothing Nothing Nothing++{- | MonadIO version of 'pull' for use in monadic contexts.++Lifts the 'pull' function into a 'MonadIO' context, allowing it to be used in monadic computations.+ Example: -> pull "myModel"+>>> import Control.Monad.IO.Class+>>> runReaderT (pullM "gemma3") someContext+Right (PullResp {status = "success", ...})+-}+pullM :: MonadIO m => Text -> m (Either OllamaError PullResp)+pullM t = liftIO $ pull t -This will pull "myModel" using default settings (no insecure connections and no streaming).+{- | MonadIO version of 'pullOps' for use in monadic contexts.++Lifts the 'pullOps' function into a 'MonadIO' context, allowing it to be used in monadic computations+with full configuration options.++Example:++>>> import Control.Monad.IO.Class+>>> runReaderT (pullOpsM "gemma3" Nothing (Just True) Nothing) someContext+Remaining bytes: 123456789+...+Completed+Right (PullResp {status = "success", ...}) -}-pull ::-  -- | Model Name+pullOpsM ::+  MonadIO m =>   Text ->-  IO ()-pull modelName = pullOps modelName Nothing Nothing+  Maybe Bool ->+  Maybe Bool ->+  Maybe OllamaConfig ->+  m (Either OllamaError PullResp)+pullOpsM t mbInsecure mbStream mbCfg = liftIO $ pullOps t mbInsecure mbStream mbCfg
src/Data/Ollama/Push.hs view
@@ -2,84 +2,117 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-} +{- |+Module      : Data.Ollama.Push+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Functionality for pushing models to the Ollama server.++This module provides functions to push (upload) a model to the Ollama server. It includes+both an IO-based function ('push') and a monadic version ('pushM') for use in 'MonadIO'+contexts. The push operation is performed via a POST request to the "/api//pull" endpoint,+with support for streaming progress updates and insecure connections.++The 'PushOps' type configures the push request, and 'PushResp' represents the response+containing the status and progress details. Streaming mode, when enabled, provides+real-time progress updates by printing to the console.++Example:++>>> push "gemma3" Nothing (Just True) Nothing+Pushing...+Completed+-} module Data.Ollama.Push-  ( -- * Push API+  ( -- * Push Model API     push-  , pushOps+  , pushM   ) where +import Control.Monad (void)+import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson-import Data.ByteString.Lazy.Char8 qualified as BSL-import Data.Maybe (fromMaybe)+import Data.Ollama.Common.Config (OllamaConfig)+import Data.Ollama.Common.Types (HasDone (getDone)) import Data.Ollama.Common.Utils as CU import Data.Text (Text)-import Data.Text qualified as T import GHC.Generics import GHC.Int (Int64)-import Network.HTTP.Client --- TODO: Add Options parameter+-- | Configuration options for pushing a model. data PushOps = PushOps-  { name :: Text-  , insecure :: Maybe Bool-  , stream :: Maybe Bool+  { name :: !Text+  -- ^ The name of the model to push (e.g., "gemma3").+  , insecure :: !(Maybe Bool)+  -- ^ Optional flag to allow insecure connections.+  -- If 'Just True', insecure connections are permitted.+  , stream :: !(Maybe Bool)+  -- ^ Optional flag to enable streaming of the upload.+  -- If 'Just True', progress updates are streamed.   }   deriving (Show, Eq, Generic, ToJSON) +-- | Response data from a push operation. data PushResp = PushResp-  { status :: Text-  , digest :: Maybe Text-  , total :: Maybe Int64+  { status :: !Text+  -- ^ The status of the push operation (e.g., "success" or "failure").+  , digest :: !(Maybe Text)+  -- ^ The digest (hash) of the model, if available.+  , total :: !(Maybe Int64)+  -- ^ The total size of the model in bytes, if available.   }   deriving (Show, Eq, Generic, FromJSON) --- | Push a model with options-pushOps ::+instance HasDone PushResp where+  getDone PushResp {..} = status /= "success"++{- | Pushes a model to the Ollama server with specified options.++Sends a POST request to the "/api//pull" endpoint to upload the specified model. Supports+streaming progress updates (if 'stream' is 'Just True') and insecure connections (if+'insecure' is 'Just True'). Prints "Pushing..." during streaming and "Completed" when+finished. Returns '()' on completion.+-}+push ::   -- | Model name   Text ->-  -- | Insecure+  -- | Optional insecure connection flag   Maybe Bool ->-  -- | Stream+  -- | Optional streaming flag   Maybe Bool ->+  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')+  Maybe OllamaConfig ->   IO ()-pushOps modelName mInsecure mStream = do-  let url = defaultOllamaUrl-  manager <- newManager defaultManagerSettings-  initialRequest <- parseRequest $ T.unpack (url <> "/api/push")-  let reqBody =-        PushOps-          { name = modelName-          , insecure = mInsecure-          , stream = mStream-          }-      request =-        initialRequest-          { method = "POST"-          , requestBody = RequestBodyLBS $ encode reqBody-          }-  withResponse request manager $ \response -> do-    let go = do-          bs <- brRead $ responseBody response-          let eRes = decode (BSL.fromStrict bs) :: Maybe PushResp-          case eRes of-            Nothing -> putStrLn "Something went wrong"-            Just res -> do-              if status res /= "success"-                then do-                  let total' = fromMaybe 0 (total res)-                  putStrLn $ "Remaining bytes: " <> show total'-                  go-                else do-                  putStrLn "Completed"-    go+push modelName mInsecure mStream mbConfig = do+  void $+    withOllamaRequest+      "/api//push"+      "POST"+      (Just $ PushOps {name = modelName, insecure = mInsecure, stream = mStream})+      mbConfig+      (commonStreamHandler onToken onComplete)+  where+    onToken :: PushResp -> IO ()+    onToken _ = putStrLn "Pushing... " --- Higher level API for Pull--- This API is untested. Will test soon!+    onComplete :: IO ()+    onComplete = putStrLn "Completed" --- | Push a model-push ::-  -- | Model name-  Text ->-  IO ()-push modelName = pushOps modelName Nothing Nothing+{- | MonadIO version of 'push' for use in monadic contexts.++Lifts the 'push' function into a 'MonadIO' context, allowing it to be used in monadic+computations.++Example:++>>> import Control.Monad.IO.Class+>>> runReaderT (pushM "gemma3" Nothing (Just True) Nothing) someContext+Pushing...+Completed+-}+pushM :: MonadIO m => Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> m ()+pushM t insec s mbCfg = liftIO $ push t insec s mbCfg
src/Data/Ollama/Show.hs view
@@ -3,108 +3,149 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE OverloadedStrings #-} +{- |+Module      : Data.Ollama.Show+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Description : Functionality for retrieving detailed information about models in the Ollama client.++This module provides functions to fetch detailed information about a specific model on the Ollama server.+It includes both high-level ('showModel', 'showModelM') and low-level ('showModelOps', 'showModelOpsM') APIs+for retrieving model details, with support for verbose output. The operation is performed via a POST request+to the "/api//show" endpoint, returning a 'ShowModelResponse' containing comprehensive model metadata.++The 'ShowModelOps' type configures the request, and 'ShowModelResponse' and 'ShowModelInfo' represent the+response structure. The module also re-exports 'CT.ModelDetails' for completeness.++Note: Verbose mode parsing is currently not fully supported.++Example:++>>> showModel "gemma3"+Right (ShowModelResponse {modelFile = "...", ...})++@since 1.0.0.0+-} module Data.Ollama.Show   ( -- * Show Model Info API     showModel+  , showModelM   , showModelOps+  , showModelOpsM++    -- * Response Types   , ShowModelResponse (..)+  , ShowModelInfo (..)+  , CT.ModelDetails (..)   ) where +import Control.Monad.IO.Class (MonadIO (liftIO)) import Data.Aeson-import Data.Ollama.Common.Utils qualified as CU+import Data.Ollama.Common.Config (OllamaConfig)+import Data.Ollama.Common.Error (OllamaError)+import Data.Ollama.Common.Types qualified as CT+import Data.Ollama.Common.Utils (commonNonStreamingHandler, withOllamaRequest) import Data.Text (Text)-import Data.Text qualified as T import GHC.Generics import GHC.Int (Int64)-import Network.HTTP.Client --- TODO: Add Options parameter--- TODO: Add Context parameter--{- |- #ShowModelOps#- Input parameters for show model information.--}+-- | Configuration options for requesting model information. data ShowModelOps = ShowModelOps-  { name :: Text-  , verbose :: Maybe Bool+  { name :: !Text+  -- ^ The name of the model to query (e.g., "gemma3").+  , verbose :: !(Maybe Bool)+  -- ^ Optional flag to request verbose output. Note: Verbose mode parsing is currently incomplete.   }   deriving (Show, Eq, Generic, ToJSON) -{- |- #ShowModelResponse#-- Ouput structure for show model information.--}+-- | Response structure for model information. data ShowModelResponse = ShowModelResponse-  { modelFile :: Text-  , parameters :: Text-  , template :: Text-  , details :: ModelDetails-  , modelInfo :: ModelInfo-  }-  deriving (Show, Eq)--data ModelDetails = ModelDetails-  { parentModel :: Text-  , format :: Text-  , familiy :: Text-  , families :: [Text]-  , parameterSize :: Text-  , quantizationLevel :: Text+  { modelFile :: !Text+  -- ^ The content of the model's Modelfile.+  , parameters :: !(Maybe Text)+  -- ^ Optional model parameters (e.g., temperature settings).+  , template :: !(Maybe Text)+  -- ^ Optional template used for the model.+  , details :: !CT.ModelDetails+  -- ^ General details about the model (e.g., format, family).+  , modelInfo :: !ShowModelInfo+  -- ^ Detailed technical information about the model.+  , license :: !(Maybe Text)+  -- ^ Optional license information for the model.+  --+  -- @since 0.2.0.0+  , capabilities :: Maybe [Text]+  -- ^ Optional list of model capabilities.+  --+  -- @since 0.2.0.0   }   deriving (Show, Eq) -data ModelInfo = ModelInfo-  { generalArchitecture :: Maybe Text-  , generalFileType :: Maybe Int-  , generalParameterCount :: Maybe Int64-  , generalQuantizationVersion :: Maybe Int-  , llamaAttentionHeadCount :: Maybe Int-  , llamaAttentionHeadCountKV :: Maybe Int-  , llamaAttentionLayerNormRMSEpsilon :: Maybe Float-  , llamaBlockCount :: Maybe Int-  , llamaContextLength :: Maybe Int-  , llamaEmbeddingLength :: Maybe Int-  , llamaFeedForwardLength :: Maybe Int-  , llamaRopeDimensionCount :: Maybe Int-  , llamaRopeFreqBase :: Maybe Int64-  , llamaVocabSize :: Maybe Int64-  , tokenizerGgmlBosToken_id :: Maybe Int-  , tokenizerGgmlEosToken_id :: Maybe Int-  , tokenizerGgmlMerges :: Maybe [Text]-  , tokenizerGgmlMode :: Maybe Text-  , tokenizerGgmlPre :: Maybe Text-  , tokenizerGgmlTokenType :: Maybe [Text]-  , tokenizerGgmlTokens :: Maybe [Text]+-- | Detailed technical information about a model.+data ShowModelInfo = ShowModelInfo+  { generalArchitecture :: !(Maybe Text)+  -- ^ The architecture of the model (e.g., "llama").+  , generalFileType :: !(Maybe Int)+  -- ^ The file type identifier for the model.+  , generalParameterCount :: !(Maybe Int64)+  -- ^ The number of parameters in the model.+  , generalQuantizationVersion :: !(Maybe Int)+  -- ^ The quantization version used by the model.+  , llamaAttentionHeadCount :: !(Maybe Int)+  -- ^ Number of attention heads in the LLaMA model.+  , llamaAttentionHeadCountKV :: !(Maybe Int)+  -- ^ Number of key-value attention heads in the LLaMA model.+  , llamaAttentionLayerNormRMSEpsilon :: !(Maybe Float)+  -- ^ RMS epsilon for layer normalization in the LLaMA model.+  , llamaBlockCount :: !(Maybe Int)+  -- ^ Number of blocks in the LLaMA model.+  , llamaContextLength :: !(Maybe Int)+  -- ^ Context length supported by the LLaMA model.+  , llamaEmbeddingLength :: !(Maybe Int)+  -- ^ Embedding length used by the LLaMA model.+  , llamaFeedForwardLength :: !(Maybe Int)+  -- ^ Feed-forward layer length in the LLaMA model.+  , llamaRopeDimensionCount :: !(Maybe Int)+  -- ^ RoPE dimension count in the LLaMA model.+  , llamaRopeFreqBase :: !(Maybe Int64)+  -- ^ Base frequency for RoPE in the LLaMA model.+  , llamaVocabSize :: !(Maybe Int64)+  -- ^ Vocabulary size of the LLaMA model.+  , tokenizerGgmlBosToken_id :: !(Maybe Int)+  -- ^ BOS (beginning of sequence) token ID for the GGML tokenizer.+  , tokenizerGgmlEosToken_id :: !(Maybe Int)+  -- ^ EOS (end of sequence) token ID for the GGML tokenizer.+  , tokenizerGgmlMerges :: !(Maybe [Text])+  -- ^ List of merges for the GGML tokenizer.+  , tokenizerGgmlMode :: !(Maybe Text)+  -- ^ Mode of the GGML tokenizer.+  , tokenizerGgmlPre :: !(Maybe Text)+  -- ^ Pre-tokenization configuration for the GGML tokenizer.+  , tokenizerGgmlTokenType :: !(Maybe [Text])+  -- ^ Token type information for the GGML tokenizer.+  , tokenizerGgmlTokens :: !(Maybe [Text])+  -- ^ List of tokens for the GGML tokenizer.   }   deriving (Show, Eq) --- FromJSON instances---- | The instance for show model response+-- | JSON parsing instance for 'ShowModelResponse'. instance FromJSON ShowModelResponse where   parseJSON = withObject "ShowModelResponse" $ \v ->     ShowModelResponse       <$> v .: "modelfile"-      <*> v .: "parameters"-      <*> v .: "template"+      <*> v .:? "parameters"+      <*> v .:? "template"       <*> v .: "details"       <*> v .: "model_info"--instance FromJSON ModelDetails where-  parseJSON = withObject "ModelDetails" $ \v ->-    ModelDetails-      <$> v .: "parent_model"-      <*> v .: "format"-      <*> v .: "family"-      <*> v .: "families"-      <*> v .: "parameter_size"-      <*> v .: "quantization_level"+      <*> v .:? "license"+      <*> v .:? "capabilities" -instance FromJSON ModelInfo where+-- | JSON parsing instance for 'ShowModelInfo'.+instance FromJSON ShowModelInfo where   parseJSON = withObject "ModelInfo" $ \v ->-    ModelInfo+    ShowModelInfo       <$> v .:? "general.architecture"       <*> v .:? "general.file_type"       <*> v .:? "general.parameter_count"@@ -127,49 +168,63 @@       <*> v .:? "tokenizer.ggml.token_type"       <*> v .:? "tokenizer.ggml.tokens" -{- | Show given model's information with options.+{- | Retrieves model information with configuration options. -@since 1.0.0.0+Sends a POST request to the "/api//show" endpoint to fetch detailed information about+the specified model. Supports verbose output if 'verbose' is 'Just True' (though verbose+mode parsing is currently incomplete). Returns 'Right' with a 'ShowModelResponse' on+success or 'Left' with an 'OllamaError' on failure. -} showModelOps ::-  -- | model name+  -- | Model name   Text ->-  -- | verbose+  -- | Optional verbose flag   Maybe Bool ->-  IO (Maybe ShowModelResponse)-showModelOps-  modelName-  verbose_ =-    do-      let url = CU.defaultOllamaUrl-      manager <- newManager defaultManagerSettings-      initialRequest <- parseRequest $ T.unpack (url <> "/api/show")-      let reqBody =-            ShowModelOps-              { name = modelName-              , verbose = verbose_-              }-          request =-            initialRequest-              { method = "POST"-              , requestBody = RequestBodyLBS $ encode reqBody-              }-      response <- httpLbs request manager-      let eRes =-            eitherDecode (responseBody response) ::-              Either String ShowModelResponse-      case eRes of-        Left _ -> pure Nothing-        Right r -> pure $ Just r+  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')+  Maybe OllamaConfig ->+  IO (Either OllamaError ShowModelResponse)+showModelOps modelName verbose_ mbConfig = do+  withOllamaRequest+    "/api//show"+    "POST"+    ( Just $+        ShowModelOps+          { name = modelName+          , verbose = verbose_+          }+    )+    mbConfig+    commonNonStreamingHandler -{- | Show given model's information.+{- | Simplified API for retrieving model information. -Higher level API for show.-@since 1.0.0.0+A higher-level function that fetches model information using default settings for+verbose output and Ollama configuration. Suitable for basic use cases. -} showModel ::-  -- | model name+  -- | Model name   Text ->-  IO (Maybe ShowModelResponse)+  IO (Either OllamaError ShowModelResponse) showModel modelName =-  showModelOps modelName Nothing+  showModelOps modelName Nothing Nothing++{- | MonadIO version of 'showModel' for use in monadic contexts.++Lifts the 'showModel' function into a 'MonadIO' context, allowing it to be used in+monadic computations.+-}+showModelM :: MonadIO m => Text -> m (Either OllamaError ShowModelResponse)+showModelM t = liftIO $ showModel t++{- | MonadIO version of 'showModelOps' for use in monadic contexts.++Lifts the 'showModelOps' function into a 'MonadIO' context, allowing it to be used in+monadic computations with full configuration options.+-}+showModelOpsM ::+  MonadIO m =>+  Text ->+  Maybe Bool ->+  Maybe OllamaConfig ->+  m (Either OllamaError ShowModelResponse)+showModelOpsM t v mbCfg = liftIO $ showModelOps t v mbCfg
src/Ollama.hs view
@@ -1,94 +1,194 @@ {-# LANGUAGE DuplicateRecordFields #-}+ {- |-  #Ollama-Haskell#-  This library lets you run LlMs from within Haskell projects. Inspired by `ollama-python`.+Module      : Data.Ollama+Copyright   : (c) 2025 Tushar Adhatrao+License     : MIT+Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>+Stability   : experimental+Portability : portable++== Ollama Haskell++This module provides a high-level Haskell interface to the [Ollama](https://ollama.com) API +    for interacting with local LLMs. It includes support for:++- Text generation (sync/streaming)+- Conversational chat (with tools and images)+- Embeddings+- Model management (pull, push, delete, list, show)+- Structured outputs+- Custom configuration and model options++Inspired by @ollama-python@, this library is built to offer idiomatic Haskell bindings +over Ollama’s HTTP API.++== 🔧 Usage++Import this module as a top-level interface:++@+import Ollama+@++All functions return @Either OllamaError a@ or can be used in a Monad stack using +their @\*M@ variants.++== 🔑 Main APIs++=== ✍️ Generate Text++- 'generate', 'generateM' – Generate text from a model+- 'defaultGenerateOps' – Default generation parameters+- 'GenerateOps', 'GenerateResponse' – Request and response types++=== 💬 Chat with LLMs++- 'chat', 'chatM' – Send chat messages to a model+- 'ChatOps', 'ChatResponse', 'Role', 'Message' – Chat input/output types+- Supports tools via 'InputTool', 'FunctionDef', 'OutputFunction', etc.++=== 🧠 Embeddings++- 'embedding', 'embeddingM' – Generate vector embeddings+- 'EmbeddingOps', 'EmbeddingResp' – Request/response types++=== 📦 Model Management++- 'copyModel', 'createModel', 'deleteModel'+- 'list' – List all installed models+- 'ps', 'psM' – Show running models+- 'showModel', 'showModelM' – Show model info+- 'pull', 'push' – Pull/push models (with progress support)++=== ⚙️ Configuration++- 'defaultOllamaConfig' – Modify host, retries, streaming, etc.+- 'withOnModelStart', 'withOnModelFinish', 'withOnModelError' – Hook support++=== 🧰 Utilities++- 'defaultModelOptions', 'encodeImage', 'withOllamaRequest'+- 'loadGenModel', 'unloadGenModel' – Load/unload generation models+- 'getVersion' – Ollama server version++== 🧾 Types++All request/response payloads and enums are exposed, including:++- 'ModelOptions', 'OllamaConfig', 'OllamaError', 'Format'+- 'Models', 'ModelInfo', 'ModelDetails', 'ShowModelResponse'+- 'RunningModels', 'RunningModel', 'Version' -} module Ollama   ( -- * Main APIs      -- ** Generate Texts     generate-  , generateJson+  , generateM   , defaultGenerateOps   , GenerateOps (..)   , GenerateResponse (..)      -- ** Chat with LLMs   , chat-  , chatJson+  , chatM   , Role (..)   , defaultChatOps   , ChatResponse (..)   , ChatOps (..)+  , InputTool (..)+  , FunctionDef (..)+  , FunctionParameters (..)+  , ToolCall (..)+  , OutputFunction (..)      -- ** Embeddings   , embedding   , embeddingOps+  , embeddingM+  , embeddingOpsM   , EmbeddingOps (..)   , EmbeddingResp (..) -    -- * Ollama operations-     -- ** Copy Models   , copyModel+  , copyModelM      -- ** Create Models   , createModel-  , createModelOps+  , createModelM      -- ** Delete Models   , deleteModel+  , deleteModelM      -- ** List Models   , list      -- ** List currently running models   , ps+  , psM      -- ** Push and Pull   , push-  , pushOps+  , pushM   , pull+  , pullM   , pullOps+  , pullOpsM      -- ** Show Model Info   , showModel   , showModelOps+  , showModelM+  , showModelOpsM +    -- * Ollama config+  , defaultOllamaConfig+  , withOnModelStart+  , withOnModelFinish+  , withOnModelError++    -- * Utils+  , defaultModelOptions+  , ModelOptions (..)+  , encodeImage+  , withOllamaRequest+  , getVersion+  , loadGenModel+  , unloadGenModel+  , loadGenModelM+  , unloadGenModelM+     -- * Types   , ShowModelResponse (..)   , Models (..)   , ModelInfo (..)+  , ModelDetails (..)+  , ShowModelInfo (..)   , RunningModels (..)   , RunningModel (..)   , Message (..)-  , Format(..)+  , Format (..)+  , OllamaError (..)+  , OllamaConfig (..)+  , Version (..)   ) where  import Data.Ollama.Chat-  ( ChatOps (..)-  , ChatResponse (..)-  , Message (..)-  , Role (..)-  , chat-  , chatJson-  , defaultChatOps-  )-import Data.Ollama.Copy (copyModel)-import Data.Ollama.Create (createModel, createModelOps)-import Data.Ollama.Delete (deleteModel)-import Data.Ollama.Embeddings (embedding, embeddingOps, EmbeddingOps (..), EmbeddingResp (..))+import Data.Ollama.Common.Config+import Data.Ollama.Common.Types+import Data.Ollama.Common.Utils+import Data.Ollama.Copy+import Data.Ollama.Create+import Data.Ollama.Delete+import Data.Ollama.Embeddings import Data.Ollama.Generate-  ( GenerateOps (..)-  , GenerateResponse (..)-  , defaultGenerateOps-  , generate-  , generateJson-  )-import Data.Ollama.List (ModelInfo (..), Models (..), list)-import Data.Ollama.Ps (RunningModel (..), RunningModels (..), ps)-import Data.Ollama.Pull (pull, pullOps)-import Data.Ollama.Push (push, pushOps)-import Data.Ollama.Show (ShowModelResponse (..), showModel, showModelOps)-import Data.Ollama.Common.Types (Format (..))+import Data.Ollama.List+import Data.Ollama.Load+import Data.Ollama.Ps+import Data.Ollama.Pull+import Data.Ollama.Push+import Data.Ollama.Show
test/Main.hs view
@@ -2,211 +2,29 @@  module Main (main) where -import Data.Either-import Data.List.NonEmpty hiding (length)-import Data.Maybe-import Data.Ollama.Chat qualified as Chat-import Data.Text.IO qualified as T-import Ollama (GenerateOps (..), Role (..), defaultChatOps, defaultGenerateOps)-import Ollama qualified-import System.IO.Silently (capture)+import Data.Text (unpack)+import Ollama (Version (..), getVersion)+import Test.Ollama.Chat qualified as Chat+import Test.Ollama.Embedding qualified as Embeddings+import Test.Ollama.Generate qualified as Generate+import Test.Ollama.Show qualified as Show import Test.Tasty-import Test.Tasty.HUnit-import qualified Data.Text as T -import Data.Aeson   tests :: TestTree tests =   testGroup     "Tests"-    [ generateTest-    , chatTest-    , psTest-    , showTest-    , embeddingTest-    , generateFormatTest-    , chatFormatTest-    ]--generateTest :: TestTree-generateTest =-  testGroup-    "Generate tests"-    [ testCase "generate stream" $ do-        output <--          capture $-            Ollama.generate-              defaultGenerateOps-                { modelName = "llama3.2"-                , prompt = "what is 4 + 2?"-                , stream = Just (T.putStr . Ollama.response_, pure ())-                }-        assertBool "Checking if generate function is printing anything" (length output > 0)-    , testCase "Generate non-stream" $ do-        eRes <--          Ollama.generate-            defaultGenerateOps-              { modelName = "llama3.2"-              , prompt = "what is 4 + 2?"-              }-        assertBool "Checking if generate function returns a valid value" (isRight eRes)-    , testCase "Generate with invalid host" $ do-        eRes <- Ollama.generate defaultGenerateOps {-            modelName = "llama3.2"-          , prompt = "what is 23 + 9?"-          , hostUrl = pure "http://some-site"-          , responseTimeOut = pure 2-        }-        print ("got response" :: String ,eRes)-        assertBool "Expecting Left" (isLeft eRes)-    , testCase "Generate with invalid model" $ do-        eRes <- Ollama.generate defaultGenerateOps {modelName = "invalid-model"}-        assertBool "Expecting generation to fail with invalid model" (isLeft eRes)-    ]--generateFormatTest :: TestTree-generateFormatTest =-  testGroup "Generate tests with format and options"-    [ testCase "Generate with SchemaFormat and options" $ do-        let schema = object-              [ "type" .= ("object" :: String)-              , "properties" .= object [ "age" .= object ["type" .= ("integer" :: String)] ]-              ]-        eRes <--          Ollama.generate-            defaultGenerateOps-              { modelName = "llama3.2"-              , prompt = "Ollama is 22 years old and is busy saving the world. Respond using JSON"-              , format = Just (Ollama.SchemaFormat schema)-              }-        case eRes of-          Right res ->-            assertBool "Response should contain JSON with key \"age\"" ( "age" `T.isInfixOf` Ollama.response_ res )-          Left err ->-            assertFailure $ "Generation failed with error: " ++ show err-    , testCase "Generate with JsonFormat and options" $ do-        eRes <--          Ollama.generate-            defaultGenerateOps-              { modelName = "llama3.2"-              , prompt = "Provide a simple JSON response describing Ollama."-              , format = Just Ollama.JsonFormat-              }-        case eRes of-          Right res ->-            assertBool "Response should start with '{'" ( "{" `T.isPrefixOf` Ollama.response_ res )-          Left err ->-            assertFailure $ "Generation failed with error: " ++ show err-    ]--chatTest :: TestTree-chatTest =-  testGroup-    "Chat tests"-    [ testCase "chat stream" $ do-        let msg = Ollama.Message User "What is 29 + 3?" Nothing Nothing-            defaultMsg = Ollama.Message User "" Nothing Nothing-        output <--          capture $-            Ollama.chat-              defaultChatOps-                { Chat.chatModelName = "llama3.2"-                , Chat.messages = msg :| []-                , Chat.stream = Just (T.putStr . Chat.content . fromMaybe defaultMsg . Chat.message, pure ())-                }-        assertBool "Checking if chat function is printing anything" (length output > 0)-    , testCase "Chat non-stream" $ do-        let msg = Ollama.Message User "What is 29 + 3?" Nothing Nothing-        eRes <--          Ollama.chat-            defaultChatOps-              { Chat.chatModelName = "llama3.2"-              , Chat.messages = msg :| []-              }-        assertBool "Checking if chat function returns a valid value" (isRight eRes)-    , testCase "Chat invalid host url" $ do-        let msg = Ollama.Message User "What is 29 + 3?" Nothing Nothing-        eRes <--          Ollama.chat-            defaultChatOps-              { Chat.chatModelName = "llama3.2"-              , Chat.messages = msg :| []-              , Chat.hostUrl = pure "some random value"-              , Chat.responseTimeOut = pure 2-              }-        assertBool "It should return Left" (isLeft eRes)-    ]--chatFormatTest :: TestTree-chatFormatTest =-  testGroup "Chat tests with format and options"-    [ testCase "Chat with SchemaFormat and options" $ do-        let schema = object-              [ "type" .= ("object" :: String)-              , "properties" .= object [ "age" .= object ["type" .= ("integer" :: String)] ]-              ]-            msg = Ollama.Message User "Ollama is 22 years old and is busy saving the world. Respond using JSON" Nothing Nothing-        eRes <--          Ollama.chat-            defaultChatOps-              { Chat.chatModelName = "llama3.2"-              , Chat.messages = msg :| []-              , Chat.format = Just (Ollama.SchemaFormat schema)-              , Chat.options = Just $ object ["penalize_newline" .= Bool True]-              }-        case eRes of-          Right res ->-            assertBool "Chat response should contain key \"age\"" $-              maybe False (\m -> "age" `T.isInfixOf` Chat.content m) (Chat.message res)-          Left err ->-            assertFailure $ "Chat failed with error: " ++ show err-    , testCase "Chat with JsonFormat and options" $ do-        let msg = Ollama.Message User "Tell me about Ollama in JSON format." Nothing Nothing-        eRes <--          Ollama.chat-            defaultChatOps-              { Chat.chatModelName = "llama3.2"-              , Chat.messages = msg :| []-              , Chat.format = Just Ollama.JsonFormat-              }-        case eRes of-          Right res ->-            assertBool "Chat response should start with '{'" $-              maybe False (\m -> "{" `T.isPrefixOf` Chat.content m) (Chat.message res)-          Left err ->-            assertFailure $ "Chat failed with error: " ++ show err-    ]--psTest :: TestTree-psTest =-  testGroup-    "PS test"-    [ testCase "check ps" $ do-        mRes <- Ollama.ps-        assertBool "Check if ps returns anything" (isJust mRes)-    ]--showTest :: TestTree-showTest =-  testGroup-    "Show test"-    [ testCase "check show" $ do-        mRes <- Ollama.showModel "llama3.2"-        assertBool "Check if model exists or not" (isJust mRes)-    ]--embeddingTest :: TestTree-embeddingTest =-  testGroup-    "Embedding test"-    [ testCase "check embedding" $ do-        eRes <- Ollama.embedding "llama3.2" "Why is sky blue?"-        assertBool "Check if embedding returns anything" (isRight eRes)+    [ Generate.tests+    , Chat.tests+    , Show.tests+    , Embeddings.tests     ]  main :: IO () main = do-  mRes <- Ollama.list-  case mRes of-    Nothing -> pure () -- Ollama is likely not running. Not running tests.-    Just _ -> defaultMain tests+  eRes <- getVersion+  case eRes of+    Left err -> putStrLn $ show err+    Right (Version r) -> do+      putStrLn $ "Ollama client version: " <> unpack r+      defaultMain tests
+ test/Test/Ollama/Chat.hs view
@@ -0,0 +1,278 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++module Test.Ollama.Chat (tests) where++import Control.Monad (void)+import Data.Aeson qualified as Aeson+import Data.ByteString.Lazy.Char8 qualified as BSL+import Data.IORef (modifyIORef, newIORef, readIORef, writeIORef)+import Data.List.NonEmpty (fromList)+import Data.List.NonEmpty qualified as NE+import Data.Map qualified as HM+import Data.Maybe (isJust)+import Data.Ollama.Chat+import Data.Scientific+import Data.Text qualified as T+import Data.Time (diffUTCTime, getCurrentTime)+import Network.HTTP.Client+import Network.HTTP.Client.TLS+import Test.Tasty+import Test.Tasty.HUnit++-- | Basic chat test with default options+basicChatTest :: TestTree+basicChatTest = testCase "Basic chat should contain 4 for 2+2" $ do+  let ops = defaultChatOps+  eRes <- chat ops Nothing+  case eRes of+    Left err -> assertFailure $ "Expected success, got error: " ++ show err+    Right r -> case message r of+      Nothing -> assertFailure "Expected a message in response"+      Just msg -> assertBool "Should contain '4'" (T.isInfixOf "4" (content msg))++-- | Test timeout configuration+timeoutTest :: TestTree+timeoutTest = testCase "Setting timeout" $ do+  let config = Just $ defaultOllamaConfig {timeout = 1}+  eRes <- chat defaultChatOps config+  case eRes of+    Left (TimeoutError _) -> pure ()+    _ -> assertFailure "Expected timeout error"++-- | Test model lifecycle hooks on failure+hooksFailTest :: TestTree+hooksFailTest = testCase "Model lifecycle hooks should trigger on failure" $ do+  refStart <- newIORef False+  refError <- newIORef False+  refFinish <- newIORef True+  let config =+        defaultOllamaConfig+          { hostUrl = "http://localhost:12345" -- Guaranteed to fail+          , onModelStart = Just $ writeIORef refStart True+          , onModelError = Just $ writeIORef refError True+          , onModelFinish = Just $ writeIORef refFinish False+          }+  void $ chat defaultChatOps (Just config)+  wasStarted <- readIORef refStart+  wasErrored <- readIORef refError+  wasFinished <- readIORef refFinish+  assertBool "onModelStart should be called" wasStarted+  assertBool "onModelError should be called" wasErrored+  assertBool "onModelFinish should be called" wasFinished++-- | Test model lifecycle hooks on success+hooksSuccessTest :: TestTree+hooksSuccessTest = testCase "Model lifecycle hooks should trigger on success" $ do+  refStart <- newIORef False+  refError <- newIORef True+  refFinish <- newIORef False+  let config =+        defaultOllamaConfig+          { onModelStart = Just $ writeIORef refStart True+          , onModelError = Just $ writeIORef refError False+          , onModelFinish = Just $ writeIORef refFinish True+          }+  void $ chat defaultChatOps (Just config)+  wasStarted <- readIORef refStart+  wasErrored <- readIORef refError+  wasFinished <- readIORef refFinish+  assertBool "onModelStart should be called" wasStarted+  assertBool "onModelError should not be called" wasErrored+  assertBool "onModelFinish should be called" wasFinished++-- | Test retry count+retryCountTest :: TestTree+retryCountTest = testCase "Should retry chat call retryCount times" $ do+  counter <- newIORef (0 :: Int)+  let config =+        defaultOllamaConfig+          { hostUrl = "http://localhost:12345" -- Fails+          , retryCount = Just 2+          , retryDelay = Just 1+          , onModelStart = Just $ modifyIORef counter (+ 1)+          , onModelError = Just $ pure ()+          , onModelFinish = Just $ pure ()+          }+  _ <- chat defaultChatOps (Just config)+  calls <- readIORef counter+  assertEqual "Expected 3 attempts (1 initial + 2 retries)" 3 calls++-- | Test retry delay+retryDelayTest :: TestTree+retryDelayTest = testCase "Should delay between retries" $ do+  counter <- newIORef (0 :: Int)+  let delaySecs = 2+  start <- getCurrentTime+  let config =+        defaultOllamaConfig+          { hostUrl = "http://localhost:12345" -- Fails+          , retryCount = Just 1+          , retryDelay = Just delaySecs+          , onModelStart = Just $ modifyIORef counter (+ 1)+          , onModelError = Just $ pure ()+          , onModelFinish = Just $ pure ()+          }+  _ <- chat defaultChatOps (Just config)+  end <- getCurrentTime+  let elapsed = realToFrac (diffUTCTime end start) :: Double+      expectedMin = fromIntegral delaySecs+  assertBool+    ("Elapsed time should be at least " ++ show expectedMin ++ "s, but was " ++ show elapsed)+    (elapsed >= expectedMin)++-- | Test common manager usage+commonManagerTest :: TestTree+commonManagerTest = testCase "Should reuse provided commonManager" $ do+  refStart <- newIORef (0 :: Int)+  mgr <-+    newTlsManagerWith+      tlsManagerSettings {managerResponseTimeout = responseTimeoutMicro 1000000}+  let config =+        defaultOllamaConfig+          { hostUrl = "http://localhost:12345" -- Will fail fast+          , commonManager = Just mgr+          , timeout = 999 -- Shouldn’t matter, manager timeout takes precedence+          , onModelStart = Just $ modifyIORef refStart (+ 1)+          , onModelError = Just $ pure ()+          , onModelFinish = Just $ pure ()+          }+  _ <- chat defaultChatOps (Just config)+  _ <- chat defaultChatOps (Just config)+  startCount <- readIORef refStart+  assertEqual "Both requests should start (reuse manager)" 2 startCount++-- | Test JSON format response+jsonFormatTest :: TestTree+jsonFormatTest = testCase "Should return response in JSON format" $ do+  let ops =+        defaultChatOps+          { messages =+              fromList+                [userMessage "Return a JSON with keys 'name' and 'age' for John, 25 years old."]+          , format = Just JsonFormat+          }+  eRes <- chat ops Nothing+  case eRes of+    Left err -> assertFailure $ "Expected success, got error: " ++ show err+    Right r -> case message r of+      Nothing -> assertFailure "Expected a message in response"+      Just msg -> do+        let responseText = content msg+        let decoded = Aeson.decode (BSL.pack $ T.unpack responseText) :: Maybe Aeson.Value+        assertBool "Expected valid JSON object in response" (decoded /= Nothing)++-- | Test streaming response+streamingTest :: TestTree+streamingTest = testCase "Should handle streaming response" $ do+  chunksRef <- newIORef []+  let streamHandler chunk = modifyIORef chunksRef (++ [message chunk])+      flushHandler = pure ()+      ops = defaultChatOps {stream = Just (streamHandler, flushHandler)}+  eRes <- chat ops Nothing+  chunks <- readIORef chunksRef+  let fullOutput = T.concat (map (maybe "" content) chunks)+  case eRes of+    Left err -> assertFailure $ "Expected streaming success, got error: " ++ show err+    Right _ -> assertBool "Expected some streamed content" (not $ T.null fullOutput)++-- | Test custom model options+modelOptionsTest :: TestTree+modelOptionsTest = testCase "Should use custom model options" $ do+  let opts =+        Just $+          defaultModelOptions+            { temperature = Just 0.9+            , topP = Just 0.8+            , topK = Nothing+            , numPredict = Just 20+            }+      ops = defaultChatOps {options = opts}+  eRes <- chat ops Nothing+  case eRes of+    Left err -> assertFailure $ "Expected success, got error: " ++ show err+    Right r -> assertBool "Expected a response message" (isJust (message r))++testToolCall_addTwoNumbers :: TestTree+testToolCall_addTwoNumbers = testCase "Tool call: addTwoNumbers(23, 46)" $ do+  let messageList = NE.singleton $ userMessage "What is 23 + 46? (Use tool)"+      paramProps =+        HM.fromList+          [ ("a", FunctionParameters "number" Nothing Nothing Nothing)+          , ("b", FunctionParameters "number" Nothing Nothing Nothing)+          ]+      functionParams =+        FunctionParameters+          { parameterType = "object"+          , requiredParams = Just ["a", "b"]+          , parameterProperties = Just paramProps+          , additionalProperties = Just False+          }+      functionDef =+        FunctionDef+          { functionName = "addTwoNumbers"+          , functionDescription = Just "Add two numbers"+          , functionParameters = Just functionParams+          , functionStrict = Nothing+          }+      tool =+        InputTool+          { toolType = "function"+          , function = functionDef+          }+      ops =+        defaultChatOps+          { chatModelName = "qwen3:0.6b"+          , messages = messageList+          , tools = Just [tool]+          }++  res <- chat ops Nothing+  case res of+    Left err -> assertFailure $ "Chat failed: " ++ show err+    Right ChatResponse {message = Nothing} -> assertFailure "No message in response"+    Right ChatResponse {message = Just msg} ->+      case tool_calls msg of+        Nothing -> assertFailure "No tool calls received"+        Just [toolCall] -> do+          result <- captureAddToolCall toolCall+          assertEqual "Expected result of 23 + 46" 69 result+        Just other -> assertFailure $ "Unexpected number of tool calls: " ++ show other++-- Helper to evaluate the tool call+captureAddToolCall :: ToolCall -> IO Int+captureAddToolCall (ToolCall func)+  | outputFunctionName func == "addTwoNumbers" =+      case ( HM.lookup "a" (arguments func) >>= convertToNumber+           , HM.lookup "b" (arguments func) >>= convertToNumber+           ) of+        (Just a, Just b) -> return $ addTwoNumbers a b+        _ -> assertFailure "Missing parameters a or b" >> return 0+  | otherwise = assertFailure "Unexpected function name" >> return 0++addTwoNumbers :: Int -> Int -> Int+addTwoNumbers = (+)++-- Convert Aeson value to Int+convertToNumber :: Aeson.Value -> Maybe Int+convertToNumber (Aeson.Number n) = toBoundedInteger n+convertToNumber _ = Nothing++-- | Group all tests+tests :: TestTree+tests =+  sequentialTestGroup+    "Chat tests"+    AllFinish+    [ basicChatTest+    , timeoutTest+    , hooksFailTest+    , hooksSuccessTest+    , retryCountTest+    , retryDelayTest+    , commonManagerTest+    , jsonFormatTest+    , streamingTest+    , modelOptionsTest+    , testToolCall_addTwoNumbers+    ]
+ test/Test/Ollama/Embedding.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Test.Ollama.Embedding (tests) where++import Data.Maybe (listToMaybe)+import Data.Ollama.Embeddings+import Test.Tasty+import Test.Tasty.HUnit++testEmbeddingBasic :: TestTree+testEmbeddingBasic = testCase "Basic embedding with qwen3" $ do+  res <- embedding "qwen3:0.6b" ["The sky is blue.", "Cats are independent."]+  case res of+    Left err -> assertFailure $ "Expected success, got error: " ++ show err+    Right EmbeddingResp {..} -> do+      assertEqual "Should return two embeddings" 2 (length respondedEmbeddings)+      assertBool "Embeddings should not be empty" (all (not . null) respondedEmbeddings)++testEmbeddingWithOptions :: TestTree+testEmbeddingWithOptions = testCase "Embedding with truncate and keepAlive" $ do+  let opts = defaultModelOptions {numKeep = Just 5, seed = Just 42}+  res <- embeddingOps "qwen3:0.6b" ["Hello world"] (Just True) (Just 30) (Just opts) Nothing+  case res of+    Left err -> assertFailure $ "Unexpected error: " ++ show err+    Right EmbeddingResp {..} -> do+      assertEqual "Should return one embedding" 1 (length respondedEmbeddings)+      assertBool+        "Embedding vector should not be empty"+        (not . null $ listToMaybe respondedEmbeddings)++testEmbeddingInvalidModel :: TestTree+testEmbeddingInvalidModel = testCase "Embedding with invalid model name" $ do+  res <- embedding "nonexistent-model" ["This should fail."]+  case res of+    Left _ -> return () -- Expected failure+    Right _ -> assertFailure "Expected failure with invalid model name"++tests :: TestTree+tests =+  testGroup+    "Embeddings tests"+    [ testEmbeddingBasic+    , testEmbeddingWithOptions+    , testEmbeddingInvalidModel+    ]
+ test/Test/Ollama/Generate.hs view
@@ -0,0 +1,319 @@+{-# LANGUAGE OverloadedStrings #-}++{-+  Tests related to Generate module+-}+module Test.Ollama.Generate (tests) where++import Control.Monad (void)+import Data.Aeson qualified as Aeson+import Data.ByteString.Lazy.Char8 qualified as BSL+import Data.IORef (modifyIORef, newIORef, readIORef, writeIORef)+import Data.Ollama.Common.SchemaBuilder+import Data.Ollama.Common.Utils (encodeImage)+import Data.Ollama.Generate+import Data.Text qualified as T+import Data.Time (diffUTCTime, getCurrentTime)+import Network.HTTP.Client+import Network.HTTP.Client.TLS+import Test.Tasty+import Test.Tasty.HUnit++generateTests :: TestTree+generateTests =+  testGroup+    "Generation with various options"+    [ testCase "Should contain 4 in 2+2" $ do+        eRes <-+          generate+            defaultGenerateOps {modelName = "gemma3", prompt = "What is 2+2?"}+            Nothing+        case eRes of+          Left err -> assertFailure $ "Expected success, got error: " ++ show err+          Right r -> assertBool "Should contain 4" (T.isInfixOf "4" (genResponse r))+    , testCase "Setting timeout" $ do+        eRes <-+          generate+            defaultGenerateOps {modelName = "gemma3", prompt = "Write a poem about French revolution"}+            (Just $ defaultOllamaConfig {timeout = 1})+        case eRes of+          Left (TimeoutError _) -> pure ()+          _ -> assertFailure "Expected timeout error"+    ]++testOnModelHooksFail :: TestTree+testOnModelHooksFail = testCase "Model lifecycle hooks should be triggered" $ do+  refStart <- newIORef False+  refError <- newIORef False+  refFinish <- newIORef True+  let config =+        defaultOllamaConfig+          { hostUrl = "http://localhost:12345" -- guaranteed to fail+          , onModelStart = Just $ writeIORef refStart True+          , onModelError = Just $ writeIORef refError True+          , onModelFinish = Just $ writeIORef refFinish True+          }++  void $+    generate+      defaultGenerateOps {modelName = "gemma3", prompt = "what is 23+41?"}+      (Just config)++  wasStarted <- readIORef refStart+  wasErrored <- readIORef refError+  wasFinished <- readIORef refFinish++  assertBool "onModelStart should be called" wasStarted+  assertBool "onModelError should be called" wasErrored+  assertBool "onModelFinish should be called" wasFinished++testOnModelHooksSucc :: TestTree+testOnModelHooksSucc = testCase "Model lifecycle hooks should be triggered 2" $ do+  refStart <- newIORef False+  refError <- newIORef True+  refFinish <- newIORef False+  let config =+        defaultOllamaConfig+          { onModelStart = Just $ writeIORef refStart True+          , onModelError = Just $ writeIORef refError False+          , onModelFinish = Just $ writeIORef refFinish True+          }++  void $+    generate+      defaultGenerateOps {modelName = "gemma3", prompt = "what is 23+41?"}+      (Just config)++  wasStarted <- readIORef refStart+  wasErrored <- readIORef refError+  wasFinished <- readIORef refFinish++  assertBool "onModelStart should be called" wasStarted+  assertBool "onModelError should be called" wasErrored+  assertBool "onModelFinish should be called" wasFinished++testRetryCount :: TestTree+testRetryCount = testCase "Should retry generate call retryCount times" $ do+  counter <- newIORef (0 :: Int)+  let config =+        defaultOllamaConfig+          { hostUrl = "http://localhost:12345" -- fails+          , retryCount = Just 2+          , retryDelay = Just 1+          , onModelStart = Just $ modifyIORef counter (+ 1)+          , onModelError = Just $ pure ()+          , onModelFinish = Just $ pure ()+          }++  _ <- generate defaultGenerateOps {prompt = "Retry test"} (Just config)+  calls <- readIORef counter+  -- Should be retryCount + 1 (initial + retries)+  assertEqual "Expected 3 attempts (1 initial + 2 retries)" 3 calls++testRetryDelay :: TestTree+testRetryDelay = testCase "Should delay between retries" $ do+  counter <- newIORef (0 :: Int)+  let delaySecs = 2+  start <- getCurrentTime++  let config =+        defaultOllamaConfig+          { hostUrl = "http://localhost:12345" -- fails+          , retryCount = Just 1+          , retryDelay = Just delaySecs+          , onModelStart = Just $ modifyIORef counter (+ 1)+          , onModelError = Just $ pure ()+          , onModelFinish = Just $ pure ()+          }++  _ <- generate defaultGenerateOps {prompt = "Retry delay test"} (Just config)+  end <- getCurrentTime+  let elapsed = realToFrac (diffUTCTime end start) :: Double+  let expectedMin = fromIntegral delaySecs++  assertBool+    ("Elapsed time should be at least " ++ show expectedMin ++ "s, but was " ++ show elapsed)+    (elapsed >= expectedMin)++testCommonManagerUsage :: TestTree+testCommonManagerUsage = testCase "Should reuse provided commonManager" $ do+  refStart <- newIORef (0 :: Int)+  mgr <-+    newTlsManagerWith tlsManagerSettings {managerResponseTimeout = responseTimeoutMicro 1000000}+  let config =+        defaultOllamaConfig+          { hostUrl = "http://localhost:12345" -- will fail fast+          , commonManager = Just mgr+          , timeout = 999 -- shouldn't matter, manager timeout will be used+          , onModelStart = Just $ modifyIORef refStart (+ 1)+          , onModelError = Just $ pure ()+          , onModelFinish = Just $ pure ()+          }++  _ <- generate defaultGenerateOps {prompt = "1"} (Just config)+  _ <- generate defaultGenerateOps {prompt = "2"} (Just config)+  startCount <- readIORef refStart+  assertEqual "Both requests should start (reuse manager)" 2 startCount++{-+ Suffix is not supported for few gemma3 and qwen3.++testSuffixOption :: TestTree+testSuffixOption = testCase "Should respect suffix in generation" $ do+  let ops = defaultGenerateOps+              { modelName = "qwen3:0.6b"+              , prompt = "Complete this sentence: The Eiffel Tower is in"+              , suffix = Just " [End]"+              }+  eRes <- generate ops Nothing+  case eRes of+    Left err -> assertFailure $ "Expected success, got error: " ++ show err+    Right r -> assertBool "Expected suffix in response" $+                  T.isSuffixOf "[End]" (genResponse r)+                  -}++testThinkOption :: TestTree+testThinkOption = testCase "Should activate thinking mode when think=True" $ do+  let ops =+        defaultGenerateOps+          { modelName = "qwen3:0.6b"+          , prompt = "What is 2+2?"+          , think = Just True+          }+  eRes <- generate ops Nothing+  case eRes of+    Left err -> assertFailure $ "Expected success, got error: " ++ show err+    Right _ -> pure () -- TODO: Need to find a way to know if model is thinking++testFormatJsonFormat :: TestTree+testFormatJsonFormat = testCase "Should return response in JsonFormat" $ do+  let ops =+        defaultGenerateOps+          { modelName = "gemma3"+          , prompt =+              "John was 23 year old in 2023, this is year 2025."+                <> "How old is John assuming he celebrated this year's birthday; "+                <> "Return an object with keys 'name' and 'age'."+          , format = Just JsonFormat+          }+  eRes <- generate ops Nothing+  case eRes of+    Left err -> assertFailure $ "Expected success, got error: " ++ show err+    Right r -> do+      let responseText = genResponse r+      let decoded = Aeson.decode (BSL.pack $ T.unpack responseText) :: Maybe Aeson.Value+      assertBool "Expected valid JSON object in response" (decoded /= Nothing)++testFormatSchemaFormat :: TestTree+testFormatSchemaFormat = testCase "Should include SchemaFormat in the request" $ do+  let schema =+        buildSchema $+          emptyObject+            |+ ("fruit", JString)+            |+ ("quantity", JNumber)+            |! "fruit"+            |! "quantity"++      ops =+        defaultGenerateOps+          { modelName = "gemma3"+          , prompt = "I had 3 apples, 1 gave one away. How many left?"+          , format = Just (SchemaFormat schema)+          }++  eRes <- generate ops Nothing+  case eRes of+    Left err -> assertFailure $ "Expected success, got error: " ++ show err+    Right r -> do+      let response = T.toLower (genResponse r)+      assertBool "Expected fruit information in response" $+        "apple" `T.isInfixOf` response || "fruit" `T.isInfixOf` response++testImageInput :: TestTree+testImageInput = testCase "Should accept and process base64 image input" $ do+  maybeImg <- encodeImage "./examples/sample.png"+  case maybeImg of+    Nothing -> assertFailure "Image encoding failed (unsupported format or missing file)"+    Just imgData -> do+      let ops =+            defaultGenerateOps+              { modelName = "gemma3"+              , prompt = "Describe this image."+              , images = Just [imgData]+              }+          cfg = Just defaultOllamaConfig {timeout = 300}++      eRes <- generate ops cfg+      case eRes of+        Left err -> assertFailure $ "Expected success, got error: " ++ show err+        Right r -> do+          let response = T.toLower (genResponse r)+          assertBool "Expected image-related description in response" $+            T.isInfixOf "i love haskell" response++testStreamingHandler :: TestTree+testStreamingHandler = testCase "Should handle streaming response" $ do+  -- IORef to collect streamed chunks+  chunksRef <- newIORef []+  -- Define the stream handler: accumulate responses+  let streamHandler chunk = modifyIORef chunksRef (++ [genResponse chunk])+      flushHandler = pure ()+      ops =+        defaultGenerateOps+          { modelName = "gemma3"+          , prompt = "Write few words about Haskell."+          , stream = Just (streamHandler, flushHandler)+          }+  eRes <- generate ops Nothing+  -- Collect streamed chunks from IORef+  chunks <- readIORef chunksRef+  let fullOutput = T.concat chunks+  case eRes of+    Left err -> assertFailure $ "Expected streaming success, got error: " ++ show err+    Right _ -> do+      assertBool "Expected streamed text to include 'haskell'" $+        "haskell" `T.isInfixOf` T.toLower fullOutput+      assertBool "Expected some streamed content" $ not (T.null fullOutput)++testModelOptionsBasic :: TestTree+testModelOptionsBasic = testCase "ModelOptions: temperature and topP" $ do+  let opts =+        Just $+          defaultModelOptions+            { temperature = Just 0.9+            , topP = Just 0.8+            , topK = Nothing+            , numPredict = Just 20+            }++  eRes <-+    generate+      defaultGenerateOps+        { modelName = "gemma3"+        , prompt = "Generate a random list of 3 animals"+        , options = opts+        }+      Nothing++  case eRes of+    Left err -> assertFailure $ "Expected success, got: " ++ show err+    Right r -> assertBool "Response should not be empty" (not . T.null $ genResponse r)++tests :: TestTree+tests =+  sequentialTestGroup+    "Generate tests"+    AllFinish+    [ generateTests+    , testOnModelHooksFail+    , testOnModelHooksSucc+    , testRetryCount+    , testRetryDelay+    , testCommonManagerUsage+    , testThinkOption+    , testFormatJsonFormat+    , testFormatSchemaFormat+    , testImageInput+    , testStreamingHandler+    , testModelOptionsBasic+    ]
+ test/Test/Ollama/Show.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}++module Test.Ollama.Show (tests) where++import Test.Tasty+import Test.Tasty.HUnit+import Data.Ollama.Show+import Data.Ollama.Ps+import Data.Text qualified as T+import Data.Maybe (isJust)++testShowModelBasic :: TestTree+testShowModelBasic = testCase "Show model info: basic call" $ do+  res <- showModel "gemma3"+  case res of+    Left err -> assertFailure $ "Expected success, got error: " ++ show err+    Right ShowModelResponse {modelFile, modelInfo = ShowModelInfo {generalArchitecture}} -> do+      assertBool "modelFile should not be empty" (not $ T.null modelFile)+      assertBool "Architecture should be present" (isJust generalArchitecture)++testShowModelVerbose :: TestTree+testShowModelVerbose = testCase "Show model info: verbose enabled" $ do+  res <- showModelOps "qwen3:0.6b" (Just True) Nothing+  case res of+    Left _ -> pure () --assertFailure $ "Expected success, got error: " ++ show err+    Right ShowModelResponse {template, parameters} -> do+      -- Verbose should yield more details like parameters/template+      assertBool "Should have a template if verbose" (isJust template)+      assertBool "Should have parameters if verbose" (isJust parameters)++testPsBasic :: TestTree+testPsBasic = testCase "List running models: basic success" $ do+  res <- ps Nothing+  case res of+    Left err -> assertFailure $ "Expected success, got error: " ++ show err+    Right (RunningModels _) -> do+      assertBool "Should return a list (possibly empty)" True++testPsModelFields :: TestTree+testPsModelFields = testCase "Running model fields are populated" $ do+  res <- ps Nothing+  case res of+    Left _ -> return () -- Allow failure if no models are running+    Right (RunningModels (m:_)) -> do+      assertBool "name_ should not be empty" (not $ T.null $ name_ m)+      assertBool "modelName should not be empty" (not $ T.null $ modelName m)+      assertBool "modelDigest should not be empty" (not $ T.null $ modelDigest m)+      assertBool "size_ should be positive" (size_ m > 0)+      assertBool "sizeVRam should be non-negative" (sizeVRam m >= 0)+    Right _ -> return () -- If empty, that's acceptable++tests :: TestTree+tests = testGroup "show model tests" [+    testShowModelBasic +  , testShowModelVerbose+  , testPsBasic+  , testPsModelFields+ ]