Package: cursivepy
Cursive is a universal and intuitive framework for interacting with LLMs.highlights✦Extensible- You can easily hook into any part of a completion life cycle. Be it to log, cache, or modify the results.✦Functions- Easily describe functions that the LLM can use along with its definition, with any model (currently supporting GPT-4, GPT-3.5, Claude 2, and Claude Instant)✦Universal- Cursive aims to bridge as many capabilities between different models as possible. Ultimately, this means that with a single interface, you can allow your users to choose any model.✦Informative- Cursive comes with built-in token usage and costs calculations, as accurate as possible.✦Reliable- Cursive comes with automatic retry and model expanding upon exceeding context length. Which you can always configure.quickstartInstall.poetryaddcursivepy# orpipinstallcursivepyStart using.fromcursiveimportCursivecursive=Cursive()response=cursive.ask(prompt='What is the meaning of life?',)print(response.answer)usageConversationChaining a conversation is easy withcursive. You can pass any of the options you're used to with OpenAI's API.res_a=cursive.ask(prompt='Give me a good name for a gecko.',model='gpt-4',max_tokens=16,)print(res_a.answer)# Zephyrres_b=res_a.conversation.ask(prompt='How would you say it in Portuguese?')print(res_b.answer)# ZéfiroStreamingStreaming is also supported, and we also keep track of the tokens for you!result=cursive.ask(prompt='Count to 10',stream=True,on_token=lambdapartial:print(partial['content']))print(result.usage.total_tokens)# 40FunctionsYou can use very easily to define and describe functions, along side with their execution code.fromcursiveimportcursive_function,Cursivecursive=Cursive()@cursive_function()defadd(a:float,b:float):"""Adds two numbers.a: The first number.b: The second number."""returna+bres=cursive.ask(prompt='What is the sum of 232 and 243?',functions=[add],)print(res.answer)# The sum of 232 and 243 is 475.The functions' result will automatically be fed into the conversation and another completion will be made. If you want to prevent this, you can addpauseto your function definition.@cursive_function(pause=True)defcreate_character(name:str,age:str):"""Creates a character.name: The name of the character.age: The age of the character."""return{'name':name,'age':age,}res=cursive.ask(prompt='Create a character named John who is 23 years old.',functions=[create_character],)print(res.function_result)# { name: 'John', age: 23 }Cursive also supports passing in undecorated functions!defadd(a:float,b:float):returna+bres=cursive.ask(prompt='What is the sum of 232 and 243?',functions=[add],# this is equivalent to cursive_function(pause=True)(add))ifres.function_result:print(res.function_result)# 475else:print(res.answer)# Text answer in case the function is not calledModelsCursive also supports the generation of Pydantic BaseModels.fromcursive.compat.pydanticimportBaseModel,Field# Pydantic V1 APIclassCharacter(BaseModel):name:strage:intskills:list[str]=Field(min_items=2)res=cursive.ask(prompt='Create a character named John who is 23 years old.',function_call=Character,)res.function_result# is a Character instance with autogenerated fieldsHooksYou can hook into any part of the completion life cycle.cursive.on('completion:after',lambdaresult:print(result.data.cost.total,result.data.usage.total_tokens,))cursive.on('completion:error',lambdaresult:print(result.error,))cursive.ask({prompt:'Can androids dream of electric sheep?',})# 0.0002185# 113EmbeddingYou can create embeddings pretty easily withcursive.embedding=cursive.embed('This should be a document.')This will support different types of documents and integrations pretty soon.ReliabilityCursive comes with automatic retry with backoff upon failing completions, and model expanding upon exceeding context length -- which means that it tries again with a model with a bigger context length when it fails by running out of it.You can configure this behavior by passing theretryandexpandoptions toCursiveconstructor.cursive=Cursive(max_retries=5,# 0 disables it completelyexpand={'enable':True,'defaults_to':'gpt-3.5-turbo-16k','resolve_model':{'gpt-3.5-turbo':'gpt-3.5-turbo-16k','gpt-4':'claude-2',},},)Available ModelsOpenAI modelsgpt-3.5-turbogpt-3.5-turbo-16kgpt-4gpt-4-32kAny other chat completion model versionCredentialsYou can pass your OpenAI API key toCursive's constructor, or set theOPENAI_API_KEYenvironment variable.Anthropic modelsclaude-2claude-instant-1claude-instant-1.2Any other model versionCredentialsYou can pass your Anthropic API key toCursive's constructor, or set theANTHROPIC_API_KEYenvironment variable.OpenRouter modelsOpenRouter is a service that gives you access to leading language models in an OpenAI-compatible API, including function calling!anthropic/claude-instant-1.2anthropic/claude-2openai/gpt-4-32kgoogle/palm-2-codechat-bisonnousresearch/nous-hermes-llama2-13bAny model version fromhttps://openrouter.ai/docs#modelsCredentialsfromcursiveimportCursivecursive=Cursive(openrouter={"api_key":"sk-or-...","app_title":"Your App Name","app_url":"https://appurl.com",})cursive.ask(model="anthropic/claude-instant-1.2",prompt="What is the meaning of life?")Cohere modelscommandAny other model version (such ascommand-nightly)CredentialsYou can pass your Cohere API key toCursive's constructor, or set theCOHERE_API_KEYenvironment variable.Replicate modelsYou can prepend `replicate/` to any model name and version available on Replicate.Examplecursive.ask(prompt='What is the meaning of life?',model='replicate/a16z-infra/llama-2-13b-chat:2a7f981751ec7fdf87b5b91ad4db53683a98082e9ff7bfd12c8cd5ea85980a52',)CredentialsYou can pass your Replicate API key toCursive's constructor, or set theREPLICATE_API_TOKENenvironment variable.roadmapvendor supportAnthropicCohereReplicateOpenRouterAzure OpenAI modelsHuggingface