diff --git a/docs/architecture.md b/docs/architecture.md index d10e1df6..a3941a81 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -129,7 +129,7 @@ Last.fm schemas (separate, not Ecto-persisted to main DB): | `Chats.StreamProvider` | Behaviour for streaming AI chat (`stream_response/3` callback) | | `Chats.RecordChat` | Chat implementation for records (OpenAI streaming, web search enabled) | | `Chats.ArtistChat` | Chat implementation for artists (OpenAI streaming, uses Wikipedia/artist context) | -| `Chats.DefaultPrompt` | Shared default prompt fragments (identity, approach) for chat implementations | +| `Chats.Prompt` | Builds complete chat prompts by interpolating identity, content, and approach guidelines | | `Country` | Country code (alpha-2, alpha-3, subdivision, IETF) to flag emoji conversion | | `ErrorTracker.ErrorNotifier` | GenServer: attaches to ErrorTracker telemetry, skips muted errors, throttles repeated errors, dispatches email notifications | | `ErrorTracker.ErrorNotifier.Email` | Builds and sends Swoosh error notification emails with stack trace formatting | diff --git a/lib/music_library/chats/artist_chat.ex b/lib/music_library/chats/artist_chat.ex index 4fea1f76..d57e2e1f 100644 --- a/lib/music_library/chats/artist_chat.ex +++ b/lib/music_library/chats/artist_chat.ex @@ -6,7 +6,7 @@ defmodule MusicLibrary.Chats.ArtistChat do @behaviour MusicLibrary.Chats.StreamProvider alias MusicLibrary.Artists.ArtistInfo - alias MusicLibrary.Chats.DefaultPrompt + alias MusicLibrary.Chats.Prompt @impl true @spec stream_response([map()], {map(), ArtistInfo.t()}, (String.t() -> any())) :: @@ -20,16 +20,13 @@ defmodule MusicLibrary.Chats.ArtistChat do defp build_instructions(artist, artist_info) do context = build_context(artist, artist_info) - """ - #{DefaultPrompt.identity()} + Prompt.build(""" Answer questions about the artist the user is currently viewing. \ - Use the provided artist information as your primary reference, \ + Use the provided artist information as your primary reference. - #{DefaultPrompt.approach()} - - Album information: - #{context} - """ + Artist information: + #{context}\ + """) end defp build_context(artist, artist_info) do diff --git a/lib/music_library/chats/default_prompt.ex b/lib/music_library/chats/default_prompt.ex deleted file mode 100644 index a832e8d7..00000000 --- a/lib/music_library/chats/default_prompt.ex +++ /dev/null @@ -1,23 +0,0 @@ -defmodule MusicLibrary.Chats.DefaultPrompt do - @moduledoc false - - def identity do - """ - You are a knowledgeable music assistant. - """ - end - - def approach do - """ - Use web search to find additional up-to-date \ - information when helpful. Be concise and accurate. When unsure, say so. \ - Include links when they add genuine value, and at least one per response \ - (but not one per paragraph). - - Vary your response style and structure. Don't repeat information already \ - discussed in the conversation. Refer back to earlier points naturally \ - instead of restating them. DO NOT INCLUDE A SUMMARY AT THE END OF YOUR MESSAGE. \ - DO NOT PROVIDE SUGGESTIONS OR ASK QUESTIONS AS A MEAN TO CONTINUE THE CONVERSATION. - """ - end -end diff --git a/lib/music_library/chats/prompt.ex b/lib/music_library/chats/prompt.ex new file mode 100644 index 00000000..bbc8af01 --- /dev/null +++ b/lib/music_library/chats/prompt.ex @@ -0,0 +1,45 @@ +defmodule MusicLibrary.Chats.Prompt do + @moduledoc """ + Builds complete chat prompts by interpolating identity, content, and approach. + """ + + @doc """ + Builds a complete prompt from the given `text` and options. + + Options: + * `:identity` - the identity preamble (defaults to a music assistant identity) + * `:approach` - the approach guidance (defaults to standard response guidelines) + """ + @spec build(String.t(), keyword()) :: String.t() + def build(text, opts \\ []) do + identity = Keyword.get(opts, :identity, default_identity()) + approach = Keyword.get(opts, :approach, default_approach()) + + """ + #{identity} + #{text} + + #{approach}\ + """ + end + + defp default_identity do + """ + You are a knowledgeable music assistant.\ + """ + end + + defp default_approach do + """ + Use web search to find additional up-to-date \ + information when helpful. Be concise and accurate. When unsure, say so. \ + Include links when they add genuine value, and at least one per response \ + (but not one per paragraph). + + Vary your response style and structure. Don't repeat information already \ + discussed in the conversation. Refer back to earlier points naturally \ + instead of restating them. DO NOT INCLUDE A SUMMARY AT THE END OF YOUR MESSAGE. \ + DO NOT PROVIDE SUGGESTIONS OR ASK QUESTIONS AS A MEAN TO CONTINUE THE CONVERSATION.\ + """ + end +end diff --git a/lib/music_library/chats/record_chat.ex b/lib/music_library/chats/record_chat.ex index bcd70e4e..f7f184ef 100644 --- a/lib/music_library/chats/record_chat.ex +++ b/lib/music_library/chats/record_chat.ex @@ -5,7 +5,7 @@ defmodule MusicLibrary.Chats.RecordChat do @behaviour MusicLibrary.Chats.StreamProvider - alias MusicLibrary.Chats.DefaultPrompt + alias MusicLibrary.Chats.Prompt alias MusicLibrary.Records.Record @impl true @@ -25,16 +25,13 @@ defmodule MusicLibrary.Chats.RecordChat do text -> text end - """ - #{DefaultPrompt.identity()} + Prompt.build(""" Answer questions about the album the user is currently viewing. \ - Use the provided album information as your primary reference, \ - - #{DefaultPrompt.approach()} + Use the provided album information as your primary reference. Album information: - #{context} - """ + #{context}\ + """) end defp basic_context(%Record{} = record) do