packages feed

ollama-haskell 0.2.1.0 → 0.3.0.0

raw patch · 81 files changed

+4664/−4997 lines, 81 filesdep +QuickCheckdep +case-insensitivedep +conduitdep −base64-bytestringdep −directorydep −filepathdep ~aesondep ~basedep ~bytestringnew-component:exe:ollama-example-all-featuresnew-component:exe:ollama-example-basic-chatnew-component:exe:ollama-example-embeddingsnew-component:exe:ollama-example-model-managementnew-component:exe:ollama-example-streaming-chatnew-component:exe:ollama-example-structured-outputnew-component:exe:ollama-example-tool-callingPVP ok

version bump matches the API change (PVP)

Dependencies added: QuickCheck, case-insensitive, conduit, conduit-extra, hashable, resourcet, retry, tasty-bench, tasty-golden, tasty-quickcheck, unliftio-core

Dependencies removed: base64-bytestring, directory, filepath, scientific, silently

Dependency ranges changed: aeson, base, bytestring, containers, mtl, stm, tasty, text, time

API changes (from Hackage documentation)

- Data.Ollama.Blob: checkBlobExists :: Text -> Maybe OllamaConfig -> IO (Either OllamaError Bool)
- Data.Ollama.Blob: createBlob :: FilePath -> Text -> Maybe OllamaConfig -> IO (Either OllamaError ())
- Data.Ollama.Chat: ApiError :: Text -> OllamaError
- Data.Ollama.Chat: Assistant :: Role
- 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 -> !Maybe Text -> ChatResponse
- 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: JsonFormat :: Format
- Data.Ollama.Chat: JsonSchemaError :: String -> OllamaError
- Data.Ollama.Chat: Message :: !Role -> !Text -> !Maybe [Text] -> !Maybe [ToolCall] -> !Maybe Text -> Message
- 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: SchemaFormat :: Schema -> Format
- Data.Ollama.Chat: System :: Role
- Data.Ollama.Chat: TimeoutError :: String -> OllamaError
- Data.Ollama.Chat: Tool :: Role
- Data.Ollama.Chat: ToolCall :: OutputFunction -> ToolCall
- Data.Ollama.Chat: User :: Role
- 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: [content] :: Message -> !Text
- Data.Ollama.Chat: [createdAt] :: ChatResponse -> !UTCTime
- Data.Ollama.Chat: [doneReason] :: ChatResponse -> !Maybe Text
- Data.Ollama.Chat: [done] :: ChatResponse -> !Bool
- Data.Ollama.Chat: [evalCount] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: [evalDuration] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: [format] :: ChatOps -> !Maybe Format
- 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: [hostUrl] :: OllamaConfig -> Text
- Data.Ollama.Chat: [images] :: Message -> !Maybe [Text]
- Data.Ollama.Chat: [keepAlive] :: ChatOps -> !Maybe Int
- Data.Ollama.Chat: [loadDuration] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: [mainGpu] :: ModelOptions -> Maybe Int
- Data.Ollama.Chat: [message] :: ChatResponse -> !Maybe Message
- Data.Ollama.Chat: [messages] :: ChatOps -> !NonEmpty Message
- Data.Ollama.Chat: [minP] :: ModelOptions -> Maybe Double
- Data.Ollama.Chat: [modelName] :: ChatOps -> !Text
- Data.Ollama.Chat: [model] :: ChatResponse -> !Text
- 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: [options] :: ChatOps -> !Maybe ModelOptions
- 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: [promptEvalCount] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: [promptEvalDuration] :: ChatResponse -> !Maybe Int64
- 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: [role] :: Message -> !Role
- Data.Ollama.Chat: [seed] :: ModelOptions -> Maybe Int
- Data.Ollama.Chat: [stop] :: ModelOptions -> Maybe [Text]
- Data.Ollama.Chat: [stream] :: ChatOps -> !Maybe (ChatResponse -> IO (), IO ())
- 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: [tool_calls] :: Message -> !Maybe [ToolCall]
- Data.Ollama.Chat: [tools] :: ChatOps -> !Maybe [InputTool]
- Data.Ollama.Chat: [topK] :: ModelOptions -> Maybe Int
- Data.Ollama.Chat: [topP] :: ModelOptions -> Maybe Double
- Data.Ollama.Chat: [totalDuration] :: ChatResponse -> !Maybe Int64
- Data.Ollama.Chat: [typicalP] :: ModelOptions -> Maybe Double
- Data.Ollama.Chat: [useMmap] :: ModelOptions -> Maybe Bool
- Data.Ollama.Chat: assistantMessage :: Text -> Message
- Data.Ollama.Chat: chat :: ChatOps -> Maybe OllamaConfig -> IO (Either OllamaError ChatResponse)
- Data.Ollama.Chat: chatM :: MonadIO m => ChatOps -> Maybe OllamaConfig -> m (Either OllamaError ChatResponse)
- Data.Ollama.Chat: data ChatOps
- Data.Ollama.Chat: data ChatResponse
- Data.Ollama.Chat: data Format
- Data.Ollama.Chat: data FunctionDef
- Data.Ollama.Chat: data FunctionParameters
- Data.Ollama.Chat: data InputTool
- Data.Ollama.Chat: data Message
- Data.Ollama.Chat: data ModelOptions
- Data.Ollama.Chat: data OllamaConfig
- Data.Ollama.Chat: data OllamaError
- Data.Ollama.Chat: data OutputFunction
- Data.Ollama.Chat: data Role
- Data.Ollama.Chat: defaultChatOps :: ChatOps
- Data.Ollama.Chat: defaultModelOptions :: ModelOptions
- Data.Ollama.Chat: defaultOllamaConfig :: OllamaConfig
- Data.Ollama.Chat: genMessage :: Role -> Text -> Message
- Data.Ollama.Chat: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Chat.ChatOps
- Data.Ollama.Chat: instance GHC.Classes.Eq Data.Ollama.Chat.ChatOps
- Data.Ollama.Chat: instance GHC.Internal.Show.Show Data.Ollama.Chat.ChatOps
- 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.Internal.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.Internal.Exception.Type.Exception Data.Ollama.Common.Error.OllamaError
- Data.Ollama.Common.Error: instance GHC.Internal.Generics.Generic Data.Ollama.Common.Error.OllamaError
- Data.Ollama.Common.Error: instance GHC.Internal.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.Internal.Generics.Generic Data.Ollama.Common.SchemaBuilder.JsonType
- Data.Ollama.Common.SchemaBuilder: instance GHC.Internal.Generics.Generic Data.Ollama.Common.SchemaBuilder.Property
- Data.Ollama.Common.SchemaBuilder: instance GHC.Internal.Generics.Generic Data.Ollama.Common.SchemaBuilder.Schema
- Data.Ollama.Common.SchemaBuilder: instance GHC.Internal.Show.Show Data.Ollama.Common.SchemaBuilder.JsonType
- Data.Ollama.Common.SchemaBuilder: instance GHC.Internal.Show.Show Data.Ollama.Common.SchemaBuilder.Property
- Data.Ollama.Common.SchemaBuilder: instance GHC.Internal.Show.Show Data.Ollama.Common.SchemaBuilder.Schema
- Data.Ollama.Common.SchemaBuilder: instance GHC.Internal.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 -> !Maybe Text -> 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 -> !Maybe Text -> GenerateResponse
- Data.Ollama.Common.Types: InputTool :: Text -> FunctionDef -> InputTool
- Data.Ollama.Common.Types: JsonFormat :: Format
- Data.Ollama.Common.Types: Message :: !Role -> !Text -> !Maybe [Text] -> !Maybe [ToolCall] -> !Maybe Text -> Message
- Data.Ollama.Common.Types: ModelDetails :: !Maybe Text -> !Text -> !Text -> ![Text] -> !Text -> Text -> ModelDetails
- 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: SchemaFormat :: Schema -> Format
- 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: [doneReason] :: ChatResponse -> !Maybe Text
- 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 Format
- 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 ModelDetails
- 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.ModelDetails
- 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.Format
- 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.Format
- 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.ModelDetails
- 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.Internal.Generics.Generic Data.Ollama.Common.Types.FunctionDef
- Data.Ollama.Common.Types: instance GHC.Internal.Generics.Generic Data.Ollama.Common.Types.InputTool
- Data.Ollama.Common.Types: instance GHC.Internal.Generics.Generic Data.Ollama.Common.Types.Message
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.ChatResponse
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.Format
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.FunctionDef
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.FunctionParameters
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.GenerateResponse
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.InputTool
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.Message
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.ModelDetails
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.ModelOptions
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.OutputFunction
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.Role
- Data.Ollama.Common.Types: instance GHC.Internal.Show.Show Data.Ollama.Common.Types.ToolCall
- Data.Ollama.Common.Types: instance GHC.Internal.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: encodeImage :: FilePath -> IO (Maybe Text)
- 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.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.Classes.Eq Data.Ollama.Conversation.Conversation
- Data.Ollama.Conversation: instance GHC.Internal.Base.Applicative Data.Ollama.Conversation.ConvoM
- Data.Ollama.Conversation: instance GHC.Internal.Base.Functor Data.Ollama.Conversation.ConvoM
- Data.Ollama.Conversation: instance GHC.Internal.Base.Monad Data.Ollama.Conversation.ConvoM
- Data.Ollama.Conversation: instance GHC.Internal.Control.Monad.IO.Class.MonadIO Data.Ollama.Conversation.ConvoM
- Data.Ollama.Conversation: instance GHC.Internal.Generics.Generic Data.Ollama.Conversation.Conversation
- Data.Ollama.Conversation: instance GHC.Internal.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: copyModel :: Text -> Text -> Maybe OllamaConfig -> IO (Either OllamaError ())
- Data.Ollama.Copy: copyModelM :: MonadIO m => Text -> Text -> Maybe OllamaConfig -> m (Either OllamaError ())
- Data.Ollama.Copy: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Copy.CopyModelOps
- Data.Ollama.Copy: instance GHC.Classes.Eq Data.Ollama.Copy.CopyModelOps
- Data.Ollama.Copy: instance GHC.Internal.Generics.Generic Data.Ollama.Copy.CopyModelOps
- Data.Ollama.Copy: instance GHC.Internal.Show.Show Data.Ollama.Copy.CopyModelOps
- Data.Ollama.Create: CreateOps :: !Text -> !Maybe Text -> !Maybe (Map Text Text) -> !Maybe (Map Text Text) -> !Maybe Text -> !Maybe [Text] -> !Maybe Text -> !Maybe ModelOptions -> !Maybe [Message] -> !Maybe Bool -> !Maybe QuantizationType -> CreateOps
- Data.Ollama.Create: CreateResp :: !Text -> !Maybe Text -> !Maybe Int64 -> !Maybe Int64 -> CreateResp
- Data.Ollama.Create: Q4_K_M :: QuantizationType
- Data.Ollama.Create: Q4_K_S :: QuantizationType
- Data.Ollama.Create: Q8_0 :: QuantizationType
- Data.Ollama.Create: [adapters] :: CreateOps -> !Maybe (Map Text Text)
- Data.Ollama.Create: [completed] :: CreateResp -> !Maybe Int64
- Data.Ollama.Create: [digest] :: CreateResp -> !Maybe Text
- Data.Ollama.Create: [files] :: CreateOps -> !Maybe (Map Text Text)
- Data.Ollama.Create: [fromModel] :: CreateOps -> !Maybe Text
- Data.Ollama.Create: [license] :: CreateOps -> !Maybe [Text]
- Data.Ollama.Create: [messages] :: CreateOps -> !Maybe [Message]
- Data.Ollama.Create: [modelName] :: CreateOps -> !Text
- Data.Ollama.Create: [parameters] :: CreateOps -> !Maybe ModelOptions
- Data.Ollama.Create: [quantizeType] :: CreateOps -> !Maybe QuantizationType
- Data.Ollama.Create: [status] :: CreateResp -> !Text
- Data.Ollama.Create: [stream] :: CreateOps -> !Maybe Bool
- Data.Ollama.Create: [systemPrompt] :: CreateOps -> !Maybe Text
- Data.Ollama.Create: [template] :: CreateOps -> !Maybe Text
- Data.Ollama.Create: [total] :: CreateResp -> !Maybe Int64
- Data.Ollama.Create: createModel :: CreateOps -> Maybe OllamaConfig -> IO ()
- Data.Ollama.Create: createModelM :: MonadIO m => CreateOps -> Maybe OllamaConfig -> m ()
- Data.Ollama.Create: data CreateOps
- Data.Ollama.Create: data CreateResp
- Data.Ollama.Create: data QuantizationType
- Data.Ollama.Create: defaultCreateOps :: Text -> CreateOps
- Data.Ollama.Create: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Create.CreateResp
- Data.Ollama.Create: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Create.QuantizationType
- Data.Ollama.Create: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Create.CreateOps
- Data.Ollama.Create: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Create.QuantizationType
- Data.Ollama.Create: instance Data.Ollama.Common.Types.HasDone Data.Ollama.Create.CreateResp
- Data.Ollama.Create: instance GHC.Classes.Eq Data.Ollama.Create.CreateOps
- Data.Ollama.Create: instance GHC.Classes.Eq Data.Ollama.Create.CreateResp
- Data.Ollama.Create: instance GHC.Classes.Eq Data.Ollama.Create.QuantizationType
- Data.Ollama.Create: instance GHC.Internal.Generics.Generic Data.Ollama.Create.CreateOps
- Data.Ollama.Create: instance GHC.Internal.Generics.Generic Data.Ollama.Create.CreateResp
- Data.Ollama.Create: instance GHC.Internal.Generics.Generic Data.Ollama.Create.QuantizationType
- Data.Ollama.Create: instance GHC.Internal.Show.Show Data.Ollama.Create.CreateOps
- Data.Ollama.Create: instance GHC.Internal.Show.Show Data.Ollama.Create.CreateResp
- Data.Ollama.Create: instance GHC.Internal.Show.Show Data.Ollama.Create.QuantizationType
- Data.Ollama.Delete: deleteModel :: Text -> Maybe OllamaConfig -> IO (Either OllamaError ())
- Data.Ollama.Delete: deleteModelM :: MonadIO m => Text -> Maybe OllamaConfig -> m (Either OllamaError ())
- Data.Ollama.Delete: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Delete.DeleteModelReq
- Data.Ollama.Delete: instance GHC.Classes.Eq Data.Ollama.Delete.DeleteModelReq
- Data.Ollama.Delete: instance GHC.Internal.Show.Show Data.Ollama.Delete.DeleteModelReq
- Data.Ollama.Embeddings: EmbeddingOps :: !Text -> ![Text] -> !Maybe Bool -> !Maybe Int -> !Maybe ModelOptions -> !Maybe Int -> EmbeddingOps
- Data.Ollama.Embeddings: EmbeddingResp :: !Text -> ![[Float]] -> EmbeddingResp
- 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: [dimensions] :: EmbeddingOps -> !Maybe Int
- Data.Ollama.Embeddings: [frequencyPenalty] :: ModelOptions -> Maybe Double
- Data.Ollama.Embeddings: [input] :: EmbeddingOps -> ![Text]
- Data.Ollama.Embeddings: [keepAlive] :: EmbeddingOps -> !Maybe Int
- Data.Ollama.Embeddings: [mainGpu] :: ModelOptions -> Maybe Int
- Data.Ollama.Embeddings: [minP] :: ModelOptions -> Maybe Double
- Data.Ollama.Embeddings: [modelName] :: EmbeddingOps -> !Text
- Data.Ollama.Embeddings: [modelOptions] :: EmbeddingOps -> !Maybe ModelOptions
- 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 EmbeddingOps
- Data.Ollama.Embeddings: data EmbeddingResp
- Data.Ollama.Embeddings: data ModelOptions
- Data.Ollama.Embeddings: defaultEmbeddingOps :: EmbeddingOps
- Data.Ollama.Embeddings: defaultModelOptions :: ModelOptions
- Data.Ollama.Embeddings: embedding :: Text -> [Text] -> IO (Either OllamaError EmbeddingResp)
- Data.Ollama.Embeddings: embeddingM :: MonadIO m => Text -> [Text] -> m (Either OllamaError EmbeddingResp)
- Data.Ollama.Embeddings: embeddingOps :: Text -> [Text] -> Maybe Bool -> Maybe Int -> Maybe ModelOptions -> Maybe Int -> Maybe OllamaConfig -> IO (Either OllamaError EmbeddingResp)
- Data.Ollama.Embeddings: embeddingOpsM :: MonadIO m => Text -> [Text] -> Maybe Bool -> Maybe Int -> Maybe ModelOptions -> Maybe Int -> Maybe OllamaConfig -> m (Either OllamaError EmbeddingResp)
- Data.Ollama.Embeddings: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Embeddings.EmbeddingResp
- Data.Ollama.Embeddings: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Embeddings.EmbeddingOps
- Data.Ollama.Embeddings: instance GHC.Classes.Eq Data.Ollama.Embeddings.EmbeddingOps
- Data.Ollama.Embeddings: instance GHC.Classes.Eq Data.Ollama.Embeddings.EmbeddingResp
- Data.Ollama.Embeddings: instance GHC.Internal.Show.Show Data.Ollama.Embeddings.EmbeddingOps
- Data.Ollama.Embeddings: instance GHC.Internal.Show.Show Data.Ollama.Embeddings.EmbeddingResp
- Data.Ollama.Generate: ApiError :: Text -> OllamaError
- Data.Ollama.Generate: DecodeError :: DecodingErrorMessage -> DecodingFailedValue -> OllamaError
- Data.Ollama.Generate: FileError :: IOException -> OllamaError
- 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 -> !Maybe Text -> !Maybe Text -> GenerateResponse
- 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: [doneReason] :: GenerateResponse -> !Maybe Text
- 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 GenerateOps
- Data.Ollama.Generate: data GenerateResponse
- Data.Ollama.Generate: data ModelOptions
- Data.Ollama.Generate: data OllamaConfig
- Data.Ollama.Generate: data OllamaError
- Data.Ollama.Generate: defaultGenerateOps :: GenerateOps
- Data.Ollama.Generate: defaultModelOptions :: ModelOptions
- Data.Ollama.Generate: defaultOllamaConfig :: OllamaConfig
- Data.Ollama.Generate: generate :: GenerateOps -> Maybe OllamaConfig -> IO (Either OllamaError GenerateResponse)
- Data.Ollama.Generate: generateM :: MonadIO m => GenerateOps -> Maybe OllamaConfig -> m (Either OllamaError GenerateResponse)
- Data.Ollama.Generate: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Generate.GenerateOps
- Data.Ollama.Generate: instance GHC.Classes.Eq Data.Ollama.Generate.GenerateOps
- Data.Ollama.Generate: instance GHC.Internal.Show.Show Data.Ollama.Generate.GenerateOps
- Data.Ollama.Generate: validateGenerateOps :: GenerateOps -> Either OllamaError GenerateOps
- Data.Ollama.List: ModelInfo :: !Text -> !UTCTime -> !Int64 -> !Text -> !ModelDetails -> ModelInfo
- Data.Ollama.List: Models :: [ModelInfo] -> Models
- Data.Ollama.List: [details] :: ModelInfo -> !ModelDetails
- Data.Ollama.List: [digest] :: ModelInfo -> !Text
- Data.Ollama.List: [modifiedAt] :: ModelInfo -> !UTCTime
- Data.Ollama.List: [name] :: ModelInfo -> !Text
- Data.Ollama.List: [size] :: ModelInfo -> !Int64
- Data.Ollama.List: data ModelInfo
- Data.Ollama.List: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.List.ModelInfo
- Data.Ollama.List: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.List.Models
- Data.Ollama.List: instance GHC.Classes.Eq Data.Ollama.List.ModelInfo
- Data.Ollama.List: instance GHC.Classes.Eq Data.Ollama.List.Models
- Data.Ollama.List: instance GHC.Internal.Show.Show Data.Ollama.List.ModelInfo
- Data.Ollama.List: instance GHC.Internal.Show.Show Data.Ollama.List.Models
- Data.Ollama.List: list :: Maybe OllamaConfig -> IO (Either OllamaError Models)
- Data.Ollama.List: listM :: MonadIO m => Maybe OllamaConfig -> m (Either OllamaError Models)
- Data.Ollama.List: newtype 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: RunningModel :: !Text -> !Text -> !Int64 -> !Text -> !ModelDetails -> !UTCTime -> !Int64 -> RunningModel
- Data.Ollama.Ps: RunningModels :: [RunningModel] -> RunningModels
- Data.Ollama.Ps: [expiresAt] :: RunningModel -> !UTCTime
- Data.Ollama.Ps: [modelDetails] :: RunningModel -> !ModelDetails
- Data.Ollama.Ps: [modelDigest] :: RunningModel -> !Text
- Data.Ollama.Ps: [modelName] :: RunningModel -> !Text
- Data.Ollama.Ps: [name_] :: RunningModel -> !Text
- Data.Ollama.Ps: [sizeVRam] :: RunningModel -> !Int64
- Data.Ollama.Ps: [size_] :: RunningModel -> !Int64
- Data.Ollama.Ps: data RunningModel
- Data.Ollama.Ps: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Ps.RunningModel
- Data.Ollama.Ps: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Ps.RunningModels
- Data.Ollama.Ps: instance GHC.Classes.Eq Data.Ollama.Ps.RunningModel
- Data.Ollama.Ps: instance GHC.Classes.Eq Data.Ollama.Ps.RunningModels
- Data.Ollama.Ps: instance GHC.Internal.Show.Show Data.Ollama.Ps.RunningModel
- Data.Ollama.Ps: instance GHC.Internal.Show.Show Data.Ollama.Ps.RunningModels
- Data.Ollama.Ps: newtype RunningModels
- Data.Ollama.Ps: ps :: Maybe OllamaConfig -> IO (Either OllamaError RunningModels)
- Data.Ollama.Ps: psM :: MonadIO m => Maybe OllamaConfig -> m (Either OllamaError RunningModels)
- Data.Ollama.Pull: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Pull.PullResp
- Data.Ollama.Pull: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Pull.PullOps
- Data.Ollama.Pull: instance Data.Ollama.Common.Types.HasDone Data.Ollama.Pull.PullResp
- Data.Ollama.Pull: instance GHC.Classes.Eq Data.Ollama.Pull.PullOps
- Data.Ollama.Pull: instance GHC.Classes.Eq Data.Ollama.Pull.PullResp
- Data.Ollama.Pull: instance GHC.Internal.Generics.Generic Data.Ollama.Pull.PullOps
- Data.Ollama.Pull: instance GHC.Internal.Generics.Generic Data.Ollama.Pull.PullResp
- Data.Ollama.Pull: instance GHC.Internal.Show.Show Data.Ollama.Pull.PullOps
- Data.Ollama.Pull: instance GHC.Internal.Show.Show Data.Ollama.Pull.PullResp
- Data.Ollama.Pull: pull :: Text -> IO (Either OllamaError PullResp)
- Data.Ollama.Pull: pullM :: MonadIO m => Text -> m (Either OllamaError PullResp)
- Data.Ollama.Pull: pullOps :: Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> IO (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.Aeson.Types.FromJSON.FromJSON Data.Ollama.Push.PushResp
- Data.Ollama.Push: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Push.PushOps
- Data.Ollama.Push: instance Data.Ollama.Common.Types.HasDone Data.Ollama.Push.PushResp
- Data.Ollama.Push: instance GHC.Classes.Eq Data.Ollama.Push.PushOps
- Data.Ollama.Push: instance GHC.Classes.Eq Data.Ollama.Push.PushResp
- Data.Ollama.Push: instance GHC.Internal.Generics.Generic Data.Ollama.Push.PushOps
- Data.Ollama.Push: instance GHC.Internal.Generics.Generic Data.Ollama.Push.PushResp
- Data.Ollama.Push: instance GHC.Internal.Show.Show Data.Ollama.Push.PushOps
- Data.Ollama.Push: instance GHC.Internal.Show.Show Data.Ollama.Push.PushResp
- Data.Ollama.Push: push :: Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> IO ()
- 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: ShowModelResponse :: !Text -> !Maybe Text -> !Maybe Text -> !ModelDetails -> !ShowModelInfo -> !Maybe Text -> Maybe [Text] -> ShowModelResponse
- 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: data ShowModelResponse
- Data.Ollama.Show: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Show.ShowModelInfo
- Data.Ollama.Show: instance Data.Aeson.Types.FromJSON.FromJSON Data.Ollama.Show.ShowModelResponse
- Data.Ollama.Show: instance Data.Aeson.Types.ToJSON.ToJSON Data.Ollama.Show.ShowModelOps
- Data.Ollama.Show: instance GHC.Classes.Eq Data.Ollama.Show.ShowModelInfo
- Data.Ollama.Show: instance GHC.Classes.Eq Data.Ollama.Show.ShowModelOps
- Data.Ollama.Show: instance GHC.Classes.Eq Data.Ollama.Show.ShowModelResponse
- Data.Ollama.Show: instance GHC.Internal.Generics.Generic Data.Ollama.Show.ShowModelOps
- Data.Ollama.Show: instance GHC.Internal.Show.Show Data.Ollama.Show.ShowModelInfo
- Data.Ollama.Show: instance GHC.Internal.Show.Show Data.Ollama.Show.ShowModelOps
- Data.Ollama.Show: instance GHC.Internal.Show.Show Data.Ollama.Show.ShowModelResponse
- Data.Ollama.Show: showModel :: Text -> IO (Either OllamaError ShowModelResponse)
- Data.Ollama.Show: showModelM :: MonadIO m => Text -> m (Either OllamaError ShowModelResponse)
- Data.Ollama.Show: showModelOps :: Text -> Maybe Bool -> Maybe OllamaConfig -> IO (Either OllamaError ShowModelResponse)
- Data.Ollama.Show: showModelOpsM :: MonadIO m => Text -> Maybe Bool -> Maybe OllamaConfig -> m (Either OllamaError ShowModelResponse)
- Ollama: ChatOps :: !Text -> !NonEmpty Message -> !Maybe [InputTool] -> !Maybe Format -> !Maybe (ChatResponse -> IO (), IO ()) -> !Maybe Int -> !Maybe ModelOptions -> !Maybe Bool -> ChatOps
- Ollama: EmbeddingOps :: !Text -> ![Text] -> !Maybe Bool -> !Maybe Int -> !Maybe ModelOptions -> !Maybe Int -> EmbeddingOps
- Ollama: EmbeddingResp :: !Text -> ![[Float]] -> EmbeddingResp
- Ollama: FileError :: IOException -> OllamaError
- 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: InputTool :: Text -> FunctionDef -> InputTool
- Ollama: JsonSchemaError :: String -> OllamaError
- Ollama: ModelDetails :: !Maybe Text -> !Text -> !Text -> ![Text] -> !Text -> Text -> ModelDetails
- Ollama: Models :: [ModelInfo] -> Models
- 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: RunningModels :: [RunningModel] -> RunningModels
- 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: ShowModelResponse :: !Text -> !Maybe Text -> !Maybe Text -> !ModelDetails -> !ShowModelInfo -> !Maybe Text -> Maybe [Text] -> ShowModelResponse
- Ollama: [additionalProperties] :: FunctionParameters -> Maybe Bool
- Ollama: [arguments] :: OutputFunction -> Map Text Value
- Ollama: [capabilities] :: ShowModelResponse -> Maybe [Text]
- Ollama: [commonManager] :: OllamaConfig -> Maybe Manager
- Ollama: [content] :: Message -> !Text
- Ollama: [details] :: ModelInfo -> !ModelDetails
- Ollama: [digest] :: ModelInfo -> !Text
- Ollama: [doneReason] :: ChatResponse -> !Maybe Text
- Ollama: [done] :: ChatResponse -> !Bool
- Ollama: [evalCount] :: ChatResponse -> !Maybe Int64
- Ollama: [evalDuration] :: ChatResponse -> !Maybe Int64
- Ollama: [families] :: ModelDetails -> ![Text]
- Ollama: [family] :: ModelDetails -> !Text
- Ollama: [format] :: 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: [hostUrl] :: OllamaConfig -> Text
- Ollama: [images] :: Message -> !Maybe [Text]
- Ollama: [keepAlive] :: ChatOps -> !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: [loadDuration] :: ChatResponse -> !Maybe Int64
- Ollama: [mainGpu] :: ModelOptions -> Maybe Int
- Ollama: [message] :: ChatResponse -> !Maybe Message
- Ollama: [minP] :: ModelOptions -> Maybe Double
- Ollama: [modelFile] :: ShowModelResponse -> !Text
- Ollama: [modelInfo] :: ShowModelResponse -> !ShowModelInfo
- Ollama: [modelName] :: ChatOps -> !Text
- Ollama: [modifiedAt] :: ModelInfo -> !UTCTime
- Ollama: [name] :: ModelInfo -> !Text
- 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: [options] :: ChatOps -> !Maybe ModelOptions
- 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: [promptEvalCount] :: ChatResponse -> !Maybe Int64
- Ollama: [promptEvalDuration] :: ChatResponse -> !Maybe Int64
- 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: [role] :: Message -> !Role
- Ollama: [seed] :: ModelOptions -> Maybe Int
- Ollama: [size] :: ModelInfo -> !Int64
- Ollama: [stop] :: ModelOptions -> Maybe [Text]
- Ollama: [stream] :: ChatOps -> !Maybe (ChatResponse -> IO (), IO ())
- 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: [tool_calls] :: Message -> !Maybe [ToolCall]
- Ollama: [tools] :: ChatOps -> !Maybe [InputTool]
- Ollama: [topK] :: ModelOptions -> Maybe Int
- Ollama: [topP] :: ModelOptions -> Maybe Double
- Ollama: [totalDuration] :: ChatResponse -> !Maybe Int64
- Ollama: [typicalP] :: ModelOptions -> Maybe Double
- Ollama: [useMmap] :: ModelOptions -> Maybe Bool
- Ollama: chatM :: MonadIO m => ChatOps -> Maybe OllamaConfig -> m (Either OllamaError ChatResponse)
- Ollama: checkBlobExists :: Text -> Maybe OllamaConfig -> IO (Either OllamaError Bool)
- Ollama: copyModelM :: MonadIO m => Text -> Text -> Maybe OllamaConfig -> m (Either OllamaError ())
- Ollama: createBlob :: FilePath -> Text -> Maybe OllamaConfig -> IO (Either OllamaError ())
- Ollama: createModelM :: MonadIO m => CreateOps -> Maybe OllamaConfig -> m ()
- Ollama: data ChatOps
- Ollama: data EmbeddingOps
- Ollama: data EmbeddingResp
- Ollama: data GenerateOps
- Ollama: data InputTool
- Ollama: data ModelDetails
- Ollama: data OllamaConfig
- Ollama: data OutputFunction
- Ollama: data ShowModelInfo
- Ollama: data ShowModelResponse
- Ollama: defaultChatOps :: ChatOps
- Ollama: defaultGenerateOps :: GenerateOps
- Ollama: defaultModelOptions :: ModelOptions
- Ollama: defaultOllamaConfig :: OllamaConfig
- Ollama: deleteModelM :: MonadIO m => Text -> Maybe OllamaConfig -> m (Either OllamaError ())
- Ollama: embedding :: Text -> [Text] -> IO (Either OllamaError EmbeddingResp)
- Ollama: embeddingM :: MonadIO m => Text -> [Text] -> m (Either OllamaError EmbeddingResp)
- Ollama: embeddingOps :: Text -> [Text] -> Maybe Bool -> Maybe Int -> Maybe ModelOptions -> Maybe Int -> Maybe OllamaConfig -> IO (Either OllamaError EmbeddingResp)
- Ollama: embeddingOpsM :: MonadIO m => Text -> [Text] -> Maybe Bool -> Maybe Int -> Maybe ModelOptions -> Maybe Int -> Maybe OllamaConfig -> m (Either OllamaError EmbeddingResp)
- Ollama: encodeImage :: FilePath -> IO (Maybe Text)
- Ollama: generateM :: MonadIO m => GenerateOps -> Maybe OllamaConfig -> m (Either OllamaError GenerateResponse)
- Ollama: list :: Maybe OllamaConfig -> IO (Either OllamaError Models)
- Ollama: loadGenModel :: Text -> IO (Either OllamaError ())
- Ollama: loadGenModelM :: MonadIO m => Text -> m (Either OllamaError ())
- Ollama: newtype Models
- Ollama: newtype RunningModels
- Ollama: ps :: Maybe OllamaConfig -> IO (Either OllamaError RunningModels)
- Ollama: psM :: MonadIO m => Maybe OllamaConfig -> m (Either OllamaError RunningModels)
- Ollama: pullM :: MonadIO m => Text -> m (Either OllamaError PullResp)
- Ollama: pullOps :: Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> IO (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: showModelOps :: Text -> Maybe Bool -> Maybe OllamaConfig -> IO (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
+ Ollama: Base64Image :: Text -> Base64Image
+ Ollama: ChatRequest :: !ModelName -> !NonEmpty Message -> !Maybe [Tool] -> !Maybe Format -> !Maybe ModelOptions -> !Maybe Bool -> !Maybe Text -> !Maybe Think -> ChatRequest
+ Ollama: ConstantRetry :: !Int -> !Int -> RetryPolicy
+ Ollama: Conversation :: !Text -> ![Message] -> !ModelName -> !UTCTime -> !UTCTime -> Conversation
+ Ollama: CreateRequest :: !ModelName -> !Maybe ModelName -> !Maybe (Map Text Digest) -> !Maybe (Map Text Digest) -> !Maybe Text -> !Maybe Text -> !Maybe Text -> !Maybe [Text] -> !Maybe Text -> !Maybe ModelOptions -> !Maybe [Message] -> !Maybe Bool -> !Maybe QuantizationType -> CreateRequest
+ Ollama: CreateResponse :: !Text -> !Maybe Digest -> !Maybe Int64 -> !Maybe Int64 -> CreateResponse
+ Ollama: Debug :: LogLevel
+ Ollama: Digest :: Text -> Digest
+ Ollama: Duration :: Int64 -> Duration
+ Ollama: EmbedRequest :: !ModelName -> !Either Text [Text] -> !Maybe Bool -> !Maybe ModelOptions -> !Maybe Text -> !Maybe Int -> EmbedRequest
+ Ollama: EmbedResponse :: !ModelName -> ![[Double]] -> !Maybe Duration -> !Maybe Duration -> !Maybe Int -> EmbedResponse
+ Ollama: EmbeddingsRequest :: !ModelName -> !Text -> !Maybe ModelOptions -> !Maybe Text -> EmbeddingsRequest
+ Ollama: EmbeddingsResponse :: [Double] -> EmbeddingsResponse
+ Ollama: Error :: LogLevel
+ Ollama: ExponentialRetry :: !Int -> !Int -> RetryPolicy
+ Ollama: GenerateRequest :: !ModelName -> !Text -> !Maybe Text -> !Maybe [Base64Image] -> !Maybe Format -> !Maybe ModelOptions -> !Maybe Text -> !Maybe Text -> !Maybe Bool -> !Maybe Bool -> !Maybe Text -> !Maybe Think -> !Maybe Int -> !Maybe Int -> !Maybe Int -> GenerateRequest
+ Ollama: InMemoryStore :: TVar (Map Text Conversation) -> InMemoryStore
+ Ollama: Info :: LogLevel
+ Ollama: ListResponse :: [ModelInfo] -> ListResponse
+ Ollama: ModelName :: Text -> ModelName
+ Ollama: NoRetry :: RetryPolicy
+ Ollama: OllamaClientConfig :: !Text -> !Int -> !RetryPolicy -> !Maybe Manager -> ![(CI ByteString, ByteString)] -> !Maybe Text -> !Maybe (LogLevel -> Text -> IO ()) -> !Maybe (IO ()) -> !Maybe (IO ()) -> !Maybe (IO ()) -> OllamaClientConfig
+ Ollama: PullResponse :: !Text -> !Maybe Digest -> !Maybe Int64 -> !Maybe Int64 -> PullResponse
+ Ollama: PushResponse :: !Text -> !Maybe Digest -> !Maybe Int64 -> !Maybe Int64 -> PushResponse
+ Ollama: Q4_K_M :: QuantizationType
+ Ollama: Q4_K_S :: QuantizationType
+ Ollama: Q8_0 :: QuantizationType
+ Ollama: RunningModelsResponse :: [RunningModel] -> RunningModelsResponse
+ Ollama: ShowResponse :: !Text -> !Maybe Text -> !Maybe Text -> !ModelDetails -> !Maybe ShowModelInfo -> !Maybe Text -> !Maybe [Text] -> ShowResponse
+ Ollama: ThinkDisabled :: Think
+ Ollama: ThinkEnabled :: Think
+ Ollama: ThinkHigh :: ThinkingLevel
+ Ollama: ThinkLevel :: !ThinkingLevel -> Think
+ Ollama: ThinkLow :: ThinkingLevel
+ Ollama: ThinkMax :: ThinkingLevel
+ Ollama: ThinkMedium :: ThinkingLevel
+ Ollama: ToolCallFunction :: !Text -> !Map Text Value -> ToolCallFunction
+ Ollama: Warn :: LogLevel
+ Ollama: [chStream] :: ChatRequest -> !Maybe Bool
+ Ollama: [chatFormat] :: ChatRequest -> !Maybe Format
+ Ollama: [chatKeepAlive] :: ChatRequest -> !Maybe Text
+ Ollama: [chatMessages] :: ChatRequest -> !NonEmpty Message
+ Ollama: [chatModel] :: ChatRequest -> !ModelName
+ Ollama: [chatOptions] :: ChatRequest -> !Maybe ModelOptions
+ Ollama: [chatThink] :: ChatRequest -> !Maybe Think
+ Ollama: [chatTools] :: ChatRequest -> !Maybe [Tool]
+ Ollama: [configApiKey] :: OllamaClientConfig -> !Maybe Text
+ Ollama: [configBaseUrl] :: OllamaClientConfig -> !Text
+ Ollama: [configHeaders] :: OllamaClientConfig -> ![(CI ByteString, ByteString)]
+ Ollama: [configLogger] :: OllamaClientConfig -> !Maybe (LogLevel -> Text -> IO ())
+ Ollama: [configManager] :: OllamaClientConfig -> !Maybe Manager
+ Ollama: [configOnError] :: OllamaClientConfig -> !Maybe (IO ())
+ Ollama: [configOnStart] :: OllamaClientConfig -> !Maybe (IO ())
+ Ollama: [configOnSuccess] :: OllamaClientConfig -> !Maybe (IO ())
+ Ollama: [configRetry] :: OllamaClientConfig -> !RetryPolicy
+ Ollama: [configTimeout] :: OllamaClientConfig -> !Int
+ Ollama: [conversationId] :: Conversation -> !Text
+ Ollama: [crCreatedAt] :: ChatResponse -> !UTCTime
+ Ollama: [crDoneReason] :: ChatResponse -> !Maybe Text
+ Ollama: [crDone] :: ChatResponse -> !Bool
+ Ollama: [crEvalCount] :: ChatResponse -> !Maybe Int
+ Ollama: [crEvalDuration] :: ChatResponse -> !Maybe Duration
+ Ollama: [crLoadDuration] :: ChatResponse -> !Maybe Duration
+ Ollama: [crMessage] :: ChatResponse -> !Maybe Message
+ Ollama: [crModel] :: ChatResponse -> !ModelName
+ Ollama: [crPromptEvalCount] :: ChatResponse -> !Maybe Int
+ Ollama: [crPromptEvalDuration] :: ChatResponse -> !Maybe Duration
+ Ollama: [crTotalDuration] :: ChatResponse -> !Maybe Duration
+ Ollama: [crqAdapters] :: CreateRequest -> !Maybe (Map Text Digest)
+ Ollama: [crqFiles] :: CreateRequest -> !Maybe (Map Text Digest)
+ Ollama: [crqFrom] :: CreateRequest -> !Maybe ModelName
+ Ollama: [crqLicense] :: CreateRequest -> !Maybe [Text]
+ Ollama: [crqMessages] :: CreateRequest -> !Maybe [Message]
+ Ollama: [crqModel] :: CreateRequest -> !ModelName
+ Ollama: [crqParameters] :: CreateRequest -> !Maybe ModelOptions
+ Ollama: [crqParser] :: CreateRequest -> !Maybe Text
+ Ollama: [crqQuantize] :: CreateRequest -> !Maybe QuantizationType
+ Ollama: [crqRenderer] :: CreateRequest -> !Maybe Text
+ Ollama: [crqStream] :: CreateRequest -> !Maybe Bool
+ Ollama: [crqSystem] :: CreateRequest -> !Maybe Text
+ Ollama: [crqTemplate] :: CreateRequest -> !Maybe Text
+ Ollama: [crsCompleted] :: CreateResponse -> !Maybe Int64
+ Ollama: [crsDigest] :: CreateResponse -> !Maybe Digest
+ Ollama: [crsStatus] :: CreateResponse -> !Text
+ Ollama: [crsTotal] :: CreateResponse -> !Maybe Int64
+ Ollama: [durationNanos] :: Duration -> Int64
+ Ollama: [ebrEmbedding] :: EmbeddingsResponse -> [Double]
+ Ollama: [ebrKeepAlive] :: EmbeddingsRequest -> !Maybe Text
+ Ollama: [ebrModel] :: EmbeddingsRequest -> !ModelName
+ Ollama: [ebrOptions] :: EmbeddingsRequest -> !Maybe ModelOptions
+ Ollama: [ebrPrompt] :: EmbeddingsRequest -> !Text
+ Ollama: [embDimensions] :: EmbedRequest -> !Maybe Int
+ Ollama: [embInput] :: EmbedRequest -> !Either Text [Text]
+ Ollama: [embKeepAlive] :: EmbedRequest -> !Maybe Text
+ Ollama: [embModel] :: EmbedRequest -> !ModelName
+ Ollama: [embOptions] :: EmbedRequest -> !Maybe ModelOptions
+ Ollama: [embTruncate] :: EmbedRequest -> !Maybe Bool
+ Ollama: [erEmbeddings] :: EmbedResponse -> ![[Double]]
+ Ollama: [erLoadDuration] :: EmbedResponse -> !Maybe Duration
+ Ollama: [erModel] :: EmbedResponse -> !ModelName
+ Ollama: [erPromptEvalCount] :: EmbedResponse -> !Maybe Int
+ Ollama: [erTotalDuration] :: EmbedResponse -> !Maybe Duration
+ Ollama: [fnDescription] :: FunctionDef -> !Maybe Text
+ Ollama: [fnName] :: FunctionDef -> !Text
+ Ollama: [fnParameters] :: FunctionDef -> !Maybe FunctionParameters
+ Ollama: [fnStrict] :: FunctionDef -> !Maybe Bool
+ Ollama: [fpAdditionalProperties] :: FunctionParameters -> !Maybe Bool
+ Ollama: [fpDescription] :: FunctionParameters -> !Maybe Text
+ Ollama: [fpEnum] :: FunctionParameters -> !Maybe [Text]
+ Ollama: [fpProperties] :: FunctionParameters -> !Maybe (Map Text FunctionParameters)
+ Ollama: [fpRequired] :: FunctionParameters -> !Maybe [Text]
+ Ollama: [fpType] :: FunctionParameters -> !Text
+ Ollama: [genFormat] :: GenerateRequest -> !Maybe Format
+ Ollama: [genHeight] :: GenerateRequest -> !Maybe Int
+ Ollama: [genImages] :: GenerateRequest -> !Maybe [Base64Image]
+ Ollama: [genKeepAlive] :: GenerateRequest -> !Maybe Text
+ Ollama: [genModel] :: GenerateRequest -> !ModelName
+ Ollama: [genOptions] :: GenerateRequest -> !Maybe ModelOptions
+ Ollama: [genPrompt] :: GenerateRequest -> !Text
+ Ollama: [genRaw] :: GenerateRequest -> !Maybe Bool
+ Ollama: [genSteps] :: GenerateRequest -> !Maybe Int
+ Ollama: [genStream] :: GenerateRequest -> !Maybe Bool
+ Ollama: [genSuffix] :: GenerateRequest -> !Maybe Text
+ Ollama: [genSystem] :: GenerateRequest -> !Maybe Text
+ Ollama: [genTemplate] :: GenerateRequest -> !Maybe Text
+ Ollama: [genThink] :: GenerateRequest -> !Maybe Think
+ Ollama: [genWidth] :: GenerateRequest -> !Maybe Int
+ Ollama: [grContext] :: GenerateResponse -> !Maybe [Int]
+ Ollama: [grCreatedAt] :: GenerateResponse -> !UTCTime
+ Ollama: [grDoneReason] :: GenerateResponse -> !Maybe Text
+ Ollama: [grDone] :: GenerateResponse -> !Bool
+ Ollama: [grEvalCount] :: GenerateResponse -> !Maybe Int
+ Ollama: [grEvalDuration] :: GenerateResponse -> !Maybe Duration
+ Ollama: [grImage] :: GenerateResponse -> !Maybe Base64Image
+ Ollama: [grLoadDuration] :: GenerateResponse -> !Maybe Duration
+ Ollama: [grModel] :: GenerateResponse -> !ModelName
+ Ollama: [grPromptEvalCount] :: GenerateResponse -> !Maybe Int
+ Ollama: [grPromptEvalDuration] :: GenerateResponse -> !Maybe Duration
+ Ollama: [grResponse] :: GenerateResponse -> !Text
+ Ollama: [grThinking] :: GenerateResponse -> !Maybe Text
+ Ollama: [grTotalDuration] :: GenerateResponse -> !Maybe Duration
+ Ollama: [lastUpdated] :: Conversation -> !UTCTime
+ Ollama: [messageContent] :: Message -> !Text
+ Ollama: [messageImages] :: Message -> !Maybe [Base64Image]
+ Ollama: [messageRole] :: Message -> !Role
+ Ollama: [messageThinking] :: Message -> !Maybe Text
+ Ollama: [messageToolCalls] :: Message -> !Maybe [ToolCall]
+ Ollama: [messageToolName] :: Message -> !Maybe Text
+ Ollama: [miDetails] :: ModelInfo -> !ModelDetails
+ Ollama: [miDigest] :: ModelInfo -> !Digest
+ Ollama: [miModel] :: ModelInfo -> !ModelName
+ Ollama: [miModifiedAt] :: ModelInfo -> !UTCTime
+ Ollama: [miName] :: ModelInfo -> !ModelName
+ Ollama: [miSize] :: ModelInfo -> !Int64
+ Ollama: [models] :: ListResponse -> [ModelInfo]
+ Ollama: [optDraftNumPredict] :: ModelOptions -> !Maybe Int
+ Ollama: [optFrequencyPenalty] :: ModelOptions -> !Maybe Double
+ Ollama: [optMainGpu] :: ModelOptions -> !Maybe Int
+ Ollama: [optMinP] :: ModelOptions -> !Maybe Double
+ Ollama: [optNumBatch] :: ModelOptions -> !Maybe Int
+ Ollama: [optNumCtx] :: ModelOptions -> !Maybe Int
+ Ollama: [optNumGpu] :: ModelOptions -> !Maybe Int
+ Ollama: [optNumKeep] :: ModelOptions -> !Maybe Int
+ Ollama: [optNumPredict] :: ModelOptions -> !Maybe Int
+ Ollama: [optNumThread] :: ModelOptions -> !Maybe Int
+ Ollama: [optNuma] :: ModelOptions -> !Maybe Bool
+ Ollama: [optPenalizeNewline] :: ModelOptions -> !Maybe Bool
+ Ollama: [optPresencePenalty] :: ModelOptions -> !Maybe Double
+ Ollama: [optRepeatLastN] :: ModelOptions -> !Maybe Int
+ Ollama: [optRepeatPenalty] :: ModelOptions -> !Maybe Double
+ Ollama: [optSeed] :: ModelOptions -> !Maybe Int
+ Ollama: [optStop] :: ModelOptions -> !Maybe [Text]
+ Ollama: [optTemperature] :: ModelOptions -> !Maybe Double
+ Ollama: [optTopK] :: ModelOptions -> !Maybe Int
+ Ollama: [optTopP] :: ModelOptions -> !Maybe Double
+ Ollama: [optTypicalP] :: ModelOptions -> !Maybe Double
+ Ollama: [optUseMmap] :: ModelOptions -> !Maybe Bool
+ Ollama: [prCompleted] :: PullResponse -> !Maybe Int64
+ Ollama: [prDigest] :: PullResponse -> !Maybe Digest
+ Ollama: [prStatus] :: PullResponse -> !Text
+ Ollama: [prTotal] :: PullResponse -> !Maybe Int64
+ Ollama: [psCompleted] :: PushResponse -> !Maybe Int64
+ Ollama: [psDigest] :: PushResponse -> !Maybe Digest
+ Ollama: [psStatus] :: PushResponse -> !Text
+ Ollama: [psTotal] :: PushResponse -> !Maybe Int64
+ Ollama: [rmDetails] :: RunningModel -> !ModelDetails
+ Ollama: [rmDigest] :: RunningModel -> !Digest
+ Ollama: [rmExpiresAt] :: RunningModel -> !UTCTime
+ Ollama: [rmModel] :: RunningModel -> !ModelName
+ Ollama: [rmName] :: RunningModel -> !ModelName
+ Ollama: [rmSizeVram] :: RunningModel -> !Int64
+ Ollama: [rmSize] :: RunningModel -> !Int64
+ Ollama: [runningModels] :: RunningModelsResponse -> [RunningModel]
+ Ollama: [srsCapabilities] :: ShowResponse -> !Maybe [Text]
+ Ollama: [srsDetails] :: ShowResponse -> !ModelDetails
+ Ollama: [srsLicense] :: ShowResponse -> !Maybe Text
+ Ollama: [srsModelInfo] :: ShowResponse -> !Maybe ShowModelInfo
+ Ollama: [srsModelfile] :: ShowResponse -> !Text
+ Ollama: [srsParameters] :: ShowResponse -> !Maybe Text
+ Ollama: [srsTemplate] :: ShowResponse -> !Maybe Text
+ Ollama: [tcFunction] :: ToolCall -> ToolCallFunction
+ Ollama: [tcfArguments] :: ToolCallFunction -> !Map Text Value
+ Ollama: [tcfName] :: ToolCallFunction -> !Text
+ Ollama: [toolFunction] :: Tool -> !FunctionDef
+ Ollama: [unBase64Image] :: Base64Image -> Text
+ Ollama: [unDigest] :: Digest -> Text
+ Ollama: [unModelName] :: ModelName -> Text
+ Ollama: [unVersion] :: Version -> Text
+ Ollama: assistantMessage :: Text -> Message
+ Ollama: chatEvalTokensPerSecond :: ChatResponse -> Maybe Double
+ Ollama: chatPromptEvalTokensPerSecond :: ChatResponse -> Maybe Double
+ Ollama: chatRequest :: ModelName -> NonEmpty Message -> ChatRequest
+ Ollama: chatStream :: MonadUnliftIO m => OllamaClient -> ChatRequest -> ConduitT () ChatResponse m ()
+ Ollama: checkBlob :: MonadIO m => OllamaClient -> Digest -> m (Either OllamaError Bool)
+ Ollama: class (Monad m) => ConversationStore m
+ Ollama: class HasDone a
+ Ollama: clientFromEnv :: MonadIO m => m OllamaClient
+ Ollama: closeClient :: MonadIO m => OllamaClient -> m ()
+ Ollama: collectStream :: MonadUnliftIO m => ConduitT () a m () -> m [a]
+ Ollama: createModelStream :: MonadUnliftIO m => OllamaClient -> CreateRequest -> ConduitT () CreateResponse m ()
+ Ollama: data ChatRequest
+ Ollama: data Conversation
+ Ollama: data CreateRequest
+ Ollama: data CreateResponse
+ Ollama: data EmbedRequest
+ Ollama: data EmbedResponse
+ Ollama: data EmbeddingsRequest
+ Ollama: data GenerateRequest
+ Ollama: data LogLevel
+ Ollama: data OllamaClient
+ Ollama: data OllamaClientConfig
+ Ollama: data PullResponse
+ Ollama: data PushResponse
+ Ollama: data QuantizationType
+ Ollama: data RetryPolicy
+ Ollama: data ShowResponse
+ Ollama: data Think
+ Ollama: data ThinkingLevel
+ Ollama: data Tool
+ Ollama: data ToolCallFunction
+ Ollama: defaultClient :: MonadIO m => m OllamaClient
+ Ollama: defaultConfig :: OllamaClientConfig
+ Ollama: defaultCreateRequest :: ModelName -> CreateRequest
+ Ollama: defaultOptions :: ModelOptions
+ Ollama: deleteConversation :: ConversationStore m => Text -> m Bool
+ Ollama: deleteConversationInMemory :: MonadIO m => InMemoryStore -> Text -> m Bool
+ Ollama: durationToMillis :: Duration -> Double
+ Ollama: durationToSeconds :: Duration -> Double
+ Ollama: embed :: MonadIO m => OllamaClient -> EmbedRequest -> m (Either OllamaError EmbedResponse)
+ Ollama: embedRequest :: ModelName -> [Text] -> EmbedRequest
+ Ollama: embeddings :: MonadIO m => OllamaClient -> EmbeddingsRequest -> m (Either OllamaError EmbeddingsResponse)
+ Ollama: evalTokensPerSecond :: GenerateResponse -> Maybe Double
+ Ollama: foldStream :: MonadUnliftIO m => (b -> a -> b) -> b -> ConduitT () a m () -> m b
+ Ollama: generateRequest :: ModelName -> Text -> GenerateRequest
+ Ollama: generateStream :: MonadUnliftIO m => OllamaClient -> GenerateRequest -> ConduitT () GenerateResponse m ()
+ Ollama: imageMessage :: Text -> [Base64Image] -> Message
+ Ollama: initInMemoryStore :: IO InMemoryStore
+ Ollama: isDone :: HasDone a => a -> Bool
+ Ollama: isRetryable :: OllamaError -> Bool
+ Ollama: listConversations :: ConversationStore m => m [Conversation]
+ Ollama: listConversationsInMemory :: MonadIO m => InMemoryStore -> m [Conversation]
+ Ollama: listModels :: MonadIO m => OllamaClient -> m (Either OllamaError ListResponse)
+ Ollama: listRunning :: MonadIO m => OllamaClient -> m (Either OllamaError RunningModelsResponse)
+ Ollama: loadConversation :: ConversationStore m => Text -> m (Maybe Conversation)
+ Ollama: loadConversationInMemory :: MonadIO m => InMemoryStore -> Text -> m (Maybe Conversation)
+ Ollama: mkModelName :: Text -> Either Text ModelName
+ Ollama: mockChatResponse :: ModelName -> Text -> ChatResponse
+ Ollama: mockEmbedResponse :: ModelName -> [[Double]] -> EmbedResponse
+ Ollama: mockGenerateResponse :: ModelName -> Text -> GenerateResponse
+ Ollama: mockListModelsResponse :: [ModelName] -> ListResponse
+ Ollama: newClient :: MonadIO m => OllamaClientConfig -> m OllamaClient
+ Ollama: newMockClient :: MonadIO m => ByteString -> m OllamaClient
+ Ollama: newtype Base64Image
+ Ollama: newtype Digest
+ Ollama: newtype Duration
+ Ollama: newtype EmbeddingsResponse
+ Ollama: newtype InMemoryStore
+ Ollama: newtype ListResponse
+ Ollama: newtype ModelName
+ Ollama: newtype RunningModelsResponse
+ Ollama: promptEvalTokensPerSecond :: GenerateResponse -> Maybe Double
+ Ollama: pullStream :: MonadUnliftIO m => OllamaClient -> ModelName -> ConduitT () PullResponse m ()
+ Ollama: pushBlob :: MonadIO m => OllamaClient -> Digest -> ByteString -> m (Either OllamaError ())
+ Ollama: pushStream :: MonadUnliftIO m => OllamaClient -> ModelName -> ConduitT () PushResponse m ()
+ Ollama: saveConversation :: ConversationStore m => Conversation -> m ()
+ Ollama: saveConversationInMemory :: MonadIO m => InMemoryStore -> Conversation -> m ()
+ Ollama: systemMessage :: Text -> Message
+ Ollama: throwOllama :: OllamaError -> IO a
+ Ollama: tokensPerSecond :: Int -> Duration -> Double
+ Ollama: toolMessage :: Text -> Message
+ Ollama: toolResultMessage :: Text -> Text -> Message
+ Ollama: userMessage :: Text -> Message
+ Ollama: withClient :: MonadUnliftIO m => OllamaClientConfig -> (OllamaClient -> m a) -> m a
+ Ollama: withMockClient :: MonadUnliftIO m => ByteString -> (OllamaClient -> m a) -> m a
+ Ollama.API.Blobs: checkBlob :: MonadIO m => OllamaClient -> Digest -> m (Either OllamaError Bool)
+ Ollama.API.Blobs: pushBlob :: MonadIO m => OllamaClient -> Digest -> ByteString -> m (Either OllamaError ())
+ Ollama.API.Chat: ChatRequest :: !ModelName -> !NonEmpty Message -> !Maybe [Tool] -> !Maybe Format -> !Maybe ModelOptions -> !Maybe Bool -> !Maybe Text -> !Maybe Think -> ChatRequest
+ Ollama.API.Chat: ChatResponse :: !ModelName -> !UTCTime -> !Maybe Message -> !Bool -> !Maybe Text -> !Maybe Duration -> !Maybe Duration -> !Maybe Int -> !Maybe Duration -> !Maybe Int -> !Maybe Duration -> ChatResponse
+ Ollama.API.Chat: [chStream] :: ChatRequest -> !Maybe Bool
+ Ollama.API.Chat: [chatFormat] :: ChatRequest -> !Maybe Format
+ Ollama.API.Chat: [chatKeepAlive] :: ChatRequest -> !Maybe Text
+ Ollama.API.Chat: [chatMessages] :: ChatRequest -> !NonEmpty Message
+ Ollama.API.Chat: [chatModel] :: ChatRequest -> !ModelName
+ Ollama.API.Chat: [chatOptions] :: ChatRequest -> !Maybe ModelOptions
+ Ollama.API.Chat: [chatThink] :: ChatRequest -> !Maybe Think
+ Ollama.API.Chat: [chatTools] :: ChatRequest -> !Maybe [Tool]
+ Ollama.API.Chat: [crCreatedAt] :: ChatResponse -> !UTCTime
+ Ollama.API.Chat: [crDoneReason] :: ChatResponse -> !Maybe Text
+ Ollama.API.Chat: [crDone] :: ChatResponse -> !Bool
+ Ollama.API.Chat: [crEvalCount] :: ChatResponse -> !Maybe Int
+ Ollama.API.Chat: [crEvalDuration] :: ChatResponse -> !Maybe Duration
+ Ollama.API.Chat: [crLoadDuration] :: ChatResponse -> !Maybe Duration
+ Ollama.API.Chat: [crMessage] :: ChatResponse -> !Maybe Message
+ Ollama.API.Chat: [crModel] :: ChatResponse -> !ModelName
+ Ollama.API.Chat: [crPromptEvalCount] :: ChatResponse -> !Maybe Int
+ Ollama.API.Chat: [crPromptEvalDuration] :: ChatResponse -> !Maybe Duration
+ Ollama.API.Chat: [crTotalDuration] :: ChatResponse -> !Maybe Duration
+ Ollama.API.Chat: chat :: MonadIO m => OllamaClient -> ChatRequest -> m (Either OllamaError ChatResponse)
+ Ollama.API.Chat: chatEvalTokensPerSecond :: ChatResponse -> Maybe Double
+ Ollama.API.Chat: chatPromptEvalTokensPerSecond :: ChatResponse -> Maybe Double
+ Ollama.API.Chat: chatRequest :: ModelName -> NonEmpty Message -> ChatRequest
+ Ollama.API.Chat: chatStream :: MonadUnliftIO m => OllamaClient -> ChatRequest -> ConduitT () ChatResponse m ()
+ Ollama.API.Chat: data ChatRequest
+ Ollama.API.Chat: data ChatResponse
+ Ollama.API.Chat: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Chat.ChatResponse
+ Ollama.API.Chat: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Chat.ChatRequest
+ Ollama.API.Chat: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Chat.ChatResponse
+ Ollama.API.Chat: instance GHC.Classes.Eq Ollama.API.Chat.ChatRequest
+ Ollama.API.Chat: instance GHC.Classes.Eq Ollama.API.Chat.ChatResponse
+ Ollama.API.Chat: instance GHC.Generics.Generic Ollama.API.Chat.ChatRequest
+ Ollama.API.Chat: instance GHC.Generics.Generic Ollama.API.Chat.ChatResponse
+ Ollama.API.Chat: instance GHC.Show.Show Ollama.API.Chat.ChatRequest
+ Ollama.API.Chat: instance GHC.Show.Show Ollama.API.Chat.ChatResponse
+ Ollama.API.Chat: instance Ollama.Streaming.HasDone Ollama.API.Chat.ChatResponse
+ Ollama.API.Embed: EmbedRequest :: !ModelName -> !Either Text [Text] -> !Maybe Bool -> !Maybe ModelOptions -> !Maybe Text -> !Maybe Int -> EmbedRequest
+ Ollama.API.Embed: EmbedResponse :: !ModelName -> ![[Double]] -> !Maybe Duration -> !Maybe Duration -> !Maybe Int -> EmbedResponse
+ Ollama.API.Embed: EmbeddingsRequest :: !ModelName -> !Text -> !Maybe ModelOptions -> !Maybe Text -> EmbeddingsRequest
+ Ollama.API.Embed: EmbeddingsResponse :: [Double] -> EmbeddingsResponse
+ Ollama.API.Embed: [ebrEmbedding] :: EmbeddingsResponse -> [Double]
+ Ollama.API.Embed: [ebrKeepAlive] :: EmbeddingsRequest -> !Maybe Text
+ Ollama.API.Embed: [ebrModel] :: EmbeddingsRequest -> !ModelName
+ Ollama.API.Embed: [ebrOptions] :: EmbeddingsRequest -> !Maybe ModelOptions
+ Ollama.API.Embed: [ebrPrompt] :: EmbeddingsRequest -> !Text
+ Ollama.API.Embed: [embDimensions] :: EmbedRequest -> !Maybe Int
+ Ollama.API.Embed: [embInput] :: EmbedRequest -> !Either Text [Text]
+ Ollama.API.Embed: [embKeepAlive] :: EmbedRequest -> !Maybe Text
+ Ollama.API.Embed: [embModel] :: EmbedRequest -> !ModelName
+ Ollama.API.Embed: [embOptions] :: EmbedRequest -> !Maybe ModelOptions
+ Ollama.API.Embed: [embTruncate] :: EmbedRequest -> !Maybe Bool
+ Ollama.API.Embed: [erEmbeddings] :: EmbedResponse -> ![[Double]]
+ Ollama.API.Embed: [erLoadDuration] :: EmbedResponse -> !Maybe Duration
+ Ollama.API.Embed: [erModel] :: EmbedResponse -> !ModelName
+ Ollama.API.Embed: [erPromptEvalCount] :: EmbedResponse -> !Maybe Int
+ Ollama.API.Embed: [erTotalDuration] :: EmbedResponse -> !Maybe Duration
+ Ollama.API.Embed: data EmbedRequest
+ Ollama.API.Embed: data EmbedResponse
+ Ollama.API.Embed: data EmbeddingsRequest
+ Ollama.API.Embed: embed :: MonadIO m => OllamaClient -> EmbedRequest -> m (Either OllamaError EmbedResponse)
+ Ollama.API.Embed: embedRequest :: ModelName -> [Text] -> EmbedRequest
+ Ollama.API.Embed: embeddings :: MonadIO m => OllamaClient -> EmbeddingsRequest -> m (Either OllamaError EmbeddingsResponse)
+ Ollama.API.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Embed.EmbedResponse
+ Ollama.API.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Embed.EmbeddingsRequest
+ Ollama.API.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Embed.EmbeddingsResponse
+ Ollama.API.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Embed.EmbedRequest
+ Ollama.API.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Embed.EmbedResponse
+ Ollama.API.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Embed.EmbeddingsRequest
+ Ollama.API.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Embed.EmbeddingsResponse
+ Ollama.API.Embed: instance GHC.Classes.Eq Ollama.API.Embed.EmbedRequest
+ Ollama.API.Embed: instance GHC.Classes.Eq Ollama.API.Embed.EmbedResponse
+ Ollama.API.Embed: instance GHC.Classes.Eq Ollama.API.Embed.EmbeddingsRequest
+ Ollama.API.Embed: instance GHC.Classes.Eq Ollama.API.Embed.EmbeddingsResponse
+ Ollama.API.Embed: instance GHC.Generics.Generic Ollama.API.Embed.EmbedRequest
+ Ollama.API.Embed: instance GHC.Generics.Generic Ollama.API.Embed.EmbedResponse
+ Ollama.API.Embed: instance GHC.Generics.Generic Ollama.API.Embed.EmbeddingsRequest
+ Ollama.API.Embed: instance GHC.Generics.Generic Ollama.API.Embed.EmbeddingsResponse
+ Ollama.API.Embed: instance GHC.Show.Show Ollama.API.Embed.EmbedRequest
+ Ollama.API.Embed: instance GHC.Show.Show Ollama.API.Embed.EmbedResponse
+ Ollama.API.Embed: instance GHC.Show.Show Ollama.API.Embed.EmbeddingsRequest
+ Ollama.API.Embed: instance GHC.Show.Show Ollama.API.Embed.EmbeddingsResponse
+ Ollama.API.Embed: newtype EmbeddingsResponse
+ Ollama.API.Generate: GenerateRequest :: !ModelName -> !Text -> !Maybe Text -> !Maybe [Base64Image] -> !Maybe Format -> !Maybe ModelOptions -> !Maybe Text -> !Maybe Text -> !Maybe Bool -> !Maybe Bool -> !Maybe Text -> !Maybe Think -> !Maybe Int -> !Maybe Int -> !Maybe Int -> GenerateRequest
+ Ollama.API.Generate: GenerateResponse :: !ModelName -> !UTCTime -> !Text -> !Bool -> !Maybe Text -> !Maybe [Int] -> !Maybe Duration -> !Maybe Duration -> !Maybe Int -> !Maybe Duration -> !Maybe Int -> !Maybe Duration -> !Maybe Text -> !Maybe Base64Image -> GenerateResponse
+ Ollama.API.Generate: [genFormat] :: GenerateRequest -> !Maybe Format
+ Ollama.API.Generate: [genHeight] :: GenerateRequest -> !Maybe Int
+ Ollama.API.Generate: [genImages] :: GenerateRequest -> !Maybe [Base64Image]
+ Ollama.API.Generate: [genKeepAlive] :: GenerateRequest -> !Maybe Text
+ Ollama.API.Generate: [genModel] :: GenerateRequest -> !ModelName
+ Ollama.API.Generate: [genOptions] :: GenerateRequest -> !Maybe ModelOptions
+ Ollama.API.Generate: [genPrompt] :: GenerateRequest -> !Text
+ Ollama.API.Generate: [genRaw] :: GenerateRequest -> !Maybe Bool
+ Ollama.API.Generate: [genSteps] :: GenerateRequest -> !Maybe Int
+ Ollama.API.Generate: [genStream] :: GenerateRequest -> !Maybe Bool
+ Ollama.API.Generate: [genSuffix] :: GenerateRequest -> !Maybe Text
+ Ollama.API.Generate: [genSystem] :: GenerateRequest -> !Maybe Text
+ Ollama.API.Generate: [genTemplate] :: GenerateRequest -> !Maybe Text
+ Ollama.API.Generate: [genThink] :: GenerateRequest -> !Maybe Think
+ Ollama.API.Generate: [genWidth] :: GenerateRequest -> !Maybe Int
+ Ollama.API.Generate: [grContext] :: GenerateResponse -> !Maybe [Int]
+ Ollama.API.Generate: [grCreatedAt] :: GenerateResponse -> !UTCTime
+ Ollama.API.Generate: [grDoneReason] :: GenerateResponse -> !Maybe Text
+ Ollama.API.Generate: [grDone] :: GenerateResponse -> !Bool
+ Ollama.API.Generate: [grEvalCount] :: GenerateResponse -> !Maybe Int
+ Ollama.API.Generate: [grEvalDuration] :: GenerateResponse -> !Maybe Duration
+ Ollama.API.Generate: [grImage] :: GenerateResponse -> !Maybe Base64Image
+ Ollama.API.Generate: [grLoadDuration] :: GenerateResponse -> !Maybe Duration
+ Ollama.API.Generate: [grModel] :: GenerateResponse -> !ModelName
+ Ollama.API.Generate: [grPromptEvalCount] :: GenerateResponse -> !Maybe Int
+ Ollama.API.Generate: [grPromptEvalDuration] :: GenerateResponse -> !Maybe Duration
+ Ollama.API.Generate: [grResponse] :: GenerateResponse -> !Text
+ Ollama.API.Generate: [grThinking] :: GenerateResponse -> !Maybe Text
+ Ollama.API.Generate: [grTotalDuration] :: GenerateResponse -> !Maybe Duration
+ Ollama.API.Generate: data GenerateRequest
+ Ollama.API.Generate: data GenerateResponse
+ Ollama.API.Generate: evalTokensPerSecond :: GenerateResponse -> Maybe Double
+ Ollama.API.Generate: generate :: MonadIO m => OllamaClient -> GenerateRequest -> m (Either OllamaError GenerateResponse)
+ Ollama.API.Generate: generateRequest :: ModelName -> Text -> GenerateRequest
+ Ollama.API.Generate: generateStream :: MonadUnliftIO m => OllamaClient -> GenerateRequest -> ConduitT () GenerateResponse m ()
+ Ollama.API.Generate: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Generate.GenerateResponse
+ Ollama.API.Generate: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Generate.GenerateRequest
+ Ollama.API.Generate: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Generate.GenerateResponse
+ Ollama.API.Generate: instance GHC.Classes.Eq Ollama.API.Generate.GenerateRequest
+ Ollama.API.Generate: instance GHC.Classes.Eq Ollama.API.Generate.GenerateResponse
+ Ollama.API.Generate: instance GHC.Generics.Generic Ollama.API.Generate.GenerateRequest
+ Ollama.API.Generate: instance GHC.Generics.Generic Ollama.API.Generate.GenerateResponse
+ Ollama.API.Generate: instance GHC.Show.Show Ollama.API.Generate.GenerateRequest
+ Ollama.API.Generate: instance GHC.Show.Show Ollama.API.Generate.GenerateResponse
+ Ollama.API.Generate: instance Ollama.Streaming.HasDone Ollama.API.Generate.GenerateResponse
+ Ollama.API.Generate: promptEvalTokensPerSecond :: GenerateResponse -> Maybe Double
+ Ollama.API.Models: CopyRequest :: !ModelName -> !ModelName -> CopyRequest
+ Ollama.API.Models: DeleteRequest :: ModelName -> DeleteRequest
+ Ollama.API.Models: ListResponse :: [ModelInfo] -> ListResponse
+ Ollama.API.Models: ShowModelInfo :: Map Text Value -> ShowModelInfo
+ Ollama.API.Models: ShowRequest :: !ModelName -> !Maybe Bool -> ShowRequest
+ Ollama.API.Models: ShowResponse :: !Text -> !Maybe Text -> !Maybe Text -> !ModelDetails -> !Maybe ShowModelInfo -> !Maybe Text -> !Maybe [Text] -> ShowResponse
+ Ollama.API.Models: [cpDestination] :: CopyRequest -> !ModelName
+ Ollama.API.Models: [cpSource] :: CopyRequest -> !ModelName
+ Ollama.API.Models: [delModel] :: DeleteRequest -> ModelName
+ Ollama.API.Models: [modelInfoMap] :: ShowModelInfo -> Map Text Value
+ Ollama.API.Models: [models] :: ListResponse -> [ModelInfo]
+ Ollama.API.Models: [srqModel] :: ShowRequest -> !ModelName
+ Ollama.API.Models: [srqVerbose] :: ShowRequest -> !Maybe Bool
+ Ollama.API.Models: [srsCapabilities] :: ShowResponse -> !Maybe [Text]
+ Ollama.API.Models: [srsDetails] :: ShowResponse -> !ModelDetails
+ Ollama.API.Models: [srsLicense] :: ShowResponse -> !Maybe Text
+ Ollama.API.Models: [srsModelInfo] :: ShowResponse -> !Maybe ShowModelInfo
+ Ollama.API.Models: [srsModelfile] :: ShowResponse -> !Text
+ Ollama.API.Models: [srsParameters] :: ShowResponse -> !Maybe Text
+ Ollama.API.Models: [srsTemplate] :: ShowResponse -> !Maybe Text
+ Ollama.API.Models: copyModel :: MonadIO m => OllamaClient -> ModelName -> ModelName -> m (Either OllamaError ())
+ Ollama.API.Models: data CopyRequest
+ Ollama.API.Models: data ShowRequest
+ Ollama.API.Models: data ShowResponse
+ Ollama.API.Models: deleteModel :: MonadIO m => OllamaClient -> ModelName -> m (Either OllamaError ())
+ Ollama.API.Models: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Models.ShowModelInfo
+ Ollama.API.Models: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Models.ShowResponse
+ Ollama.API.Models: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.CopyRequest
+ Ollama.API.Models: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.DeleteRequest
+ Ollama.API.Models: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.ShowModelInfo
+ Ollama.API.Models: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.ShowRequest
+ Ollama.API.Models: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.ShowResponse
+ Ollama.API.Models: instance GHC.Classes.Eq Ollama.API.Models.CopyRequest
+ Ollama.API.Models: instance GHC.Classes.Eq Ollama.API.Models.DeleteRequest
+ Ollama.API.Models: instance GHC.Classes.Eq Ollama.API.Models.ShowModelInfo
+ Ollama.API.Models: instance GHC.Classes.Eq Ollama.API.Models.ShowRequest
+ Ollama.API.Models: instance GHC.Classes.Eq Ollama.API.Models.ShowResponse
+ Ollama.API.Models: instance GHC.Generics.Generic Ollama.API.Models.CopyRequest
+ Ollama.API.Models: instance GHC.Generics.Generic Ollama.API.Models.DeleteRequest
+ Ollama.API.Models: instance GHC.Generics.Generic Ollama.API.Models.ShowModelInfo
+ Ollama.API.Models: instance GHC.Generics.Generic Ollama.API.Models.ShowRequest
+ Ollama.API.Models: instance GHC.Generics.Generic Ollama.API.Models.ShowResponse
+ Ollama.API.Models: instance GHC.Show.Show Ollama.API.Models.CopyRequest
+ Ollama.API.Models: instance GHC.Show.Show Ollama.API.Models.DeleteRequest
+ Ollama.API.Models: instance GHC.Show.Show Ollama.API.Models.ShowModelInfo
+ Ollama.API.Models: instance GHC.Show.Show Ollama.API.Models.ShowRequest
+ Ollama.API.Models: instance GHC.Show.Show Ollama.API.Models.ShowResponse
+ Ollama.API.Models: listModels :: MonadIO m => OllamaClient -> m (Either OllamaError ListResponse)
+ Ollama.API.Models: newtype DeleteRequest
+ Ollama.API.Models: newtype ListResponse
+ Ollama.API.Models: newtype ShowModelInfo
+ Ollama.API.Models: showModel :: MonadIO m => OllamaClient -> ModelName -> m (Either OllamaError ShowResponse)
+ Ollama.API.Models.Create: CreateRequest :: !ModelName -> !Maybe ModelName -> !Maybe (Map Text Digest) -> !Maybe (Map Text Digest) -> !Maybe Text -> !Maybe Text -> !Maybe Text -> !Maybe [Text] -> !Maybe Text -> !Maybe ModelOptions -> !Maybe [Message] -> !Maybe Bool -> !Maybe QuantizationType -> CreateRequest
+ Ollama.API.Models.Create: CreateResponse :: !Text -> !Maybe Digest -> !Maybe Int64 -> !Maybe Int64 -> CreateResponse
+ Ollama.API.Models.Create: Q4_K_M :: QuantizationType
+ Ollama.API.Models.Create: Q4_K_S :: QuantizationType
+ Ollama.API.Models.Create: Q8_0 :: QuantizationType
+ Ollama.API.Models.Create: [crqAdapters] :: CreateRequest -> !Maybe (Map Text Digest)
+ Ollama.API.Models.Create: [crqFiles] :: CreateRequest -> !Maybe (Map Text Digest)
+ Ollama.API.Models.Create: [crqFrom] :: CreateRequest -> !Maybe ModelName
+ Ollama.API.Models.Create: [crqLicense] :: CreateRequest -> !Maybe [Text]
+ Ollama.API.Models.Create: [crqMessages] :: CreateRequest -> !Maybe [Message]
+ Ollama.API.Models.Create: [crqModel] :: CreateRequest -> !ModelName
+ Ollama.API.Models.Create: [crqParameters] :: CreateRequest -> !Maybe ModelOptions
+ Ollama.API.Models.Create: [crqParser] :: CreateRequest -> !Maybe Text
+ Ollama.API.Models.Create: [crqQuantize] :: CreateRequest -> !Maybe QuantizationType
+ Ollama.API.Models.Create: [crqRenderer] :: CreateRequest -> !Maybe Text
+ Ollama.API.Models.Create: [crqStream] :: CreateRequest -> !Maybe Bool
+ Ollama.API.Models.Create: [crqSystem] :: CreateRequest -> !Maybe Text
+ Ollama.API.Models.Create: [crqTemplate] :: CreateRequest -> !Maybe Text
+ Ollama.API.Models.Create: [crsCompleted] :: CreateResponse -> !Maybe Int64
+ Ollama.API.Models.Create: [crsDigest] :: CreateResponse -> !Maybe Digest
+ Ollama.API.Models.Create: [crsStatus] :: CreateResponse -> !Text
+ Ollama.API.Models.Create: [crsTotal] :: CreateResponse -> !Maybe Int64
+ Ollama.API.Models.Create: createModel :: MonadIO m => OllamaClient -> CreateRequest -> m (Either OllamaError CreateResponse)
+ Ollama.API.Models.Create: createModelStream :: MonadUnliftIO m => OllamaClient -> CreateRequest -> ConduitT () CreateResponse m ()
+ Ollama.API.Models.Create: data CreateRequest
+ Ollama.API.Models.Create: data CreateResponse
+ Ollama.API.Models.Create: data QuantizationType
+ Ollama.API.Models.Create: defaultCreateRequest :: ModelName -> CreateRequest
+ Ollama.API.Models.Create: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Models.Create.CreateResponse
+ Ollama.API.Models.Create: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Models.Create.QuantizationType
+ Ollama.API.Models.Create: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.Create.CreateRequest
+ Ollama.API.Models.Create: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.Create.CreateResponse
+ Ollama.API.Models.Create: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.Create.QuantizationType
+ Ollama.API.Models.Create: instance GHC.Classes.Eq Ollama.API.Models.Create.CreateRequest
+ Ollama.API.Models.Create: instance GHC.Classes.Eq Ollama.API.Models.Create.CreateResponse
+ Ollama.API.Models.Create: instance GHC.Classes.Eq Ollama.API.Models.Create.QuantizationType
+ Ollama.API.Models.Create: instance GHC.Enum.Bounded Ollama.API.Models.Create.QuantizationType
+ Ollama.API.Models.Create: instance GHC.Enum.Enum Ollama.API.Models.Create.QuantizationType
+ Ollama.API.Models.Create: instance GHC.Generics.Generic Ollama.API.Models.Create.CreateRequest
+ Ollama.API.Models.Create: instance GHC.Generics.Generic Ollama.API.Models.Create.CreateResponse
+ Ollama.API.Models.Create: instance GHC.Generics.Generic Ollama.API.Models.Create.QuantizationType
+ Ollama.API.Models.Create: instance GHC.Show.Show Ollama.API.Models.Create.CreateRequest
+ Ollama.API.Models.Create: instance GHC.Show.Show Ollama.API.Models.Create.CreateResponse
+ Ollama.API.Models.Create: instance GHC.Show.Show Ollama.API.Models.Create.QuantizationType
+ Ollama.API.Models.Create: instance Ollama.Streaming.HasDone Ollama.API.Models.Create.CreateResponse
+ Ollama.API.Models.Pull: PullRequest :: !ModelName -> !Maybe Bool -> !Maybe Bool -> PullRequest
+ Ollama.API.Models.Pull: PullResponse :: !Text -> !Maybe Digest -> !Maybe Int64 -> !Maybe Int64 -> PullResponse
+ Ollama.API.Models.Pull: [prCompleted] :: PullResponse -> !Maybe Int64
+ Ollama.API.Models.Pull: [prDigest] :: PullResponse -> !Maybe Digest
+ Ollama.API.Models.Pull: [prStatus] :: PullResponse -> !Text
+ Ollama.API.Models.Pull: [prTotal] :: PullResponse -> !Maybe Int64
+ Ollama.API.Models.Pull: [prqInsecure] :: PullRequest -> !Maybe Bool
+ Ollama.API.Models.Pull: [prqModel] :: PullRequest -> !ModelName
+ Ollama.API.Models.Pull: [prqStream] :: PullRequest -> !Maybe Bool
+ Ollama.API.Models.Pull: data PullRequest
+ Ollama.API.Models.Pull: data PullResponse
+ Ollama.API.Models.Pull: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Models.Pull.PullResponse
+ Ollama.API.Models.Pull: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.Pull.PullRequest
+ Ollama.API.Models.Pull: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.Pull.PullResponse
+ Ollama.API.Models.Pull: instance GHC.Classes.Eq Ollama.API.Models.Pull.PullRequest
+ Ollama.API.Models.Pull: instance GHC.Classes.Eq Ollama.API.Models.Pull.PullResponse
+ Ollama.API.Models.Pull: instance GHC.Generics.Generic Ollama.API.Models.Pull.PullRequest
+ Ollama.API.Models.Pull: instance GHC.Generics.Generic Ollama.API.Models.Pull.PullResponse
+ Ollama.API.Models.Pull: instance GHC.Show.Show Ollama.API.Models.Pull.PullRequest
+ Ollama.API.Models.Pull: instance GHC.Show.Show Ollama.API.Models.Pull.PullResponse
+ Ollama.API.Models.Pull: instance Ollama.Streaming.HasDone Ollama.API.Models.Pull.PullResponse
+ Ollama.API.Models.Pull: pull :: MonadIO m => OllamaClient -> ModelName -> m (Either OllamaError PullResponse)
+ Ollama.API.Models.Pull: pullStream :: MonadUnliftIO m => OllamaClient -> ModelName -> ConduitT () PullResponse m ()
+ Ollama.API.Models.Push: PushRequest :: !ModelName -> !Maybe Bool -> !Maybe Bool -> PushRequest
+ Ollama.API.Models.Push: PushResponse :: !Text -> !Maybe Digest -> !Maybe Int64 -> !Maybe Int64 -> PushResponse
+ Ollama.API.Models.Push: [psCompleted] :: PushResponse -> !Maybe Int64
+ Ollama.API.Models.Push: [psDigest] :: PushResponse -> !Maybe Digest
+ Ollama.API.Models.Push: [psStatus] :: PushResponse -> !Text
+ Ollama.API.Models.Push: [psTotal] :: PushResponse -> !Maybe Int64
+ Ollama.API.Models.Push: [psqInsecure] :: PushRequest -> !Maybe Bool
+ Ollama.API.Models.Push: [psqModel] :: PushRequest -> !ModelName
+ Ollama.API.Models.Push: [psqStream] :: PushRequest -> !Maybe Bool
+ Ollama.API.Models.Push: data PushRequest
+ Ollama.API.Models.Push: data PushResponse
+ Ollama.API.Models.Push: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.API.Models.Push.PushResponse
+ Ollama.API.Models.Push: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.Push.PushRequest
+ Ollama.API.Models.Push: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.API.Models.Push.PushResponse
+ Ollama.API.Models.Push: instance GHC.Classes.Eq Ollama.API.Models.Push.PushRequest
+ Ollama.API.Models.Push: instance GHC.Classes.Eq Ollama.API.Models.Push.PushResponse
+ Ollama.API.Models.Push: instance GHC.Generics.Generic Ollama.API.Models.Push.PushRequest
+ Ollama.API.Models.Push: instance GHC.Generics.Generic Ollama.API.Models.Push.PushResponse
+ Ollama.API.Models.Push: instance GHC.Show.Show Ollama.API.Models.Push.PushRequest
+ Ollama.API.Models.Push: instance GHC.Show.Show Ollama.API.Models.Push.PushResponse
+ Ollama.API.Models.Push: instance Ollama.Streaming.HasDone Ollama.API.Models.Push.PushResponse
+ Ollama.API.Models.Push: push :: MonadIO m => OllamaClient -> ModelName -> m (Either OllamaError PushResponse)
+ Ollama.API.Models.Push: pushStream :: MonadUnliftIO m => OllamaClient -> ModelName -> ConduitT () PushResponse m ()
+ Ollama.API.Ps: RunningModel :: !ModelName -> !ModelName -> !Int64 -> !Digest -> !ModelDetails -> !UTCTime -> !Int64 -> RunningModel
+ Ollama.API.Ps: RunningModelsResponse :: [RunningModel] -> RunningModelsResponse
+ Ollama.API.Ps: [rmDetails] :: RunningModel -> !ModelDetails
+ Ollama.API.Ps: [rmDigest] :: RunningModel -> !Digest
+ Ollama.API.Ps: [rmExpiresAt] :: RunningModel -> !UTCTime
+ Ollama.API.Ps: [rmModel] :: RunningModel -> !ModelName
+ Ollama.API.Ps: [rmName] :: RunningModel -> !ModelName
+ Ollama.API.Ps: [rmSizeVram] :: RunningModel -> !Int64
+ Ollama.API.Ps: [rmSize] :: RunningModel -> !Int64
+ Ollama.API.Ps: [runningModels] :: RunningModelsResponse -> [RunningModel]
+ Ollama.API.Ps: data RunningModel
+ Ollama.API.Ps: listRunning :: MonadIO m => OllamaClient -> m (Either OllamaError RunningModelsResponse)
+ Ollama.API.Ps: newtype RunningModelsResponse
+ Ollama.API.Version: Version :: Text -> Version
+ Ollama.API.Version: [unVersion] :: Version -> Text
+ Ollama.API.Version: getVersion :: MonadIO m => OllamaClient -> m (Either OllamaError Version)
+ Ollama.API.Version: newtype Version
+ Ollama.Client: OllamaClient :: !Manager -> !OllamaClientConfig -> !Bool -> OllamaClient
+ Ollama.Client: [clientConfig] :: OllamaClient -> !OllamaClientConfig
+ Ollama.Client: [clientManager] :: OllamaClient -> !Manager
+ Ollama.Client: [clientOwned] :: OllamaClient -> !Bool
+ Ollama.Client: clientFromEnv :: MonadIO m => m OllamaClient
+ Ollama.Client: closeClient :: MonadIO m => OllamaClient -> m ()
+ Ollama.Client: data OllamaClient
+ Ollama.Client: defaultClient :: MonadIO m => m OllamaClient
+ Ollama.Client: newClient :: MonadIO m => OllamaClientConfig -> m OllamaClient
+ Ollama.Client: withClient :: MonadUnliftIO m => OllamaClientConfig -> (OllamaClient -> m a) -> m a
+ Ollama.Client.Config: ConstantRetry :: !Int -> !Int -> RetryPolicy
+ Ollama.Client.Config: Debug :: LogLevel
+ Ollama.Client.Config: Error :: LogLevel
+ Ollama.Client.Config: ExponentialRetry :: !Int -> !Int -> RetryPolicy
+ Ollama.Client.Config: Info :: LogLevel
+ Ollama.Client.Config: NoRetry :: RetryPolicy
+ Ollama.Client.Config: OllamaClientConfig :: !Text -> !Int -> !RetryPolicy -> !Maybe Manager -> ![(CI ByteString, ByteString)] -> !Maybe Text -> !Maybe (LogLevel -> Text -> IO ()) -> !Maybe (IO ()) -> !Maybe (IO ()) -> !Maybe (IO ()) -> OllamaClientConfig
+ Ollama.Client.Config: Warn :: LogLevel
+ Ollama.Client.Config: [configApiKey] :: OllamaClientConfig -> !Maybe Text
+ Ollama.Client.Config: [configBaseUrl] :: OllamaClientConfig -> !Text
+ Ollama.Client.Config: [configHeaders] :: OllamaClientConfig -> ![(CI ByteString, ByteString)]
+ Ollama.Client.Config: [configLogger] :: OllamaClientConfig -> !Maybe (LogLevel -> Text -> IO ())
+ Ollama.Client.Config: [configManager] :: OllamaClientConfig -> !Maybe Manager
+ Ollama.Client.Config: [configOnError] :: OllamaClientConfig -> !Maybe (IO ())
+ Ollama.Client.Config: [configOnStart] :: OllamaClientConfig -> !Maybe (IO ())
+ Ollama.Client.Config: [configOnSuccess] :: OllamaClientConfig -> !Maybe (IO ())
+ Ollama.Client.Config: [configRetry] :: OllamaClientConfig -> !RetryPolicy
+ Ollama.Client.Config: [configTimeout] :: OllamaClientConfig -> !Int
+ Ollama.Client.Config: constantRetry :: Int -> Int -> RetryPolicy
+ Ollama.Client.Config: data LogLevel
+ Ollama.Client.Config: data OllamaClientConfig
+ Ollama.Client.Config: data RetryPolicy
+ Ollama.Client.Config: defaultConfig :: OllamaClientConfig
+ Ollama.Client.Config: exponentialRetry :: Int -> Int -> RetryPolicy
+ Ollama.Client.Config: instance GHC.Classes.Eq Ollama.Client.Config.LogLevel
+ Ollama.Client.Config: instance GHC.Classes.Eq Ollama.Client.Config.RetryPolicy
+ Ollama.Client.Config: instance GHC.Classes.Ord Ollama.Client.Config.LogLevel
+ Ollama.Client.Config: instance GHC.Enum.Bounded Ollama.Client.Config.LogLevel
+ Ollama.Client.Config: instance GHC.Enum.Enum Ollama.Client.Config.LogLevel
+ Ollama.Client.Config: instance GHC.Show.Show Ollama.Client.Config.LogLevel
+ Ollama.Client.Config: instance GHC.Show.Show Ollama.Client.Config.RetryPolicy
+ Ollama.Client.Config: noRetry :: RetryPolicy
+ Ollama.Conversation: Conversation :: !Text -> ![Message] -> !ModelName -> !UTCTime -> !UTCTime -> Conversation
+ Ollama.Conversation: InMemoryStore :: TVar (Map Text Conversation) -> InMemoryStore
+ Ollama.Conversation: [conversationId] :: Conversation -> !Text
+ Ollama.Conversation: [createdAt] :: Conversation -> !UTCTime
+ Ollama.Conversation: [lastUpdated] :: Conversation -> !UTCTime
+ Ollama.Conversation: [messages] :: Conversation -> ![Message]
+ Ollama.Conversation: [model] :: Conversation -> !ModelName
+ Ollama.Conversation: class (Monad m) => ConversationStore m
+ Ollama.Conversation: data Conversation
+ Ollama.Conversation: deleteConversation :: ConversationStore m => Text -> m Bool
+ Ollama.Conversation: deleteConversationInMemory :: MonadIO m => InMemoryStore -> Text -> m Bool
+ Ollama.Conversation: initInMemoryStore :: IO InMemoryStore
+ Ollama.Conversation: instance Control.Monad.IO.Class.MonadIO m => Ollama.Conversation.ConversationStore (Control.Monad.Trans.Reader.ReaderT Ollama.Conversation.InMemoryStore m)
+ Ollama.Conversation: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Conversation.Conversation
+ Ollama.Conversation: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Conversation.Conversation
+ Ollama.Conversation: instance GHC.Classes.Eq Ollama.Conversation.Conversation
+ Ollama.Conversation: instance GHC.Generics.Generic Ollama.Conversation.Conversation
+ Ollama.Conversation: instance GHC.Show.Show Ollama.Conversation.Conversation
+ Ollama.Conversation: listConversations :: ConversationStore m => m [Conversation]
+ Ollama.Conversation: listConversationsInMemory :: MonadIO m => InMemoryStore -> m [Conversation]
+ Ollama.Conversation: loadConversation :: ConversationStore m => Text -> m (Maybe Conversation)
+ Ollama.Conversation: loadConversationInMemory :: MonadIO m => InMemoryStore -> Text -> m (Maybe Conversation)
+ Ollama.Conversation: newtype InMemoryStore
+ Ollama.Conversation: saveConversation :: ConversationStore m => Conversation -> m ()
+ Ollama.Conversation: saveConversationInMemory :: MonadIO m => InMemoryStore -> Conversation -> m ()
+ Ollama.Error: ApiError :: !Int -> !Text -> OllamaError
+ Ollama.Error: DecodeError :: !Text -> !ByteString -> OllamaError
+ Ollama.Error: HttpError :: !HttpException -> OllamaError
+ Ollama.Error: InvalidRequest :: !Text -> OllamaError
+ Ollama.Error: TimeoutError :: OllamaError
+ Ollama.Error: data OllamaError
+ Ollama.Error: instance GHC.Classes.Eq Ollama.Error.OllamaError
+ Ollama.Error: instance GHC.Exception.Type.Exception Ollama.Error.OllamaError
+ Ollama.Error: instance GHC.Show.Show Ollama.Error.OllamaError
+ Ollama.Error: isRetryable :: OllamaError -> Bool
+ Ollama.Error: throwOllama :: OllamaError -> IO a
+ Ollama.Streaming: class HasDone a
+ Ollama.Streaming: collectStream :: MonadUnliftIO m => ConduitT () a m () -> m [a]
+ Ollama.Streaming: foldStream :: MonadUnliftIO m => (b -> a -> b) -> b -> ConduitT () a m () -> m b
+ Ollama.Streaming: isDone :: HasDone a => a -> Bool
+ Ollama.Testing: mockChatResponse :: ModelName -> Text -> ChatResponse
+ Ollama.Testing: mockEmbedResponse :: ModelName -> [[Double]] -> EmbedResponse
+ Ollama.Testing: mockGenerateResponse :: ModelName -> Text -> GenerateResponse
+ Ollama.Testing: mockListModelsResponse :: [ModelName] -> ListResponse
+ Ollama.Testing: newMockClient :: MonadIO m => ByteString -> m OllamaClient
+ Ollama.Testing: withMockClient :: MonadUnliftIO m => ByteString -> (OllamaClient -> m a) -> m a
+ Ollama.Types: Assistant :: Role
+ Ollama.Types: FunctionDef :: !Text -> !Maybe Text -> !Maybe FunctionParameters -> !Maybe Bool -> FunctionDef
+ Ollama.Types: FunctionParameters :: !Text -> !Maybe (Map Text FunctionParameters) -> !Maybe [Text] -> !Maybe Bool -> !Maybe Text -> !Maybe [Text] -> FunctionParameters
+ Ollama.Types: Message :: !Role -> !Text -> !Maybe [Base64Image] -> !Maybe [ToolCall] -> !Maybe Text -> !Maybe Text -> Message
+ Ollama.Types: System :: Role
+ Ollama.Types: Tool :: !Text -> !FunctionDef -> Tool
+ Ollama.Types: ToolCall :: ToolCallFunction -> ToolCall
+ Ollama.Types: ToolCallFunction :: !Text -> !Map Text Value -> ToolCallFunction
+ Ollama.Types: User :: Role
+ Ollama.Types: [fnDescription] :: FunctionDef -> !Maybe Text
+ Ollama.Types: [fnName] :: FunctionDef -> !Text
+ Ollama.Types: [fnParameters] :: FunctionDef -> !Maybe FunctionParameters
+ Ollama.Types: [fnStrict] :: FunctionDef -> !Maybe Bool
+ Ollama.Types: [fpAdditionalProperties] :: FunctionParameters -> !Maybe Bool
+ Ollama.Types: [fpDescription] :: FunctionParameters -> !Maybe Text
+ Ollama.Types: [fpEnum] :: FunctionParameters -> !Maybe [Text]
+ Ollama.Types: [fpProperties] :: FunctionParameters -> !Maybe (Map Text FunctionParameters)
+ Ollama.Types: [fpRequired] :: FunctionParameters -> !Maybe [Text]
+ Ollama.Types: [fpType] :: FunctionParameters -> !Text
+ Ollama.Types: [messageContent] :: Message -> !Text
+ Ollama.Types: [messageImages] :: Message -> !Maybe [Base64Image]
+ Ollama.Types: [messageRole] :: Message -> !Role
+ Ollama.Types: [messageThinking] :: Message -> !Maybe Text
+ Ollama.Types: [messageToolCalls] :: Message -> !Maybe [ToolCall]
+ Ollama.Types: [messageToolName] :: Message -> !Maybe Text
+ Ollama.Types: [tcFunction] :: ToolCall -> ToolCallFunction
+ Ollama.Types: [tcfArguments] :: ToolCallFunction -> !Map Text Value
+ Ollama.Types: [tcfName] :: ToolCallFunction -> !Text
+ Ollama.Types: [toolFunction] :: Tool -> !FunctionDef
+ Ollama.Types: [toolType] :: Tool -> !Text
+ Ollama.Types: assistantMessage :: Text -> Message
+ Ollama.Types: data FunctionDef
+ Ollama.Types: data FunctionParameters
+ Ollama.Types: data Message
+ Ollama.Types: data Role
+ Ollama.Types: data Tool
+ Ollama.Types: data ToolCallFunction
+ Ollama.Types: imageMessage :: Text -> [Base64Image] -> Message
+ Ollama.Types: newtype ToolCall
+ Ollama.Types: systemMessage :: Text -> Message
+ Ollama.Types: toolMessage :: Text -> Message
+ Ollama.Types: toolResultMessage :: Text -> Text -> Message
+ Ollama.Types: userMessage :: Text -> Message
+ Ollama.Types.Common: Base64Image :: Text -> Base64Image
+ Ollama.Types.Common: Digest :: Text -> Digest
+ Ollama.Types.Common: Duration :: Int64 -> Duration
+ Ollama.Types.Common: ModelName :: Text -> ModelName
+ Ollama.Types.Common: ThinkDisabled :: Think
+ Ollama.Types.Common: ThinkEnabled :: Think
+ Ollama.Types.Common: ThinkHigh :: ThinkingLevel
+ Ollama.Types.Common: ThinkLevel :: !ThinkingLevel -> Think
+ Ollama.Types.Common: ThinkLow :: ThinkingLevel
+ Ollama.Types.Common: ThinkMax :: ThinkingLevel
+ Ollama.Types.Common: ThinkMedium :: ThinkingLevel
+ Ollama.Types.Common: Version :: Text -> Version
+ Ollama.Types.Common: [durationNanos] :: Duration -> Int64
+ Ollama.Types.Common: [unBase64Image] :: Base64Image -> Text
+ Ollama.Types.Common: [unDigest] :: Digest -> Text
+ Ollama.Types.Common: [unModelName] :: ModelName -> Text
+ Ollama.Types.Common: [unVersion] :: Version -> Text
+ Ollama.Types.Common: data Think
+ Ollama.Types.Common: data ThinkingLevel
+ Ollama.Types.Common: durationToMillis :: Duration -> Double
+ Ollama.Types.Common: durationToSeconds :: Duration -> Double
+ Ollama.Types.Common: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Common.Base64Image
+ Ollama.Types.Common: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Common.Digest
+ Ollama.Types.Common: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Common.Duration
+ Ollama.Types.Common: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Common.ModelName
+ Ollama.Types.Common: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Common.Think
+ Ollama.Types.Common: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Common.ThinkingLevel
+ Ollama.Types.Common: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Common.Version
+ Ollama.Types.Common: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Common.Base64Image
+ Ollama.Types.Common: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Common.Digest
+ Ollama.Types.Common: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Common.Duration
+ Ollama.Types.Common: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Common.ModelName
+ Ollama.Types.Common: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Common.Think
+ Ollama.Types.Common: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Common.ThinkingLevel
+ Ollama.Types.Common: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Common.Version
+ Ollama.Types.Common: instance Data.Hashable.Class.Hashable Ollama.Types.Common.Digest
+ Ollama.Types.Common: instance Data.Hashable.Class.Hashable Ollama.Types.Common.ModelName
+ Ollama.Types.Common: instance Data.String.IsString Ollama.Types.Common.ModelName
+ Ollama.Types.Common: instance GHC.Classes.Eq Ollama.Types.Common.Base64Image
+ Ollama.Types.Common: instance GHC.Classes.Eq Ollama.Types.Common.Digest
+ Ollama.Types.Common: instance GHC.Classes.Eq Ollama.Types.Common.Duration
+ Ollama.Types.Common: instance GHC.Classes.Eq Ollama.Types.Common.ModelName
+ Ollama.Types.Common: instance GHC.Classes.Eq Ollama.Types.Common.Think
+ Ollama.Types.Common: instance GHC.Classes.Eq Ollama.Types.Common.ThinkingLevel
+ Ollama.Types.Common: instance GHC.Classes.Eq Ollama.Types.Common.Version
+ Ollama.Types.Common: instance GHC.Classes.Ord Ollama.Types.Common.Digest
+ Ollama.Types.Common: instance GHC.Classes.Ord Ollama.Types.Common.Duration
+ Ollama.Types.Common: instance GHC.Classes.Ord Ollama.Types.Common.ModelName
+ Ollama.Types.Common: instance GHC.Enum.Bounded Ollama.Types.Common.ThinkingLevel
+ Ollama.Types.Common: instance GHC.Enum.Enum Ollama.Types.Common.ThinkingLevel
+ Ollama.Types.Common: instance GHC.Generics.Generic Ollama.Types.Common.Think
+ Ollama.Types.Common: instance GHC.Generics.Generic Ollama.Types.Common.ThinkingLevel
+ Ollama.Types.Common: instance GHC.Generics.Generic Ollama.Types.Common.Version
+ Ollama.Types.Common: instance GHC.Num.Num Ollama.Types.Common.Duration
+ Ollama.Types.Common: instance GHC.Show.Show Ollama.Types.Common.Base64Image
+ Ollama.Types.Common: instance GHC.Show.Show Ollama.Types.Common.Digest
+ Ollama.Types.Common: instance GHC.Show.Show Ollama.Types.Common.Duration
+ Ollama.Types.Common: instance GHC.Show.Show Ollama.Types.Common.ModelName
+ Ollama.Types.Common: instance GHC.Show.Show Ollama.Types.Common.Think
+ Ollama.Types.Common: instance GHC.Show.Show Ollama.Types.Common.ThinkingLevel
+ Ollama.Types.Common: instance GHC.Show.Show Ollama.Types.Common.Version
+ Ollama.Types.Common: mkModelName :: Text -> Either Text ModelName
+ Ollama.Types.Common: newtype Base64Image
+ Ollama.Types.Common: newtype Digest
+ Ollama.Types.Common: newtype Duration
+ Ollama.Types.Common: newtype ModelName
+ Ollama.Types.Common: newtype Version
+ Ollama.Types.Common: tokensPerSecond :: Int -> Duration -> Double
+ Ollama.Types.Format: JsonFormat :: Format
+ Ollama.Types.Format: SchemaFormat :: !Schema -> Format
+ Ollama.Types.Format: data Format
+ Ollama.Types.Format: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Format.Format
+ Ollama.Types.Format: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Format.Format
+ Ollama.Types.Format: instance GHC.Classes.Eq Ollama.Types.Format.Format
+ Ollama.Types.Format: instance GHC.Show.Show Ollama.Types.Format.Format
+ Ollama.Types.Format.SchemaBuilder: (|!!) :: SchemaBuilder -> [Text] -> SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: (|!) :: SchemaBuilder -> Text -> SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: (|+) :: SchemaBuilder -> (Text, JsonType) -> SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: (|++) :: SchemaBuilder -> (Text, Schema) -> SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: JArray :: !JsonType -> JsonType
+ Ollama.Types.Format.SchemaBuilder: JBoolean :: JsonType
+ Ollama.Types.Format.SchemaBuilder: JInteger :: JsonType
+ Ollama.Types.Format.SchemaBuilder: JNull :: JsonType
+ Ollama.Types.Format.SchemaBuilder: JNumber :: JsonType
+ Ollama.Types.Format.SchemaBuilder: JObject :: !Schema -> JsonType
+ Ollama.Types.Format.SchemaBuilder: JString :: JsonType
+ Ollama.Types.Format.SchemaBuilder: Property :: JsonType -> Property
+ Ollama.Types.Format.SchemaBuilder: Schema :: !Map Text Property -> ![Text] -> Schema
+ Ollama.Types.Format.SchemaBuilder: [schemaProperties] :: Schema -> !Map Text Property
+ Ollama.Types.Format.SchemaBuilder: [schemaRequired] :: Schema -> ![Text]
+ Ollama.Types.Format.SchemaBuilder: addObjectProperty :: Text -> Schema -> SchemaBuilder -> SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: addProperty :: Text -> JsonType -> SchemaBuilder -> SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: arrayOf :: JsonType -> JsonType
+ Ollama.Types.Format.SchemaBuilder: buildSchema :: SchemaBuilder -> Schema
+ Ollama.Types.Format.SchemaBuilder: data JsonType
+ Ollama.Types.Format.SchemaBuilder: data Schema
+ Ollama.Types.Format.SchemaBuilder: data SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: emptyObject :: SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: infixl 6 |!!
+ Ollama.Types.Format.SchemaBuilder: infixl 7 |++
+ Ollama.Types.Format.SchemaBuilder: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Format.SchemaBuilder.JsonType
+ Ollama.Types.Format.SchemaBuilder: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Format.SchemaBuilder.Property
+ Ollama.Types.Format.SchemaBuilder: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Format.SchemaBuilder.Schema
+ Ollama.Types.Format.SchemaBuilder: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Format.SchemaBuilder.JsonType
+ Ollama.Types.Format.SchemaBuilder: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Format.SchemaBuilder.Property
+ Ollama.Types.Format.SchemaBuilder: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Format.SchemaBuilder.Schema
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Classes.Eq Ollama.Types.Format.SchemaBuilder.JsonType
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Classes.Eq Ollama.Types.Format.SchemaBuilder.Property
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Classes.Eq Ollama.Types.Format.SchemaBuilder.Schema
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Classes.Eq Ollama.Types.Format.SchemaBuilder.SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Generics.Generic Ollama.Types.Format.SchemaBuilder.JsonType
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Generics.Generic Ollama.Types.Format.SchemaBuilder.Property
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Generics.Generic Ollama.Types.Format.SchemaBuilder.Schema
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Show.Show Ollama.Types.Format.SchemaBuilder.JsonType
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Show.Show Ollama.Types.Format.SchemaBuilder.Property
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Show.Show Ollama.Types.Format.SchemaBuilder.Schema
+ Ollama.Types.Format.SchemaBuilder: instance GHC.Show.Show Ollama.Types.Format.SchemaBuilder.SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: newtype Property
+ Ollama.Types.Format.SchemaBuilder: objectOf :: SchemaBuilder -> JsonType
+ Ollama.Types.Format.SchemaBuilder: printSchema :: Schema -> IO ()
+ Ollama.Types.Format.SchemaBuilder: requireField :: Text -> SchemaBuilder -> SchemaBuilder
+ Ollama.Types.Format.SchemaBuilder: requireFields :: [Text] -> SchemaBuilder -> SchemaBuilder
+ Ollama.Types.Message: Assistant :: Role
+ Ollama.Types.Message: Message :: !Role -> !Text -> !Maybe [Base64Image] -> !Maybe [ToolCall] -> !Maybe Text -> !Maybe Text -> Message
+ Ollama.Types.Message: System :: Role
+ Ollama.Types.Message: Tool :: Role
+ Ollama.Types.Message: User :: Role
+ Ollama.Types.Message: [messageContent] :: Message -> !Text
+ Ollama.Types.Message: [messageImages] :: Message -> !Maybe [Base64Image]
+ Ollama.Types.Message: [messageRole] :: Message -> !Role
+ Ollama.Types.Message: [messageThinking] :: Message -> !Maybe Text
+ Ollama.Types.Message: [messageToolCalls] :: Message -> !Maybe [ToolCall]
+ Ollama.Types.Message: [messageToolName] :: Message -> !Maybe Text
+ Ollama.Types.Message: assistantMessage :: Text -> Message
+ Ollama.Types.Message: data Message
+ Ollama.Types.Message: data Role
+ Ollama.Types.Message: imageMessage :: Text -> [Base64Image] -> Message
+ Ollama.Types.Message: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Message.Message
+ Ollama.Types.Message: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Message.Role
+ Ollama.Types.Message: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Message.Message
+ Ollama.Types.Message: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Message.Role
+ Ollama.Types.Message: instance GHC.Classes.Eq Ollama.Types.Message.Message
+ Ollama.Types.Message: instance GHC.Classes.Eq Ollama.Types.Message.Role
+ Ollama.Types.Message: instance GHC.Classes.Ord Ollama.Types.Message.Role
+ Ollama.Types.Message: instance GHC.Enum.Bounded Ollama.Types.Message.Role
+ Ollama.Types.Message: instance GHC.Enum.Enum Ollama.Types.Message.Role
+ Ollama.Types.Message: instance GHC.Generics.Generic Ollama.Types.Message.Message
+ Ollama.Types.Message: instance GHC.Generics.Generic Ollama.Types.Message.Role
+ Ollama.Types.Message: instance GHC.Show.Show Ollama.Types.Message.Message
+ Ollama.Types.Message: instance GHC.Show.Show Ollama.Types.Message.Role
+ Ollama.Types.Message: systemMessage :: Text -> Message
+ Ollama.Types.Message: toolMessage :: Text -> Message
+ Ollama.Types.Message: toolResultMessage :: Text -> Text -> Message
+ Ollama.Types.Message: userMessage :: Text -> Message
+ Ollama.Types.Model: ListResponse :: [ModelInfo] -> ListResponse
+ Ollama.Types.Model: ModelDetails :: !Maybe Text -> !Text -> !Text -> ![Text] -> !Text -> !Text -> ModelDetails
+ Ollama.Types.Model: ModelInfo :: !ModelName -> !ModelName -> !UTCTime -> !Int64 -> !Digest -> !ModelDetails -> ModelInfo
+ Ollama.Types.Model: RunningModel :: !ModelName -> !ModelName -> !Int64 -> !Digest -> !ModelDetails -> !UTCTime -> !Int64 -> RunningModel
+ Ollama.Types.Model: RunningModelsResponse :: [RunningModel] -> RunningModelsResponse
+ Ollama.Types.Model: [families] :: ModelDetails -> ![Text]
+ Ollama.Types.Model: [family] :: ModelDetails -> !Text
+ Ollama.Types.Model: [format] :: ModelDetails -> !Text
+ Ollama.Types.Model: [miDetails] :: ModelInfo -> !ModelDetails
+ Ollama.Types.Model: [miDigest] :: ModelInfo -> !Digest
+ Ollama.Types.Model: [miModel] :: ModelInfo -> !ModelName
+ Ollama.Types.Model: [miModifiedAt] :: ModelInfo -> !UTCTime
+ Ollama.Types.Model: [miName] :: ModelInfo -> !ModelName
+ Ollama.Types.Model: [miSize] :: ModelInfo -> !Int64
+ Ollama.Types.Model: [models] :: ListResponse -> [ModelInfo]
+ Ollama.Types.Model: [parameterSize] :: ModelDetails -> !Text
+ Ollama.Types.Model: [parentModel] :: ModelDetails -> !Maybe Text
+ Ollama.Types.Model: [quantizationLevel] :: ModelDetails -> !Text
+ Ollama.Types.Model: [rmDetails] :: RunningModel -> !ModelDetails
+ Ollama.Types.Model: [rmDigest] :: RunningModel -> !Digest
+ Ollama.Types.Model: [rmExpiresAt] :: RunningModel -> !UTCTime
+ Ollama.Types.Model: [rmModel] :: RunningModel -> !ModelName
+ Ollama.Types.Model: [rmName] :: RunningModel -> !ModelName
+ Ollama.Types.Model: [rmSizeVram] :: RunningModel -> !Int64
+ Ollama.Types.Model: [rmSize] :: RunningModel -> !Int64
+ Ollama.Types.Model: [runningModels] :: RunningModelsResponse -> [RunningModel]
+ Ollama.Types.Model: data ModelDetails
+ Ollama.Types.Model: data ModelInfo
+ Ollama.Types.Model: data RunningModel
+ Ollama.Types.Model: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Model.ListResponse
+ Ollama.Types.Model: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Model.ModelDetails
+ Ollama.Types.Model: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Model.ModelInfo
+ Ollama.Types.Model: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Model.RunningModel
+ Ollama.Types.Model: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Model.RunningModelsResponse
+ Ollama.Types.Model: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Model.ListResponse
+ Ollama.Types.Model: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Model.ModelDetails
+ Ollama.Types.Model: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Model.ModelInfo
+ Ollama.Types.Model: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Model.RunningModel
+ Ollama.Types.Model: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Model.RunningModelsResponse
+ Ollama.Types.Model: instance GHC.Classes.Eq Ollama.Types.Model.ListResponse
+ Ollama.Types.Model: instance GHC.Classes.Eq Ollama.Types.Model.ModelDetails
+ Ollama.Types.Model: instance GHC.Classes.Eq Ollama.Types.Model.ModelInfo
+ Ollama.Types.Model: instance GHC.Classes.Eq Ollama.Types.Model.RunningModel
+ Ollama.Types.Model: instance GHC.Classes.Eq Ollama.Types.Model.RunningModelsResponse
+ Ollama.Types.Model: instance GHC.Generics.Generic Ollama.Types.Model.ListResponse
+ Ollama.Types.Model: instance GHC.Generics.Generic Ollama.Types.Model.ModelDetails
+ Ollama.Types.Model: instance GHC.Generics.Generic Ollama.Types.Model.ModelInfo
+ Ollama.Types.Model: instance GHC.Generics.Generic Ollama.Types.Model.RunningModel
+ Ollama.Types.Model: instance GHC.Generics.Generic Ollama.Types.Model.RunningModelsResponse
+ Ollama.Types.Model: instance GHC.Show.Show Ollama.Types.Model.ListResponse
+ Ollama.Types.Model: instance GHC.Show.Show Ollama.Types.Model.ModelDetails
+ Ollama.Types.Model: instance GHC.Show.Show Ollama.Types.Model.ModelInfo
+ Ollama.Types.Model: instance GHC.Show.Show Ollama.Types.Model.RunningModel
+ Ollama.Types.Model: instance GHC.Show.Show Ollama.Types.Model.RunningModelsResponse
+ Ollama.Types.Model: newtype ListResponse
+ Ollama.Types.Model: newtype RunningModelsResponse
+ Ollama.Types.Options: ModelOptions :: !Maybe Int -> !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.Types.Options: [optDraftNumPredict] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optFrequencyPenalty] :: ModelOptions -> !Maybe Double
+ Ollama.Types.Options: [optMainGpu] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optMinP] :: ModelOptions -> !Maybe Double
+ Ollama.Types.Options: [optNumBatch] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optNumCtx] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optNumGpu] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optNumKeep] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optNumPredict] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optNumThread] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optNuma] :: ModelOptions -> !Maybe Bool
+ Ollama.Types.Options: [optPenalizeNewline] :: ModelOptions -> !Maybe Bool
+ Ollama.Types.Options: [optPresencePenalty] :: ModelOptions -> !Maybe Double
+ Ollama.Types.Options: [optRepeatLastN] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optRepeatPenalty] :: ModelOptions -> !Maybe Double
+ Ollama.Types.Options: [optSeed] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optStop] :: ModelOptions -> !Maybe [Text]
+ Ollama.Types.Options: [optTemperature] :: ModelOptions -> !Maybe Double
+ Ollama.Types.Options: [optTopK] :: ModelOptions -> !Maybe Int
+ Ollama.Types.Options: [optTopP] :: ModelOptions -> !Maybe Double
+ Ollama.Types.Options: [optTypicalP] :: ModelOptions -> !Maybe Double
+ Ollama.Types.Options: [optUseMmap] :: ModelOptions -> !Maybe Bool
+ Ollama.Types.Options: data ModelOptions
+ Ollama.Types.Options: defaultOptions :: ModelOptions
+ Ollama.Types.Options: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Options.ModelOptions
+ Ollama.Types.Options: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Options.ModelOptions
+ Ollama.Types.Options: instance GHC.Classes.Eq Ollama.Types.Options.ModelOptions
+ Ollama.Types.Options: instance GHC.Generics.Generic Ollama.Types.Options.ModelOptions
+ Ollama.Types.Options: instance GHC.Show.Show Ollama.Types.Options.ModelOptions
+ Ollama.Types.Tool: FunctionDef :: !Text -> !Maybe Text -> !Maybe FunctionParameters -> !Maybe Bool -> FunctionDef
+ Ollama.Types.Tool: FunctionParameters :: !Text -> !Maybe (Map Text FunctionParameters) -> !Maybe [Text] -> !Maybe Bool -> !Maybe Text -> !Maybe [Text] -> FunctionParameters
+ Ollama.Types.Tool: Tool :: !Text -> !FunctionDef -> Tool
+ Ollama.Types.Tool: ToolCall :: ToolCallFunction -> ToolCall
+ Ollama.Types.Tool: ToolCallFunction :: !Text -> !Map Text Value -> ToolCallFunction
+ Ollama.Types.Tool: [fnDescription] :: FunctionDef -> !Maybe Text
+ Ollama.Types.Tool: [fnName] :: FunctionDef -> !Text
+ Ollama.Types.Tool: [fnParameters] :: FunctionDef -> !Maybe FunctionParameters
+ Ollama.Types.Tool: [fnStrict] :: FunctionDef -> !Maybe Bool
+ Ollama.Types.Tool: [fpAdditionalProperties] :: FunctionParameters -> !Maybe Bool
+ Ollama.Types.Tool: [fpDescription] :: FunctionParameters -> !Maybe Text
+ Ollama.Types.Tool: [fpEnum] :: FunctionParameters -> !Maybe [Text]
+ Ollama.Types.Tool: [fpProperties] :: FunctionParameters -> !Maybe (Map Text FunctionParameters)
+ Ollama.Types.Tool: [fpRequired] :: FunctionParameters -> !Maybe [Text]
+ Ollama.Types.Tool: [fpType] :: FunctionParameters -> !Text
+ Ollama.Types.Tool: [tcFunction] :: ToolCall -> ToolCallFunction
+ Ollama.Types.Tool: [tcfArguments] :: ToolCallFunction -> !Map Text Value
+ Ollama.Types.Tool: [tcfName] :: ToolCallFunction -> !Text
+ Ollama.Types.Tool: [toolFunction] :: Tool -> !FunctionDef
+ Ollama.Types.Tool: [toolType] :: Tool -> !Text
+ Ollama.Types.Tool: data FunctionDef
+ Ollama.Types.Tool: data FunctionParameters
+ Ollama.Types.Tool: data Tool
+ Ollama.Types.Tool: data ToolCallFunction
+ Ollama.Types.Tool: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Tool.FunctionDef
+ Ollama.Types.Tool: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Tool.FunctionParameters
+ Ollama.Types.Tool: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Tool.Tool
+ Ollama.Types.Tool: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Tool.ToolCall
+ Ollama.Types.Tool: instance Data.Aeson.Types.FromJSON.FromJSON Ollama.Types.Tool.ToolCallFunction
+ Ollama.Types.Tool: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Tool.FunctionDef
+ Ollama.Types.Tool: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Tool.FunctionParameters
+ Ollama.Types.Tool: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Tool.Tool
+ Ollama.Types.Tool: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Tool.ToolCall
+ Ollama.Types.Tool: instance Data.Aeson.Types.ToJSON.ToJSON Ollama.Types.Tool.ToolCallFunction
+ Ollama.Types.Tool: instance GHC.Classes.Eq Ollama.Types.Tool.FunctionDef
+ Ollama.Types.Tool: instance GHC.Classes.Eq Ollama.Types.Tool.FunctionParameters
+ Ollama.Types.Tool: instance GHC.Classes.Eq Ollama.Types.Tool.Tool
+ Ollama.Types.Tool: instance GHC.Classes.Eq Ollama.Types.Tool.ToolCall
+ Ollama.Types.Tool: instance GHC.Classes.Eq Ollama.Types.Tool.ToolCallFunction
+ Ollama.Types.Tool: instance GHC.Generics.Generic Ollama.Types.Tool.FunctionDef
+ Ollama.Types.Tool: instance GHC.Generics.Generic Ollama.Types.Tool.FunctionParameters
+ Ollama.Types.Tool: instance GHC.Generics.Generic Ollama.Types.Tool.Tool
+ Ollama.Types.Tool: instance GHC.Generics.Generic Ollama.Types.Tool.ToolCall
+ Ollama.Types.Tool: instance GHC.Generics.Generic Ollama.Types.Tool.ToolCallFunction
+ Ollama.Types.Tool: instance GHC.Show.Show Ollama.Types.Tool.FunctionDef
+ Ollama.Types.Tool: instance GHC.Show.Show Ollama.Types.Tool.FunctionParameters
+ Ollama.Types.Tool: instance GHC.Show.Show Ollama.Types.Tool.Tool
+ Ollama.Types.Tool: instance GHC.Show.Show Ollama.Types.Tool.ToolCall
+ Ollama.Types.Tool: instance GHC.Show.Show Ollama.Types.Tool.ToolCallFunction
+ Ollama.Types.Tool: newtype ToolCall
- Ollama: ApiError :: Text -> OllamaError
+ Ollama: ApiError :: !Int -> !Text -> OllamaError
- Ollama: ChatResponse :: !Text -> !UTCTime -> !Maybe Message -> !Bool -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Text -> ChatResponse
+ Ollama: ChatResponse :: !ModelName -> !UTCTime -> !Maybe Message -> !Bool -> !Maybe Text -> !Maybe Duration -> !Maybe Duration -> !Maybe Int -> !Maybe Duration -> !Maybe Int -> !Maybe Duration -> ChatResponse
- Ollama: DecodeError :: DecodingErrorMessage -> DecodingFailedValue -> OllamaError
+ Ollama: DecodeError :: !Text -> !ByteString -> OllamaError
- Ollama: FunctionDef :: Text -> Maybe Text -> Maybe FunctionParameters -> Maybe Bool -> FunctionDef
+ Ollama: FunctionDef :: !Text -> !Maybe Text -> !Maybe FunctionParameters -> !Maybe Bool -> FunctionDef
- Ollama: FunctionParameters :: Text -> Maybe (Map Text FunctionParameters) -> Maybe [Text] -> Maybe Bool -> FunctionParameters
+ Ollama: FunctionParameters :: !Text -> !Maybe (Map Text FunctionParameters) -> !Maybe [Text] -> !Maybe Bool -> !Maybe Text -> !Maybe [Text] -> FunctionParameters
- Ollama: GenerateResponse :: !Text -> !UTCTime -> !Text -> !Bool -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Int64 -> !Maybe Text -> !Maybe Text -> GenerateResponse
+ Ollama: GenerateResponse :: !ModelName -> !UTCTime -> !Text -> !Bool -> !Maybe Text -> !Maybe [Int] -> !Maybe Duration -> !Maybe Duration -> !Maybe Int -> !Maybe Duration -> !Maybe Int -> !Maybe Duration -> !Maybe Text -> !Maybe Base64Image -> GenerateResponse
- Ollama: HttpError :: HttpException -> OllamaError
+ Ollama: HttpError :: !HttpException -> OllamaError
- Ollama: InvalidRequest :: String -> OllamaError
+ Ollama: InvalidRequest :: !Text -> OllamaError
- Ollama: Message :: !Role -> !Text -> !Maybe [Text] -> !Maybe [ToolCall] -> !Maybe Text -> Message
+ Ollama: Message :: !Role -> !Text -> !Maybe [Base64Image] -> !Maybe [ToolCall] -> !Maybe Text -> !Maybe Text -> Message
- Ollama: ModelInfo :: !Text -> !UTCTime -> !Int64 -> !Text -> !ModelDetails -> ModelInfo
+ Ollama: ModelInfo :: !ModelName -> !ModelName -> !UTCTime -> !Int64 -> !Digest -> !ModelDetails -> ModelInfo
- 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: ModelOptions :: !Maybe Int -> !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: RunningModel :: !Text -> !Text -> !Int64 -> !Text -> !ModelDetails -> !UTCTime -> !Int64 -> RunningModel
+ Ollama: RunningModel :: !ModelName -> !ModelName -> !Int64 -> !Digest -> !ModelDetails -> !UTCTime -> !Int64 -> RunningModel
- Ollama: SchemaFormat :: Schema -> Format
+ Ollama: SchemaFormat :: !Schema -> Format
- Ollama: TimeoutError :: String -> OllamaError
+ Ollama: TimeoutError :: OllamaError
- Ollama: Tool :: Role
+ Ollama: Tool :: !Text -> !FunctionDef -> Tool
- Ollama: ToolCall :: OutputFunction -> ToolCall
+ Ollama: ToolCall :: ToolCallFunction -> ToolCall
- Ollama: [createdAt] :: ChatResponse -> !UTCTime
+ Ollama: [createdAt] :: Conversation -> !UTCTime
- Ollama: [messages] :: ChatOps -> !NonEmpty Message
+ Ollama: [messages] :: Conversation -> ![Message]
- Ollama: [model] :: ChatResponse -> !Text
+ Ollama: [model] :: Conversation -> !ModelName
- Ollama: [toolType] :: InputTool -> Text
+ Ollama: [toolType] :: Tool -> !Text
- Ollama: chat :: ChatOps -> Maybe OllamaConfig -> IO (Either OllamaError ChatResponse)
+ Ollama: chat :: MonadIO m => OllamaClient -> ChatRequest -> m (Either OllamaError ChatResponse)
- Ollama: copyModel :: Text -> Text -> Maybe OllamaConfig -> IO (Either OllamaError ())
+ Ollama: copyModel :: MonadIO m => OllamaClient -> ModelName -> ModelName -> m (Either OllamaError ())
- Ollama: createModel :: CreateOps -> Maybe OllamaConfig -> IO ()
+ Ollama: createModel :: MonadIO m => OllamaClient -> CreateRequest -> m (Either OllamaError CreateResponse)
- Ollama: deleteModel :: Text -> Maybe OllamaConfig -> IO (Either OllamaError ())
+ Ollama: deleteModel :: MonadIO m => OllamaClient -> ModelName -> m (Either OllamaError ())
- Ollama: generate :: GenerateOps -> Maybe OllamaConfig -> IO (Either OllamaError GenerateResponse)
+ Ollama: generate :: MonadIO m => OllamaClient -> GenerateRequest -> m (Either OllamaError GenerateResponse)
- Ollama: getVersion :: IO (Either OllamaError Version)
+ Ollama: getVersion :: MonadIO m => OllamaClient -> m (Either OllamaError Version)
- Ollama: pull :: Text -> IO (Either OllamaError PullResp)
+ Ollama: pull :: MonadIO m => OllamaClient -> ModelName -> m (Either OllamaError PullResponse)
- Ollama: push :: Text -> Maybe Bool -> Maybe Bool -> Maybe OllamaConfig -> IO ()
+ Ollama: push :: MonadIO m => OllamaClient -> ModelName -> m (Either OllamaError PushResponse)
- Ollama: showModel :: Text -> IO (Either OllamaError ShowModelResponse)
+ Ollama: showModel :: MonadIO m => OllamaClient -> ModelName -> m (Either OllamaError ShowResponse)

Files

CHANGELOG.md view
@@ -1,67 +1,33 @@-# Revision history for ollama-haskell--## Unreleased--## 0.2.1.0 -- 2025-09-24--* Added blob module for managing binary large objects (GGUF files/safetensors).-* Breaking: Added `dimensions` option in embeddings for specifying embedding dimensions.-* Breaking: Added `doneReason` field in chat and generate responses.-* Improved test suite with more comprehensive test cases.-* Added `onComplete` callback function in stream handlers for better streaming control.-* Breaking: Standardized field names across the library for consistency.-* Applied fourmolu code formatting and added hlint for better code quality.--## 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.-* Exported EmbeddingResponse.-* Added Format argument in chat and generate function for structured output.--## 0.1.2.0 -- 2024-11-20--* Added hostUrl and responseTimeOut options in generate function.-* Added hostUrl and responseTimeOut options in chat function.--## 0.1.1.3 -- 2024-11-08--* Increase response timeout to 15 minutes-* Added encodeImage utility function that converts image filePath to base64 image data.-* Added generateJson and chatJson. High level function to return response in Haskell type.--## 0.1.0.3 -- 2024-11-05--* Moving to stack instead of cabal.+# Changelog -## 0.1.0.2 -- 2024-10-18+All notable changes to `ollama-haskell` will be documented in this file.+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),+and this project adheres to [PVP (Haskell Package Versioning Policy)](https://pvp.haskell.org/). -* Increased response timeout time for chat function. +--- -## 0.1.0.1 -- 2024-10-18+## [0.3.0.0] - 2026-08-04 -* Renaming Lib.hs to OllamaExamples.hs as it was conflicting `Lib.hs` name+### Added+- **`OllamaClient` Core**: Thread-safe client handle with automatic connection manager lifecycle management (`newClient`, `defaultClient`, `clientFromEnv`, `withClient`).+- **First-Class Streaming Pipeline**: `conduit`-based response streaming (`chatStream`, `generateStream`, `pullStream`, `pushStream`, `createModelStream`).+- **Stream Combinators**: `collectStream` and `foldStream` in `Ollama.Streaming`.+- **Structured Output DSL**: Type-safe `SchemaBuilder` DSL in `Ollama.Types.Format.SchemaBuilder` (`|+`, `|++`, `|!`, `|!!`) for constructing JSON Schemas.+- **Thinking / Reasoning Models Support**: `Think` ADT (`ThinkEnabled`, `ThinkDisabled`, `ThinkLevel`) and `ThinkingLevel` (`ThinkLow`, `ThinkMedium`, `ThinkHigh`, `ThinkMax`) supporting models such as `qwen3.5` and `deepseek-r1`.+- **Function / Tool Calling**: `Tool`, `FunctionDef`, `FunctionParameters`, `ToolCall`, and `toolResultMessage` helper.+- **Environment Resolution**: Automatic `OLLAMA_HOST` parsing and normalization in `clientFromEnv` supporting `host:port`, `http://host:port`, and bare `host`.+- **Authorization & Headers**: Support for `OLLAMA_API_KEY` bearer tokens and custom `configHeaders`.+- **Configurable Resilience**: `RetryPolicy` ADT (`NoRetry`, `ConstantRetry`, `ExponentialRetry`), lifecycle callbacks (`configOnStart`, `configOnSuccess`, `configOnError`), and structured logger `configLogger`.+- **Token Throughput Metrics**: Metrics helpers `chatEvalTokensPerSecond`, `chatPromptEvalTokensPerSecond`, `evalTokensPerSecond`, `promptEvalTokensPerSecond`, `tokensPerSecond`.+- **Testing Infrastructure**: Built-in mock testing module `Ollama.Testing` (`newMockClient`, `withMockClient`, `mockGenerateResponse`, `mockChatResponse`, `mockEmbedResponse`, `mockListModelsResponse`).+- **Conversation Store**: Transactional STM-backed `InMemoryStore` and `ConversationStore` typeclass.+- **New API Endpoints**: `Ollama.API.Embed` (`/api/embed`), `Ollama.API.Blobs` (`/api/blobs`), `Ollama.API.Ps` (`/api/ps`), `Ollama.API.Version` (`/api/version`).+- **Benchmark Suite**: Criterion/tasty-bench suite in `bench/Main.hs` measuring serialization and throughput. -## 0.1.0.0 -- YYYY-mm-dd+### Changed+- **MonadIO / MonadUnliftIO Polymorphism**: All API functions use `MonadIO m =>` / `MonadUnliftIO m =>` signatures instead of dual `*M` variants.+- **Typed Newtypes**: `ModelName`, `Digest`, `Base64Image`, `Duration`, `Version` replace primitive string types.+- **Unified Error Type**: `OllamaError` sum type with structured constructors and `Exception` instance. -* First version. Released on an unsuspecting world.+### Deprecated+- `embeddings` endpoint (`/api/embeddings`) marked deprecated in favor of `/api/embed`.
README.md view
@@ -1,102 +1,181 @@-# 🦙 Ollama Haskell+# ollama-haskell -<div style="text-align: center;">-<img src="./examples/ollama_haskell.png" alt="logo image" height="200"/>-</div>+[![Hackage](https://img.shields.io/hackage/v/ollama-haskell.svg)](https://hackage.haskell.org/package/ollama-haskell)+[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -**`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.+Industry-grade, feature-complete, modern Haskell client library for the [Ollama](https://ollama.com) local LLM engine. +## Features++- **Client-Centric Architecture**: Thread-safe `OllamaClient` handle with connection pooling and resource management (`newClient`, `defaultClient`, `clientFromEnv`, `withClient`).+- **First-Class Streaming**: `conduit`-based response streaming (`chatStream`, `generateStream`, `pullStream`, `pushStream`, `createModelStream`).+- **Complete API Surface**: Text generation, chat completions, vector embeddings, model management (list, show, copy, delete, pull, push, create), and system endpoints.+- **Structured Outputs**: Powerful `SchemaBuilder` DSL (`|+`, `|++`, `|!`, `|!!`) for type-safe JSON Schema structured responses.+- **Function / Tool Calling**: Full support for tool definitions (`Tool`), tool calls (`ToolCall`), and execution results (`toolResultMessage`).+- **Thinking Models Support**: Native support for reasoning models (`qwen3.5`, `deepseek-r1`) with `Think` / `ThinkingLevel` types.+- **Environment & Auth Integration**: Robust URL normalization for `OLLAMA_HOST` and bearer token support for `OLLAMA_API_KEY`.+- **Configurable Resilience**: Flexible retry policies (`NoRetry`, `ConstantRetry`, `ExponentialRetry`), lifecycle callbacks, and structured logging.+- **Conversation Store**: Transactional STM-backed `InMemoryStore` and `ConversationStore` typeclass for managing multi-turn chat sessions.+- **SDK Comparison Matrix**: Detailed feature comparison against Python, JS/TS, and Go SDKs in [doc/COMPARISON.md](doc/COMPARISON.md).+ --- -## ✨ Features+## Installation -* 💬 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+Add `ollama-haskell` to your `.cabal` file: +```cabal+build-depends:+    base >= 4.17 && < 5+  , ollama-haskell >= 0.3.0.0+```++Or using Stack in `package.yaml`:++```yaml+dependencies:+  - ollama-haskell >= 0.3.0.0+```+ --- -## ⚡ Quick Example+## Quick Start (5 Lines)  ```haskell-{-# LANGUAGE OverloadedStrings #-}-module Main where--import Data.Ollama.Generate-import qualified Data.Text.IO as T+import Data.List.NonEmpty (NonEmpty ((:|)))+import Data.Text.IO qualified as TIO+import Ollama  main :: IO () main = do-  let ops =-        defaultGenerateOps-          { 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)+  client <- defaultClient+  res <- chat client $ chatRequest "qwen3.5:2b" (userMessage "Why is the sky blue?" :| [])+  case res of+    Left err   -> print err+    Right resp -> mapM_ (TIO.putStrLn . messageContent) (crMessage resp) ```  --- -## 📦 Installation+## Streaming Responses with Conduit -Add to your `.cabal` file:+Stream LLM responses token-by-token as they generate: -```cabal-build-depends:-  base >=4.7 && <5,-  ollama-haskell-```+```haskell+import Data.List.NonEmpty (NonEmpty ((:|)))+import Data.Text.IO qualified as TIO+import Ollama -Or use with `stack`/`nix-shell`.+main :: IO ()+main = do+  client <- defaultClient+  let req = chatRequest "qwen3.5:2b" (userMessage "Count from 1 to 5." :| [])+  +  -- Stream chunks directly into stdout or collect them+  chunks <- collectStream (chatStream client req)+  mapM_ (TIO.putStr . maybe "" messageContent . crMessage) chunks+  putStrLn ""+```  --- -## 📚 More Examples+## Function & Tool Calling -See [`examples/OllamaExamples.hs`](examples/OllamaExamples.hs) for:+Define function signatures and let the LLM execute structured tool calls: -* Chat with conversation memory-* Structured JSON output-* Embeddings-* Tool/function calling-* Multimodal input-* Streaming and non-streaming variants+```haskell+import Data.List.NonEmpty (NonEmpty ((:|)))+import Ollama +calculatorTool :: Tool+calculatorTool = Tool "function" $ FunctionDef+  { fnName = "add"+  , fnDescription = Just "Add two numbers"+  , fnParameters = Just (FunctionParameters "object" Nothing (Just ["a", "b"]) Nothing Nothing Nothing)+  , fnStrict = Just True+  }++main :: IO ()+main = do+  client <- defaultClient+  let req = (chatRequest "qwen3.5:2b" (userMessage "What is 40 + 2?" :| []))+        { chatTools = Just [calculatorTool] }+  res <- chat client req+  case res of+    Left err   -> print err+    Right resp -> print (crMessage resp)+```+ --- -## 🛠 Prerequisite+## Structured Outputs (JSON Schema DSL) -Make sure you have [Ollama installed and running locally](https://ollama.com/download). Run `ollama pull llama3` to download a model.+Enforce structured JSON output formats using `SchemaBuilder`: +```haskell+import Data.Text.IO qualified as TIO+import Ollama+import Ollama.Types.Format.SchemaBuilder++personSchema :: Schema+personSchema = buildSchema $ emptyObject+  |+ ("name", JString)+  |+ ("age", JInteger)+  |! "name"++main :: IO ()+main = do+  client <- defaultClient+  let req = (generateRequest "qwen3.5:2b" "Generate a person profile.")+        { genFormat = Just (SchemaFormat personSchema) }+  res <- generate client req+  case res of+    Left err   -> print err+    Right resp -> TIO.putStrLn (grResponse resp)+```+ --- -## 🧪 Dev & Nix Support+## Environment Variables & Configuration -Use Nix:+Construct a client using environment variables (`OLLAMA_HOST`, `OLLAMA_API_KEY`): -```bash-nix-shell+```haskell+main :: IO ()+main = do+  client <- clientFromEnv+  -- Automatically connects to OLLAMA_HOST with optional Authorization: Bearer header+  ... ``` -This will install `stack` and Ollama.+Or configure custom retry policies and loggers: +```haskell+customConfig :: OllamaClientConfig+customConfig = defaultConfig+  { configBaseUrl = "http://my-ollama-server:11434"+  , configTimeout = 120+  , configRetry   = ExponentialRetry 3 1 -- 3 retries with exponential backoff+  , configLogger  = Just (\level msg -> putStrLn $ "[" <> show level <> "] " <> show msg)+  }++main :: IO ()+main = withClient customConfig $ \client -> do+  ...+```+ --- -## 👨‍💻 Author+## Documentation & SDK Comparison -Created and maintained by [@tusharad](https://github.com/tusharad). PRs and feedback are welcome!+- [doc/COMPARISON.md](doc/COMPARISON.md) — SDK Feature Matrix comparing `ollama-haskell` with Python, JS/TS, and Go SDKs.+- [ARCHITECTURE.md](ARCHITECTURE.md) — Detailed internal module design and extension guide.+- [CONTRIBUTING.md](CONTRIBUTING.md) — Development setup, testing guidelines, and code style.+- [CHANGELOG.md](CHANGELOG.md) — Release notes and changelog.+- [Hackage Documentation](https://hackage.haskell.org/package/ollama-haskell) — Full Haddock reference.  --- -## 🤝 Contributing+## License -Have ideas or improvements? Feel free to [open an issue](https://github.com/tusharad/ollama-haskell/issues) or submit a PR!+MIT © 2024–2026 Tushar Adhatrao
+ bench/Main.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE OverloadedStrings #-}++{- |+Module      : Main+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Benchmark suite for Ollama client JSON serialization and URL normalization operations.++@since 1.0.0.0+-}+module Main (main) where++import Data.Aeson (decode, encode)+import Data.ByteString.Lazy (ByteString)+import Data.List.NonEmpty (NonEmpty ((:|)))+import Ollama.API.Chat (ChatRequest, ChatResponse, chatRequest)+import Ollama.API.Embed (EmbedRequest, EmbedResponse, embedRequest)+import Ollama.API.Generate (GenerateRequest, GenerateResponse, generateRequest)+import Ollama.API.Models.Create (CreateRequest, defaultCreateRequest)+import Ollama.Testing (mockChatResponse, mockEmbedResponse, mockGenerateResponse)+import Ollama.Types.Common (ModelName (..))+import Ollama.Types.Message (userMessage)+import Test.Tasty.Bench (bench, bgroup, defaultMain, whnf)++main :: IO ()+main =+  defaultMain+    [ bgroup+        "JSON Encoding"+        [ bench "GenerateRequest" $ whnf encode sampleGenerateRequest+        , bench "ChatRequest" $ whnf encode sampleChatRequest+        , bench "EmbedRequest" $ whnf encode sampleEmbedRequest+        , bench "CreateRequest" $ whnf encode sampleCreateRequest+        ]+    , bgroup+        "JSON Decoding"+        [ bench "GenerateResponse" $ whnf (decode @GenerateResponse) sampleGenerateBytes+        , bench "ChatResponse" $ whnf (decode @ChatResponse) sampleChatBytes+        , bench "EmbedResponse" $ whnf (decode @EmbedResponse) sampleEmbedBytes+        ]+    ]++sampleGenerateRequest :: GenerateRequest+sampleGenerateRequest = generateRequest (ModelName "llama3.2") "Why is the sky blue?"++sampleChatRequest :: ChatRequest+sampleChatRequest = chatRequest (ModelName "llama3.2") (userMessage "Hello, world!" :| [])++sampleEmbedRequest :: EmbedRequest+sampleEmbedRequest = embedRequest (ModelName "nomic-embed-text") ["Hello", "World", "Vector"]++sampleCreateRequest :: CreateRequest+sampleCreateRequest = defaultCreateRequest (ModelName "custom-llama")++sampleGenerateBytes :: ByteString+sampleGenerateBytes = encode $ mockGenerateResponse (ModelName "llama3.2") "Sky is blue"++sampleChatBytes :: ByteString+sampleChatBytes = encode $ mockChatResponse (ModelName "llama3.2") "Hello there"++sampleEmbedBytes :: ByteString+sampleEmbedBytes = encode $ mockEmbedResponse (ModelName "nomic") [[0.1, 0.2]]
+ doc/COMPARISON.md view
@@ -0,0 +1,66 @@+# SDK Feature & Architecture Comparison++This document provides a comprehensive technical comparison between **`ollama-haskell` (v0.3.0.0)**, official SDKs in other ecosystems (**Python**, **JavaScript/TypeScript**, **Go**), and existing Haskell LLM libraries.++---++## 1. Feature Support Matrix Across Language SDKs++| Feature / Endpoint | `ollama-haskell` (v0.3.0.0) | `ollama-python` | `ollama-js` | `ollama/ollama/api` (Go) |+| :--- | :---: | :---: | :---: | :---: |+| **Language Paradigm** | Pure Functional / Typed | Dynamic / Async | Dynamic / Promises | Imperative / Structs |+| **Response Streaming** | `conduit` Pipelines | Iterator / AsyncGenerator | AsyncIterable | Channel / Callback |+| **Chat Completions (`/api/chat`)** | ✅ | ✅ | ✅ | ✅ |+| **Text Generation (`/api/generate`)** | ✅ | ✅ | ✅ | ✅ |+| **Thinking / Reasoning Models** | ✅ `Think` ADT (`qwen3.5`, `deepseek-r1`) | ⚠️ Raw JSON parameter | ⚠️ Raw JSON parameter | ⚠️ Raw JSON parameter |+| **Structured Output Schema** | ✅ Type-safe `SchemaBuilder` DSL | ⚠️ Pydantic / Raw Dict | ⚠️ Zod / Raw Schema | ⚠️ Struct tag / Raw Schema |+| **Function / Tool Calling** | ✅ Strongly-typed `Tool` ADT | ✅ Dict / Callables | ✅ JSON schema objects | ✅ Go Structs |+| **Vector Embeddings (`/api/embed`)** | ✅ | ✅ | ✅ | ✅ |+| **Model Lifecycle (`copy`, `delete`, `show`, `ps`)** | ✅ | ✅ | ✅ | ✅ |+| **Blob Management (`checkBlob`, `pushBlob`)** | ✅ | ✅ | ✅ | ✅ |+| **Automatic Retry Policy** | ✅ `NoRetry`, `Constant`, `Exponential` | ❌ (User implementation) | ❌ (User implementation) | ❌ (User implementation) |+| **Connection Lifecycles** | ✅ Automatic GC & Bracket | ⚠️ Manual session | ⚠️ Fetch client | ⚠️ Manual `http.Client` |+| **STM Session Management** | ✅ `InMemoryStore` & `ConversationStore` | ❌ | ❌ | ❌ |+| **Mock Testing Harness** | ✅ `Ollama.Testing` (`withMockClient`) | ❌ | ❌ | ❌ |++---++## 2. Comparison with Other Haskell LLM Libraries++| Feature | `ollama-haskell` | `openai-hs` | `langchain-hs` |+| :--- | :--- | :--- | :--- |+| **Target Provider** | Local Ollama Engine | OpenAI Cloud API | Multi-provider Framework |+| **Streaming Abstraction** | First-class `conduit` streams | Lazy ByteString / SSE | Custom Stream types |+| **Retry & Resilience** | Integrated `retry` policy backoff | None | Basic |+| **Mocking & Testing** | Built-in `Ollama.Testing` module | None | Mock handlers |+| **Memory Persistence** | STM-backed `InMemoryStore` | Manual | Vector store abstractions |++---++## 3. Key Architectural Advantages of `ollama-haskell`++1. **Type Safety & Smart Constructors**:+   - String parameters are wrapped in domain-specific newtypes (`ModelName`, `Digest`, `Base64Image`, `Duration`, `Version`).+   - `mkModelName` validates model name invariants at runtime.++2. **First-Class Streaming via `conduit`**:+   - `chatStream` and `generateStream` stream line-delimited JSON objects over constant memory pipelines without buffering entire responses in memory.+   - Stream combinators `collectStream` and `foldStream` simplify consumption.++3. **Domain-Specific Schema Builder (`SchemaBuilder`)**:+   - Construct complex JSON Schemas using readable infix operators:+     ```haskell+     userSchema = buildSchema $+       emptyObject+         |+ ("name", JString)+         |+ ("age", JInteger)+         |! "name"+     ```++4. **Built-In Resilient Transport**:+   - Exponential backoff retry strategies (`ExponentialRetry 3 1.0`).+   - Lifecycle callbacks (`configOnStart`, `configOnSuccess`, `configOnError`).+   - Customizable logger thresholds (`Debug`, `Info`, `Warn`, `Error`).++5. **Mock Infrastructure (`Ollama.Testing`)**:+   - Test application code deterministically offline using `withMockClient` without needing a running Ollama server during CI unit testing.
+ examples/AllFeatures.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE OverloadedStrings #-}++{- |+Module      : Main+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Comprehensive example demonstrating all v1.0 features of ollama-haskell:+  * Client builder with env resolution, custom headers, & retry policies+  * Conduit-based response streaming+  * Thinking / reasoning model integration+  * Function / tool calling+  * Structured JSON schema output+  * Vector embeddings & token throughput metrics+  * Transactional STM conversation storage++@since 1.0.0.0+-}+module Main (main) where++import Data.List.NonEmpty (NonEmpty ((:|)))+import Data.Text qualified as T+import Data.Time (getCurrentTime)+import Ollama++fastOptions :: Maybe ModelOptions+fastOptions = Just (defaultOptions {optNumPredict = Just 20})++main :: IO ()+main = do+  putStrLn "=========================================================="+  putStrLn "   ollama-haskell v1.0 — All Features Showcase Example"+  putStrLn "=========================================================="++  -- 1. Client Builder with env vars, custom headers, & Exponential Retry Policy+  putStrLn "\n[1] Initializing client..."+  let customConfig =+        defaultConfig+          { configRetry = ExponentialRetry 3 1+          , configHeaders = [("X-Custom-Client", "ollama-haskell-v1.0")]+          }+  client <- newClient customConfig+  putStrLn "Client initialized with ExponentialRetry policy."++  -- 2. System Inspection+  putStrLn "\n[2] System Engine Version..."+  verRes <- getVersion client+  case verRes of+    Left err -> putStrLn $ "Error fetching version: " <> show err+    Right ver -> putStrLn $ "Ollama Engine Version: " <> T.unpack (unVersion ver)++  putStrLn "\n[3] Listing Local Models..."+  modelsRes <- listModels client+  case modelsRes of+    Left err -> putStrLn $ "Error listing models: " <> show err+    Right (ListResponse ms) -> do+      putStrLn $ "Found " <> show (length ms) <> " installed models:"+      mapM_ (\m -> putStrLn $ "  - " <> T.unpack (unModelName (miName m))) ms++  let model = "qwen3.5:2b"++  -- 4. Conduit-Based Streaming Chat+  putStrLn $ "\n[4] Streaming Chat with Conduit (" <> T.unpack (unModelName model) <> ")..."+  let streamReq =+        (chatRequest model (userMessage "Count from 1 to 5." :| []))+          { chatOptions = fastOptions+          , chatThink = Just ThinkDisabled+          }+  putStr "Response stream: "+  chunks <- collectStream (chatStream client streamReq)+  mapM_+    ( \c -> case crMessage c of+        Just msg -> putStr (T.unpack (messageContent msg))+        Nothing -> pure ()+    )+    chunks+  putStrLn ""++  -- 5. Non-Streaming Chat with Token Throughput Metrics+  putStrLn "\n[5] Non-Streaming Chat & Token Metrics..."+  let chatReq =+        ( chatRequest+            model+            (systemMessage "You are a concise assistant." :| [userMessage "Explain gravity in one sentence."])+        )+          { chatOptions = fastOptions+          , chatThink = Just ThinkDisabled+          }+  chatRes <- chat client chatReq+  case chatRes of+    Left err -> putStrLn $ "Chat error: " <> show err+    Right resp -> do+      case crMessage resp of+        Just msg -> putStrLn $ "Answer: " <> T.unpack (messageContent msg)+        Nothing -> putStrLn "No message returned."+      case chatEvalTokensPerSecond resp of+        Just tps -> putStrLn $ "Generation Speed: " <> show tps <> " tokens/sec"+        Nothing -> pure ()++  -- 6. Thinking / Reasoning Model Integration+  putStrLn "\n[6] Generation with Thinking Mode..."+  let thinkReq =+        (generateRequest model "What is 15 * 14?")+          { genThink = Just (ThinkLevel ThinkMedium)+          , genOptions = fastOptions+          }+  thinkRes <- generate client thinkReq+  case thinkRes of+    Left err -> putStrLn $ "Generate error: " <> show err+    Right resp -> putStrLn $ "Result: " <> T.unpack (grResponse resp)++  -- 7. Tool / Function Calling+  putStrLn "\n[7] Tool / Function Calling..."+  let calcTool =+        Tool+          { toolType = "function"+          , toolFunction =+              FunctionDef+                { fnName = "calculator"+                , fnDescription = Just "Perform basic math calculations"+                , fnParameters =+                    Just+                      FunctionParameters+                        { fpType = "object"+                        , fpProperties = Nothing+                        , fpRequired = Just ["expression"]+                        , fpAdditionalProperties = Nothing+                        , fpDescription = Nothing+                        , fpEnum = Nothing+                        }+                , fnStrict = Just True+                }+          }+      toolReq =+        (chatRequest model (userMessage "Calculate 42 * 8" :| []))+          { chatTools = Just [calcTool]+          , chatOptions = fastOptions+          , chatThink = Just ThinkDisabled+          }+  toolRes <- chat client toolReq+  case toolRes of+    Left err -> putStrLn $ "Tool chat error: " <> show err+    Right resp -> case crMessage resp of+      Just msg -> case messageToolCalls msg of+        Just calls -> putStrLn $ "Model requested tool execution: " <> show calls+        Nothing -> putStrLn $ "Response: " <> T.unpack (messageContent msg)+      Nothing -> putStrLn "No message returned."++  -- 8. Vector Embeddings+  putStrLn "\n[8] Vector Embeddings..."+  let embReq = embedRequest model ["Haskell AI development", "Ollama LLM client"]+  embRes <- embed client embReq+  case embRes of+    Left err -> putStrLn $ "Embed error: " <> show err+    Right resp -> putStrLn $ "Generated " <> show (length (erEmbeddings resp)) <> " embedding vectors."++  -- 9. Transactional Conversation Store+  putStrLn "\n[9] STM Conversation Store..."+  store <- initInMemoryStore+  now <- getCurrentTime+  let convId = "demo-session-42"+      session =+        Conversation+          convId+          [systemMessage "Context saved.", userMessage "Favorite language is Haskell."]+          model+          now+          now+  saveConversationInMemory store session+  retrieved <- loadConversationInMemory store convId+  case retrieved of+    Just c ->+      putStrLn $+        "Successfully loaded conversation ["+          <> T.unpack (conversationId c)+          <> "] with "+          <> show (length (messages c))+          <> " messages."+    Nothing -> putStrLn "Failed to load conversation."++  closeClient client+  putStrLn "\n=========================================================="+  putStrLn "   Showcase Completed Successfully!"+  putStrLn "=========================================================="
+ examples/BasicChat.hs view
@@ -0,0 +1,21 @@+module Main (main) where++import Data.List.NonEmpty (NonEmpty ((:|)))+import Data.Text.IO qualified as TIO+import Ollama++main :: IO ()+main = do+  client <- defaultClient+  let opts = Just (defaultOptions {optNumPredict = Just 20})+      req =+        (chatRequest "qwen3.5:2b" (userMessage "Why is the sky blue?" :| []))+          { chatOptions = opts+          , chatThink = Just ThinkDisabled+          }+  res <- chat client req+  case res of+    Left err -> putStrLn $ "Error: " <> show err+    Right resp -> case crMessage resp of+      Just msg -> TIO.putStrLn $ "Response: " <> messageContent msg+      Nothing -> putStrLn "No content returned"
+ examples/Embeddings.hs view
@@ -0,0 +1,12 @@+module Main (main) where++import Ollama++main :: IO ()+main = do+  client <- defaultClient+  let req = embedRequest "qwen3.5:2b" ["Hello world", "Haskell LLM integration"]+  res <- embed client req+  case res of+    Left err -> putStrLn $ "Error: " <> show err+    Right resp -> putStrLn $ "Generated " <> show (length $ erEmbeddings resp) <> " embeddings."
+ examples/ModelManagement.hs view
@@ -0,0 +1,13 @@+module Main (main) where++import Ollama++main :: IO ()+main = do+  client <- defaultClient+  res <- listModels client+  case res of+    Left err -> putStrLn $ "Error listing models: " <> show err+    Right (ListResponse ms) -> do+      putStrLn "Installed Models:"+      mapM_ (print . miName) ms
+ examples/StreamingChat.hs view
@@ -0,0 +1,18 @@+module Main (main) where++import Data.List.NonEmpty (NonEmpty ((:|)))+import Data.Text.IO qualified as TIO+import Ollama++main :: IO ()+main = do+  client <- defaultClient+  let opts = Just (defaultOptions {optNumPredict = Just 20})+      req =+        (chatRequest "qwen3.5:2b" (userMessage "Count from 1 to 5." :| []))+          { chatOptions = opts+          , chatThink = Just ThinkDisabled+          }+  chunks <- collectStream (chatStream client req)+  mapM_ (TIO.putStr . maybe "" messageContent . crMessage) chunks+  putStrLn ""
+ examples/StructuredOutput.hs view
@@ -0,0 +1,28 @@+module Main (main) where++import Data.Text.IO qualified as TIO+import Ollama+import Ollama.Types.Format.SchemaBuilder++personSchema :: Schema+personSchema =+  buildSchema $+    emptyObject+      |+ ("name", JString)+      |+ ("age", JInteger)+      |! "name"++main :: IO ()+main = do+  client <- defaultClient+  let opts = Just (defaultOptions {optNumPredict = Just 20})+      req =+        (generateRequest "qwen3.5:2b" "Generate a person profile.")+          { genFormat = Just (SchemaFormat personSchema)+          , genOptions = opts+          , genThink = Just ThinkDisabled+          }+  res <- generate client req+  case res of+    Left err -> putStrLn $ "Error: " <> show err+    Right resp -> TIO.putStrLn $ "Structured Response:\n" <> grResponse resp
+ examples/ToolCalling.hs view
@@ -0,0 +1,41 @@+module Main (main) where++import Data.List.NonEmpty (NonEmpty ((:|)))+import Ollama++calculatorTool :: Tool+calculatorTool =+  Tool+    { toolType = "function"+    , toolFunction =+        FunctionDef+          { fnName = "add"+          , fnDescription = Just "Add two numbers"+          , fnParameters =+              Just+                FunctionParameters+                  { fpType = "object"+                  , fpProperties = Nothing+                  , fpRequired = Just ["a", "b"]+                  , fpAdditionalProperties = Nothing+                  , fpDescription = Nothing+                  , fpEnum = Nothing+                  }+          , fnStrict = Just True+          }+    }++main :: IO ()+main = do+  client <- defaultClient+  let opts = Just (defaultOptions {optNumPredict = Just 20})+      req =+        (chatRequest "qwen3.5:2b" (userMessage "What is 25 + 17?" :| []))+          { chatTools = Just [calculatorTool]+          , chatOptions = opts+          , chatThink = Just ThinkDisabled+          }+  res <- chat client req+  case res of+    Left err -> putStrLn $ "Error: " <> show err+    Right resp -> print (crMessage resp)
ollama-haskell.cabal view
@@ -1,115 +1,241 @@-cabal-version: 1.12---- This file has been generated from package.yaml by hpack version 0.38.1.------ see: https://github.com/sol/hpack--name:           ollama-haskell-version:        0.2.1.0-synopsis:       Haskell client for ollama.-description:    Ollama client for Haskell-category:       Web-homepage:       https://github.com/tusharad/ollama-haskell#readme-bug-reports:    https://github.com/tusharad/ollama-haskell/issues-author:         tushar-maintainer:     tusharadhatrao@gmail.com-copyright:      2024 tushar-license:        MIT-license-file:   LICENSE-build-type:     Simple-extra-source-files:-    README.md-    CHANGELOG.md+cabal-version: 3.0+name:          ollama-haskell+version:       0.3.0.0+synopsis:      Industry-grade Haskell client for the Ollama API+description:+  A type-safe, well-tested Haskell client for interacting with+  locally-running LLMs via the Ollama HTTP API. Supports chat,+  text generation, embeddings, model management, streaming via+  conduit, structured outputs, tool calling, and more.+category:      Web, AI, Network+license:       MIT+license-file:  LICENSE+author:        Tushar Adhatrao+maintainer:    tusharadhatrao@gmail.com+copyright:     2024-2026 Tushar Adhatrao+homepage:      https://github.com/tusharad/ollama-haskell+bug-reports:   https://github.com/tusharad/ollama-haskell/issues+tested-with:   GHC == 9.4.8, GHC == 9.6.7, GHC == 9.8.4, GHC == 9.10.3, GHC == 9.12.4+stability:     stable+extra-doc-files:+  README.md+  CHANGELOG.md+  doc/COMPARISON.md  source-repository head   type: git   location: https://github.com/tusharad/ollama-haskell +flag integration-tests+  description: Build and run integration tests (requires running Ollama server)+  default: False+  manual: True++common warnings+  ghc-options:+    -Wall+    -Wcompat+    -Widentities+    -Wincomplete-record-updates+    -Wincomplete-uni-patterns+    -Wmissing-export-lists+    -Wmissing-home-modules+    -Wpartial-fields+    -Wredundant-constraints++common lang+  default-language: GHC2021+  default-extensions:+    StrictData+    DerivingStrategies+    DeriveGeneric+    DeriveAnyClass+    GeneralizedNewtypeDeriving+    OverloadedStrings+    ImportQualifiedPost+    TypeApplications+    RecordWildCards+    NamedFieldPuns+    LambdaCase+    MultiWayIf+    ScopedTypeVariables+    BangPatterns+ library+  import: warnings, lang+  hs-source-dirs: src   exposed-modules:-      Data.Ollama.Blob-      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-      Data.Ollama.Show-      Ollama+    Ollama+    Ollama.Client+    Ollama.Client.Config+    Ollama.API.Generate+    Ollama.API.Chat+    Ollama.API.Embed+    Ollama.API.Models+    Ollama.API.Models.Create+    Ollama.API.Models.Pull+    Ollama.API.Models.Push+    Ollama.API.Blobs+    Ollama.API.Ps+    Ollama.API.Version+    Ollama.Types+    Ollama.Types.Message+    Ollama.Types.Tool+    Ollama.Types.Model+    Ollama.Types.Options+    Ollama.Types.Format+    Ollama.Types.Format.SchemaBuilder+    Ollama.Types.Common+    Ollama.Error+    Ollama.Streaming+    Ollama.Testing+    Ollama.Conversation   other-modules:-      Paths_ollama_haskell-  hs-source-dirs:-      src-  default-extensions:-      ImportQualifiedPost-  ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints+    Ollama.Client.Internal   build-depends:-      aeson ==2.*-    , base >=4.7 && <5-    , 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+      aeson            >= 2.0 && < 3+    , base             >= 4.17 && < 5+    , bytestring       >= 0.10 && < 0.13+    , case-insensitive >= 1.2 && < 1.3+    , conduit          >= 1.3 && < 1.4+    , conduit-extra    >= 1.3 && < 1.4+    , containers       >= 0.6 && < 0.9+    , hashable         >= 1.4 && < 1.6+    , http-client      >= 0.6 && < 0.8+    , http-client-tls  >= 0.2 && < 0.5+    , http-types       >= 0.7 && < 0.13+    , mtl              >= 2.2 && < 3+    , retry            >= 0.9 && < 0.10+    , resourcet        >= 1.3 && < 1.4+    , stm              >= 2.5 && < 3+    , text             >= 2.0 && < 3+    , time             >= 1.11 && < 2+    , unliftio-core    >= 0.2 && < 0.3  test-suite ollama-haskell-test+  import: warnings, lang   type: exitcode-stdio-1.0+  hs-source-dirs: test   main-is: Main.hs   other-modules:-      Test.Ollama.Blob-      Test.Ollama.Chat-      Test.Ollama.Common-      Test.Ollama.Copy-      Test.Ollama.Create-      Test.Ollama.Delete-      Test.Ollama.Embedding-      Test.Ollama.Generate-      Test.Ollama.List-      Test.Ollama.Load-      Test.Ollama.Show-      Paths_ollama_haskell-  hs-source-dirs:-      test-  default-extensions:-      ImportQualifiedPost-  ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N+    Test.Ollama.Unit.Types+    Test.Ollama.Unit.Error+    Test.Ollama.Unit.Config+    Test.Ollama.Unit.SchemaBuilder+    Test.Ollama.Unit.Testing+    Test.Ollama.Property.Arbitrary+    Test.Ollama.Property.Roundtrip+    Test.Ollama.Golden.Chat+    Test.Ollama.Golden.Generate+    Test.Ollama.Golden.Embed+    Test.Ollama.Golden.Models   build-depends:-      aeson-    , base >=4.7 && <5-    , 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.*+      base     , ollama-haskell-    , scientific-    , silently-    , stm ==2.*-    , tasty >=1.5+    , aeson+    , bytestring+    , containers+    , QuickCheck       >= 2.14+    , tasty          >= 1.5+    , tasty-golden   >= 2.3     , tasty-hunit+    , tasty-quickcheck >= 0.10     , text-    , time ==1.*-  default-language: Haskell2010+    , time+    , conduit++test-suite ollama-haskell-integration+  import: warnings, lang+  type: exitcode-stdio-1.0+  hs-source-dirs: test-integration+  main-is: Main.hs+  if !flag(integration-tests)+    buildable: False+  build-depends:+      base+    , ollama-haskell+    , aeson+    , tasty+    , tasty-hunit+    , text+    , time++benchmark ollama-haskell-bench+  import: warnings, lang+  type: exitcode-stdio-1.0+  hs-source-dirs: bench+  main-is: Main.hs+  build-depends:+      base+    , ollama-haskell+    , aeson+    , bytestring+    , tasty          >= 1.5+    , tasty-bench    >= 0.3+    , text++executable ollama-example-basic-chat+  import: warnings, lang+  main-is: BasicChat.hs+  hs-source-dirs: examples+  build-depends:+      base+    , ollama-haskell+    , text++executable ollama-example-streaming-chat+  import: warnings, lang+  main-is: StreamingChat.hs+  hs-source-dirs: examples+  build-depends:+      base+    , ollama-haskell+    , text++executable ollama-example-tool-calling+  import: warnings, lang+  main-is: ToolCalling.hs+  hs-source-dirs: examples+  build-depends:+      base+    , ollama-haskell+    , text++executable ollama-example-structured-output+  import: warnings, lang+  main-is: StructuredOutput.hs+  hs-source-dirs: examples+  build-depends:+      base+    , ollama-haskell+    , text++executable ollama-example-embeddings+  import: warnings, lang+  main-is: Embeddings.hs+  hs-source-dirs: examples+  build-depends:+      base+    , ollama-haskell+    , text++executable ollama-example-model-management+  import: warnings, lang+  main-is: ModelManagement.hs+  hs-source-dirs: examples+  build-depends:+      base+    , ollama-haskell+    , text++executable ollama-example-all-features+  import: warnings, lang+  main-is: AllFeatures.hs+  hs-source-dirs: examples+  build-depends:+      base+    , ollama-haskell+    , aeson+    , text+    , time+
− src/Data/Ollama/Blob.hs
@@ -1,176 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}--{- |-Module      : Data.Ollama.Blob-Copyright   : (c) 2025 Tushar Adhatrao-License     : MIT-Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>-Stability   : experimental-Description : Functions for managing binary large objects (blobs) in the Ollama API.--This module provides functionality for checking the existence of blobs and uploading-files as blobs to the Ollama server. Blobs are used when creating models from-GGUF files or safetensors directories.--The blob operations interact with the @\/api\/blobs@ endpoints:--- 'checkBlobExists' sends a HEAD request to check if a blob exists-- 'createBlob' uploads a file as a blob using streaming POST--Example usage:-->>> let digest = "sha256:29fdb92e57cf0827ded04ae6461b5931d01fa595843f55d36f5b275a52087dd2"->>> exists <- checkBlobExists digest Nothing->>> case exists of->>>   Right True -> putStrLn "Blob exists"->>>   Right False -> putStrLn "Blob not found"->>>   Left err -> putStrLn $ "Error: " ++ show err-->>> result <- createBlob "model.gguf" digest Nothing->>> case result of->>>   Right () -> putStrLn "Blob uploaded successfully"->>>   Left err -> putStrLn $ "Upload failed: " ++ show err--}-module Data.Ollama.Blob-  ( -- * Blob Operations-    checkBlobExists-  , createBlob-  ) where--import Control.Exception (try)-import Data.ByteString qualified as BS-import Data.Maybe (fromMaybe)-import Data.Ollama.Common.Config (OllamaConfig (..), defaultOllamaConfig)-import Data.Ollama.Common.Error-import Data.Ollama.Common.Error qualified as Error-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 (doesFileExist)--{- | Check if a blob exists on the Ollama server.--Sends a HEAD request to @\/api\/blobs\/sha256:\<digest\>@ to check if a blob-with the given SHA256 digest exists on the server.--Returns:-- 'Right' 'True' if the blob exists (HTTP 200 OK)-- 'Right' 'False' if the blob does not exist (HTTP 404 Not Found)-- 'Left' 'OllamaError' for other errors (network issues, invalid digest, etc.)--The digest should be a SHA256 hash string without the "sha256:" prefix.--}-checkBlobExists ::-  -- | SHA256 digest of the blob (without "sha256:" prefix)-  Text ->-  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')-  Maybe OllamaConfig ->-  IO (Either OllamaError Bool)-checkBlobExists digest mbOllamaConfig = do-  let OllamaConfig {..} = fromMaybe defaultOllamaConfig mbOllamaConfig-      endpoint = "/api/blobs/sha256:" <> digest-      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 = "HEAD"}-      eResponse <- try $ httpNoBody request manager-      case eResponse of-        Left ex -> return $ Left $ Error.HttpError ex-        Right response -> do-          let status = statusCode $ responseStatus response-          case status of-            200 -> return $ Right True-            404 -> return $ Right False-            _ ->-              return $-                Left $-                  Error.ApiError $-                    "Unexpected status code: " <> T.pack (show status)--{- | Upload a file as a blob to the Ollama server.--Streams the contents of the file at the given 'FilePath' to the Ollama server-via a POST request to @\/api\/blobs\/sha256:\<digest\>@. The server will verify-that the uploaded file matches the expected SHA256 digest.--Returns:-- 'Right' @()@ if the blob was uploaded successfully (HTTP 201 Created)-- 'Left' 'OllamaError' if the upload failed--The digest should be the expected SHA256 hash of the file without the "sha256:" prefix.-If the file content doesn't match the digest, the server will return an error.--Note: This function streams the file content, so it can handle large files efficiently-without loading them entirely into memory.--}-createBlob ::-  -- | Path to the file to upload-  FilePath ->-  -- | Expected SHA256 digest of the file (without "sha256:" prefix)-  Text ->-  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')-  Maybe OllamaConfig ->-  IO (Either OllamaError ())-createBlob filePath digest mbOllamaConfig = do-  let OllamaConfig {..} = fromMaybe defaultOllamaConfig mbOllamaConfig-      endpoint = "/api/blobs/sha256:" <> digest-      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-      -- check if file exists-      fileExists <- doesFileExist filePath-      if not fileExists-        then return $ Left $ Error.ApiError "File does not exist"-        else do-          -- Create a request body from the file-          fileContent <- BS.readFile filePath-          let request =-                req-                  { method = "POST"-                  , requestBody = RequestBodyBS fileContent-                  }--          eResponse <- try $ withResponse request manager $ \response -> do-            let status = statusCode $ responseStatus response-            case status of-              201 -> return $ Right ()-              400 -> do-                bodyReader <- brRead $ responseBody response-                return $-                  Left $-                    Error.ApiError $-                      "Bad request - digest mismatch: " <> TE.decodeUtf8 bodyReader-              _ -> do-                bodyReader <- brRead $ responseBody response-                return $-                  Left $-                    Error.ApiError $-                      "Unexpected status code " <> T.pack (show status) <> ": " <> TE.decodeUtf8 bodyReader--          case eResponse of-            Left ex -> return $ Left $ Error.HttpError ex-            Right result -> return result
− src/Data/Ollama/Chat.hs
@@ -1,295 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--{- |-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-  , chatM--    -- * Message Types-  , Message (..)-  , Role (..)-  , systemMessage-  , userMessage-  , assistantMessage-  , toolMessage-  , genMessage--    -- * Chat Configuration-  , defaultChatOps-  , ChatOps (..)--    -- * Response Types-  , ChatResponse (..)-  , Format (..)--    -- * Configuration and Error Types-  , OllamaConfig (..)-  , defaultOllamaConfig-  , OllamaError (..)-  , ModelOptions (..)-  , defaultModelOptions--    -- * Tool and Function Types-  , InputTool (..)-  , FunctionDef (..)-  , FunctionParameters (..)-  , OutputFunction (..)-  , ToolCall (..)-  ) where--import Control.Monad.IO.Class (MonadIO (liftIO))-import Data.Aeson-import Data.List.NonEmpty as NonEmpty-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.Text (Text)-import Data.Text qualified as T--{- | Constructs a 'Message' with the specified role and content.--Creates a 'Message' with the given 'Role' and textual content, setting optional fields-('images', 'tool_calls', 'thinking') to 'Nothing'.--Example:-->>> 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-    }--{- | Creates a 'Message' with the 'System' role.--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 = genMessage System--{- | 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 = genMessage User--{- | 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 = genMessage Assistant--{- | 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 = genMessage Tool--{- | 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 (modelName 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-  { modelName :: !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 [InputTool])-  -- ^ Optional tools that may be used in the chat.-  , 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 callback function to be called with each incoming response.-  , 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-        { modelName = 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 =-    modelName a == modelName b-      && messages a == messages b-      && tools a == tools b-      && format a == format b-      && keepAlive a == keepAlive b--instance ToJSON ChatOps where-  toJSON (ChatOps model_ messages_ tools_ format_ stream_ keepAlive_ options_ think_) =-    object-      [ "model" .= model_-      , "messages" .= messages_-      , "tools" .= tools_-      , "format" .= format_-      , "stream" .= if isNothing stream_ then Just False else Just True-      , "keep_alive" .= keepAlive_-      , "options" .= options_-      , "think" .= think_-      ]--{- | Default configuration for initiating a chat.--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", messages = userMessage "Hello!" :| [] }->>> chat ops Nothing-Either OllamaError ChatResponse--}-defaultChatOps :: ChatOps-defaultChatOps =-  ChatOps-    { modelName = "gemma3"-    , messages = userMessage "What is 2+2?" :| []-    , tools = Nothing-    , format = Nothing-    , stream = Nothing-    , keepAlive = Nothing-    , options = Nothing-    , think = Nothing-    }--{- | Sends a chat request to the Ollama API.--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 { chatModelName = "gemma3", messages = userMessage "What's the capital of France?" :| [] }->>> chat ops Nothing-Either OllamaError ChatResponse--}-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 = maybe commonNonStreamingHandler commonStreamHandler (stream ops)--{- | MonadIO version of 'chat' for use in monadic contexts.--Lifts the 'chat' function into a 'MonadIO' context, allowing it to be used in monadic computations.--Example:-->>> 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
@@ -1,90 +0,0 @@-{-# 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
@@ -1,65 +0,0 @@-{-# 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
@@ -1,191 +0,0 @@-{-# 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
@@ -1,464 +0,0 @@-{-# 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 (..)-  , 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)-  -- ^ 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)--instance FromJSON ModelDetails where-  parseJSON = withObject "ModelDetails" $ \v ->-    ModelDetails-      <$> v .: "parent_model"-      <*> v .: "format"-      <*> v .: "family"-      <*> v .:? "families" .!= []-      <*> v .: "parameter_size"-      <*> v .: "quantization_level"--{- | 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-  , doneReason :: !(Maybe Text)-  -- ^ Reason why the generation process completed (e.g., "stop", "length", "cancel").-  -- Available when the Ollama server provides completion reason information.-  ---  -- @since 0.2.1.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"-      <*> v .:? "done_reason"---- | 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.-  , doneReason :: !(Maybe Text)-  -- ^ Reason why the chat process completed (e.g., "stop", "length", "cancel").-  -- Available when the Ollama server provides completion reason information.-  ---  -- @since 0.2.1.0-  }-  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"-      <*> v .:? "done_reason"---- | 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"--{- | 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-  }-  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 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
@@ -1,303 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}--{- |-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---- | 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-  if exists-    then either (const Nothing) Just <$> safeReadFile filePath-    else return Nothing---- | Check if a file has a supported image extension.-isSupportedExtension :: FilePath -> Bool-isSupportedExtension p = map toLower (takeExtension p) `elem` supportedExtensions--{- | 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-  if not (isSupportedExtension filePath)-    then return Nothing-    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 (RequestBodyLBS . encode) 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 (), IO ()) ->-  Response BodyReader ->-  IO (Either OllamaError a)-commonStreamHandler (sendChunk, onComplete) 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-              if getDone res then onComplete >> 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
@@ -1,186 +0,0 @@-{-# 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
@@ -1,86 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# 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.IO.Class (MonadIO (liftIO))-import Data.Aeson-import Data.Ollama.Common.Config (OllamaConfig (..))-import Data.Ollama.Common.Error (OllamaError)-import Data.Ollama.Common.Utils (nonJsonHandler, withOllamaRequest)-import Data.Text (Text)-import GHC.Generics---- | Configuration for copying a model.-data CopyModelOps = CopyModelOps-  { source :: !Text-  -- ^ The name of the source model to copy.-  , destination :: !Text-  -- ^ The name of the destination model.-  }-  deriving (Show, Eq, Generic, ToJSON)--{- | 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 name-  Text ->-  -- | Destination model name-  Text ->-  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')-  Maybe OllamaConfig ->-  IO (Either OllamaError ())-copyModel-  source_-  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
@@ -1,214 +0,0 @@-{-# LANGUAGE DeriveGeneric #-}-{-# 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 new models in the Ollama API. Models can be created from:--- Another existing model (using 'from' parameter)-- A safetensors directory (using 'files' parameter)-- A GGUF file (using 'files' parameter)--The create operation is performed via a POST request to the @\/api\/create@ endpoint, with streaming-support for progress updates. The module supports model quantization, custom templates, system prompts,-parameters, and LORA adapters.--Example creating from existing model:-->>> let ops = defaultCreateOps { modelName = "mario", fromModel = Just "llama3.2", systemPrompt = Just "You are Mario from Super Mario Bros." }->>> createModel ops Nothing-Creating model...-Success--Example quantizing a model:-->>> let ops = defaultCreateOps { modelName = "llama3.2:quantized", fromModel = Just "llama3.2:3b-instruct-fp16", quantizeType = Just Q4_K_M }->>> createModel ops Nothing-Quantizing model...-Success--}-module Data.Ollama.Create-  ( -- * Create Model API-    createModel-  , createModelM--    -- * Configuration Types-  , CreateOps (..)-  , defaultCreateOps--    -- * Response Types-  , CreateResp (..)--    -- * Quantization Types-  , QuantizationType (..)-  ) where--import Control.Monad (void)-import Control.Monad.IO.Class (MonadIO (liftIO))-import Data.Aeson-import Data.Map.Strict (Map)-import Data.Maybe (catMaybes)-import Data.Ollama.Common.Config (OllamaConfig)-import Data.Ollama.Common.Types (HasDone (getDone), Message, ModelOptions)-import Data.Ollama.Common.Utils as CU-import Data.Text (Text)-import GHC.Generics (Generic)-import GHC.Int (Int64)---- | Quantization types supported by Ollama.-data QuantizationType-  = -- | Recommended quantization type-    Q4_K_M-  | -- | Alternative quantization type-    Q4_K_S-  | -- | Recommended quantization type-    Q8_0-  deriving (Show, Eq, Generic)--instance ToJSON QuantizationType where-  toJSON Q4_K_M = String "q4_K_M"-  toJSON Q4_K_S = String "q4_K_S"-  toJSON Q8_0 = String "q8_0"--instance FromJSON QuantizationType where-  parseJSON = withText "QuantizationType" $ \t ->-    case t of-      "q4_K_M" -> pure Q4_K_M-      "q4_K_S" -> pure Q4_K_S-      "q8_0" -> pure Q8_0-      _ -> fail $ "Invalid QuantizationType: " <> show t---- | Configuration for creating a new model.-data CreateOps = CreateOps-  { modelName :: !Text-  -- ^ The name of the model to create.-  , fromModel :: !(Maybe Text)-  -- ^ Optional name of an existing model to create the new model from.-  , files :: !(Maybe (Map Text Text))-  -- ^ Optional dictionary of file names to SHA256 digests of blobs to create the model from.-  , adapters :: !(Maybe (Map Text Text))-  -- ^ Optional dictionary of file names to SHA256 digests of blobs for LORA adapters.-  , template :: !(Maybe Text)-  -- ^ Optional prompt template for the model.-  , license :: !(Maybe [Text])-  -- ^ Optional list of strings containing the license(s) for the model.-  , systemPrompt :: !(Maybe Text)-  -- ^ Optional system prompt for the model.-  , parameters :: !(Maybe ModelOptions)-  -- ^ Optional parameters for the model.-  , messages :: !(Maybe [Message])-  -- ^ Optional list of message objects used to create a conversation.-  , stream :: !(Maybe Bool)-  -- ^ Optional flag to enable streaming progress updates.-  , quantizeType :: !(Maybe QuantizationType)-  -- ^ Optional quantization type for quantizing a non-quantized model.-  }-  deriving (Show, Eq, Generic)---- | Default configuration for creating a model.-defaultCreateOps :: Text -> CreateOps-defaultCreateOps name =-  CreateOps-    { modelName = name-    , fromModel = Nothing-    , files = Nothing-    , adapters = Nothing-    , template = Nothing-    , license = Nothing-    , systemPrompt = Nothing-    , parameters = Nothing-    , messages = Nothing-    , stream = Nothing-    , quantizeType = Nothing-    }---- | Response type for model creation operations.-data CreateResp = CreateResp-  { status :: !Text-  -- ^ The status of the create operation (e.g., "success", "reading model metadata").-  , digest :: !(Maybe Text)-  -- ^ Optional digest (hash) of the model layer being processed.-  , total :: !(Maybe Int64)-  -- ^ Optional total size in bytes for quantization operations.-  , completed :: !(Maybe Int64)-  -- ^ Optional number of bytes completed for quantization operations.-  }-  deriving (Show, Eq, Generic)--instance HasDone CreateResp where-  getDone CreateResp {..} = status == "success"--instance ToJSON CreateOps where-  toJSON CreateOps {..} =-    object $-      catMaybes-        [ Just ("model" .= modelName)-        , ("from" .=) <$> fromModel-        , ("files" .=) <$> files-        , ("adapters" .=) <$> adapters-        , ("template" .=) <$> template-        , ("license" .=) <$> license-        , ("system" .=) <$> systemPrompt-        , ("parameters" .=) <$> parameters-        , ("messages" .=) <$> messages-        , ("stream" .=) <$> stream-        , ("quantize" .=) <$> quantizeType-        ]--instance FromJSON CreateResp where-  parseJSON = withObject "CreateResp" $ \v ->-    CreateResp-      <$> v .: "status"-      <*> v .:? "digest"-      <*> v .:? "total"-      <*> v .:? "completed"--{- | Creates a new model according to the provided configuration.--Sends a POST request to the @\/api\/create@ endpoint to create a model. The model can be created from:--- Another existing model (specify 'fromModel')-- A safetensors directory (specify 'files' with file name to SHA256 digest mappings)-- A GGUF file (specify 'files' with file name to SHA256 digest mapping)--Supports quantization, custom templates, system prompts, parameters, and LORA adapters.-Prints progress messages to the console during creation.--}-createModel ::-  -- | Model creation configuration-  CreateOps ->-  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')-  Maybe OllamaConfig ->-  IO ()-createModel createOps mbConfig =-  void $-    withOllamaRequest-      "/api/create"-      "POST"-      (Just createOps)-      mbConfig-      (commonStreamHandler (onToken, pure ()))-  where-    onToken :: CreateResp -> IO ()-    onToken CreateResp {..} = case (total, completed) of-      (Just t, Just c) -> putStrLn $ "Progress: " <> show c <> "/" <> show t <> " bytes"-      _ -> putStrLn $ "Status: " <> show status--{- | 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.--}-createModelM ::-  MonadIO m =>-  CreateOps ->-  Maybe OllamaConfig ->-  m ()-createModelM createOps mbCfg = liftIO $ createModel createOps mbCfg
− src/Data/Ollama/Delete.hs
@@ -1,71 +0,0 @@-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# 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 Model API-    deleteModel-  , deleteModelM-  ) 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.Utils (nonJsonHandler, withOllamaRequest)-import Data.Text (Text)---- | Request payload for deleting a model.-newtype DeleteModelReq-  = -- | The name of the model to delete.-    DeleteModelReq {name :: Text}-  deriving newtype (Show, Eq)--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 to delete-  Text ->-  -- | 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
@@ -1,189 +0,0 @@-{-# 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)--{- | 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-    { modelName = "nomic-embed-text"-    , input = []-    , truncateInput = Nothing-    , keepAlive = Nothing-    , modelOptions = Nothing-    , dimensions = Nothing-    }---- | Configuration for an embedding request.-data EmbeddingOps = EmbeddingOps-  { modelName :: !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.-  , keepAlive :: !(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-  , dimensions :: !(Maybe Int)-  -- ^ number of dimensions for the embedding-  ---  -- @since 0.2.1.0-  }-  deriving (Show, Eq)---- | Response type for an embedding request.-data EmbeddingResp = EmbeddingResp-  { 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"--instance ToJSON EmbeddingOps where-  toJSON (EmbeddingOps model_ input_ truncate' keepAlive_ ops dimensions_) =-    object-      [ "model" .= model_-      , "input" .= input_-      , "truncate" .= truncate'-      , "keep_alive" .= keepAlive_-      , "options" .= ops-      , "dimensions" .= dimensions_-      ]--{- | Generates embeddings for a list of input texts with full configuration.--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 name-  Text ->-  -- | List of input texts-  [Text] ->-  -- | Optional truncation flag-  Maybe Bool ->-  -- | Optional keep-alive timeout in minutes-  Maybe Int ->-  -- | Optional model options-  Maybe ModelOptions ->-  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')-  Maybe Int ->-  Maybe OllamaConfig ->-  IO (Either OllamaError EmbeddingResp)-embeddingOps modelName_ input_ mTruncate mKeepAlive mbOptions mbDimensions mbConfig = do-  withOllamaRequest-    "/api/embed"-    "POST"-    ( Just $-        EmbeddingOps-          { modelName = modelName_-          , input = input_-          , truncateInput = mTruncate-          , keepAlive = mKeepAlive-          , modelOptions = mbOptions-          , dimensions = mbDimensions-          }-    )-    mbConfig-    commonNonStreamingHandler--{- | Simplified API for generating embeddings.--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 name-  Text ->-  -- | List of input texts-  [Text] ->-  IO (Either OllamaError EmbeddingResp)-embedding modelName_ input_ =-  embeddingOps modelName_ input_ Nothing 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 Int ->-  Maybe OllamaConfig ->-  m (Either OllamaError EmbeddingResp)-embeddingOpsM m ip mbTruncate mbKeepAlive mbOptions mbDimensions mbCfg =-  liftIO $ embeddingOps m ip mbTruncate mbKeepAlive mbOptions mbDimensions mbCfg
− src/Data/Ollama/Generate.hs
@@ -1,248 +0,0 @@-{-# LANGUAGE DuplicateRecordFields #-}-{-# 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-  , GenerateOps (..)-  , validateGenerateOps--    -- * Response and Configuration Types-  , GenerateResponse (..)-  , Format (..)-  , OllamaConfig (..)-  , defaultOllamaConfig-  , ModelOptions (..)-  , defaultModelOptions--    -- * Error Types-  , OllamaError (..)-  ) where--import Control.Monad.IO.Class (MonadIO (liftIO))-import Data.Aeson-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.Text (Text)-import Data.Text qualified as T--{- | Validates 'GenerateOps' to ensure required fields are non-empty.--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:-->>> 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 use for generation (e.g., "gemma3").-  , prompt :: !Text-  -- ^ The prompt text to provide to the model for generating a response.-  , suffix :: Maybe Text-  -- ^ 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 callback function to be called with each incoming response.-  , 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-  show GenerateOps {..} =-    "GenerateOps { "-      <> "model : "-      <> T.unpack modelName-      <> ", prompt : "-      <> T.unpack prompt-      <> ", suffix : "-      <> show suffix-      <> ", images : "-      <> show images-      <> ", format : "-      <> show format-      <> ", system : "-      <> show system-      <> ", template : "-      <> show template-      <> ", stream : "-      <> "Stream functions"-      <> ", raw : "-      <> show raw-      <> ", keepAlive : "-      <> show keepAlive-      <> ", options : "-      <> show options-      <> ", think: "-      <> show think--instance Eq GenerateOps where-  (==) a b =-    modelName a == modelName b-      && prompt a == prompt b-      && suffix a == suffix b-      && images a == images b-      && format a == format b-      && system a == system b-      && template a == template b-      && raw a == raw b-      && keepAlive a == keepAlive b-      && options a == options b-      && think a == think b--instance ToJSON GenerateOps where-  toJSON-    ( GenerateOps-        model-        prompt-        suffix-        images-        format-        system-        template-        stream-        raw-        keepAlive-        options-        think-      ) =-      object-        [ "model" .= model-        , "prompt" .= prompt-        , "suffix" .= suffix-        , "images" .= images-        , "format" .= format-        , "system" .= system-        , "template" .= template-        , "stream" .= if isNothing stream then Just False else Just True-        , "raw" .= raw-        , "keep_alive" .= keepAlive-        , "options" .= options-        , "think" .= think-        ]--{- | Default configuration for text generation.--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 { modelName = "customModel", prompt = "Hello!" }->>> generate ops Nothing--}-defaultGenerateOps :: GenerateOps-defaultGenerateOps =-  GenerateOps-    { modelName = "gemma3"-    , prompt = ""-    , suffix = Nothing-    , images = Nothing-    , format = Nothing-    , system = Nothing-    , template = Nothing-    , stream = Nothing-    , raw = Nothing-    , keepAlive = Nothing-    , options = Nothing-    , think = Nothing-    }--{- | Generates text using the specified model and configuration.--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.--Example:-->>> let ops = defaultGenerateOps { modelName = "gemma3", prompt = "Write a short poem." }->>> generate ops Nothing-Right (GenerateResponse ...)--}-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 = maybe commonNonStreamingHandler commonStreamHandler (stream ops)--{- | MonadIO version of 'generate' for use in monadic contexts.--Lifts the 'generate' function into a 'MonadIO' context, allowing it to be used in monadic computations.--Example:-->>> 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
@@ -1,105 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--{- |-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 ...])--}-module Data.Ollama.List-  ( -- * List Models API-    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.Time-import GHC.Int (Int64)---- | A wrapper type containing a list of available models.-newtype Models-  = -- | List of 'ModelInfo' records describing available models.-    Models [ModelInfo]-  deriving (Eq, Show)---- | Details about a specific model.-data ModelInfo = ModelInfo-  { 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)---- | 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-      <$> v .: "name"-      <*> v .: "modified_at"-      <*> v .: "size"-      <*> v .: "digest"-      <*> v .: "details"--{- | 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 ::-  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')-  Maybe OllamaConfig ->-  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
@@ -1,103 +0,0 @@-{-# 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
@@ -1,109 +0,0 @@-{-# 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-  ( -- * 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.Time-import GHC.Int (Int64)---- | 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-  -- ^ 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-      <$> v .: "name"-      <*> v .: "model"-      <*> v .: "size"-      <*> v .: "digest"-      <*> v .: "details"-      <*> v .: "expires_at"-      <*> v .: "size_vram"--{- | 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
@@ -1,153 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# 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-  ( -- * Pull Model API-    pull-  , pullOps-  , pullM-  , pullOpsM-  ) where--import Control.Monad.IO.Class (MonadIO (liftIO))-import Data.Aeson-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 GHC.Generics-import GHC.Int (Int64)---- | Configuration options for pulling a model.-data PullOps = PullOps-  { 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 (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 downloaded, if available.-  }-  deriving (Show, Eq, Generic, FromJSON)--instance HasDone PullResp where-  getDone PullResp {..} = status /= "success"--{- | Pulls a model with full configuration.--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-  Text ->-  -- | Optional insecure connection flag-  Maybe Bool ->-  -- | Optional streaming flag-  Maybe Bool ->-  -- | 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, pure ()))-  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')--{- | 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:-->>> 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--{- | 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", ...})--}-pullOpsM ::-  MonadIO m =>-  Text ->-  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
@@ -1,115 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# 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 Model API-    push-  , pushM-  ) where--import Control.Monad (void)-import Control.Monad.IO.Class (MonadIO (liftIO))-import Data.Aeson-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 GHC.Generics-import GHC.Int (Int64)---- | Configuration options for pushing a model.-data PushOps = PushOps-  { 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-  -- ^ 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)--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 ->-  -- | Optional insecure connection flag-  Maybe Bool ->-  -- | Optional streaming flag-  Maybe Bool ->-  -- | Optional 'OllamaConfig' (defaults to 'defaultOllamaConfig' if 'Nothing')-  Maybe OllamaConfig ->-  IO ()-push modelName mInsecure mStream mbConfig = do-  void $-    withOllamaRequest-      "/api/push"-      "POST"-      (Just $ PushOps {name = modelName, insecure = mInsecure, stream = mStream})-      mbConfig-      (commonStreamHandler (onToken, pure ()))-  where-    onToken :: PushResp -> IO ()-    onToken _ = putStrLn "Pushing... "--{- | 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
@@ -1,230 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# 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.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 GHC.Generics-import GHC.Int (Int64)---- | Configuration options for requesting model information.-data ShowModelOps = ShowModelOps-  { 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)---- | Response structure for model information.-data ShowModelResponse = ShowModelResponse-  { 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)---- | 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)---- | JSON parsing instance for 'ShowModelResponse'.-instance FromJSON ShowModelResponse where-  parseJSON = withObject "ShowModelResponse" $ \v ->-    ShowModelResponse-      <$> v .: "modelfile"-      <*> v .:? "parameters"-      <*> v .:? "template"-      <*> v .: "details"-      <*> v .: "model_info"-      <*> v .:? "license"-      <*> v .:? "capabilities"---- | JSON parsing instance for 'ShowModelInfo'.-instance FromJSON ShowModelInfo where-  parseJSON = withObject "ModelInfo" $ \v ->-    ShowModelInfo-      <$> v .:? "general.architecture"-      <*> v .:? "general.file_type"-      <*> v .:? "general.parameter_count"-      <*> v .:? "general.quantization_version"-      <*> v .:? "llama.attention.head_count"-      <*> v .:? "llama.attention.head_count_kv"-      <*> v .:? "llama.attention.layer_norm_rms_epsilon"-      <*> v .:? "llama.block_count"-      <*> v .:? "llama.context_length"-      <*> v .:? "llama.embedding_length"-      <*> v .:? "llama.feed_forward_length"-      <*> v .:? "llama.rope.dimension_count"-      <*> v .:? "llama.rope.freq_base"-      <*> v .:? "llama.vocab_size"-      <*> v .:? "tokenizer.ggml.bos_token_id"-      <*> v .:? "tokenizer.ggml.eos_token_id"-      <*> v .:? "tokenizer.ggml.merges"-      <*> v .:? "tokenizer.ggml.model"-      <*> v .:? "tokenizer.ggml.pre"-      <*> v .:? "tokenizer.ggml.token_type"-      <*> v .:? "tokenizer.ggml.tokens"--{- | Retrieves model information with configuration options.--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-  Text ->-  -- | Optional verbose flag-  Maybe Bool ->-  -- | 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--{- | Simplified API for retrieving model information.--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-  Text ->-  IO (Either OllamaError ShowModelResponse)-showModel modelName =-  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,199 +1,189 @@-{-# LANGUAGE DuplicateRecordFields #-}- {- |-Module      : Data.Ollama-Copyright   : (c) 2025 Tushar Adhatrao+Module      : Ollama+Copyright   : (c) 2024-2026 Tushar Adhatrao License     : MIT-Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>-Stability   : experimental+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable 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+Top-level umbrella re-export module for the Ollama Haskell client library. -Import this module as a top-level interface:+== Quick Example  @ 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+main :: IO ()+main = do+  client <- defaultClient+  let req = chatRequest "llama3.2" (userMessage "Why is the sky blue?" :| [])+  result <- chat client req+  case result of+    Left err -> print err+    Right resp -> case crMessage resp of+      Just msg -> putStrLn (messageContent msg)+      Nothing  -> putStrLn "No message returned"+@ -=== 🧰 Utilities+@since 1.0.0.0+-}+module Ollama (+  -- * Client+  OllamaClient,+  newClient,+  defaultClient,+  clientFromEnv,+  closeClient,+  withClient, -- 'defaultModelOptions', 'encodeImage', 'withOllamaRequest'-- 'loadGenModel', 'unloadGenModel' – Load/unload generation models-- 'getVersion' – Ollama server version+  -- * Config & Retry+  OllamaClientConfig (..),+  defaultConfig,+  RetryPolicy (..),+  LogLevel (..), -== 🧾 Types+  -- * API Endpoints -All request/response payloads and enums are exposed, including:+  -- ** Chat+  chat,+  chatStream,+  ChatRequest (..),+  ChatResponse (..),+  chatRequest,+  chatEvalTokensPerSecond,+  chatPromptEvalTokensPerSecond, -- 'ModelOptions', 'OllamaConfig', 'OllamaError', 'Format'-- 'Models', 'ModelInfo', 'ModelDetails', 'ShowModelResponse'-- 'RunningModels', 'RunningModel', 'Version'--}-module Ollama-  ( -- * Main APIs+  -- ** Generate+  generate,+  generateStream,+  GenerateRequest (..),+  GenerateResponse (..),+  generateRequest,+  evalTokensPerSecond,+  promptEvalTokensPerSecond, -    -- ** Generate Texts-    generate-  , generateM-  , defaultGenerateOps-  , GenerateOps (..)-  , GenerateResponse (..)+  -- ** Embeddings+  embed,+  EmbedRequest (..),+  EmbedResponse (..),+  embedRequest,+  embeddings,+  EmbeddingsRequest (..),+  EmbeddingsResponse (..), -    -- ** Chat with LLMs-  , chat-  , chatM-  , Role (..)-  , defaultChatOps-  , ChatResponse (..)-  , ChatOps (..)-  , InputTool (..)-  , FunctionDef (..)-  , FunctionParameters (..)-  , ToolCall (..)-  , OutputFunction (..)+  -- ** Model Management+  listModels,+  showModel,+  copyModel,+  deleteModel,+  ListResponse (..),+  ModelInfo (..),+  RunningModel (..),+  ShowResponse (..), -    -- ** Embeddings-  , embedding-  , embeddingOps-  , embeddingM-  , embeddingOpsM-  , EmbeddingOps (..)-  , EmbeddingResp (..)+  -- ** Create+  createModel,+  createModelStream,+  defaultCreateRequest,+  CreateRequest (..),+  CreateResponse (..),+  QuantizationType (..), -    -- ** Copy Models-  , copyModel-  , copyModelM+  -- ** Pull & Push+  pull,+  pullStream,+  push,+  pushStream,+  PullResponse (..),+  PushResponse (..), -    -- ** Create Models-  , createModel-  , createModelM+  -- ** Blobs+  checkBlob,+  pushBlob, -    -- ** Delete Models-  , deleteModel-  , deleteModelM+  -- ** System+  getVersion,+  listRunning,+  RunningModelsResponse (..), -    -- ** List Models-  , list+  -- * Types & Primitives+  ModelName (..),+  mkModelName,+  Digest (..),+  Base64Image (..),+  Duration (..),+  durationToSeconds,+  durationToMillis,+  tokensPerSecond,+  Version (..),+  Think (..),+  ThinkingLevel (..), -    -- ** List currently running models-  , ps-  , psM+  -- ** Messages+  Role (..),+  Message (..),+  userMessage,+  systemMessage,+  assistantMessage,+  toolMessage,+  toolResultMessage,+  imageMessage, -    -- ** Push and Pull-  , push-  , pushM-  , pull-  , pullM-  , pullOps-  , pullOpsM+  -- ** Tools & Functions+  Tool (..),+  FunctionDef (..),+  FunctionParameters (..),+  ToolCall (..),+  ToolCallFunction (..), -    -- ** Show Model Info-  , showModel-  , showModelOps-  , showModelM-  , showModelOpsM+  -- ** Options & Format+  ModelOptions (..),+  defaultOptions,+  Format (..), -    -- ** Blob Operations-  , checkBlobExists-  , createBlob+  -- * Error Handling+  OllamaError (..),+  isRetryable,+  throwOllama, -    -- * Ollama config-  , defaultOllamaConfig-  , withOnModelStart-  , withOnModelFinish-  , withOnModelError+  -- * Streaming+  HasDone (..),+  collectStream,+  foldStream, -    -- * Utils-  , defaultModelOptions-  , ModelOptions (..)-  , encodeImage-  , withOllamaRequest-  , getVersion-  , loadGenModel-  , unloadGenModel-  , loadGenModelM-  , unloadGenModelM+  -- * Testing Infrastructure+  newMockClient,+  withMockClient,+  mockGenerateResponse,+  mockChatResponse,+  mockEmbedResponse,+  mockListModelsResponse, -    -- * Types-  , ShowModelResponse (..)-  , Models (..)-  , ModelInfo (..)-  , ModelDetails (..)-  , ShowModelInfo (..)-  , RunningModels (..)-  , RunningModel (..)-  , Message (..)-  , Format (..)-  , OllamaError (..)-  , OllamaConfig (..)-  , Version (..)-  )-where+  -- * Conversation Store+  Conversation (..),+  ConversationStore (..),+  InMemoryStore (..),+  initInMemoryStore,+  saveConversationInMemory,+  loadConversationInMemory,+  listConversationsInMemory,+  deleteConversationInMemory,+) where -import Data.Ollama.Blob-import Data.Ollama.Chat-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 hiding (keepAlive, modelName)-import Data.Ollama.Generate-import Data.Ollama.List-import Data.Ollama.Load-import Data.Ollama.Ps hiding (modelName)-import Data.Ollama.Pull-import Data.Ollama.Push-import Data.Ollama.Show+import Ollama.API.Blobs+import Ollama.API.Chat+import Ollama.API.Embed+import Ollama.API.Generate+import Ollama.API.Models+import Ollama.API.Models.Create+import Ollama.API.Models.Pull+import Ollama.API.Models.Push+import Ollama.API.Ps+import Ollama.API.Version+import Ollama.Client+import Ollama.Client.Config+import Ollama.Conversation+import Ollama.Error+import Ollama.Streaming+import Ollama.Testing+import Ollama.Types
+ src/Ollama/API/Blobs.hs view
@@ -0,0 +1,45 @@+{- |+Module      : Ollama.API.Blobs+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Blob management endpoints (@/api/blobs/:digest@).++@since 1.0.0.0+-}+module Ollama.API.Blobs (+  checkBlob,+  pushBlob,+) where++import Control.Monad.IO.Class (MonadIO)+import Data.ByteString (ByteString)+import Data.Functor (void)+import Ollama.Client (OllamaClient)+import Ollama.Client.Internal (requestRaw)+import Ollama.Error (OllamaError (..))+import Ollama.Types.Common (Digest (..))++{- | Check if a blob exists on the server (@HEAD /api/blobs/:digest@).++@since 1.0.0.0+-}+checkBlob :: (MonadIO m) => OllamaClient -> Digest -> m (Either OllamaError Bool)+checkBlob client (Digest d) = do+  res <- requestRaw client "HEAD" ("/api/blobs/" <> d) Nothing+  pure $ case res of+    Right _ -> Right True+    Left (ApiError 404 _) -> Right False+    Left err -> Left err++{- | Push / upload a file blob to the server (@POST /api/blobs/:digest@).++@since 1.0.0.0+-}+pushBlob :: (MonadIO m) => OllamaClient -> Digest -> ByteString -> m (Either OllamaError ())+pushBlob client (Digest d) payload = do+  res <- requestRaw client "POST" ("/api/blobs/" <> d) (Just payload)+  pure $ void res
+ src/Ollama/API/Chat.hs view
@@ -0,0 +1,170 @@+{- |+Module      : Ollama.API.Chat+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Chat completion API endpoint (@/api/chat@).++@since 1.0.0.0+-}+module Ollama.API.Chat (+  ChatRequest (..),+  ChatResponse (..),+  chatRequest,+  chat,+  chatStream,+  chatEvalTokensPerSecond,+  chatPromptEvalTokensPerSecond,+) where++import Conduit (ConduitT)+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.IO.Unlift (MonadUnliftIO)+import Data.Aeson+import Data.List.NonEmpty (NonEmpty)+import Data.Maybe (catMaybes)+import Data.Text (Text)+import Data.Time (UTCTime)+import GHC.Generics (Generic)+import Ollama.Client (OllamaClient)+import Ollama.Client.Internal (request, requestStreaming)+import Ollama.Error (OllamaError)+import Ollama.Streaming (HasDone (..))+import Ollama.Types.Common (Duration, ModelName, Think, tokensPerSecond)+import Ollama.Types.Format (Format)+import Ollama.Types.Message (Message)+import Ollama.Types.Options (ModelOptions)+import Ollama.Types.Tool (Tool)++{- | Chat completion request payload.++@since 1.0.0.0+-}+data ChatRequest = ChatRequest+  { chatModel :: !ModelName+  , chatMessages :: !(NonEmpty Message)+  , chatTools :: !(Maybe [Tool])+  , chatFormat :: !(Maybe Format)+  , chatOptions :: !(Maybe ModelOptions)+  , chStream :: !(Maybe Bool)+  , chatKeepAlive :: !(Maybe Text)+  , chatThink :: !(Maybe Think)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON ChatRequest where+  toJSON ChatRequest {..} =+    object $+      catMaybes+        [ Just $ "model" .= chatModel+        , Just $ "messages" .= chatMessages+        , ("tools" .=) <$> chatTools+        , ("format" .=) <$> chatFormat+        , ("options" .=) <$> chatOptions+        , ("stream" .=) <$> chStream+        , ("keep_alive" .=) <$> chatKeepAlive+        , ("think" .=) <$> chatThink+        ]++{- | Create a default 'ChatRequest' for a model and message history.++@since 1.0.0.0+-}+chatRequest :: ModelName -> NonEmpty Message -> ChatRequest+chatRequest model msgs =+  ChatRequest+    { chatModel = model+    , chatMessages = msgs+    , chatTools = Nothing+    , chatFormat = Nothing+    , chatOptions = Nothing+    , chStream = Just False+    , chatKeepAlive = Nothing+    , chatThink = Nothing+    }++{- | Chat completion response payload.++@since 1.0.0.0+-}+data ChatResponse = ChatResponse+  { crModel :: !ModelName+  , crCreatedAt :: !UTCTime+  , crMessage :: !(Maybe Message)+  , crDone :: !Bool+  , crDoneReason :: !(Maybe Text)+  , crTotalDuration :: !(Maybe Duration)+  , crLoadDuration :: !(Maybe Duration)+  , crPromptEvalCount :: !(Maybe Int)+  , crPromptEvalDuration :: !(Maybe Duration)+  , crEvalCount :: !(Maybe Int)+  , crEvalDuration :: !(Maybe Duration)+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON ChatResponse where+  parseJSON = withObject "ChatResponse" $ \v ->+    ChatResponse+      <$> v .: "model"+      <*> v .: "created_at"+      <*> v .:? "message"+      <*> v .: "done"+      <*> v .:? "done_reason"+      <*> v .:? "total_duration"+      <*> v .:? "load_duration"+      <*> v .:? "prompt_eval_count"+      <*> v .:? "prompt_eval_duration"+      <*> v .:? "eval_count"+      <*> v .:? "eval_duration"++instance ToJSON ChatResponse where+  toJSON ChatResponse {..} =+    object+      [ "model" .= crModel+      , "created_at" .= crCreatedAt+      , "message" .= crMessage+      , "done" .= crDone+      , "done_reason" .= crDoneReason+      , "total_duration" .= crTotalDuration+      , "load_duration" .= crLoadDuration+      , "prompt_eval_count" .= crPromptEvalCount+      , "prompt_eval_duration" .= crPromptEvalDuration+      , "eval_count" .= crEvalCount+      , "eval_duration" .= crEvalDuration+      ]++instance HasDone ChatResponse where+  isDone = crDone++{- | Non-streaming chat completion API.++@since 1.0.0.0+-}+chat :: (MonadIO m) => OllamaClient -> ChatRequest -> m (Either OllamaError ChatResponse)+chat client req = request client "POST" "/api/chat" (Just req {chStream = Just False})++{- | Streaming chat completion API yielding 'ChatResponse' chunks.++@since 1.0.0.0+-}+chatStream :: (MonadUnliftIO m) => OllamaClient -> ChatRequest -> ConduitT () ChatResponse m ()+chatStream client req = requestStreaming client "/api/chat" (req {chStream = Just True})++{- | Calculate generation throughput (eval tokens \/ second) from a 'ChatResponse'.++@since 1.0.0.0+-}+chatEvalTokensPerSecond :: ChatResponse -> Maybe Double+chatEvalTokensPerSecond ChatResponse {..} =+  tokensPerSecond <$> crEvalCount <*> crEvalDuration++{- | Calculate prompt evaluation throughput (prompt tokens \/ second) from a 'ChatResponse'.++@since 1.0.0.0+-}+chatPromptEvalTokensPerSecond :: ChatResponse -> Maybe Double+chatPromptEvalTokensPerSecond ChatResponse {..} =+  tokensPerSecond <$> crPromptEvalCount <*> crPromptEvalDuration
+ src/Ollama/API/Embed.hs view
@@ -0,0 +1,175 @@+{- |+Module      : Ollama.API.Embed+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Vector embeddings API endpoint (@/api/embed@).++@since 1.0.0.0+-}+module Ollama.API.Embed (+  EmbedRequest (..),+  EmbedResponse (..),+  embedRequest,+  embed,++  -- * Deprecated Legacy API+  EmbeddingsRequest (..),+  EmbeddingsResponse (..),+  embeddings,+) where++import Control.Monad.IO.Class (MonadIO)+import Data.Aeson+import Data.Maybe (catMaybes)+import Data.Text (Text)+import GHC.Generics (Generic)+import Ollama.Client (OllamaClient)+import Ollama.Client.Internal (request)+import Ollama.Error (OllamaError)+import Ollama.Types.Common (Duration, ModelName)+import Ollama.Types.Options (ModelOptions)++{- | Embedding request payload for single text or batch list of texts.++@since 1.0.0.0+-}+data EmbedRequest = EmbedRequest+  { embModel :: !ModelName+  , embInput :: !(Either Text [Text])+  , embTruncate :: !(Maybe Bool)+  , embOptions :: !(Maybe ModelOptions)+  , embKeepAlive :: !(Maybe Text)+  , embDimensions :: !(Maybe Int)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON EmbedRequest where+  toJSON EmbedRequest {..} =+    object $+      catMaybes+        [ Just $ "model" .= embModel+        , Just $ case embInput of+            Left single -> "input" .= single+            Right multiple -> "input" .= multiple+        , ("truncate" .=) <$> embTruncate+        , ("options" .=) <$> embOptions+        , ("keep_alive" .=) <$> embKeepAlive+        , ("dimensions" .=) <$> embDimensions+        ]++{- | Create an 'EmbedRequest' for a list of input texts.++@since 1.0.0.0+-}+embedRequest :: ModelName -> [Text] -> EmbedRequest+embedRequest model inputs =+  EmbedRequest+    { embModel = model+    , embInput = Right inputs+    , embTruncate = Nothing+    , embOptions = Nothing+    , embKeepAlive = Nothing+    , embDimensions = Nothing+    }++{- | Embedding response payload containing vector embeddings.++@since 1.0.0.0+-}+data EmbedResponse = EmbedResponse+  { erModel :: !ModelName+  , erEmbeddings :: ![[Double]]+  , erTotalDuration :: !(Maybe Duration)+  , erLoadDuration :: !(Maybe Duration)+  , erPromptEvalCount :: !(Maybe Int)+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON EmbedResponse where+  parseJSON = withObject "EmbedResponse" $ \v ->+    EmbedResponse+      <$> v .: "model"+      <*> v .: "embeddings"+      <*> v .:? "total_duration"+      <*> v .:? "load_duration"+      <*> v .:? "prompt_eval_count"++instance ToJSON EmbedResponse where+  toJSON EmbedResponse {..} =+    object+      [ "model" .= erModel+      , "embeddings" .= erEmbeddings+      , "total_duration" .= erTotalDuration+      , "load_duration" .= erLoadDuration+      , "prompt_eval_count" .= erPromptEvalCount+      ]++{- | Generate vector embeddings.++@since 1.0.0.0+-}+embed :: (MonadIO m) => OllamaClient -> EmbedRequest -> m (Either OllamaError EmbedResponse)+embed client req = request client "POST" "/api/embed" (Just req)++{- | Legacy request payload for deprecated @/api/embeddings@ endpoint.++@since 1.0.0.0+-}+data EmbeddingsRequest = EmbeddingsRequest+  { ebrModel :: !ModelName+  , ebrPrompt :: !Text+  , ebrOptions :: !(Maybe ModelOptions)+  , ebrKeepAlive :: !(Maybe Text)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON EmbeddingsRequest where+  toJSON EmbeddingsRequest {..} =+    object $+      catMaybes+        [ Just $ "model" .= ebrModel+        , Just $ "prompt" .= ebrPrompt+        , ("options" .=) <$> ebrOptions+        , ("keep_alive" .=) <$> ebrKeepAlive+        ]++instance FromJSON EmbeddingsRequest where+  parseJSON = withObject "EmbeddingsRequest" $ \v ->+    EmbeddingsRequest+      <$> v .: "model"+      <*> v .: "prompt"+      <*> v .:? "options"+      <*> v .:? "keep_alive"++{- | Legacy response payload for deprecated @/api/embeddings@ endpoint.++@since 1.0.0.0+-}+newtype EmbeddingsResponse = EmbeddingsResponse+  { ebrEmbedding :: [Double]+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON EmbeddingsResponse where+  parseJSON = withObject "EmbeddingsResponse" $ \v ->+    EmbeddingsResponse <$> v .: "embedding"++instance ToJSON EmbeddingsResponse where+  toJSON EmbeddingsResponse {..} =+    object ["embedding" .= ebrEmbedding]++{- | Generate vector embeddings using the deprecated @/api/embeddings@ endpoint.++@since 1.0.0.0+-}+embeddings ::+  (MonadIO m) =>+  OllamaClient ->+  EmbeddingsRequest ->+  m (Either OllamaError EmbeddingsResponse)+embeddings client req = request client "POST" "/api/embeddings" (Just req)+{-# DEPRECATED embeddings "Use embed instead" #-}
+ src/Ollama/API/Generate.hs view
@@ -0,0 +1,199 @@+{- |+Module      : Ollama.API.Generate+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Text completion API endpoint (@/api/generate@).++@since 1.0.0.0+-}+module Ollama.API.Generate (+  GenerateRequest (..),+  GenerateResponse (..),+  generateRequest,+  generate,+  generateStream,+  evalTokensPerSecond,+  promptEvalTokensPerSecond,+) where++import Conduit (ConduitT)+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.IO.Unlift (MonadUnliftIO)+import Data.Aeson+import Data.Maybe (catMaybes)+import Data.Text (Text)+import Data.Time (UTCTime)+import GHC.Generics (Generic)+import Ollama.Client (OllamaClient)+import Ollama.Client.Internal (request, requestStreaming)+import Ollama.Error (OllamaError)+import Ollama.Streaming (HasDone (..))+import Ollama.Types.Common (Base64Image, Duration, ModelName, Think, tokensPerSecond)+import Ollama.Types.Format (Format)+import Ollama.Types.Options (ModelOptions)++{- | Request payload for text generation completion.++@since 1.0.0.0+-}+data GenerateRequest = GenerateRequest+  { genModel :: !ModelName+  , genPrompt :: !Text+  , genSuffix :: !(Maybe Text)+  , genImages :: !(Maybe [Base64Image])+  , genFormat :: !(Maybe Format)+  , genOptions :: !(Maybe ModelOptions)+  , genSystem :: !(Maybe Text)+  , genTemplate :: !(Maybe Text)+  , genStream :: !(Maybe Bool)+  , genRaw :: !(Maybe Bool)+  , genKeepAlive :: !(Maybe Text)+  , genThink :: !(Maybe Think)+  , genWidth :: !(Maybe Int)+  , genHeight :: !(Maybe Int)+  , genSteps :: !(Maybe Int)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON GenerateRequest where+  toJSON GenerateRequest {..} =+    object $+      catMaybes+        [ Just $ "model" .= genModel+        , Just $ "prompt" .= genPrompt+        , ("suffix" .=) <$> genSuffix+        , ("images" .=) <$> genImages+        , ("format" .=) <$> genFormat+        , ("options" .=) <$> genOptions+        , ("system" .=) <$> genSystem+        , ("template" .=) <$> genTemplate+        , ("stream" .=) <$> genStream+        , ("raw" .=) <$> genRaw+        , ("keep_alive" .=) <$> genKeepAlive+        , ("think" .=) <$> genThink+        , ("width" .=) <$> genWidth+        , ("height" .=) <$> genHeight+        , ("steps" .=) <$> genSteps+        ]++{- | Create a default 'GenerateRequest' for a model and prompt.++@since 1.0.0.0+-}+generateRequest :: ModelName -> Text -> GenerateRequest+generateRequest model prompt =+  GenerateRequest+    { genModel = model+    , genPrompt = prompt+    , genSuffix = Nothing+    , genImages = Nothing+    , genFormat = Nothing+    , genOptions = Nothing+    , genSystem = Nothing+    , genTemplate = Nothing+    , genStream = Just False+    , genRaw = Nothing+    , genKeepAlive = Nothing+    , genThink = Nothing+    , genWidth = Nothing+    , genHeight = Nothing+    , genSteps = Nothing+    }++{- | Response payload returned by text generation.++@since 1.0.0.0+-}+data GenerateResponse = GenerateResponse+  { grModel :: !ModelName+  , grCreatedAt :: !UTCTime+  , grResponse :: !Text+  , grDone :: !Bool+  , grDoneReason :: !(Maybe Text)+  , grContext :: !(Maybe [Int])+  , grTotalDuration :: !(Maybe Duration)+  , grLoadDuration :: !(Maybe Duration)+  , grPromptEvalCount :: !(Maybe Int)+  , grPromptEvalDuration :: !(Maybe Duration)+  , grEvalCount :: !(Maybe Int)+  , grEvalDuration :: !(Maybe Duration)+  , grThinking :: !(Maybe Text)+  , grImage :: !(Maybe Base64Image)+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON GenerateResponse where+  parseJSON = withObject "GenerateResponse" $ \v ->+    GenerateResponse+      <$> v .: "model"+      <*> v .: "created_at"+      <*> v .: "response"+      <*> v .: "done"+      <*> v .:? "done_reason"+      <*> v .:? "context"+      <*> v .:? "total_duration"+      <*> v .:? "load_duration"+      <*> v .:? "prompt_eval_count"+      <*> v .:? "prompt_eval_duration"+      <*> v .:? "eval_count"+      <*> v .:? "eval_duration"+      <*> v .:? "thinking"+      <*> v .:? "image"++instance ToJSON GenerateResponse where+  toJSON GenerateResponse {..} =+    object+      [ "model" .= grModel+      , "created_at" .= grCreatedAt+      , "response" .= grResponse+      , "done" .= grDone+      , "done_reason" .= grDoneReason+      , "context" .= grContext+      , "total_duration" .= grTotalDuration+      , "load_duration" .= grLoadDuration+      , "prompt_eval_count" .= grPromptEvalCount+      , "prompt_eval_duration" .= grPromptEvalDuration+      , "eval_count" .= grEvalCount+      , "eval_duration" .= grEvalDuration+      , "thinking" .= grThinking+      , "image" .= grImage+      ]++instance HasDone GenerateResponse where+  isDone = grDone++{- | Non-streaming text completion API.++@since 1.0.0.0+-}+generate ::+  (MonadIO m) => OllamaClient -> GenerateRequest -> m (Either OllamaError GenerateResponse)+generate client req = request client "POST" "/api/generate" (Just req {genStream = Just False})++{- | Streaming text completion API yielding 'GenerateResponse' chunks.++@since 1.0.0.0+-}+generateStream ::+  (MonadUnliftIO m) => OllamaClient -> GenerateRequest -> ConduitT () GenerateResponse m ()+generateStream client req = requestStreaming client "/api/generate" (req {genStream = Just True})++{- | Calculate generation throughput (eval tokens \/ second) from a 'GenerateResponse'.++@since 1.0.0.0+-}+evalTokensPerSecond :: GenerateResponse -> Maybe Double+evalTokensPerSecond GenerateResponse {..} =+  tokensPerSecond <$> grEvalCount <*> grEvalDuration++{- | Calculate prompt evaluation throughput (prompt tokens \/ second) from a 'GenerateResponse'.++@since 1.0.0.0+-}+promptEvalTokensPerSecond :: GenerateResponse -> Maybe Double+promptEvalTokensPerSecond GenerateResponse {..} =+  tokensPerSecond <$> grPromptEvalCount <*> grPromptEvalDuration
+ src/Ollama/API/Models.hs view
@@ -0,0 +1,171 @@+{- |+Module      : Ollama.API.Models+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Model management endpoints (list, show, copy, delete).++@since 1.0.0.0+-}+module Ollama.API.Models (+  -- * Listing+  listModels,+  ListResponse (..),++  -- * Show Info+  showModel,+  ShowRequest (..),+  ShowResponse (..),+  ShowModelInfo (..),++  -- * Copy+  copyModel,+  CopyRequest (..),++  -- * Delete+  deleteModel,+  DeleteRequest (..),+) where++import Control.Monad.IO.Class (MonadIO)+import Data.Aeson+import Data.Map.Strict (Map)+import Data.Maybe (catMaybes)+import Data.Text (Text)+import GHC.Generics (Generic)+import Ollama.Client (OllamaClient)+import Ollama.Client.Internal (request)+import Ollama.Error (OllamaError)+import Ollama.Types.Common (ModelName)+import Ollama.Types.Model (ListResponse (..), ModelDetails (..))++{- | Show model info request payload.++@since 1.0.0.0+-}+data ShowRequest = ShowRequest+  { srqModel :: !ModelName+  , srqVerbose :: !(Maybe Bool)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON ShowRequest where+  toJSON ShowRequest {..} =+    object $+      catMaybes+        [ Just $ "model" .= srqModel+        , ("verbose" .=) <$> srqVerbose+        ]++{- | Detailed technical parameters from model metadata.++@since 1.0.0.0+-}+newtype ShowModelInfo = ShowModelInfo+  { modelInfoMap :: Map Text Value+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON ShowModelInfo where+  parseJSON v = ShowModelInfo <$> parseJSON v++instance ToJSON ShowModelInfo where+  toJSON (ShowModelInfo m) = toJSON m++{- | Model inspection response payload.++@since 1.0.0.0+-}+data ShowResponse = ShowResponse+  { srsModelfile :: !Text+  , srsParameters :: !(Maybe Text)+  , srsTemplate :: !(Maybe Text)+  , srsDetails :: !ModelDetails+  , srsModelInfo :: !(Maybe ShowModelInfo)+  , srsLicense :: !(Maybe Text)+  , srsCapabilities :: !(Maybe [Text])+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON ShowResponse where+  parseJSON = withObject "ShowResponse" $ \v ->+    ShowResponse+      <$> v .:? "modelfile" .!= ""+      <*> v .:? "parameters"+      <*> v .:? "template"+      <*> v .:? "details" .!= ModelDetails Nothing "" "" [] "" ""+      <*> v .:? "model_info"+      <*> v .:? "license"+      <*> v .:? "capabilities"++instance ToJSON ShowResponse where+  toJSON ShowResponse {..} =+    object+      [ "modelfile" .= srsModelfile+      , "parameters" .= srsParameters+      , "template" .= srsTemplate+      , "details" .= srsDetails+      , "model_info" .= srsModelInfo+      , "license" .= srsLicense+      , "capabilities" .= srsCapabilities+      ]++{- | Copy model request payload.++@since 1.0.0.0+-}+data CopyRequest = CopyRequest+  { cpSource :: !ModelName+  , cpDestination :: !ModelName+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON CopyRequest where+  toJSON CopyRequest {..} =+    object+      [ "source" .= cpSource+      , "destination" .= cpDestination+      ]++{- | Delete model request payload.++@since 1.0.0.0+-}+newtype DeleteRequest = DeleteRequest+  { delModel :: ModelName+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON DeleteRequest where+  toJSON DeleteRequest {..} = object ["model" .= delModel]++{- | List installed local models (@GET /api/tags@).++@since 1.0.0.0+-}+listModels :: (MonadIO m) => OllamaClient -> m (Either OllamaError ListResponse)+listModels client = request client "GET" "/api/tags" (Nothing :: Maybe Value)++{- | Fetch information and Modelfile content for a model (@POST /api/show@).++@since 1.0.0.0+-}+showModel :: (MonadIO m) => OllamaClient -> ModelName -> m (Either OllamaError ShowResponse)+showModel client model = request client "POST" "/api/show" (Just $ ShowRequest model Nothing)++{- | Duplicate an existing model under a new tag (@POST /api/copy@).++@since 1.0.0.0+-}+copyModel :: (MonadIO m) => OllamaClient -> ModelName -> ModelName -> m (Either OllamaError ())+copyModel client src dst = request client "POST" "/api/copy" (Just $ CopyRequest src dst)++{- | Delete a local model (@DELETE /api/delete@).++@since 1.0.0.0+-}+deleteModel :: (MonadIO m) => OllamaClient -> ModelName -> m (Either OllamaError ())+deleteModel client model = request client "DELETE" "/api/delete" (Just $ DeleteRequest model)
+ src/Ollama/API/Models/Create.hs view
@@ -0,0 +1,165 @@+{- |+Module      : Ollama.API.Models.Create+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Model creation endpoint (@/api/create@).++@since 1.0.0.0+-}+module Ollama.API.Models.Create (+  CreateRequest (..),+  CreateResponse (..),+  QuantizationType (..),+  createModel,+  createModelStream,+  defaultCreateRequest,+) where++import Conduit (ConduitT)+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.IO.Unlift (MonadUnliftIO)+import Data.Aeson+import Data.Int (Int64)+import Data.Map.Strict (Map)+import Data.Maybe (catMaybes)+import Data.Text (Text)+import GHC.Generics (Generic)+import Ollama.Client (OllamaClient)+import Ollama.Client.Internal (request, requestStreaming)+import Ollama.Error (OllamaError)+import Ollama.Streaming (HasDone (..))+import Ollama.Types.Common (Digest, ModelName)+import Ollama.Types.Message (Message)+import Ollama.Types.Options (ModelOptions)++{- | Quantization precision options for model creation.++@since 1.0.0.0+-}+data QuantizationType = Q4_K_M | Q4_K_S | Q8_0+  deriving stock (Eq, Show, Bounded, Enum, Generic)++instance ToJSON QuantizationType where+  toJSON Q4_K_M = String "q4_K_M"+  toJSON Q4_K_S = String "q4_K_S"+  toJSON Q8_0 = String "q8_0"++instance FromJSON QuantizationType where+  parseJSON = withText "QuantizationType" $ \case+    "q4_K_M" -> pure Q4_K_M+    "q4_K_S" -> pure Q4_K_S+    "q8_0" -> pure Q8_0+    other -> fail $ "Invalid QuantizationType: " <> show other++{- | Model creation request configuration payload.++@since 1.0.0.0+-}+data CreateRequest = CreateRequest+  { crqModel :: !ModelName+  , crqFrom :: !(Maybe ModelName)+  , crqFiles :: !(Maybe (Map Text Digest))+  , crqAdapters :: !(Maybe (Map Text Digest))+  , crqTemplate :: !(Maybe Text)+  , crqRenderer :: !(Maybe Text)+  , crqParser :: !(Maybe Text)+  , crqLicense :: !(Maybe [Text])+  , crqSystem :: !(Maybe Text)+  , crqParameters :: !(Maybe ModelOptions)+  , crqMessages :: !(Maybe [Message])+  , crqStream :: !(Maybe Bool)+  , crqQuantize :: !(Maybe QuantizationType)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON CreateRequest where+  toJSON CreateRequest {..} =+    object $+      catMaybes+        [ Just $ "model" .= crqModel+        , ("from" .=) <$> crqFrom+        , ("files" .=) <$> crqFiles+        , ("adapters" .=) <$> crqAdapters+        , ("template" .=) <$> crqTemplate+        , ("renderer" .=) <$> crqRenderer+        , ("parser" .=) <$> crqParser+        , ("license" .=) <$> crqLicense+        , ("system" .=) <$> crqSystem+        , ("parameters" .=) <$> crqParameters+        , ("messages" .=) <$> crqMessages+        , ("stream" .=) <$> crqStream+        , ("quantize" .=) <$> crqQuantize+        ]++{- | Smart constructor for a basic 'CreateRequest'.++@since 1.0.0.0+-}+defaultCreateRequest :: ModelName -> CreateRequest+defaultCreateRequest name =+  CreateRequest+    { crqModel = name+    , crqFrom = Nothing+    , crqFiles = Nothing+    , crqAdapters = Nothing+    , crqTemplate = Nothing+    , crqRenderer = Nothing+    , crqParser = Nothing+    , crqLicense = Nothing+    , crqSystem = Nothing+    , crqParameters = Nothing+    , crqMessages = Nothing+    , crqStream = Just False+    , crqQuantize = Nothing+    }++{- | Progress / status response during model creation.++@since 1.0.0.0+-}+data CreateResponse = CreateResponse+  { crsStatus :: !Text+  , crsDigest :: !(Maybe Digest)+  , crsTotal :: !(Maybe Int64)+  , crsCompleted :: !(Maybe Int64)+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON CreateResponse where+  parseJSON = withObject "CreateResponse" $ \v ->+    CreateResponse+      <$> v .: "status"+      <*> v .:? "digest"+      <*> v .:? "total"+      <*> v .:? "completed"++instance ToJSON CreateResponse where+  toJSON CreateResponse {..} =+    object+      [ "status" .= crsStatus+      , "digest" .= crsDigest+      , "total" .= crsTotal+      , "completed" .= crsCompleted+      ]++instance HasDone CreateResponse where+  isDone CreateResponse {..} = crsStatus == "success"++{- | Create a model non-streaming.++@since 1.0.0.0+-}+createModel :: (MonadIO m) => OllamaClient -> CreateRequest -> m (Either OllamaError CreateResponse)+createModel client req = request client "POST" "/api/create" (Just req {crqStream = Just False})++{- | Create a model streaming progress updates.++@since 1.0.0.0+-}+createModelStream ::+  (MonadUnliftIO m) => OllamaClient -> CreateRequest -> ConduitT () CreateResponse m ()+createModelStream client req = requestStreaming client "/api/create" (req {crqStream = Just True})
+ src/Ollama/API/Models/Pull.hs view
@@ -0,0 +1,100 @@+{- |+Module      : Ollama.API.Models.Pull+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Model pull endpoint (@/api/pull@).++@since 1.0.0.0+-}+module Ollama.API.Models.Pull (+  PullRequest (..),+  PullResponse (..),+  pull,+  pullStream,+) where++import Conduit (ConduitT)+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.IO.Unlift (MonadUnliftIO)+import Data.Aeson+import Data.Int (Int64)+import Data.Maybe (catMaybes)+import Data.Text (Text)+import GHC.Generics (Generic)+import Ollama.Client (OllamaClient)+import Ollama.Client.Internal (request, requestStreaming)+import Ollama.Error (OllamaError)+import Ollama.Streaming (HasDone (..))+import Ollama.Types.Common (Digest, ModelName)++{- | Pull model request configuration payload.++@since 1.0.0.0+-}+data PullRequest = PullRequest+  { prqModel :: !ModelName+  , prqInsecure :: !(Maybe Bool)+  , prqStream :: !(Maybe Bool)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON PullRequest where+  toJSON PullRequest {..} =+    object $+      catMaybes+        [ Just $ "model" .= prqModel+        , ("insecure" .=) <$> prqInsecure+        , ("stream" .=) <$> prqStream+        ]++{- | Pull progress/status response payload.++@since 1.0.0.0+-}+data PullResponse = PullResponse+  { prStatus :: !Text+  , prDigest :: !(Maybe Digest)+  , prTotal :: !(Maybe Int64)+  , prCompleted :: !(Maybe Int64)+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON PullResponse where+  parseJSON = withObject "PullResponse" $ \v ->+    PullResponse+      <$> v .: "status"+      <*> v .:? "digest"+      <*> v .:? "total"+      <*> v .:? "completed"++instance ToJSON PullResponse where+  toJSON PullResponse {..} =+    object+      [ "status" .= prStatus+      , "digest" .= prDigest+      , "total" .= prTotal+      , "completed" .= prCompleted+      ]++instance HasDone PullResponse where+  isDone PullResponse {..} = prStatus == "success"++{- | Download / pull a model (non-streaming, blocks until complete).++@since 1.0.0.0+-}+pull :: (MonadIO m) => OllamaClient -> ModelName -> m (Either OllamaError PullResponse)+pull client model =+  request client "POST" "/api/pull" (Just $ PullRequest model Nothing (Just False))++{- | Download / pull a model streaming progress updates.++@since 1.0.0.0+-}+pullStream :: (MonadUnliftIO m) => OllamaClient -> ModelName -> ConduitT () PullResponse m ()+pullStream client model =+  requestStreaming client "/api/pull" (PullRequest model Nothing (Just True))
+ src/Ollama/API/Models/Push.hs view
@@ -0,0 +1,100 @@+{- |+Module      : Ollama.API.Models.Push+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Model push endpoint (@/api/push@).++@since 1.0.0.0+-}+module Ollama.API.Models.Push (+  PushRequest (..),+  PushResponse (..),+  push,+  pushStream,+) where++import Conduit (ConduitT)+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.IO.Unlift (MonadUnliftIO)+import Data.Aeson+import Data.Int (Int64)+import Data.Maybe (catMaybes)+import Data.Text (Text)+import GHC.Generics (Generic)+import Ollama.Client (OllamaClient)+import Ollama.Client.Internal (request, requestStreaming)+import Ollama.Error (OllamaError)+import Ollama.Streaming (HasDone (..))+import Ollama.Types.Common (Digest, ModelName)++{- | Push model request payload.++@since 1.0.0.0+-}+data PushRequest = PushRequest+  { psqModel :: !ModelName+  , psqInsecure :: !(Maybe Bool)+  , psqStream :: !(Maybe Bool)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON PushRequest where+  toJSON PushRequest {..} =+    object $+      catMaybes+        [ Just $ "model" .= psqModel+        , ("insecure" .=) <$> psqInsecure+        , ("stream" .=) <$> psqStream+        ]++{- | Push progress response payload.++@since 1.0.0.0+-}+data PushResponse = PushResponse+  { psStatus :: !Text+  , psDigest :: !(Maybe Digest)+  , psTotal :: !(Maybe Int64)+  , psCompleted :: !(Maybe Int64)+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON PushResponse where+  parseJSON = withObject "PushResponse" $ \v ->+    PushResponse+      <$> v .: "status"+      <*> v .:? "digest"+      <*> v .:? "total"+      <*> v .:? "completed"++instance ToJSON PushResponse where+  toJSON PushResponse {..} =+    object+      [ "status" .= psStatus+      , "digest" .= psDigest+      , "total" .= psTotal+      , "completed" .= psCompleted+      ]++instance HasDone PushResponse where+  isDone PushResponse {..} = psStatus == "success"++{- | Push a model to a remote library (non-streaming).++@since 1.0.0.0+-}+push :: (MonadIO m) => OllamaClient -> ModelName -> m (Either OllamaError PushResponse)+push client model =+  request client "POST" "/api/push" (Just $ PushRequest model Nothing (Just False))++{- | Push a model streaming upload progress updates.++@since 1.0.0.0+-}+pushStream :: (MonadUnliftIO m) => OllamaClient -> ModelName -> ConduitT () PushResponse m ()+pushStream client model =+  requestStreaming client "/api/push" (PushRequest model Nothing (Just True))
+ src/Ollama/API/Ps.hs view
@@ -0,0 +1,31 @@+{- |+Module      : Ollama.API.Ps+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Running models endpoint (@/api/ps@).++@since 1.0.0.0+-}+module Ollama.API.Ps (+  listRunning,+  RunningModelsResponse (..),+  RunningModel (..),+) where++import Control.Monad.IO.Class (MonadIO)+import Data.Aeson (Value)+import Ollama.Client (OllamaClient)+import Ollama.Client.Internal (request)+import Ollama.Error (OllamaError)+import Ollama.Types.Model (RunningModel (..), RunningModelsResponse (..))++{- | List models currently loaded into memory (@GET /api/ps@).++@since 1.0.0.0+-}+listRunning :: (MonadIO m) => OllamaClient -> m (Either OllamaError RunningModelsResponse)+listRunning client = request client "GET" "/api/ps" (Nothing :: Maybe Value)
+ src/Ollama/API/Version.hs view
@@ -0,0 +1,30 @@+{- |+Module      : Ollama.API.Version+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Version endpoint (@/api/version@).++@since 1.0.0.0+-}+module Ollama.API.Version (+  getVersion,+  Version (..),+) where++import Control.Monad.IO.Class (MonadIO)+import Data.Aeson (Value)+import Ollama.Client (OllamaClient)+import Ollama.Client.Internal (request)+import Ollama.Error (OllamaError)+import Ollama.Types.Common (Version (..))++{- | Retrieve Ollama server engine version (@GET /api/version@).++@since 1.0.0.0+-}+getVersion :: (MonadIO m) => OllamaClient -> m (Either OllamaError Version)+getVersion client = request client "GET" "/api/version" (Nothing :: Maybe Value)
+ src/Ollama/Client.hs view
@@ -0,0 +1,110 @@+{- |+Module      : Ollama.Client+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Opaque client management and construction functions.++@since 1.0.0.0+-}+module Ollama.Client (+  OllamaClient (..),+  newClient,+  defaultClient,+  clientFromEnv,+  closeClient,+  withClient,+) where++import Control.Monad.IO.Class (MonadIO (liftIO))+import Control.Monad.IO.Unlift (MonadUnliftIO, withRunInIO)+import Data.Text (Text)+import Data.Text qualified as T+import Network.HTTP.Client (Manager, newManager)+import Network.HTTP.Client.TLS (tlsManagerSettings)+import Ollama.Client.Config (OllamaClientConfig (..), defaultConfig)+import System.Environment (lookupEnv)++{- | Opaque client handle for dispatching API calls.++@since 1.0.0.0+-}+data OllamaClient = OllamaClient+  { clientManager :: !Manager+  , clientConfig :: !OllamaClientConfig+  , clientOwned :: !Bool+  }++{- | Construct a client with custom configuration settings.++@since 1.0.0.0+-}+newClient :: (MonadIO m) => OllamaClientConfig -> m OllamaClient+newClient cfg = liftIO $ do+  case configManager cfg of+    Just mgr -> pure $ OllamaClient mgr cfg False+    Nothing -> do+      mgr <- newManager tlsManagerSettings+      pure $ OllamaClient mgr cfg True++{- | Construct a client with default settings (@http://127.0.0.1:11434@).++@since 1.0.0.0+-}+defaultClient :: (MonadIO m) => m OllamaClient+defaultClient = newClient defaultConfig++{- | Construct a client resolving host and credentials from environment variables+(@OLLAMA_HOST@, @OLLAMA_API_KEY@).++Parses @OLLAMA_HOST@ robustly, handling these formats:++  * @host:port@        → @http:\/\/host:port@+  * @http:\/\/host:port@ → used as-is+  * @host@             → @http:\/\/host:11434@++@since 1.0.0.0+-}+clientFromEnv :: (MonadIO m) => m OllamaClient+clientFromEnv = liftIO $ do+  mbHost <- lookupEnv "OLLAMA_HOST"+  mbKey <- lookupEnv "OLLAMA_API_KEY"+  let hostText = maybe "http://127.0.0.1:11434" (normalizeHost . T.pack) mbHost+      keyText = T.pack <$> mbKey+      cfg = defaultConfig {configBaseUrl = hostText, configApiKey = keyText}+  newClient cfg++{- | Normalize an @OLLAMA_HOST@ value to a full URL with scheme.++Handles: bare @host:port@, @http(s):\/\/host:port@, and bare @host@.++@since 1.0.0.0+-}+normalizeHost :: Text -> Text+normalizeHost raw+  | "http://" `T.isPrefixOf` raw || "https://" `T.isPrefixOf` raw = T.dropWhileEnd (== '/') raw+  | ":" `T.isInfixOf` raw = "http://" <> T.dropWhileEnd (== '/') raw+  | otherwise = "http://" <> T.dropWhileEnd (== '/') raw <> ":11434"++{- | Close the underlying HTTP connection manager if owned by this client.++Note: Connection managers in @http-client@ are automatically reclaimed by garbage collection.++@since 1.0.0.0+-}+closeClient :: (MonadIO m) => OllamaClient -> m ()+closeClient _ = pure ()++{- | Resource bracket helper to initialize, run a computation, and close client resources.++@since 1.0.0.0+-}+withClient :: (MonadUnliftIO m) => OllamaClientConfig -> (OllamaClient -> m a) -> m a+withClient cfg action = withRunInIO $ \run -> do+  client <- newClient cfg+  res <- run (action client)+  closeClient client+  pure res
+ src/Ollama/Client/Config.hs view
@@ -0,0 +1,103 @@+{- |+Module      : Ollama.Client.Config+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Client configuration settings, retry policies, and logging thresholds.++@since 3.0.0.0+-}+module Ollama.Client.Config (+  OllamaClientConfig (..),+  defaultConfig,+  RetryPolicy (..),+  noRetry,+  constantRetry,+  exponentialRetry,+  LogLevel (..),+) where++import Data.ByteString (ByteString)+import Data.CaseInsensitive (CI)+import Data.Text (Text)+import Network.HTTP.Client (Manager)++{- | Logging levels for structured client events.++@since 3.0.0.0+-}+data LogLevel = Debug | Info | Warn | Error+  deriving stock (Eq, Ord, Show, Bounded, Enum)++{- | Configurable retry strategy for recoverable network errors.++@since 3.0.0.0+-}+data RetryPolicy+  = -- | Disable all retries+    NoRetry+  | -- | Retry up to @count@ times with fixed @delayMicros@ interval+    ConstantRetry !Int !Int+  | -- | Retry up to @count@ times with exponential backoff starting at @baseDelayMicros@+    ExponentialRetry !Int !Int+  deriving stock (Eq, Show)++{- | Helper constructor for 'NoRetry'.++@since 3.0.0.0+-}+noRetry :: RetryPolicy+noRetry = NoRetry++{- | Helper constructor for 'ConstantRetry'.++@since 3.0.0.0+-}+constantRetry :: Int -> Int -> RetryPolicy+constantRetry = ConstantRetry++{- | Helper constructor for 'ExponentialRetry'.++@since 3.0.0.0+-}+exponentialRetry :: Int -> Int -> RetryPolicy+exponentialRetry = ExponentialRetry++{- | Configuration settings for an 'OllamaClient'.++@since 3.0.0.0+-}+data OllamaClientConfig = OllamaClientConfig+  { configBaseUrl :: !Text+  , configTimeout :: !Int+  , configRetry :: !RetryPolicy+  , configManager :: !(Maybe Manager)+  , configHeaders :: ![(CI ByteString, ByteString)]+  , configApiKey :: !(Maybe Text)+  , configLogger :: !(Maybe (LogLevel -> Text -> IO ()))+  , configOnStart :: !(Maybe (IO ()))+  , configOnSuccess :: !(Maybe (IO ()))+  , configOnError :: !(Maybe (IO ()))+  }++{- | Default configuration connecting to @http://127.0.0.1:11434@ with 90s timeout and 'NoRetry'.++@since 3.0.0.0+-}+defaultConfig :: OllamaClientConfig+defaultConfig =+  OllamaClientConfig+    { configBaseUrl = "http://127.0.0.1:11434"+    , configTimeout = 90+    , configRetry = NoRetry+    , configManager = Nothing+    , configHeaders = []+    , configApiKey = Nothing+    , configLogger = Nothing+    , configOnStart = Nothing+    , configOnSuccess = Nothing+    , configOnError = Nothing+    }
+ src/Ollama/Client/Internal.hs view
@@ -0,0 +1,276 @@+{- |+Module      : Ollama.Client.Internal+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Low-level HTTP transport plumbing and request dispatchers.++Implements retry logic, lifecycle callbacks, structured logging,+authentication header injection, and conduit-based response streaming.++@since 1.0.0.0+-}+module Ollama.Client.Internal (+  request,+  requestRaw,+  requestStreaming,+) where++import Conduit (+  ConduitT,+  awaitForever,+  bracketP,+  filterC,+  takeWhileC,+  transPipe,+  yield,+  (.|),+ )+import Control.Exception (SomeException, catch, try)+import Control.Monad.IO.Class (MonadIO (liftIO))+import Control.Monad.IO.Unlift (MonadUnliftIO)+import Control.Monad.Trans.Resource (runResourceT)+import Control.Retry qualified as Retry+import Data.Aeson (FromJSON, ToJSON, eitherDecode, encode)+import Data.ByteString (ByteString)+import Data.ByteString qualified as BS+import Data.ByteString.Lazy qualified as BSL+import Data.CaseInsensitive (CI)+import Data.Conduit.Binary qualified as CB+import Data.Conduit.Combinators (repeatM)+import Data.Text (Text)+import Data.Text qualified as T+import Data.Text.Encoding qualified as TE+import Network.HTTP.Client+import Network.HTTP.Types (statusCode)+import Ollama.Client (OllamaClient (..))+import Ollama.Client.Config (LogLevel (..), OllamaClientConfig (..), RetryPolicy (..))+import Ollama.Error (OllamaError (..), isRetryable)++-- ---------------------------------------------------------------------------+-- Public API+-- ---------------------------------------------------------------------------++{- | Dispatch a non-streaming JSON API request.++Applies authentication headers, retry policy, lifecycle callbacks,+and structured logging as configured on the client.++@since 1.0.0.0+-}+request ::+  (MonadIO m, ToJSON req, FromJSON resp) =>+  OllamaClient ->+  ByteString ->+  Text ->+  Maybe req ->+  m (Either OllamaError resp)+request client reqMethod endpoint mbPayload =+  liftIO $+    withRetry client endpoint $+      executeJsonRequest client reqMethod endpoint mbPayload++{- | Dispatch a raw (non-JSON) request returning raw bytes.++Used for blob endpoints where the response body is not JSON.+Applies authentication headers, retry policy, lifecycle callbacks,+and structured logging.++@since 1.0.0.0+-}+requestRaw ::+  (MonadIO m) =>+  OllamaClient ->+  ByteString ->+  Text ->+  Maybe ByteString ->+  m (Either OllamaError ByteString)+requestRaw client reqMethod endpoint mbPayload =+  liftIO $+    withRetry client endpoint $+      executeRawRequest client reqMethod endpoint mbPayload++{- | Dispatch a conduit-based streaming API request.++Opens an HTTP response stream, reads line-delimited JSON chunks as they arrive,+decodes each chunk, and yields values into a 'ConduitT'. Stops when the server+closes the connection.++@since 1.0.0.0+-}+requestStreaming ::+  (MonadUnliftIO m, ToJSON req, FromJSON resp) =>+  OllamaClient ->+  Text ->+  req ->+  ConduitT () resp m ()+requestStreaming OllamaClient {..} endpoint payload = do+  let fullUrl = T.unpack $ configBaseUrl clientConfig <> endpoint+      cfg = clientConfig+  initReq <- liftIO $ parseRequest fullUrl+  let req =+        initReq+          { method = "POST"+          , responseTimeout = responseTimeoutNone+          , requestHeaders =+              [ ("Content-Type", "application/json")+              , ("Accept", "application/x-ndjson, application/json")+              , ("Connection", "keep-alive")+              ]+                ++ authHeader cfg+                ++ configHeaders cfg+          , requestBody = RequestBodyLBS (encode payload)+          }+  transPipe runResourceT $+    bracketP+      (responseOpen req clientManager)+      responseClose+      ( \resp -> do+          let bodyReader = responseBody resp+              readChunk = liftIO $ brRead bodyReader `catch` \(_ :: HttpException) -> pure BS.empty+              source = repeatM readChunk .| takeWhileC (not . BS.null)+          source .| CB.lines .| filterC (not . BS.null) .| parseAndYield+      )+  where+    parseAndYield = awaitForever $ \line -> do+      case eitherDecode (BSL.fromStrict line) of+        Left _err -> pure ()+        Right val -> yield val++-- ---------------------------------------------------------------------------+-- Core request execution+-- ---------------------------------------------------------------------------++-- | Execute a JSON request without retry wrapping.+executeJsonRequest ::+  (ToJSON req, FromJSON resp) =>+  OllamaClient ->+  ByteString ->+  Text ->+  Maybe req ->+  IO (Either OllamaError resp)+executeJsonRequest OllamaClient {..} reqMethod endpoint mbPayload = do+  let fullUrl = T.unpack $ configBaseUrl clientConfig <> endpoint+      cfg = clientConfig+  initReq <- parseRequest fullUrl+  let timeoutMicro = configTimeout cfg * 1000000+      req =+        initReq+          { method = reqMethod+          , responseTimeout = responseTimeoutMicro timeoutMicro+          , requestHeaders =+              [("Content-Type", "application/json"), ("Accept", "application/json")]+                ++ authHeader cfg+                ++ configHeaders cfg+          , requestBody = maybe mempty (RequestBodyLBS . encode) mbPayload+          }+  result <- try @HttpException $ httpLbs req clientManager+  case result of+    Left httpErr -> pure $ Left $ HttpError httpErr+    Right resp -> do+      let status = statusCode (responseStatus resp)+          body = responseBody resp+      if status >= 200 && status < 300+        then+          if BSL.null body+            then case eitherDecode "null" of+              Left err -> pure $ Left $ DecodeError (T.pack err) (BSL.toStrict body)+              Right val -> pure $ Right val+            else case eitherDecode body of+              Left err -> pure $ Left $ DecodeError (T.pack err) (BSL.toStrict body)+              Right val -> pure $ Right val+        else pure $ Left $ ApiError status (TE.decodeUtf8 . BSL.toStrict $ body)++-- | Execute a raw byte request without retry wrapping.+executeRawRequest ::+  OllamaClient ->+  ByteString ->+  Text ->+  Maybe ByteString ->+  IO (Either OllamaError ByteString)+executeRawRequest OllamaClient {..} reqMethod endpoint mbPayload = do+  let fullUrl = T.unpack $ configBaseUrl clientConfig <> endpoint+      cfg = clientConfig+  initReq <- parseRequest fullUrl+  let timeoutMicro = configTimeout cfg * 1000000+      req =+        initReq+          { method = reqMethod+          , responseTimeout = responseTimeoutMicro timeoutMicro+          , requestHeaders = authHeader cfg ++ configHeaders cfg+          , requestBody = maybe mempty RequestBodyBS mbPayload+          }+  result <- try @HttpException $ httpLbs req clientManager+  case result of+    Left httpErr -> pure $ Left $ HttpError httpErr+    Right resp -> do+      let status = statusCode (responseStatus resp)+      if status >= 200 && status < 300+        then pure $ Right (BSL.toStrict $ responseBody resp)+        else pure $ Left $ ApiError status (TE.decodeUtf8 . BSL.toStrict $ body)+      where+        body = responseBody resp++-- ---------------------------------------------------------------------------+-- Retry logic+-- ---------------------------------------------------------------------------++{- | Wrap an IO action with the client's configured retry policy, lifecycle+callbacks, and structured logging.++Only retries when 'isRetryable' returns 'True' for the error.+-}+withRetry ::+  OllamaClient ->+  Text ->+  IO (Either OllamaError a) ->+  IO (Either OllamaError a)+withRetry OllamaClient {clientConfig = cfg} endpoint action = do+  let policy = toRetryPolicy (configRetry cfg)+      shouldRetry _status (Left err) = do+        logMsg cfg Warn $ "Retryable error on " <> endpoint <> ", will retry: " <> T.pack (show err)+        pure $ isRetryable err+      shouldRetry _status (Right _) = pure False+  fireCallback (configOnStart cfg)+  logMsg cfg Debug $ "Requesting " <> endpoint+  result <- Retry.retrying policy shouldRetry (const action)+  case result of+    Left err -> do+      fireCallback (configOnError cfg)+      logMsg cfg Error $ "Request failed: " <> endpoint <> " — " <> T.pack (show err)+    Right _ -> do+      fireCallback (configOnSuccess cfg)+      logMsg cfg Info $ "Request succeeded: " <> endpoint+  pure result++-- | Map our 'RetryPolicy' ADT to the @retry@ package's 'Retry.RetryPolicyM'.+toRetryPolicy :: RetryPolicy -> Retry.RetryPolicyM IO+toRetryPolicy NoRetry = Retry.limitRetries 0+toRetryPolicy (ConstantRetry count delaySec) =+  Retry.constantDelay (delaySec * 1000000) <> Retry.limitRetries count+toRetryPolicy (ExponentialRetry count initialDelayMs) =+  Retry.exponentialBackoff (initialDelayMs * 1000) <> Retry.limitRetries count++-- ---------------------------------------------------------------------------+-- Helpers+-- ---------------------------------------------------------------------------++-- | Build the Authorization header if an API key is configured.+authHeader :: OllamaClientConfig -> [(CI ByteString, ByteString)]+authHeader cfg = case configApiKey cfg of+  Nothing -> []+  Just key -> [("Authorization", "Bearer " <> TE.encodeUtf8 key)]++-- | Fire an optional callback, silently ignoring exceptions.+fireCallback :: Maybe (IO ()) -> IO ()+fireCallback Nothing = pure ()+fireCallback (Just cb) = cb `catch` \(_ :: SomeException) -> pure ()++-- | Log a message via the configured logger, if present.+logMsg :: OllamaClientConfig -> LogLevel -> Text -> IO ()+logMsg cfg level msg = case configLogger cfg of+  Nothing -> pure ()+  Just logger -> logger level msg `catch` \(_ :: SomeException) -> pure ()
+ src/Ollama/Conversation.hs view
@@ -0,0 +1,110 @@+{- |+Module      : Ollama.Conversation+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Conversation store typeclass and in-memory transactional implementation.++@since 1.0.0.0+-}+module Ollama.Conversation (+  Conversation (..),+  ConversationStore (..),+  InMemoryStore (..),+  initInMemoryStore,+  saveConversationInMemory,+  loadConversationInMemory,+  listConversationsInMemory,+  deleteConversationInMemory,+) where++import Control.Concurrent.STM (TVar, atomically, modifyTVar', newTVarIO, readTVar, readTVarIO)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Monad.Reader (ReaderT, ask)+import Data.Aeson (FromJSON, ToJSON)+import Data.Map.Strict (Map)+import Data.Map.Strict qualified as Map+import Data.Text (Text)+import Data.Time (UTCTime)+import GHC.Generics (Generic)+import Ollama.Types.Common (ModelName)+import Ollama.Types.Message (Message)++{- | Recorded chat conversation session.++@since 1.0.0.0+-}+data Conversation = Conversation+  { conversationId :: !Text+  , messages :: ![Message]+  , model :: !ModelName+  , createdAt :: !UTCTime+  , lastUpdated :: !UTCTime+  }+  deriving stock (Eq, Show, Generic)+  deriving anyclass (ToJSON, FromJSON)++{- | Abstract interface for persisting and managing chat conversations.++@since 1.0.0.0+-}+class (Monad m) => ConversationStore m where+  saveConversation :: Conversation -> m ()+  loadConversation :: Text -> m (Maybe Conversation)+  listConversations :: m [Conversation]+  deleteConversation :: Text -> m Bool++{- | Thread-safe transactional in-memory conversation store.++@since 1.0.0.0+-}+newtype InMemoryStore = InMemoryStore (TVar (Map Text Conversation))++{- | Initialize a new empty 'InMemoryStore'.++@since 1.0.0.0+-}+initInMemoryStore :: IO InMemoryStore+initInMemoryStore = InMemoryStore <$> newTVarIO Map.empty++{- | Save a conversation into an 'InMemoryStore'.++@since 1.0.0.0+-}+saveConversationInMemory :: (MonadIO m) => InMemoryStore -> Conversation -> m ()+saveConversationInMemory (InMemoryStore ref) conv = liftIO $ atomically $ do+  modifyTVar' ref (Map.insert (conversationId conv) conv)++{- | Load a conversation by ID from an 'InMemoryStore'.++@since 1.0.0.0+-}+loadConversationInMemory :: (MonadIO m) => InMemoryStore -> Text -> m (Maybe Conversation)+loadConversationInMemory (InMemoryStore ref) cid = liftIO $ Map.lookup cid <$> readTVarIO ref++{- | List all stored conversations from an 'InMemoryStore'.++@since 1.0.0.0+-}+listConversationsInMemory :: (MonadIO m) => InMemoryStore -> m [Conversation]+listConversationsInMemory (InMemoryStore ref) = liftIO $ Map.elems <$> readTVarIO ref++{- | Delete a conversation by ID from an 'InMemoryStore'.++@since 1.0.0.0+-}+deleteConversationInMemory :: (MonadIO m) => InMemoryStore -> Text -> m Bool+deleteConversationInMemory (InMemoryStore ref) cid = liftIO $ atomically $ do+  m <- readTVar ref+  if Map.member cid m+    then modifyTVar' ref (Map.delete cid) >> pure True+    else pure False++instance (MonadIO m) => ConversationStore (ReaderT InMemoryStore m) where+  saveConversation conv = ask >>= \store -> saveConversationInMemory store conv+  loadConversation cid = ask >>= \store -> loadConversationInMemory store cid+  listConversations = ask >>= \store -> listConversationsInMemory store+  deleteConversation cid = ask >>= \store -> deleteConversationInMemory store cid
+ src/Ollama/Error.hs view
@@ -0,0 +1,65 @@+{- |+Module      : Ollama.Error+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Core error type definitions for the Ollama library.++@since 3.0.0.0+-}+module Ollama.Error (+  OllamaError (..),+  isRetryable,+  throwOllama,+) where++import Control.Exception (Exception, throwIO)+import Data.ByteString (ByteString)+import Data.Text (Text)+import Network.HTTP.Client (HttpException)++{- | Unified error type representing all failure modes in the Ollama client.++@since 3.0.0.0+-}+data OllamaError+  = -- | HTTP transport failure (connection error, DNS failure, etc.)+    HttpError !HttpException+  | -- | Ollama API returned an error response (HTTP status code + message)+    ApiError !Int !Text+  | -- | Failed to decode JSON response body+    DecodeError !Text !ByteString+  | -- | Request timed out waiting for a response+    TimeoutError+  | -- | Client-side validation failure before sending the request+    InvalidRequest !Text+  deriving stock (Show)++instance Exception OllamaError++instance Eq OllamaError where+  ApiError s1 t1 == ApiError s2 t2 = s1 == s2 && t1 == t2+  DecodeError t1 _ == DecodeError t2 _ = t1 == t2+  TimeoutError == TimeoutError = True+  InvalidRequest t1 == InvalidRequest t2 = t1 == t2+  HttpError _ == HttpError _ = False+  _ == _ = False++{- | Determine whether an error is transient and safe to retry.++@since 3.0.0.0+-}+isRetryable :: OllamaError -> Bool+isRetryable (HttpError _) = True+isRetryable TimeoutError = True+isRetryable _ = False++{- | Helper to throw an 'OllamaError' as an exception.++@since 3.0.0.0+-}+throwOllama :: OllamaError -> IO a+throwOllama = throwIO
+ src/Ollama/Streaming.hs view
@@ -0,0 +1,41 @@+{- |+Module      : Ollama.Streaming+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Streaming pipeline utilities, stream combinators, and 'HasDone' class for API responses.++@since 1.0.0.0+-}+module Ollama.Streaming (+  HasDone (..),+  collectStream,+  foldStream,+) where++import Conduit (ConduitT, foldlC, runConduit, sinkList, (.|))+import Control.Monad.IO.Unlift (MonadUnliftIO)++{- | Typeclass for responses that indicate completion in a stream.++@since 1.0.0.0+-}+class HasDone a where+  isDone :: a -> Bool++{- | Collect all yielded items from a streaming conduit into a list.++@since 1.0.0.0+-}+collectStream :: (MonadUnliftIO m) => ConduitT () a m () -> m [a]+collectStream stream = runConduit $ stream .| sinkList++{- | Fold over all yielded items from a streaming conduit.++@since 1.0.0.0+-}+foldStream :: (MonadUnliftIO m) => (b -> a -> b) -> b -> ConduitT () a m () -> m b+foldStream f acc stream = runConduit $ stream .| foldlC f acc
+ src/Ollama/Testing.hs view
@@ -0,0 +1,162 @@+{- |+Module      : Ollama.Testing+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Mock client and test helpers for unit testing code without a live Ollama server.++@since 1.0.0.0+-}+module Ollama.Testing (+  newMockClient,+  withMockClient,+  mockGenerateResponse,+  mockChatResponse,+  mockEmbedResponse,+  mockListModelsResponse,+) where++import Control.Monad.IO.Class (MonadIO (liftIO))+import Control.Monad.IO.Unlift (MonadUnliftIO)+import Data.ByteString (ByteString)+import Data.ByteString.Char8 qualified as BS8+import Data.IORef (atomicModifyIORef, newIORef)+import Data.Text (Text)+import Data.Time (Day (..), UTCTime (..))+import Network.HTTP.Client (+  defaultManagerSettings,+  managerRawConnection,+  newManager,+ )+import Network.HTTP.Client.Internal (makeConnection)+import Ollama.API.Chat (ChatResponse (..))+import Ollama.API.Embed (EmbedResponse (..))+import Ollama.API.Generate (GenerateResponse (..))+import Ollama.Client (OllamaClient (..), closeClient)+import Ollama.Client.Config (defaultConfig)+import Ollama.Types.Common (Digest (..), Duration (..), ModelName (..))+import Ollama.Types.Message (assistantMessage)+import Ollama.Types.Model (ListResponse (..), ModelDetails (..), ModelInfo (..))++{- | Construct an 'OllamaClient' that returns mock HTTP response bytes for any request.++@since 1.0.0.0+-}+newMockClient :: (MonadIO m) => ByteString -> m OllamaClient+newMockClient bodyBytes = liftIO $ do+  let httpResponse =+        "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: "+          <> BS8.pack (show (BS8.length bodyBytes))+          <> "\r\n\r\n"+          <> bodyBytes+  ref <- newIORef [httpResponse]+  let mockConn =+        makeConnection+          ( atomicModifyIORef ref $ \case+              [] -> ([], "")+              (x : xs) -> (xs, x)+          )+          (\_ -> pure ())+          (pure ())+      settings = defaultManagerSettings {managerRawConnection = pure (\_ _ _ -> mockConn)}+  mgr <- newManager settings+  pure $ OllamaClient mgr defaultConfig True++{- | Resource bracket helper to create a mock client, execute an action, and close resources.++@since 1.0.0.0+-}+withMockClient :: (MonadUnliftIO m) => ByteString -> (OllamaClient -> m a) -> m a+withMockClient body action = do+  client <- newMockClient body+  res <- action client+  closeClient client+  pure res++{- | Construct a mock 'GenerateResponse'.++@since 1.0.0.0+-}+mockGenerateResponse :: ModelName -> Text -> GenerateResponse+mockGenerateResponse model text =+  GenerateResponse+    { grModel = model+    , grCreatedAt = UTCTime (ModifiedJulianDay 60000) 0+    , grResponse = text+    , grDone = True+    , grDoneReason = Just "stop"+    , grContext = Just [1, 2, 3]+    , grTotalDuration = Just (Duration 1000000000)+    , grLoadDuration = Just (Duration 100000000)+    , grPromptEvalCount = Just 10+    , grPromptEvalDuration = Just (Duration 200000000)+    , grEvalCount = Just 20+    , grEvalDuration = Just (Duration 700000000)+    , grThinking = Nothing+    , grImage = Nothing+    }++{- | Construct a mock 'ChatResponse'.++@since 1.0.0.0+-}+mockChatResponse :: ModelName -> Text -> ChatResponse+mockChatResponse model text =+  ChatResponse+    { crModel = model+    , crCreatedAt = UTCTime (ModifiedJulianDay 60000) 0+    , crMessage = Just (assistantMessage text)+    , crDone = True+    , crDoneReason = Just "stop"+    , crTotalDuration = Just (Duration 1000000000)+    , crLoadDuration = Just (Duration 100000000)+    , crPromptEvalCount = Just 10+    , crPromptEvalDuration = Just (Duration 200000000)+    , crEvalCount = Just 20+    , crEvalDuration = Just (Duration 700000000)+    }++{- | Construct a mock 'EmbedResponse'.++@since 1.0.0.0+-}+mockEmbedResponse :: ModelName -> [[Double]] -> EmbedResponse+mockEmbedResponse model vectors =+  EmbedResponse+    { erModel = model+    , erEmbeddings = vectors+    , erTotalDuration = Just (Duration 500000000)+    , erLoadDuration = Just (Duration 50000000)+    , erPromptEvalCount = Just 8+    }++{- | Construct a mock 'ListResponse'.++@since 1.0.0.0+-}+mockListModelsResponse :: [ModelName] -> ListResponse+mockListModelsResponse names =+  ListResponse+    { models = map mkModel names+    }+  where+    mkModel name =+      ModelInfo+        { miName = name+        , miModel = name+        , miModifiedAt = UTCTime (ModifiedJulianDay 60000) 0+        , miSize = 4000000000+        , miDigest = Digest "sha256:1234567890abcdef"+        , miDetails =+            ModelDetails+              { parentModel = Nothing+              , format = "gguf"+              , family = "llama"+              , families = ["llama"]+              , parameterSize = "7B"+              , quantizationLevel = "Q4_K_M"+              }+        }
+ src/Ollama/Types.hs view
@@ -0,0 +1,38 @@+{- |+Module      : Ollama.Types+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Re-export all domain types for convenience.++@since 3.0.0.0+-}+module Ollama.Types (+  module Ollama.Types.Common,+  Role (System, User, Assistant),+  Message (..),+  userMessage,+  systemMessage,+  assistantMessage,+  toolMessage,+  toolResultMessage,+  imageMessage,+  Tool (..),+  FunctionDef (..),+  FunctionParameters (..),+  ToolCall (..),+  ToolCallFunction (..),+  module Ollama.Types.Options,+  module Ollama.Types.Format,+  module Ollama.Types.Model,+) where++import Ollama.Types.Common+import Ollama.Types.Format+import Ollama.Types.Message+import Ollama.Types.Model+import Ollama.Types.Options+import Ollama.Types.Tool
+ src/Ollama/Types/Common.hs view
@@ -0,0 +1,152 @@+{- |+Module      : Ollama.Types.Common+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Common newtypes and domain primitives for the Ollama API.++@since 3.0.0.0+-}+module Ollama.Types.Common (+  ModelName (..),+  mkModelName,+  Digest (..),+  Base64Image (..),+  Duration (..),+  durationToSeconds,+  durationToMillis,+  tokensPerSecond,+  Version (..),+  Think (..),+  ThinkingLevel (..),+) where++import Data.Aeson (FromJSON (..), ToJSON (..), Value (..), object, withText, (.:), (.=))+import Data.Aeson.Types (typeMismatch)+import Data.Hashable (Hashable)+import Data.Int (Int64)+import Data.String (IsString)+import Data.Text (Text)+import Data.Text qualified as T+import GHC.Generics (Generic)++{- | Model name following the @model:tag@ format.++@since 3.0.0.0+-}+newtype ModelName = ModelName {unModelName :: Text}+  deriving newtype (Eq, Ord, Show, IsString, ToJSON, FromJSON, Hashable)++{- | Smart constructor that validates that a model name is non-empty.++@since 3.0.0.0+-}+mkModelName :: Text -> Either Text ModelName+mkModelName t+  | T.null t = Left "Model name cannot be empty"+  | otherwise = Right (ModelName t)++{- | SHA256 digest of a layer blob.++@since 3.0.0.0+-}+newtype Digest = Digest {unDigest :: Text}+  deriving newtype (Eq, Ord, Show, ToJSON, FromJSON, Hashable)++{- | Base64-encoded image data for multimodal inputs.++@since 3.0.0.0+-}+newtype Base64Image = Base64Image {unBase64Image :: Text}+  deriving newtype (Eq, Show, ToJSON, FromJSON)++{- | Duration in nanoseconds as returned by the Ollama API.++@since 3.0.0.0+-}+newtype Duration = Duration {durationNanos :: Int64}+  deriving newtype (Eq, Ord, Show, ToJSON, FromJSON, Num)++{- | Convert duration nanoseconds to seconds.++@since 3.0.0.0+-}+durationToSeconds :: Duration -> Double+durationToSeconds (Duration ns) = fromIntegral ns / 1e9++{- | Convert duration nanoseconds to milliseconds.++@since 1.0.0.0+-}+durationToMillis :: Duration -> Double+durationToMillis (Duration ns) = fromIntegral ns / 1e6++{- | Calculate tokens per second (tokens\/s) given a token count and a 'Duration'.++@since 1.0.0.0+-}+tokensPerSecond :: Int -> Duration -> Double+tokensPerSecond count dur =+  let secs = durationToSeconds dur+   in if secs <= 0 then 0.0 else fromIntegral count / secs++{- | Ollama server engine version string.++@since 3.0.0.0+-}+newtype Version = Version {unVersion :: Text}+  deriving stock (Eq, Show, Generic)++instance FromJSON Version where+  parseJSON = \case+    String s -> pure $ Version s+    Object v -> Version <$> v .: "version"+    v -> typeMismatch "Version" v++instance ToJSON Version where+  toJSON (Version s) = object ["version" .= s]++{- | Thinking level settings for reasoning models.++@since 3.0.0.0+-}+data ThinkingLevel = ThinkLow | ThinkMedium | ThinkHigh | ThinkMax+  deriving stock (Eq, Show, Bounded, Enum, Generic)++instance ToJSON ThinkingLevel where+  toJSON ThinkLow = String "low"+  toJSON ThinkMedium = String "medium"+  toJSON ThinkHigh = String "high"+  toJSON ThinkMax = String "max"++instance FromJSON ThinkingLevel where+  parseJSON = withText "ThinkingLevel" $ \case+    "low" -> pure ThinkLow+    "medium" -> pure ThinkMedium+    "high" -> pure ThinkHigh+    "max" -> pure ThinkMax+    other -> fail $ "Unknown thinking level: " <> T.unpack other++{- | Controls whether a thinking/reasoning model outputs its thoughts.++@since 3.0.0.0+-}+data Think+  = ThinkEnabled+  | ThinkDisabled+  | ThinkLevel !ThinkingLevel+  deriving stock (Eq, Show, Generic)++instance ToJSON Think where+  toJSON ThinkEnabled = Bool True+  toJSON ThinkDisabled = Bool False+  toJSON (ThinkLevel lvl) = toJSON lvl++instance FromJSON Think where+  parseJSON (Bool True) = pure ThinkEnabled+  parseJSON (Bool False) = pure ThinkDisabled+  parseJSON (String s) = ThinkLevel <$> parseJSON (String s)+  parseJSON v = typeMismatch "Think" v
+ src/Ollama/Types/Format.hs view
@@ -0,0 +1,38 @@+{- |+Module      : Ollama.Types.Format+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Response formatting specifications for structured model output.++@since 1.0.0.0+-}+module Ollama.Types.Format (+  Format (..),+  module Ollama.Types.Format.SchemaBuilder,+) where++import Data.Aeson+import Ollama.Types.Format.SchemaBuilder++{- | Response output format hint.++@since 1.0.0.0+-}+data Format+  = -- | Constrain response output to generic valid JSON+    JsonFormat+  | -- | Constrain response output to a specific JSON Schema+    SchemaFormat !Schema+  deriving stock (Eq, Show)++instance ToJSON Format where+  toJSON JsonFormat = String "json"+  toJSON (SchemaFormat sch) = toJSON sch++instance FromJSON Format where+  parseJSON (String "json") = pure JsonFormat+  parseJSON v = SchemaFormat <$> parseJSON v
+ src/Ollama/Types/Format/SchemaBuilder.hs view
@@ -0,0 +1,223 @@+{- |+Module      : Ollama.Types.Format.SchemaBuilder+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++DSL for constructing structured JSON Schemas for Ollama's structured output API.++@since 1.0.0.0+-}+module Ollama.Types.Format.SchemaBuilder (+  JsonType (..),+  Property (..),+  Schema (..),+  SchemaBuilder,+  emptyObject,+  addProperty,+  addObjectProperty,+  requireField,+  requireFields,+  buildSchema,+  objectOf,+  arrayOf,+  printSchema,+  (|+),+  (|++),+  (|!),+  (|!!),+) 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 TEncoding+import GHC.Generics (Generic)++{- | Supported JSON primitive and compound types.++@since 1.0.0.0+-}+data JsonType+  = JString+  | JNumber+  | JInteger+  | JBoolean+  | JNull+  | JArray !JsonType+  | JObject !Schema+  deriving stock (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"++{- | Property metadata for schema properties.++@since 1.0.0.0+-}+newtype Property = Property JsonType+  deriving stock (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]++{- | JSON schema specification.++@since 1.0.0.0+-}+data Schema = Schema+  { schemaProperties :: !(HM.Map Text Property)+  , schemaRequired :: ![Text]+  }+  deriving stock (Show, Eq, Generic)++instance ToJSON Schema where+  toJSON (Schema props req) =+    object+      [ "type" .= ("object" :: Text)+      , "properties" .= props+      , "required" .= req+      ]++instance FromJSON JsonType where+  parseJSON = withText "JsonType" $ \case+    "string" -> pure JString+    "number" -> pure JNumber+    "integer" -> pure JInteger+    "boolean" -> pure JBoolean+    "null" -> pure JNull+    "array" -> pure (JArray JString)+    "object" -> pure (JObject (Schema HM.empty []))+    other -> fail $ "Unknown JsonType: " <> T.unpack other++instance FromJSON Property where+  parseJSON = withObject "Property" $ \v -> do+    t <- v .: "type"+    case (t :: Text) of+      "array" -> Property . JArray <$> (v .: "items" >>= parseJSON)+      "object" -> Property . JObject <$> parseJSON (Object v)+      _ -> Property <$> parseJSON (String t)++instance FromJSON Schema where+  parseJSON = withObject "Schema" $ \v ->+    Schema+      <$> v .:? "properties" .!= HM.empty+      <*> v .:? "required" .!= []++{- | Opaque builder for fluid schema construction.++@since 1.0.0.0+-}+newtype SchemaBuilder = SchemaBuilder Schema+  deriving stock (Show, Eq)++{- | Create an empty schema builder object.++@since 1.0.0.0+-}+emptyObject :: SchemaBuilder+emptyObject = SchemaBuilder $ Schema HM.empty []++{- | Add a primitive property to the schema builder.++@since 1.0.0.0+-}+addProperty :: Text -> JsonType -> SchemaBuilder -> SchemaBuilder+addProperty name typ (SchemaBuilder s) =+  SchemaBuilder $ s {schemaProperties = HM.insert name (Property typ) (schemaProperties s)}++{- | Add a nested object property to the schema builder.++@since 1.0.0.0+-}+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.++@since 1.0.0.0+-}+requireField :: Text -> SchemaBuilder -> SchemaBuilder+requireField name (SchemaBuilder s) =+  SchemaBuilder $ s {schemaRequired = name : schemaRequired s}++{- | Mark multiple fields as required.++@since 1.0.0.0+-}+requireFields :: [Text] -> SchemaBuilder -> SchemaBuilder+requireFields names builder = foldr requireField builder names++{- | Finalize a 'Schema' from a 'SchemaBuilder'.++@since 1.0.0.0+-}+buildSchema :: SchemaBuilder -> Schema+buildSchema (SchemaBuilder s) = s++{- | Treat a 'SchemaBuilder' as a nested object type.++@since 1.0.0.0+-}+objectOf :: SchemaBuilder -> JsonType+objectOf builder = JObject (buildSchema builder)++{- | Create an array schema type of an element type.++@since 1.0.0.0+-}+arrayOf :: JsonType -> JsonType+arrayOf = JArray++{- | Pretty-print a schema as formatted JSON.++@since 1.0.0.0+-}+printSchema :: Schema -> IO ()+printSchema = putStrLn . T.unpack . TL.toStrict . TEncoding.decodeUtf8 . encode++{- | Infix alias for 'addProperty'.++@since 1.0.0.0+-}+(|+) :: SchemaBuilder -> (Text, JsonType) -> SchemaBuilder+builder |+ (name, typ) = addProperty name typ builder++{- | Infix alias for 'addObjectProperty'.++@since 1.0.0.0+-}+(|++) :: SchemaBuilder -> (Text, Schema) -> SchemaBuilder+builder |++ (name, schema) = addObjectProperty name schema builder++{- | Infix alias for 'requireField'.++@since 1.0.0.0+-}+(|!) :: SchemaBuilder -> Text -> SchemaBuilder+builder |! name = requireField name builder++{- | Infix alias for 'requireFields'.++@since 1.0.0.0+-}+(|!!) :: SchemaBuilder -> [Text] -> SchemaBuilder+builder |!! names = requireFields names builder++infixl 7 |+, |+++infixl 6 |!, |!!
+ src/Ollama/Types/Message.hs view
@@ -0,0 +1,129 @@+{- |+Module      : Ollama.Types.Message+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Chat message definitions and helper constructors.++@since 3.0.0.0+-}+module Ollama.Types.Message (+  Role (..),+  Message (..),+  userMessage,+  systemMessage,+  assistantMessage,+  toolMessage,+  toolResultMessage,+  imageMessage,+) where++import Data.Aeson+import Data.Maybe (catMaybes)+import Data.Text (Text)+import GHC.Generics (Generic)+import Ollama.Types.Common (Base64Image)+import Ollama.Types.Tool (ToolCall)++{- | Entity role in a conversation.++@since 3.0.0.0+-}+data Role = System | User | Assistant | Tool+  deriving stock (Eq, Ord, Show, Bounded, Enum, Generic)++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" $ \case+    "system" -> pure System+    "user" -> pure User+    "assistant" -> pure Assistant+    "tool" -> pure Tool+    other -> fail $ "Invalid Role: " <> show other++{- | Chat message within a conversation payload.++@since 3.0.0.0+-}+data Message = Message+  { messageRole :: !Role+  , messageContent :: !Text+  , messageImages :: !(Maybe [Base64Image])+  , messageToolCalls :: !(Maybe [ToolCall])+  , messageToolName :: !(Maybe Text)+  , messageThinking :: !(Maybe Text)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON Message where+  toJSON Message {..} =+    object $+      catMaybes+        [ Just $ "role" .= messageRole+        , Just $ "content" .= messageContent+        , ("images" .=) <$> messageImages+        , ("tool_calls" .=) <$> messageToolCalls+        , ("tool_name" .=) <$> messageToolName+        , ("thinking" .=) <$> messageThinking+        ]++instance FromJSON Message where+  parseJSON = withObject "Message" $ \v ->+    Message+      <$> v .: "role"+      <*> v .: "content"+      <*> v .:? "images"+      <*> v .:? "tool_calls"+      <*> v .:? "tool_name"+      <*> v .:? "thinking"++{- | Create a 'User' role message.++@since 3.0.0.0+-}+userMessage :: Text -> Message+userMessage t = Message User t Nothing Nothing Nothing Nothing++{- | Create a 'System' role message.++@since 3.0.0.0+-}+systemMessage :: Text -> Message+systemMessage t = Message System t Nothing Nothing Nothing Nothing++{- | Create an 'Assistant' role message.++@since 3.0.0.0+-}+assistantMessage :: Text -> Message+assistantMessage t = Message Assistant t Nothing Nothing Nothing Nothing++{- | Create a 'Tool' role message.++@since 3.0.0.0+-}+toolMessage :: Text -> Message+toolMessage t = Message Tool t Nothing Nothing Nothing Nothing++{- | Create a 'Tool' role message with specific @tool_name@ informing the model of tool execution.++@since 3.0.0.0+-}+toolResultMessage :: Text -> Text -> Message+toolResultMessage content toolName =+  Message Tool content Nothing Nothing (Just toolName) Nothing++{- | Create a 'User' message with attached Base64 image data.++@since 3.0.0.0+-}+imageMessage :: Text -> [Base64Image] -> Message+imageMessage t imgs = Message User t (Just imgs) Nothing Nothing Nothing
+ src/Ollama/Types/Model.hs view
@@ -0,0 +1,161 @@+{- |+Module      : Ollama.Types.Model+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Model info, details, listing, and metadata types.++@since 1.0.0.0+-}+module Ollama.Types.Model (+  ModelDetails (..),+  ModelInfo (..),+  ListResponse (..),+  RunningModel (..),+  RunningModelsResponse (..),+) where++import Data.Aeson+import Data.Int (Int64)+import Data.Text (Text)+import Data.Time (UTCTime)+import GHC.Generics (Generic)+import Ollama.Types.Common (Digest, ModelName)++{- | Detailed specifications of a model's architecture and family.++@since 1.0.0.0+-}+data ModelDetails = ModelDetails+  { parentModel :: !(Maybe Text)+  , format :: !Text+  , family :: !Text+  , families :: ![Text]+  , parameterSize :: !Text+  , quantizationLevel :: !Text+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON ModelDetails where+  parseJSON = withObject "ModelDetails" $ \v ->+    ModelDetails+      <$> v .:? "parent_model"+      <*> v .:? "format" .!= ""+      <*> v .:? "family" .!= ""+      <*> v .:? "families" .!= []+      <*> v .:? "parameter_size" .!= ""+      <*> v .:? "quantization_level" .!= ""++instance ToJSON ModelDetails where+  toJSON ModelDetails {..} =+    object+      [ "parent_model" .= parentModel+      , "format" .= format+      , "family" .= family+      , "families" .= families+      , "parameter_size" .= parameterSize+      , "quantization_level" .= quantizationLevel+      ]++{- | Summary information for an installed local model.++@since 1.0.0.0+-}+data ModelInfo = ModelInfo+  { miName :: !ModelName+  , miModel :: !ModelName+  , miModifiedAt :: !UTCTime+  , miSize :: !Int64+  , miDigest :: !Digest+  , miDetails :: !ModelDetails+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON ModelInfo where+  parseJSON = withObject "ModelInfo" $ \v ->+    ModelInfo+      <$> v .: "name"+      <*> v .: "model"+      <*> v .: "modified_at"+      <*> v .: "size"+      <*> v .: "digest"+      <*> v .: "details"++instance ToJSON ModelInfo where+  toJSON ModelInfo {..} =+    object+      [ "name" .= miName+      , "model" .= miModel+      , "modified_at" .= miModifiedAt+      , "size" .= miSize+      , "digest" .= miDigest+      , "details" .= miDetails+      ]++{- | Response listing available local models.++@since 1.0.0.0+-}+newtype ListResponse = ListResponse+  { models :: [ModelInfo]+  }+  deriving stock (Eq, Show, Generic)+  deriving anyclass (ToJSON, FromJSON)++{- | Summary information for a model currently loaded in memory.++@since 1.0.0.0+-}+data RunningModel = RunningModel+  { rmName :: !ModelName+  , rmModel :: !ModelName+  , rmSize :: !Int64+  , rmDigest :: !Digest+  , rmDetails :: !ModelDetails+  , rmExpiresAt :: !UTCTime+  , rmSizeVram :: !Int64+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON RunningModel where+  parseJSON = withObject "RunningModel" $ \v ->+    RunningModel+      <$> v .: "name"+      <*> v .: "model"+      <*> v .: "size"+      <*> v .: "digest"+      <*> v .: "details"+      <*> v .: "expires_at"+      <*> v .: "size_vram"++instance ToJSON RunningModel where+  toJSON RunningModel {..} =+    object+      [ "name" .= rmName+      , "model" .= rmModel+      , "size" .= rmSize+      , "digest" .= rmDigest+      , "details" .= rmDetails+      , "expires_at" .= rmExpiresAt+      , "size_vram" .= rmSizeVram+      ]++{- | Response listing loaded running models.++@since 1.0.0.0+-}+newtype RunningModelsResponse = RunningModelsResponse+  { runningModels :: [RunningModel]+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON RunningModelsResponse where+  parseJSON = withObject "RunningModelsResponse" $ \v ->+    RunningModelsResponse <$> v .: "models"++instance ToJSON RunningModelsResponse where+  toJSON RunningModelsResponse {..} =+    object ["models" .= runningModels]
+ src/Ollama/Types/Options.hs view
@@ -0,0 +1,135 @@+{- |+Module      : Ollama.Types.Options+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Model parameters and runtime execution options.++@since 3.0.0.0+-}+module Ollama.Types.Options (+  ModelOptions (..),+  defaultOptions,+) where++import Data.Aeson (FromJSON (..), ToJSON (..), object, withObject, (.:?), (.=))+import Data.Maybe (catMaybes)+import Data.Text (Text)+import GHC.Generics (Generic)++{- | Optional inference and hardware tuning parameters.++@since 3.0.0.0+-}+data ModelOptions = ModelOptions+  { optNumKeep :: !(Maybe Int)+  , optSeed :: !(Maybe Int)+  , optNumPredict :: !(Maybe Int)+  , optDraftNumPredict :: !(Maybe Int)+  , optTopK :: !(Maybe Int)+  , optTopP :: !(Maybe Double)+  , optMinP :: !(Maybe Double)+  , optTypicalP :: !(Maybe Double)+  , optRepeatLastN :: !(Maybe Int)+  , optTemperature :: !(Maybe Double)+  , optRepeatPenalty :: !(Maybe Double)+  , optPresencePenalty :: !(Maybe Double)+  , optFrequencyPenalty :: !(Maybe Double)+  , optPenalizeNewline :: !(Maybe Bool)+  , optStop :: !(Maybe [Text])+  , optNuma :: !(Maybe Bool)+  , optNumCtx :: !(Maybe Int)+  , optNumBatch :: !(Maybe Int)+  , optNumGpu :: !(Maybe Int)+  , optMainGpu :: !(Maybe Int)+  , optUseMmap :: !(Maybe Bool)+  , optNumThread :: !(Maybe Int)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON ModelOptions where+  toJSON opts =+    object $+      catMaybes+        [ ("num_keep" .=) <$> optNumKeep opts+        , ("seed" .=) <$> optSeed opts+        , ("num_predict" .=) <$> optNumPredict opts+        , ("draft_num_predict" .=) <$> optDraftNumPredict opts+        , ("top_k" .=) <$> optTopK opts+        , ("top_p" .=) <$> optTopP opts+        , ("min_p" .=) <$> optMinP opts+        , ("typical_p" .=) <$> optTypicalP opts+        , ("repeat_last_n" .=) <$> optRepeatLastN opts+        , ("temperature" .=) <$> optTemperature opts+        , ("repeat_penalty" .=) <$> optRepeatPenalty opts+        , ("presence_penalty" .=) <$> optPresencePenalty opts+        , ("frequency_penalty" .=) <$> optFrequencyPenalty opts+        , ("penalize_newline" .=) <$> optPenalizeNewline opts+        , ("stop" .=) <$> optStop opts+        , ("numa" .=) <$> optNuma opts+        , ("num_ctx" .=) <$> optNumCtx opts+        , ("num_batch" .=) <$> optNumBatch opts+        , ("num_gpu" .=) <$> optNumGpu opts+        , ("main_gpu" .=) <$> optMainGpu opts+        , ("use_mmap" .=) <$> optUseMmap opts+        , ("num_thread" .=) <$> optNumThread opts+        ]++instance FromJSON ModelOptions where+  parseJSON = withObject "ModelOptions" $ \v ->+    ModelOptions+      <$> v .:? "num_keep"+      <*> v .:? "seed"+      <*> v .:? "num_predict"+      <*> v .:? "draft_num_predict"+      <*> v .:? "top_k"+      <*> v .:? "top_p"+      <*> v .:? "min_p"+      <*> v .:? "typical_p"+      <*> v .:? "repeat_last_n"+      <*> v .:? "temperature"+      <*> v .:? "repeat_penalty"+      <*> v .:? "presence_penalty"+      <*> v .:? "frequency_penalty"+      <*> v .:? "penalize_newline"+      <*> v .:? "stop"+      <*> v .:? "numa"+      <*> v .:? "num_ctx"+      <*> v .:? "num_batch"+      <*> v .:? "num_gpu"+      <*> v .:? "main_gpu"+      <*> v .:? "use_mmap"+      <*> v .:? "num_thread"++{- | Default empty options (all settings default to server Modelfile values).++@since 3.0.0.0+-}+defaultOptions :: ModelOptions+defaultOptions =+  ModelOptions+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing+    Nothing
+ src/Ollama/Types/Tool.hs view
@@ -0,0 +1,148 @@+{- |+Module      : Ollama.Types.Tool+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Tool calling and structured function interfaces for the Ollama API.++@since 3.0.0.0+-}+module Ollama.Types.Tool (+  Tool (..),+  FunctionDef (..),+  FunctionParameters (..),+  ToolCall (..),+  ToolCallFunction (..),+) where++import Data.Aeson+import Data.Map.Strict (Map)+import Data.Text (Text)+import GHC.Generics (Generic)++{- | Tool definition provided to the model.++@since 3.0.0.0+-}+data Tool = Tool+  { toolType :: !Text+  , toolFunction :: !FunctionDef+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON Tool where+  toJSON Tool {..} =+    object+      [ "type" .= toolType+      , "function" .= toolFunction+      ]++instance FromJSON Tool where+  parseJSON = withObject "Tool" $ \v ->+    Tool+      <$> v .: "type"+      <*> v .: "function"++{- | Definition of a function that can be called by the model.++@since 3.0.0.0+-}+data FunctionDef = FunctionDef+  { fnName :: !Text+  , fnDescription :: !(Maybe Text)+  , fnParameters :: !(Maybe FunctionParameters)+  , fnStrict :: !(Maybe Bool)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON FunctionDef where+  toJSON FunctionDef {..} =+    object $+      ["name" .= fnName]+        ++ maybe [] (\d -> ["description" .= d]) fnDescription+        ++ maybe [] (\p -> ["parameters" .= p]) fnParameters+        ++ maybe [] (\s -> ["strict" .= s]) fnStrict++instance FromJSON FunctionDef where+  parseJSON = withObject "FunctionDef" $ \v ->+    FunctionDef+      <$> v .: "name"+      <*> v .:? "description"+      <*> v .:? "parameters"+      <*> v .:? "strict"++{- | Parameters schema for a function call.++@since 3.0.0.0+-}+data FunctionParameters = FunctionParameters+  { fpType :: !Text+  , fpProperties :: !(Maybe (Map Text FunctionParameters))+  , fpRequired :: !(Maybe [Text])+  , fpAdditionalProperties :: !(Maybe Bool)+  , fpDescription :: !(Maybe Text)+  , fpEnum :: !(Maybe [Text])+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON FunctionParameters where+  toJSON FunctionParameters {..} =+    object $+      ["type" .= fpType]+        ++ maybe [] (\p -> ["properties" .= p]) fpProperties+        ++ maybe [] (\r -> ["required" .= r]) fpRequired+        ++ maybe [] (\a -> ["additionalProperties" .= a]) fpAdditionalProperties+        ++ maybe [] (\d -> ["description" .= d]) fpDescription+        ++ maybe [] (\e -> ["enum" .= e]) fpEnum++instance FromJSON FunctionParameters where+  parseJSON = withObject "FunctionParameters" $ \v ->+    FunctionParameters+      <$> v .: "type"+      <*> v .:? "properties"+      <*> v .:? "required"+      <*> v .:? "additionalProperties"+      <*> v .:? "description"+      <*> v .:? "enum"++{- | Tool call returned in model's assistant response.++@since 3.0.0.0+-}+newtype ToolCall = ToolCall+  { tcFunction :: ToolCallFunction+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON ToolCall where+  toJSON ToolCall {..} = object ["function" .= tcFunction]++instance FromJSON ToolCall where+  parseJSON = withObject "ToolCall" $ \v ->+    ToolCall <$> v .: "function"++{- | Function invocation payload inside a tool call.++@since 3.0.0.0+-}+data ToolCallFunction = ToolCallFunction+  { tcfName :: !Text+  , tcfArguments :: !(Map Text Value)+  }+  deriving stock (Eq, Show, Generic)++instance ToJSON ToolCallFunction where+  toJSON ToolCallFunction {..} =+    object+      [ "name" .= tcfName+      , "arguments" .= tcfArguments+      ]++instance FromJSON ToolCallFunction where+  parseJSON = withObject "ToolCallFunction" $ \v ->+    ToolCallFunction+      <$> v .: "name"+      <*> v .: "arguments"
+ test-integration/Main.hs view
@@ -0,0 +1,176 @@+module Main (main) where++import Data.List.NonEmpty (NonEmpty ((:|)))+import Data.Text qualified as T+import Data.Time (getCurrentTime)+import Ollama+import Test.Tasty+import Test.Tasty.HUnit++testModel :: ModelName+testModel = "qwen3.5:2b"++fastOptions :: Maybe ModelOptions+fastOptions = Just (defaultOptions {optNumPredict = Just 15})++tests :: TestTree+tests =+  testGroup+    "ollama-haskell Live Server End-to-End Test Suite"+    [ testCase "GET /api/version — getVersion" $ do+        client <- defaultClient+        res <- getVersion client+        case res of+          Left err -> assertFailure $ "Version request failed: " <> show err+          Right ver -> assertBool "Version non-empty" (not $ T.null $ unVersion ver)+    , testCase "GET /api/tags — listModels" $ do+        client <- defaultClient+        res <- listModels client+        case res of+          Left err -> assertFailure $ "List models failed: " <> show err+          Right (ListResponse ms) ->+            assertBool "Has installed models" (not $ null ms)+    , testCase "POST /api/show — showModel" $ do+        client <- defaultClient+        res <- showModel client testModel+        case res of+          Left err -> assertFailure $ "Show model failed: " <> show err+          Right resp ->+            assertBool "Modelfile or details present" (not $ T.null $ srsModelfile resp)+    , testCase "GET /api/ps — listRunning" $ do+        client <- defaultClient+        res <- listRunning client+        case res of+          Left err -> assertFailure $ "List running failed: " <> show err+          Right _ -> pure ()+    , testCase "POST /api/chat — non-streaming chat" $ do+        client <- defaultClient+        let msgs = systemMessage "You are a helpful assistant." :| [userMessage "Say hello in one word."]+            req = (chatRequest testModel msgs) {chatOptions = fastOptions, chatThink = Just ThinkDisabled}+        res <- chat client req+        case res of+          Left err -> assertFailure $ "Chat request failed: " <> show err+          Right resp -> do+            assertBool "Chat response done" (crDone resp)+            case crMessage resp of+              Nothing -> assertFailure "Expected message in response"+              Just msg ->+                assertBool+                  "Message content or thinking present"+                  (not (T.null (messageContent msg)) || maybe False (not . T.null) (messageThinking msg))+    , testCase "POST /api/chat — streaming chat with conduit" $ do+        client <- defaultClient+        let req = (chatRequest testModel (userMessage "Count from 1 to 5." :| [])) {chatThink = Just ThinkDisabled}+        chunks <- collectStream (chatStream client req)+        assertBool "Stream produced response chunks" (not $ null chunks)+    , testCase "POST /api/generate — non-streaming generate" $ do+        client <- defaultClient+        let req =+              (generateRequest testModel "Write 3 words.")+                { genOptions = fastOptions+                , genThink = Just ThinkDisabled+                }+        res <- generate client req+        case res of+          Left err -> assertFailure $ "Generate request failed: " <> show err+          Right resp -> do+            assertBool "Generate response done" (grDone resp)+            assertBool "Generated response non-empty" (not $ T.null $ grResponse resp)+    , testCase "POST /api/generate — streaming generate with conduit" $ do+        client <- defaultClient+        let req = (generateRequest testModel "Say hi.") {genThink = Just ThinkDisabled}+        chunks <- collectStream (generateStream client req)+        assertBool "Stream produced generate chunks" (not $ null chunks)+    , testCase "POST /api/generate — thinking model support" $ do+        client <- defaultClient+        let req =+              (generateRequest testModel "What is 2 + 2?")+                { genThink = Just ThinkEnabled+                , genOptions = fastOptions+                }+        res <- generate client req+        case res of+          Left err -> assertFailure $ "Thinking generate failed: " <> show err+          Right resp -> assertBool "Response done" (grDone resp)+    , testCase "POST /api/chat — tool calling definition and execution" $ do+        client <- defaultClient+        let weatherTool =+              Tool+                { toolType = "function"+                , toolFunction =+                    FunctionDef+                      { fnName = "get_current_weather"+                      , fnDescription = Just "Get current weather for a city"+                      , fnParameters =+                          Just+                            FunctionParameters+                              { fpType = "object"+                              , fpProperties = Nothing+                              , fpRequired = Just ["location"]+                              , fpAdditionalProperties = Nothing+                              , fpDescription = Nothing+                              , fpEnum = Nothing+                              }+                      , fnStrict = Nothing+                      }+                }+            req =+              (chatRequest testModel (userMessage "What is the weather in Tokyo?" :| []))+                { chatTools = Just [weatherTool]+                , chatOptions = fastOptions+                , chatThink = Just ThinkDisabled+                }+        res <- chat client req+        case res of+          Left err -> assertFailure $ "Tool chat request failed: " <> show err+          Right resp -> assertBool "Chat response completed" (crDone resp)+    , testCase "POST /api/chat — structured output format" $ do+        client <- defaultClient+        let req =+              (chatRequest testModel (userMessage "Respond with JSON listing 2 colors" :| []))+                { chatFormat = Just JsonFormat+                , chatOptions = fastOptions+                , chatThink = Just ThinkDisabled+                }+        res <- chat client req+        case res of+          Left err -> assertFailure $ "Structured chat failed: " <> show err+          Right resp -> assertBool "Response done" (crDone resp)+    , testCase "POST /api/embed — vector embeddings" $ do+        client <- defaultClient+        let req = embedRequest testModel ["Hello world", "Haskell LLM client"]+        res <- embed client req+        case res of+          Left (ApiError 501 _) -> pure ()+          Left err -> assertFailure $ "Embed request failed: " <> show err+          Right resp ->+            assertBool "Embeddings non-empty" (not $ null $ erEmbeddings resp)+    , testCase "POST /api/copy & DELETE /api/delete — model lifecycle" $ do+        client <- defaultClient+        let copyTarget = "qwen3.5:2b-test-copy"+        copyRes <- copyModel client testModel copyTarget+        case copyRes of+          Left err -> assertFailure $ "Copy model failed: " <> show err+          Right () -> do+            delRes <- deleteModel client copyTarget+            case delRes of+              Left err -> assertFailure $ "Delete model failed: " <> show err+              Right () -> pure ()+    , testCase "ConversationStore — InMemoryStore with real conversation" $ do+        store <- initInMemoryStore+        now <- getCurrentTime+        let cid = "test-conv-1"+            conv =+              Conversation+                cid+                [systemMessage "You are a concise assistant.", userMessage "My favorite color is green."]+                testModel+                now+                now+        saveConversationInMemory store conv+        mConv <- loadConversationInMemory store cid+        assertEqual "Loaded saved conversation" (Just conv) mConv+    ]++main :: IO ()+main = defaultMain tests
test/Main.hs view
@@ -1,47 +1,32 @@-{-# LANGUAGE OverloadedStrings #-}- module Main (main) where -import Data.Text (unpack)-import Ollama (Version (..), getVersion)-import Test.Ollama.Blob qualified as Blob-import Test.Ollama.Chat qualified as Chat-import Test.Ollama.Common qualified as Common-import Test.Ollama.Copy qualified as Copy-import Test.Ollama.Create qualified as Create-import Test.Ollama.Delete qualified as Delete-import Test.Ollama.Embedding qualified as Embeddings-import Test.Ollama.Generate qualified as Generate-import Test.Ollama.List qualified as List-import Test.Ollama.Load qualified as Load-import Test.Ollama.Show qualified as Show+import Test.Ollama.Golden.Chat qualified as GoldenChat+import Test.Ollama.Golden.Embed qualified as GoldenEmbed+import Test.Ollama.Golden.Generate qualified as GoldenGenerate+import Test.Ollama.Golden.Models qualified as GoldenModels+import Test.Ollama.Property.Roundtrip qualified as PropertyRoundtrip+import Test.Ollama.Unit.Config qualified as UnitConfig+import Test.Ollama.Unit.Error qualified as UnitError+import Test.Ollama.Unit.SchemaBuilder qualified as UnitSchemaBuilder+import Test.Ollama.Unit.Testing qualified as UnitTesting+import Test.Ollama.Unit.Types qualified as UnitTypes import Test.Tasty  tests :: TestTree tests =   testGroup-    "Tests"-    [ -- Core functionality tests-      Generate.tests-    , Chat.tests-    , Embeddings.tests-    , -- Model management tests-      Show.tests-    , List.tests-    , Copy.tests-    , Create.tests-    , Delete.tests-    , Load.tests-    , -- Utility and blob tests-      Blob.tests-    , Common.tests+    "ollama-haskell Pure Test Suite"+    [ UnitTypes.tests+    , UnitError.tests+    , UnitConfig.tests+    , UnitSchemaBuilder.tests+    , UnitTesting.testingTests+    , PropertyRoundtrip.tests+    , GoldenChat.tests+    , GoldenGenerate.tests+    , GoldenEmbed.tests+    , GoldenModels.tests     ]  main :: IO ()-main = do-  eRes <- getVersion-  case eRes of-    Left err -> print err-    Right (Version r) -> do-      putStrLn $ "Ollama client version: " <> unpack r-      defaultMain tests+main = defaultMain tests
− test/Test/Ollama/Blob.hs
@@ -1,50 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Test.Ollama.Blob (tests) where--import Data.Ollama.Blob-import Data.Ollama.Common.Config (OllamaConfig (..), defaultOllamaConfig)-import Test.Tasty-import Test.Tasty.HUnit--testCheckBlobExistsInvalid :: TestTree-testCheckBlobExistsInvalid = testCase "Check blob exists: invalid digest should fail" $ do-  res <- checkBlobExists "invalid-digest" Nothing-  case res of-    Left _ -> assertBool "Should fail with invalid digest" True-    Right _ -> assertBool "Or return False for invalid digest" True--testCheckBlobExistsNonExistent :: TestTree-testCheckBlobExistsNonExistent = testCase "Check blob exists: non-existent blob" $ do-  let fakeDigest = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"-  res <- checkBlobExists fakeDigest Nothing-  case res of-    Left _ -> return () -- Network error is acceptable-    Right exists -> assertBool "Non-existent blob should return False" (not exists)--testCheckBlobExistsWithConfig :: TestTree-testCheckBlobExistsWithConfig = testCase "Check blob exists: with custom config" $ do-  let config = Just $ defaultOllamaConfig {timeout = 5}-      fakeDigest = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"-  res <- checkBlobExists fakeDigest config-  case res of-    Left _ -> return () -- Network error is acceptable-    Right _ -> assertBool "Should handle custom config" True--testCreateBlobInvalidFile :: TestTree-testCreateBlobInvalidFile = testCase "Create blob: invalid file path should fail" $ do-  let fakeDigest = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"-  res <- createBlob "/nonexistent/file/path" fakeDigest Nothing-  case res of-    Left _ -> assertBool "Should fail with invalid file path" True-    Right () -> assertFailure "Should not succeed with invalid file path"--tests :: TestTree-tests =-  testGroup-    "Blob tests"-    [ testCheckBlobExistsInvalid-    , testCheckBlobExistsNonExistent-    , testCheckBlobExistsWithConfig-    , testCreateBlobInvalidFile-    ]
− test/Test/Ollama/Chat.hs
@@ -1,307 +0,0 @@-{-# 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-    Right _ -> assertFailure "The model responded before timeout"-    Left (TimeoutError _) -> pure ()-    Left other -> assertFailure $ "Expected timeout error, got " ++ show other---- | 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" (isJust decoded)---- | Test streaming response-streamingTest :: TestTree-streamingTest = testCase "Should handle streaming response" $ do-  chunksRef <- newIORef []-  let streamHandler chunk = modifyIORef chunksRef (++ [message chunk])-      ops = defaultChatOps {stream = Just (streamHandler, pure ())}-  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))--testToolCallAddTwoNumbers :: TestTree-testToolCallAddTwoNumbers = 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-          { modelName = "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---- | Test conversation with multiple messages-multiMessageConversationTest :: TestTree-multiMessageConversationTest = testCase "Multi-message conversation should work" $ do-  let msgs =-        fromList-          [ systemMessage "You are a helpful assistant."-          , userMessage "What is 2+2?"-          , assistantMessage "2+2 equals 4."-          , userMessage "What about 3+3?"-          ]-      ops = defaultChatOps {messages = msgs}-  eRes <- chat ops Nothing-  case eRes of-    Left _ -> assertFailure "Expected success, got error"-    Right r -> case message r of-      Nothing -> assertFailure "Expected a message in response"-      Just msg -> assertBool "Should contain '6'" (T.isInfixOf "6" (content msg))---- | Test invalid model name-invalidModelChatTest :: TestTree-invalidModelChatTest = testCase "Invalid model name should fail" $ do-  let ops = defaultChatOps {modelName = "nonexistent-chat-model"}-  eRes <- chat ops Nothing-  case eRes of-    Left _ -> assertBool "Should fail with invalid model" True-    Right _ -> assertFailure "Should not succeed with invalid model"---- | Group all tests-tests :: TestTree-tests =-  sequentialTestGroup-    "Chat tests"-    AllFinish-    [ basicChatTest-    , timeoutTest-    , hooksFailTest-    , hooksSuccessTest-    , retryCountTest-    , retryDelayTest-    , commonManagerTest-    , jsonFormatTest-    , streamingTest-    , modelOptionsTest-    , testToolCallAddTwoNumbers-    , multiMessageConversationTest-    , invalidModelChatTest-    ]
− test/Test/Ollama/Common.hs
@@ -1,91 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Test.Ollama.Common (tests) where--import Data.Ollama.Common.SchemaBuilder-import Data.Ollama.Common.Utils (encodeImage)-import Data.Text qualified as T-import Test.Tasty-import Test.Tasty.HUnit---- Test SchemaBuilder functionality-testSchemaBuilderBasic :: TestTree-testSchemaBuilderBasic = testCase "SchemaBuilder: basic object construction" $ do-  let schema =-        buildSchema $-          emptyObject-            |+ ("name", JString)-            |+ ("age", JNumber)-            |! "name"-            |! "age"--  -- Check that schema is not null/empty-  let schemaText = T.pack $ show schema-  assertBool "Schema should not be empty" (not $ T.null schemaText)-  assertBool "Schema should contain 'name'" ("name" `T.isInfixOf` schemaText)-  assertBool "Schema should contain 'age'" ("age" `T.isInfixOf` schemaText)--testSchemaBuilderArray :: TestTree-testSchemaBuilderArray = testCase "SchemaBuilder: array types" $ do-  let arraySchema =-        buildSchema $-          emptyObject-            |+ ("items", JArray JString)-            |+ ("numbers", JArray JNumber)-            |+ ("flags", JArray JBoolean)-            |! "items"--  let schemaText = T.pack $ show arraySchema-  assertBool "Array schema should not be empty" (not $ T.null schemaText)-  assertBool "Should contain items field" ("items" `T.isInfixOf` schemaText)--testSchemaBuilderOptionalFields :: TestTree-testSchemaBuilderOptionalFields = testCase "SchemaBuilder: optional vs required fields" $ do-  let schema =-        buildSchema $-          emptyObject-            |+ ("required_field", JString)-            |+ ("optional_field", JString)-            |! "required_field"--  let schemaText = T.pack $ show schema-  assertBool "Schema should contain both fields" $-    "required_field" `T.isInfixOf` schemaText-      && "optional_field" `T.isInfixOf` schemaText---- Test image encoding utility-testEncodeImageValidFile :: TestTree-testEncodeImageValidFile = testCase "EncodeImage: should handle existing image file" $ do-  -- Test with the sample image from the examples-  result <- encodeImage "./examples/sample.png"-  case result of-    Nothing -> return () -- File might not exist in test environment-    Just encoded -> do-      assertBool "Encoded image should not be empty" (not $ T.null encoded)-      assertBool "Should be base64-like content" (T.length encoded > 10)--testEncodeImageNonExistentFile :: TestTree-testEncodeImageNonExistentFile = testCase "EncodeImage: should return Nothing for non-existent file" $ do-  result <- encodeImage "./nonexistent/file.png"-  case result of-    Nothing -> assertBool "Should return Nothing for non-existent file" True-    Just _ -> assertFailure "Should not encode non-existent file"--testEncodeImageInvalidFormat :: TestTree-testEncodeImageInvalidFormat = testCase "EncodeImage: should handle invalid file format" $ do-  result <- encodeImage "./test/Main.hs" -- Text file, not an image-  case result of-    Nothing -> assertBool "Should return Nothing for invalid format" True-    Just _ -> assertFailure "Should not encode invalid format"--tests :: TestTree-tests =-  testGroup-    "Common utilities tests"-    [ testSchemaBuilderBasic-    , testSchemaBuilderArray-    , testSchemaBuilderOptionalFields-    , testEncodeImageValidFile-    , testEncodeImageNonExistentFile-    , testEncodeImageInvalidFormat-    ]
− test/Test/Ollama/Copy.hs
@@ -1,45 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Test.Ollama.Copy (tests) where--import Control.Monad (void)-import Data.Ollama.Common.Config (OllamaConfig (..), defaultOllamaConfig)-import Data.Ollama.Copy-import Data.Ollama.Delete (deleteModel)-import Test.Tasty-import Test.Tasty.HUnit--testCopyModelBasic :: TestTree-testCopyModelBasic = testCase "Copy model: basic functionality" $ do-  res <- copyModel "gemma3" "gemma3-test-copy" Nothing-  case res of-    Left _ -> return () -- Allow failure if source model doesn't exist-    Right () -> do-      assertBool "Copy should succeed" True-      void $ deleteModel "gemma3-test-copy" Nothing--testCopyModelWithConfig :: TestTree-testCopyModelWithConfig = testCase "Copy model: with custom config" $ do-  let config = Just $ defaultOllamaConfig {timeout = 30}-  res <- copyModel "gemma3" "gemma3-test-copy-config" config-  case res of-    Left _ -> return () -- Allow failure if source doesn't exist-    Right () -> do-      assertBool "Copy with config should work" True-      void $ deleteModel "gemma3-test-copy-config" Nothing--testCopyModelInvalidSource :: TestTree-testCopyModelInvalidSource = testCase "Copy model: invalid source should fail" $ do-  res <- copyModel "nonexistent-model-12345" "some-destination" Nothing-  case res of-    Left _ -> assertBool "Should fail with invalid source" True-    Right () -> assertFailure "Should not succeed with invalid source"--tests :: TestTree-tests =-  testGroup-    "Copy tests"-    [ testCopyModelBasic-    , testCopyModelWithConfig-    , testCopyModelInvalidSource-    ]
− test/Test/Ollama/Create.hs
@@ -1,79 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Test.Ollama.Create (tests) where--import Control.Monad (void)-import Data.Maybe (isNothing)-import Data.Ollama.Common.Types (ModelOptions (..))-import Data.Ollama.Common.Utils (defaultModelOptions)-import Data.Ollama.Create-import Data.Ollama.Delete (deleteModel)-import Test.Tasty-import Test.Tasty.HUnit--testCreateModelBasic :: TestTree-testCreateModelBasic = testCase "Create model: basic from existing model" $ do-  let ops =-        (defaultCreateOps "test-model-basic")-          { fromModel = Just "gemma3"-          , systemPrompt = Just "You are a helpful assistant."-          }-  createModel ops Nothing-  assertBool "Create should complete without error" True-  void $ deleteModel "test-model-basic" Nothing--testCreateModelWithQuantization :: TestTree-testCreateModelWithQuantization = testCase "Create model: with quantization" $ do-  let ops =-        (defaultCreateOps "test-model-quantized")-          { fromModel = Just "gemma3"-          , quantizeType = Just Q4_K_M-          }-  createModel ops Nothing-  assertBool "Quantization request should complete" True-  void $ deleteModel "test-model-quantized" Nothing--testCreateModelWithParameters :: TestTree-testCreateModelWithParameters = testCase "Create model: with custom parameters" $ do-  let modelOpts =-        defaultModelOptions-          { temperature = Just 0.7-          , topP = Just 0.9-          , topK = Just 40-          }-      ops =-        (defaultCreateOps "test-model-params")-          { fromModel = Just "gemma3"-          , parameters = Just modelOpts-          , template = Just "Custom template: {{.Prompt}}"-          }-  createModel ops Nothing-  assertBool "Custom parameters should be handled" True-  void $ deleteModel "test-model-params" Nothing--testQuantizationTypeValues :: TestTree-testQuantizationTypeValues = testCase "Quantization types: should have valid values" $ do-  let q1 = Q4_K_M-      q2 = Q4_K_S-      q3 = Q8_0-  assertBool "Q4_K_M should be valid" (show q1 == "Q4_K_M")-  assertBool "Q4_K_S should be valid" (show q2 == "Q4_K_S")-  assertBool "Q8_0 should be valid" (show q3 == "Q8_0")--testCreateModelFieldAccess :: TestTree-testCreateModelFieldAccess = testCase "CreateOps: field access should work" $ do-  let ops = defaultCreateOps "test-model"-  assertBool "modelName should be accessible" (modelName ops == "test-model")-  assertBool "fromModel should be Nothing by default" (isNothing (fromModel ops))-  assertBool "files should be Nothing by default" (isNothing (files ops))--tests :: TestTree-tests =-  testGroup-    "Create tests"-    [ testCreateModelBasic-    , testCreateModelWithQuantization-    , testCreateModelWithParameters-    , testQuantizationTypeValues-    , testCreateModelFieldAccess-    ]
− test/Test/Ollama/Delete.hs
@@ -1,42 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Test.Ollama.Delete (tests) where--import Data.Ollama.Common.Config (OllamaConfig (..), defaultOllamaConfig)-import Data.Ollama.Delete-import Test.Tasty-import Test.Tasty.HUnit--testDeleteModelNonExistent :: TestTree-testDeleteModelNonExistent = testCase "Delete non-existent model should fail gracefully" $ do-  res <- deleteModel "nonexistent-model-12345" Nothing-  case res of-    Left _ -> assertBool "Should fail when deleting non-existent model" True-    Right () -> assertBool "Or succeed if server handles gracefully" True--testDeleteModelWithConfig :: TestTree-testDeleteModelWithConfig = testCase "Delete model: with custom config" $ do-  let config = Just $ defaultOllamaConfig {timeout = 30}-  res <- deleteModel "nonexistent-test-model" config-  case res of-    Left _ -> assertBool "Should handle custom config" True-    Right () -> assertBool "Or succeed if server handles gracefully" True--testDeleteModelEmptyName :: TestTree-testDeleteModelEmptyName = testCase "Delete model: empty name should fail" $ do-  res <- deleteModel "" Nothing-  case res of-    Left _ -> assertBool "Should fail with empty name" True-    Right () -> assertFailure "Should not succeed with empty name"---- Note: We avoid testing actual deletion of existing models in unit tests--- as it would be destructive. Integration tests could cover this.--tests :: TestTree-tests =-  testGroup-    "Delete tests"-    [ testDeleteModelNonExistent-    , testDeleteModelWithConfig-    , testDeleteModelEmptyName-    ]
− test/Test/Ollama/Embedding.hs
@@ -1,53 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Test.Ollama.Embedding (tests) where--import Data.Ollama.Embeddings-import Test.Tasty-import Test.Tasty.HUnit---- Qwen doesn't support embeddings yet--- TODO: Add embeddings supporting model.---- 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" (not (any 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---       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"-    [ testEmbeddingInvalidModel-    ]
− test/Test/Ollama/Generate.hs
@@ -1,360 +0,0 @@-{-# 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.Maybe (isJust)-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" (isJust decoded)--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-      -- Validate the encoded image data-      assertBool "Encoded image should not be empty" (not $ T.null imgData)-      assertBool "Encoded image should be reasonable length" (T.length imgData > 100)--      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 "Response should not be empty" (not $ T.null response)-          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])-      ops =-        defaultGenerateOps-          { modelName = "gemma3"-          , prompt = "Write few words about Haskell."-          , stream = Just (streamHandler, pure ())-          }-  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)--testModelOptionsEdgeCases :: TestTree-testModelOptionsEdgeCases = testCase "ModelOptions: edge case values" $ do-  let opts =-        Just $-          defaultModelOptions-            { temperature = Just 0.0 -- Minimum temperature-            , topP = Just 1.0 -- Maximum topP-            , topK = Just 1 -- Minimum topK-            , numPredict = Just 1 -- Minimum prediction-            }-  eRes <--    generate-      defaultGenerateOps-        { modelName = "gemma3"-        , prompt = "Hi"-        , options = opts-        }-      Nothing-  case eRes of-    Left _ -> assertFailure "Expected success, got error"-    Right _ -> assertBool "Should handle edge case model options" True--testInvalidModelName :: TestTree-testInvalidModelName = testCase "Invalid model name should fail gracefully" $ do-  eRes <- generate defaultGenerateOps {modelName = "invalid-model-xyz"} Nothing-  case eRes of-    Left _ -> assertBool "Should fail with invalid model name" True-    Right _ -> assertFailure "Should not succeed with invalid model name"--tests :: TestTree-tests =-  sequentialTestGroup-    "Generate tests"-    AllFinish-    [ generateTests-    , testOnModelHooksFail-    , testOnModelHooksSucc-    , testRetryCount-    , testRetryDelay-    , testCommonManagerUsage-    , testThinkOption-    , testFormatJsonFormat-    , testFormatSchemaFormat-    , testImageInput-    , testStreamingHandler-    , testModelOptionsBasic-    , testModelOptionsEdgeCases-    , testInvalidModelName-    ]
+ test/Test/Ollama/Golden/Chat.hs view
@@ -0,0 +1,25 @@+module Test.Ollama.Golden.Chat (tests) where++import Data.Aeson (encode)+import Data.List.NonEmpty (NonEmpty ((:|)))+import Ollama+import Test.Tasty+import Test.Tasty.Golden++tests :: TestTree+tests =+  testGroup+    "Golden JSON Serialization Tests"+    [ goldenVsString+        "ChatRequest JSON wire format matches golden fixture"+        "test/golden/chat_request.golden"+        (pure $ encode $ chatRequest "llama3.2" (userMessage "Why is the sky blue?" :| []))+    , goldenVsString+        "GenerateRequest JSON wire format matches golden fixture"+        "test/golden/generate_request.golden"+        (pure $ encode $ generateRequest "llama3.2" "Why is the sky blue?")+    , goldenVsString+        "EmbedRequest JSON wire format matches golden fixture"+        "test/golden/embed_request.golden"+        (pure $ encode $ embedRequest "nomic-embed-text" ["hello", "world"])+    ]
+ test/Test/Ollama/Golden/Embed.hs view
@@ -0,0 +1,16 @@+module Test.Ollama.Golden.Embed (tests) where++import Data.Aeson (encode)+import Ollama+import Test.Tasty+import Test.Tasty.Golden++tests :: TestTree+tests =+  testGroup+    "Embed Golden JSON Serialization Tests"+    [ goldenVsString+        "EmbedRequest golden serialization"+        "test/golden/embed_request.golden"+        (pure $ encode $ embedRequest "nomic-embed-text" ["hello", "world"])+    ]
+ test/Test/Ollama/Golden/Generate.hs view
@@ -0,0 +1,16 @@+module Test.Ollama.Golden.Generate (tests) where++import Data.Aeson (encode)+import Ollama+import Test.Tasty+import Test.Tasty.Golden++tests :: TestTree+tests =+  testGroup+    "Generate Golden JSON Serialization Tests"+    [ goldenVsString+        "GenerateRequest golden serialization"+        "test/golden/generate_request.golden"+        (pure $ encode $ generateRequest "llama3.2" "Why is the sky blue?")+    ]
+ test/Test/Ollama/Golden/Models.hs view
@@ -0,0 +1,16 @@+module Test.Ollama.Golden.Models (tests) where++import Data.Aeson (encode)+import Ollama+import Test.Tasty+import Test.Tasty.Golden++tests :: TestTree+tests =+  testGroup+    "Model Management Golden JSON Serialization Tests"+    [ goldenVsString+        "CreateRequest golden serialization"+        "test/golden/create_request.golden"+        (pure $ encode $ defaultCreateRequest "custom-model")+    ]
− test/Test/Ollama/List.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Test.Ollama.List (tests) where--import Data.Ollama.Common.Config (OllamaConfig (..), defaultOllamaConfig)-import Data.Ollama.List-import Data.Text qualified as T-import Test.Tasty-import Test.Tasty.HUnit--testListBasic :: TestTree-testListBasic = testCase "List models: basic call should return Models" $ do-  res <- list Nothing-  case res of-    Left err -> assertFailure $ "Expected success, got error: " ++ show err-    Right (Models modelList) -> do-      assertBool "Should return a list (possibly empty)" True-      -- Additional checks if models are present-      case modelList of-        [] -> return () -- Empty list is acceptable-        (model : _) -> do-          assertBool "Model name should not be empty" (not $ T.null $ name model)-          assertBool "Model digest should not be empty" (not $ T.null $ digest model)-          assertBool "Model size should be positive" (size model > 0)-          assertBool "details should be present" True -- ModelDetails is always present--testListWithConfig :: TestTree-testListWithConfig = testCase "List with custom config should work" $ do-  let config = Just $ defaultOllamaConfig {timeout = 10}-  res <- list config-  case res of-    Left _ -> assertFailure "Expected success, got error"-    Right (Models _) -> assertBool "Should return Models type" True--tests :: TestTree-tests =-  testGroup-    "List tests"-    [ testListBasic-    , testListWithConfig-    ]
− test/Test/Ollama/Load.hs
@@ -1,53 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Test.Ollama.Load (tests) where--import Data.Ollama.Load-import Test.Tasty-import Test.Tasty.HUnit--testLoadGenModelBasic :: TestTree-testLoadGenModelBasic = testCase "Load generation model: basic functionality" $ do-  res <- loadGenModel "gemma3"-  case res of-    Left _ -> assertFailure "Expected success, got error"-    Right () -> assertBool "Load should succeed" True--testUnloadGenModelBasic :: TestTree-testUnloadGenModelBasic = testCase "Unload generation model: basic functionality" $ do-  res <- unloadGenModel "gemma3"-  case res of-    Left _ -> assertFailure "Expected success, got error"-    Right () -> assertBool "Unload should succeed" True--testLoadInvalidModel :: TestTree-testLoadInvalidModel = testCase "Load invalid model should fail" $ do-  res <- loadGenModel "nonexistent-model-12345"-  case res of-    Left _ -> assertBool "Should fail with invalid model" True-    Right () -> assertFailure "Should not succeed with invalid model"--testUnloadInvalidModel :: TestTree-testUnloadInvalidModel = testCase "Unload invalid model should handle gracefully" $ do-  res <- unloadGenModel "nonexistent-model-12345"-  case res of-    Left _ -> assertBool "Should fail or handle gracefully" True-    Right () -> assertBool "Or succeed if server handles gracefully" True--testLoadEmptyModelName :: TestTree-testLoadEmptyModelName = testCase "Load model: empty name should fail" $ do-  res <- loadGenModel ""-  case res of-    Left _ -> assertBool "Should fail with empty name" True-    Right () -> assertFailure "Should not succeed with empty name"--tests :: TestTree-tests =-  testGroup-    "Load tests"-    [ testLoadGenModelBasic-    , testUnloadGenModelBasic-    , testLoadInvalidModel-    , testUnloadInvalidModel-    , testLoadEmptyModelName-    ]
+ test/Test/Ollama/Property/Arbitrary.hs view
@@ -0,0 +1,51 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Test.Ollama.Property.Arbitrary () where++import Data.Text (Text)+import Data.Text qualified as T+import Ollama+import Ollama.Types.Message qualified as M+import Test.QuickCheck++genNonEmptyText :: Gen Text+genNonEmptyText = T.pack <$> listOf1 (elements ['a' .. 'z'])++instance Arbitrary Role where+  arbitrary = elements [System, User, Assistant, M.Tool]++instance Arbitrary ModelName where+  arbitrary = ModelName <$> genNonEmptyText++instance Arbitrary Digest where+  arbitrary = Digest . ("sha256:" <>) <$> genNonEmptyText++instance Arbitrary Base64Image where+  arbitrary = Base64Image <$> genNonEmptyText++instance Arbitrary Duration where+  arbitrary = Duration <$> choose (1, 1000000000)++instance Arbitrary ThinkingLevel where+  arbitrary = elements [ThinkLow, ThinkMedium, ThinkHigh, ThinkMax]++instance Arbitrary Think where+  arbitrary =+    oneof+      [ pure ThinkEnabled+      , pure ThinkDisabled+      , ThinkLevel <$> arbitrary+      ]++instance Arbitrary Message where+  arbitrary =+    Message+      <$> arbitrary+      <*> genNonEmptyText+      <*> pure Nothing+      <*> pure Nothing+      <*> pure Nothing+      <*> pure Nothing++instance Arbitrary Format where+  arbitrary = pure JsonFormat
+ test/Test/Ollama/Property/Roundtrip.hs view
@@ -0,0 +1,34 @@+module Test.Ollama.Property.Roundtrip (tests) where++import Data.Aeson (decode, encode)+import Data.Text qualified as T+import Ollama+import Test.Ollama.Property.Arbitrary ()+import Test.Tasty+import Test.Tasty.QuickCheck++tests :: TestTree+tests =+  testGroup+    "Property & Roundtrip QuickCheck Tests"+    [ testProperty "Role JSON roundtrip: ∀ x. decode (encode x) == Just x" $+        \(r :: Role) -> decode (encode r) === Just r+    , testProperty "Message JSON roundtrip: ∀ x. decode (encode x) == Just x" $+        \(msg :: Message) -> decode (encode msg) === Just msg+    , testProperty "ModelName JSON roundtrip: ∀ x. decode (encode x) == Just x" $+        \(m :: ModelName) -> decode (encode m) === Just m+    , testProperty "Think JSON roundtrip: ∀ x. decode (encode x) == Just x" $+        \(t :: Think) -> decode (encode t) === Just t+    , testProperty "Digest JSON roundtrip: ∀ x. decode (encode x) == Just x" $+        \(d :: Digest) -> decode (encode d) === Just d+    , testProperty "Duration JSON roundtrip: ∀ x. decode (encode x) == Just x" $+        \(dur :: Duration) -> decode (encode dur) === Just dur+    , testProperty "Idempotency property: ∀ x. encode (decoded x) == encode x" $+        \(msg :: Message) -> case decode (encode msg) :: Maybe Message of+          Nothing -> property False+          Just decoded -> encode decoded === encode msg+    , testProperty "Smart constructor invariant: mkModelName never returns empty ModelName" $+        \txt -> case mkModelName (T.pack txt) of+          Left err -> err === "Model name cannot be empty"+          Right (ModelName name) -> not (T.null name) === True+    ]
− test/Test/Ollama/Show.hs
@@ -1,61 +0,0 @@-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE OverloadedStrings #-}--module Test.Ollama.Show (tests) where--import Data.Maybe (isJust)-import Data.Ollama.Ps-import Data.Ollama.Show-import Data.Text qualified as T-import Test.Tasty-import Test.Tasty.HUnit--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-    ]
+ test/Test/Ollama/Unit/Config.hs view
@@ -0,0 +1,19 @@+module Test.Ollama.Unit.Config (tests) where++import Ollama.Client.Config+import Test.Tasty+import Test.Tasty.HUnit++tests :: TestTree+tests =+  testGroup+    "Unit Config Tests"+    [ testCase "defaultConfig settings" $ do+        assertEqual "Default base URL" "http://127.0.0.1:11434" (configBaseUrl defaultConfig)+        assertEqual "Default timeout" 90 (configTimeout defaultConfig)+        assertEqual "Default retry policy" NoRetry (configRetry defaultConfig)+    , testCase "RetryPolicy smart constructors" $ do+        assertEqual "noRetry" NoRetry noRetry+        assertEqual "constantRetry" (ConstantRetry 3 1000000) (constantRetry 3 1000000)+        assertEqual "exponentialRetry" (ExponentialRetry 5 500000) (exponentialRetry 5 500000)+    ]
+ test/Test/Ollama/Unit/Error.hs view
@@ -0,0 +1,22 @@+module Test.Ollama.Unit.Error (tests) where++import Control.Exception (try)+import Ollama.Error+import Test.Tasty+import Test.Tasty.HUnit++tests :: TestTree+tests =+  testGroup+    "Unit Error Tests"+    [ testCase "isRetryable correctly classifies transient vs non-transient errors" $ do+        assertBool "TimeoutError is retryable" (isRetryable TimeoutError)+        assertBool "ApiError is not retryable" (not $ isRetryable (ApiError 404 "Not Found"))+        assertBool "InvalidRequest is not retryable" (not $ isRetryable (InvalidRequest "Bad model"))+    , testCase "OllamaError Eq instance compares ApiError and TimeoutError" $ do+        assertEqual "ApiError equal" (ApiError 500 "Server Error") (ApiError 500 "Server Error")+        assertBool "ApiError not equal to TimeoutError" (ApiError 500 "Server Error" /= TimeoutError)+    , testCase "throwOllama raises OllamaError as an Exception" $ do+        res <- try (throwOllama TimeoutError) :: IO (Either OllamaError ())+        assertEqual "Caught thrown OllamaError" (Left TimeoutError) res+    ]
+ test/Test/Ollama/Unit/SchemaBuilder.hs view
@@ -0,0 +1,33 @@+module Test.Ollama.Unit.SchemaBuilder (tests) where++import Data.Aeson (decode, encode)+import Ollama.Types.Format+import Test.Tasty+import Test.Tasty.HUnit++tests :: TestTree+tests =+  testGroup+    "Unit SchemaBuilder DSL Tests"+    [ testCase "Build object schema with required and optional fields" $ do+        let builder =+              emptyObject+                |+ ("name", JString)+                |+ ("age", JInteger)+                |+ ("is_student", JBoolean)+                |! "name"+            sch = buildSchema builder+            encoded = encode sch+        assertBool "Non-empty JSON schema" (not $ null $ show encoded)+    , testCase "Build array schema" $ do+        let itemType = arrayOf JString+            builder = emptyObject |+ ("items", itemType)+            sch = buildSchema builder+            encoded = encode sch+        assertBool "Non-empty array schema" (not $ null $ show encoded)+    , testCase "SchemaFormat wrapping & JSON roundtrip" $ do+        let builder = emptyObject |+ ("count", JInteger) |! "count"+            sch = buildSchema builder+            fmt = SchemaFormat sch+        assertEqual "SchemaFormat JSON roundtrip check" (Just fmt) (decode $ encode fmt)+    ]
+ test/Test/Ollama/Unit/Testing.hs view
@@ -0,0 +1,87 @@+{-# OPTIONS_GHC -Wno-deprecations #-}++{- |+Module      : Test.Ollama.Unit.Testing+Copyright   : (c) 2024-2026 Tushar Adhatrao+License     : MIT+Maintainer  : tusharadhatrao@gmail.com+Stability   : stable+Portability : portable++Unit tests for Ollama.Testing mock client and helper functions.++@since 1.0.0.0+-}+module Test.Ollama.Unit.Testing (testingTests) where++import Data.Aeson (encode)+import Data.ByteString.Lazy qualified as LBS+import Data.List.NonEmpty (NonEmpty ((:|)))+import Ollama.API.Chat (ChatResponse (..), chat, chatRequest)+import Ollama.API.Embed (+  EmbedResponse (..),+  EmbeddingsRequest (..),+  EmbeddingsResponse (..),+  embed,+  embedRequest,+  embeddings,+ )+import Ollama.API.Generate (GenerateResponse (..), generate, generateRequest)+import Ollama.API.Models (ListResponse (..), listModels)+import Ollama.Testing (+  mockChatResponse,+  mockEmbedResponse,+  mockGenerateResponse,+  mockListModelsResponse,+  withMockClient,+ )+import Ollama.Types.Common (ModelName (..))+import Ollama.Types.Message (userMessage)+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (assertEqual, testCase)++testingTests :: TestTree+testingTests =+  testGroup+    "Unit Testing Infrastructure Tests"+    [ testCase "Mock generate response" $ do+        let respPayload = mockGenerateResponse (ModelName "llama3.2") "Sky is blue"+            encoded = encode respPayload+        withMockClient (LBS.toStrict encoded) $ \client -> do+          res <- generate client (generateRequest (ModelName "llama3.2") "Why?")+          case res of+            Left err -> fail $ "Expected success, got: " <> show err+            Right resp -> assertEqual "Matching text" "Sky is blue" (grResponse resp)+    , testCase "Mock chat response" $ do+        let respPayload = mockChatResponse (ModelName "llama3.2") "Hello there"+            encoded = encode respPayload+        withMockClient (LBS.toStrict encoded) $ \client -> do+          res <- chat client (chatRequest (ModelName "llama3.2") (userMessage "Hi" :| []))+          case res of+            Left err -> fail $ "Expected success, got: " <> show err+            Right resp -> assertEqual "Matching model" (ModelName "llama3.2") (crModel resp)+    , testCase "Mock embed response" $ do+        let respPayload = mockEmbedResponse (ModelName "nomic") [[0.1, 0.2]]+            encoded = encode respPayload+        withMockClient (LBS.toStrict encoded) $ \client -> do+          res <- embed client (embedRequest (ModelName "nomic") ["test"])+          case res of+            Left err -> fail $ "Expected success, got: " <> show err+            Right resp -> assertEqual "Matching embeddings" [[0.1, 0.2]] (erEmbeddings resp)+    , testCase "Mock deprecated embeddings endpoint" $ do+        let respPayload = EmbeddingsResponse [0.5, 0.6]+            encoded = encode respPayload+        withMockClient (LBS.toStrict encoded) $ \client -> do+          res <- embeddings client (EmbeddingsRequest (ModelName "nomic") "test" Nothing Nothing)+          case res of+            Left err -> fail $ "Expected success, got: " <> show err+            Right resp -> assertEqual "Matching embedding" [0.5, 0.6] (ebrEmbedding resp)+    , testCase "Mock list models response" $ do+        let respPayload = mockListModelsResponse [ModelName "llama3.2", ModelName "nomic"]+            encoded = encode respPayload+        withMockClient (LBS.toStrict encoded) $ \client -> do+          res <- listModels client+          case res of+            Left err -> fail $ "Expected success, got: " <> show err+            Right resp -> assertEqual "Matching count" 2 (length (models resp))+    ]
+ test/Test/Ollama/Unit/Types.hs view
@@ -0,0 +1,72 @@+module Test.Ollama.Unit.Types (tests) where++import Conduit (yield)+import Data.Aeson (decode, encode)+import Data.List.NonEmpty (NonEmpty ((:|)))+import Data.Time (getCurrentTime)+import Ollama+import Ollama.Types.Message qualified as M+import Test.Tasty+import Test.Tasty.HUnit++tests :: TestTree+tests =+  testGroup+    "Unit Types & API Tests"+    [ testCase "ModelName smart constructor validation" $ do+        assertEqual "Empty name invalid" (Left "Model name cannot be empty") (mkModelName "")+        assertEqual "Valid name" (Right "llama3.2") (mkModelName "llama3.2")+    , testCase "GenerateRequest smart constructor" $ do+        let req = generateRequest "llama3.2" "Hello world"+        assertEqual "Model match" (ModelName "llama3.2") (genModel req)+        assertEqual "Prompt match" "Hello world" (genPrompt req)+        assertEqual "Stream default" (Just False) (genStream req)+    , testCase "ChatRequest smart constructor" $ do+        let msg = userMessage "Hi"+            req = chatRequest "llama3.2" (msg :| [])+        assertEqual "Model match" (ModelName "llama3.2") (chatModel req)+        assertEqual "Messages length" 1 (length (chatMessages req))+    , testCase "EmbedRequest smart constructor" $ do+        let req = embedRequest "nomic-embed-text" ["hello", "world"]+        assertEqual "Model match" (ModelName "nomic-embed-text") (embModel req)+        assertEqual "Input match" (Right ["hello", "world"]) (embInput req)+    , testCase "CreateRequest smart constructor" $ do+        let req = defaultCreateRequest "custom-model"+        assertEqual "Model match" (ModelName "custom-model") (crqModel req)+    , testCase "Role JSON roundtrip" $ do+        assertEqual "User role" (Just User) (decode (encode User))+        assertEqual "Assistant role" (Just Assistant) (decode (encode Assistant))+        assertEqual "System role" (Just System) (decode (encode System))+        assertEqual "Tool role" (Just M.Tool) (decode (encode M.Tool))+    , testCase "InMemoryStore operations" $ do+        store <- initInMemoryStore+        now <- getCurrentTime+        let conv =+              Conversation+                { conversationId = "c1"+                , messages = [userMessage "hi"]+                , model = "llama3.2"+                , createdAt = now+                , lastUpdated = now+                }+        saveConversationInMemory store conv+        mLoaded <- loadConversationInMemory store "c1"+        assertEqual "Load conversation" (Just conv) mLoaded++        allConvs <- listConversationsInMemory store+        assertEqual "List conversations" [conv] allConvs++        deleted <- deleteConversationInMemory store "c1"+        assertBool "Delete succeeded" deleted++        mLoadedAfter <- loadConversationInMemory store "c1"+        assertEqual "Load after delete" Nothing mLoadedAfter+    , testCase "Streaming collectStream helper" $ do+        let mockStream = mapM_ yield [1 .. 5 :: Int]+        items <- collectStream mockStream+        assertEqual "Collected list" [1, 2, 3, 4, 5] items+    , testCase "Streaming foldStream helper" $ do+        let mockStream = mapM_ yield [1 .. 5 :: Int]+        sumVal <- foldStream (+) 0 mockStream+        assertEqual "Folded sum" 15 sumVal+    ]