Packages
fnord
0.9.14
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/ai/tools/conversation.ex
defmodule AI.Tools.Conversation do
@behaviour AI.Tools
@impl AI.Tools
def async?, do: true
@impl AI.Tools
def is_available?(), do: match?({:ok, _}, Store.get_project())
@impl AI.Tools
def ui_note_on_request(%{"action" => "search", "query" => query}) do
{"Searching past conversations", query}
end
def ui_note_on_request(%{"action" => "ask", "conversation_id" => id, "query" => query}) do
{"Recalling past conversation", "(#{id}) #{query}"}
end
def ui_note_on_request(_), do: nil
@impl AI.Tools
def ui_note_on_result(%{"action" => "search"} = args, result) do
query = Map.get(args, "query", "")
titles =
result
|> SafeJson.decode!()
|> Enum.map(fn %{"conversation_id" => id, "title" => title} ->
title =
if String.contains?(title, "\n") do
title
|> String.split("\n")
|> List.first()
|> then(&(&1 <> "..."))
else
title
end
"- [#{id}] #{title}"
end)
|> Enum.join("\n")
{"Searched past conversations",
"""
# #{query}
#{titles}
"""}
end
def ui_note_on_result(%{"action" => "ask"} = args, result) do
id = Map.get(args, "conversation_id", "")
question = Map.get(args, "question", "")
{"Recalled past conversation",
"""
# (#{id}) #{question}
#{result}
"""}
end
def ui_note_on_result(_, _), do: nil
@impl AI.Tools
def tool_call_failure_message(_args, _reason), do: :default
@impl AI.Tools
def read_args(args), do: {:ok, args}
@impl AI.Tools
def spec do
%{
type: "function",
function: %{
name: "conversation_tool",
description: """
This tool allows you to perform a semantic search through past
discussions that you have had with the user. Once you find a relevant
conversation, you can ask specific questions about it and an AI agent
will extract the relevant information from the conversation for you.
""",
parameters: %{
type: "object",
additionalProperties: false,
required: ["action"],
properties: %{
"action" => %{
type: "string",
enum: ["search", "ask"],
description: "Which operation to perform."
},
"query" => %{
type: "string",
description: "Search query for semantic conversation search (action=search)."
},
"limit" => %{
type: "integer",
description: "Max number of search results.",
default: 5
},
"conversation_id" => %{
type: "string",
description: "Conversation id to ask about (action=ask)."
},
"question" => %{
type: "string",
description: "Question about the specified conversation (action=ask)."
}
}
}
}
}
end
@impl AI.Tools
def call(%{"action" => "search"} = args), do: do_search(args)
def call(%{"action" => "ask"} = args), do: do_ask(args)
defp do_search(%{"query" => query} = args) do
limit = Map.get(args, "limit", 5)
with {:ok, project} <- Store.get_project(),
{:ok, results} <- Search.Conversations.search(project, query, limit: limit) do
{:ok, results}
end
end
defp do_search(_), do: {:error, "Missing required field 'query' for action 'search'"}
defp do_ask(%{"conversation_id" => id, "question" => question}) do
agent = AI.Agent.new(AI.Agent.ConversationQA, [])
case AI.Agent.get_response(agent, %{conversation_id: id, question: question}) do
{:ok, answer} -> {:ok, answer}
{:error, reason} -> {:error, inspect(reason)}
end
end
defp do_ask(_),
do: {:error, "Missing required fields 'conversation_id' and 'question' for action 'ask'"}
end