From a80a7b321f7a6b7b98bc8514f1d445a9df64dbfb Mon Sep 17 00:00:00 2001 From: Rick Hennigan Date: Thu, 16 Nov 2023 10:00:49 -0500 Subject: [PATCH 1/2] Add a "ToolCallFrequency" option and a corresponding UI control --- Source/Chatbook/SendChat.wl | 20 ++++--- Source/Chatbook/Settings.wl | 3 +- Source/Chatbook/Tools.wl | 86 ++++++++++++++++++++++++----- Source/Chatbook/UI.wl | 107 ++++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+), 23 deletions(-) diff --git a/Source/Chatbook/SendChat.wl b/Source/Chatbook/SendChat.wl index a1bfe817..7f9385de 100644 --- a/Source/Chatbook/SendChat.wl +++ b/Source/Chatbook/SendChat.wl @@ -575,7 +575,7 @@ ServiceConnectionUtilities`ConnectionInformation["Anthropic", "ProcessedRequests makeLLMConfiguration[ as_Association ] := $lastLLMConfiguration = LLMConfiguration @ Association[ - KeyTake[ as, { "Model", "MaxTokens" } ], + KeyTake[ as, { "Model", "MaxTokens", "Temperature" } ], "StopTokens" -> { "ENDTOOLCALL" } ]; @@ -1227,21 +1227,22 @@ resolveAutoSetting[ settings_, key_ -> value_ ] := <| settings, key -> resolveAu resolveAutoSetting // endDefinition; resolveAutoSetting0 // beginDefinition; -resolveAutoSetting0[ as_, "ToolsEnabled" ] := toolsEnabledQ @ as; resolveAutoSetting0[ as_, "DynamicAutoFormat" ] := dynamicAutoFormatQ @ as; resolveAutoSetting0[ as_, "EnableLLMServices" ] := $useLLMServices; resolveAutoSetting0[ as_, "HandlerFunctionsKeys" ] := chatHandlerFunctionsKeys @ as; resolveAutoSetting0[ as_, "IncludeHistory" ] := Automatic; +resolveAutoSetting0[ as_, "MaxCellStringLength" ] := chooseMaxCellStringLength @ as; +resolveAutoSetting0[ as_, "MaxContextTokens" ] := autoMaxContextTokens @ as; +resolveAutoSetting0[ as_, "MaxOutputCellStringLength" ] := chooseMaxOutputCellStringLength @ as; +resolveAutoSetting0[ as_, "MaxTokens" ] := autoMaxTokens @ as; +resolveAutoSetting0[ as_, "Multimodal" ] := multimodalQ @ as; resolveAutoSetting0[ as_, "NotebookWriteMethod" ] := "PreemptiveLink"; resolveAutoSetting0[ as_, "ShowMinimized" ] := Automatic; resolveAutoSetting0[ as_, "StreamingOutputMethod" ] := "PartialDynamic"; -resolveAutoSetting0[ as_, "TrackScrollingWhenPlaced" ] := scrollOutputQ @ as; -resolveAutoSetting0[ as_, "Multimodal" ] := multimodalQ @ as; -resolveAutoSetting0[ as_, "MaxContextTokens" ] := autoMaxContextTokens @ as; -resolveAutoSetting0[ as_, "MaxTokens" ] := autoMaxTokens @ as; -resolveAutoSetting0[ as_, "MaxCellStringLength" ] := chooseMaxCellStringLength @ as; -resolveAutoSetting0[ as_, "MaxOutputCellStringLength" ] := chooseMaxOutputCellStringLength @ as; resolveAutoSetting0[ as_, "Tokenizer" ] := getTokenizer @ as; +resolveAutoSetting0[ as_, "ToolCallFrequency" ] := Automatic; +resolveAutoSetting0[ as_, "ToolsEnabled" ] := toolsEnabledQ @ as; +resolveAutoSetting0[ as_, "TrackScrollingWhenPlaced" ] := scrollOutputQ @ as; resolveAutoSetting0[ as_, key_String ] := Automatic; resolveAutoSetting0 // endDefinition; @@ -1255,7 +1256,7 @@ $autoSettingKeyDependencies = <| "Multimodal" -> { "EnableLLMServices", "Model" }, "Tokenizer" -> "Model", "Tools" -> { "LLMEvaluator", "ToolsEnabled" }, - "ToolsEnabled" -> "Model" + "ToolsEnabled" -> { "Model", "ToolCallFrequency" } |>; (* Sort topologically so dependencies will be satisfied in order: *) @@ -1391,6 +1392,7 @@ getNamedLLMEvaluator // endDefinition; (*toolsEnabledQ*) (*FIXME: move to Tools.wl *) toolsEnabledQ[ KeyValuePattern[ "ToolsEnabled" -> enabled: True|False ] ] := enabled; +toolsEnabledQ[ KeyValuePattern[ "ToolCallFrequency" -> freq: (_Integer|_Real)? NonPositive ] ] := False; toolsEnabledQ[ KeyValuePattern[ "Model" -> model_ ] ] := toolsEnabledQ @ toModelName @ model; toolsEnabledQ[ "chat-bison-001" ] := False; toolsEnabledQ[ model_String ] := ! TrueQ @ StringContainsQ[ model, "gpt-3", IgnoreCase -> True ]; diff --git a/Source/Chatbook/Settings.wl b/Source/Chatbook/Settings.wl index abbc46d5..33840344 100644 --- a/Source/Chatbook/Settings.wl +++ b/Source/Chatbook/Settings.wl @@ -51,6 +51,7 @@ $defaultChatSettings = <| "StreamingOutputMethod" -> Automatic, "Temperature" -> 0.7, "Tokenizer" -> Automatic, + "ToolCallFrequency" -> Automatic, "ToolOptions" :> $DefaultToolOptions, "Tools" -> Automatic, "ToolsEnabled" -> Automatic, @@ -432,7 +433,7 @@ $currentEvaluationObject := $FrontEndSession; verifyInheritance // beginDefinition; verifyInheritance[ obj: $$feObj ] /; $cloudNotebooks := True; verifyInheritance[ obj: $$feObj? inheritingQ ] := True; -verifyInheritance[ obj: $$feObj ] := With[ { verified = verifyInheritance0 @ obj }, True /; inheritingQ @ obj ]; +verifyInheritance[ obj: $$feObj ] := With[ { verified = verifyInheritance0 @ obj }, inheritingQ @ obj ]; verifyInheritance // endDefinition; diff --git a/Source/Chatbook/Tools.wl b/Source/Chatbook/Tools.wl index d36f97b2..06336349 100644 --- a/Source/Chatbook/Tools.wl +++ b/Source/Chatbook/Tools.wl @@ -509,7 +509,7 @@ makeToolConfiguration // beginDefinition; makeToolConfiguration[ settings_Association ] := Enclose[ Module[ { tools }, tools = ConfirmMatch[ DeleteDuplicates @ Flatten @ Values @ $selectedTools, { ___LLMTool }, "SelectedTools" ]; - $toolConfiguration = LLMConfiguration @ <| "Tools" -> tools, "ToolPrompt" -> $toolPrompt |> + $toolConfiguration = LLMConfiguration @ <| "Tools" -> tools, "ToolPrompt" -> makeToolPrompt @ settings |> ], throwInternalFailure[ makeToolConfiguration @ settings, ## ] & ]; @@ -532,6 +532,35 @@ toolRequestParser := toolRequestParser = LLMConfiguration::invprop ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makeToolPrompt*) +makeToolPrompt // beginDefinition; + +makeToolPrompt[ settings_Association ] := $lastToolPrompt = TemplateObject[ + Riffle[ + DeleteMissing @ { + $toolPre, + TemplateSequence[ + TemplateExpression @ StringTemplate[ + "Tool Name: `Name`\nDescription: `Description`\nSchema:\n`Schema`\n\n" + ], + TemplateExpression @ Map[ + Append[ #[ "Data" ], "Schema" -> ExportString[ #[ "JSONSchema" ], "JSON" ] ] &, + TemplateSlot[ "Tools" ] + ] + ], + $toolPost, + makeToolPreferencePrompt @ settings + }, + "\n\n" + ], + CombinerFunction -> StringJoin, + InsertionFunction -> TextString +]; + +makeToolPrompt // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*$toolPrompt*) @@ -547,7 +576,8 @@ $toolPrompt := TemplateObject[ TemplateSlot[ "Tools" ] ] ], - $toolPost + $toolPost, + $fullExamples }, CombinerFunction -> StringJoin, InsertionFunction -> TextString @@ -558,13 +588,10 @@ $toolPre = "\ # Tool Instructions You have access to tools which can be used to do things, fetch data, compute, etc. while you create your response. \ -Each tool takes input as JSON following a JSON schema. Here are the available tools and their associated schemas: - -"; +Each tool takes input as JSON following a JSON schema. Here are the available tools and their associated schemas:"; -$toolPost := " - +$toolPost := "\ To call a tool, write the following at any time during your response: TOOLCALL: @@ -590,14 +617,47 @@ If a user asks you to use a specific tool, you MUST attempt to use that tool as even if you think it will not work. \ If the tool fails, use any error message to correct the issue or explain why it failed. \ NEVER state that a tool cannot be used for a particular task without trying it first. \ -You did not create these tools, so you do not know what they can and cannot do. +You did not create these tools, so you do not know what they can and cannot do."; -" <> $fullExamples; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*makeToolPreferencePrompt*) +makeToolPreferencePrompt // beginDefinition; -(* TODO: - Create a preference setting called "ToolCallFrequency" that inserts a prompt here telling the LLM how often it - should be making tool calls. -*) +makeToolPreferencePrompt[ settings_ ] := + makeToolPreferencePrompt[ settings, settings[ "ToolCallFrequency" ] ]; + +makeToolPreferencePrompt[ settings_, Automatic ] := + Missing[ "NotAvailable" ]; + +makeToolPreferencePrompt[ settings_, freq_? NumberQ ] := + With[ { key = Round @ Clip[ 5 * freq, { 0, 5 } ] }, + TemplateApply[ + $toolPreferencePrompt, + <| "Number" -> Round[ freq * 100 ], "Explanation" -> Lookup[ $toolFrequencyExplanations, key, "" ] |> + ] + ]; + +makeToolPreferencePrompt // endDefinition; + + +$toolPreferencePrompt = "\ +## User Tool Call Preferences + +The user has specified their desired tool calling frequency to be `Number`% with the following instructions: + +IMPORTANT +`Explanation`"; + + +$toolFrequencyExplanations = <| + 0 -> "Only use a tool if explicitly instructed to use tools. Never use tools unless specifically asked to.", + 1 -> "Avoid using tools unless you think it is necessary.", + 2 -> "Only use tools if you think it will significantly improve the quality of your response.", + 3 -> "Use tools whenever it is appropriate to do so.", + 4 -> "Use tools whenever there's even a slight chance that it could improve the quality of your response (e.g. fact checking).", + 5 -> "ALWAYS make a tool call in EVERY response, no matter what." +|>; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) diff --git a/Source/Chatbook/UI.wl b/Source/Chatbook/UI.wl index cd1cf669..879c5d00 100644 --- a/Source/Chatbook/UI.wl +++ b/Source/Chatbook/UI.wl @@ -471,6 +471,98 @@ labeledCheckbox[value_, label_, enabled_ : Automatic] := (*====================================*) +makeToolCallFrequencySlider[ obj_ ] := Pane[ + Grid[ + { + { + labeledCheckbox[ + Dynamic[ + currentChatSettings[ obj, "ToolCallFrequency" ] === Automatic, + Function[ + If[ TrueQ[ # ], + CurrentValue[ obj, { TaggingRules, "ChatNotebookSettings", "ToolCallFrequency" } ] = Inherited, + CurrentValue[ obj, { TaggingRules, "ChatNotebookSettings", "ToolCallFrequency" } ] = 0.5 + ] + ] + ], + Style[ "Choose automatically", "ChatMenuLabel" ] + ] + }, + { + Pane[ + Slider[ + Dynamic[ + Replace[ currentChatSettings[ obj, "ToolCallFrequency" ], Automatic -> 0.5 ], + (CurrentValue[ obj, { TaggingRules, "ChatNotebookSettings", "ToolCallFrequency" } ] = #) & + ], + { 0, 1, 0.01 }, + (* Enabled -> Dynamic[ currentChatSettings[ obj, "ToolCallFrequency" ] =!= Automatic ], *) + ImageSize -> { 150, Automatic }, + ImageMargins -> { { 5, 0 }, { 5, 5 } } + ], + ImageSize -> { 180, Automatic }, + BaseStyle -> { FontSize -> 12 } + ], + SpanFromLeft + } + }, + Alignment -> Left, + Spacings -> { Automatic, 0 } + ], + ImageMargins -> { { 5, 0 }, { 5, 5 } } +]; + +makeToolCallFrequencySlider[ obj_ ] := + Module[ { checkbox, slider }, + checkbox = labeledCheckbox[ + Dynamic[ + currentChatSettings[ obj, "ToolCallFrequency" ] === Automatic, + Function[ + If[ TrueQ[ # ], + CurrentValue[ obj, { TaggingRules, "ChatNotebookSettings", "ToolCallFrequency" } ] = Inherited, + CurrentValue[ obj, { TaggingRules, "ChatNotebookSettings", "ToolCallFrequency" } ] = 0.5 + ] + ] + ], + Style[ "Choose automatically", "ChatMenuLabel" ] + ]; + slider = Pane[ + Grid[ + { + { + Style[ "Rare", "ChatMenuLabel", FontSize -> 12 ], + Slider[ + Dynamic[ + Replace[ currentChatSettings[ obj, "ToolCallFrequency" ], Automatic -> 0.5 ], + (CurrentValue[ obj, { TaggingRules, "ChatNotebookSettings", "ToolCallFrequency" } ] = #) & + ], + { 0, 1, 0.01 }, + ImageSize -> { 100, Automatic }, + ImageMargins -> { { 0, 0 }, { 5, 5 } } + ], + Style[ "Often", "ChatMenuLabel", FontSize -> 12 ] + } + }, + Spacings -> { { 0, { 0.5 }, 0 }, 0 }, + Alignment -> { { Left, Center, Right }, Baseline } + ], + ImageMargins -> 0, + ImageSize -> { 170, Automatic } + ]; + Pane[ + PaneSelector[ + { + True -> Column[ { checkbox }, Alignment -> Left ], + False -> Column[ { slider, checkbox }, Alignment -> Left ] + }, + Dynamic[ currentChatSettings[ obj, "ToolCallFrequency" ] === Automatic ], + ImageSize -> Automatic + ], + ImageMargins -> { { 5, 0 }, { 5, 5 } } + ] + ]; + + makeTemperatureSlider[ value_ ] := @@ -592,6 +684,10 @@ makeFrontEndAndNotebookSettingsContent[ ] ] }, Spacer[3]]}, + {Row[{ + tr["Default Tool Call Frequency:"], + makeToolCallFrequencySlider[ targetObj ] + }, Spacer[3]]}, {Row[{ tr["Default Temperature:"], makeTemperatureSlider[ @@ -985,6 +1081,7 @@ makeChatActionMenu[ targetObj, {TaggingRules, "ChatNotebookSettings", "Role"} ], + "ToolCallFrequency" -> targetObj, "TemperatureValue" -> Dynamic[ currentChatSettings[ targetObj, "Temperature" ], newValue |-> ( @@ -1005,6 +1102,7 @@ Options[makeChatActionMenuContent] = { "PersonaValue" -> Automatic, "ModelValue" -> Automatic, "RoleValue" -> Automatic, + "ToolCallFrequency" -> Automatic, "TemperatureValue" -> Automatic, "ActionCallback" -> (Null &) } @@ -1020,6 +1118,7 @@ makeChatActionMenuContent[ personaValue = OptionValue["PersonaValue"], modelValue = OptionValue["ModelValue"], roleValue = OptionValue["RoleValue"], + toolValue = OptionValue["ToolCallFrequency"], tempValue = OptionValue["TemperatureValue"], advancedSettingsMenu, menuLabel, @@ -1039,6 +1138,14 @@ makeChatActionMenuContent[ None } }, + { + "Tool Call Frequency", + { + None, + makeToolCallFrequencySlider[toolValue], + None + } + }, {"Roles"}, Map[ entry |-> ConfirmReplace[entry, { From d68439e5a71287517ce6cf111eb623536162f103 Mon Sep 17 00:00:00 2001 From: Rick Hennigan Date: Mon, 20 Nov 2023 12:46:56 -0500 Subject: [PATCH 2/2] Only show the custom API endpoint input when it would have an effect --- Source/Chatbook/UI.wl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/Chatbook/UI.wl b/Source/Chatbook/UI.wl index 44eb6cc8..8f201353 100644 --- a/Source/Chatbook/UI.wl +++ b/Source/Chatbook/UI.wl @@ -42,6 +42,7 @@ Needs[ "Wolfram`Chatbook`Models`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; Needs[ "Wolfram`Chatbook`PreferencesUtils`" ]; Needs[ "Wolfram`Chatbook`Serialization`" ]; +Needs[ "Wolfram`Chatbook`Services`" ]; Needs[ "Wolfram`Chatbook`Settings`" ]; Needs[ "Wolfram`Chatbook`Utils`" ]; @@ -578,6 +579,7 @@ makeTemperatureSlider[ BaseStyle -> { FontSize -> 12 } ] +(* cSpell: ignore AIAPI *) makeOpenAIAPICompletionURLForm[value_]:= Pane[ InputField[value, String, @@ -710,7 +712,9 @@ makeFrontEndAndNotebookSettingsContent[ ] }, Spacer[3]]}, - {Row[{ + If[ TrueQ @ $useLLMServices, + Nothing, + {Row[{ tr["Chat Completion URL:"], makeOpenAIAPICompletionURLForm[ Dynamic[ @@ -723,7 +727,7 @@ makeFrontEndAndNotebookSettingsContent[ ) ] ] - }, Spacer[3]]}, + }, Spacer[3]]}], { labeledCheckbox[ Dynamic[