# Karn
Karn is an interactive AI assistant for your Elixir codebase, designed to be used within an `IEx` session. It helps you understand and query your code using natural language, leveraging the power of Large Language Models.
## Features
* **Natural Language Queries**: Ask questions about your code in plain English.
* **Code Explanations**: Get detailed explanations for specific modules and their functions.
* **Conversational Context**: Karn remembers the history of your conversation, allowing for follow-up questions.
* **Context Management**: View the current conversation context or reset it when needed.
* **Usage Tracking**: Monitor your LLM token usage for the current session.
## Installation
Add `karn` as a dependency to your `mix.exs` file. It is recommended to add it only for the `:dev` environment.
User can change the default model by adding to their dev config
``` elixir
config :my_app,Karn,default_model: "anthropic:model"
```
```elixir
def deps do
[
{:karn, "~> 0.1.0", only: [:dev]}
]
end
```
One can also install Karn using igniter
```elixir
# picks suggested model to use
mix igniter.install karn --google
```
Then, fetch the dependencies:
```shell
mix deps.get
```
## Todo List
- [ ] docs
- [ ] cleanup
- [ ] default models for common providers
- [ ] upgrade to stable version of reqllm
- [ ] integration tests
- [ ] validate multimodel support
- [ ] add message id/sequencing for editing specific message
- [ ] add more models in igniter installation
- [ ] update message on start for config of reqLLM on start
## Setup and Usage
Karn is designed to be used interactively within an `IEx` session.
### 1. Start IEx
Start your project's `IEx` session:
```shell
iex -S mix phx.server
#
iex -S mix run
```
### 2. Configure API Key
Karn uses the `ReqLLM` library to communicate with LLMs. You need to provide an API key for the desired service. The default model is `google:gemini-2.0-flash`, so you'll need a Google AI API key.
You can configure your key in one of two ways:
1. **Environment Variable (Recommended)**: Export the key in your shell.
```shell
export GOOGLE_API_KEY="your-google-api-key"
```
`ReqLLM` will automatically pick it up when you start `iex`.
2. **In your `IEx` session**: Configure the key manually.
```elixir
# Replace "your-google-api-key" with your actual key
ReqLLM.put_key(:google_api_key, "your-google-api-key")
```
### 3. Start the Karn Server
Start the `Karn.Ai.Server` process:
```elixir
Karn.start
```
You should see the message: `"Ask your elixir query"`
### 4. Use Karn
For a more human-friendly experience, import the `Karn.Ai` functions into your `IEx` shell. This allows you to call them directly.
```elixir
iex> import Karn
Karn
```
Now you can interact with the AI.
#### General Query (`q/1`)
Ask any question about Elixir or your project.
```elixir
iex> q "What is the difference between a GenServer and an Agent?"
```
#### Explain Module (`e/3`)
Get an explanation for a specific module. You can also provide related modules for more context.
```elixir
# Get a general explanation of MyModule
iex> e MyModule
# Get a specific explanation of MyModule
iex> e MyModule,"How does function b work?"
iex> e MyModule,[ModuleB],"How are the two modules related"
# Ask a specific question about MyModule, providing another module for context
iex> e MyModule, [MyOtherModule], "How does the main function work?"
```
#### View Conversation Context (`view_context/0`)
See the history of messages (user and assistant) in the current session.
```elixir
iex> view_context()
```
#### Reset Conversation Context (`reset_context/1`)
Clear the current conversation history. You can optionally provide a new system prompt.
```elixir
# Reset to the default system prompt
iex> reset_context()
# Reset with a custom system prompt
iex> reset_context "You are a helpful Elixir assistant."
```
#### View Usage (`usage/0`)
Check the token usage (input, output, and total cost) for the current session.
```elixir
iex> usage()
```
#### Stop Karn (`stop/0`)
Stop the `Karn.Ai.Server`. This will also print the final usage statistics for the session.
```elixir
iex> stop()
```