diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index bbc0a28f..e4f22de4 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check run: wolframscript -f Scripts/CheckPaclet.wls @@ -38,7 +38,7 @@ jobs: run: wolframscript -f Scripts/BuildPaclet.wls - name: UploadArtifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: ${{ env.PACLET_BUILD_DIR }} diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index f80c55c8..73328037 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check run: wolframscript -f Scripts/CheckPaclet.wls @@ -64,7 +64,7 @@ jobs: dpkg -i gh.deb - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build run: wolframscript -f Scripts/BuildPaclet.wls @@ -96,16 +96,16 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: BuildMX run: wolframscript -f Scripts/BuildMX.wls - name: Submit - uses: WolframResearch/submit-paclet@v1.11.0 + run: wolframscript -f Scripts/SubmitPaclet.wls - name: UploadArtifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: ${{ env.PACLET_BUILD_DIR }} if-no-files-found: ignore diff --git a/Assets/AIAssistant/APIKeyDialogDescription.wl b/Assets/AIAssistant/APIKeyDialogDescription.wl index 975b1dc3..3ee285ad 100644 --- a/Assets/AIAssistant/APIKeyDialogDescription.wl +++ b/Assets/AIAssistant/APIKeyDialogDescription.wl @@ -1,6 +1,6 @@ RawBoxes @ Cell[ TextData @ { - "If you do not yet have an API key, you can create one ", + trExprTemplate["APIKeyDialogCreateKeyTemplate"][<|"1" -> Cell @ BoxData @ TagBox[ ButtonBox[ StyleBox[ "here", FontFamily -> "Source Sans Pro" ], @@ -16,8 +16,9 @@ RawBoxes @ Cell[ ] ], MouseAppearanceTag[ "LinkHand" ] - ], - ".\nTo avoid seeing this dialog in the future, choose \"Save\" to store the key in ", + ]|>], + "\n", + trExprTemplate["APIKeyDialogSaveKeyTemplate"][<|"1" -> Cell[ BoxData @ RowBox @ { TagBox[ @@ -44,8 +45,7 @@ RawBoxes @ Cell[ FontFamily -> "Source Sans Pro", ShowStringCharacters -> True, FontSize -> Inherited * 0.9 - ], - "." + ]|>] }, "Text", FontSize -> 12 diff --git a/Assets/AIAssistant/ChatContextDialogButtons.wl b/Assets/AIAssistant/ChatContextDialogButtons.wl index e5f948b6..f6484a61 100644 --- a/Assets/AIAssistant/ChatContextDialogButtons.wl +++ b/Assets/AIAssistant/ChatContextDialogButtons.wl @@ -16,7 +16,7 @@ Function[ { StyleBox[ TemplateBox[ - { "\"Cancel\"" }, + { ToBoxes[tr["CancelButton"]] }, "Row", DisplayFunction -> (Function[ @@ -161,7 +161,7 @@ Function[ { StyleBox[ TemplateBox[ - { "\"OK\"" }, + { ToBoxes[tr["OKButton"]] }, "Row", DisplayFunction -> (Function[ diff --git a/Assets/AIAssistant/ChatContextDialogCellsTemplate.wl b/Assets/AIAssistant/ChatContextDialogCellsTemplate.wl index e0e48f0f..5bdf04e6 100644 --- a/Assets/AIAssistant/ChatContextDialogCellsTemplate.wl +++ b/Assets/AIAssistant/ChatContextDialogCellsTemplate.wl @@ -190,7 +190,7 @@ { Cell[ TextData @ { - "System Prompt Text", + trRaw["ChatContextDialogSystemPromptText"], Cell @ BoxData @ PaneSelectorBox[ { True -> @@ -199,7 +199,7 @@ "ChatContextPreprompt", Cell[ BoxData @ FrameBox[ - Cell[ "This is the text that tells you what to do.", "MoreInfoText" ], + Cell[ trRaw["ChatContextDialogDescription"], "MoreInfoText" ], Background -> GrayLevel[ 0.95 ], FrameMargins -> 20, FrameStyle -> GrayLevel[ 0.9 ], @@ -250,7 +250,7 @@ { Cell[ TextData @ { - "Cell Processing Function", + trRaw["ChatContextDialogCellProcessingFunction"], Cell @ BoxData @ PaneSelectorBox[ { True -> @@ -259,7 +259,7 @@ "CellToMessageFunction", Cell[ BoxData @ FrameBox[ - Cell[ "This is the text that tells you what to do.", "MoreInfoText" ], + Cell[ trRaw["ChatContextDialogDescription"], "MoreInfoText" ], Background -> GrayLevel[ 0.95 ], FrameMargins -> 20, FrameStyle -> GrayLevel[ 0.9 ], @@ -302,7 +302,7 @@ { Cell[ TextData @ { - "Cell Post Evaluation Function", + trRaw["ChatContextDialogCellPostEvaluationFunction"], Cell @ BoxData @ PaneSelectorBox[ { True -> @@ -311,7 +311,7 @@ "ChatPost", Cell[ BoxData @ FrameBox[ - Cell[ "This is the text that tells you what to do.", "MoreInfoText" ], + Cell[ trRaw["ChatContextDialogDescription"], "MoreInfoText" ], Background -> GrayLevel[ 0.95 ], FrameMargins -> 20, FrameStyle -> GrayLevel[ 0.9 ], diff --git a/Assets/AIAssistant/ChatContextDialogStyles.wl b/Assets/AIAssistant/ChatContextDialogStyles.wl index bc9cbc57..3343c254 100644 --- a/Assets/AIAssistant/ChatContextDialogStyles.wl +++ b/Assets/AIAssistant/ChatContextDialogStyles.wl @@ -292,7 +292,7 @@ Notebook[ TemplateBox[ { TemplateBox[ { }, "MoreInfoOpenerIconTemplate" ], - "\"Click for more information\"" + tr["ChatContextDialogClickForMoreInfo"] }, "PrettyTooltipTemplate" ], diff --git a/Assets/DisplayFunctions.wxf b/Assets/DisplayFunctions.wxf index 674588ee..29f63245 100644 Binary files a/Assets/DisplayFunctions.wxf and b/Assets/DisplayFunctions.wxf differ diff --git a/Assets/Icons.wxf b/Assets/Icons.wxf index a88ca1c8..5b19bec1 100644 Binary files a/Assets/Icons.wxf and b/Assets/Icons.wxf differ diff --git a/Assets/SandboxMessages.wl b/Assets/SandboxMessages.wl index 5b07daee..12b14983 100644 --- a/Assets/SandboxMessages.wl +++ b/Assets/SandboxMessages.wl @@ -1,10 +1,11 @@ -(* cSpell: ignore ntype, usenl, notent *) +(* cSpell: ignore ntype, usenl, notent, unkunit *) ExampleData::notent = "`1` is not a known entity for the collection `2`. Try using natural language input (\[FreeformPrompt][\"query\"]) to get the correct expression instead." -General::messages = "Messages were generated which may indicate errors. Use the documentation_searcher tool to find solutions." +General::messages = "Messages were generated which may indicate errors. Use the documentation searcher tool to find solutions." General::usenl = "Messages involving `1` were generated. Try using natural language input (\[FreeformPrompt][\"query\"]) to get the correct expression instead." -Needs::nocont = "Context `1` was not created when Needs was evaluated. Use the documentation_searcher tool to find alternatives." -RandomEntity::ntype = "`1` is not a valid type of Entity or EntityClass. Use the documentation_searcher tool to find alternatives." -ResourceObject::notfname = "The ResourceObject `1` does not exist. Use the documentation_searcher tool to find alternatives." -Symbol::undefined = "Warning: Global symbol `1` is undefined. Use the documentation_searcher tool to find alternatives." -Symbol::undefined2 = "Warning: Global symbols `1` are undefined. Use the documentation_searcher tool to find alternatives." \ No newline at end of file +Needs::nocont = "Context `1` was not created when Needs was evaluated. Use the documentation searcher tool to find alternatives." +Quantity::unkunit = "Unable to interpret unit specification `1`. Try using natural language input (\[FreeformPrompt][\"query\"]) to get the correct expression instead."; +RandomEntity::ntype = "`1` is not a valid type of Entity or EntityClass. Use the documentation searcher tool to find alternatives." +ResourceObject::notfname = "The ResourceObject `1` does not exist. Use the documentation searcher tool to find alternatives." +Symbol::undefined = "Warning: Global symbol `1` is undefined. Use the documentation searcher tool to find alternatives." +Symbol::undefined2 = "Warning: Global symbols `1` are undefined. Use the documentation searcher tool to find alternatives." \ No newline at end of file diff --git a/Developer/Resources/Icons/ChatEvaluatingSpinner.wl b/Developer/Resources/Icons/ChatEvaluatingSpinner.wl new file mode 100644 index 00000000..ee058006 --- /dev/null +++ b/Developer/Resources/Icons/ChatEvaluatingSpinner.wl @@ -0,0 +1,232 @@ +Function[ + RawBoxes @ DynamicBox[ + If[ TrueQ @ $CloudEvaluation, + GraphicsBox[ + { Thickness[ 0.05 ], GrayLevel[ 0.9 ], CircleBox[ { 0, 0 }, 1 ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + DynamicModuleBox[ + { i }, + OverlayBox[ + { + PaneBox[ + AnimatorBox[ + Dynamic @ i, + { 1, 30, 1 }, + AutoAction -> False, + AnimationRate -> Automatic, + DisplayAllSteps -> True, + DefaultDuration -> 2, + AppearanceElements -> None + ], + ImageSize -> { 0, 0 } + ], + GraphicsBox[ + { Thickness[ 0.05 ], GrayLevel[ 0.9 ], CircleBox[ { 0, 0 }, 1, { 0.0, 6.2832 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + PaneSelectorBox[ + { + 1 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 4.5332, 4.9332 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 2 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 4.5151, 4.9332 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 3 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 4.4611, 4.9332 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 4 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 4.3713, 4.9332 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 5 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 4.2463, 4.9332 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 6 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 4.0869, 4.9332 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 7 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 3.894, 4.9332 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 8 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 3.6686, 4.9332 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 9 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 3.412, 4.9332 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 10 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 3.1258, 4.924 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 11 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 2.8116, 4.8802 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 12 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 2.4711, 4.8006 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 13 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 2.1064, 4.6856 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 14 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 1.7195, 4.5359 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 15 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 1.3127, 4.3525 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 16 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 0.88824, 4.1362 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 17 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { 0.44865, 3.8884 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 18 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -0.0035846, 3.6105 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 19 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -0.46585, 3.3041 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 20 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -0.9355, 2.9709 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 21 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -1.4098, 2.6129 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 22 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -1.75, 2.2322 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 23 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -1.75, 1.8308 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 24 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -1.75, 1.4112 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 25 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -1.75, 0.97565 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 26 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -1.75, 0.52676 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 27 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -1.75, 0.067093 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 28 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -1.75, -0.40072 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 29 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -1.75, -0.87399 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 30 -> + GraphicsBox[ + { Thickness[ 0.06 ], GrayLevel[ 0.7 ], CircleBox[ { 0, 0 }, 1, { -1.75, -1.35 } ] }, + PlotRange -> 1.1, + ImageSize -> #1 + ] + }, + Dynamic @ i, + ContentPadding -> False, + FrameMargins -> 0, + ImageSize -> All, + Alignment -> Automatic, + BaseStyle -> None, + TransitionDirection -> Horizontal, + TransitionDuration -> 0.5, + TransitionEffect -> Automatic + ] + }, + ContentPadding -> False, + FrameMargins -> 0 + ], + DynamicModuleValues :> { } + ] + ], + SingleEvaluation -> True + ] +] \ No newline at end of file diff --git a/Developer/Resources/Icons/DiscardedMaterial.wl b/Developer/Resources/Icons/DiscardedMaterial.wl new file mode 100644 index 00000000..46daa39c --- /dev/null +++ b/Developer/Resources/Icons/DiscardedMaterial.wl @@ -0,0 +1,134 @@ +Graphics[ + { + Thickness[ 0.066667 ], + FaceForm @ { RGBColor[ 0.53725, 0.53725, 0.53725 ], Opacity[ 1.0 ] }, + FilledCurve[ + { + { + { 1, 4, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 } + }, + { + { 0, 2, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 1, 3, 3 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 } + }, + { + { 0, 2, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 } + } + }, + { + { + { 13.0, 12.75 }, + { 13.0, 12.888 }, + { 12.888, 13.0 }, + { 12.75, 13.0 }, + { 2.25, 13.0 }, + { 2.112, 13.0 }, + { 2.0, 12.888 }, + { 2.0, 12.75 }, + { 2.0, 5.25 }, + { 2.0, 5.112 }, + { 2.112, 5.0 }, + { 2.25, 5.0 }, + { 4.468, 5.0 }, + { 4.744, 5.0 }, + { 4.968, 4.776 }, + { 4.968, 4.5 }, + { 4.968, 2.698 }, + { 7.148, 4.855 }, + { 7.242, 4.948 }, + { 7.368, 5.0 }, + { 7.5, 5.0 }, + { 12.75, 5.0 }, + { 12.888, 5.0 }, + { 13.0, 5.112 }, + { 13.0, 5.25 }, + { 13.0, 12.75 } + }, + { + { 14.0, 12.75 }, + { 14.0, 5.25 }, + { 14.0, 4.561 }, + { 13.439, 4.0 }, + { 12.75, 4.0 }, + { 7.706, 4.0 }, + { 4.819, 1.145 }, + { 4.724, 1.05 }, + { 4.597, 1.0 }, + { 4.468, 1.0 }, + { 4.403, 1.0 }, + { 4.337, 1.013 }, + { 4.275, 1.038 }, + { 4.089, 1.116 }, + { 3.968, 1.298 }, + { 3.968, 1.5 }, + { 3.968, 4.0 }, + { 2.25, 4.0 }, + { 1.561, 4.0 }, + { 1.0, 4.561 }, + { 1.0, 5.25 }, + { 1.0, 12.75 }, + { 1.0, 13.439 }, + { 1.561, 14.0 }, + { 2.25, 14.0 }, + { 12.75, 14.0 }, + { 13.439, 14.0 }, + { 14.0, 13.439 }, + { 14.0, 12.75 } + }, + { + { 10.316, 11.109 }, + { 8.207, 9.0 }, + { 10.316, 6.891 }, + { 9.609, 6.184 }, + { 7.5, 8.293 }, + { 5.391, 6.184 }, + { 4.684, 6.891 }, + { 6.793, 9.0 }, + { 4.684, 11.109 }, + { 5.391, 11.816 }, + { 7.5, 9.707 }, + { 9.609, 11.816 }, + { 10.316, 11.109 } + } + } + ] + }, + AspectRatio -> Automatic, + ImageSize -> { 16.0, 16.0 }, + PlotRange -> { { -0.5, 15.5 }, { -0.5, 15.5 } } +] \ No newline at end of file diff --git a/Developer/Resources/Icons/SendChatButton.wl b/Developer/Resources/Icons/SendChatButton.wl new file mode 100644 index 00000000..d0b6c068 --- /dev/null +++ b/Developer/Resources/Icons/SendChatButton.wl @@ -0,0 +1,42 @@ +Function[ + DynamicModule[ { cell }, + PaneSelector[ + { + False -> + Button[ + RawBoxes @ TemplateBox[ { #1, #2 }, "SendChatButtonLabel" ], + Wolfram`Chatbook`$ChatEvaluationCell = cell; + SelectionMove[ cell, All, Cell ]; + FrontEndTokenExecute[ Notebooks @ cell, "EvaluateCells" ], + FrameMargins -> 0, + Method -> "Queued" + ], + True -> + Button[ + Overlay[ + { + RawBoxes @ TemplateBox[ { #2 }, "ChatEvaluatingSpinner" ], + Graphics[ + { RGBColor[ 0.71373, 0.054902, 0.0 ], Rectangle[ { -0.5, -0.5 }, { 0.5, 0.5 } ] }, + ImageSize -> #2, + PlotRange -> 1.1 + ] + }, + Alignment -> { Center, Center } + ], + If[ Wolfram`Chatbook`$ChatEvaluationCell =!= cell, + NotebookWrite[ cell, NotebookRead @ cell, None, AutoScroll -> False ], + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ "StopChat" ] + ], + FrameMargins -> 0 + ] + }, + Dynamic[ Wolfram`Chatbook`$ChatEvaluationCell === cell ], + Alignment -> { Automatic, Baseline } + ], + Initialization :> (cell = If[ $CloudEvaluation, x; EvaluationCell[ ], ParentCell @ EvaluationCell[ ] ]), + DynamicModuleValues :> { }, + UnsavedVariables :> { cell } + ] +] \ No newline at end of file diff --git a/Developer/Resources/Icons/SendChatButtonLabel.wl b/Developer/Resources/Icons/SendChatButtonLabel.wl new file mode 100644 index 00000000..aa8ec88c --- /dev/null +++ b/Developer/Resources/Icons/SendChatButtonLabel.wl @@ -0,0 +1,62 @@ +Function[ + Graphics[ + { + Thickness[ 0.055556 ], + FaceForm[ #1 ], + FilledCurve[ + { + { + { 0, 2, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 }, + { 0, 1, 0 }, + { 1, 3, 3 } + } + }, + { + { + { 16.027, 14.999 }, + { 1.9266, 14.502 }, + { 1.0396, 14.472 }, + { 0.6156, 13.398 }, + { 1.2516, 12.793 }, + { 4.3856, 9.8123 }, + { 4.6816, 9.5303 }, + { 5.1256, 9.4603 }, + { 5.5026, 9.6363 }, + { 9.1226, 11.324 }, + { 9.3736, 11.441 }, + { 9.6716, 11.336 }, + { 9.7866, 11.088 }, + { 9.9026, 10.84 }, + { 9.7916, 10.545 }, + { 9.5406, 10.428 }, + { 5.9206, 8.7393 }, + { 5.5436, 8.5643 }, + { 5.3116, 8.1793 }, + { 5.3376, 7.7713 }, + { 5.6066, 3.4543 }, + { 5.6606, 2.5783 }, + { 6.7556, 2.2123 }, + { 7.3496, 2.8723 }, + { 16.794, 13.354 }, + { 17.382, 14.007 }, + { 16.905, 15.03 }, + { 16.027, 14.999 } + } + } + ] + }, + AspectRatio -> Automatic, + ImageSize -> #2, + PlotRange -> { { -0.5, 18.5 }, { -0.5, 18.5 } } + ] +] \ No newline at end of file diff --git a/Developer/Resources/Styles.wl b/Developer/Resources/Styles.wl index 764af57e..09aac119 100644 --- a/Developer/Resources/Styles.wl +++ b/Developer/Resources/Styles.wl @@ -3,6 +3,16 @@ Begin[ "Wolfram`ChatbookStylesheetBuilder`Private`" ]; +(* ::Section::Closed:: *) +(*Resources*) + + +(* ::Subsection::Closed:: *) +(*tr*) + + +tr[name_?StringQ] := Dynamic[FEPrivate`FrontEndResource["ChatbookStrings", name]] + (* ::Section::Closed:: *) (*Notebook*) @@ -126,15 +136,20 @@ Cell[ Cell[ StyleData[ "ChatInput", StyleDefinitions -> StyleData[ "FramedChatCell" ] ], - CellFrameColor -> RGBColor[ "#a3c9f2" ], - CellGroupingRules -> "InputGrouping", - CellMargins -> { { 66, 25 }, { 1, 8 } }, - CellTrayWidgets -> <| "ChatWidget" -> <| "Visible" -> False |> |>, - CounterIncrements -> { "ChatInputCount" }, - Evaluatable -> True, - MenuSortingValue -> 1543, - StyleKeyMapping -> { "~" -> "ChatDelimiter", "'" -> "SideChat", "=" -> "WolframAlphaShort", "*" -> "Item" }, - TaggingRules -> <| "ChatNotebookSettings" -> <| |> |>, + CellFrameColor -> RGBColor[ "#a3c9f2" ], + CellFrameLabelMargins -> -32, + CellGroupingRules -> "InputGrouping", + CellMargins -> { { 66, 32 }, { 1, 8 } }, + CellTrayWidgets -> <| "ChatWidget" -> <| "Visible" -> False |> |>, + CounterIncrements -> { "ChatInputCount" }, + Evaluatable -> True, + MenuSortingValue -> 1543, + StyleKeyMapping -> { "~" -> "ChatDelimiter", "'" -> "SideChat", "=" -> "WolframAlphaShort", "*" -> "Item" }, + TaggingRules -> <| "ChatNotebookSettings" -> <| |> |>, + CellFrameLabels -> { + { None, Cell[ BoxData @ TemplateBox[ { RGBColor[ "#a3c9f2" ], 20 }, "SendChatButton" ], Background -> None ] }, + { None, None } + }, CellDingbat -> Cell[ BoxData @ DynamicBox @ ToBoxes[ If[ TrueQ @ CloudSystem`$CloudNotebooks, @@ -1004,6 +1019,107 @@ Cell[ ] +(* ::Section::Closed:: *) +(*Inline Chat Styles*) + + +(* ::Subsection::Closed:: *) +(*MessageAuthorLabel*) + + +Cell[ + StyleData[ "MessageAuthorLabel", StyleDefinitions -> StyleData[ "Text" ] ], + FontSize -> 14, + FontWeight -> "DemiBold", + ShowStringCharacters -> False +] + + +(* ::Subsection::Closed:: *) +(*UserMessageLabel*) + + +Cell[ + StyleData[ "UserMessageLabel" ], + TemplateBoxOptions -> { + DisplayFunction -> Function @ PaneBox[ + #, + BaseStyle -> { "MessageAuthorLabel" }, + ImageSize -> { Scaled[ 1 ], Automatic }, + Alignment -> Right, + FrameMargins -> { { 0, 11 }, { 0, 0 } } + ] + } +] + + +(* ::Subsection::Closed:: *) +(*AssistantMessageLabel*) + + +Cell[ + StyleData[ "AssistantMessageLabel" ], + TemplateBoxOptions -> { + DisplayFunction -> Function @ PaneBox[ + #, + BaseStyle -> { "MessageAuthorLabel" }, + ImageSize -> { Scaled[ 1 ], Automatic }, + Alignment -> Left, + FrameMargins -> { { 11, 0 }, { 0, 0 } } + ] + } +] + + +(* ::Subsection::Closed:: *) +(*UserMessageBox*) + + +Cell[ + StyleData[ "UserMessageBox" ], + TemplateBoxOptions -> { + DisplayFunction -> Function @ Evaluate @ FrameBox[ + Cell[ #, "Text", Background -> None ], + Background -> RGBColor[ "#edf4fc" ], + FrameMargins -> 8, + FrameStyle -> RGBColor[ "#a3c9f2" ], + RoundingRadius -> 10, + StripOnInput -> False + ] + } +] + + +(* ::Subsection::Closed:: *) +(*AssistantMessageBox*) + + +Cell[ + StyleData[ "AssistantMessageBox" ], + TemplateBoxOptions -> { + DisplayFunction -> Function @ Evaluate @ FrameBox[ + #, + BaseStyle -> "Text", + Background -> RGBColor[ "#fcfdff" ], + FrameMargins -> 8, + FrameStyle -> RGBColor[ "#c9ccd0" ], + ImageSize -> { Scaled[ 1 ], Automatic }, + RoundingRadius -> 10, + StripOnInput -> False + ] + } +] + + +(* ::Subsection::Closed:: *) +(*DropShadowPaneBox*) + + +Cell[ + StyleData[ "DropShadowPaneBox" ], + TemplateBoxOptions -> { DisplayFunction -> $dropShadowPaneBox } +] + (* ::Section::Closed:: *) (*Templates*) @@ -1147,7 +1263,7 @@ Cell[ DisplayFunction -> Function[ Evaluate @ ToBoxes @ Button[ MouseAppearance[ - Tooltip[ RawBoxes @ TemplateBox[ { }, "ChatWidgetIcon" ], "Send to LLM" ], + Tooltip[ RawBoxes @ TemplateBox[ { }, "ChatWidgetIcon" ], tr["StylesheetChatWidgetButtonTooltip"] ], "LinkHand" ], With[ { $CellContext`cell = ParentCell @ EvaluationCell[ ] }, @@ -1181,6 +1297,138 @@ Cell[ +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*DiscardedMaterialOpener*) + + +Cell[ + StyleData[ "DiscardedMaterialOpener" ], + TemplateBoxOptions -> { + DisplayFunction -> Function @ DynamicModuleBox[ + { Typeset`hover$$ = False, Typeset`open$$ = False }, + PaneSelectorBox[ + { + False -> TagBox[ + GridBox[ + { { $discardedMaterialLabel } }, + DefaultBaseStyle -> "Column", + GridBoxAlignment -> { "Columns" -> { { Left } } }, + GridBoxItemSize -> { "Columns" -> { { Automatic } }, "Rows" -> { { Automatic } } }, + GridBoxSpacings -> { "Columns" -> { { Automatic } }, "Rows" -> { { 0.25 } } } + ], + "Column" + ], + True -> TagBox[ + GridBox[ + { + { $discardedMaterialLabel }, + { + FrameBox[ + #1, + Background -> RGBColor[ 0.94902, 0.96863, 0.98824 ], + FrameMargins -> 10, + FrameStyle -> RGBColor[ 0.9098, 0.93333, 0.95294 ], + ImageSize -> { Full, Automatic }, + RoundingRadius -> 5, + StripOnInput -> False + ] + } + }, + DefaultBaseStyle -> "Column", + GridBoxAlignment -> { "Columns" -> { { Left } } }, + GridBoxItemSize -> { "Columns" -> { { Automatic } }, "Rows" -> { { Automatic } } }, + GridBoxSpacings -> { "Columns" -> { { Automatic } }, "Rows" -> { { 0.25 } } } + ], + "Column" + ] + }, + Dynamic @ Typeset`open$$, + ImageMargins -> 10, + ImageSize -> Automatic, + Alignment -> Left, + ContentPadding -> False + ], + DynamicModuleValues :> { }, + UnsavedVariables :> { Typeset`hover$$ } + ] + } +] + + +Cell[ + StyleData[ "DiscardedMaterialOpenerIcon" ], + TemplateBoxOptions -> { + DisplayFunction -> Function @ GraphicsBox[ + { + #1, + Thickness[ 0.090909 ], + Opacity[ 1.0 ], + FilledCurveBox[ + { + { + { 0, 2, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 }, + { 0, 1, 0 } + } + }, + { + { + { 8.5, 4.5 }, + { 6.5, 4.5 }, + { 6.5, 2.5 }, + { 4.5, 2.5 }, + { 4.5, 4.5 }, + { 2.5, 4.5 }, + { 2.5, 6.5 }, + { 4.5, 6.5 }, + { 4.5, 8.5 }, + { 6.5, 8.5 }, + { 6.5, 6.5 }, + { 8.5, 6.5 } + } + } + ] + }, + AspectRatio -> Automatic, + BaselinePosition -> Center -> Center, + ImageSize -> { 11.0, 11.0 }, + PlotRange -> { { 0.0, 11.0 }, { 0.0, 11.0 } } + ] + } +] + + +Cell[ + StyleData[ "DiscardedMaterialCloserIcon" ], + TemplateBoxOptions -> { + DisplayFunction -> Function @ GraphicsBox[ + { + #1, + Thickness[ 0.090909 ], + Opacity[ 1.0 ], + FilledCurveBox[ + { { { 0, 2, 0 }, { 0, 1, 0 }, { 0, 1, 0 } } }, + { { { 8.5, 4.5 }, { 2.5, 4.5 }, { 2.5, 6.5 }, { 8.5, 6.5 } } } + ] + }, + AspectRatio -> Automatic, + BaselinePosition -> Center -> Center, + ImageSize -> { 11.0, 11.0 }, + PlotRange -> { { 0.0, 11.0 }, { 0.0, 11.0 } } + ] + } +] + + (* ::Section::Closed:: *) (*Package Footer*) diff --git a/Developer/Resources/WorkspaceStyles.wl b/Developer/Resources/WorkspaceStyles.wl new file mode 100644 index 00000000..d768b537 --- /dev/null +++ b/Developer/Resources/WorkspaceStyles.wl @@ -0,0 +1,173 @@ +(* ::Section::Closed:: *) +(*Package Header*) +Begin[ "Wolfram`ChatbookStylesheetBuilder`Private`" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Notebook*) +Cell[ + StyleData[ "Notebook" ], + Background -> White, + CellInsertionPointCell -> None, + "ClosingSaveDialog" -> False, + DefaultNewCellStyle -> "AutoMoveToChatInputField", + DockedCells -> $workspaceChatDockedCells, + Magnification -> 0.85, + Saveable -> False, + Selectable -> False, + ShowCellBracket -> False, + TaggingRules -> <| "ChatNotebookSettings" -> $workspaceDefaultSettings |>, + WindowClickSelect -> True, + WindowElements -> { "VerticalScrollBar" }, + WindowFrame -> "ModelessDialog", + WindowFrameElements -> { "CloseBox", "ResizeArea" }, + WindowMargins -> { { 0, Automatic }, { 0, 0 } }, + WindowSize -> { $sideChatWidth, Automatic }, + WindowTitle -> "Code Assistance Chat", + WindowToolbars -> { } +] + + +Cell[ + StyleData[ "WorkspaceChatStyleSheetInformation" ], + TaggingRules -> <| "WorkspaceChatStyleSheetVersion" -> $stylesheetVersion |> +] + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*ChatInput*) +Cell[ + StyleData[ "ChatInput" ], + CellDingbat -> None, + CellFrame -> 0, + CellFrameLabelMargins -> 6, + CellMargins -> { { 15, 10 }, { 5, 10 } }, + Selectable -> True, + ShowCellBracket -> False, + TextAlignment -> Right, + CellFrameLabels -> { + { None, None }, + { + None, + Cell @ BoxData @ TemplateBox[ + { + DynamicBox[ + ToBoxes[ + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ "UserMessageLabel" ], + StandardForm + ], + SingleEvaluation -> True + ] + }, + "UserMessageLabel" + ] + } + } +] + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*ChatOutput*) +Cell[ + StyleData[ "ChatOutput" ], + Background -> None, + CellDingbat -> None, + CellFrame -> 0, + CellMargins -> { { 10, 15 }, { 15, 12 } }, + Initialization -> None, + Selectable -> True, + ShowCellBracket -> False, + CellFrameLabels -> { + { None, None }, + { + None, + Cell @ BoxData @ TemplateBox[ + { + DynamicBox[ + ToBoxes[ + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ "AssistantMessageLabel" ], + StandardForm + ], + SingleEvaluation -> True + ] + }, + "AssistantMessageLabel" + ] + } + } +] + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*ChatInputField*) +Cell[ + StyleData[ "ChatInputField" ], + CellFrame -> 1, + CellFrameColor -> GrayLevel[ 0.85 ], + CellFrameMargins -> { { 5, 5 }, { 0, 0 } } +] + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*AutoMoveToChatInputField*) +Cell[ + StyleData[ "AutoMoveToChatInputField" ], + Initialization :> ( + NotebookDelete @ EvaluationCell[ ]; + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ "MoveToChatInputField", EvaluationNotebook[ ], True ]; + ) +] + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Template Boxes*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*WorkspaceSendChatButton*) +Cell[ + StyleData[ "WorkspaceSendChatButton" ], + TemplateBoxOptions -> { + DisplayFunction -> Function @ Evaluate @ ToBoxes @ PaneSelector[ + { + None -> Button[ + RawBoxes @ TemplateBox[ { #1, #2 }, "SendChatButtonLabel" ], + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ + "EvaluateWorkspaceChat", + #3, + Dynamic @ CurrentValue[ #3, { TaggingRules, "ChatInputString" } ] + ], + FrameMargins -> 0, + Method -> "Queued" + ] + }, + Dynamic @ Wolfram`Chatbook`$ChatEvaluationCell, + Button[ + Overlay[ + { + RawBoxes @ TemplateBox[ { #2 }, "ChatEvaluatingSpinner" ], + Graphics[ + { RGBColor[ 0.71373, 0.054902, 0.0 ], Rectangle[ { -0.5, -0.5 }, { 0.5, 0.5 } ] }, + ImageSize -> #2, + PlotRange -> 1.1 + ] + }, + Alignment -> { Center, Center } + ], + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ "StopChat" ], + FrameMargins -> 0 + ], + Alignment -> { Automatic, Baseline } + ] + } +] + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Package Footer*) +End[ ]; \ No newline at end of file diff --git a/Developer/StylesheetBuilder.wl b/Developer/StylesheetBuilder.wl index 6e819e6d..0b8ba9ca 100644 --- a/Developer/StylesheetBuilder.wl +++ b/Developer/StylesheetBuilder.wl @@ -10,7 +10,10 @@ ClearAll[ "`*" ]; ClearAll[ "`Private`*" ]; $ChatbookStylesheet; +$WorkspaceStylesheet; +BuildStylesheets; BuildChatbookStylesheet; +BuildWorkspaceStylesheet; System`LinkedItems; System`MenuAnchor; @@ -18,6 +21,7 @@ System`MenuItem; System`RawInputForm; System`ToggleMenuItem; System`Scope; +System`ClosingSaveDialog; Begin[ "`Private`" ]; @@ -27,18 +31,29 @@ Begin[ "`Private`" ]; (*Config*) +$sideChatWidth = 350; + +$workspaceDefaultSettings = <| + "SetCellDingbat" -> False, + "TabbedOutput" -> False, (* FIXME: this is temporarily set to False to avoid some bad bugs *) + "WorkspaceChat" -> True +|>; + + (* ::Subsection::Closed:: *) (*Paths*) -$assetLocation = FileNameJoin @ { DirectoryName @ $InputFileName, "Resources" }; -$iconDirectory = FileNameJoin @ { $assetLocation, "Icons" }; -$ninePatchDirectory = FileNameJoin @ { $assetLocation, "NinePatchImages" }; -$styleDataFile = FileNameJoin @ { $assetLocation, "Styles.wl" }; -$pacletDirectory = DirectoryName[ $InputFileName, 2 ]; -$iconManifestFile = FileNameJoin @ { $pacletDirectory, "Assets", "Icons.wxf" }; -$displayFunctionsFile = FileNameJoin @ { $pacletDirectory, "Assets", "DisplayFunctions.wxf" }; -$styleSheetTarget = FileNameJoin @ { $pacletDirectory, "FrontEnd", "StyleSheets", "Chatbook.nb" }; +$assetLocation = FileNameJoin @ { DirectoryName @ $InputFileName, "Resources" }; +$iconDirectory = FileNameJoin @ { $assetLocation, "Icons" }; +$ninePatchDirectory = FileNameJoin @ { $assetLocation, "NinePatchImages" }; +$styleDataFile = FileNameJoin @ { $assetLocation, "Styles.wl" }; +$workspaceStyleDataFile = FileNameJoin @ { $assetLocation, "WorkspaceStyles.wl" }; +$pacletDirectory = DirectoryName[ $InputFileName, 2 ]; +$iconManifestFile = FileNameJoin @ { $pacletDirectory, "Assets", "Icons.wxf" }; +$displayFunctionsFile = FileNameJoin @ { $pacletDirectory, "Assets", "DisplayFunctions.wxf" }; +$styleSheetTarget = FileNameJoin @ { $pacletDirectory, "FrontEnd", "StyleSheets", "Chatbook.nb" }; +$floatStyleSheetTarget = FileNameJoin @ { $pacletDirectory, "FrontEnd", "StyleSheets", "Wolfram", "WorkspaceChat.nb" }; @@ -54,6 +69,14 @@ Get[ "Wolfram`Chatbook`" ]; (*Resources*) +(* ::Subsection::Closed:: *) +(*tr*) + + +tr[name_?StringQ] := Dynamic[FEPrivate`FrontEndResource["ChatbookStrings", name]] +trBox[name_?StringQ] := DynamicBox[FEPrivate`FrontEndResource["ChatbookStrings", name]] + + (* ::Subsection::Closed:: *) (*$floatingButtonNinePatch*) @@ -61,6 +84,118 @@ Get[ "Wolfram`Chatbook`" ]; $floatingButtonNinePatch = Import @ FileNameJoin @ { $ninePatchDirectory, "FloatingButtonGrid.wxf" }; +(* ::Subsection::Closed:: *) +(*Drop Shadows*) + +$dropShadowConfig = <| + "CenterColor" -> GrayLevel[ 0.95 ], + "FrameColor" -> GrayLevel[ 0.85 ], + "FrameThickness" -> 1, + "Offset" -> { 0, -2 }, + "Radius" -> 10, + "ShadowColor" -> GrayLevel[ 0.5, 0.5 ], + "ShadowIntensity" -> 0.4 +|>; + + +$dropShadowPaneBox := $dropShadowPaneBox = + With[ { img = createNinePatch @ $dropShadowConfig }, + Function[ + PanelBox[ + #, + Appearance -> img, + ContentPadding -> False, + FrameMargins -> { { 0, 0 }, { 0, 0 } } + ] + ] + ]; + + +(* ::Subsubsection::Closed:: *) +(*createNinePatch*) + + +createNinePatch[ config_ ] := set9PatchPixels[ createBaseImage @ config, config ]; + + +(* ::Subsubsection::Closed:: *) +(*set9PatchPixels*) + + +set9PatchPixels[ image_, config: KeyValuePattern[ "Offset" -> { oh_, ov_ } ] ] := + Module[ { padded, w, h }, + padded = ImagePad[ image, 1, White ]; + { w, h } = ImageDimensions @ padded; + toByteImage @ ReplacePixelValue[ + padded, + { + { Ceiling[ w / 2 ] - oh, 1 }, + { Ceiling[ w / 2 ] - oh, h }, + { 1, Ceiling[ h / 2 ] - ov }, + { w, Ceiling[ h / 2 ] - ov } + } -> Black + ] + ]; + + +(* ::Subsubsection::Closed:: *) +(*createBaseImage*) + + +createBaseImage[ config: KeyValuePattern @ { "ShadowColor" -> shadowColor_ } ] := + With[ { alpha = createAlphaMask @ config }, + setFramePixels[ SetAlphaChannel[ ConstantImage[ shadowColor, ImageDimensions @ alpha ], alpha ], config ] + ]; + + +(* ::Subsubsection::Closed:: *) +(*toByteImage*) + + +toByteImage[ img_ ] := Image[ + NumericArray[ Round @ Clip[ 255 * ImageData @ ColorConvert[ img, "RGB" ], { 0, 255 } ], "UnsignedInteger8" ], + "Byte", + ColorSpace -> "RGB", + Interleaving -> True, + ImageResolution -> 72 +]; + + +(* ::Subsubsection::Closed:: *) +(*createAlphaMask*) + + +createAlphaMask[ config: KeyValuePattern @ { "Radius" -> radius_, "ShadowIntensity" -> shadowIntensity_ } ] := + setFramePixels[ + Image[ shadowIntensity * Rescale @ GaussianMatrix @ { radius, 0.4 * radius } ], + <| config, "FrameColor" -> White, "CenterColor" -> Black |> + ]; + + +(* ::Subsubsection::Closed:: *) +(*setFramePixels*) + + +setFramePixels[ + image_, + KeyValuePattern @ { + "CenterColor" -> centerColor_, + "FrameColor" -> frameColor_, + "FrameThickness" -> frameThickness_, + "Offset" -> { oh_, ov_ }, + "Radius" -> radius_ + } +] := + With[ { r = radius, ft = frameThickness }, + ReplacePixelValue[ + ReplacePixelValue[ + image, + { r - ft - oh + 1 ;; r + ft - oh + 1, r - ft - ov + 1 ;; r + ft - ov + 1 } -> frameColor + ], + { r - oh + 1, r - ov + 1 } -> centerColor + ] + ]; + (* ::Subsection::Closed:: *) (*$suppressButtonAppearance*) @@ -102,7 +237,21 @@ $includedCellWidget = Cell[ makeIconTemplateBoxStyle[ file_ ] := makeIconTemplateBoxStyle[ file, Import @ file ]; makeIconTemplateBoxStyle[ file_, func_Function ] := - makeIconTemplateBoxStyle[ file, func, ToBoxes @ func @ $$slot[ 1 ] /. $$slot -> Slot ]; + makeIconTemplateBoxStyle[ + file, + func, + ToBoxes @ func[ $$slot1, $$slot2, $$slot3 ] /. { + ToBoxes @ $$slot1 -> $$slot1, + ToBoxes @ $$slot2 -> $$slot2, + ToBoxes @ $$slot3 -> $$slot3 + } /. { + $$slot1 -> $$slot[ 1 ], + $$slot2 -> $$slot[ 2 ], + $$slot3 -> $$slot[ 3 ] + } /. { + $$slot -> Slot + } + ]; makeIconTemplateBoxStyle[ file_, icon_ ] := makeIconTemplateBoxStyle[ file, icon, ToBoxes @ icon ]; @@ -211,7 +360,7 @@ assistantMenuInitializer[ name_String, color_ ] := ], Appearance -> $suppressButtonAppearance ], - "Disable automatic assistance" + tr["StylesheetAssistantMenuInitializerButtonTooltip"] ], RawBoxes @ TemplateBox[ { name, color }, "ChatMenuButton" ] }, @@ -251,7 +400,7 @@ feedbackButton[ positive: True|False, name_String ] := RawBoxes @ TemplateBox[ { }, name<>"Inactive" ], RawBoxes @ TemplateBox[ { }, name<>"Active" ] ], - "Send feedback to Wolfram" + tr["StylesheetFeedbackButtonTooltip"] ], "LinkHand" ], @@ -324,13 +473,13 @@ menuItem[ icon_, label_, code_ ] := $chatOutputMenu := $chatOutputMenu = ToBoxes @ makeMenu[ { - (* Icon , Label , ActionName *) - { "DivideCellsIcon" , "Explode Cells (In Place)" , "ExplodeInPlace" }, - { "OverflowIcon" , "Explode Cells (Duplicate)", "ExplodeDuplicate" }, - { "HyperlinkCopyIcon", "Copy Exploded Cells" , "CopyExplodedCells" }, + (* Icon , Label , ActionName *) + { "DivideCellsIcon" , tr[ "StylesheetExplodeCellsInPlace" ] , "ExplodeInPlace" }, + { "OverflowIcon" , tr[ "StylesheetExplodeCellsDuplicate" ], "ExplodeDuplicate" }, + { "HyperlinkCopyIcon", tr[ "StylesheetCopyExplodedCells" ] , "CopyExplodedCells" }, Delimiter, - { "TypesettingIcon" , "Toggle Formatting" , "ToggleFormatting" }, - { "InPlaceIcon" , "Copy ChatObject" , "CopyChatObject" } + { "TypesettingIcon" , tr[ "StylesheetToggleFormatting" ] , "ToggleFormatting" }, + { "InPlaceIcon" , tr[ "StylesheetCopyChatObject" ] , "CopyChatObject" } }, GrayLevel[ 0.85 ], 250 @@ -399,7 +548,12 @@ $tabbedOutputControls = Alignment -> Center, Spacings -> 0.1 ], - Initialization :> (cell = If[ $CloudEvaluation, x; EvaluationCell[ ], ParentCell @ EvaluationCell[ ] ]), + Initialization :> ( + cell = If[ $CloudEvaluation, + Wolfram`ChatNB`x; EvaluationCell[ ], + ParentCell @ EvaluationCell[ ] + ] + ), UnsavedVariables :> { cell } ]; @@ -441,8 +595,8 @@ $cellInsertionPointCell := $cellInsertionPointCell = ReplaceAll[ item: HoldPattern[ _ :> FrontEndTokenExecute[ EvaluationNotebook[ ], "Style", "ExternalLanguage" ] ] :> Sequence[ item, - insertionPointMenuItem[ TemplateBox[ { }, "ChatInputIcon" ], "Chat Input", "'", "ChatInput" ], - insertionPointMenuItem[ TemplateBox[ { }, "SideChatIcon" ], "Side Chat", "''", "SideChat" ] + insertionPointMenuItem[ TemplateBox[ { }, "ChatInputIcon" ], trBox[ "StylesheetInsertionMenuChatInput" ], "'", "ChatInput" ], + insertionPointMenuItem[ TemplateBox[ { }, "SideChatIcon" ], trBox[ "StylesheetInsertionMenuSideChat" ], "''", "SideChat" ] ] } ]; @@ -489,12 +643,88 @@ insertionPointMenuItem[ icon_, label_, shortcut_, style_ ] := ] :> FrontEndTokenExecute[ EvaluationNotebook[ ], "Style", style ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*DiscardedMaterialOpener*) + +discardedMaterialLabelBox[ Dynamic[ hover_ ], Dynamic[ open_ ] ] := TagBox[ + TagBox[ + FrameBox[ + TagBox[ + GridBox[ + { + { + TemplateBox[ { }, "DiscardedMaterial" ], + "\"Discarded material\"", + discardedMaterialLabelIcon[ Dynamic @ hover, Dynamic @ open ] + } + }, + GridBoxAlignment -> { "Columns" -> { { Automatic } }, "Rows" -> { { Baseline } } }, + AutoDelete -> False, + GridBoxItemSize -> { "Columns" -> { { Automatic } }, "Rows" -> { { Automatic } } } + ], + "Grid" + ], + Background -> Dynamic @ FEPrivate`If[ hover, GrayLevel[ 1 ], RGBColor[ 0.94902, 0.96863, 0.98824 ] ], + BaseStyle -> { "Text", "IconizedDefaultName", ShowStringCharacters -> False }, + FrameMargins -> 2, + FrameStyle -> RGBColor[ 0.9098, 0.93333, 0.95294 ], + RoundingRadius -> 5, + StripOnInput -> False + ], + EventHandlerTag @ { + "MouseEntered" :> FEPrivate`Set[ hover, True ], + "MouseExited" :> FEPrivate`Set[ hover, False ], + "MouseClicked" :> FEPrivate`Set[ open, FEPrivate`If[ open, False, True ] ], + PassEventsDown -> True, + Method -> "Preemptive", + PassEventsUp -> True + } + ], + MouseAppearanceTag[ "LinkHand" ] +]; + +discardedMaterialLabelIcon[ Dynamic[ hover_ ], Dynamic[ open_ ] ] := + With[ { hoverColor = RGBColor[ 0.3451, 0.72157, 0.98039 ], defaultColor = GrayLevel[ 0.7451 ] }, + PaneSelectorBox[ + { + { True , False } -> TemplateBox[ { hoverColor }, "DiscardedMaterialOpenerIcon" ], + { False, False } -> TemplateBox[ { defaultColor }, "DiscardedMaterialOpenerIcon" ], + { True , True } -> TemplateBox[ { hoverColor }, "DiscardedMaterialCloserIcon" ], + { False, True } -> TemplateBox[ { defaultColor }, "DiscardedMaterialCloserIcon" ] + }, + Dynamic[ { hover, open } ] + ] + ]; + + +$discardedMaterialLabel = discardedMaterialLabelBox[ Dynamic @ Typeset`hover$$, Dynamic @ Typeset`open$$ ]; + + +(* ::Subsection::Closed:: *) +(*$workspaceChatDockedCells*) + + +$workspaceChatDockedCells = { + Cell @ BoxData @ DynamicBox[ + ToBoxes[ + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ "MakeWorkspaceChatDockedCell" ], + StandardForm + ], + Initialization :> With[ { nbo = EvaluationNotebook[ ] }, + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ "AttachWorkspaceChatInput", nbo ] + ] + ] +}; + (* ::Subsection::Closed:: *) (*Stylesheet Version*) -$stylesheetVersion = StringJoin[ +$stylesheetVersion := $stylesheetVersion = StringJoin[ PacletObject[ File[ $pacletDirectory ] ][ "Version" ], ".", ToString @ Round @ AbsoluteTime[ ] @@ -509,7 +739,8 @@ $stylesheetVersion = StringJoin[ inlineResources[ expr_ ] := expr /. { HoldPattern @ $askMenuItem :> RuleCondition @ $askMenuItem, HoldPattern @ $defaultChatbookSettings :> RuleCondition @ $defaultChatbookSettings, - HoldPattern @ $suppressButtonAppearance :> RuleCondition @ $suppressButtonAppearance + HoldPattern @ $suppressButtonAppearance :> RuleCondition @ $suppressButtonAppearance, + HoldPattern @ $discardedMaterialLabel :> RuleCondition @ $discardedMaterialLabel }; @@ -521,6 +752,8 @@ inlineResources[ expr_ ] := expr /. { $styleDataCells = inlineResources @ Cases[ Flatten @ ReadList @ $styleDataFile, _Cell ]; +$workspaceStyleDataCells = inlineResources @ Cases[ Flatten @ ReadList @ $workspaceStyleDataFile, _Cell ]; + (* ::Subsection::Closed:: *) (*$templateBoxDisplayFunctions*) @@ -533,10 +766,6 @@ $templateBoxDisplayFunctions = Association @ Cases[ ]; -Developer`WriteWXFFile[ $displayFunctionsFile, $templateBoxDisplayFunctions ]; - - - (* ::Subsection::Closed:: *) (*Default Settings*) @@ -562,6 +791,49 @@ $ChatbookStylesheet = Notebook[ +(* ::Section::Closed:: *) +(*$WorkspaceStylesheet*) + + +$WorkspaceStylesheet = Notebook[ + Flatten @ { + Cell @ StyleData[ StyleDefinitions -> "Chatbook.nb" ], + $workspaceStyleDataCells + }, + StyleDefinitions -> "PrivateStylesheetFormatting.nb" +]; + + + +(* ::Section::Closed:: *) +(*BuildStylesheets*) + + +BuildStylesheets[ ] := BuildStylesheets @ All; +BuildStylesheets[ All | Automatic ] := BuildStylesheets @ $validStylesheetNames; +BuildStylesheets[ styles: { ___String } ] := AssociationMap[ BuildStylesheets, styles ]; +BuildStylesheets[ "Chatbook" ] := BuildChatbookStylesheet[ ]; +BuildStylesheets[ "WorkspaceChat" ] := BuildWorkspaceStylesheet[ ]; + +BuildStylesheets[ style_String ] := Failure[ + "UnknownStyle", + <| + "MessageTemplate" -> "Unknown style: `1`. Valid styles are `2`.", + "MessageParameters" -> { style, $validStylesheetNames } + |> +]; + +BuildStylesheets[ other___ ] := Failure[ + "InvalidArguments", + <| + "MessageTemplate" -> "Invalid arguments for BuildStylesheets: `1`. Expected a list of style names or All.", + "MessageParameters" -> { { other } } + |> +]; + + +$validStylesheetNames = { "Chatbook", "WorkspaceChat" }; + (* ::Section::Closed:: *) (*BuildChatbookStylesheet*) @@ -582,6 +854,7 @@ BuildChatbookStylesheet[ ] := BuildChatbookStylesheet @ $styleSheetTarget; BuildChatbookStylesheet[ target_ ] := Block[ { $Context = "Global`", $ContextPath = { "System`", "Global`" } }, Module[ { exported }, + Developer`WriteWXFFile[ $displayFunctionsFile, fixContexts @ $templateBoxDisplayFunctions ]; exported = Export[ target, fixContexts @ $ChatbookStylesheet, "NB" ]; PacletInstall[ "Wolfram/PacletCICD" ]; Needs[ "Wolfram`PacletCICD`" -> None ]; @@ -601,6 +874,34 @@ BuildChatbookStylesheet[ target_ ] := ]; +(* ::Section::Closed:: *) +(*BuildWorkspaceStylesheet*) + + +BuildWorkspaceStylesheet[ ] := BuildWorkspaceStylesheet @ $floatStyleSheetTarget; + +BuildWorkspaceStylesheet[ target_ ] := + Block[ { $Context = "Global`", $ContextPath = { "System`", "Global`" } }, + Module[ { exported }, + exported = Export[ target, fixContexts @ $WorkspaceStylesheet, "NB" ]; + PacletInstall[ "Wolfram/PacletCICD" ]; + Needs[ "Wolfram`PacletCICD`" -> None ]; + SetOptions[ + ResourceFunction[ "SaveReadableNotebook" ], + "RealAccuracy" -> 10, + "ExcludedNotebookOptions" -> { + ExpressionUUID, + FrontEndVersion, + WindowMargins, + WindowSize + } + ]; + Wolfram`PacletCICD`FormatNotebooks @ exported; + exported + ] + ]; + + (* ::Section::Closed:: *) (*Package Footer*) diff --git a/FrontEnd/StyleSheets/Chatbook.nb b/FrontEnd/StyleSheets/Chatbook.nb index d3212075..30547ddb 100644 --- a/FrontEnd/StyleSheets/Chatbook.nb +++ b/FrontEnd/StyleSheets/Chatbook.nb @@ -398,7 +398,15 @@ Notebook[ TemplateBox[{}, "ChatInputIcon"], BaselinePosition -> Center -> Scaled[0.55] ], - StyleBox["Chat Input", "CellInsertionMenu"], + StyleBox[ + DynamicBox[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetInsertionMenuChatInput" + ] + ], + "CellInsertionMenu" + ], StyleBox[ StyleBox["'", "CellInsertionMenuShortcut"], "CellInsertionMenuShortcut" @@ -471,7 +479,15 @@ Notebook[ TemplateBox[{}, "SideChatIcon"], BaselinePosition -> Center -> Scaled[0.55] ], - StyleBox["Side Chat", "CellInsertionMenu"], + StyleBox[ + DynamicBox[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetInsertionMenuSideChat" + ] + ], + "CellInsertionMenu" + ], StyleBox[ StyleBox["''", "CellInsertionMenuShortcut"], "CellInsertionMenuShortcut" @@ -1161,7 +1177,7 @@ Notebook[ ], Cell[ StyleData["ChatStyleSheetInformation"], - TaggingRules -> <|"StyleSheetVersion" -> "1.4.2.3915874681"|> + TaggingRules -> <|"StyleSheetVersion" -> "1.4.6.3930718414"|> ], Cell[ StyleData["Text"], @@ -1577,8 +1593,13 @@ Notebook[ CellFrame -> 0, CellMargins -> 0 ], - CellMargins -> {{66, 25}, {1, 8}}, - StyleKeyMapping -> {"~" -> "ChatDelimiter", "'" -> "SideChat"}, + CellMargins -> {{66, 32}, {1, 8}}, + StyleKeyMapping -> { + "~" -> "ChatDelimiter", + "'" -> "SideChat", + "=" -> "WolframAlphaShort", + "*" -> "Item" + }, Evaluatable -> True, CellGroupingRules -> "InputGrouping", TaggingRules -> <|"ChatNotebookSettings" -> <||>|>, @@ -1648,6 +1669,22 @@ Notebook[ ] }, CellFrameColor -> RGBColor[0.639216, 0.788235, 0.94902], + CellFrameLabels -> { + { + None, + Cell[ + BoxData[ + TemplateBox[ + {RGBColor[0.639216, 0.788235, 0.94902], 20}, + "SendChatButton" + ] + ], + Background -> None + ] + }, + {None, None} + }, + CellFrameLabelMargins -> -32, CounterIncrements -> {"ChatInputCount"}, MenuSortingValue -> 1543 ], @@ -1843,10 +1880,28 @@ Notebook[ ImageSize -> Automatic, FrameMargins -> 0 ], - "\"Send feedback to Wolfram\"", - TooltipStyle -> "TextStyling" + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetFeedbackButtonTooltip" + ], + StandardForm + ] + ] ], - Annotation[#1, "Send feedback to Wolfram", "Tooltip"] & + Function[ + Annotation[ + #1, + Dynamic[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetFeedbackButtonTooltip" + ] + ], + "Tooltip" + ] + ] ], MouseAppearanceTag["LinkHand"] ], @@ -1887,10 +1942,28 @@ Notebook[ ImageSize -> Automatic, FrameMargins -> 0 ], - "\"Send feedback to Wolfram\"", - TooltipStyle -> "TextStyling" + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetFeedbackButtonTooltip" + ], + StandardForm + ] + ] ], - Annotation[#1, "Send feedback to Wolfram", "Tooltip"] & + Function[ + Annotation[ + #1, + Dynamic[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetFeedbackButtonTooltip" + ] + ], + "Tooltip" + ] + ] ], MouseAppearanceTag["LinkHand"] ], @@ -2019,10 +2092,28 @@ Notebook[ Evaluator -> Automatic, Method -> "Preemptive" ], - "\"Disable automatic assistance\"", - TooltipStyle -> "TextStyling" + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetAssistantMenuInitializerButtonTooltip" + ], + StandardForm + ] + ] ], - Annotation[#1, "Disable automatic assistance", "Tooltip"] & + Function[ + Annotation[ + #1, + Dynamic[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetAssistantMenuInitializerButtonTooltip" + ] + ], + "Tooltip" + ] + ] ] }, { @@ -2101,10 +2192,28 @@ Notebook[ Evaluator -> Automatic, Method -> "Preemptive" ], - "\"Disable automatic assistance\"", - TooltipStyle -> "TextStyling" + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetAssistantMenuInitializerButtonTooltip" + ], + StandardForm + ] + ] ], - Annotation[#1, "Disable automatic assistance", "Tooltip"] & + Function[ + Annotation[ + #1, + Dynamic[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetAssistantMenuInitializerButtonTooltip" + ] + ], + "Tooltip" + ] + ] ] }, { @@ -2183,10 +2292,28 @@ Notebook[ Evaluator -> Automatic, Method -> "Preemptive" ], - "\"Disable automatic assistance\"", - TooltipStyle -> "TextStyling" + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetAssistantMenuInitializerButtonTooltip" + ], + StandardForm + ] + ] ], - Annotation[#1, "Disable automatic assistance", "Tooltip"] & + Function[ + Annotation[ + #1, + Dynamic[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetAssistantMenuInitializerButtonTooltip" + ] + ], + "Tooltip" + ] + ] ] }, { @@ -2340,13 +2467,13 @@ Notebook[ DisplayFunction -> (Function[ DynamicModuleBox[ - {Wolfram`Chatbook`UI`Private`cell$$}, + {Wolfram`ChatNB`cell$$}, DynamicBox[ ToBoxes[ Catch[ Wolfram`Chatbook`Dynamics`Private`$chatBlockTrigger; Wolfram`Chatbook`UI`MakeChatDelimiterCellDingbat[ - Wolfram`Chatbook`UI`Private`cell$$ + Wolfram`ChatNB`cell$$ ], Blank[] ], @@ -2355,14 +2482,20 @@ Notebook[ TrackedSymbols :> {Wolfram`Chatbook`Dynamics`Private`$chatBlockTrigger} ], Initialization :> - (Wolfram`Chatbook`UI`Private`cell$$ = EvaluationCell[]; + (Wolfram`ChatNB`cell$$ = EvaluationCell[]; Needs["Wolfram`Chatbook`" -> None]; - Wolfram`Chatbook`Dynamics`updateDynamics["ChatBlock"]), + Symbol["Wolfram`Chatbook`ChatbookAction"][ + "UpdateDynamics", + "ChatBlock" + ]), DynamicModuleValues :> { }, Deinitialization :> (Needs["Wolfram`Chatbook`" -> None]; - Wolfram`Chatbook`Dynamics`updateDynamics["ChatBlock"]), - UnsavedVariables :> {Wolfram`Chatbook`UI`Private`cell$$} + Symbol["Wolfram`Chatbook`ChatbookAction"][ + "UpdateDynamics", + "ChatBlock" + ]), + UnsavedVariables :> {Wolfram`ChatNB`cell$$} ] ]) } @@ -2759,7 +2892,15 @@ Notebook[ TemplateBox[ { TemplateBox[{"DivideCellsIcon"}, "ChatMenuItemToolbarIcon"], - "\"Explode Cells (In Place)\"", + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetExplodeCellsInPlace" + ], + StandardForm + ] + ], Hold[ With[ { Wolfram`ChatNB`cell$ = EvaluationCell[] }, {Wolfram`ChatNB`root$ = ParentCell[Wolfram`ChatNB`cell$]}, @@ -2781,7 +2922,15 @@ Notebook[ TemplateBox[ { TemplateBox[{"OverflowIcon"}, "ChatMenuItemToolbarIcon"], - "\"Explode Cells (Duplicate)\"", + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetExplodeCellsDuplicate" + ], + StandardForm + ] + ], Hold[ With[ { Wolfram`ChatNB`cell$ = EvaluationCell[] }, {Wolfram`ChatNB`root$ = ParentCell[Wolfram`ChatNB`cell$]}, @@ -2806,7 +2955,15 @@ Notebook[ {"HyperlinkCopyIcon"}, "ChatMenuItemToolbarIcon" ], - "\"Copy Exploded Cells\"", + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetCopyExplodedCells" + ], + StandardForm + ] + ], Hold[ With[ { Wolfram`ChatNB`cell$ = EvaluationCell[] }, {Wolfram`ChatNB`root$ = ParentCell[Wolfram`ChatNB`cell$]}, @@ -2829,7 +2986,15 @@ Notebook[ TemplateBox[ { TemplateBox[{"TypesettingIcon"}, "ChatMenuItemToolbarIcon"], - "\"Toggle Formatting\"", + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetToggleFormatting" + ], + StandardForm + ] + ], Hold[ With[ { Wolfram`ChatNB`cell$ = EvaluationCell[] }, {Wolfram`ChatNB`root$ = ParentCell[Wolfram`ChatNB`cell$]}, @@ -2851,7 +3016,15 @@ Notebook[ TemplateBox[ { TemplateBox[{"InPlaceIcon"}, "ChatMenuItemToolbarIcon"], - "\"Copy ChatObject\"", + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetCopyChatObject" + ], + StandardForm + ] + ], Hold[ With[ { Wolfram`ChatNB`cell$ = EvaluationCell[] }, {Wolfram`ChatNB`root$ = ParentCell[Wolfram`ChatNB`cell$]}, @@ -4457,6 +4630,368 @@ Notebook[ ]) } ], + Cell[ + StyleData["ChatEvaluatingSpinner"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + DynamicBox[ + If[ TrueQ[$CloudEvaluation], + GraphicsBox[ + {Thickness[0.05], GrayLevel[0.9], CircleBox[{0, 0}, 1]}, + PlotRange -> 1.1, + ImageSize -> #1 + ], + DynamicModuleBox[ + {Wolfram`ChatNB`i}, + OverlayBox[ + { + PaneBox[ + AnimatorBox[ + Dynamic[Wolfram`ChatNB`i], + {1, 30, 1}, + AutoAction -> False, + AnimationRate -> Automatic, + DisplayAllSteps -> True, + DefaultDuration -> 2, + AppearanceElements -> None + ], + ImageSize -> {0, 0} + ], + GraphicsBox[ + { + Thickness[0.05], + GrayLevel[0.9], + CircleBox[{0, 0}, 1, {0.0, 6.2832}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + PaneSelectorBox[ + { + 1 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {4.5332, 4.9332}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 2 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {4.5151, 4.9332}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 3 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {4.4611, 4.9332}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 4 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {4.3713, 4.9332}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 5 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {4.2463, 4.9332}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 6 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {4.0869, 4.9332}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 7 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {3.894, 4.9332}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 8 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {3.6686, 4.9332}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 9 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {3.412, 4.9332}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 10 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {3.1258, 4.924}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 11 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {2.8116, 4.8802}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 12 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {2.4711, 4.8006}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 13 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {2.1064, 4.6856}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 14 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {1.7195, 4.5359}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 15 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {1.3127, 4.3525}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 16 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {0.88824, 4.1362}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 17 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {0.44865, 3.8884}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 18 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-0.0035846, 3.6105}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 19 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-0.46585, 3.3041}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 20 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-0.9355, 2.9709}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 21 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-1.4098, 2.6129}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 22 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-1.75, 2.2322}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 23 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-1.75, 1.8308}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 24 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-1.75, 1.4112}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 25 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-1.75, 0.97565}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 26 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-1.75, 0.52676}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 27 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-1.75, 0.067093}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 28 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-1.75, -0.40072}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 29 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-1.75, -0.87399}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ], + 30 -> + GraphicsBox[ + { + Thickness[0.06], + GrayLevel[0.7], + CircleBox[{0, 0}, 1, {-1.75, -1.35}] + }, + PlotRange -> 1.1, + ImageSize -> #1 + ] + }, + Dynamic[Wolfram`ChatNB`i], + ContentPadding -> False, + FrameMargins -> 0, + ImageSize -> All, + Alignment -> Automatic, + BaseStyle -> None, + TransitionDirection -> Horizontal, + TransitionDuration -> 0.5, + TransitionEffect -> Automatic + ] + }, + ContentPadding -> False, + FrameMargins -> 0 + ], + DynamicModuleValues :> { } + ] + ], + SingleEvaluation -> True + ] + ]) + } + ], Cell[ StyleData["ChatExcludedWidget"], TemplateBoxOptions -> { @@ -7034,35 +7569,126 @@ Notebook[ } ], Cell[ - StyleData["HelperIcon"], + StyleData["DiscardedMaterial"], TemplateBoxOptions -> { DisplayFunction -> (Function[ GraphicsBox[ { - Thickness[0.05], - { - FaceForm[{RGBColor[0.0, 0.52157, 0.8549], Opacity[1.0]}], - FilledCurveBox[ + Thickness[0.066667], + FaceForm[ + {RGBColor[0.53725, 0.53725, 0.53725], Opacity[1.0]} + ], + FilledCurveBox[ + { { - { - {0, 2, 0}, - {1, 3, 3}, - {0, 1, 0}, - {1, 3, 3}, - {0, 1, 0}, - {1, 3, 3}, - {0, 1, 0}, - {1, 3, 3}, - {0, 1, 0}, - {0, 1, 0}, - {0, 1, 0} - } + {1, 4, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0} }, - CompressedData[ - "\n1:eJxTTMoPSmVmYGBgBGIRIGYC4icisief/hdzYAADcYfjmlaTTv/nh/Mr5ixS\n3lnDhSbP6hBhueVEmZ0knA+Rl0HjG8D5qz5e8k3aYIBqnoMhqn1APkwfjA/T\nhyKPSxxJ39MLSrd//pOG82HuRdEH9A+KPiD/IlBbnZYKnI8aPiwO6OEFAIL+\nVdY=\n " - ] - ] + { + {0, 2, 0}, + {1, 3, 3}, + {0, 1, 0}, + {0, 1, 0}, + {1, 3, 3}, + {1, 3, 3}, + {1, 3, 3}, + {0, 1, 0}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3} + }, + { + {0, 2, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0} + } + }, + { + CompressedData[ + "\n1:eJxTTMoPSmViYGCQAmIQDQFaDmCqQdMBxtfdNPf98mOacBqXOgjNBOf7mHc6\nJjxlQJNnQDOHAc0cmHpROH/Z7CMKG4pE0MwTQbNPxGGNTFSK9X1BOD/h6QWl\n2z+F0OSFHbacKNs3X0oYzofIC8H5+ndV2BqnsjoAOf6902Uc3gTukGvNFnbQ\nbhe7ee67jMOMPKHmA6eEHdy2ff57pUIWzT1yqHy4v0TQ/A1TrwX3H2o4iaLy\ngeYAADp3VlE=\n " + ], + CompressedData[ + "\n1:eJxTTMoPSmViYGCQBWIQDQE6DmCqQdMBhc8gCudHWG45UWYn5BDyeOnsIw+0\noOICaPoEHHKf/1758ZIcnK+7ae775W7CDkE75FpfB36y9zHvdEx4KuRw9gwI\nfLAXv3nue3CyEFT9B/s1MlEp1vcF4fyXaoYca+Yg+DxM2u1ikYIOGRPf1tib\nfrCfNRMIJAUdzn8PBrrsg71TwtMLStECDmD69kd7sLv38Tv8AEkf+QLnQ8z7\ngcaH+oeBCc4HG/Pzhz2q/Ad7WHjA+KjhBeXDw+WDPSzcUM2DhTPMPsx4QA1v\nHfziQH0Arfp+zg==\n " + ], + { + {10.316, 11.109}, + {8.207, 9.0}, + {10.316, 6.891}, + {9.609, 6.184}, + {7.5, 8.293}, + {5.391, 6.184}, + {4.684, 6.891}, + {6.793, 9.0}, + {4.684, 11.109}, + {5.391, 11.816}, + {7.5, 9.707}, + {9.609, 11.816}, + {10.316, 11.109} + } + } + ] + }, + AspectRatio -> Automatic, + ImageSize -> {16.0, 16.0}, + PlotRange -> {{-0.5, 15.5}, {-0.5, 15.5}} + ] + ]) + } + ], + Cell[ + StyleData["HelperIcon"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + GraphicsBox[ + { + Thickness[0.05], + { + FaceForm[{RGBColor[0.0, 0.52157, 0.8549], Opacity[1.0]}], + FilledCurveBox[ + { + { + {0, 2, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0} + } + }, + CompressedData[ + "\n1:eJxTTMoPSmVmYGBgBGIRIGYC4icisief/hdzYAADcYfjmlaTTv/nh/Mr5ixS\n3lnDhSbP6hBhueVEmZ0knA+Rl0HjG8D5qz5e8k3aYIBqnoMhqn1APkwfjA/T\nhyKPSxxJ39MLSrd//pOG82HuRdEH9A+KPiD/IlBbnZYKnI8aPiwO6OEFAIL+\nVdY=\n " + ] + ] }, { Thickness[0.05], @@ -11687,6 +12313,129 @@ Notebook[ ]) } ], + Cell[ + StyleData["SendChatButtonLabel"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + GraphicsBox[ + { + Thickness[0.055556], + FaceForm[#1], + FilledCurveBox[ + { + { + {0, 2, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3}, + {0, 1, 0}, + {1, 3, 3} + } + }, + CompressedData[ + "\n1:eJxTTMoPSmVmYGBgBGIZIGYC4i9/r1S8ZDNwKM6Y+Lbmv67DvcntrVGX/9lL\n699VYWPUdXiwj2+O8aIP9t05z3+v/Kjj8Dsm9+i/TY/tN819v/zYaS0HweO7\ndvSyfbHfUzJZgmWapsOWyK87b3UJOjwRkT35dL6yQ+2FzUARIQcrZa/qZn5l\nh1VNgZ5zG0Qcpm3iKVzzWsnh/gPuySuZxBz2PgZqcFV2WPsLaIGdksPNc9+D\nHy9Vc7CadLreY7+SQ75Q84FTD9Ucdv5p/3I7XNmh8qWaIccaNQcTQTObvZOU\nHYC2h/HpqjnY7A2apnhO2WGd+8MqkXWqDt/Z4mf4TFV2uL64wJZLXNUhM/9D\n60kRZQenhKcXlG6rOEScMjqycZ24w4y7QI9XKToo5VRULdURc/jn/OvtawVF\nB6Y9rEIi9qIOlRErTM9GKzhsa6kB+kjUoWXe2VXnReUdNjA/79HIFXOQmHqF\nM2MRt4Pv577gkiViDo/NpA5EL2Bx0M9bzLiHVdrhUNvy8FObGB1AofM3VdaB\nKwNo0y82B1W2xqnOpw0cQMFvv1UL4s9EQwdg6DdOZdZx8AB547mBQ/+hrxox\n/HoO6PEFAPo2ybM=\n " + ] + ] + }, + AspectRatio -> Automatic, + ImageSize -> #2, + PlotRange -> {{-0.5, 18.5}, {-0.5, 18.5}} + ] + ]) + } + ], + Cell[ + StyleData["SendChatButton"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + DynamicModuleBox[ + {Wolfram`ChatNB`cell$$}, + PaneSelectorBox[ + { + False -> + ButtonBox[ + TemplateBox[{#1, #2}, "SendChatButtonLabel"], + ButtonFunction :> + ( + Wolfram`Chatbook`$ChatEvaluationCell = + Wolfram`ChatNB`cell$$; + + SelectionMove[Wolfram`ChatNB`cell$$, All, Cell]; + FrontEndTokenExecute[ + Notebooks[Wolfram`ChatNB`cell$$], + "EvaluateCells" + ]), + FrameMargins -> 0, + Method -> "Queued", + Appearance -> Automatic, + Evaluator -> Automatic + ], + True -> + ButtonBox[ + OverlayBox[ + { + TemplateBox[{#2}, "ChatEvaluatingSpinner"], + GraphicsBox[ + { + RGBColor[0.71373, 0.054902, 0.0], + RectangleBox[{-0.5, -0.5}, {0.5, 0.5}] + }, + ImageSize -> #2, + PlotRange -> 1.1 + ] + }, + Alignment -> {Center, Center} + ], + ButtonFunction :> + If[ UnsameQ[ + Wolfram`Chatbook`$ChatEvaluationCell, + Wolfram`ChatNB`cell$$ + ], + NotebookWrite[ + Wolfram`ChatNB`cell$$, + NotebookRead[Wolfram`ChatNB`cell$$], + None, + AutoScroll -> False + ], + Needs["Wolfram`Chatbook`" -> None]; + Symbol["Wolfram`Chatbook`ChatbookAction"]["StopChat"] + ], + FrameMargins -> 0, + Appearance -> Automatic, + Evaluator -> Automatic, + Method -> "Preemptive" + ] + }, + Dynamic[ + SameQ[ + Wolfram`Chatbook`$ChatEvaluationCell, + Wolfram`ChatNB`cell$$ + ] + ], + Alignment -> {Automatic, Baseline} + ], + Initialization :> + (Wolfram`ChatNB`cell$$ = + If[ $CloudEvaluation, + Wolfram`ChatNB`x; + EvaluationCell[], + ParentCell[EvaluationCell[]] + ]), + DynamicModuleValues :> { }, + UnsavedVariables :> {Wolfram`ChatNB`cell$$} + ] + ]) + } + ], Cell[ StyleData["ServiceIconAnthropic"], TemplateBoxOptions -> { @@ -17368,6 +18117,102 @@ Notebook[ ]) } ], + Cell[ + StyleData[ + "MessageAuthorLabel", + StyleDefinitions -> StyleData["Text"] + ], + ShowStringCharacters -> False, + FontSize -> 14, + FontWeight -> "DemiBold" + ], + Cell[ + StyleData["UserMessageLabel"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + PaneBox[ + #1, + BaseStyle -> {"MessageAuthorLabel"}, + ImageSize -> {Scaled[1], Automatic}, + Alignment -> Right, + FrameMargins -> {{0, 11}, {0, 0}} + ] + ]) + } + ], + Cell[ + StyleData["AssistantMessageLabel"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + PaneBox[ + #1, + BaseStyle -> {"MessageAuthorLabel"}, + ImageSize -> {Scaled[1], Automatic}, + Alignment -> Left, + FrameMargins -> {{11, 0}, {0, 0}} + ] + ]) + } + ], + Cell[ + StyleData["UserMessageBox"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + FrameBox[ + Cell[#1, "Text", Background -> None], + Background -> RGBColor[0.929412, 0.956863, 0.988235], + FrameMargins -> 8, + FrameStyle -> RGBColor[0.639216, 0.788235, 0.94902], + RoundingRadius -> 10, + StripOnInput -> False + ] + ]) + } + ], + Cell[ + StyleData["AssistantMessageBox"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + FrameBox[ + #1, + BaseStyle -> "Text", + Background -> RGBColor[0.988235, 0.992157, 1.0], + FrameMargins -> 8, + FrameStyle -> RGBColor[0.788235, 0.8, 0.815686], + ImageSize -> {Scaled[1], Automatic}, + RoundingRadius -> 10, + StripOnInput -> False + ] + ]) + } + ], + Cell[ + StyleData["DropShadowPaneBox"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + PanelBox[ + #1, + Appearance -> + Image[ + CompressedData[ + "\n1:eJy9lU1LAlEUhqdxdIYYQ5gkwQFNXLiQlkMhLqJVIQhGCK7UUmljoEG0m7/p\n3/AP2HvlvXK6STnFNPB4mcM5z5x7nI/z8UtvaluWtfTw0xu9XS8Wo/f7Ak4e\n5svn2XzydDt/ncwmi8txBsEz4oBNgiNh+vaI49gSHBGbZICzh4zI0TU7zx63\n9KraLMgBF3gCl/GsuMYnv+GWToe1ynMMfJAX+Ix7zHOMa0i3vqb2uqxVngII\nQFEQMJ5nniv8W5fhtg3vCR0lEIIKqHINGQ+YJ/224dazyAnvKSiDGmiAJrjg\n2mC8zDztz+nZGO4s55dnP6quTl8EWqDNNWK8zryAdR490i17LnC/NdZfgZvV\narXRqHPGL5hXYt2ud/08iDn77CHkviN6usq5Xq+1u8t4xLyQdb6eu37O6Nbz\nKPL/anL/d6Bv9N1nvMW8Cuv0XBwxE9Nd5X7VfDtgAB7BlOuA8TbzqgncX/oG\nQ3qHv+j723nTN+D647yT3Cfss8P1oPvkH+7vNJ/LNN8nab4HrTi997cVp/vd\n2ef/8/fy0CPpd/4Dbscq/g==\n " + ], + "Byte", + ColorSpace -> "RGB", + ImageResolution -> 72, + Interleaving -> True + ], + ContentPadding -> False, + FrameMargins -> {{0, 0}, {0, 0}} + ] + ]) + } + ], Cell[ StyleData["ChatbookPersona"], TemplateBoxOptions -> { @@ -17529,10 +18374,28 @@ Notebook[ TagBox[ TooltipBox[ TemplateBox[{}, "ChatWidgetIcon"], - "\"Send to LLM\"", - TooltipStyle -> "TextStyling" + DynamicBox[ + ToBoxes[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetChatWidgetButtonTooltip" + ], + StandardForm + ] + ] ], - Annotation[#1, "Send to LLM", "Tooltip"] & + Function[ + Annotation[ + #1, + Dynamic[ + FEPrivate`FrontEndResource[ + "ChatbookStrings", + "StylesheetChatWidgetButtonTooltip" + ] + ], + "Tooltip" + ] + ] ], MouseAppearanceTag["LinkHand"] ], @@ -17574,6 +18437,296 @@ Notebook[ ] ]) } + ], + Cell[ + StyleData["DiscardedMaterialOpener"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + DynamicModuleBox[ + {Typeset`hover$$ = False, Typeset`open$$ = False}, + PaneSelectorBox[ + { + False -> + TagBox[ + GridBox[ + { + { + TagBox[ + TagBox[ + FrameBox[ + TagBox[ + GridBox[ + { + { + TemplateBox[{}, "DiscardedMaterial"], + "\"Discarded material\"", + PaneSelectorBox[ + { + {True, False} -> + TemplateBox[ + {RGBColor[0.3451, 0.72157, 0.98039]}, + "DiscardedMaterialOpenerIcon" + ], + {False, False} -> + TemplateBox[ + {GrayLevel[0.7451]}, + "DiscardedMaterialOpenerIcon" + ], + {True, True} -> + TemplateBox[ + {RGBColor[0.3451, 0.72157, 0.98039]}, + "DiscardedMaterialCloserIcon" + ], + {False, True} -> + TemplateBox[ + {GrayLevel[0.7451]}, + "DiscardedMaterialCloserIcon" + ] + }, + Dynamic[{Typeset`hover$$, Typeset`open$$}] + ] + } + }, + GridBoxAlignment -> {"Columns" -> {{Automatic}}, "Rows" -> {{Baseline}}}, + AutoDelete -> False, + GridBoxItemSize -> {"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}} + ], + "Grid" + ], + Background -> + Dynamic[ + FEPrivate`If[ + Typeset`hover$$, + GrayLevel[1], + RGBColor[0.94902, 0.96863, 0.98824] + ] + ], + BaseStyle -> { + "Text", + "IconizedDefaultName", + ShowStringCharacters -> False + }, + FrameMargins -> 2, + FrameStyle -> RGBColor[0.9098, 0.93333, 0.95294], + RoundingRadius -> 5, + StripOnInput -> False + ], + EventHandlerTag[ + { + "MouseEntered" :> FEPrivate`Set[Typeset`hover$$, True], + "MouseExited" :> FEPrivate`Set[Typeset`hover$$, False], + "MouseClicked" :> + FEPrivate`Set[ + Typeset`open$$, + FEPrivate`If[Typeset`open$$, False, True] + ], + PassEventsDown -> True, + Method -> "Preemptive", + PassEventsUp -> True + } + ] + ], + MouseAppearanceTag["LinkHand"] + ] + } + }, + DefaultBaseStyle -> "Column", + GridBoxAlignment -> {"Columns" -> {{Left}}}, + GridBoxItemSize -> {"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}}, + GridBoxSpacings -> {"Columns" -> {{Automatic}}, "Rows" -> {{0.25}}} + ], + "Column" + ], + True -> + TagBox[ + GridBox[ + { + { + TagBox[ + TagBox[ + FrameBox[ + TagBox[ + GridBox[ + { + { + TemplateBox[{}, "DiscardedMaterial"], + "\"Discarded material\"", + PaneSelectorBox[ + { + {True, False} -> + TemplateBox[ + {RGBColor[0.3451, 0.72157, 0.98039]}, + "DiscardedMaterialOpenerIcon" + ], + {False, False} -> + TemplateBox[ + {GrayLevel[0.7451]}, + "DiscardedMaterialOpenerIcon" + ], + {True, True} -> + TemplateBox[ + {RGBColor[0.3451, 0.72157, 0.98039]}, + "DiscardedMaterialCloserIcon" + ], + {False, True} -> + TemplateBox[ + {GrayLevel[0.7451]}, + "DiscardedMaterialCloserIcon" + ] + }, + Dynamic[{Typeset`hover$$, Typeset`open$$}] + ] + } + }, + GridBoxAlignment -> {"Columns" -> {{Automatic}}, "Rows" -> {{Baseline}}}, + AutoDelete -> False, + GridBoxItemSize -> {"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}} + ], + "Grid" + ], + Background -> + Dynamic[ + FEPrivate`If[ + Typeset`hover$$, + GrayLevel[1], + RGBColor[0.94902, 0.96863, 0.98824] + ] + ], + BaseStyle -> { + "Text", + "IconizedDefaultName", + ShowStringCharacters -> False + }, + FrameMargins -> 2, + FrameStyle -> RGBColor[0.9098, 0.93333, 0.95294], + RoundingRadius -> 5, + StripOnInput -> False + ], + EventHandlerTag[ + { + "MouseEntered" :> FEPrivate`Set[Typeset`hover$$, True], + "MouseExited" :> FEPrivate`Set[Typeset`hover$$, False], + "MouseClicked" :> + FEPrivate`Set[ + Typeset`open$$, + FEPrivate`If[Typeset`open$$, False, True] + ], + PassEventsDown -> True, + Method -> "Preemptive", + PassEventsUp -> True + } + ] + ], + MouseAppearanceTag["LinkHand"] + ] + }, + { + FrameBox[ + #1, + Background -> RGBColor[0.94902, 0.96863, 0.98824], + FrameMargins -> 10, + FrameStyle -> RGBColor[0.9098, 0.93333, 0.95294], + ImageSize -> {Full, Automatic}, + RoundingRadius -> 5, + StripOnInput -> False + ] + } + }, + DefaultBaseStyle -> "Column", + GridBoxAlignment -> {"Columns" -> {{Left}}}, + GridBoxItemSize -> {"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}}, + GridBoxSpacings -> {"Columns" -> {{Automatic}}, "Rows" -> {{0.25}}} + ], + "Column" + ] + }, + Dynamic[Typeset`open$$], + ImageMargins -> 10, + ImageSize -> Automatic, + Alignment -> Left, + ContentPadding -> False + ], + DynamicModuleValues :> { }, + UnsavedVariables :> {Typeset`hover$$} + ] + ]) + } + ], + Cell[ + StyleData["DiscardedMaterialOpenerIcon"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + GraphicsBox[ + { + #1, + Thickness[0.090909], + Opacity[1.0], + FilledCurveBox[ + { + { + {0, 2, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0} + } + }, + { + { + {8.5, 4.5}, + {6.5, 4.5}, + {6.5, 2.5}, + {4.5, 2.5}, + {4.5, 4.5}, + {2.5, 4.5}, + {2.5, 6.5}, + {4.5, 6.5}, + {4.5, 8.5}, + {6.5, 8.5}, + {6.5, 6.5}, + {8.5, 6.5} + } + } + ] + }, + AspectRatio -> Automatic, + BaselinePosition -> Center -> Center, + ImageSize -> {11.0, 11.0}, + PlotRange -> {{0.0, 11.0}, {0.0, 11.0}} + ] + ]) + } + ], + Cell[ + StyleData["DiscardedMaterialCloserIcon"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + GraphicsBox[ + { + #1, + Thickness[0.090909], + Opacity[1.0], + FilledCurveBox[ + {{{0, 2, 0}, {0, 1, 0}, {0, 1, 0}}}, + {{{8.5, 4.5}, {2.5, 4.5}, {2.5, 6.5}, {8.5, 6.5}}} + ] + }, + AspectRatio -> Automatic, + BaselinePosition -> Center -> Center, + ImageSize -> {11.0, 11.0}, + PlotRange -> {{0.0, 11.0}, {0.0, 11.0}} + ] + ]) + } ] }, StyleDefinitions -> "PrivateStylesheetFormatting.nb" diff --git a/FrontEnd/StyleSheets/Wolfram/WorkspaceChat.nb b/FrontEnd/StyleSheets/Wolfram/WorkspaceChat.nb new file mode 100644 index 00000000..beeeaebc --- /dev/null +++ b/FrontEnd/StyleSheets/Wolfram/WorkspaceChat.nb @@ -0,0 +1,208 @@ +(* Content-type: application/vnd.wolfram.mathematica *) + +(*** Wolfram Notebook File ***) +(* http://www.wolfram.com/nb *) + +(* Created By: SaveReadableNotebook *) +(* https://resources.wolframcloud.com/FunctionRepository/resources/SaveReadableNotebook *) + +Notebook[ + { + Cell[StyleData[StyleDefinitions -> "Chatbook.nb"]], + Cell[ + StyleData["Notebook"], + ClosingSaveDialog -> False, + Saveable -> False, + WindowToolbars -> { }, + CellInsertionPointCell -> None, + Selectable -> False, + WindowSize -> {350, Automatic}, + WindowMargins -> {{0, Automatic}, {0, 0}}, + WindowFrame -> "ModelessDialog", + WindowElements -> {"VerticalScrollBar"}, + WindowFrameElements -> {"CloseBox", "ResizeArea"}, + WindowClickSelect -> True, + WindowTitle -> "Code Assistance Chat", + DockedCells -> { + Cell[ + BoxData[ + DynamicBox[ + ToBoxes[ + Needs["Wolfram`Chatbook`" -> None]; + Symbol["Wolfram`Chatbook`ChatbookAction"][ + "MakeWorkspaceChatDockedCell" + ], + StandardForm + ], + Initialization :> + With[ { Wolfram`ChatNB`nbo = EvaluationNotebook[] }, + Needs["Wolfram`Chatbook`" -> None]; + Symbol["Wolfram`Chatbook`ChatbookAction"][ + "AttachWorkspaceChatInput", + Wolfram`ChatNB`nbo + ] + ] + ] + ] + ] + }, + ShowCellBracket -> False, + TaggingRules -> <| + "ChatNotebookSettings" -> <| + "SetCellDingbat" -> False, + "TabbedOutput" -> False, + "WorkspaceChat" -> True + |> + |>, + DefaultNewCellStyle -> "AutoMoveToChatInputField", + Magnification -> 0.85, + Background -> GrayLevel[1] + ], + Cell[ + StyleData["WorkspaceChatStyleSheetInformation"], + TaggingRules -> <|"WorkspaceChatStyleSheetVersion" -> "1.4.6.3930718414"|> + ], + Cell[ + StyleData["ChatInput"], + Selectable -> True, + CellFrame -> 0, + CellDingbat -> None, + ShowCellBracket -> False, + CellMargins -> {{15, 10}, {5, 10}}, + CellFrameLabels -> { + {None, None}, + { + None, + Cell[ + BoxData[ + TemplateBox[ + { + DynamicBox[ + ToBoxes[ + Needs["Wolfram`Chatbook`" -> None]; + Symbol["Wolfram`Chatbook`ChatbookAction"][ + "UserMessageLabel" + ], + StandardForm + ], + SingleEvaluation -> True + ] + }, + "UserMessageLabel" + ] + ] + ] + } + }, + CellFrameLabelMargins -> 6, + TextAlignment -> Right + ], + Cell[ + StyleData["ChatOutput"], + Selectable -> True, + CellFrame -> 0, + CellDingbat -> None, + ShowCellBracket -> False, + CellMargins -> {{10, 15}, {15, 12}}, + Initialization :> None, + CellFrameLabels -> { + {None, None}, + { + None, + Cell[ + BoxData[ + TemplateBox[ + { + DynamicBox[ + ToBoxes[ + Needs["Wolfram`Chatbook`" -> None]; + Symbol["Wolfram`Chatbook`ChatbookAction"][ + "AssistantMessageLabel" + ], + StandardForm + ], + SingleEvaluation -> True + ] + }, + "AssistantMessageLabel" + ] + ] + ] + } + }, + Background -> None + ], + Cell[ + StyleData["ChatInputField"], + CellFrame -> 1, + CellFrameMargins -> {{5, 5}, {0, 0}}, + CellFrameColor -> GrayLevel[0.85] + ], + Cell[ + StyleData["AutoMoveToChatInputField"], + Initialization :> + (NotebookDelete[EvaluationCell[]]; + Needs["Wolfram`Chatbook`" -> None]; + Symbol["Wolfram`Chatbook`ChatbookAction"][ + "MoveToChatInputField", + EvaluationNotebook[], + True + ];) + ], + Cell[ + StyleData["WorkspaceSendChatButton"], + TemplateBoxOptions -> { + DisplayFunction -> + (Function[ + PaneSelectorBox[ + { + None -> + ButtonBox[ + TemplateBox[{#1, #2}, "SendChatButtonLabel"], + ButtonFunction :> + (Needs["Wolfram`Chatbook`" -> None]; + Symbol["Wolfram`Chatbook`ChatbookAction"][ + "EvaluateWorkspaceChat", + #3, + Dynamic[ + CurrentValue[#3, {TaggingRules, "ChatInputString"}] + ] + ]), + FrameMargins -> 0, + Method -> "Queued", + Appearance -> Automatic, + Evaluator -> Automatic + ] + }, + Dynamic[Wolfram`Chatbook`$ChatEvaluationCell], + ButtonBox[ + OverlayBox[ + { + TemplateBox[{#2}, "ChatEvaluatingSpinner"], + GraphicsBox[ + { + RGBColor[0.71373, 0.054902, 0.0], + RectangleBox[{-0.5, -0.5}, {0.5, 0.5}] + }, + ImageSize -> #2, + PlotRange -> 1.1 + ] + }, + Alignment -> {Center, Center} + ], + ButtonFunction :> + (Needs["Wolfram`Chatbook`" -> None]; + Symbol["Wolfram`Chatbook`ChatbookAction"]["StopChat"]), + FrameMargins -> 0, + Appearance -> Automatic, + Evaluator -> Automatic, + Method -> "Preemptive" + ], + Alignment -> {Automatic, Baseline} + ] + ]) + } + ] + }, + StyleDefinitions -> "PrivateStylesheetFormatting.nb" +] \ No newline at end of file diff --git a/FrontEnd/TextResources/ChatbookStrings.tr b/FrontEnd/TextResources/ChatbookStrings.tr new file mode 100644 index 00000000..caae4a34 --- /dev/null +++ b/FrontEnd/TextResources/ChatbookStrings.tr @@ -0,0 +1,180 @@ +@@resource ChatbookStrings +{ +"ConnectButton" -> "Connect", +"DisconnectButton" -> "Disconnect", +"OKButton" -> "OK", +"CancelButton" -> "Cancel", +"DeleteButton" -> "Delete", +"SendButton" -> "Send", +"URLButton" -> "URL", +"ScopeGlobal" -> "Global", +"ScopeNotebook" -> "Selected Notebook", +"ScopeCells" -> "Selected Cells", +"EnabledByModel" -> "Automatic by model", +"EnabledByPersona" -> "Automatic by persona", +"EnabledAlways" -> "Always enabled", +"EnabledNever" -> "Always disabled", +"EnabledNever2" -> "Never enabled", +"Always" -> "Always", +"Never" -> "Never", +"Automatic" -> "Automatic", +"Custom" -> "Custom", +"Rare" -> "Rare", +"Often" -> "Often", + +"ActionsAPIKeyDialogTitle" -> "Please enter your OpenAI API key", +"ActionsAPIKeyDialogAPIKey" -> "API Key", +"ActionsAPIKeyDialogSave" -> "Save", +"APIKeyDialogCreateKeyTemplate" -> "If you do not yet have an API key, you can create one `1`.", +"APIKeyDialogSaveKeyTemplate" -> "To avoid seeing this dialog in the future, choose \"Save\" to store the key in `1`.", + +"ChatContextDialogSystemPromptText" -> "System Prompt Text", +"ChatContextDialogCellProcessingFunction" -> "Cell Processing Function", +"ChatContextDialogCellPostEvaluationFunction" -> "Cell Post Evaluation Function", +"ChatContextDialogDescription" -> "This is the text that tells you what to do.", +"ChatContextDialogClickForMoreInfo" -> "Click for more information", + +"ChatToolbarInsertChatCell" -> "Insert Chat Cell", +"ChatToolbarChatSettings" -> "Chat Settings", +"ChatToolbarChatDrivenLabel" -> "Chat-Driven Notebook", +"ChatToolbarChatEnabledLabel" -> "Chat-Enabled Notebook", + +"DefaultToolsLinks" -> "Links", + +"FeedbackChatMessagesContent" -> "Chat messages", +"FeedbackChatMessagesTooltip" -> "Chat messages involved in creating this chat output.", +"FeedbackSystemMessageContent" -> "System message", +"FeedbackSystemMessageTooltip" -> "The underlying system message used for giving instructions to the AI.", +"FeedbackChatHistoryContent" -> "Chat history used to generate this output", +"FeedbackChatHistoryTooltip" -> "Additional messages that were used as conversation history to generate this output.", +"FeedbackChatImageContent" -> "Image of chat output", +"FeedbackChatImageTooltip" -> "A screenshot of the chat output, which can be used if feedback is related to the output's appearance.", +"FeedbackDialogHeader" -> "Send Wolfram AI Chat Feedback", +"FeedbackDialogBodyThumbs" -> "Sending feedback helps us improve our AI features.", +"FeedbackDialogContentIncludedLabel" -> "Included content:", +"FeedbackDialogContentOutputImageLabel" -> "Output image", +"FeedbackDialogCommentFieldHint" -> "Do you have additional feedback? (Optional)", +"FeedbackDialogBodyUsedForTraining" -> "Your chat history and feedback may be used for training purposes.", +"FeedbackDialogBodyPreviewData" -> "Preview data to be sent", +"FeedbackDialogThanks" -> "Thanks for your feedback!", + +"FormattingInsertContentAndEvaluateTooltip" -> "Insert content as new input cell below and evaluate", +"FormattingCopyToClipboardTooltip" -> "Copy to clipboard", +"FormattingInsertContentTooltip" -> "Insert content as new input cell below", + +"InlineReferencesFieldHint" -> "PromptName", +"InlineReferencesInsertLabel" -> "Insert:", +"InlineReferencesInsertPersonaPrompt" -> "Enter a persona name", +"InlineReferencesInsertPersonaFail" -> "No persona with name \"`name`\" found.", +"InlineReferencesInsertModifierPrompt" -> "Enter a modifier prompt", +"InlineReferencesInsertModifierFail" -> "No modifier with name \"`name`\" found.", +"InlineReferencesInsertFunctionPrompt" -> "Enter a function prompt", +"InlineReferencesInsertFunctionFail" -> "No function with name \"`name`\" found.", + +"PersonaManagerTitle" -> "Add & Manage Personas", +"PersonaManagerInstallPersonas" -> "Install Personas", +"PersonaManagerInstallFrom" -> "Install from", +"PersonaManagerInstallFromPromptRepo" -> "Prompt Repository \[UpperRightArrow]", +"PersonaManagerManagePersonas" -> "Manage and Enable Personas", +"PersonaManagerInMenu" -> "In Menu", +"PersonaManagerName" -> "Name", +"PersonaManagerVersion" -> "Version", +"PersonaManagerOriginChatbookTooltip" -> "Persona installed from the Wolfram/Chatbook paclet. Visit page \[RightGuillemet]", +"PersonaManagerOriginRepositoryTooltip" -> "Persona installed from the `name` paclet. Visit page \[RightGuillemet].", +"PersonaManagerPersonaUninstallTooltip" -> "This persona cannot be uninstalled because it is provided by the `1` paclet.", + +"PreferencesContentNotebooksTab" -> "Notebooks", +"PreferencesContentPersonasTab" -> "Personas", +"PreferencesContentServicesTab" -> "Services", +"PreferencesContentToolsTab" -> "Tools", +"PreferencesContentEnableAssistanceLabel" -> "Enable automatic assistance", +"PreferencesContentEnableAssistanceTooltip" -> "If enabled, automatic AI provided suggestions will be added following evaluation results.", +"PreferencesContentPersonaLabel" -> "Persona:", +"PreferencesContentLLMServiceLabel" -> "LLM Service:", +"PreferencesContentModelLabel" -> "Model:", +"PreferencesContentTemperatureLabel" -> "Temperature:", +"PreferencesContentSubsectionChat" -> "Chat Notebook Cells", +"PreferencesContentFormatOutputLabel" -> "Format chat output", +"PreferencesContentIncludeHistoryLabel" -> "Include chat history", +"PreferencesContentIncludeHistoryTooltip" -> "If enabled, cells preceding the chat input will be included as additional context for the LLM.", +"PreferencesContentHistoryLengthLabel" -> "Chat history length:", +"PreferencesContentHistoryLengthTooltip" -> "Maximum number of cells to include in chat history", +"PreferencesContentMergeChatLabel" -> "Merge chat messages", +"PreferencesContentMergeChatTooltip" -> "If enabled, adjacent cells with the same author will be merged into a single chat message.", +"PreferencesContentSubsectionFeatures" -> "Features", +"PreferencesContentEnableMultimodalLabel" -> "Enable multimodal content: ", +"PreferencesContentEnableTools" -> "Enable tools: ", +"PreferencesContentToolCallFrequency" -> "Tool call frequency:", +"PreferencesContentSubsectionRegisteredServices" -> "Registered Services", +"PreferencesContentService" -> "Service", +"PreferencesContentServiceConnectButton" -> "Connect for model list", +"PreferencesContentAuthentication" -> "Authentication", +"PreferencesContentUnregisterTooltip" -> "Unregister service connection", +"PreferencesContentOpenAICompletionURLLabel" -> "Chat Completion URL:", + +"ResourceInstallerFromURLPrompt" -> "Enter a URL", + +"ToolManagerTitle" -> "Add & Manage LLM Tools", +"ToolManagerInstallTools" -> "Install Tools", +"ToolManagerInstallFrom" -> "Install from", +"ToolManagerInstallFromLLMToolRepo" -> "LLM Tool Repository \[UpperRightArrow]", +"ToolManagerManageTools" -> "Manage and Enable Tools", +"ToolManagerShowEnabledFor" -> "Show enabled tools for:", +"ToolManagerTool" -> "Tool", +"ToolManagerEnabledFor" -> "Enabled for\[VeryThinSpace]:", +"ToolManagerEnabledByPersona" -> "Enabled by persona", +"ToolManagerEnabledNever" -> "Never enabled", +"ToolManagerEnabledAlways" -> "Always enabled", +"ToolManagerTooltipNonConfigurable" -> "`name` does not have any configurable parameters.", +"ToolManagerTooltipNonDeletable1" -> "`name` is a built-in tool and cannot be deleted.", +"ToolManagerTooltipNonDeletable2" -> "`name` is provided by the persona `persona` and cannot be deleted separately.", +"ToolManagerDeleteTool" -> "Delete Tool", + +"UIEnableChatFeatures" -> "Enable AI Chat Features", +"UIAutomaticAnalysisLabel" -> "Do automatic result analysis", +"UIAutomaticAnalysisTooltip" -> "If enabled, automatic AI provided suggestions will be added following evaluation results.", +"UIPersonas" -> "Personas", +"UIChatBlockSettings" -> "Chat Block Settings\[Ellipsis]", +"UIAddAndManagePersonas" -> "Add & Manage Personas\[Ellipsis]", +"UIAddAndManageTools" -> "Add & Manage Tools\[Ellipsis]", +"UIModels" -> "Models", +"UIModelsServices" -> "Services", +"UIModelsGet" -> "Getting available models\[Ellipsis]", +"UIModelsNoList" -> "Connect for model list", +"UIModelsFineTuned" -> "Fine Tuned Models", +"UIModelsSnapshot" -> "Snapshot Models", +"UIModelsPreview" -> "Preview Models", +"UIAdvancedSettings" -> "Advanced Settings", +"UIAdvancedTemperature" -> "Temperature", +"UIAdvancedToolCallFrequency" -> "Tool Call Frequency", +"UIAdvancedChooseAutomatically" -> "Choose automatically", +"UIAdvancedRoles" -> "Roles", +"UITryEnableChatDialogMainText" -> "Enabling Chat Notebook functionality will destroy the private styles defined in this notebook, and replace them with the shared Chatbook stylesheet.", +"UITryEnableChatDialogConfirm" -> "Are you sure you wish to continue?", + +"StylesheetChatWidgetButtonTooltip" -> "Send to LLM", +"StylesheetAssistantMenuInitializerButtonTooltip" -> "Disable automatic assistance", +"StylesheetFeedbackButtonTooltip" -> "Send feedback to Wolfram", +"StylesheetExplodeCellsInPlace" -> "Explode Cells (In Place)", +"StylesheetExplodeCellsDuplicate" -> "Explode Cells (Duplicate)", +"StylesheetCopyExplodedCells" -> "Copy Exploded Cells", +"StylesheetToggleFormatting" -> "Toggle Formatting", +"StylesheetCopyChatObject" -> "Copy ChatObject", +"StylesheetInsertionMenuChatInput" -> "Chat Input", +"StylesheetInsertionMenuSideChat" -> "Side Chat", + +"PersonaNameBirdnardo" -> "Birdnardo", +"PersonaNameCodeAssistant" -> "Code Assistant", +"PersonaNameCodeWriter" -> "Code Writer", +"PersonaNamePlainChat" -> "Plain Chat", +"PersonaNameRawModel" -> "Raw Model", +"PersonaNameWolfie" -> "Wolfie", + +"AttachedChatFieldHint" -> "Ask me anything" +} +@| +@| +@@resource ChatbookLocalizableBitmaps +{ +} +@| \ No newline at end of file diff --git a/FrontEnd/TextResources/ChineseSimplified/ChatbookStrings.tr b/FrontEnd/TextResources/ChineseSimplified/ChatbookStrings.tr new file mode 100644 index 00000000..69c7c0ce --- /dev/null +++ b/FrontEnd/TextResources/ChineseSimplified/ChatbookStrings.tr @@ -0,0 +1,180 @@ +@@resource ChatbookStrings +{ +"ConnectButton" -> "\:8FDE\:63A5", +"DisconnectButton" -> "\:65AD\:5F00\:8FDE\:63A5", +"OKButton" -> "\:786E\:8BA4", +"CancelButton" -> "\:53D6\:6D88", +"DeleteButton" -> "\:5220\:9664", +"SendButton" -> "\:53D1\:9001", +"URLButton" -> "URL", +"ScopeGlobal" -> "\:5168\:5C40", +"ScopeNotebook" -> "\:9009\:4E2D\:7684\:7B14\:8BB0\:672C", +"ScopeCells" -> "\:9009\:4E2D\:7684\:5355\:5143", +"EnabledByModel" -> "\:6839\:636E\:6A21\:578B\:81EA\:52A8\:542F\:7528", +"EnabledByPersona" -> "\:6839\:636E\:89D2\:8272\:81EA\:52A8\:751F\:6210", +"EnabledAlways" -> "\:59CB\:7EC8\:542F\:7528", +"EnabledNever" -> "\:59CB\:7EC8\:7981\:7528", +"EnabledNever2" -> "\:6C38\:4E0D\:542F\:7528", +"Always" -> "\:59CB\:7EC8", +"Never" -> "\:6C38\:4E0D", +"Automatic" -> "\:81EA\:52A8", +"Custom" -> "\:5B9A\:5236", +"Rare" -> "\:5F88\:5C11", +"Often" -> "\:7ECF\:5E38", + +"ActionsAPIKeyDialogTitle" -> "\:8BF7\:8F93\:5165\:60A8\:7684 OpenAI API \:5BC6\:94A5", +"ActionsAPIKeyDialogAPIKey" -> "API \:5BC6\:94A5", +"ActionsAPIKeyDialogSave" -> "\:4FDD\:5B58", +"APIKeyDialogCreateKeyTemplate" -> "\:5982\:679C\:60A8\:8FD8\:6CA1\:6709 API \:5BC6\:94A5\:ff0c\:8BF7\:521B\:5EFA\:4E00\:4E2A `1`\:3002", +"APIKeyDialogSaveKeyTemplate" -> "\:5982\:679C\:4E0D\:60F3\:518D\:770B\:5230\:6B64\:5BF9\:8BDD\:6846\:ff0c\:8BF7\:9009\:62E9\:201c\:4FDD\:5B58\:201d\:5C06\:5BC6\:94A5\:4FDD\:5B58\:5230 `1`\:4E2D\:3002", + +"ChatContextDialogSystemPromptText" -> "\:7CFB\:7EDF\:63D0\:793A\:8BCD", +"ChatContextDialogCellProcessingFunction" -> "\:5355\:5143\:5904\:7406\:51FD\:6570", +"ChatContextDialogCellPostEvaluationFunction" -> "\:8BA1\:7B97\:5B8C\:6210\:540E\:5E94\:7528\:4E8E\:5355\:5143\:7684\:51FD\:6570", +"ChatContextDialogDescription" -> "\:8FD9\:662F\:544A\:8BC9\:60A8\:8BE5\:600E\:4E48\:505A\:7684\:6587\:5B57\:63CF\:8FF0\:3002", +"ChatContextDialogClickForMoreInfo" -> "\:70B9\:51FB\:4E86\:89E3\:66F4\:591A\:4FE1\:606F", + +"ChatToolbarInsertChatCell" -> "\:63D2\:5165\:804A\:5929\:5355\:5143", +"ChatToolbarChatSettings" -> "\:804A\:5929\:8BBE\:7F6E", +"ChatToolbarChatDrivenLabel" -> "\:804A\:5929\:7B14\:8BB0\:672C", +"ChatToolbarChatEnabledLabel" -> "\:652F\:6301\:804A\:5929\:7684\:7B14\:8BB0\:672C", + +"DefaultToolsLinks" -> "\:94FE\:63A5", + +"FeedbackChatMessagesContent" -> "\:804A\:5929\:4FE1\:606F", +"FeedbackChatMessagesTooltip" -> "\:521B\:5EFA\:6B64\:804A\:5929\:8F93\:51FA\:6D89\:53CA\:7684\:804A\:5929\:6D88\:606F\:3002", +"FeedbackSystemMessageContent" -> "\:7CFB\:7EDF\:6D88\:606F", +"FeedbackSystemMessageTooltip" -> "\:7528\:4E8E\:5411 AI \:53D1\:51FA\:6307\:4EE4\:7684\:5E95\:5C42\:7CFB\:7EDF\:6D88\:606F\:3002", +"FeedbackChatHistoryContent" -> "\:7528\:4E8E\:751F\:6210\:6B64\:8F93\:51FA\:7684\:804A\:5929\:8BB0\:5F55", +"FeedbackChatHistoryTooltip" -> "\:7528\:4F5C\:5BF9\:8BDD\:8BB0\:5F55\:4EE5\:751F\:6210\:6B64\:8F93\:51FA\:7684\:5176\:4ED6\:6D88\:606F\:3002", +"FeedbackChatImageContent" -> "\:804A\:5929\:8F93\:51FA\:56FE\:50CF", +"FeedbackChatImageTooltip" -> "\:804A\:5929\:8F93\:51FA\:7684\:622A\:5C4F\:ff0c\:53EF\:5728\:53CD\:9988\:610F\:89C1\:4E0E\:8F93\:51FA\:7684\:6837\:5F0F\:6709\:5173\:65F6\:4F7F\:7528\:3002", +"FeedbackDialogHeader" -> "\:53D1\:9001\:5173\:4E8E Wolfram AI \:804A\:5929\:7684\:53CD\:9988\:610F\:89C1", +"FeedbackDialogBodyThumbs" -> "\:63D0\:4F9B\:53CD\:9988\:610F\:89C1\:6709\:52A9\:4E8E\:6211\:4EEC\:6539\:8FDB AI \:7684\:529F\:80FD\:3002", +"FeedbackDialogContentIncludedLabel" -> "\:5305\:542B\:7684\:5185\:5BB9\:ff1a", +"FeedbackDialogContentOutputImageLabel" -> "\:8F93\:51FA\:56FE\:50CF", +"FeedbackDialogCommentFieldHint" -> "\:60A8\:8FD8\:6709\:5176\:4ED6\:5EFA\:8BAE\:5417\:ff1f\:ff08\:53EF\:9009\:ff09", +"FeedbackDialogBodyUsedForTraining" -> "\:60A8\:7684\:804A\:5929\:8BB0\:5F55\:548C\:53CD\:9988\:610F\:89C1\:53EF\:80FD\:4F1A\:7528\:6765\:8FDB\:884C\:57F9\:8BAD\:3002", +"FeedbackDialogBodyPreviewData" -> "\:9884\:89C8\:5C06\:8981\:53D1\:9001\:7684\:6570\:636E", +"FeedbackDialogThanks" -> "\:611F\:8C22\:60A8\:7684\:53CD\:9988\:610F\:89C1\:ff01", + +"FormattingInsertContentAndEvaluateTooltip" -> "\:5728\:4E0B\:9762\:63D2\:5165\:5185\:5BB9\:4F5C\:4E3A\:65B0\:7684\:8F93\:5165\:5355\:5143\:5E76\:8BA1\:7B97", +"FormattingCopyToClipboardTooltip" -> "\:590D\:5236\:5230\:526A\:8D34\:677F", +"FormattingInsertContentTooltip" -> "\:5728\:4E0B\:9762\:63D2\:5165\:5185\:5BB9\:4F5C\:4E3A\:65B0\:7684\:8F93\:5165\:5355\:5143", + +"InlineReferencesFieldHint" -> "PromptName", +"InlineReferencesInsertLabel" -> "\:63D2\:5165\:ff1a", +"InlineReferencesInsertPersonaPrompt" -> "\:8F93\:5165\:89D2\:8272\:7684\:540D\:5B57", +"InlineReferencesInsertPersonaFail" -> "\:6CA1\:6709\:627E\:5230\:540D\:4E3A\:201c`name`\:201d\:7684\:89D2\:8272\:3002", +"InlineReferencesInsertModifierPrompt" -> "\:8BF7\:8F93\:5165\:9650\:5B9A\:6027\:63D0\:793A\:8BCD", +"InlineReferencesInsertModifierFail" -> "\:6CA1\:6709\:627E\:5230\:540D\:4E3A\:201c`name`\:201d\:7684\:9650\:5B9A\:6027\:63D0\:793A\:8BCD\:3002", +"InlineReferencesInsertFunctionPrompt" -> "\:8BF7\:8F93\:5165\:529F\:80FD\:6027\:63D0\:793A\:8BCD", +"InlineReferencesInsertFunctionFail" -> "\:6CA1\:6709\:627E\:5230\:540D\:4E3A\:201c`name`\:201d\:7684\:529F\:80FD\:6027\:63D0\:793A\:8BCD\:3002", + +"PersonaManagerTitle" -> "\:6DFB\:52A0\:548C\:7BA1\:7406\:89D2\:8272", +"PersonaManagerInstallPersonas" -> "\:5B89\:88C5\:89D2\:8272", +"PersonaManagerInstallFrom" -> "\:4ECE\:6B64\:5904\:5B89\:88C5\:ff1a", +"PersonaManagerInstallFromPromptRepo" -> "\:63D0\:793A\:8BCD\:5B58\:50A8\:5E93 \[UpperRightArrow]", +"PersonaManagerManagePersonas" -> "\:7BA1\:7406\:548C\:542F\:7528\:89D2\:8272", +"PersonaManagerInMenu" -> "\:5305\:62EC\:5728\:83DC\:5355\:4E2D", +"PersonaManagerName" -> "\:540D\:5B57", +"PersonaManagerVersion" -> "\:7248\:672C", +"PersonaManagerOriginChatbookTooltip" -> "\:4ECE Wolfram/Chatbook \:7A0B\:5E8F\:5305\:5B89\:88C5\:7684\:89D2\:8272\:3002\:8BBF\:95EE\:7F51\:9875 \[RightGuillemet]", +"PersonaManagerOriginRepositoryTooltip" -> "\:4ECE `name` \:7A0B\:5E8F\:5305\:5B89\:88C5\:7684\:89D2\:8272\:3002\:8BBF\:95EE\:7F51\:9875 \[RightGuillemet]", +"PersonaManagerPersonaUninstallTooltip" -> "\:65E0\:6CD5\:5378\:8F7D\:8BE5\:89D2\:8272\:ff0c\:56E0\:4E3A\:5B83\:662F\:7531 `1` \:7A0B\:5E8F\:5305\:63D0\:4F9B\:7684\:3002", + +"PreferencesContentNotebooksTab" -> "\:7B14\:8BB0\:672C", +"PreferencesContentPersonasTab" -> "\:89D2\:8272", +"PreferencesContentServicesTab" -> "\:670D\:52A1\:5546", +"PreferencesContentToolsTab" -> "\:5DE5\:5177", +"PreferencesContentEnableAssistanceLabel" -> "\:542F\:7528\:81EA\:52A8\:534F\:52A9\:529F\:80FD", +"PreferencesContentEnableAssistanceTooltip" -> "\:5982\:679C\:542F\:7528\:ff0cAI \:63D0\:4F9B\:7684\:5EFA\:8BAE\:5C06\:88AB\:6DFB\:52A0\:5230\:8BA1\:7B97\:7ED3\:679C\:7684\:540E\:9762\:3002", +"PreferencesContentPersonaLabel" -> "\:89D2\:8272\:ff1a", +"PreferencesContentLLMServiceLabel" -> "LLM \:670D\:52A1\:5546\:ff1a", +"PreferencesContentModelLabel" -> "\:6A21\:578B\:ff1a", +"PreferencesContentTemperatureLabel" -> "\:6E29\:5EA6\:ff1a", +"PreferencesContentSubsectionChat" -> "\:804A\:5929\:7B14\:8BB0\:672C\:4E2D\:7684\:5355\:5143", +"PreferencesContentFormatOutputLabel" -> "\:683C\:5F0F\:5316\:804A\:5929\:8F93\:51FA", +"PreferencesContentIncludeHistoryLabel" -> "\:5305\:62EC\:804A\:5929\:8BB0\:5F55", +"PreferencesContentIncludeHistoryTooltip" -> "\:5982\:679C\:542F\:7528\:ff0c\:804A\:5929\:8F93\:5165\:4E4B\:524D\:7684\:5355\:5143\:4E5F\:4F1A\:88AB\:8003\:8651\:5728\:5185\:ff0c\:4F5C\:4E3A LLM \:7684\:4E0A\:4E0B\:6587\:73AF\:5883\:3002", +"PreferencesContentHistoryLengthLabel" -> "\:804A\:5929\:8BB0\:5F55\:7684\:957F\:5EA6\:ff1a", +"PreferencesContentHistoryLengthTooltip" -> "\:804A\:5929\:8BB0\:5F55\:4E2D\:6700\:591A\:5305\:542B\:591A\:5C11\:4E2A\:5355\:5143", +"PreferencesContentMergeChatLabel" -> "\:5408\:5E76\:804A\:5929\:6D88\:606F", +"PreferencesContentMergeChatTooltip" -> "\:5982\:679C\:542F\:7528\:ff0c\:5C06\:4F5C\:8005\:76F8\:540C\:7684\:76F8\:90BB\:5355\:5143\:5408\:5E76\:4E3A\:4E00\:6761\:804A\:5929\:6D88\:606F\:3002", +"PreferencesContentSubsectionFeatures" -> "\:529F\:80FD", +"PreferencesContentEnableMultimodalLabel" -> "\:542F\:7528\:591A\:6A21\:6001\:5185\:5BB9\:ff1a", +"PreferencesContentEnableTools" -> "\:542F\:7528\:5DE5\:5177\:ff1a", +"PreferencesContentToolCallFrequency" -> "\:8C03\:7528\:5DE5\:5177\:7684\:9891\:7387\:ff1a", +"PreferencesContentSubsectionRegisteredServices" -> "\:6CE8\:518C\:670D\:52A1\:5546", +"PreferencesContentService" -> "\:670D\:52A1\:5546", +"PreferencesContentServiceConnectButton" -> "\:8FDE\:63A5\:83B7\:53D6\:6A21\:578B\:5217\:8868", +"PreferencesContentAuthentication" -> "\:8BA4\:8BC1", +"PreferencesContentUnregisterTooltip" -> "\:53D6\:6D88\:4E0E\:6CE8\:518C\:670D\:52A1\:5546\:7684\:8FDE\:63A5", +"PreferencesContentOpenAICompletionURLLabel" -> "\:804A\:5929\:8865\:5168 URL\:ff1a", + +"ResourceInstallerFromURLPrompt" -> "\:8F93\:5165 URL", + +"ToolManagerTitle" -> "\:6DFB\:52A0\:548C\:7BA1\:7406 LLM \:5DE5\:5177", +"ToolManagerInstallTools" -> "\:5B89\:88C5\:5DE5\:5177", +"ToolManagerInstallFrom" -> "\:4ECE\:6B64\:5904\:5B89\:88C5\:ff1a", +"ToolManagerInstallFromLLMToolRepo" -> "LLM \:5DE5\:5177\:5E93 \[UpperRightArrow]", +"ToolManagerManageTools" -> "\:7BA1\:7406\:548C\:542F\:7528\:5DE5\:5177", +"ToolManagerShowEnabledFor" -> "\:663E\:793A\:542F\:7528\:7684\:5DE5\:5177\:ff1a", +"ToolManagerTool" -> "\:5DE5\:5177", +"ToolManagerEnabledFor" -> "\:542F\:7528\:72B6\:6001\[VeryThinSpace]:", +"ToolManagerEnabledByPersona" -> "\:6839\:636E\:89D2\:8272\:542F\:7528", +"ToolManagerEnabledNever" -> "\:6C38\:4E0D\:542F\:7528", +"ToolManagerEnabledAlways" -> "\:59CB\:7EC8\:542F\:7528", +"ToolManagerTooltipNonConfigurable" -> "`name` \:6CA1\:6709\:53EF\:914D\:7F6E\:7684\:53C2\:6570\:3002", +"ToolManagerTooltipNonDeletable1" -> "`name` \:662F\:5185\:7F6E\:5DE5\:5177\:ff0c\:65E0\:6CD5\:5220\:9664\:3002", +"ToolManagerTooltipNonDeletable2" -> "`name` \:662F\:7531\:89D2\:8272 `persona` \:63D0\:4F9B\:7684\:ff0c\:4E0D\:80FD\:5355\:72EC\:5220\:9664\:3002", +"ToolManagerDeleteTool" -> "\:5220\:9664\:5DE5\:5177", + +"UIEnableChatFeatures" -> "\:542F\:7528 AI \:804A\:5929\:529F\:80FD", +"UIAutomaticAnalysisLabel" -> "\:81EA\:52A8\:5BF9\:7ED3\:679C\:8FDB\:884C\:5206\:6790", +"UIAutomaticAnalysisTooltip" -> "\:5982\:679C\:542F\:7528\:ff0cAI \:63D0\:4F9B\:7684\:5EFA\:8BAE\:5C06\:88AB\:6DFB\:52A0\:5230\:8BA1\:7B97\:7ED3\:679C\:7684\:540E\:9762\:3002", +"UIPersonas" -> "\:89D2\:8272", +"UIChatBlockSettings" -> "\:804A\:5929\:7B14\:8BB0\:672C\:7684\:8BBE\:7F6E\[Ellipsis]", +"UIAddAndManagePersonas" -> "\:6DFB\:52A0\:5E76\:7BA1\:7406\:89D2\:8272\[Ellipsis]", +"UIAddAndManageTools" -> "\:6DFB\:52A0\:5E76\:7BA1\:7406\:5DE5\:5177\[Ellipsis]", +"UIModels" -> "\:6A21\:578B", +"UIModelsServices" -> "\:670D\:52A1\:5546", +"UIModelsGet" -> "\:83B7\:53D6\:53EF\:7528\:6A21\:578B\[Ellipsis]", +"UIModelsNoList" -> "\:8FDE\:63A5\:83B7\:53D6\:6A21\:578B\:5217\:8868", +"UIModelsFineTuned" -> "\:7CBE\:5FC3\:8C03\:6574\:8FC7\:7684\:6A21\:578B", +"UIModelsSnapshot" -> "Snapshot \:6A21\:578B", +"UIModelsPreview" -> "\:9884\:89C8\:6A21\:578B", +"UIAdvancedSettings" -> "\:9AD8\:7EA7\:8BBE\:7F6E", +"UIAdvancedTemperature" -> "\:6E29\:5EA6", +"UIAdvancedToolCallFrequency" -> "\:5DE5\:5177\:8C03\:7528\:9891\:7387", +"UIAdvancedChooseAutomatically" -> "\:81EA\:52A8\:9009\:62E9", +"UIAdvancedRoles" -> "\:89D2\:8272", +"UITryEnableChatDialogMainText" -> "\:542F\:7528\:804A\:5929\:7B14\:8BB0\:672C\:529F\:80FD\:5C06\:7834\:574F\:6B64\:7B14\:8BB0\:672C\:4E2D\:5B9A\:4E49\:7684\:4E13\:6709\:6837\:5F0F\:ff0c\:5E76\:5C06\:5176\:66FF\:6362\:4E3A\:5171\:4EAB\:7684\:804A\:5929\:7B14\:8BB0\:672C\:6837\:5F0F\:3002", +"UITryEnableChatDialogConfirm" -> "\:60A8\:786E\:5B9A\:8981\:7EE7\:7EED\:5417\:ff1f", + +"StylesheetChatWidgetButtonTooltip" -> "\:53D1\:9001\:5230 LLM", +"StylesheetAssistantMenuInitializerButtonTooltip" -> "\:7981\:7528\:81EA\:52A8\:534F\:52A9\:529F\:80FD", +"StylesheetFeedbackButtonTooltip" -> "\:5411 Wolfram \:53D1\:9001\:53CD\:9988\:610F\:89C1", +"StylesheetExplodeCellsInPlace" -> "\:62C6\:5206\:5355\:5143\:ff08\:539F\:5730\:ff09", +"StylesheetExplodeCellsDuplicate" -> "\:62C6\:5206\:5355\:5143\:ff08\:590D\:5236\:ff09", +"StylesheetCopyExplodedCells" -> "\:590D\:5236\:62C6\:5206\:540E\:7684\:5355\:5143", +"StylesheetToggleFormatting" -> "\:5207\:6362\:683C\:5F0F", +"StylesheetCopyChatObject" -> "\:590D\:5236 ChatObject", +"StylesheetInsertionMenuChatInput" -> "\:804A\:5929\:8F93\:5165", +"StylesheetInsertionMenuSideChat" -> "\:79C1\:804A", + +"PersonaNameBirdnardo" -> "Birdnardo", +"PersonaNameCodeAssistant" -> "\:4EE3\:7801\:52A9\:624B", +"PersonaNameCodeWriter" -> "\:4EE3\:7801\:5199\:624B", +"PersonaNamePlainChat" -> "\:666E\:901A\:804A\:5929\:4EBA", +"PersonaNameRawModel" -> "\:539F\:59CB\:6A21\:578B", +"PersonaNameWolfie" -> "Wolfie", + +"AttachedChatFieldHint" -> "\:6709\:95EE\:5FC5\:7B54" +} +@| +@| +@@resource ChatbookLocalizableBitmaps +{ +} +@| \ No newline at end of file diff --git a/FrontEnd/TextResources/ChineseTraditional/ChatbookStrings.tr b/FrontEnd/TextResources/ChineseTraditional/ChatbookStrings.tr new file mode 100644 index 00000000..abff0bf2 --- /dev/null +++ b/FrontEnd/TextResources/ChineseTraditional/ChatbookStrings.tr @@ -0,0 +1,180 @@ +@@resource ChatbookStrings +{ +"ConnectButton" -> "\:9023\:63A5", +"DisconnectButton" -> "\:5207\:65B7", +"OKButton" -> "\:78BA\:5B9A", +"CancelButton" -> "\:53D6\:6D88", +"DeleteButton" -> "\:522A\:9664", +"SendButton" -> "\:767C\:9001", +"URLButton" -> "\:7DB2\:5740", +"ScopeGlobal" -> "\:7E3D\:9AD4", +"ScopeNotebook" ->"\:5DF2\:9078\:53D6\:7B46\:8A18\:672C", +"ScopeCells" ->"\:5DF2\:9078\:53D6\:5132\:5B58\:683C", +"EnabledByModel" ->"\:4F9D\:6A21\:578B\:81EA\:52D5\:8CE6\:80FD", +"EnabledByPersona" -> "\:4F9D\:4EBA\:7269\:8A8C\:81EA\:52D5\:8CE6\:80FD", +"EnabledAlways" -> "\:6C38\:9060\:8CE6\:80FD", +"EnabledNever" -> "\:6C38\:9060\:5931\:80FD", +"EnabledNever2" -> "\:6C38\:4E0D\:8CE6\:80FD", +"Always" -> "\:6C38\:9060", +"Never" -> "\:6C38\:4E0D", +"Automatic" -> "\:81EA\:52D5", +"Custom" -> "\:5BA2\:88FD", +"Rare" -> "\:7F55\:898B", +"Often" -> "\:7D93\:5E38", + +"ActionsAPIKeyDialogTitle" -> "\:8ACB\:8F38\:5165\:60A8\:7684 OpenAI API \:91D1\:9470", +"ActionsAPIKeyDialogAPIKey" -> "API \:91D1\:9470", +"ActionsAPIKeyDialogSave" -> "\:5132\:5B58", +"APIKeyDialogCreateKeyTemplate" -> "\:5982\:679C\:60A8\:5C1A\:672A\:6301\:6709 API \:91D1\:9470\:FF0C\:60A8\:53EF\:4EE5\:5275\:5EFA\:4E00\:500B `1`\:3002", +"APIKeyDialogSaveKeyTemplate" -> "\:70BA\:4E86\:907F\:514D\:65E5\:5F8C\:518D\:51FA\:73FE\:6B64\:5C0D\:8A71\:FF0C\:9078\:64C7 \"\:5132\:5B58\" \:5C07\:91D1\:9470\:6536\:85CF\:5728 `1` \:4E2D\:3002", + +"ChatContextDialogSystemPromptText" -> "\:7CFB\:7D71\:63D0\:793A\:6587\:672C", +"ChatContextDialogCellProcessingFunction" -> "\:5132\:5B58\:683C\:8655\:7406\:51FD\:6578", +"ChatContextDialogCellPostEvaluationFunction" -> "\:5132\:5B58\:683C\:5F8C\:8A55\:4F30\:51FD\:6578", +"ChatContextDialogDescription" -> "\:6B64\:6587\:672C\:5F15\:5C0E\:60A8\:8981\:505A\:4EC0\:9EBC\:3002", +"ChatContextDialogClickForMoreInfo" -> "\:6309\:6B64\:7372\:53D6\:66F4\:591A\:8CC7\:8A0A", + +"ChatToolbarInsertChatCell" -> "\:63D2\:5165\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:5132\:5B58\:683C", +"ChatToolbarChatSettings" -> "\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:8A2D\:5B9A", +"ChatToolbarChatDrivenLabel" -> "\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:9A45\:52D5\:7B46\:8A18\:672C", +"ChatToolbarChatEnabledLabel" -> "\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:8CE6\:80FD\:7B46\:8A18\:672C", + +"DefaultToolsLinks" -> "\:93C8\:7D50", + +"FeedbackChatMessagesContent" -> "\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:8A0A\:606F", +"FeedbackChatMessagesTooltip" -> "\:6D89\:53CA\:5230\:5275\:5EFA\:6B64\:804A\:5929\:8F38\:51FA\:7684\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:8A0A\:606F\:3002", +"FeedbackSystemMessageContent" -> "\:7CFB\:7D71\:8A0A\:606F", +"FeedbackSystemMessageTooltip" -> "\:91DD\:5C0D\:50B3\:9054\:6307\:4EE4\:7D66 AI \:6240\:4F7F\:7528\:7684\:57FA\:790E\:7CFB\:7D71\:8A0A\:606F\:3002", +"FeedbackChatHistoryContent" -> "\:751F\:6210\:6B64\:8F38\:51FA\:6240\:4F7F\:7528\:7684\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:6B77\:53F2\:7D00\:9304", +"FeedbackChatHistoryTooltip" -> "\:4F7F\:7528\:88AB\:7576\:4F5C\:5C0D\:8A71\:6B77\:53F2\:7D00\:9304\:7684\:984D\:5916\:8A0A\:606F\:4F86\:751F\:6210\:6B64\:8F38\:51FA\:3002", +"FeedbackChatImageContent" -> "\:804A\:5929\:8F38\:51FA\:5F71\:50CF", +"FeedbackChatImageTooltip" ->"\:5982\:679C\:56DE\:994B\:662F\:95DC\:65BC\:8F38\:51FA\:7684\:5916\:8C8C\:FF0C\:53EF\:4EE5\:4F7F\:7528\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:8F38\:51FA\:7684\:87A2\:5E55\:622A\:5716\:3002", +"FeedbackDialogHeader" -> "\:767C\:9001 Wolfram AI \:804A\:5929\:56DE\:994B", +"FeedbackDialogBodyThumbs" -> "\:767C\:9001\:56DE\:994B\:53EF\:671B\:5E6B\:52A9\:6211\:5011\:589E\:9032 AI \:529F\:80FD\:3002", +"FeedbackDialogContentIncludedLabel" -> "\:5DF2\:5305\:62EC\:5167\:5BB9\:FF1A", +"FeedbackDialogContentOutputImageLabel" -> "\:8F38\:51FA\:5F71\:50CF", +"FeedbackDialogCommentFieldHint" -> "\:60A8\:9084\:6709\:53E6\:5916\:7684\:56DE\:994B\:55CE\:FF1F\:FF08\:53EF\:9078\:7684\:FF09", +"FeedbackDialogBodyUsedForTraining" -> "\:60A8\:7684\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:6B77\:53F2\:7D00\:9304\:548C\:56DE\:994B\:FF0C\:4E5F\:8A31\:6703\:88AB\:7528\:4F86\:7576\:4F5C\:6559\:80B2\:8A13\:7DF4\:984C\:6750\:3002", +"FeedbackDialogBodyPreviewData" -> "\:9810\:89BD\:8CC7\:6599\:5C07\:6703\:88AB\:767C\:9001", +"FeedbackDialogThanks" -> "\:611F\:8B1D\:60A8\:7684\:56DE\:994B\:FF01", + +"FormattingInsertContentAndEvaluateTooltip" -> "\:63D2\:5165\:5982\:540C\:5728\:4E0B\:65B9\:65B0\:589E\:8F38\:5165\:5132\:5B58\:683C\:7684\:5167\:5BB9\:4E26\:9032\:884C\:8A08\:7B97", +"FormattingCopyToClipboardTooltip" -> "\:8907\:88FD\:81F3\:526A\:8CBC\:7C3F", +"FormattingInsertContentTooltip" -> "\:63D2\:5165\:5982\:540C\:5728\:4E0B\:65B9\:65B0\:589E\:8F38\:5165\:5132\:5B58\:683C\:7684\:5167\:5BB9", + +"InlineReferencesFieldHint" -> "\:63D0\:793A\:540D\:7A31", +"InlineReferencesInsertLabel" -> "\:63D2\:5165\:FF1A", +"InlineReferencesInsertPersonaPrompt" -> "\:8F38\:5165\:4EBA\:7269\:8A8C\:540D\:7A31", +"InlineReferencesInsertPersonaFail" -> "\:7121\:6CD5\:627E\:5230\:540D\:7A31\:70BA \"`name`\" \:7684\:4EBA\:7269\:8A8C\:3002", +"InlineReferencesInsertModifierPrompt" -> "\:8F38\:5165\:4FEE\:98FE\:7B26\:63D0\:793A", +"InlineReferencesInsertModifierFail" ->"\:7121\:6CD5\:627E\:5230\:540D\:7A31\:70BA \"`name`\" \:7684\:4FEE\:98FE\:7B26\:3002", +"InlineReferencesInsertFunctionPrompt" -> "\:8F38\:5165\:51FD\:6578\:63D0\:793A", +"InlineReferencesInsertFunctionFail" -> "\:7121\:6CD5\:627E\:5230\:540D\:7A31\:70BA \"`name`\" \:7684\:51FD\:6578\:3002", + +"PersonaManagerTitle" -> "\:589E\:6DFB\:4E26\:7BA1\:7406\:4EBA\:7269\:8A8C", +"PersonaManagerInstallPersonas" -> "\:5B89\:88DD\:4EBA\:7269\:8A8C", +"PersonaManagerInstallFrom" -> "\:5B89\:88DD\:8D77\:65BC", +"PersonaManagerInstallFromPromptRepo" -> "\:63D0\:793A\:5132\:5B58\:5EAB \[UpperRightArrow]", +"PersonaManagerManagePersonas" -> "\:7BA1\:7406\:4E26\:8CE6\:80FD\:4EBA\:7269\:8A8C", +"PersonaManagerInMenu" -> "\:6311\:9078\:9078\:55AE", +"PersonaManagerName" -> "\:540D\:7A31", +"PersonaManagerVersion" -> "\:7248\:672C", +"PersonaManagerOriginChatbookTooltip" -> "\:6B32\:5B89\:88DD\:51FA\:81EA Wolfram/Chatbook paclet \:7684\:4EBA\:7269\:8A8C\:3002\:8ACB\:53C3\:8A2A\:7DB2\:9801 \[RightGuillemet]", +"PersonaManagerOriginRepositoryTooltip" -> "\:6B32\:5B89\:88DD\:51FA\:81EA `name` paclet \:7684\:4EBA\:7269\:8A8C\:3002\:8ACB\:53C3\:8A2A\:7DB2\:9801 \[RightGuillemet]", +"PersonaManagerPersonaUninstallTooltip" -> "\:5B89\:88DD\:7D93\:7531 `1` paclet \:6240\:63D0\:4F9B\:7684\:4EBA\:7269\:8A8C\:7121\:6CD5\:88AB\:89E3\:9664\:3002", + +"PreferencesContentNotebooksTab" -> "\:7B46\:8A18\:672C", +"PreferencesContentPersonasTab" -> "\:4EBA\:7269\:8A8C", +"PreferencesContentServicesTab" -> "\:670D\:52D9", +"PreferencesContentToolsTab" -> "\:5DE5\:5177", +"PreferencesContentEnableAssistanceLabel" -> "\:8CE6\:80FD\:81EA\:52D5\:8F14\:52A9", +"PreferencesContentEnableAssistanceTooltip" -> "\:8CE6\:80FD\:5F8C\:FF0C\:81EA\:52D5 AI \:6240\:63D0\:4F9B\:7684\:5EFA\:8B70\:5C07\:6703\:88AB\:6DFB\:52A0\:81F3\:4E0B\:5217\:8A08\:7B97\:7D50\:679C\:4E2D\:3002", +"PreferencesContentPersonaLabel" -> "\:4EBA\:7269\:8A8C\:FF1A", +"PreferencesContentLLMServiceLabel" -> "LLM \:4F3A\:670D\:5668\:FF1A", +"PreferencesContentModelLabel" -> "\:6A21\:578B\:FF1A", +"PreferencesContentTemperatureLabel" -> "\:6EAB\:5EA6\:FF1A", +"PreferencesContentSubsectionChat" -> "\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:7B46\:8A18\:672C\:5132\:5B58\:683C", +"PreferencesContentFormatOutputLabel" -> "\:683C\:5F0F\:5316\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:8F38\:51FA", +"PreferencesContentIncludeHistoryLabel" -> "\:6536\:7D0D\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:6B77\:53F2\:7D00\:9304", +"PreferencesContentIncludeHistoryTooltip" -> "\:8CE6\:80FD\:5F8C\:FF0C\:5132\:5B58\:683C\:6240\:524D\:5C0E\:7684\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:8F38\:5165\:5C07\:6703\:7576\:4F5C LLM \:9644\:52A0\:7684\:4E0A\:4E0B\:6587\:88AB\:6536\:7D0D\:5176\:4E2D\:3002", +"PreferencesContentHistoryLengthLabel" -> "\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:6B77\:53F2\:7D00\:9304\:9577\:5EA6\:FF1A", +"PreferencesContentHistoryLengthTooltip" -> "\:6975\:5927\:5316\:6536\:7D0D\:65BC\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:6B77\:53F2\:7D00\:9304\:7684\:5132\:5B58\:683C\:6578\:91CF", +"PreferencesContentMergeChatLabel" -> "\:5408\:4F75\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:8A0A\:606F", +"PreferencesContentMergeChatTooltip" -> "\:8CE6\:80FD\:5F8C\:FF0C\:5E36\:6709\:76F8\:540C\:4F5C\:8005\:7684\:9130\:63A5\:5132\:5B58\:683C\:5C07\:6703\:88AB\:5408\:4F75\:6210\:55AE\:4E00\:7684\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:8A0A\:606F\:3002", +"PreferencesContentSubsectionFeatures" -> "\:529F\:80FD", +"PreferencesContentEnableMultimodalLabel" -> "\:8CE6\:80FD\:591A\:6A21\:614B\:5167\:5BB9\:FF1A", +"PreferencesContentEnableTools" -> "\:8CE6\:80FD\:5DE5\:5177\:FF1A", +"PreferencesContentToolCallFrequency" -> "\:5DE5\:5177\:8ABF\:7528\:983B\:7387\:FF1A", +"PreferencesContentSubsectionRegisteredServices" -> "\:5DF2\:8A3B\:518A\:670D\:52D9", +"PreferencesContentService" -> "\:670D\:52D9", +"PreferencesContentServiceConnectButton" -> "\:91DD\:5C0D\:6A21\:578B\:5217\:8868\:9032\:884C\:9023\:63A5", +"PreferencesContentAuthentication" -> "\:9A57\:8B49", +"PreferencesContentUnregisterTooltip" -> "\:672A\:8A3B\:518A\:670D\:52D9\:9023\:63A5", +"PreferencesContentOpenAICompletionURLLabel" -> "\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:5BE6\:73FE\:7DB2\:5740\:FF1A", + +"ResourceInstallerFromURLPrompt" -> "\:8F38\:5165\:7DB2\:5740", + +"ToolManagerTitle" -> "\:589E\:6DFB\:4E26\:7BA1\:7406 LLM \:5DE5\:5177", +"ToolManagerInstallTools" -> "\:5B89\:88DD\:5DE5\:5177", +"ToolManagerInstallFrom" -> "\:5B89\:88DD\:8D77\:65BC", +"ToolManagerInstallFromLLMToolRepo" -> "LLM \:5DE5\:5177\:5132\:5B58\:5EAB \[UpperRightArrow]", +"ToolManagerManageTools" -> "\:7BA1\:7406\:4E26\:8CE6\:80FD\:5DE5\:5177", +"ToolManagerShowEnabledFor" -> "\:986F\:793A\:8CE6\:80FD\:5DE5\:5177\:FF1A", +"ToolManagerTool" -> "\:5DE5\:5177", +"ToolManagerEnabledFor" -> "\:8CE6\:80FD\:8D77\:65BC\[VeryThinSpace]\:FF1A", +"ToolManagerEnabledByPersona" -> "\:4F9D\:4EBA\:7269\:8A8C\:9032\:884C\:8CE6\:80FD", +"ToolManagerEnabledNever" -> "\:6C38\:4E0D\:8CE6\:80FD", +"ToolManagerEnabledAlways" -> "\:6C38\:9060\:8CE6\:80FD", +"ToolManagerTooltipNonConfigurable" -> "`name` \:4E26\:4E0D\:5B58\:6709\:4EFB\:4F55\:7D44\:614B\:53C3\:6578\:3002", +"ToolManagerTooltipNonDeletable1" -> "`name` \:662F\:5167\:5EFA\:5DE5\:5177\:4E14\:7121\:6CD5\:88AB\:522A\:9664\:3002", +"ToolManagerTooltipNonDeletable2" -> "`name` \:662F\:4F9D\:4EBA\:7269\:8A8C `persona` \:6240\:63D0\:4F9B\:4E14\:7121\:6CD5\:88AB\:500B\:5225\:522A\:9664\:3002", +"ToolManagerDeleteTool" -> "\:522A\:9664\:5DE5\:5177", + +"UIEnableChatFeatures" -> "\:8CE6\:80FD AI \:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:529F\:80FD", +"UIAutomaticAnalysisLabel" -> "\:57F7\:884C\:81EA\:52D5\:7D50\:679C\:5206\:6790", +"UIAutomaticAnalysisTooltip" -> "\:8CE6\:80FD\:5F8C\:FF0C\:81EA\:52D5 AI \:6240\:63D0\:4F9B\:7684\:5EFA\:8B70\:5C07\:6703\:88AB\:6DFB\:52A0\:81F3\:4E0B\:5217\:8A08\:7B97\:7D50\:679C\:4E2D\:3002", +"UIPersonas" -> "\:4EBA\:7269\:8A8C", +"UIChatBlockSettings" -> "\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:5C01\:9396\:8A2D\:5B9A\[Ellipsis]", +"UIAddAndManagePersonas" -> "\:589E\:6DFB\:4E26\:7BA1\:7406\:4EBA\:7269\:8A8C\[Ellipsis]", +"UIAddAndManageTools" -> "\:589E\:6DFB\:4E26\:7BA1\:7406\:5DE5\:5177\[Ellipsis]", +"UIModels" -> "\:6A21\:578B", +"UIModelsServices" ->"\:670D\:52D9", +"UIModelsGet" -> "\:7372\:53D6\:53EF\:4F9B\:4F7F\:7528\:6A21\:578B\[Ellipsis]", +"UIModelsNoList" -> "\:4F9D\:6A21\:578B\:5217\:8868\:9032\:884C\:9023\:63A5", +"UIModelsFineTuned" ->"\:5FAE\:8ABF\:6A21\:578B", +"UIModelsSnapshot" -> "\:5FEB\:7167\:6A21\:578B", +"UIModelsPreview" -> "\:9810\:89BD\:6A21\:578B", +"UIAdvancedSettings" -> "\:9032\:968E\:8A2D\:5B9A", +"UIAdvancedTemperature" -> "\:6EAB\:5EA6", +"UIAdvancedToolCallFrequency" -> "\:5DE5\:5177\:8ABF\:7528\:983B\:7387", +"UIAdvancedChooseAutomatically" -> "\:81EA\:52D5\:9032\:884C\:9078\:64C7", +"UIAdvancedRoles" -> "\:89D2\:8272", +"UITryEnableChatDialogMainText" -> "\:8CE6\:80FD\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:7B46\:8A18\:672C\:7684\:529F\:80FD\:6027\:FF0C\:4E0D\:50C5\:5C07\:6703\:6BC0\:640D\:8F09\:6B64\:7B46\:8A18\:672C\:4E2D\:6240\:5B9A\:7FA9\:7684\:79C1\:7528\:6A23\:5F0F\:FF0C\:4E14\:6703\:88AB\:5171\:4EAB Chatbook \:6A23\:5F0F\:8868\:53D6\:800C\:4EE3\:4E4B\:3002", +"UITryEnableChatDialogConfirm" -> "\:60A8\:78BA\:5B9A\:8981\:7E7C\:7E8C\:55CE\:FF1F", + +"StylesheetChatWidgetButtonTooltip" -> "\:767C\:9001\:81F3 LLM", +"StylesheetAssistantMenuInitializerButtonTooltip" -> "\:5931\:80FD\:81EA\:52D5\:8F14\:52A9", +"StylesheetFeedbackButtonTooltip" -> "\:767C\:9001\:56DE\:994B\:81F3 Wolfram", +"StylesheetExplodeCellsInPlace" -> "\:7206\:7834\:5132\:5B58\:683C\:FF08\:5728\:9069\:7576\:7684\:4F4D\:7F6E\:4E0A\:FF09", +"StylesheetExplodeCellsDuplicate" -> "\:7206\:7834\:5132\:5B58\:683C\:FF08\:6210\:5C0D\:7684\:FF09", +"StylesheetCopyExplodedCells" -> "\:8907\:88FD\:7206\:7834\:5132\:5B58\:683C", +"StylesheetToggleFormatting" ->"\:96D9\:614B\:89F8\:8B8A\:683C\:5F0F\:5316\:4E2D", +"StylesheetCopyChatObject" -> "\:8907\:88FD ChatObject", +"StylesheetInsertionMenuChatInput" -> "\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71\:8F38\:5165", +"StylesheetInsertionMenuSideChat" -> "Side Chat \:FF08\:585E\:6390\:FF09", + +"PersonaNameBirdnardo" -> "Birdnardo", +"PersonaNameCodeAssistant" -> "\:7DE8\:78BC\:5C0F\:5E6B\:624B", +"PersonaNameCodeWriter" -> "\:7DE8\:78BC\:64B0\:5BEB\:5668", +"PersonaNamePlainChat" ->"\:76F4\:7387\:5F0F\:7DB2\:8DEF\:804A\:5929\:7CFB\:7D71", +"PersonaNameRawModel" -> "\:539F\:751F\:6A21\:578B", +"PersonaNameWolfie" -> "Wolfie", + +"AttachedChatFieldHint" -> "\:6B61\:8FCE\:8A62\:554F\:4EFB\:4F55\:4E8B\:60C5" +} +@| +@| +@@resource ChatbookLocalizableBitmaps +{ +} +@| \ No newline at end of file diff --git a/FrontEnd/TextResources/French/ChatbookStrings.tr b/FrontEnd/TextResources/French/ChatbookStrings.tr new file mode 100644 index 00000000..7a6eadf4 --- /dev/null +++ b/FrontEnd/TextResources/French/ChatbookStrings.tr @@ -0,0 +1,180 @@ +@@resource ChatbookStrings +{ +"ConnectButton" -> "Se connecter", +"DisconnectButton" -> "Se d\[EAcute]connecter", +"OKButton" -> "Ok", +"CancelButton" -> "Annuler", +"DeleteButton" -> "Supprimer", +"SendButton" -> "Envoyer", +"URLButton" -> "URL", +"ScopeGlobal" -> "Global", +"ScopeNotebook" -> "Notebook s\[EAcute]lectionn\[EAcute]", +"ScopeCells" -> "Cellules s\[EAcute]lectionn\[EAcute]es", +"EnabledByModel" -> "Automatique par mod\[EGrave]le", +"EnabledByPersona" -> "Automatique par personnage", +"EnabledAlways" -> "Toujours activ\[EAcute]", +"EnabledNever" -> "Toujours d\[EAcute]sactiv\[EAcute]", +"EnabledNever2" -> "Jamais activ\[EAcute]", +"Always" -> "Toujours", +"Never" -> "Jamais", +"Automatic" -> "Automatique", +"Custom" -> "Personnalis\[EAcute]", +"Rare" -> "Rare", +"Often" -> "Souvent", + +"ActionsAPIKeyDialogTitle" -> "Veuillez saisir votre cl\[EAcute] API d\[CloseCurlyQuote]OpenAI", +"ActionsAPIKeyDialogAPIKey" -> "Cl\[EAcute] API", +"ActionsAPIKeyDialogSave" -> "Enregistrer", +"APIKeyDialogCreateKeyTemplate" -> "Si vous n\[CloseCurlyQuote]avez pas encore de cl\[EAcute] API, vous pouvez en cr\[EAcute]er une `1`.", +"APIKeyDialogSaveKeyTemplate" -> "Pour \[EAcute]viter de voir cette bo\[IHat]te de dialogue \[AGrave] l\[CloseCurlyQuote]avenir, choisissez \"Enregistrer\" pour stocker la cl\[EAcute] dans `1`.", + +"ChatContextDialogSystemPromptText" -> "Texte d\[CloseCurlyQuote]invite du syst\[EGrave]me", +"ChatContextDialogCellProcessingFunction" -> "Fonction de traitement des cellules", +"ChatContextDialogCellPostEvaluationFunction" -> "Fonction d\[CloseCurlyQuote]\[EAcute]valuation a posteriori des cellules", +"ChatContextDialogDescription" -> "Voici le texte qui vous indique ce qu\[CloseCurlyQuote]il faut faire.", +"ChatContextDialogClickForMoreInfo" -> "Cliquer pour en savoir plus", + +"ChatToolbarInsertChatCell" -> "Ins\[EAcute]rer une cellule de chat", +"ChatToolbarChatSettings" -> "Param\[EGrave]tres du chat", +"ChatToolbarChatDrivenLabel" -> "Notebook pilot\[EAcute] par le chat", +"ChatToolbarChatEnabledLabel" -> "Notebook avec chat", + +"DefaultToolsLinks" -> "Liens", + +"FeedbackChatMessagesContent" -> "Messages du chat", +"FeedbackChatMessagesTooltip" -> "Messages du chat impliqu\[EAcute]s dans la cr\[EAcute]ation de cette sortie de chat.", +"FeedbackSystemMessageContent" -> "Message du syst\[EGrave]me", +"FeedbackSystemMessageTooltip" -> "Le message du syst\[EGrave]me sous-jacent utilis\[EAcute] pour donner des instructions \[AGrave] l\[CloseCurlyQuote]IA.", +"FeedbackChatHistoryContent" -> "Historique du chat utilis\[EAcute] pour g\[EAcute]n\[EAcute]rer cette sortie", +"FeedbackChatHistoryTooltip" -> "Messages suppl\[EAcute]mentaires utilis\[EAcute]s comme historique du chat pour g\[EAcute]n\[EAcute]rer cette sortie.", +"FeedbackChatImageContent" -> "Image de la sortie du chat", +"FeedbackChatImageTooltip" -> "Une capture d\[CloseCurlyQuote]\[EAcute]cran de la sortie de chat, qui peut \[EHat]tre utilis\[EAcute]e si les commentaires sont li\[EAcute]s \[AGrave] l\[CloseCurlyQuote]apparence de la sortie.", +"FeedbackDialogHeader" -> "Envoyer des commentaires sur le chat de Wolfram AI", +"FeedbackDialogBodyThumbs" -> "L\[CloseCurlyQuote]envoi de commentaires nous aide \[AGrave] am\[EAcute]liorer nos fonctionnalit\[EAcute]s d\[CloseCurlyQuote]IA.", +"FeedbackDialogContentIncludedLabel" -> "Contenu inclus\[NonBreakingSpace]:", +"FeedbackDialogContentOutputImageLabel" -> "Image de sortie", +"FeedbackDialogCommentFieldHint" -> "Avez-vous d\[CloseCurlyQuote]autres commentaires \[AGrave] formuler\[NonBreakingSpace]? (facultatif)", +"FeedbackDialogBodyUsedForTraining" -> "Votre historique de chat et vos commentaires peuvent \[EHat]tre utilis\[EAcute]s \[AGrave] des fins de formation.", +"FeedbackDialogBodyPreviewData" -> "Aper\[CCedilla]u des donn\[EAcute]es \[AGrave] envoyer", +"FeedbackDialogThanks" -> "Merci pour vos commentaires\[NonBreakingSpace]!", + +"FormattingInsertContentAndEvaluateTooltip" -> "Ins\[EAcute]rer le contenu en tant que nouvelle cellule d\[CloseCurlyQuote]entr\[EAcute]e ci-dessous et l\[CloseCurlyQuote]\[EAcute]valuer", +"FormattingCopyToClipboardTooltip" -> "Copier dans le presse-papiers", +"FormattingInsertContentTooltip" -> "Ins\[EAcute]rer le contenu en tant que nouvelle cellule d\[CloseCurlyQuote]entr\[EAcute]e ci-dessous", + +"InlineReferencesFieldHint" -> "Nom de l\[CloseCurlyQuote]invite", +"InlineReferencesInsertLabel" -> "Ins\[EAcute]rer\[NonBreakingSpace]:", +"InlineReferencesInsertPersonaPrompt" -> "Entrer le nom d\[CloseCurlyQuote]un personnage", +"InlineReferencesInsertPersonaFail" -> "Aucun personnage portant le nom \"`name`\" n\[CloseCurlyQuote]a \[EAcute]t\[EAcute] trouv\[EAcute].", +"InlineReferencesInsertModifierPrompt" -> "Entrer une invite de modification", +"InlineReferencesInsertModifierFail" -> "Aucun modificateur portant le nom \"`name`\" n\[CloseCurlyQuote]a \[EAcute]t\[EAcute] trouv\[EAcute].", +"InlineReferencesInsertFunctionPrompt" -> "Entrer l\[CloseCurlyQuote]invite d\[CloseCurlyQuote]une fonction", +"InlineReferencesInsertFunctionFail" -> "Aucune fonction portant le nom \"`name`\" n\[CloseCurlyQuote]a \[EAcute]t\[EAcute] trouv\[EAcute]e.", + +"PersonaManagerTitle" -> "Ajouter et g\[EAcute]rer des personnages", +"PersonaManagerInstallPersonas" -> "Installer des personnages", +"PersonaManagerInstallFrom" -> "Installer \[AGrave] partir de", +"PersonaManagerInstallFromPromptRepo" -> "R\[EAcute]f\[EAcute]rentiel de l\[CloseCurlyQuote]invite \[UpperRightArrow]", +"PersonaManagerManagePersonas" -> "G\[EAcute]rer et activer les personnages", +"PersonaManagerInMenu" -> "Dans le menu", +"PersonaManagerName" -> "Nom", +"PersonaManagerVersion" -> "Version", +"PersonaManagerOriginChatbookTooltip" -> "Personnage install\[EAcute] \[AGrave] partir du paquet Wolfram/Chatbook. Visiter la page \[RightGuillemet]", +"PersonaManagerOriginRepositoryTooltip" -> "Personnage install\[EAcute] \[AGrave] partir du paquet `name`. Visiter la page \[RightGuillemet].", +"PersonaManagerPersonaUninstallTooltip" -> "Ce personnage ne peut pas \[EHat]tre d\[EAcute]sinstall\[EAcute] car il est fourni par le paquet `1`.", + +"PreferencesContentNotebooksTab" -> "Notebooks", +"PreferencesContentPersonasTab" -> "Personnages", +"PreferencesContentServicesTab" -> "Services", +"PreferencesContentToolsTab" -> "Outils", +"PreferencesContentEnableAssistanceLabel" -> "Activer l\[CloseCurlyQuote]assistance automatique", +"PreferencesContentEnableAssistanceTooltip" -> "Si cette option est activ\[EAcute]e, des suggestions automatiques fournies par l\[CloseCurlyQuote]IA seront ajout\[EAcute]es en fonction des r\[EAcute]sultats de l\[CloseCurlyQuote]\[EAcute]valuation.", +"PreferencesContentPersonaLabel" -> "Personnage\[NonBreakingSpace]:", +"PreferencesContentLLMServiceLabel" -> "Service LLM\[NonBreakingSpace]:", +"PreferencesContentModelLabel" -> "Mod\[EGrave]le\[NonBreakingSpace]:", +"PreferencesContentTemperatureLabel" -> "Temp\[EAcute]rature\[NonBreakingSpace]:", +"PreferencesContentSubsectionChat" -> "Cellules du notebook de chat", +"PreferencesContentFormatOutputLabel" -> "Mise en forme de la sortie du chat", +"PreferencesContentIncludeHistoryLabel" -> "Inclure l\[CloseCurlyQuote]historique du chat", +"PreferencesContentIncludeHistoryTooltip" -> "Si cette option est activ\[EAcute]e, les cellules pr\[EAcute]c\[EAcute]dant l\[CloseCurlyQuote]entr\[EAcute]e du chat seront incluses en tant que contexte suppl\[EAcute]mentaire pour le LLM.", +"PreferencesContentHistoryLengthLabel" -> "Longueur de l\[CloseCurlyQuote]historique du chat\[NonBreakingSpace]:", +"PreferencesContentHistoryLengthTooltip" -> "Nombre maximum de cellules \[AGrave] inclure dans l\[CloseCurlyQuote]historique du chat", +"PreferencesContentMergeChatLabel" -> "Fusionner les messages du chat", +"PreferencesContentMergeChatTooltip" -> "Si cette option est activ\[EAcute]e, les cellules adjacentes ayant le m\[EHat]me auteur seront fusionn\[EAcute]es en un seul message de chat.", +"PreferencesContentSubsectionFeatures" -> "Fonctionnalit\[EAcute]s", +"PreferencesContentEnableMultimodalLabel" -> "Activer le contenu multimodal\[NonBreakingSpace]: ", +"PreferencesContentEnableTools" -> "Activer les outils\[NonBreakingSpace]: ", +"PreferencesContentToolCallFrequency" -> "Fr\[EAcute]quence d\[CloseCurlyQuote]appel des outils\[NonBreakingSpace]:", +"PreferencesContentSubsectionRegisteredServices" -> "Services enregistr\[EAcute]s", +"PreferencesContentService" -> "Service", +"PreferencesContentServiceConnectButton" -> "Se connecter pour la liste des mod\[EGrave]les", +"PreferencesContentAuthentication" -> "Authentification", +"PreferencesContentUnregisterTooltip" -> "Annuler la connexion au service", +"PreferencesContentOpenAICompletionURLLabel" -> "URL compl\[EGrave]te du chat\[NonBreakingSpace]:", + +"ResourceInstallerFromURLPrompt" -> "Entrer une URL", + +"ToolManagerTitle" -> "Ajouter et g\[EAcute]rer des outils LLM", +"ToolManagerInstallTools" -> "Installer des outils", +"ToolManagerInstallFrom" -> "Installer \[AGrave] partir de", +"ToolManagerInstallFromLLMToolRepo" -> "R\[EAcute]f\[EAcute]rentiel d\[CloseCurlyQuote]outils LLM \[UpperRightArrow]", +"ToolManagerManageTools" -> "G\[EAcute]rer et activer les outils", +"ToolManagerShowEnabledFor" -> "Afficher les outils activ\[EAcute]s pour\[NonBreakingSpace]:", +"ToolManagerTool" -> "Outil", +"ToolManagerEnabledFor" -> "Activ\[EAcute] pour\[NonBreakingSpace]:", +"ToolManagerEnabledByPersona" -> "Activ\[EAcute] par personnage", +"ToolManagerEnabledNever" -> "Jamais activ\[EAcute]", +"ToolManagerEnabledAlways" -> "Toujours activ\[EAcute]", +"ToolManagerTooltipNonConfigurable" -> "`name` n\[CloseCurlyQuote]a pas de param\[EGrave]tres configurables.", +"ToolManagerTooltipNonDeletable1" -> "`name` est un outil int\[EAcute]gr\[EAcute] et ne peut pas \[EHat]tre supprim\[EAcute].", +"ToolManagerTooltipNonDeletable2" -> "`name` est fourni par le personnage `persona` et ne peut pas \[EHat]tre supprim\[EAcute] s\[EAcute]par\[EAcute]ment.", +"ToolManagerDeleteTool" -> "Supprimer l\[CloseCurlyQuote]outil", + +"UIEnableChatFeatures" -> "Activer les fonctions de chat de l\[CloseCurlyQuote]IA", +"UIAutomaticAnalysisLabel" -> "Effectuer une analyse automatique des r\[EAcute]sultats", +"UIAutomaticAnalysisTooltip" -> "Si cette option est activ\[EAcute]e, des suggestions automatiques fournies par l\[CloseCurlyQuote]IA seront ajout\[EAcute]es en fonction des r\[EAcute]sultats de l\[CloseCurlyQuote]\[EAcute]valuation.", +"UIPersonas" -> "Personnages", +"UIChatBlockSettings" -> "Param\[EGrave]tres de blocage du chat\[Ellipsis]", +"UIAddAndManagePersonas" -> "Ajouter et g\[EAcute]rer des personnages\[Ellipsis]", +"UIAddAndManageTools" -> "Ajouter et g\[EAcute]rer des outils\[Ellipsis]", +"UIModels" -> "Mod\[EGrave]les", +"UIModelsServices" -> "Services", +"UIModelsGet" -> "Obtenir les mod\[EGrave]les disponibles\[Ellipsis]", +"UIModelsNoList" -> "Se connecter pour obtenir la liste des mod\[EGrave]les", +"UIModelsFineTuned" -> "Mod\[EGrave]les affin\[EAcute]s", +"UIModelsSnapshot" -> "Mod\[EGrave]les d\[CloseCurlyQuote]instantan\[EAcute]s", +"UIModelsPreview" -> "Pr\[EAcute]visualiser les mod\[EGrave]les", +"UIAdvancedSettings" -> "Param\[EGrave]tres avanc\[EAcute]s", +"UIAdvancedTemperature" -> "Temp\[EAcute]rature", +"UIAdvancedToolCallFrequency" -> "Fr\[EAcute]quence d\[CloseCurlyQuote]appel de l\[CloseCurlyQuote]outil", +"UIAdvancedChooseAutomatically" -> "Choisir automatiquement", +"UIAdvancedRoles" -> "Choisir automatiquement", +"UITryEnableChatDialogMainText" -> "L\[CloseCurlyQuote]activation de la fonctionnalit\[EAcute] du notebook de chat d\[EAcute]truira les styles priv\[EAcute]s d\[EAcute]finis dans ce notebook et les remplacera par la feuille de style du chatbook partag\[EAcute]e.", +"UITryEnableChatDialogConfirm" -> "Etes-vous s\[UHat]r de vouloir continuer\[NonBreakingSpace]?", + +"StylesheetChatWidgetButtonTooltip" -> "Envoyer au LLM", +"StylesheetAssistantMenuInitializerButtonTooltip" -> "D\[EAcute]sactiver l\[CloseCurlyQuote]assistance automatique", +"StylesheetFeedbackButtonTooltip" -> "Envoyer un commentaire \[AGrave] Wolfram", +"StylesheetExplodeCellsInPlace" -> "\[CapitalEAcute]clater les cellules (en place)", +"StylesheetExplodeCellsDuplicate" -> "\[CapitalEAcute]clater les cellules (dupliquer)", +"StylesheetCopyExplodedCells" -> "Copier les cellules \[EAcute]clat\[EAcute]es", +"StylesheetToggleFormatting" -> "Basculer la mise en forme", +"StylesheetCopyChatObject" -> "Copier l\[CloseCurlyQuote]objet de Chat", +"StylesheetInsertionMenuChatInput" -> "Entr\[EAcute]e de chat", +"StylesheetInsertionMenuSideChat" -> "Chat lat\[EAcute]ral", + +"PersonaNameBirdnardo" -> "Birdnardo", +"PersonaNameCodeAssistant" -> "Assistant de code", +"PersonaNameCodeWriter" -> "R\[EAcute]dacteur de code", +"PersonaNamePlainChat" -> "Chat simple", +"PersonaNameRawModel" -> "Mod\[EGrave]le brut", +"PersonaNameWolfie" -> "Wolfie", + +"AttachedChatFieldHint" -> "Demandez\[Hyphen]moi quelque chose" +} +@| +@| +@@resource ChatbookLocalizableBitmaps +{ +} +@| \ No newline at end of file diff --git a/FrontEnd/TextResources/Japanese/ChatbookStrings.tr b/FrontEnd/TextResources/Japanese/ChatbookStrings.tr new file mode 100644 index 00000000..ba877dd0 --- /dev/null +++ b/FrontEnd/TextResources/Japanese/ChatbookStrings.tr @@ -0,0 +1,180 @@ +@@resource ChatbookStrings +{ +"ConnectButton" -> "\:63a5\:7d9a", +"DisconnectButton" -> "\:5207\:65ad", +"OKButton" -> "OK", +"CancelButton" -> "\:30ad\:30e3\:30f3\:30bb\:30eb", +"DeleteButton" -> "\:524a\:9664", +"SendButton" -> "\:9001\:4fe1", +"URLButton" -> "URL", +"ScopeGlobal" -> "\:30b0\:30ed\:30fc\:30d0\:30eb", +"ScopeNotebook" -> "\:9078\:629e\:3055\:308c\:3066\:3044\:308b\:30ce\:30fc\:30c8\:30d6\:30c3\:30af", +"ScopeCells" -> "\:9078\:629e\:7bc4\:56f2", +"EnabledByModel" -> "\:30e2\:30c7\:30eb\:3067\:81ea\:52d5", +"EnabledByPersona" -> "\:30da\:30eb\:30bd\:30ca\:3067\:81ea\:52d5", +"EnabledAlways" -> "\:5e38\:306b\:6709\:52b9", +"EnabledNever" -> "\:5e38\:306b\:7121\:52b9", +"EnabledNever2" -> "\:6c7a\:3057\:3066\:6709\:52b9\:306b\:3057\:306a\:3044", +"Always" -> "\:5e38\:306b\:3059\:308b", +"Never" -> "\:6c7a\:3057\:3066\:3057\:306a\:3044", +"Automatic" -> "\:81ea\:52d5", +"Custom" -> "\:30ab\:30b9\:30bf\:30e0", +"Rare" -> "\:305f\:307e\:306b\:3059\:308b", +"Often" -> "\:3057\:3070\:3057\:3070\:3059\:308b", + +"ActionsAPIKeyDialogTitle" -> "OpenAI\:306eAPI\:30ad\:30fc\:3092\:5165\:529b\:3057\:3066\:304f\:3060\:3055\:3044", +"ActionsAPIKeyDialogAPIKey" -> "API\:30ad\:30fc", +"ActionsAPIKeyDialogSave" -> "\:4fdd\:5b58", +"APIKeyDialogCreateKeyTemplate" -> "\:307e\:3060API\:30ad\:30fc\:3092\:304a\:6301\:3061\:3067\:306a\:3044\:5834\:5408\:306f\:ff0c`1`\:304c1\:3064\:4f5c\:6210\:3067\:304d\:307e\:3059\:ff0e", +"APIKeyDialogSaveKeyTemplate" -> "\:4eca\:5f8c\:3053\:306e\:30c0\:30a4\:30a2\:30ed\:30b0\:304c\:8868\:793a\:3055\:308c\:306a\:3044\:3088\:3046\:306b\:3057\:305f\:3051\:308c\:3070\:ff0c\:300c\:4fdd\:5b58\:300d\:3092\:9078\:3073\:ff0c\:30ad\:30fc\:3092`1`\:306b\:4fdd\:5b58\:3057\:3066\:304f\:3060\:3055\:3044\:ff0e", + +"ChatContextDialogSystemPromptText" -> "\:30b7\:30b9\:30c6\:30e0\:30d7\:30ed\:30f3\:30d7\:30c8\:30c6\:30ad\:30b9\:30c8", +"ChatContextDialogCellProcessingFunction" -> "\:30bb\:30eb\:51e6\:7406\:306e\:95a2\:6570", +"ChatContextDialogCellPostEvaluationFunction" -> "\:30bb\:30eb\:8a55\:4fa1\:5f8c\:306e\:95a2\:6570", +"ChatContextDialogDescription" -> "\:3053\:308c\:306f\:4f55\:3092\:3059\:3079\:304d\:304b\:3092\:6307\:793a\:3059\:308b\:30c6\:30ad\:30b9\:30c8\:3067\:3059\:ff0e", +"ChatContextDialogClickForMoreInfo" -> "\:30af\:30ea\:30c3\:30af\:3057\:3066\:8a73\:7d30\:3092\:3054\:89a7\:304f\:3060\:3055\:3044", + +"ChatToolbarInsertChatCell" -> "\:30c1\:30e3\:30c3\:30c8\:30bb\:30eb\:306e\:633f\:5165", +"ChatToolbarChatSettings" -> "\:30c1\:30e3\:30c3\:30c8\:306e\:8a2d\:5b9a", +"ChatToolbarChatDrivenLabel" -> "\:30c1\:30e3\:30c3\:30c8\:99c6\:52d5\:578b\:30ce\:30fc\:30c8\:30d6\:30c3\:30af", +"ChatToolbarChatEnabledLabel" -> "\:30c1\:30e3\:30c3\:30c8\:6709\:52b9\:30ce\:30fc\:30c8\:30d6\:30c3\:30af", + +"DefaultToolsLinks" -> "\:30ea\:30f3\:30af", + +"FeedbackChatMessagesContent" -> "\:30c1\:30e3\:30c3\:30c8\:30e1\:30c3\:30bb\:30fc\:30b8", +"FeedbackChatMessagesTooltip" -> "\:3053\:306e\:30c1\:30e3\:30c3\:30c8\:51fa\:529b\:306e\:4f5c\:6210\:306b\:95a2\:4fc2\:304c\:3042\:308b\:30c1\:30e3\:30c3\:30c8\:30e1\:30c3\:30bb\:30fc\:30b8\:ff0e", +"FeedbackSystemMessageContent" -> "\:30b7\:30b9\:30c6\:30e0\:30e1\:30c3\:30bb\:30fc\:30b8", +"FeedbackSystemMessageTooltip" -> "AI\:306b\:6307\:793a\:3092\:51fa\:3059\:305f\:3081\:306b\:4f7f\:308f\:308c\:308b\:57fa\:672c\:306e\:30b7\:30b9\:30c6\:30e0\:30e1\:30c3\:30bb\:30fc\:30b8\:ff0e", +"FeedbackChatHistoryContent" -> "\:3053\:306e\:51fa\:529b\:3092\:751f\:6210\:3059\:308b\:305f\:3081\:306b\:4f7f\:308f\:308c\:308b\:30c1\:30e3\:30c3\:30c8\:5c65\:6b74", +"FeedbackChatHistoryTooltip" -> "\:3053\:306e\:51fa\:529b\:3092\:751f\:6210\:3059\:308b\:305f\:3081\:306e\:4f1a\:8a71\:5c65\:6b74\:3068\:3057\:3066\:4f7f\:308f\:308c\:305f\:8ffd\:52a0\:306e\:30e1\:30c3\:30bb\:30fc\:30b8\:ff0e", +"FeedbackChatImageContent" -> "\:30c1\:30e3\:30c3\:30c8\:51fa\:529b\:306e\:753b\:50cf", +"FeedbackChatImageTooltip" -> "\:30c1\:30e3\:30c3\:30c8\:51fa\:529b\:306e\:30b9\:30af\:30ea\:30fc\:30f3\:30b7\:30e7\:30c3\:30c8\:ff0e\:3053\:308c\:306f\:30d5\:30a3\:30fc\:30c9\:30d0\:30c3\:30af\:304c\:51fa\:529b\:306e\:5916\:89b3\:306b\:95a2\:4fc2\:3057\:3066\:3044\:308b\:5834\:5408\:306b\:4f7f\:3048\:307e\:3059\:ff0e", +"FeedbackDialogHeader" -> "Wolfram\:306bAI\:30c1\:30e3\:30c3\:30c8\:306e\:30d5\:30a3\:30fc\:30c9\:30d0\:30c3\:30af\:3092\:9001\:4fe1\:3059\:308b", +"FeedbackDialogBodyThumbs" -> "\:30d5\:30a3\:30fc\:30c9\:30d0\:30c3\:30af\:3092\:3054\:9001\:4fe1\:3044\:305f\:3060\:304f\:3068\:ff0c\:5f0a\:793e\:306eAI\:6a5f\:80fd\:306e\:5411\:4e0a\:306b\:5f79\:7acb\:3061\:307e\:3059\:ff0e", +"FeedbackDialogContentIncludedLabel" -> "\:542b\:307e\:308c\:308b\:30b3\:30f3\:30c6\:30f3\:30c4\:ff1a", +"FeedbackDialogContentOutputImageLabel" -> "\:51fa\:529b\:753b\:50cf", +"FeedbackDialogCommentFieldHint" -> "\:4ed6\:306b\:3082\:30d5\:30a3\:30fc\:30c9\:30d0\:30c3\:30af\:304c\:3042\:308a\:307e\:3059\:304b\:ff1f\:ff08\:4efb\:610f\:ff09", +"FeedbackDialogBodyUsedForTraining" -> "\:304a\:5ba2\:69d8\:306e\:30c1\:30e3\:30c3\:30c8\:5c65\:6b74\:3068\:30d5\:30a3\:30fc\:30c9\:30d0\:30c3\:30af\:306f\:8a13\:7df4\:306e\:305f\:3081\:306b\:4f7f\:308f\:308c\:308b\:3053\:3068\:304c\:3042\:308a\:307e\:3059\:ff0e", +"FeedbackDialogBodyPreviewData" -> "\:9001\:4fe1\:3059\:308b\:30c7\:30fc\:30bf\:306e\:30d7\:30ec\:30d3\:30e5\:30fc", +"FeedbackDialogThanks" -> "\:30d5\:30a3\:30fc\:30c9\:30d0\:30c3\:30af\:306e\:9001\:4fe1\:ff0c\:3042\:308a\:304c\:3068\:3046\:3054\:3056\:3044\:307e\:3057\:305f\:ff01", + +"FormattingInsertContentAndEvaluateTooltip" -> "\:30b3\:30f3\:30c6\:30f3\:30c4\:3092\:65b0\:898f\:306e\:5165\:529b\:30bb\:30eb\:3068\:3057\:3066\:4e0b\:306b\:633f\:5165\:3057\:8a55\:4fa1\:3059\:308b", +"FormattingCopyToClipboardTooltip" -> "\:30af\:30ea\:30c3\:30d7\:30dc\:30fc\:30c9\:306b\:30b3\:30d4\:30fc", +"FormattingInsertContentTooltip" -> "\:30b3\:30f3\:30c6\:30f3\:30c4\:3092\:65b0\:898f\:306e\:5165\:529b\:30bb\:30eb\:3068\:3057\:3066\:4e0b\:306b\:633f\:5165\:3059\:308b", + +"InlineReferencesFieldHint" -> "\:30d7\:30ed\:30f3\:30d7\:30c8\:540d", +"InlineReferencesInsertLabel" -> "\:633f\:5165\:ff1a", +"InlineReferencesInsertPersonaPrompt" -> "\:30da\:30eb\:30bd\:30ca\:540d\:3092\:5165\:529b\:3057\:3066\:304f\:3060\:3055\:3044", +"InlineReferencesInsertPersonaFail" -> "\"`name`\"\:3068\:3044\:3046\:540d\:524d\:306e\:30da\:30eb\:30bd\:30ca\:306f\:898b\:4ed8\:304b\:308a\:307e\:305b\:3093\:ff0e", +"InlineReferencesInsertModifierPrompt" -> "\:4fee\:98fe\:5b50\:30d7\:30ed\:30f3\:30d7\:30c8\:3092\:5165\:529b\:3057\:3066\:304f\:3060\:3055\:3044", +"InlineReferencesInsertModifierFail" -> "\"`name`\"\:3068\:3044\:3046\:540d\:524d\:306e\:4fee\:98fe\:5b50\:306f\:898b\:4ed8\:304b\:308a\:307e\:305b\:3093\:ff0e", +"InlineReferencesInsertFunctionPrompt" -> "\:95a2\:6570\:30d7\:30ed\:30f3\:30d7\:30c8\:3092\:5165\:529b\:3057\:3066\:304f\:3060\:3055\:3044", +"InlineReferencesInsertFunctionFail" -> "\"`name`\"\:3068\:3044\:3046\:540d\:524d\:306e\:95a2\:6570\:306f\:898b\:4ed8\:304b\:308a\:307e\:305b\:3093\:ff0e", + +"PersonaManagerTitle" -> "\:30da\:30eb\:30bd\:30ca\:306e\:8ffd\:52a0\:3068\:7ba1\:7406", +"PersonaManagerInstallPersonas" -> "\:30da\:30eb\:30bd\:30ca\:306e\:30a4\:30f3\:30b9\:30c8\:30fc\:30eb", +"PersonaManagerInstallFrom" -> "\:6b21\:304b\:3089\:30a4\:30f3\:30b9\:30c8\:30fc\:30eb\:ff1a", +"PersonaManagerInstallFromPromptRepo" -> "Prompt Repository \[UpperRightArrow]", +"PersonaManagerManagePersonas" -> "\:30da\:30eb\:30bd\:30ca\:306e\:7ba1\:7406\:3068\:6709\:52b9\:5316", +"PersonaManagerInMenu" -> "\:30e1\:30cb\:30e5\:30fc", +"PersonaManagerName" -> "\:540d\:524d", +"PersonaManagerVersion" -> "\:30d0\:30fc\:30b8\:30e7\:30f3", +"PersonaManagerOriginChatbookTooltip" -> "Wolfram/Chatbook\:30d1\:30af\:30ec\:30c3\:30c8\:304b\:3089\:30a4\:30f3\:30b9\:30c8\:30fc\:30eb\:3057\:305f\:30da\:30eb\:30bd\:30ca\:ff0e\:30da\:30fc\:30b8\:3092\:898b\:308b \[RightGuillemet]", +"PersonaManagerOriginRepositoryTooltip" -> "`name`\:30d1\:30af\:30ec\:30c3\:30c8\:304b\:3089\:30a4\:30f3\:30b9\:30c8\:30fc\:30eb\:3057\:305f\:30da\:30eb\:30bd\:30ca\:ff0e\:30da\:30fc\:30b8\:3092\:898b\:308b \[RightGuillemet]", +"PersonaManagerPersonaUninstallTooltip" -> "\:3053\:306e\:30da\:30eb\:30bd\:30ca\:306f`1`\:30d1\:30af\:30ec\:30c3\:30c8\:306b\:3088\:3063\:3066\:63d0\:4f9b\:3055\:308c\:308b\:3082\:306e\:306a\:306e\:3067\:30a2\:30f3\:30a4\:30f3\:30b9\:30c8\:30fc\:30eb\:3067\:304d\:307e\:305b\:3093\:ff0e", + +"PreferencesContentNotebooksTab" -> "\:30ce\:30fc\:30c8\:30d6\:30c3\:30af", +"PreferencesContentPersonasTab" -> "\:30da\:30eb\:30bd\:30ca", +"PreferencesContentServicesTab" -> "\:30b5\:30fc\:30d3\:30b9", +"PreferencesContentToolsTab" -> "\:30c4\:30fc\:30eb", +"PreferencesContentEnableAssistanceLabel" -> "\:81ea\:52d5\:30a2\:30b7\:30b9\:30bf\:30f3\:30c8\:3092\:6709\:52b9\:5316", +"PreferencesContentEnableAssistanceTooltip" -> "\:6709\:52b9\:306b\:3059\:308b\:3068\:ff0cAI\:304c\:81ea\:52d5\:7684\:306b\:63d0\:4f9b\:3059\:308b\:63d0\:6848\:304c\:4ee5\:4e0b\:306e\:8a55\:4fa1\:7d50\:679c\:306b\:8ffd\:52a0\:3055\:308c\:307e\:3059\:ff0e", +"PreferencesContentPersonaLabel" -> "\:30da\:30eb\:30bd\:30ca\:ff1a", +"PreferencesContentLLMServiceLabel" -> "\:5927\:898f\:6a21\:8a00\:8a9e\:30e2\:30c7\:30eb\:30b5\:30fc\:30d3\:30b9\:ff1a", +"PreferencesContentModelLabel" -> "\:30e2\:30c7\:30eb\:ff1a", +"PreferencesContentTemperatureLabel" -> "\:6e29\:5ea6\:ff1a", +"PreferencesContentSubsectionChat" -> "\:30c1\:30e3\:30c3\:30c8\:30ce\:30fc\:30c8\:30d6\:30c3\:30af\:30bb\:30eb", +"PreferencesContentFormatOutputLabel" -> "\:30c1\:30e3\:30c3\:30c8\:51fa\:529b\:306e\:66f8\:5f0f\:8a2d\:5b9a", +"PreferencesContentIncludeHistoryLabel" -> "\:30c1\:30e3\:30c3\:30c8\:5c65\:6b74\:3092\:542b\:3081\:308b", +"PreferencesContentIncludeHistoryTooltip" -> "\:6709\:52b9\:306b\:3059\:308b\:3068\:ff0c\:5927\:898f\:6a21\:8a00\:8a9e\:30e2\:30c7\:30eb\:306e\:8ffd\:52a0\:30b3\:30f3\:30c6\:30ad\:30b9\:30c8\:3068\:3057\:3066\:ff0c\:30c1\:30e3\:30c3\:30c8\:5165\:529b\:306b\:5148\:884c\:3059\:308b\:30bb\:30eb\:304c\:542b\:307e\:308c\:307e\:3059\:ff0e", +"PreferencesContentHistoryLengthLabel" -> "\:30c1\:30e3\:30c3\:30c8\:5c65\:6b74\:306e\:9577\:3055\:ff1a", +"PreferencesContentHistoryLengthTooltip" -> "\:30c1\:30e3\:30c3\:30c8\:5c65\:6b74\:306b\:542b\:3081\:308b\:6700\:5927\:30bb\:30eb\:6570", +"PreferencesContentMergeChatLabel" -> "\:30c1\:30e3\:30c3\:30c8\:30e1\:30c3\:30bb\:30fc\:30b8\:306e\:7d71\:5408", +"PreferencesContentMergeChatTooltip" -> "\:6709\:52b9\:306b\:3059\:308b\:3068\:ff0c\:540c\:4e00\:306e\:30c1\:30e3\:30c3\:30c8\:4f5c\:6210\:8005\:306b\:3088\:308b\:96a3\:63a5\:30bb\:30eb\:304c1\:3064\:306e\:30c1\:30e3\:30c3\:30c8\:30e1\:30c3\:30bb\:30fc\:30b8\:306b\:7d71\:5408\:3055\:308c\:307e\:3059\:ff0e", +"PreferencesContentSubsectionFeatures" -> "\:6a5f\:80fd", +"PreferencesContentEnableMultimodalLabel" -> "\:30de\:30eb\:30c1\:30e2\:30fc\:30c0\:30eb\:30b3\:30f3\:30c6\:30f3\:30c4\:306e\:6709\:52b9\:5316\:ff1a", +"PreferencesContentEnableTools" -> "\:30c4\:30fc\:30eb\:306e\:6709\:52b9\:5316\:ff1a", +"PreferencesContentToolCallFrequency" -> "\:30c4\:30fc\:30eb\:547c\:51fa\:3057\:306e\:983b\:5ea6\:ff1a", +"PreferencesContentSubsectionRegisteredServices" -> "\:767b\:9332\:3055\:308c\:305f\:30b5\:30fc\:30d3\:30b9", +"PreferencesContentService" -> "\:30b5\:30fc\:30d3\:30b9", +"PreferencesContentServiceConnectButton" -> "\:30e2\:30c7\:30eb\:30ea\:30b9\:30c8\:306b\:63a5\:7d9a", +"PreferencesContentAuthentication" -> "\:8a8d\:8a3c", +"PreferencesContentUnregisterTooltip" -> "\:30b5\:30fc\:30d3\:30b9\:63a5\:7d9a\:306e\:767b\:9332\:53d6\:6d88\:3057", +"PreferencesContentOpenAICompletionURLLabel" -> "\:30c1\:30e3\:30c3\:30c8\:5b8c\:4e86\:306eURL\:ff1a", + +"ResourceInstallerFromURLPrompt" -> "URL\:3092\:5165\:529b\:3057\:3066\:304f\:3060\:3055\:3044", + +"ToolManagerTitle" -> "\:5927\:898f\:6a21\:8a00\:8a9e\:30c4\:30fc\:30eb\:306e\:8ffd\:52a0\:3068\:7ba1\:7406", +"ToolManagerInstallTools" -> "\:30c4\:30fc\:30eb\:306e\:30a4\:30f3\:30b9\:30c8\:30fc\:30eb", +"ToolManagerInstallFrom" -> "\:6b21\:304b\:3089\:30a4\:30f3\:30b9\:30c8\:30fc\:30eb\:ff1a", +"ToolManagerInstallFromLLMToolRepo" -> "LLM Tool Repository \[UpperRightArrow]", +"ToolManagerManageTools" -> "\:30c4\:30fc\:30eb\:306e\:7ba1\:7406\:3068\:6709\:52b9\:5316", +"ToolManagerShowEnabledFor" -> "\:6b21\:306b\:3064\:3044\:3066\:6709\:52b9\:5316\:3055\:308c\:305f\:30c4\:30fc\:30eb\:3092\:8868\:793a\:ff1a", +"ToolManagerTool" -> "\:30c4\:30fc\:30eb", +"ToolManagerEnabledFor" -> "\:6b21\:306b\:3064\:3044\:3066\:6709\:52b9\:5316\[VeryThinSpace]\:ff1a", +"ToolManagerEnabledByPersona" -> "\:30da\:30eb\:30bd\:30ca\:3067\:6709\:52b9\:5316", +"ToolManagerEnabledNever" -> "\:5e38\:306b\:7121\:52b9", +"ToolManagerEnabledAlways" -> "\:5e38\:306b\:6709\:52b9", +"ToolManagerTooltipNonConfigurable" -> "`name`\:306b\:306f\:8a2d\:5b9a\:53ef\:80fd\:306a\:30d1\:30e9\:30e1\:30fc\:30bf\:304c\:3042\:308a\:307e\:305b\:3093\:ff0e", +"ToolManagerTooltipNonDeletable1" -> "`name`\:306f\:7d44\:8fbc\:307f\:306e\:30c4\:30fc\:30eb\:306a\:306e\:3067\:524a\:9664\:3067\:304d\:307e\:305b\:3093\:ff0e", +"ToolManagerTooltipNonDeletable2" -> "`name`\:306f\:30da\:30eb\:30bd\:30ca`persona`\:306b\:3088\:3063\:3066\:63d0\:4f9b\:3055\:308c\:305f\:3082\:306e\:3067\:ff0c\:500b\:5225\:306b\:524a\:9664\:3059\:308b\:3053\:3068\:306f\:3067\:304d\:307e\:305b\:3093\:ff0e", +"ToolManagerDeleteTool" -> "\:30c4\:30fc\:30eb\:306e\:524a\:9664", + +"UIEnableChatFeatures" -> "AI\:30c1\:30e3\:30c3\:30c8\:6a5f\:80fd\:306e\:6709\:52b9\:5316", +"UIAutomaticAnalysisLabel" -> "\:81ea\:52d5\:7684\:306b\:7d50\:679c\:5206\:6790\:3092\:884c\:3046", +"UIAutomaticAnalysisTooltip" -> "\:6709\:52b9\:306b\:3059\:308b\:3068\:ff0c\:81ea\:52d5\:7684\:306bAI\:304c\:63d0\:4f9b\:3059\:308b\:63d0\:6848\:304c\:4ee5\:4e0b\:306e\:8a55\:4fa1\:7d50\:679c\:306b\:8ffd\:52a0\:3055\:308c\:307e\:3059\:ff0e", +"UIPersonas" -> "\:30da\:30eb\:30bd\:30ca", +"UIChatBlockSettings" -> "\:30c1\:30e3\:30c3\:30c8\:30d6\:30ed\:30c3\:30af\:306e\:8a2d\:5b9a\[Ellipsis]", +"UIAddAndManagePersonas" -> "\:30da\:30eb\:30bd\:30ca\:306e\:8ffd\:52a0\:3068\:7ba1\:7406\[Ellipsis]", +"UIAddAndManageTools" -> "\:30c4\:30fc\:30eb\:306e\:8ffd\:52a0\:3068\:7ba1\:7406\[Ellipsis]", +"UIModels" -> "\:30e2\:30c7\:30eb", +"UIModelsServices" -> "\:30b5\:30fc\:30d3\:30b9", +"UIModelsGet" -> "\:4f7f\:7528\:53ef\:80fd\:306a\:30e2\:30c7\:30eb\:3092\:53d6\:5f97\:3057\:3066\:3044\:307e\:3059\[Ellipsis]", +"UIModelsNoList" -> "\:30e2\:30c7\:30eb\:30ea\:30b9\:30c8\:3078\:306e\:63a5\:7d9a", +"UIModelsFineTuned" -> "\:5fae\:8abf\:6574\:3055\:308c\:305f\:30e2\:30c7\:30eb", +"UIModelsSnapshot" -> "\:30e2\:30c7\:30eb\:306e\:30b9\:30ca\:30c3\:30d7\:30b7\:30e7\:30c3\:30c8", +"UIModelsPreview" -> "\:30e2\:30c7\:30eb\:306e\:30d7\:30ec\:30d3\:30e5\:30fc", +"UIAdvancedSettings" -> "\:8a73\:7d30\:8a2d\:5b9a", +"UIAdvancedTemperature" -> "\:6e29\:5ea6", +"UIAdvancedToolCallFrequency" -> "\:30c4\:30fc\:30eb\:547c\:51fa\:3057\:306e\:983b\:5ea6", +"UIAdvancedChooseAutomatically" -> "\:81ea\:52d5\:7684\:306b\:9078\:629e\:3059\:308b", +"UIAdvancedRoles" -> "\:5f79\:5272", +"UITryEnableChatDialogMainText" -> "\:30c1\:30e3\:30c3\:30c8\:30ce\:30fc\:30c8\:30d6\:30c3\:30af\:306e\:6a5f\:80fd\:3092\:6709\:52b9\:306b\:3059\:308b\:3068\:ff0c\:3053\:306e\:30ce\:30fc\:30c8\:30d6\:30c3\:30af\:306b\:5b9a\:7fa9\:3055\:308c\:305f\:30b9\:30bf\:30a4\:30eb\:304c\:7834\:68c4\:3055\:308c\:ff0c\:5171\:6709\:306eChatbook\:30b9\:30bf\:30a4\:30eb\:30b7\:30fc\:30c8\:3067\:7f6e\:63db\:3055\:308c\:307e\:3059\:ff0e", +"UITryEnableChatDialogConfirm" -> "\:7d9a\:884c\:3057\:307e\:3059\:304b\:ff1f", + +"StylesheetChatWidgetButtonTooltip" -> "\:5927\:898f\:6a21\:8a00\:8a9e\:30e2\:30c7\:30eb\:306b\:9001\:4fe1", +"StylesheetAssistantMenuInitializerButtonTooltip" -> "\:81ea\:52d5\:30a2\:30b7\:30b9\:30bf\:30f3\:30c8\:3092\:7121\:52b9\:306b\:3059\:308b", +"StylesheetFeedbackButtonTooltip" -> "\:30d5\:30a3\:30fc\:30c9\:30d0\:30c3\:30af\:3092Wolfram\:306b\:9001\:4fe1\:3059\:308b", +"StylesheetExplodeCellsInPlace" -> "\:ff08\:3082\:3068\:306e\:ff09\:30bb\:30eb\:3092\:5206\:5272\:3059\:308b", +"StylesheetExplodeCellsDuplicate" -> "\:ff08\:30b3\:30d4\:30fc\:306e\:ff09\:30bb\:30eb\:3092\:5206\:5272\:3059\:308b", +"StylesheetCopyExplodedCells" -> "\:5206\:5272\:3057\:305f\:30bb\:30eb\:3092\:30b3\:30d4\:30fc\:3059\:308b", +"StylesheetToggleFormatting" -> "\:66f8\:5f0f\:8a2d\:5b9a\:3092\:5207\:308a\:66ff\:3048\:308b", +"StylesheetCopyChatObject" -> "ChatObject\:3092\:30b3\:30d4\:30fc\:3059\:308b", +"StylesheetInsertionMenuChatInput" -> "\:30c1\:30e3\:30c3\:30c8\:5165\:529b", +"StylesheetInsertionMenuSideChat" -> "\:30b5\:30a4\:30c9\:30c1\:30e3\:30c3\:30c8", + +"PersonaNameBirdnardo" -> "Birdnardo", +"PersonaNameCodeAssistant" -> "Code Assistant", +"PersonaNameCodeWriter" -> "Code Writer", +"PersonaNamePlainChat" -> "\:30d7\:30ec\:30fc\:30f3\:30c1\:30e3\:30c3\:30c8", +"PersonaNameRawModel" -> "\:672a\:52a0\:5de5\:306e\:30e2\:30c7\:30eb", +"PersonaNameWolfie" -> "Wolfie", + +"AttachedChatFieldHint" -> "\:4f55\:3067\:3082\:805e\:3044\:3066\:304f\:3060\:3055\:3044" +} +@| +@| +@@resource ChatbookLocalizableBitmaps +{ +} +@| \ No newline at end of file diff --git a/FrontEnd/TextResources/Korean/ChatbookStrings.tr b/FrontEnd/TextResources/Korean/ChatbookStrings.tr new file mode 100644 index 00000000..0a861cfc --- /dev/null +++ b/FrontEnd/TextResources/Korean/ChatbookStrings.tr @@ -0,0 +1,181 @@ +@@resource ChatbookStrings +{ +"ConnectButton" -> "\:C811\:C18D", +"DisconnectButton" -> "\:C811\:C18D \:B04A\:AE30", +"OKButton" -> "OK", +"CancelButton" -> "\:CDE8\:C18C", +"DeleteButton" -> "\:C0AD\:C81C", +"SendButton" -> "\:C804\:C1A1", +"URLButton" -> "URL", +"ScopeGlobal" -> "\:AE00\:B85C\:BC8C", +"ScopeNotebook" -> "\:C120\:D0DD\:D55C \:B178\:D2B8\:BD81", +"ScopeCells" -> "\:C120\:D0DD\:D55C \:C140", +"EnabledByModel" -> "\:BAA8\:B378\:C5D0\:C11C \:C790\:B3D9", +"EnabledByPersona" -> "\:D398\:B974\:C18C\:B098\:BCC4 \:C790\:B3D9", +"EnabledAlways" -> "\:D56D\:C0C1 \:D65C\:C131\:D654", +"EnabledNever" -> "\:D56D\:C0C1 \:BE44\:D65C\:C131\:D654", +"EnabledNever2" -> "\:D65C\:C131\:D654\:D558\:C9C0 \:C54A\:C74C", +"Always" -> "\:D56D\:C0C1", +"Never" -> "\:C808\:B300", +"Automatic" -> "\:C790\:B3D9", +"Custom" -> "\:C0AC\:C6A9\:C790 \:C815\:C758", +"Rare" -> "\:AC00\:B054", +"Often" -> "\:C790\:C8FC", + +"ActionsAPIKeyDialogTitle" -> "OpenAI\:C758 API \:D0A4\:B97C \:C785\:B825\:D558\:C138\:C694", +"ActionsAPIKeyDialogAPIKey" -> "API \:D0A4", +"ActionsAPIKeyDialogSave" -> "\:C800\:C7A5", +"APIKeyDialogCreateKeyTemplate" -> "\:C544\:C9C1 API \:D0A4\:AC00 \:C5C6\:C73C\:C2DC\:BA74 `1`\:C744 \:D558\:B098 \:B9CC\:B4E4 \:C218 \:C788\:C2B5\:B2C8\:B2E4.", +"APIKeyDialogSaveKeyTemplate" -> "\:C55E\:C73C\:B85C \:C774 \:B300\:D654 \:C0C1\:C790\:B97C \:BCF4\:C9C0 \:C54A\:C73C\:B824\:BA74, \"\:C800\:C7A5\"\:C744 \:C120\:D0DD\:D558\:ACE0 \:D0A4\:B97C `1`\:C5D0 \:C800\:C7A5\:D569\:B2C8\:B2E4.", + +"ChatContextDialogSystemPromptText" -> "\:C2DC\:C2A4\:D15C \:D504\:B86C\:D504\:D2B8 \:D14D\:C2A4\:D2B8", +"ChatContextDialogCellProcessingFunction" -> "\:C140 \:CC98\:B9AC \:D568\:C218", +"ChatContextDialogCellPostEvaluationFunction" -> "\:C140 \:D3C9\:AC00 \:D6C4\:C758 \:D568\:C218", +"ChatContextDialogDescription" -> "\:C774\:AC83\:C740 \:BB34\:C5C7\:C744 \:D574\:C57C \:D558\:B294\:C9C0 \:C9C0\:C2DC\:D558\:B294 \:D14D\:C2A4\:D2B8\:C785\:B2C8\:B2E4.", +"ChatContextDialogClickForMoreInfo" -> "\:D074\:B9AD\:D558\:C5EC \:C790\:C138\:D788 \:C54C\:C544\:BCF4\:AE30", + +"ChatToolbarInsertChatCell" -> "\:CC44\:D305 \:C140 \:C0BD\:C785", +"ChatToolbarChatSettings" -> "\:CC44\:D305 \:C124\:C815", +"ChatToolbarChatDrivenLabel" -> "\:CC44\:D305 \:AE30\:BC18 \:B178\:D2B8\:BD81", +"ChatToolbarChatEnabledLabel" -> "\:CC44\:D305 \:AC00\:B2A5\:D55C \:B178\:D2B8\:BD81", + +"DefaultToolsLinks" -> "\:B9C1\:D06C", + +"FeedbackChatMessagesContent" -> "\:CC44\:D305 \:BA54\:C2DC\:C9C0", +"FeedbackChatMessagesTooltip" -> "\:C774 \:CC44\:D305 \:CD9C\:B825 \:C0DD\:C131\:ACFC \:AD00\:B828\:B41C \:CC44\:D305 \:BA54\:C2DC\:C9C0.", +"FeedbackSystemMessageContent" -> "\:C2DC\:C2A4\:D15C \:BA54\:C2DC\:C9C0", +"FeedbackSystemMessageTooltip" -> "AI\:C5D0 \:C9C0\:CE68\:C744 \:C81C\:ACF5\:D558\:B294 \:B370 \:C0AC\:C6A9\:D558\:B294 \:AE30\:BCF8 \:C2DC\:C2A4\:D15C \:BA54\:C2DC\:C9C0", +"FeedbackChatHistoryContent" -> "\:C774 \:CD9C\:B825\:C744 \:C0DD\:C131\:D558\:B294 \:B370 \:C0AC\:C6A9\:B418\:B294 \:CC44\:D305 \:AE30\:B85D", +"FeedbackChatHistoryTooltip" -> "\:C774 \:CD9C\:B825\:C744 \:C0DD\:C131\:D558\:AE30 \:C704\:D574 \:B300\:D654 \:AE30\:B85D\:C73C\:B85C \:C0AC\:C6A9\:B41C \:CD94\:AC00 \:BA54\:C2DC\:C9C0.", +"FeedbackChatImageContent" -> "\:CC44\:D305 \:CD9C\:B825 \:C774\:BBF8\:C9C0", +"FeedbackChatImageTooltip" -> "\:CD9C\:B825\:C758 \:BAA8\:C2B5\:C5D0 \:AD00\:B828\:B41C \:D53C\:B4DC\:BC31\:C774 \:C788\:B294 \:ACBD\:C6B0 \:C0AC\:C6A9\:D560 \:C218 \:C788\:B294 \:CC44\:D305 \:CD9C\:B825\:C758 \:C2A4\:D06C\:B9B0\:C0F7.", +"FeedbackDialogHeader" -> "Wolfram\:C5D0 AI \:CC44\:D305 \:D53C\:B4DC\:BC31 \:BCF4\:B0B4\:AE30", +"FeedbackDialogBodyThumbs" -> "\:D53C\:B4DC\:BC31\:C744 \:BCF4\:B0B4 \:C8FC\:C2DC\:BA74 AI \:AE30\:B2A5\:C744 \:D5A5\:C0C1\:C2DC\:D0A4\:B294 \:B370 \:B3C4\:C6C0\:C774 \:B429\:B2C8\:B2E4.", +"FeedbackDialogContentIncludedLabel" -> "\:D3EC\:D568\:B41C \:CF58\:D150\:CE20:", +"FeedbackDialogContentOutputImageLabel" -> "\:CD9C\:B825 \:C774\:BBF8\:C9C0", +"FeedbackDialogCommentFieldHint" -> "\:B2E4\:B978 \:D53C\:B4DC\:BC31\:C774 \:C788\:C73C\:C2E0\:AC00\:C694? (\:C120\:D0DD)", +"FeedbackDialogBodyUsedForTraining" -> "\:ACE0\:AC1D\:C758 \:CC44\:D305 \:AE30\:B85D\:ACFC \:D53C\:B4DC\:BC31\:C740 \:AD50\:C721 \:BAA9\:C801\:C73C\:B85C \:C0AC\:C6A9\:B420 \:C218 \:C788\:C2B5\:B2C8\:B2E4.", +"FeedbackDialogBodyPreviewData" -> "\:C804\:C1A1\:D560 \:B370\:C774\:D130 \:BBF8\:B9AC\:BCF4\:AE30", +"FeedbackDialogThanks" -> "\:D53C\:B4DC\:BC31\:C744 \:BCF4\:B0B4 \:C8FC\:C154\:C11C \:AC10\:C0AC\:D569\:B2C8\:B2E4!", + +"FormattingInsertContentAndEvaluateTooltip" -> "\:C544\:B798\:C5D0 \:CF58\:D150\:CE20\:B97C \:C0C8 \:C785\:B825 \ +\:C140\:B85C \:C0BD\:C785\:D558\:ACE0 \:D3C9\:AC00", +"FormattingCopyToClipboardTooltip" -> "\:D074\:B9BD\:BCF4\:B4DC\:C5D0 \:BCF5\:C0AC", +"FormattingInsertContentTooltip" -> "\:CF58\:D150\:CE20\:B97C \:C0C8 \:C785\:B825 \:C140\:B85C \:C544\:B798\:C5D0 \:C0BD\:C785", + +"InlineReferencesFieldHint" -> "\:D504\:B86C\:D504\:D2B8 \:C774\:B984", +"InlineReferencesInsertLabel" -> "\:C0BD\:C785:", +"InlineReferencesInsertPersonaPrompt" -> "\:D398\:B974\:C18C\:B098 \:C774\:B984\:C744 \:C785\:B825", +"InlineReferencesInsertPersonaFail" -> "\"`name`\"\:C774\:B77C\:B294 \:C774\:B984\:C758 \:D398\:B974\:C18C\:B098\:B294 \:CC3E\:C744 \:C218 \:C5C6\:C2B5\:B2C8\:B2E4.", +"InlineReferencesInsertModifierPrompt" -> "\:C218\:C815\:C790 \:D504\:B86C\:D504\:D2B8\:B97C \:C785\:B825", +"InlineReferencesInsertModifierFail" -> "\"`name`\"\:C774\:B77C\:B294 \:C218\:C815\:C790\:B97C \:CC3E\:C744 \:C218 \:C5C6\:C2B5\:B2C8\:B2E4.", +"InlineReferencesInsertFunctionPrompt" -> "\:D568\:C218 \:D504\:B86C\:D504\:D2B8\:B97C \:C785\:B825", +"InlineReferencesInsertFunctionFail" -> "\"`name`\"\:C774\:B77C\:B294 \:D568\:C218\:B97C \:CC3E\:C744 \:C218 \:C5C6\:C2B5\:B2C8\:B2E4.", + +"PersonaManagerTitle" -> "\:D398\:B974\:C18C\:B098 \:CD94\:AC00 \:BC0F \:AD00\:B9AC", +"PersonaManagerInstallPersonas" -> "\:D398\:B974\:C18C\:B098 \:C124\:CE58", +"PersonaManagerInstallFrom" -> "\:B2E4\:C74C\:BD80\:D130 \:C124\:CE58", +"PersonaManagerInstallFromPromptRepo" -> "\:D504\:B86C\:D504\:D2B8 \:B9AC\:D3EC\:C9C0\:D1A0\:B9AC \[UpperRightArrow]", +"PersonaManagerManagePersonas" -> "\:D398\:B974\:C18C\:B098 \:AD00\:B9AC \:BC0F \:D65C\:C131\:D654", +"PersonaManagerInMenu" -> "\:BA54\:B274\:C5D0\:C11C", +"PersonaManagerName" -> "\:C774\:B984", +"PersonaManagerVersion" -> "\:BC84\:C804", +"PersonaManagerOriginChatbookTooltip" -> "Wolfram/Chatbook \:D328\:D074\:B9BF\:C5D0\:C11C \:C124\:CE58 \:D55C \:D398\:B974\:C18C\:B098. \:D398\:C774\:C9C0 \:BCF4\:AE30 \[RightGuillemet]", +"PersonaManagerOriginRepositoryTooltip" -> "`name` \:D328\:D074\:B9BF\:C5D0\:C11C \:C124\:CE58\:B41C \:D398\:B974\:C18C\:B098. \:D398\:C774\:C9C0 \:BCF4\:AE30 \[RightGuillemet].", +"PersonaManagerPersonaUninstallTooltip" -> "\:C774 \:D398\:B974\:C18C\:B098\:B294 `1` \:D328\:D074\:B9BF\:C5D0\:C11C \:C81C\:ACF5\:B418\:B294 \:AC83\:C774\:BBC0\:B85C \:C0AD\:C81C\:D560 \:C218 \:C5C6\:C2B5\:B2C8\:B2E4.", + +"PreferencesContentNotebooksTab" -> "\:B178\:D2B8\:BD81", +"PreferencesContentPersonasTab" -> "\:D398\:B974\:C18C\:B098", +"PreferencesContentServicesTab" -> "\:C11C\:BE44\:C2A4", +"PreferencesContentToolsTab" -> "\:B3C4\:AD6C", +"PreferencesContentEnableAssistanceLabel" -> "\:C790\:B3D9 \:B3C4\:C6B0\:BBF8 \:D65C\:C131\:D654", +"PreferencesContentEnableAssistanceTooltip" -> "\:D65C\:C131\:D654\:D558\:BA74 AI\:AC00 \:C81C\:ACF5\:D558\:B294 \:C81C\:C548\:C774 \:C790\:B3D9\:C73C\:B85C \:B2E4\:C74C \:D3C9\:AC00 \:ACB0\:ACFC\:C5D0 \:CD94\:AC00\:B429\:B2C8\:B2E4.", +"PreferencesContentPersonaLabel" -> "\:D398\:B974\:C18C\:B098:", +"PreferencesContentLLMServiceLabel" -> "\:B300\:D615 \:C5B8\:C5B4 \:BAA8\:B378 \:C11C\:BE44\:C2A4:", +"PreferencesContentModelLabel" -> "\:BAA8\:B378:", +"PreferencesContentTemperatureLabel" -> "\:C628\:B3C4", +"PreferencesContentSubsectionChat" -> "\:CC44\:D305 \:B178\:D2B8\:BD81 \:C140", +"PreferencesContentFormatOutputLabel" -> "\:CC44\:D305 \:CD9C\:B825\:C758 \:C11C\:C2DD \:C9C0\:C815", +"PreferencesContentIncludeHistoryLabel" -> "\:CC44\:D305 \:AE30\:B85D\:C744 \:D3EC\:D568", +"PreferencesContentIncludeHistoryTooltip" -> "\:D65C\:C131\:D654\:B418\:BA74 \:B300\:D615 \:C5B8\:C5B4 \:BAA8\:B378\:C758 \:CD94\:AC00 \:CEE8\:D14D\:C2A4\:D2B8\:B85C \:CC44\:D305 \:C785\:B825 \:C55E\:C5D0 \:C624\:B294 \:C140\:C774 \:D3EC\:D568\:B429\:B2C8\:B2E4.", +"PreferencesContentHistoryLengthLabel" -> "\:CC44\:D305 \:AE30\:B85D\:C758 \:AE38\:C774:", +"PreferencesContentHistoryLengthTooltip" -> "\:CC44\:D305 \:AE30\:B85D\:C5D0 \:D3EC\:D568\:D560 \:CD5C\:B300 \:C140 \:C218", +"PreferencesContentMergeChatLabel" -> "\:CC44\:D305 \:BA54\:C2DC\:C9C0 \:D1B5\:D569", +"PreferencesContentMergeChatTooltip" -> "\:D65C\:C131\:D654\:D558\:BA74 \:B3D9\:C77C\:D55C \:CC44\:D305 \:C791\:C131\:C790\:C758 \:C778\:C811 \:C140\:C774 \:B2E8\:C77C \:CC44\:D305 \:BA54\:C2DC\:C9C0\:C5D0 \:D1B5\:D569\:B429\:B2C8\:B2E4.", +"PreferencesContentSubsectionFeatures" -> "\:AE30\:B2A5", +"PreferencesContentEnableMultimodalLabel" -> "\:B2E4\:C911 \:BAA8\:B4DC \:CF58\:D150\:CE20 \:D65C\:C131\:D654: ", +"PreferencesContentEnableTools" -> "\:B3C4\:AD6C \:D65C\:C131\:D654: ", +"PreferencesContentToolCallFrequency" -> "\:B3C4\:AD6C \:D638\:CD9C\:C758 \:BE48\:B3C4:", +"PreferencesContentSubsectionRegisteredServices" -> "\:B4F1\:B85D\:B41C \:C11C\:BE44\:C2A4", +"PreferencesContentService" -> "\:C11C\:BE44\:C2A4", +"PreferencesContentServiceConnectButton" -> "\:BAA8\:B378 \:BAA9\:B85D\:C5D0 \:C5F0\:ACB0", +"PreferencesContentAuthentication" -> "\:C778\:C99D", +"PreferencesContentUnregisterTooltip" -> "\:C11C\:BE44\:C2A4 \:C5F0\:ACB0 \:B4F1\:B85D \:CDE8\:C18C", +"PreferencesContentOpenAICompletionURLLabel" -> "\:CC44\:D305 \:C644\:B8CC URL:", + +"ResourceInstallerFromURLPrompt" -> "URL\:C744 \:C785\:B825", + +"ToolManagerTitle" -> "\:B300\:D615 \:C5B8\:C5B4 \:BAA8\:B378 \:B3C4\:AD6C\:C758 \:CD94\:AC00 \:BC0F \:AD00\:B9AC", +"ToolManagerInstallTools" -> "\:B3C4\:AD6C \:C124\:CE58", +"ToolManagerInstallFrom" -> "\:B2E4\:C74C\:BD80\:D130 \:C124\:CE58", +"ToolManagerInstallFromLLMToolRepo" -> "\:B300\:D615 \:C5B8\:C5B4 \:BAA8\:B378 \:B3C4\:AD6C \:B9AC\:D3EC\:C9C0\:D1A0\:B9AC \[UpperRightArrow]", +"ToolManagerManageTools" -> "\:B3C4\:AD6C \:AD00\:B9AC \:BC0F \:D65C\:C131\:D654", +"ToolManagerShowEnabledFor" -> "\:B2E4\:C74C\:C5D0 \:B300\:D574 \:D65C\:C131\:D654\:B41C \:B3C4\:AD6C \:D45C\:C2DC:", +"ToolManagerTool" -> "\:B3C4\:AD6C", +"ToolManagerEnabledFor" -> "\:B2E4\:C74C\:C5D0 \:B300\:D574 \:D65C\:C131\:D654\[VeryThinSpace]:", +"ToolManagerEnabledByPersona" -> "\:D398\:B974\:C18C\:B098\:C5D0 \:C758\:D574 \:D65C\:C131\:D654", +"ToolManagerEnabledNever" -> "\:D56D\:C0C1 \:BE44\:D65C\:C131\:D654", +"ToolManagerEnabledAlways" -> "\:D56D\:C0C1 \:D65C\:C131\:D654", +"ToolManagerTooltipNonConfigurable" -> "`name`\:C5D0\:B294 \:C124\:C815\:D560 \:C218 \:C788\:B294 \:B9E4\:AC1C\:BCC0\:C218\:AC00 \:C5C6\:C2B5\:B2C8\:B2E4.", +"ToolManagerTooltipNonDeletable1" -> "`name`\:C740 \:B0B4\:C7A5 \:B3C4\:AD6C\:C774\:BBC0\:B85C \:C0AD\:C81C\:D560 \:C218 \:C5C6\:C2B5\:B2C8\:B2E4.", +"ToolManagerTooltipNonDeletable2" -> "`name`\:C740 \:D398\:B974\:C18C\:B098 `persona`\:C5D0 \:C758\:D574 \:C81C\:ACF5\:B418\:C5C8\:C73C\:BA70 \:BCC4\:B3C4\:B85C \:C0AD\:C81C\:D560 \:C218 \:C5C6\:C2B5\:B2C8\:B2E4.", +"ToolManagerDeleteTool" -> "\:B3C4\:AD6C \:C0AD\:C81C", + +"UIEnableChatFeatures" -> "AI \:CC44\:D305 \:AE30\:B2A5 \:D65C\:C131\:D654", +"UIAutomaticAnalysisLabel" -> "\:C790\:B3D9\:C73C\:B85C \:ACB0\:ACFC \:BD84\:C11D", +"UIAutomaticAnalysisTooltip" -> "\:D65C\:C131\:D654\:D558\:BA74 AI\:AC00 \:C81C\:ACF5\:D558\:B294 \:C81C\:C548\:C774 \:C790\:B3D9\:C73C\:B85C \:B2E4\:C74C \:D3C9\:AC00 \:ACB0\:ACFC\:C5D0 \:CD94\:AC00\:B429\:B2C8\:B2E4.", +"UIPersonas" -> "\:D398\:B974\:C18C\:B098", +"UIChatBlockSettings" -> "\:CC44\:D305 \:BE14\:B85D \:C124\:C815\[Ellipsis]", +"UIAddAndManagePersonas" -> "\:D398\:B974\:C18C\:B098 \:CD94\:AC00 \:BC0F \:AD00\:B9AC\[Ellipsis]", +"UIAddAndManageTools" -> "\:B3C4\:AD6C \:CD94\:AC00 \:BC0F \:AD00\:B9AC\[Ellipsis]", +"UIModels" -> "\:BAA8\:B378", +"UIModelsServices" -> "\:C11C\:BE44\:C2A4", +"UIModelsGet" -> "\:C0AC\:C6A9 \:AC00\:B2A5\:D55C \:BAA8\:B378 \:AC00\:C838\:C624\:AE30\[Ellipsis]", +"UIModelsNoList" -> "\:BAA8\:B378 \:BAA9\:B85D\:C5D0 \:C5F0\:ACB0", +"UIModelsFineTuned" -> "\:BBF8\:C138 \:C870\:C815\:B41C \:BAA8\:B378", +"UIModelsSnapshot" -> "\:BAA8\:B378\:C758 \:C2A4\:B0C5\:C0F7", +"UIModelsPreview" -> "\:BAA8\:B378 \:BBF8\:B9AC\:BCF4\:AE30", +"UIAdvancedSettings" -> "\:ACE0\:AE09 \:C124\:C815", +"UIAdvancedTemperature" -> "\:C628\:B3C4", +"UIAdvancedToolCallFrequency" -> "\:B3C4\:AD6C \:D638\:CD9C \:BE48\:B3C4", +"UIAdvancedChooseAutomatically" -> "\:C790\:B3D9\:C73C\:B85C \:C120\:D0DD", +"UIAdvancedRoles" -> "\:C5ED\:D560", +"UITryEnableChatDialogMainText" -> "\:CC44\:D305 \:B178\:D2B8\:BD81 \:AE30\:B2A5\:C744 \:D65C\:C131\:D654\:D558\:BA74 \:C774 \:B178\:D2B8\:BD81\:C5D0 \:C815\:C758\:B41C \:C2A4\:D0C0\:C77C\:C774 \:C0AD\:C81C\:B418\:BA70 \:ACF5\:C720\:B41C Chatbook \:C2A4\:D0C0\:C77C\:C2DC\:D2B8\:B85C \:B300\:CCB4\:B429\:B2C8\:B2E4.", +"UITryEnableChatDialogConfirm" -> "\:ACC4\:C18D \:D558\:C2DC\:ACA0\:C2B5\:B2C8\:AE4C?", + +"StylesheetChatWidgetButtonTooltip" -> "\:B300\:D615 \:C5B8\:C5B4 \:BAA8\:B378\:B85C \:C804\:C1A1", +"StylesheetAssistantMenuInitializerButtonTooltip" -> "\:C790\:B3D9 \:B3C4\:C6B0\:BBF8 \:BE44\:D65C\:C131\:D654", +"StylesheetFeedbackButtonTooltip" -> "Wolfram\:C5D0 \:D53C\:B4DC\:BC31 \:BCF4\:B0B4\:AE30", +"StylesheetExplodeCellsInPlace" -> "(\:C81C \:C790\:B9AC) \:C140 \:BD84\:D560", +"StylesheetExplodeCellsDuplicate" -> "(\:C911\:BCF5) \:C140 \:BD84\:D560", +"StylesheetCopyExplodedCells" -> "\:BD84\:D560\:B41C \:C140 \:BCF5\:C0AC", +"StylesheetToggleFormatting" -> "\:C11C\:C2DD \:C124\:C815 \:C804\:D658", +"StylesheetCopyChatObject" -> "ChatObject \:BCF5\:C0AC", +"StylesheetInsertionMenuChatInput" -> "\:CC44\:D305 \:C785\:B825", +"StylesheetInsertionMenuSideChat" -> "\:C0AC\:C774\:B4DC \:CC44\:D305", + +"PersonaNameBirdnardo" -> "Birdnardo", +"PersonaNameCodeAssistant" -> "Code Assistant", +"PersonaNameCodeWriter" -> "Code Writer", +"PersonaNamePlainChat" -> "\:C77C\:BC18 \:CC44\:D305", +"PersonaNameRawModel" -> "\:C6D0\:C2DC \:BAA8\:B378", +"PersonaNameWolfie" -> "Wolfie", + +"AttachedChatFieldHint" -> "\:BB34\:C5C7\:C774\:B4E0 \:BB3C\:C5B4\:BCF4\:C138\:C694" +} +@| +@| +@@resource ChatbookLocalizableBitmaps +{ +} +@| \ No newline at end of file diff --git a/FrontEnd/TextResources/Spanish/ChatbookStrings.tr b/FrontEnd/TextResources/Spanish/ChatbookStrings.tr new file mode 100644 index 00000000..86f37b27 --- /dev/null +++ b/FrontEnd/TextResources/Spanish/ChatbookStrings.tr @@ -0,0 +1,180 @@ +@@resource ChatbookStrings +{ +"ConnectButton" -> "Conectar", +"DisconnectButton" -> "Desconectar", +"OKButton" -> "Aceptar", +"CancelButton" -> "Cancelar", +"DeleteButton" -> "Eliminar", +"SendButton" -> "Enviar", +"URLButton" -> "URL", +"ScopeGlobal" -> "Global", +"ScopeNotebook" -> "Cuaderno seleccionado", +"ScopeCells" -> "Celdas seleccionadas", +"EnabledByModel" -> "Autom\[AAcute]tico seg\[UAcute]n modelo", +"EnabledByPersona" -> "Autom\[AAcute]tico seg\[UAcute]n persona", +"EnabledAlways" -> "Siempre habilitado", +"EnabledNever" -> "Siempre deshabilitado", +"EnabledNever2" -> "Nunca habilitado", +"Always" -> "Siempre", +"Never" -> "Nunca", +"Automatic" -> "Autom\[AAcute]tico", +"Custom" -> "Personalizado", +"Rare" -> "Poco com\[UAcute]n", +"Often" -> "Frecuentemente", + +"ActionsAPIKeyDialogTitle" -> "Por favor ingrese su clave de API de OpenAI", +"ActionsAPIKeyDialogAPIKey" -> "Clave de API", +"ActionsAPIKeyDialogSave" -> "Guardar", +"APIKeyDialogCreateKeyTemplate" -> "Si aun no cuenta con una clave de API, puede crear una `1`.", +"APIKeyDialogSaveKeyTemplate" -> "Para evitar ver esta ventana en el futuro, seleccione \"Guardar\" para guardar la clave en `1`.", + +"ChatContextDialogSystemPromptText" -> "Texto del mensaje de sistema", +"ChatContextDialogCellProcessingFunction" -> "Funci\[OAcute]n de procesamiento de celdas", +"ChatContextDialogCellPostEvaluationFunction" -> "Funci\[OAcute]n de evaluaci\[OAcute]n posterior de celdas", +"ChatContextDialogDescription" -> "Este es el texto que le indica qu\[EAcute] hacer.", +"ChatContextDialogClickForMoreInfo" -> "Haga clic para m\[AAcute]s informaci\[OAcute]", + +"ChatToolbarInsertChatCell" -> "Insertar celda de chat", +"ChatToolbarChatSettings" -> "Configuraci\[OAcute]n de chat", +"ChatToolbarChatDrivenLabel" -> "Cuaderno impulsado por chat", +"ChatToolbarChatEnabledLabel" -> "Cuaderno habilitado para chat", + +"DefaultToolsLinks" -> "Enlaces", + +"FeedbackChatMessagesContent" -> "Mensajes de chat", +"FeedbackChatMessagesTooltip" -> "Mensajes de chat involucrados en la creaci\[OAcute]n de esta salida de chat.", +"FeedbackSystemMessageContent" -> "Mensaje del sistema", +"FeedbackSystemMessageTooltip" -> "El mensaje subyacente utilizado para para dar indicaciones a la IA.", +"FeedbackChatHistoryContent" -> "Historial de chat utilizado para generar esta salida", +"FeedbackChatHistoryTooltip" -> "Mensajes adicionales utilizados como historial de conversaci\[OAcute]n para generar esta salida.", +"FeedbackChatImageContent" -> "Imagen de salida de chat", +"FeedbackChatImageTooltip" -> "Una captura de pantalla de la salida de chat, la cual puede utilizarse si el comentario est\[AAcute] relacionado con la apariencia de la salida.", +"FeedbackDialogHeader" -> "Enviar comentarios del chat de IA a Wolfram", +"FeedbackDialogBodyThumbs" -> "Sus comentarios nos ayudan a mejorar nuestras caracter\[IAcute]sticas de IA.", +"FeedbackDialogContentIncludedLabel" -> "Contenido incluido:", +"FeedbackDialogContentOutputImageLabel" -> "Imagen de salida", +"FeedbackDialogCommentFieldHint" -> "\[DownExclamation]Tiene comentarios adicionales? (Opcional)", +"FeedbackDialogBodyUsedForTraining" -> "Su historial de chat y comentarios pueden ser utilizados con fines de entrenamiento.", +"FeedbackDialogBodyPreviewData" -> "Previsualizar datos a enviar", +"FeedbackDialogThanks" -> "\[DownExclamation]Gracias por sus comentarios!", + +"FormattingInsertContentAndEvaluateTooltip" -> "Insertar contenido como una nueva celda de entrada debajo y evaluar", +"FormattingCopyToClipboardTooltip" -> "Copiar al portapapeles", +"FormattingInsertContentTooltip" -> "Insertar contenido como una nueva celda de entrada debajo", + +"InlineReferencesFieldHint" -> "PromptName", +"InlineReferencesInsertLabel" -> "Insertar:", +"InlineReferencesInsertPersonaPrompt" -> "Ingrese un nombre de persona", +"InlineReferencesInsertPersonaFail" -> "No se encontr\[OAcute] una persona con el nombre \"`name`\".", +"InlineReferencesInsertModifierPrompt" -> "Ingrese un prompt de modificador", +"InlineReferencesInsertModifierFail" -> "No se encontr\[OAcute] un modificador con el nombre \"`name`\".", +"InlineReferencesInsertFunctionPrompt" -> "Ingrese un prompt de funci\[OAcute]n", +"InlineReferencesInsertFunctionFail" -> "No se encontr\[OAcute] una funci\[OAcute]n con el nombre \"`name`\".", + +"PersonaManagerTitle" -> "Agregar y administrar personas", +"PersonaManagerInstallPersonas" -> "Instalar personas", +"PersonaManagerInstallFrom" -> "Instalar desde", +"PersonaManagerInstallFromPromptRepo" -> "Repositorio de prompts \[UpperRightArrow]", +"PersonaManagerManagePersonas" -> "Gestionar y habilitar personas", +"PersonaManagerInMenu" -> "En men\[UAcute]", +"PersonaManagerName" -> "Nombre", +"PersonaManagerVersion" -> "Versi\[OAcute]n", +"PersonaManagerOriginChatbookTooltip" -> "Persona instalada desde el paclet Wolfram/Chatbook. Visite la p\[AAcute]gina \[RightGuillemet]", +"PersonaManagerOriginRepositoryTooltip" -> "Persona instalada desde el paclet `name`. Visite la p\[AAcute]gina \[RightGuillemet].", +"PersonaManagerPersonaUninstallTooltip" -> "Esta persona no puede desinstalarse ya que ha sido proporcionada por el paclet `1`.", + +"PreferencesContentNotebooksTab" -> "Cuadernos", +"PreferencesContentPersonasTab" -> "Personas", +"PreferencesContentServicesTab" -> "Servicios", +"PreferencesContentToolsTab" -> "Herramientas", +"PreferencesContentEnableAssistanceLabel" -> "Habilitar asistencia autom\[AAcute]tica", +"PreferencesContentEnableAssistanceTooltip" -> "Si ha sido habilitada, las sugerencias autom\[AAcute]ticas proporcionadas por IA ser\[AAcute]n agregadas luego de los resultados de evaluaci\[OAcute]n.", +"PreferencesContentPersonaLabel" -> "Persona:", +"PreferencesContentLLMServiceLabel" -> "Servicio LLM:", +"PreferencesContentModelLabel" -> "Modelo:", +"PreferencesContentTemperatureLabel" -> "Temperatura:", +"PreferencesContentSubsectionChat" -> "Celdas de Cuadernos de chat", +"PreferencesContentFormatOutputLabel" -> "Formatear salida de chat", +"PreferencesContentIncludeHistoryLabel" -> "Incluir historial de chat", +"PreferencesContentIncludeHistoryTooltip" -> "Si ha sido habilitado, las celdas anteriores a la entrada de chat ser\[AAcute]n incluidas como contexto adicional para el LLM.", +"PreferencesContentHistoryLengthLabel" -> "Longitud de historial de chat:", +"PreferencesContentHistoryLengthTooltip" -> "El n\[UAcute]mero m\[AAcute]ximo de celdas a incluir en el historial de chat", +"PreferencesContentMergeChatLabel" -> "Combinar mensajes de chat", +"PreferencesContentMergeChatTooltip" -> "Si ha sido habilitado, las celdas adyacentes con el mismo autor ser\[AAcute]n combinadas en un solo mensaje de chat.", +"PreferencesContentSubsectionFeatures" -> "Caracter\[IAcute]sticas", +"PreferencesContentEnableMultimodalLabel" -> "Habilitar contenido multimodal: ", +"PreferencesContentEnableTools" -> "Habilitar herramientas: ", +"PreferencesContentToolCallFrequency" -> "Frecuencia de llamadas de herramienta:", +"PreferencesContentSubsectionRegisteredServices" -> "Servicios registrados", +"PreferencesContentService" -> "Servicio", +"PreferencesContentServiceConnectButton" -> "Conectar para lista de modelos", +"PreferencesContentAuthentication" -> "Autenticaci\[OAcute]n", +"PreferencesContentUnregisterTooltip" -> "Cancelar registro de conexi\[OAcute]n de servicio", +"PreferencesContentOpenAICompletionURLLabel" -> "URL de finalizaci\[OAcute]n de chat:", + +"ResourceInstallerFromURLPrompt" -> "Ingrese un enlace URL", + +"ToolManagerTitle" -> "Agregar y administrar herramientas LLM", +"ToolManagerInstallTools" -> "Instalar herramientas", +"ToolManagerInstallFrom" -> "Instalar desde", +"ToolManagerInstallFromLLMToolRepo" -> "Repositorio de herramientas LLM \[UpperRightArrow]", +"ToolManagerManageTools" -> "Administrar y habilitar herramientas", +"ToolManagerShowEnabledFor" -> "Mostrar herramientas habilitadas para:", +"ToolManagerTool" -> "Herramienta", +"ToolManagerEnabledFor" -> "Habilitada para\[VeryThinSpace]:", +"ToolManagerEnabledByPersona" -> "Habilitada por persona", +"ToolManagerEnabledNever" -> "Nunca habilitada", +"ToolManagerEnabledAlways" -> "Siempre habilitada", +"ToolManagerTooltipNonConfigurable" -> "`name` no posee par\[AAcute]metros configurables.", +"ToolManagerTooltipNonDeletable1" -> "`name` es una herramienta incorporada y no puede eliminarse.", +"ToolManagerTooltipNonDeletable2" -> "`name` ha sido proporcionada por la persona `persona` y no puede eliminarse por separado.", +"ToolManagerDeleteTool" -> "Eliminar herramienta", + +"UIEnableChatFeatures" -> "Habilitar caracter\[IAcute]sticas de chat de IA", +"UIAutomaticAnalysisLabel" -> "Realizar an\[AAcute]lisis autom\[AAcute]tico de resultados", +"UIAutomaticAnalysisTooltip" -> "Si ha sido habilitado, se agregar\[AAcute]n sugerencias autom\[AAcute]ticas proporcionadas por IA luego de los resultados de la evaluaci\[OAcute].", +"UIPersonas" -> "Personas", +"UIChatBlockSettings" -> "Configuraci\[OAcute]n de bloqueo de chat\[Ellipsis]", +"UIAddAndManagePersonas" -> "Agregar y administrar personas\[Ellipsis]", +"UIAddAndManageTools" -> "Agregar y administrar herramientas\[Ellipsis]", +"UIModels" -> "Modelos", +"UIModelsServices" -> "Servicios", +"UIModelsGet" -> "Obteniendo modelos disponibles\[Ellipsis]", +"UIModelsNoList" -> "Conectar para la lista de modelos", +"UIModelsFineTuned" -> "Modelos afinados", +"UIModelsSnapshot" -> "Modelos instant\[AAcute]neos", +"UIModelsPreview" -> "Previsualizar los modelos", +"UIAdvancedSettings" -> "Configuraci\[OAcute]n avanzada", +"UIAdvancedTemperature" -> "Temperatura", +"UIAdvancedToolCallFrequency" -> "Frecuencia de llamadas de herramienta", +"UIAdvancedChooseAutomatically" -> "Seleccionar de manera autom\[AAcute]tica", +"UIAdvancedRoles" -> "Roles", +"UITryEnableChatDialogMainText" -> "Habilitar la funcionalidad de Cuadernos de chat destruir\[AAcute] los estilos privados definidos en este cuaderno, y los reemplazar\[AAcute] con la hoja de estilo compartida Chatbook.", +"UITryEnableChatDialogConfirm" -> "\[DownQuestion]Est\[AAcute] seguro que desea continuar?", + +"StylesheetChatWidgetButtonTooltip" -> "Enviar a LLM", +"StylesheetAssistantMenuInitializerButtonTooltip" -> "Deshabilitar asistencia autom\[AAcute]tica", +"StylesheetFeedbackButtonTooltip" -> "Enviar comentarios a Wolfram", +"StylesheetExplodeCellsInPlace" -> "Explotar celdas (en su lugar)", +"StylesheetExplodeCellsDuplicate" -> "Explotar celdas (Duplicadas)", +"StylesheetCopyExplodedCells" -> "Copiar celdas explotadas", +"StylesheetToggleFormatting" -> "Activar formato", +"StylesheetCopyChatObject" -> "Copiar ChatObject", +"StylesheetInsertionMenuChatInput" -> "Entrada de chat", +"StylesheetInsertionMenuSideChat" -> "Chat lateral", + +"PersonaNameBirdnardo" -> "Birdnardo", +"PersonaNameCodeAssistant" -> "Asistente de c\[OAcute]digo", +"PersonaNameCodeWriter" -> "Escritor de c\[OAcute]digo", +"PersonaNamePlainChat" -> "Chat simple", +"PersonaNameRawModel" -> "Modelo sin procesar", +"PersonaNameWolfie" -> "Wolfie", + +"AttachedChatFieldHint" -> "Preg\[UAcute]ntame lo que sea" +} +@| +@| +@@resource ChatbookLocalizableBitmaps +{ +} +@| \ No newline at end of file diff --git a/LLMConfiguration/Personas/Birdnardo/LLMConfiguration.wl b/LLMConfiguration/Personas/Birdnardo/LLMConfiguration.wl index 9634ac2a..55525d6c 100644 --- a/LLMConfiguration/Personas/Birdnardo/LLMConfiguration.wl +++ b/LLMConfiguration/Personas/Birdnardo/LLMConfiguration.wl @@ -1,5 +1,6 @@ <| "Description" -> "The one and only Birdnardo", + "DisplayName" -> Dynamic @ FEPrivate`FrontEndResource[ "ChatbookStrings", "PersonaNameBirdnardo" ], "DocumentationLink" -> "https://resources.wolframcloud.com/PromptRepository/resources/Birdnardo/", "Tools" -> { "DocumentationLookup", @@ -8,7 +9,8 @@ "WolframLanguageEvaluator", "WebSearcher", "WebFetcher", - "WebImageSearcher" + "WebImageSearcher", + ParentList }, "Icon" -> <| "Default" -> RawBoxes @ TemplateBox[ { }, "BirdnardoIcon" ], diff --git a/LLMConfiguration/Personas/CodeAssistant/LLMConfiguration.wl b/LLMConfiguration/Personas/CodeAssistant/LLMConfiguration.wl index 2f5c9233..c08926a0 100644 --- a/LLMConfiguration/Personas/CodeAssistant/LLMConfiguration.wl +++ b/LLMConfiguration/Personas/CodeAssistant/LLMConfiguration.wl @@ -1,7 +1,13 @@ <| "BasePrompt" -> { "Notebooks", "WolframLanguageStyle" }, - "DisplayName" -> "Code Assistant", + "Description" -> "Help with writing and generating Wolfram Language code", + "DisplayName" -> Dynamic @ FEPrivate`FrontEndResource[ "ChatbookStrings", "PersonaNameCodeAssistant" ], "Icon" -> RawBoxes @ TemplateBox[ { }, "ChatIconCodeAssistant" ], - "Tools" -> { "DocumentationLookup", "DocumentationSearcher", "WolframAlpha", "WolframLanguageEvaluator" }, - "Description" -> "Help with writing and generating Wolfram Language code" + "Tools" -> { + "DocumentationLookup", + "DocumentationSearcher", + "WolframAlpha", + "WolframLanguageEvaluator", + ParentList + } |> \ No newline at end of file diff --git a/LLMConfiguration/Personas/CodeWriter/LLMConfiguration.wl b/LLMConfiguration/Personas/CodeWriter/LLMConfiguration.wl index 4ae12867..6ee20f2c 100644 --- a/LLMConfiguration/Personas/CodeWriter/LLMConfiguration.wl +++ b/LLMConfiguration/Personas/CodeWriter/LLMConfiguration.wl @@ -1,8 +1,8 @@ <| "BasePrompt" -> { "WolframLanguageStyle" }, - "DisplayName" -> "Code Writer", + "DisplayName" -> Dynamic @ FEPrivate`FrontEndResource[ "ChatbookStrings", "PersonaNameCodeWriter" ], "Icon" -> RawBoxes @ TemplateBox[ { }, "ChatIconCodeWriter" ], - "Tools" -> { "DocumentationLookup", "DocumentationSearcher" }, + "Tools" -> { "DocumentationLookup", "DocumentationSearcher", ParentList }, "Description" -> "AI code generation with minimal commentary", "DocumentationLink" -> "https://resources.wolframcloud.com/PromptRepository/resources/CodeWriter/" |> \ No newline at end of file diff --git a/LLMConfiguration/Personas/PlainChat/LLMConfiguration.wl b/LLMConfiguration/Personas/PlainChat/LLMConfiguration.wl index 637ef4a2..6a4f65df 100644 --- a/LLMConfiguration/Personas/PlainChat/LLMConfiguration.wl +++ b/LLMConfiguration/Personas/PlainChat/LLMConfiguration.wl @@ -1,8 +1,8 @@ <| "BasePrompt" -> Automatic, - "DisplayName" -> "Plain Chat", + "DisplayName" -> Dynamic @ FEPrivate`FrontEndResource[ "ChatbookStrings", "PersonaNamePlainChat" ], "Icon" -> RawBoxes @ TemplateBox[ { }, "ChatIconPlainChat" ], "Pre" -> "", - "Tools" -> { "WebSearcher", "WebImageSearcher", "WebFetcher" }, + "Tools" -> { "WebSearcher", "WebImageSearcher", "WebFetcher", ParentList }, "Description" -> "Chat without a focus on code" |> \ No newline at end of file diff --git a/LLMConfiguration/Personas/RawModel/LLMConfiguration.wl b/LLMConfiguration/Personas/RawModel/LLMConfiguration.wl index 1b09182b..88938c6f 100644 --- a/LLMConfiguration/Personas/RawModel/LLMConfiguration.wl +++ b/LLMConfiguration/Personas/RawModel/LLMConfiguration.wl @@ -1,6 +1,6 @@ <| "BasePrompt" -> None, - "DisplayName" -> "Raw Model", + "DisplayName" -> Dynamic @ FEPrivate`FrontEndResource[ "ChatbookStrings", "PersonaNameRawModel" ], "Icon" -> RawBoxes @ TemplateBox[ { }, "PersonaRawModel" ], "Description" -> "No custom prompting, just the raw LLM", "Tools" -> None diff --git a/LLMConfiguration/Personas/Wolfie/LLMConfiguration.wl b/LLMConfiguration/Personas/Wolfie/LLMConfiguration.wl index 9c73955c..4f08c719 100644 --- a/LLMConfiguration/Personas/Wolfie/LLMConfiguration.wl +++ b/LLMConfiguration/Personas/Wolfie/LLMConfiguration.wl @@ -1,5 +1,6 @@ <| - "Description" -> "Wolfram's friendliest AI guide", + "Description" -> "Wolfram's friendliest AI guide", + "DisplayName" -> Dynamic @ FEPrivate`FrontEndResource[ "ChatbookStrings", "PersonaNameWolfie" ], "DocumentationLink" -> "https://resources.wolframcloud.com/PromptRepository/resources/Wolfie/", "Tools" -> { "DocumentationLookup", @@ -7,6 +8,7 @@ "WolframAlpha", "WolframLanguageEvaluator", "WebSearcher", - "WebFetcher" + "WebFetcher", + ParentList } |> \ No newline at end of file diff --git a/PacletInfo.wl b/PacletInfo.wl index b4a5361a..36ede23b 100644 --- a/PacletInfo.wl +++ b/PacletInfo.wl @@ -1,7 +1,7 @@ PacletObject[ <| "Name" -> "Wolfram/Chatbook", "PublisherID" -> "Wolfram", - "Version" -> "1.4.5", + "Version" -> "1.4.7", "WolframVersion" -> "13.3+", "Description" -> "Wolfram Notebooks + LLMs", "License" -> "MIT", diff --git a/Scripts/.githooks/pre-commit b/Scripts/.githooks/pre-commit index 5dba6948..c06d3a5c 100644 --- a/Scripts/.githooks/pre-commit +++ b/Scripts/.githooks/pre-commit @@ -11,7 +11,9 @@ if [ "$changed" != "" ]; then for sourceFilePath in $changed do - git add $sourceFilePath + if [ -f "$sourceFilePath" ]; then + git add "$sourceFilePath" + fi done; -fi +fi \ No newline at end of file diff --git a/Scripts/BuildMX.wls b/Scripts/BuildMX.wls index 28c00dc3..121ad918 100755 --- a/Scripts/BuildMX.wls +++ b/Scripts/BuildMX.wls @@ -9,8 +9,10 @@ If[ ! TrueQ @ $loadedDefinitions, Get @ FileNameJoin @ { DirectoryName @ $InputF (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Initialization*) -Needs[ "Wolfram`PacletCICD`" -> "cicd`" ]; +Needs[ "CodeParser`" -> "cp`" ]; Needs[ "GeneralUtilities`" -> "gu`" ]; +Needs[ "PacletTools`" -> "pt`" ]; +Needs[ "Wolfram`PacletCICD`" -> "cicd`" ]; Wolfram`ChatbookInternal`$BuildingMX = True; @@ -25,6 +27,120 @@ $mxFile = cStr @ FileNameJoin @ { "Chatbook.mx" }; +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Definitions*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*codeParse*) +codeParse[ file_ ] := codeParse[ file ] = + cp`CodeParse @ Flatten @ File @ file; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*codeParseIndexed*) +codeParseIndexed[ file_ ] := codeParseIndexed[ file ] = + cp`CodeParse[ Flatten @ File @ file, "SourceConvention" -> "SourceCharacterIndex" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*copyTemporary*) +copyTemporary[ dir_ ] := + Enclose @ Module[ { tmp, extFiles }, + tmp = FileNameJoin @ { $TemporaryDirectory, CreateUUID[ ] }; + extFiles = ConfirmMatch[ pacletFiles @ dir, { _String, __String }, "Files" ]; + ConfirmMatch[ (copyTemporary0[ dir, tmp, #1 ] &) /@ extFiles, { _String, __String }, "Copied" ]; + tmp + ]; + +copyTemporary0[ dir_, tmp_, file_ ] := + With[ { rel = StringReplace[ ResourceFunction[ "RelativePath" ][ dir, file ], "\\" -> "/" ] }, + CopyFile[ file, ResourceFunction[ "EnsureFilePath" ][ FileNameJoin @ { tmp, rel } ] ] + ]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*pacletFiles*) +pacletFiles[ dir_ ] := Flatten @ { + FileNameJoin @ { dir, "PacletInfo.wl" }, + Values @ pt`PacletExtensionFiles @ File @ dir +}; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*expandTags*) +expandTags[ root_ ] := + Enclose @ Map[ + Confirm[ expandTags[ root, #1 ], "Expand" ] &, + ConfirmMatch[ FileNames[ "*.wl", root, Infinity ], { __String }, "Files" ] + ]; + +expandTags[ root_, file_ ] := + Enclose @ Catch @ Module[ { tags, pos, string, newString }, + tags = ConfirmMatch[ getNewTags[ root, file ], { ___String }, "Tags" ]; + If[ tags === { }, Throw @ file ]; + cicd`ConsoleLog[ "\t" <> ToString @ file ]; + pos = ConfirmMatch[ getTagPos @ file, { { _Integer, _Integer }.. }, "Positions" ]; + ConfirmAssert[ Length @ tags == Length @ pos, "LengthCheck" ]; + string = ConfirmBy[ ReadString @ file, StringQ, "FileContent" ]; + newString = ConfirmBy[ StringReplacePart[ string, tags, pos ], StringQ, "NewFileContent" ]; + ConfirmBy[ Export[ file, newString, "String" ], FileExistsQ, "ExportFile" ] + ]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*getNewTags*) +getNewTags[ root_, file_ ] := + Module[ { relativeFile }, + + relativeFile = StringReplace[ ResourceFunction[ "RelativePath" ][ root, file ], "\\" -> "/" ]; + + Cases[ + codeParse @ file, + ResourceFunction[ "ASTPattern" ][ + HoldPattern @ Alternatives[ + (Confirm|ConfirmAssert)[ _, $tag1_String ], + (ConfirmBy|ConfirmMatch|ConfirmQuiet)[ _, _, $tag2_String ] + ], + KeyValuePattern[ cp`Source -> { { $l1_, $c1_ }, { $l2_, $c2_ } } ] + ] :> + With[ { tag = First @ { $tag1, $tag2 } }, + TemplateApply[ + $tagTemplate, + <| + "File" -> relativeFile, + "Tag" -> First @ StringSplit[ ToExpression @ tag[[ 2 ]], "@@" ], + "Line1" -> $l1, + "Line2" -> $l2, + "Column1" -> $c1, + "Column2" -> $c2 + |> + ] + ], + Infinity + ] + ]; + +$tagTemplate = StringTemplate[ "\"`Tag`@@`File`:`Line1`,`Column1`-`Line2`,`Column2`\"" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*getTagPos*) +getTagPos[ file_ ] := Cases[ + codeParseIndexed @ file, + ResourceFunction[ "ASTPattern" ][ + HoldPattern[ + Alternatives[ + (Confirm|ConfirmAssert)[ _, $tag1_String ], + (ConfirmBy|ConfirmMatch|ConfirmQuiet)[ _, _, $tag2_String ] + ] + ], + KeyValuePattern[ cp`Source -> p_ ] + ] :> (First @ { $tag1, $tag2 })[[ 3, Key @ cp`Source ]], + Infinity +]; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Build MX*) @@ -33,16 +149,28 @@ If[ FileExistsQ @ $mxFile, cicd`ScriptConfirm @ DeleteFile @ $mxFile ]; +cicd`ConsoleLog[ "Copying files..." ]; +tmp = cicd`ScriptConfirmBy[ copyTemporary @ $pacletDir, DirectoryQ ]; +cicd`ScriptConfirmBy[ setPacletReleaseID[ tmp, releaseID @ $pacletDir ], StringQ ]; +cicd`ConsoleLog[ "Inserting confirmation source info..." ]; +cicd`ScriptConfirm @ expandTags @ tmp; + cicd`ConsoleLog[ "Loading paclet..." ]; -cicd`ScriptConfirmBy[ PacletDirectoryLoad @ $pacletDir, MemberQ @ $pacletDir ]; +PacletDirectoryUnload @ $pacletDir; +cicd`ScriptConfirmBy[ PacletDirectoryLoad @ tmp, MemberQ @ tmp ]; cicd`ScriptConfirm @ CheckAbort[ Get[ "Wolfram`Chatbook`" ], $Failed ]; +cicd`ScriptConfirmMatch[ DeleteDirectory[ tmp, DeleteContents -> True ], Null ]; + $mxDir = cDir @ gu`EnsureDirectory @ DirectoryName @ $mxFile; cicd`ConsoleLog @ SequenceForm[ "MX target directory: ", $mxDir ]; cicd`ConsoleLog @ SequenceForm[ "Building MX file: " , $mxFile ]; DumpSave[ $mxFile, { "Wolfram`Chatbook`" }, "SymbolAttributes" -> False ]; +PacletDirectoryUnload @ tmp; +PacletDirectoryLoad @ $pacletDir; + result = If[ ! FileExistsQ @ $mxFile, cicd`ConsoleError[ "Failed to build MX file!", "Fatal" -> True ], $mxFile diff --git a/Scripts/Common.wl b/Scripts/Common.wl index 38d3a304..ef755624 100644 --- a/Scripts/Common.wl +++ b/Scripts/Common.wl @@ -107,6 +107,9 @@ messageString[ ___ ] := "-- Message text not found --"; (* ::Section::Closed:: *) (*Definitions*) +$$ws = WhitespaceCharacter...; +$$id = "\"" ~~ Except[ "\"" ].. ~~ "\""; + $envSHA = SelectFirst[ { Environment[ "GITHUB_SHA" ], Environment[ "BUILD_VCS_NUMBER_WolframLanguage_Paclets_Chatbook_PacChatbook" ] }, StringQ @@ -119,7 +122,7 @@ $inCICD = StringQ @ $envSHA; (*gitCommand*) gitCommand[ { cmd__String }, dir_ ] := Enclose @ Module[ { res }, - res = RunProcess[ { "git", cmd }, ProcessDirectory -> dir ]; + res = RunProcess[ { "git", cmd }, ProcessDirectory -> ExpandFileName @ dir ]; ConfirmAssert[ res[ "ExitCode" ] === 0 ]; StringTrim @ ConfirmBy[ res[ "StandardOutput" ], StringQ ] ]; @@ -169,7 +172,7 @@ actionURL[ ] := Enclose[ (*updatePacletInfo*) updatePacletInfo[ dir_ ] /; $inCICD := Enclose[ Module[ - { cs, file, string, id, date, url, run, cmt, new }, + { cs, file, string, id, date, url, run, cmt, oldID, new }, cs = ConfirmBy[ Echo[ #1, "Update PacletInfo [" <> ToString @ #2 <> "]: " ], StringQ, #2 ] &; file = cs[ FileNameJoin @ { dir, "PacletInfo.wl" }, "Original PacletInfo" ]; @@ -180,13 +183,14 @@ updatePacletInfo[ dir_ ] /; $inCICD := Enclose[ url = cs[ releaseURL @ file, "ReleaseURL" ]; run = cs[ actionURL[ ], "ActionURL" ]; cmt = cs[ commitURL @ id, "CommitURL" ]; + oldID = cs[ PacletObject[ Flatten @ File @ dir ][ "ReleaseID" ], "OldReleaseID" ]; new = cs[ StringReplace[ string, { "\r\n" -> "\n", - "$RELEASE_ID$" -> id, + oldID -> id, "$RELEASE_DATE$" -> date, "$RELEASE_URL$" -> url, "$ACTION_URL$" -> run, @@ -217,8 +221,28 @@ updatePacletInfo[ dir_ ] /; $inCICD := Enclose[ ] ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*setPacletReleaseID*) +(* :!CodeAnalysis::Disable::LeakedVariable:: *) +setPacletReleaseID[ dir_ ] := + setPacletReleaseID[ dir, releaseID @ dir ]; + +setPacletReleaseID[ dir_, id_String? StringQ ] := + Enclose @ Module[ { file, bytes, string, new }, + file = ConfirmBy[ FileNameJoin @ { dir, "PacletInfo.wl" }, FileExistsQ, "PacletInfoFile" ]; + bytes = ConfirmBy[ ReadByteArray @ file, ByteArrayQ, "ByteArray" ]; + Quiet @ Close @ file; + string = ConfirmBy[ ByteArrayToString @ bytes, StringQ, "String" ]; + new = StringReplace[ string, before: ("\"ReleaseID\""~~$$ws~~"->"~~$$ws) ~~ $$id :> before<>"\""<>id<>"\"" ]; + cicd`ConsoleNotice @ SequenceForm[ "Setting paclet release ID: ", id ]; + WithCleanup[ BinaryWrite[ file, StringToByteArray @ new ], Close @ file ]; + id + ]; - +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*updateReleaseInfoCell*) updateReleaseInfoCell[ dir_, url_, cmt_, run_ ] /; Environment[ "GITHUB_WORKFLOW" ] === "Release" := UsingFrontEnd @ Enclose @ Module[ { cells, nbFile, nbo, cell }, @@ -368,7 +392,14 @@ Print[ "ResourceSystemBase: ", $ResourceSystemBase ]; $defNB = File @ FileNameJoin @ { $pacletDir, "ResourceDefinition.nb" }; Print[ "Definition Notebook: ", $defNB ]; -PacletDirectoryLoad @ $pacletDir; +cicd`ScriptConfirmBy[ PacletDirectoryLoad @ $pacletDir, MemberQ @ $pacletDir ]; +cicd`ScriptConfirmAssert[ + StringStartsQ[ FindFile[ "Wolfram`Chatbook`" ], $pacletDir ], + TemplateApply[ + "Chatbook context points to \"`1`\" which is not contained in the expected paclet directory \"`2`\".", + { FindFile["Wolfram`Chatbook`"], $pacletDir } + ] +]; $loadedDefinitions = True; diff --git a/Scripts/FormatFiles.wls b/Scripts/FormatFiles.wls index d5624bd6..e289b66e 100644 --- a/Scripts/FormatFiles.wls +++ b/Scripts/FormatFiles.wls @@ -98,7 +98,8 @@ getFiles[ root_, None ] := FileNames[ "*.nb", root, Infinity ]; getFiles[ root_, ignore_ ] := getFiles[ root, ignore, getNotebookArgs[ ] ]; -getFiles[ root_, ignore_, files: { ___String? FileExistsQ } ] := files; +getFiles[ root_, ignore_, files: { ___String } ] := + Select[ files, FileExistsQ ]; getFiles[ root_, ignore_, _ ] := Select[ FileNames[ { "*.nb", "*.wlt" }, root, Infinity ], @@ -106,11 +107,8 @@ getFiles[ root_, ignore_, _ ] := ]; getNotebookArgs[ ] := getNotebookArgs @ getArg[ "files", None ]; - getNotebookArgs[ nbs_String ] := getNotebookArgs @ StringSplit[ nbs, "\n" ]; - -getNotebookArgs[ { files___String? FileExistsQ } ] := { files }; - +getNotebookArgs[ files: { __String } ] := Select[ files, FileExistsQ ]; getNotebookArgs[ ___ ] := Missing[ "NotFound" ]; (* ::**************************************************************************************************************:: *) diff --git a/Source/Chatbook/Actions.wl b/Source/Chatbook/Actions.wl index b8268c72..ec36c786 100644 --- a/Source/Chatbook/Actions.wl +++ b/Source/Chatbook/Actions.wl @@ -16,47 +16,13 @@ BeginPackage[ "Wolfram`Chatbook`Actions`" ]; `StopChat; `WidgetSend; -`$alwaysOpen; -`$autoOpen; -`$chatState; -`$finalCell; -`$lastCellObject; -`$lastChatString; -`$lastMessages; -`$lastSettings; -`$lastTask; -`$nextTaskEvaluation; -`apiKeyDialog; -`autoAssistQ; -`chatInputCellQ; -`clearMinimizedChats; -`revertMultimodalContent; -`standardizeMessageKeys; -`systemCredential; -`toAPIKey; -`withChatState; - Begin[ "`Private`" ]; -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`ChatHistory`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Dynamics`" ]; -Needs[ "Wolfram`Chatbook`Explode`" ]; -Needs[ "Wolfram`Chatbook`Feedback`" ]; -Needs[ "Wolfram`Chatbook`Formatting`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`Handlers`" ]; -Needs[ "Wolfram`Chatbook`InlineReferences`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; -Needs[ "Wolfram`Chatbook`PersonaManager`" ]; -Needs[ "Wolfram`Chatbook`Prompting`" ]; -Needs[ "Wolfram`Chatbook`SendChat`" ]; -Needs[ "Wolfram`Chatbook`Serialization`" ]; -Needs[ "Wolfram`Chatbook`Services`" ]; -Needs[ "Wolfram`Chatbook`Settings`" ]; -Needs[ "Wolfram`Chatbook`ToolManager`" ]; -Needs[ "Wolfram`Chatbook`Tools`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`PersonaManager`" ]; +Needs[ "Wolfram`Chatbook`Serialization`" ]; +Needs[ "Wolfram`Chatbook`ToolManager`" ]; HoldComplete[ System`GenerateLLMToolResponse, @@ -64,6 +30,11 @@ HoldComplete[ System`LLMToolResponse ]; +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*$ChatEvaluationCell*) +$ChatEvaluationCell = None; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*ChatCellEvaluate*) @@ -92,32 +63,41 @@ ChatCellEvaluate[ args___ ] := (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*ChatbookAction*) -ChatbookAction[ "AccentIncludedCells" , args___ ] := catchMine @ accentIncludedCells @ args; -ChatbookAction[ "AIAutoAssist" , args___ ] := catchMine @ AIAutoAssist @ args; -ChatbookAction[ "Ask" , args___ ] := catchMine @ AskChat @ args; -ChatbookAction[ "AttachCodeButtons" , args___ ] := catchMine @ AttachCodeButtons @ args; -ChatbookAction[ "CopyChatObject" , args___ ] := catchMine @ CopyChatObject @ args; -ChatbookAction[ "CopyExplodedCells" , args___ ] := catchMine @ CopyExplodedCells @ args; -ChatbookAction[ "DisableAssistance" , args___ ] := catchMine @ DisableAssistance @ args; -ChatbookAction[ "EvaluateChatInput" , args___ ] := catchMine @ EvaluateChatInput @ args; -ChatbookAction[ "ExclusionToggle" , args___ ] := catchMine @ ExclusionToggle @ args; -ChatbookAction[ "ExplodeDuplicate" , args___ ] := catchMine @ ExplodeDuplicate @ args; -ChatbookAction[ "ExplodeInPlace" , args___ ] := catchMine @ ExplodeInPlace @ args; -ChatbookAction[ "InsertCodeBelow", args___ ] := catchMine @ insertCodeBelow @ args; -ChatbookAction[ "InsertInlineReference", args___ ] := catchMine @ InsertInlineReference @ args; -ChatbookAction[ "OpenChatBlockSettings", args___ ] := catchMine @ OpenChatBlockSettings @ args; -ChatbookAction[ "OpenChatMenu" , args___ ] := catchMine @ OpenChatMenu @ args; -ChatbookAction[ "PersonaManage" , args___ ] := catchMine @ PersonaManage @ args; -ChatbookAction[ "RemoveCellAccents" , args___ ] := catchMine @ removeCellAccents @ args; -ChatbookAction[ "Send" , args___ ] := catchMine @ SendChat @ args; -ChatbookAction[ "SendFeedback" , args___ ] := catchMine @ SendFeedback @ args; -ChatbookAction[ "StopChat" , args___ ] := catchMine @ StopChat @ args; -ChatbookAction[ "TabLeft" , args___ ] := catchMine @ TabLeft @ args; -ChatbookAction[ "TabRight" , args___ ] := catchMine @ TabRight @ args; -ChatbookAction[ "ToggleFormatting" , args___ ] := catchMine @ ToggleFormatting @ args; -ChatbookAction[ "ToolManage" , args___ ] := catchMine @ ToolManage @ args; -ChatbookAction[ "WidgetSend" , args___ ] := catchMine @ WidgetSend @ args; -ChatbookAction[ args___ ] := catchMine @ throwInternalFailure @ ChatbookAction @ args; +ChatbookAction[ "AccentIncludedCells" , args___ ] := catchMine @ accentIncludedCells @ args; +ChatbookAction[ "AIAutoAssist" , args___ ] := catchMine @ AIAutoAssist @ args; +ChatbookAction[ "Ask" , args___ ] := catchMine @ AskChat @ args; +ChatbookAction[ "AssistantMessageLabel" , args___ ] := catchMine @ assistantMessageLabel @ args; +ChatbookAction[ "AttachCodeButtons" , args___ ] := catchMine @ AttachCodeButtons @ args; +ChatbookAction[ "AttachWorkspaceChatInput" , args___ ] := catchMine @ attachWorkspaceChatInput @ args; +ChatbookAction[ "CopyChatObject" , args___ ] := catchMine @ CopyChatObject @ args; +ChatbookAction[ "CopyExplodedCells" , args___ ] := catchMine @ CopyExplodedCells @ args; +ChatbookAction[ "DisableAssistance" , args___ ] := catchMine @ DisableAssistance @ args; +ChatbookAction[ "DisplayInlineChat" , args___ ] := catchMine @ displayInlineChat @ args; +ChatbookAction[ "EvaluateChatInput" , args___ ] := catchMine @ EvaluateChatInput @ args; +ChatbookAction[ "EvaluateWorkspaceChat" , args___ ] := catchMine @ evaluateWorkspaceChat @ args; +ChatbookAction[ "EvaluateInlineChat" , args___ ] := catchMine @ evaluateInlineChat @ args; +ChatbookAction[ "ExclusionToggle" , args___ ] := catchMine @ ExclusionToggle @ args; +ChatbookAction[ "ExplodeDuplicate" , args___ ] := catchMine @ ExplodeDuplicate @ args; +ChatbookAction[ "ExplodeInPlace" , args___ ] := catchMine @ ExplodeInPlace @ args; +ChatbookAction[ "InsertCodeBelow" , args___ ] := catchMine @ insertCodeBelow @ args; +ChatbookAction[ "InsertInlineReference" , args___ ] := catchMine @ InsertInlineReference @ args; +ChatbookAction[ "MakeWorkspaceChatDockedCell", args___ ] := catchMine @ makeWorkspaceChatDockedCell @ args; +ChatbookAction[ "MoveToChatInputField" , args___ ] := catchMine @ moveToChatInputField @ args; +ChatbookAction[ "OpenChatBlockSettings" , args___ ] := catchMine @ OpenChatBlockSettings @ args; +ChatbookAction[ "OpenChatMenu" , args___ ] := catchMine @ OpenChatMenu @ args; +ChatbookAction[ "PersonaManage" , args___ ] := catchMine @ PersonaManage @ args; +ChatbookAction[ "RemoveCellAccents" , args___ ] := catchMine @ removeCellAccents @ args; +ChatbookAction[ "Send" , args___ ] := catchMine @ SendChat @ args; +ChatbookAction[ "SendFeedback" , args___ ] := catchMine @ SendFeedback @ args; +ChatbookAction[ "StopChat" , args___ ] := catchMine @ StopChat @ args; +ChatbookAction[ "TabLeft" , args___ ] := catchMine @ TabLeft @ args; +ChatbookAction[ "TabRight" , args___ ] := catchMine @ TabRight @ args; +ChatbookAction[ "ToggleFormatting" , args___ ] := catchMine @ ToggleFormatting @ args; +ChatbookAction[ "ToolManage" , args___ ] := catchMine @ ToolManage @ args; +ChatbookAction[ "UpdateDynamics" , args___ ] := catchMine @ updateDynamics @ args; +ChatbookAction[ "UserMessageLabel" , args___ ] := catchMine @ userMessageLabel @ args; +ChatbookAction[ "WidgetSend" , args___ ] := catchMine @ WidgetSend @ args; +ChatbookAction[ args___ ] := catchMine @ throwInternalFailure @ ChatbookAction @ args; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -406,51 +386,53 @@ EvaluateChatInput[ source: _CellObject | $Failed ] := EvaluateChatInput @ evalCell /; chatInputCellQ @ evalCell ]; -(* TODO: resolve auto settings here and set as a Block symbol *) EvaluateChatInput[ evalCell_CellObject, nbo_NotebookObject ] := withChatState @ EvaluateChatInput[ evalCell, nbo, resolveAutoSettings @ currentChatSettings @ evalCell ]; EvaluateChatInput[ evalCell_CellObject, nbo_NotebookObject, settings_Association? AssociationQ ] := - withChatState @ Block[ { $AutomaticAssistance = False, $aborted = False }, - $lastCellObject = None; - $lastChatString = None; - $lastMessages = None; - $nextTaskEvaluation = None; - $enableLLMServices = settings[ "EnableLLMServices" ]; - clearMinimizedChats @ nbo; - - (* Send chat while listening for an abort: *) - CheckAbort[ - sendChat[ evalCell, nbo, settings ]; - waitForLastTask[ ] - , - (* The user has issued an abort: *) - $aborted = True; - (* Clean up the current chat evaluation: *) - With[ { cell = $lastCellObject }, - If[ MatchQ[ cell, _CellObject ], - StopChat @ cell, - removeTask @ $lastTask + withChatStateAndFEObjects[ + { evalCell, nbo }, + Block[ { $AutomaticAssistance = False, $aborted = False }, + $lastCellObject = None; + $lastChatString = None; + $lastMessages = None; + $nextTaskEvaluation = None; + $enableLLMServices = settings[ "EnableLLMServices" ]; + clearMinimizedChats @ nbo; + + (* Send chat while listening for an abort: *) + CheckAbort[ + sendChat[ evalCell, nbo, settings ]; + waitForLastTask[ ] + , + (* The user has issued an abort: *) + $aborted = True; + (* Clean up the current chat evaluation: *) + With[ { cell = $lastCellObject }, + If[ MatchQ[ cell, _CellObject ], + StopChat @ cell, + removeTask @ $lastTask + ] ] - ] - , - PropagateAborts -> False - ]; - - blockChatObject[ - If[ ListQ @ $lastMessages && StringQ @ $lastChatString, - With[ - { - chat = constructChatObject @ Append[ - $lastMessages, - <| "Role" -> "Assistant", "Content" -> $lastChatString |> - ] - }, - applyChatPost[ chat, settings, nbo, $aborted ] - ], - applyChatPost[ None, settings, nbo, $aborted ]; - Null + , + PropagateAborts -> False ]; + + blockChatObject[ + If[ ListQ @ $lastMessages && StringQ @ $lastChatString, + With[ + { + chat = constructChatObject @ Append[ + $lastMessages, + <| "Role" -> "Assistant", "Content" -> $lastChatString |> + ] + }, + applyChatPost[ chat, settings, nbo, $aborted ] + ], + applyChatPost[ None, settings, nbo, $aborted ]; + Null + ]; + ] ] ]; @@ -492,7 +474,6 @@ delayedChatObject // endDefinition; (*chatInputCellQ*) chatInputCellQ[ cell_CellObject ] := chatInputCellQ[ cell ] = chatInputCellQ[ cell, Developer`CellInformation @ cell ]; chatInputCellQ[ cell_, KeyValuePattern[ "Style" -> $$chatInputStyle ] ] := True; -chatInputCellQ[ cell_CellObject, ___ ] := ($badCellObject = cell; $badCell = NotebookRead @ cell; False); chatInputCellQ[ ___ ] := False; (* ::**************************************************************************************************************:: *) @@ -526,12 +507,6 @@ chatOutputCellQ[ cell_, KeyValuePattern[ "Style" -> $$chatOutputStyle ] ] := chatOutputCellQ[ cell_CellObject, KeyValuePattern[ "Style" -> "Output" ] ] /; $cloudNotebooks := MatchQ[ CurrentValue[ cell, { TaggingRules, "ChatNotebookSettings", "CellObject" } ], _CellObject ]; -chatOutputCellQ[ cell_CellObject, ___ ] := ( - $badCellObject = cell; - $badCell = NotebookRead @ cell; - False -); - chatOutputCellQ[ ___ ] := False; @@ -544,7 +519,7 @@ ensureChatOutputCell[ cell_CellObject? chatOutputCellQ ] := ensureChatOutputCell[ cell ] = cell; ensureChatOutputCell[ cell_ ] := - ensureChatOutputCell[ cell, rootEvaluationCell @ cell ]; + ensureChatOutputCell[ cell, topParentCell @ cell ]; ensureChatOutputCell[ cell_CellObject, new_CellObject? chatOutputCellQ ] := ensureChatOutputCell[ cell ] = ensureChatOutputCell[ new ] = new; @@ -552,6 +527,12 @@ ensureChatOutputCell[ cell_CellObject, new_CellObject? chatOutputCellQ ] := ensureChatOutputCell[ cell_, new_CellObject? chatOutputCellQ ] := ensureChatOutputCell[ new ] = new; +ensureChatOutputCell[ cell_, new_CellObject? chatInputCellQ ] := + ensureChatOutputCell[ cell, nextChatOutput @ new ]; + +ensureChatOutputCell[ cell_, None ] := + None; + ensureChatOutputCell // endDefinition; (* ::**************************************************************************************************************:: *) @@ -640,29 +621,67 @@ autoAssistQ // endDefinition; (*StopChat*) StopChat // beginDefinition; +StopChat[ ] := + With[ { cell = $lastCellObject }, + StopChat @ cell /; chatOutputCellQ @ cell + ]; + +StopChat[ ] := + With[ { cell = $ChatEvaluationCell }, + StopChat @ cell /; chatInputCellQ @ cell + ]; + +StopChat[ ] := + StopChat @ rootEvaluationCell[ ]; + StopChat[ cell_CellObject ] := With[ { parent = parentCell @ cell }, StopChat @ parent /; MatchQ[ parent, Except[ cell, _CellObject ] ] ]; StopChat[ cell0_CellObject ] := Enclose[ - Module[ { cell, settings, container, content }, - cell = ConfirmMatch[ ensureChatOutputCell @ cell0, _CellObject, "ParentCell" ]; - settings = ConfirmBy[ currentChatSettings @ cell, AssociationQ, "ChatNotebookSettings" ]; - removeTask @ Lookup[ settings, "Task" ]; - container = ConfirmBy[ Lookup[ settings, "Container" ], AssociationQ, "Container" ]; + Catch @ Module[ { finish, cell, settings, container, content }, + finish = Function[ $ChatEvaluationCell = None; removeTask @ $lastTask; Throw @ Null ]; + cell = ConfirmMatch[ ensureChatOutputCell @ cell0, _CellObject|None, "ParentCell" ]; + If[ cell === None, finish[ ] ]; + settings = ConfirmMatch[ currentChatSettings @ cell, _Association|_Missing, "ChatNotebookSettings" ]; + If[ MissingQ @ settings, finish[ ] ]; + removeTask @ Lookup[ settings, "Task", None ]; + container = ConfirmMatch[ Lookup[ settings, "Container", None ], _Association|None, "Container" ]; + If[ container === None, finish[ ] ]; content = ConfirmMatch[ Lookup[ container, "FullContent" ], _String|_ProgressIndicator, "Content" ]; FinishDynamic[ ]; Block[ { createFETask = # & }, writeReformattedCell[ settings, content, cell ] ] ], - throwInternalFailure[ StopChat @ cell0, ## ] & + throwInternalFailure ]; StopChat[ $Failed ] := - StopChat @ rootEvaluationCell[ ]; + With[ { cell = rootEvaluationCell[ ] }, + If[ MatchQ[ cell, _CellObject ], StopChat @ cell ] + ]; StopChat // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*nextChatOutput*) +nextChatOutput // beginDefinition; +nextChatOutput[ cell_CellObject? chatOutputCellQ ] := cell; +nextChatOutput[ cell_CellObject ] /; $cloudNotebooks := cloudNextChatOutput @ cell; +nextChatOutput[ cell_CellObject ] := NextCell[ cell, CellStyle -> "ChatOutput" ]; +nextChatOutput // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*cloudNextChatOutput*) +cloudNextChatOutput // beginDefinition; +cloudNextChatOutput[ cell_CellObject ] := cloudNextChatOutput[ cell, parentNotebook @ cell ]; +cloudNextChatOutput[ cell_CellObject, nbo_NotebookObject ] := cloudNextChatOutput[ cell, Cells @ nbo ]; +cloudNextChatOutput[ cell_, { ___, cell_, cells___CellObject } ] := SelectFirst[ { cells }, chatOutputCellQ, None ]; +cloudNextChatOutput[ cell_, _ ] := None; +cloudNextChatOutput // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*removeTask*) @@ -886,26 +905,17 @@ setChatSectionSettings // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*$chatContextDialogButtons*) -$chatContextDialogButtons := $chatContextDialogButtons = Get @ FileNameJoin @ { - PacletObject[ "Wolfram/Chatbook" ][ "AssetLocation", "AIAssistant" ], - "ChatContextDialogButtons.wl" -}; +$chatContextDialogButtons := getAsset[ "ChatContextDialogButtons" ]; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*$chatContextDialogTemplateCells*) -$chatContextDialogTemplateCells := $chatContextDialogTemplateCells = Get @ FileNameJoin @ { - PacletObject[ "Wolfram/Chatbook" ][ "AssetLocation", "AIAssistant" ], - "ChatContextDialogCellsTemplate.wl" -}; +$chatContextDialogTemplateCells := getAsset[ "ChatContextDialogCellsTemplate" ]; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*$chatContextDialogStyles*) -$chatContextDialogStyles := $chatContextDialogStyles = Get @ FileNameJoin @ { - PacletObject[ "Wolfram/Chatbook" ][ "AssetLocation", "AIAssistant" ], - "ChatContextDialogStyles.wl" -}; +$chatContextDialogStyles := getAsset[ "ChatContextDialogStyles" ]; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) @@ -970,16 +980,17 @@ scrape // endDefinition; (*AttachCodeButtons*) AttachCodeButtons // beginDefinition; -AttachCodeButtons[ Dynamic[ attached_ ], cell_CellObject? chatCodeBlockQ, string_, lang_ ] := ( - attached = AttachCell[ - cell, - floatingButtonGrid[ attached, cell, lang ], - { Left, Bottom }, - Offset[ { 0, 13 }, { 0, 0 } ], - { Left, Top }, - RemovalConditions -> { "MouseClickOutside", "MouseExit" } - ] -); +AttachCodeButtons[ Dynamic[ attached_ ], cell_CellObject? chatCodeBlockQ, string_, lang_ ] := + Block[ { $InlineChat = inlineChatQ @ cell }, + attached = AttachCell[ + cell, + floatingButtonGrid[ attached, cell, lang ], + { Left, Bottom }, + Offset[ { 0, 13 }, { 0, 0 } ], + { Left, Top }, + RemovalConditions -> { "MouseClickOutside", "MouseExit" } + ] + ]; AttachCodeButtons[ attached_, cell_CellObject, string_, lang_ ] := Enclose[ Catch @ Module[ { parent, evalCell, newParent }, @@ -1004,6 +1015,13 @@ AttachCodeButtons[ attached_, cell_CellObject, string_, lang_ ] := Enclose[ AttachCodeButtons // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*inlineChatQ*) +inlineChatQ // beginDefinition; +inlineChatQ[ cell_CellObject ] := inlineChatQ[ cell ] = currentChatSettings[ cell, "InlineChat" ]; +inlineChatQ // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*chatCodeBlockQ*) @@ -1146,7 +1164,8 @@ SendChat[ evalCell_CellObject, nbo_NotebookObject, settings_Association? Associa SendChat[ evalCell_, nbo_, settings_, Automatic ] /; $cloudNotebooks := SendChat[ evalCell, nbo, settings, False ]; -SendChat[ evalCell_, nbo_, settings_, Automatic ] := withChatState @ +SendChat[ evalCell_, nbo_, settings_, Automatic ] := withChatStateAndFEObjects[ + { evalCell, nbo }, With[ { styles = cellStyles @ evalCell }, Block[ { $autoOpen, $alwaysOpen = $alwaysOpen }, $autoOpen = MemberQ[ styles, $$chatInputStyle ]; @@ -1154,13 +1173,16 @@ SendChat[ evalCell_, nbo_, settings_, Automatic ] := withChatState @ $enableLLMServices = settings[ "EnableLLMServices" ]; sendChat[ evalCell, nbo, addCellStyleSettings[ settings, styles ] ] ] - ]; + ] +]; -SendChat[ evalCell_, nbo_, settings_, minimized_ ] := withChatState @ +SendChat[ evalCell_, nbo_, settings_, minimized_ ] := withChatStateAndFEObjects[ + { evalCell, nbo }, Block[ { $alwaysOpen = alwaysOpenQ[ settings, minimized ] }, $enableLLMServices = settings[ "EnableLLMServices" ]; sendChat[ evalCell, nbo, addCellStyleSettings[ settings, evalCell ] ] - ]; + ] +]; SendChat // endDefinition; @@ -1346,7 +1368,7 @@ showAPIKeyDialog[ ] := AuthenticationDialog[ { "APIKey" -> <| "Masked" -> True, - "Label" -> "API Key", + "Label" -> tr[ "ActionsAPIKeyDialogAPIKey" ], "Control" -> Function[ InputField[ ##, @@ -1358,11 +1380,11 @@ showAPIKeyDialog[ ] := AuthenticationDialog[ ] ] |>, - "Save" -> <| "Interpreter" -> "Boolean" |> + "Save" -> <| "Interpreter" -> "Boolean", "Label" -> tr[ "ActionsAPIKeyDialogSave" ] |> }, AppearanceRules -> { - "Title" -> "Please enter your OpenAI API key", - "Description" -> $apiKeyDialogDescription + "Title" -> tr[ "ActionsAPIKeyDialogTitle" ], + "Description" -> getAsset[ "APIKeyDialogDescription" ] } ], WindowSize -> { 400, All }, @@ -1371,45 +1393,49 @@ showAPIKeyDialog[ ] := AuthenticationDialog[ showAPIKeyDialog // endDefinition; - -$apiKeyDialogDescription := $apiKeyDialogDescription = Get @ FileNameJoin @ { - PacletObject[ "Wolfram/Chatbook" ][ "AssetLocation", "AIAssistant" ], - "APIKeyDialogDescription.wl" -}; - (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) -(*Settings*) +(*Paclet Assets*) (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) -(*withChatState*) -withChatState // beginDefinition; -withChatState // Attributes = { HoldFirst }; +(*getAsset*) +getAsset // beginDefinition; + +getAsset[ name0_String? StringQ ] := Enclose[ + Module[ { name, dir, file, expr }, + name = StringDelete[ name0, ".wl"~~EndOfString ] <> ".wl"; + dir = ConfirmBy[ $thisPaclet[ "AssetLocation", "AIAssistant" ], DirectoryQ, "Directory" ]; + file = ConfirmBy[ FileNameJoin @ { dir, name }, FileExistsQ, "File" ]; + expr = Confirm[ getAssetFile @ file, "Expression" ]; + getAsset[ name ] = expr + ], + throwInternalFailure +]; + +getAsset // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*getAssetFile*) +getAssetFile // beginDefinition; -(* TODO: create a `$CurrentChatSettings` symbol that's scoped here and defined as soon as settings are resolved *) -withChatState[ eval_ ] := +getAssetFile[ file_? FileExistsQ ] := Block[ { - $AutomaticAssistance = False, - $chatState = True, - $enableLLMServices = Automatic, - withChatState = # & + $Context = "Wolfram`ChatNB`", + $ContextPath = { "Wolfram`ChatNB`", "Wolfram`Chatbook`Common`", "System`" } }, - $ChatHandlerData = <| |>; - withToolBox @ withBasePromptBuilder @ eval + Get @ file ]; -withChatState // endDefinition; +getAssetFile // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - $chatContextDialogButtons; - $chatContextDialogTemplateCells; - $chatContextDialogStyles; - $apiKeyDialogDescription; +addToMXInitialization[ + Null ]; End[ ]; diff --git a/Source/Chatbook/ChatGroups.wl b/Source/Chatbook/ChatGroups.wl index e0201ffa..707814ed 100644 --- a/Source/Chatbook/ChatGroups.wl +++ b/Source/Chatbook/ChatGroups.wl @@ -1,17 +1,12 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`ChatGroups`" ]; +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -`getChatGroupPrompt; -`getChatGroupSettings; - -Begin[ "`Private`" ]; - -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -103,8 +98,8 @@ cellGroupingOrder // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/ChatHistory.wl b/Source/Chatbook/ChatHistory.wl index 6ec46ec0..68c14103 100644 --- a/Source/Chatbook/ChatHistory.wl +++ b/Source/Chatbook/ChatHistory.wl @@ -1,27 +1,13 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`ChatHistory`" ]; +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -HoldComplete[ - `accentIncludedCells; - `chatExcludedQ; - `extraCellHeight; - `filterChatCells; - `getCellsInChatHistory; - `removeCellAccents; -]; - -Begin[ "`Private`" ]; - -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Actions`" ]; -Needs[ "Wolfram`Chatbook`ChatMessages`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`SendChat`" ]; -Needs[ "Wolfram`Chatbook`Settings`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Actions`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -190,6 +176,8 @@ chatExcludedQ[ KeyValuePattern[ "ChatNotebookSettings" -> settings_ ] ] := chatE chatExcludedQ[ KeyValuePattern[ "ExcludeFromChat" -> exclude_ ] ] := TrueQ @ exclude; chatExcludedQ[ KeyValuePattern[ { } ] ] := False; chatExcludedQ[ Inherited ] := False; +chatExcludedQ[ _? FailureQ ] := False; +chatExcludedQ[ _FrontEnd`AbsoluteCurrentValue ] := False; chatExcludedQ // endDefinition; @@ -282,8 +270,8 @@ extraCellHeight // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/ChatMessages.wl b/Source/Chatbook/ChatMessages.wl index 8b8f6572..395b39e0 100644 --- a/Source/Chatbook/ChatMessages.wl +++ b/Source/Chatbook/ChatMessages.wl @@ -1,41 +1,15 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`ChatMessages`" ]; - -(* cSpell: ignore nodef *) +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -Wolfram`Chatbook`CellToChatMessage; - -`$chatDataTag; -`$initialCellStringBudget; -`$multimodalMessages; -`$tokenBudget; -`$tokenPressure; -`cachedTokenizer; -`constructMessages; -`expandMultimodalString; -`getTokenizer; -`getTokenizerName; -`logUsage; -`resizeMultimodalImage; - -Begin[ "`Private`" ]; - -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Actions`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`Handlers`" ]; -Needs[ "Wolfram`Chatbook`InlineReferences`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; -Needs[ "Wolfram`Chatbook`Personas`" ]; -Needs[ "Wolfram`Chatbook`Prompting`" ]; -Needs[ "Wolfram`Chatbook`Serialization`" ]; -Needs[ "Wolfram`Chatbook`Settings`" ]; -Needs[ "Wolfram`Chatbook`Tools`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Actions`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`Personas`" ]; +Needs[ "Wolfram`Chatbook`Serialization`" ]; $ContextAliases[ "tokens`" ] = "Wolfram`LLMFunctions`Utilities`Tokenization`"; @@ -77,15 +51,18 @@ $cachedTokenizerNames = { "chat-bison", "claude-3", "claude", + "generic", "gpt-2", "gpt-3.5", + "gpt-4o", + "gpt-4o-text", "gpt-4-turbo", "gpt-4-vision", "gpt-4" }; -$cachedTokenizers = <| |>; -$fallbackTokenizer = "gpt-2"; +$cachedTokenizers = <| |>; +$fallbackTokenizer = "generic"; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -101,7 +78,7 @@ CellToChatMessage[ cell_Cell, settings_Association? AssociationQ, opts: OptionsP Replace[ Flatten @ { If[ TrueQ @ Positive @ Lookup[ settings, "HistoryPosition", 0 ], - makeCellMessage @ cell, + makeCellMessage[ cell, settings ], makeCurrentCellMessage[ settings, Replace[ @@ -126,6 +103,9 @@ constructMessages // beginDefinition; constructMessages[ _Association? AssociationQ, { } ] := { }; +constructMessages[ settings_Association? AssociationQ, cells: { __CellObject } ] /; $InlineChat := + constructInlineMessages @ settings; + constructMessages[ settings_Association? AssociationQ, cells: { __CellObject } ] := constructMessages[ settings, notebookRead @ cells ]; @@ -140,7 +120,7 @@ constructMessages[ settings_Association? AssociationQ, messages0: { __Associatio If[ settings[ "AutoFormat" ], needsBasePrompt[ "Formatting" ] ]; needsBasePrompt @ settings; - prompted = addPrompts[ settings, messages0 ]; + prompted = addPrompts[ settings, messages0 ]; messages = prompted /. s_String :> RuleCondition @ StringTrim @ StringReplace[ @@ -171,15 +151,42 @@ constructMessages[ settings_Association? AssociationQ, messages0: { __Associatio constructMessages // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*constructInlineMessages*) +constructInlineMessages // beginDefinition; + +constructInlineMessages[ settings_ ] := + constructInlineMessages[ settings, $inlineChatState ]; + +constructInlineMessages[ settings_, state_Association ] := + constructInlineMessages[ settings, state, state[ "MessageCells" ] ]; + +constructInlineMessages[ settings_, state_, Dynamic[ cells_ ] ] := + constructInlineMessages[ settings, state, cells ]; + +constructInlineMessages[ settings_, state_, cells: { __Cell } ] := + constructMessages[ settings, cells ]; + +constructInlineMessages // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*addPrompts*) addPrompts // beginDefinition; -addPrompts[ settings_Association, messages_List ] := - addPrompts[ assembleCustomPrompt @ settings, messages ]; +addPrompts[ settings_Association, messages_List ] := Enclose[ + Module[ { custom, workspace, inline, prompt }, + custom = ConfirmMatch[ assembleCustomPrompt @ settings, None|_String, "Custom" ]; + workspace = ConfirmMatch[ getWorkspacePrompt @ settings , None|_String, "Workspace" ]; + inline = ConfirmMatch[ getInlineChatPrompt @ settings , None|_String, "Inline" ]; + prompt = StringRiffle[ Select[ { custom, workspace, inline }, StringQ ], "\n\n" ]; + addPrompts[ prompt, messages ] + ], + throwInternalFailure +]; -addPrompts[ None, messages_List ] := +addPrompts[ None|"", messages_List ] := messages; addPrompts[ prompt_String, { sysMessage: KeyValuePattern[ "Role" -> "System" ], messages___ } ] := Enclose[ @@ -213,7 +220,7 @@ assembleCustomPrompt[ settings_? AssociationQ, templated: { ___, _TemplateObject prompts = Replace[ templated, t_TemplateObject :> applyPromptTemplate[ t, params ], { 1 } ]; assembleCustomPrompt[ settings, prompts ] /; MatchQ[ prompts, { ___String } ] ], - throwInternalFailure[ assembleCustomPrompt[ settings, templated ], ## ] & + throwInternalFailure ]; assembleCustomPrompt // endDefinition; @@ -237,6 +244,16 @@ applyPromptTemplate // endDefinition; makeChatMessages // beginDefinition; makeChatMessages[ settings_, cells_ ] := + makeChatMessages[ settings, cells, True ]; + +makeChatMessages[ settings_, cells_, includeSystem_ ] /; $chatState := + Block[ { $chatInputIndicator = mixedContentQ @ cells }, + If[ includeSystem && settings[ "BasePrompt" ] =!= None, tokenCheckedMessage[ settings, $fullBasePrompt ] ]; + (* FIXME: need to account for persona/tool prompting as well *) + makeChatMessages0[ settings, cells, includeSystem ] + ]; + +makeChatMessages[ settings_, cells_, includeSystem_ ] := Block[ { $multimodalMessages = TrueQ @ settings[ "Multimodal" ], @@ -244,12 +261,13 @@ makeChatMessages[ settings_, cells_ ] := $tokenPressure = 0.0, $initialCellStringBudget = makeCellStringBudget @ settings, $chatInputIndicator = mixedContentQ @ cells, - $cellStringBudget + $cellStringBudget, $conversionRules }, + $conversionRules = settings[ "ConversionRules" ]; $cellStringBudget = $initialCellStringBudget; - If[ settings[ "BasePrompt" ] =!= None, tokenCheckedMessage[ settings, $fullBasePrompt ] ]; + If[ includeSystem && settings[ "BasePrompt" ] =!= None, tokenCheckedMessage[ settings, $fullBasePrompt ] ]; (* FIXME: need to account for persona/tool prompting as well *) - makeChatMessages0[ settings, cells ] + makeChatMessages0[ settings, cells, includeSystem ] ]; makeChatMessages // endDefinition; @@ -257,20 +275,18 @@ makeChatMessages // endDefinition; makeChatMessages0 // beginDefinition; -makeChatMessages0[ settings_, { cells___, cell_ ? promptFunctionCellQ } ] := ( +makeChatMessages0[ settings_, { cells___, cell_ ? promptFunctionCellQ }, includeSystem_ ] := ( Sow[ <| "RawOutput" -> True |>, $chatDataTag ]; makePromptFunctionMessages[ settings, { cells, cell } ] ); -makeChatMessages0[ settings0_, cells_List ] := Enclose[ +makeChatMessages0[ settings0_, cells_List, includeSystem_ ] := Enclose[ Module[ { settings, role, message, toMessage0, toMessage, cell, history, messages, merged }, settings = ConfirmBy[ <| settings0, "HistoryPosition" -> 0, "Cells" -> cells |>, AssociationQ, "Settings" ]; - role = makeCurrentRole @ settings; + role = If[ TrueQ @ includeSystem, makeCurrentRole @ settings, Missing[ ] ]; cell = ConfirmMatch[ Last[ cells, $Failed ], _Cell, "Cell" ]; toMessage0 = Confirm[ getCellMessageFunction @ settings, "CellMessageFunction" ]; - $tokenBudgetLog = Internal`Bag[ ]; - toMessage = Function @ With[ { msg = toMessage0[ #1, <| #2, "TokenBudget" -> $tokenBudget, "TokenPressure" -> $tokenPressure |> ] }, tokenCheckedMessage[ settings, msg ] @@ -297,7 +313,7 @@ makeChatMessages0[ settings0_, cells_List ] := Enclose[ merged = If[ TrueQ @ Lookup[ settings, "MergeMessages" ], mergeMessageData @ messages, messages ]; $lastMessageList = merged ], - throwInternalFailure[ makeChatMessages0[ settings0, cells ], ## ] & + throwInternalFailure ]; makeChatMessages0 // endDefinition; @@ -416,7 +432,7 @@ tokenCheckedMessage[ as_Association, message_ ] := Enclose[ message ], - throwInternalFailure[ tokenCheckedMessage[ as, message ], ## ] & + throwInternalFailure ]; tokenCheckedMessage // endDefinition; @@ -528,12 +544,27 @@ logUsage // endDefinition; (* ::Subsubsection::Closed:: *) (*applyTokenizer*) applyTokenizer // beginDefinition; -applyTokenizer[ tokenizer_, content_String ] := tokenizer @ content; -applyTokenizer[ tokenizer_, content_? graphicsQ ] := tokenizer @ content; +applyTokenizer[ tokenizer_, content_String ] := applyTokenizer0[ tokenizer, content ]; +applyTokenizer[ tokenizer_, content_? graphicsQ ] := applyTokenizer0[ tokenizer, content ]; applyTokenizer[ tokenizer_, content_List ] := Flatten[ applyTokenizer[ tokenizer, # ] & /@ content ]; -applyTokenizer[ tokenizer_, KeyValuePattern[ "Data" -> data_ ] ] := tokenizer @ data; +applyTokenizer[ tokenizer_, KeyValuePattern[ "Data" -> data_ ] ] := applyTokenizer0[ tokenizer, data ]; applyTokenizer // endDefinition; + +applyTokenizer0 // beginDefinition; +(* cSpell: ignore invencin *) +applyTokenizer0[ tokenizer_, content_ ] := + Module[ { result, $retry }, + result = Quiet[ Check[ tokenizer @ content, $retry, NetEncoder::invencin ], NetEncoder::invencin ]; + If[ result === $retry, + Pause[ 0.1 ]; + tokenizer @ content, + result + ] + ]; + +applyTokenizer0 // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*messageContent*) @@ -751,13 +782,19 @@ makeCurrentCellMessage[ settings_, { cells___, cell0_ } ] := Enclose[ Module[ { modifiers, cell, role, content }, { modifiers, cell } = ConfirmMatch[ extractModifiers @ cell0, { _, _ }, "Modifiers" ]; role = ConfirmBy[ cellRole @ cell, StringQ, "CellRole" ]; - content = ConfirmBy[ Block[ { $CurrentCell = True }, makeMessageContent @ cell ], validContentQ, "Content" ]; + + content = ConfirmBy[ + Block[ { $CurrentCell = True }, makeMessageContent[ cell, role, settings ] ], + validContentQ, + "Content" + ]; + Flatten @ { expandModifierMessages[ settings, modifiers, { cells }, cell ], <| "Role" -> role, "Content" -> content |> } ], - throwInternalFailure[ makeCurrentCellMessage[ settings, { cells, cell0 } ], ## ] & + throwInternalFailure ]; makeCurrentCellMessage // endDefinition; @@ -767,19 +804,43 @@ makeCurrentCellMessage // endDefinition; (*makeMessageContent*) makeMessageContent // beginDefinition; -makeMessageContent[ cell_Cell ] /; $multimodalMessages := Enclose[ - Module[ { string, split, joined }, +makeMessageContent[ cell_Cell, role_String, settings_ ] /; $multimodalMessages := Enclose[ + Module[ { string, roles }, string = ConfirmBy[ cellToString @ cell, StringQ, "CellToString" ]; - expandMultimodalString @ string + roles = ConfirmMatch[ allowedMultimodalRoles @ settings, All | { ___String }, "Roles" ]; + If[ MatchQ[ roles, All | { ___, role, ___ } ], + expandMultimodalString @ string, + string + ] ], - throwInternalFailure[ makeMessageContent @ cell, ## ] & + throwInternalFailure ]; -makeMessageContent[ cell_Cell ] := +makeMessageContent[ cell_Cell, role_, settings_ ] := cellToString @ cell; makeMessageContent // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*allowedMultimodalRoles*) +allowedMultimodalRoles // beginDefinition; +allowedMultimodalRoles[ settings_ ] := allowedMultimodalRoles0 @ toModelName @ settings[ "Model" ]; +allowedMultimodalRoles // endDefinition; + + +allowedMultimodalRoles0 // beginDefinition; + +allowedMultimodalRoles0[ model_String ] := allowedMultimodalRoles0[ model ] = + If[ StringContainsQ[ model, WordBoundary~~"gpt-4o"~~WordBoundary ], + { "User" }, + All + ]; + +allowedMultimodalRoles0[ _Missing ] := All; + +allowedMultimodalRoles0 // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*expandMultimodalStrings*) @@ -909,7 +970,15 @@ validContentPartQ[ ___ ] := False; (* ::Subsection::Closed:: *) (*makeCellMessage*) makeCellMessage // beginDefinition; -makeCellMessage[ cell_Cell ] := <| "Role" -> cellRole @ cell, "Content" -> makeMessageContent @ cell |>; + +makeCellMessage[ cell_Cell, settings_ ] := + With[ { role = cellRole @ cell }, + <| + "Role" -> role, + "Content" -> makeMessageContent[ cell, role, settings ] + |> + ]; + makeCellMessage // endDefinition; (* ::**************************************************************************************************************:: *) @@ -929,6 +998,8 @@ cellRole[ Cell[ cellRole[ Cell[ _, styles__String, OptionsPattern[ ] ] ] := FirstCase[ { styles }, style_ :> With[ { role = $styleRoles @ style }, role /; StringQ @ role ], "User" ]; +cellRole[ Cell[ _, OptionsPattern[ ] ] ] := "User"; + cellRole // endDefinition; (* ::**************************************************************************************************************:: *) @@ -955,33 +1026,70 @@ mergeMessages // beginDefinition; mergeMessages[ { } ] := Nothing; mergeMessages[ { message_ } ] := message; -mergeMessages[ messages: { first_Association, __Association } ] := - Module[ { role, content, stitch }, - role = Lookup[ first, "Role" ]; - content = Flatten @ Lookup[ messages, "Content" ]; - stitch = StringDelete[ #1, Longest[ "```\n\n```"~~("wl"|"") ] ] &; +mergeMessages[ messages: { first_Association, __Association } ] := Enclose[ + Module[ { role, content, merged }, + role = ConfirmBy[ Lookup[ first, "Role" ], StringQ, "Role" ]; + + content = Replace[ + Flatten @ Lookup[ messages, "Content" ], + KeyValuePattern @ { "Type" -> "Text", "Data" -> s_String } :> s, + { 1 } + ]; - If[ AllTrue[ content, StringQ ], - <| - "Role" -> role, - "Content" -> stitch @ StringRiffle[ content, "\n\n" ] - |>, - <| - "Role" -> role, - "Content" -> FixedPoint[ - Replace @ { - { a___, b_String, c_String, d___ } :> { a, stitch[ b<>"\n\n"<>c ], d }, - { a___, b_String, { c_String, d___ }, e___ } :> { a, { stitch[ b<>"\n\n"<>c ], d }, e }, - { a___, { b___, c_String }, d_String, e___ } :> { a, { b, stitch[ c<>"\n\n"<>d ] }, e } - }, - content - ] - |> - ] - ]; + merged = ConfirmMatch[ mergeCodeBlocks @ content, { (_String|_Association)... }, "Merged" ]; + + <| "Role" -> role, "Content" -> merged |> + ], + throwInternalFailure +]; mergeMessages // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*mergeCodeBlocks*) +mergeCodeBlocks // beginDefinition; + +mergeCodeBlocks[ content_List ] := Enclose[ + Module[ { split, joined }, + split = SplitBy[ content, StringQ ]; + joined = Replace[ split, s: { __String } :> mergeCodeBlocks @ StringRiffle[ s, "\n\n" ], { 1 } ]; + Flatten @ joined + ], + throwInternalFailure +]; + +mergeCodeBlocks[ string0_String ] := Enclose[ + Catch @ Module[ { string, split, strings }, + string = StringReplace[ string0, "```\n\n"~~("\n"..)~~"```" :> "```\n\n```" ]; + + split = StringSplit[ + string, + Shortest[ "```" ~~ lang: Except[ WhitespaceCharacter ]... ~~ "\n" ~~ code__ ~~ "\n```" ] :> + codeBlock[ StringTrim @ lang, StringTrim @ code ] + ]; + + strings = Replace[ + FixedPoint[ + Replace[ + { a___, codeBlock[ lang_, code1_ ], "\n\n", codeBlock[ lang_, code2_ ], b___ } :> + { a, codeBlock[ lang, code1<>"\n\n"<>code2 ], b } + ], + split + ], + codeBlock[ lang_, code_ ] :> "```"<>lang<>"\n"<>code<>"\n```", + { 1 } + ]; + + ConfirmAssert[ AllTrue[ strings, StringQ ], "StringCheck" ]; + + mergeCodeBlocks[ string0 ] = StringJoin @ strings + ], + throwInternalFailure +]; + +mergeCodeBlocks // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Prompt Repository Integration*) @@ -1010,6 +1118,7 @@ inlineFunctionReferenceBoxesQ[ ___ ] := False; (*makePromptFunctionMessages*) makePromptFunctionMessages // beginDefinition; +(* cSpell: ignore nodef *) makePromptFunctionMessages[ settings_, { cells___, cell0_ } ] := Enclose[ Module[ { modifiers, cell, name, arguments, filled, prompt, string }, (* Ensure Wolfram/LLMFunctions is installed and loaded before calling System`LLMPrompt[..] *) @@ -1268,7 +1377,7 @@ cachedTokenizer[ id_String ] := Enclose[ tokenizer = findTokenizer @ name; If[ MissingQ @ tokenizer, (* Fallback to the GPT-2 tokenizer: *) - tokenizer = ConfirmMatch[ $gpt2Tokenizer, Except[ $$unspecified ], "GPT2Tokenizer" ]; + tokenizer = ConfirmMatch[ $genericTokenizer, Except[ $$unspecified ], "GPT2Tokenizer" ]; If[ TrueQ @ Wolfram`ChatbookInternal`$BuildingMX, tokenizer, (* Avoid caching fallback values into MX definitions *) cacheTokenizer[ name, tokenizer ] @@ -1298,6 +1407,11 @@ cacheTokenizer // endDefinition; (*findTokenizer*) findTokenizer // beginDefinition; +findTokenizer[ "gpt-4o-text" ] := + With[ { tokenizer = findTokenizer[ "gpt-4o" ] }, + tokenizer /; ! MissingQ @ tokenizer + ]; + findTokenizer[ model_String ] := Enclose[ Quiet @ Module[ { name, tokenizer }, initTools[ ]; @@ -1316,9 +1430,10 @@ findTokenizer // endDefinition; (* ::Subsubsubsection::Closed:: *) (*Pre-cached small tokenizer functions*) $cachedTokenizers[ "chat-bison" ] = ToCharacterCode[ #, "UTF8" ] &; -$cachedTokenizers[ "gpt-4-turbo" ] = If[ graphicsQ @ #, gpt4ImageTokenizer, cachedTokenizer[ "gpt-4" ] ][ # ] &; $cachedTokenizers[ "gpt-4-vision" ] = If[ graphicsQ @ #, gpt4ImageTokenizer, cachedTokenizer[ "gpt-4" ] ][ # ] &; +$cachedTokenizers[ "gpt-4o" ] = If[ graphicsQ @ #, gpt4ImageTokenizer, cachedTokenizer[ "gpt-4o-text" ] ][ # ] &; $cachedTokenizers[ "claude-3" ] = If[ graphicsQ @ #, claude3ImageTokenizer, cachedTokenizer[ "claude" ] ][ # ] &; +$cachedTokenizers[ "generic" ] = If[ graphicsQ @ #, { }, $gpt2Tokenizer @ # ] &; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) @@ -1326,6 +1441,7 @@ $cachedTokenizers[ "claude-3" ] = If[ graphicsQ @ #, claude3ImageTokenizer, tokenizerName // beginDefinition; tokenizerName[ "gpt-4-turbo-preview" ] = "gpt-4"; +tokenizerName[ "gpt-4-turbo" ] = "gpt-4-vision"; tokenizerName[ name_String ] := SelectFirst[ @@ -1418,7 +1534,7 @@ importResourceFunction[ gpt2Tokenizer, "GPTTokenizer" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ cachedTokenizer[ All ]; $gpt2Tokenizer; (* This is only needed to generate $gpt2Tokenizer once, so it can be removed to reduce MX file size: *) diff --git a/Source/Chatbook/ChatModes/ChatModes.wl b/Source/Chatbook/ChatModes/ChatModes.wl new file mode 100644 index 00000000..72f03983 --- /dev/null +++ b/Source/Chatbook/ChatModes/ChatModes.wl @@ -0,0 +1,59 @@ +(* ::Section::Closed:: *) +(*Package Header*) +BeginPackage[ "Wolfram`Chatbook`ChatModes`" ]; +Begin[ "`Private`" ]; + +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; + +(* TODO: + * Workspace Chat + * Get context from multiple notebooks + * Set up an LLM subtask to choose relevant notebooks for inclusion + * Fine-grained selection prompts (e.g. specific character ranges, instead of whole cells) + * Update serialization to include cell identifiers when serializing notebook context + * Create NotebookEditor tool that utilizes these cell identifiers to allow for editing of notebooks + * Create test writer tool + * Define a `$ChatEvaluationMode` that gives "Inline", "Workspace", or None based on the current chat mode +*) + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*$WorkspaceChat*) +GeneralUtilities`SetUsage[ "\ +$WorkspaceChat gives True when chat is occurring in a separate dedicated chat window and False otherwise." ]; + +$WorkspaceChat = False; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*$WorkspaceChat*) +GeneralUtilities`SetUsage[ "\ +$InlineChat gives True when chat is occurring in an attached chat cell and False otherwise." ]; + +$InlineChat = False; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Load Subcontexts*) +$subcontexts = { + "Wolfram`Chatbook`ChatModes`Common`", + "Wolfram`Chatbook`ChatModes`Context`", + "Wolfram`Chatbook`ChatModes`Evaluate`", + "Wolfram`Chatbook`ChatModes`ShowCodeAssistance`", + "Wolfram`Chatbook`ChatModes`UI`" +}; + +Scan[ Needs[ # -> None ] &, $subcontexts ]; + +$ChatbookContexts = Union[ $ChatbookContexts, $subcontexts ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Package Footer*) +addToMXInitialization[ + Null +]; + +End[ ]; +EndPackage[ ]; diff --git a/Source/Chatbook/ChatModes/Common.wl b/Source/Chatbook/ChatModes/Common.wl new file mode 100644 index 00000000..cda3b9ce --- /dev/null +++ b/Source/Chatbook/ChatModes/Common.wl @@ -0,0 +1,20 @@ +BeginPackage[ "Wolfram`Chatbook`ChatModes`Common`" ]; + +HoldComplete[ + `$defaultUserImage, + `$inlineChatScrollPosition, + `$inputFieldFrameOptions, + `$inputFieldGridMagnification, + `$inputFieldOptions, + `$inputFieldOuterBackground, + `$inputFieldPaneMargins, + `createWorkspaceChat, + `findCurrentWorkspaceChat, + `getSelectionInfo, + `moveToInlineChatInputField, + `scrollInlineChat, + `userNotebookQ, + `validInputStringQ +]; + +EndPackage[ ]; \ No newline at end of file diff --git a/Source/Chatbook/ChatModes/Context.wl b/Source/Chatbook/ChatModes/Context.wl new file mode 100644 index 00000000..6834a1ee --- /dev/null +++ b/Source/Chatbook/ChatModes/Context.wl @@ -0,0 +1,470 @@ +(* ::Section::Closed:: *) +(*Package Header*) +BeginPackage[ "Wolfram`Chatbook`ChatModes`Context`" ]; +Begin[ "`Private`" ]; + +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`ChatModes`Common`" ]; +Needs[ "Wolfram`Chatbook`Serialization`" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Configuration*) +$maxCellsBeforeSelection = 100; +$maxCellsAfterSelection = 10; + +$currentSelectionIndicator = { $leftSelectionIndicator, $rightSelectionIndicator }; + +$notebookContextTemplate = StringTemplate[ "\ +IMPORTANT: Below is some context from the user's currently selected notebook. \ +The location of the user's current selection is marked by %%SelectionIndicator%%. \ +Use this to determine where the user is in the notebook. + +%%NotebookContent%%", Delimiters -> "%%" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Context from other notebooks*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*getInlineChatPrompt*) +getInlineChatPrompt // beginDefinition; + +getInlineChatPrompt[ settings_ ] := + If[ TrueQ @ $InlineChat, + getInlineChatPrompt0[ settings, $inlineChatState ], + None + ]; + +getInlineChatPrompt // endDefinition; + + +getInlineChatPrompt0 // beginDefinition; + +getInlineChatPrompt0[ settings_, state_Association ] := + getInlineChatPrompt0[ + settings, + state[ "SelectionInfo" ], + state[ "ParentCell" ], + state[ "ParentNotebook" ] + ]; + +getInlineChatPrompt0[ settings_, info_, cell_CellObject, nbo_NotebookObject ] := + getInlineChatPrompt0[ settings, info, cell, Cells @ nbo ]; + +getInlineChatPrompt0[ + settings_, + info_, + cell_CellObject, + { before___CellObject, cell_, after___CellObject } +] := + Block[ { $selectionInfo = info }, + getContextFromSelection0[ + <| + "Before" -> { before }, + "Selected" -> { cell }, + "After" -> { after } + |>, + settings + ] + ]; + +getInlineChatPrompt0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*getWorkspacePrompt*) +getWorkspacePrompt // beginDefinition; + +getWorkspacePrompt[ settings_Association ] := + If[ TrueQ @ $WorkspaceChat, + getContextFromSelection[ $evaluationNotebook, settings ], + None + ]; + +getWorkspacePrompt // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*getContextFromSelection*) +getContextFromSelection // beginDefinition; + +getContextFromSelection[ chatNB_NotebookObject, settings_Association ] := + getContextFromSelection[ chatNB, getUserNotebook @ chatNB, settings ]; + +getContextFromSelection[ chatNB_NotebookObject, None, settings_Association ] := + None; + +getContextFromSelection[ chatNB_, nbo_NotebookObject, settings_Association ] := Enclose[ + Module[ { selectionData }, + selectionData = ConfirmBy[ selectContextCells @ nbo, AssociationQ, "SelectionData" ]; + ConfirmBy[ getContextFromSelection0[ selectionData, settings ], StringQ, "Context" ] + ], + throwInternalFailure +]; + +getContextFromSelection // endDefinition; + + +getContextFromSelection0 // beginDefinition; + +getContextFromSelection0[ selectionData: KeyValuePattern[ "Selected" -> { cell_CellObject } ], settings_ ] /; + ! MatchQ[ $selectionInfo, None|_Association ] := + Block[ { $selectionInfo = getSelectionInfo @ cell }, + getContextFromSelection0[ selectionData, settings ] /; MatchQ[ $selectionInfo, None|_Association ] + ]; + +getContextFromSelection0[ selectionData_Association, settings_ ] := Enclose[ + Catch @ Module[ { cellObjects, cells, len1, len2, before, selected, after, marked, messages, string }, + + cellObjects = ConfirmMatch[ Flatten @ Values @ selectionData, { ___CellObject }, "CellObjects" ]; + cells = ConfirmMatch[ notebookRead @ cellObjects, { ___Cell }, "Cells" ]; + + len1 = Length @ ConfirmMatch[ selectionData[ "Before" ], { ___CellObject }, "BeforeLength" ]; + len2 = Length @ ConfirmMatch[ selectionData[ "Selected" ], { ___CellObject }, "SelectedLength" ]; + + before = ConfirmMatch[ cells[[ 1 ;; len1 ]] , { ___Cell }, "BeforeCells" ]; + selected = ConfirmMatch[ cells[[ len1 + 1 ;; len1 + len2 ]], { ___Cell }, "SelectedCells" ]; + after = ConfirmMatch[ cells[[ len1 + len2 + 1 ;; All ]] , { ___Cell }, "AfterCells" ]; + + marked = ConfirmMatch[ insertSelectionIndicator @ { before, selected, after }, { ___Cell }, "Marked" ]; + messages = ConfirmMatch[ makeChatMessages[ settings, marked, False ], { ___Association }, "Messages" ]; + string = ConfirmBy[ messagesToString @ messages, StringQ, "String" ]; + postProcessNotebookContextString[ applyNotebookContextTemplate @ string, string ] + ], + throwInternalFailure +]; + +getContextFromSelection0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*messagesToString*) +messagesToString // beginDefinition; +messagesToString[ messages_List ] := messagesToString[ messages, messageToString /@ revertMultimodalContent @ messages ]; +messagesToString[ _, strings: { ___String } ] := StringRiffle[ strings, "\n\n" ]; +messagesToString // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*messageToString*) +messageToString // beginDefinition; +messageToString[ KeyValuePattern[ "Content" -> content_ ] ] := messageToString @ content; +messageToString[ KeyValuePattern[ "Data" -> content_ ] ] := messageToString @ content; +messageToString[ { message___String } ] := StringJoin @ message; +messageToString[ message_String ] := message; +messageToString // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*postProcessNotebookContextString*) +postProcessNotebookContextString // beginDefinition; + +postProcessNotebookContextString[ prompt_String, string_String ] := + Module[ { selected, selectedString }, + selected = StringCases[ string, $leftSelectionIndicator ~~ s__ ~~ $rightSelectionIndicator :> s, 1 ]; + selectedString = First[ selected, None ]; + If[ StringQ @ selectedString && StringLength @ selectedString < 100, + StringJoin[ + prompt, + "\n\nReminder: The user's currently selected text is: \"", + StringTrim @ selectedString, + "\"" + ], + prompt + ] + ]; + +postProcessNotebookContextString // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*applyNotebookContextTemplate*) +applyNotebookContextTemplate // beginDefinition; + +applyNotebookContextTemplate[ string_String ] := + applyNotebookContextTemplate[ string, $currentSelectionIndicator ]; + +applyNotebookContextTemplate[ string_String, { before_String, after_String } ] := + applyNotebookContextTemplate[ string, before <> "..." <> after ]; + +applyNotebookContextTemplate[ string_String, indicator_String ] := TemplateApply[ + $notebookContextTemplate, + <| + "SelectionIndicator" -> indicator, + "NotebookContent" -> string + |> +]; + +applyNotebookContextTemplate // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*insertSelectionIndicator*) +insertSelectionIndicator // beginDefinition; + +insertSelectionIndicator[ { { beforeCells___Cell }, { selectedCell_Cell }, { afterCells___Cell } } ] := + With[ { info = $selectionInfo }, + { beforeCells, insertSelectionMarkers[ selectedCell, info ], afterCells } /; AssociationQ @ info + ]; + +insertSelectionIndicator[ cells_ ] := + insertSelectionIndicator[ cells, $currentSelectionIndicator ]; + +insertSelectionIndicator[ + { { beforeCells___Cell }, { selectedCells___Cell }, { afterCells___Cell } }, + { before_String, after_String } +] := { + beforeCells, + Cell @ Verbatim @ before, + selectedCells, + Cell @ Verbatim @ after, + afterCells +}; + +insertSelectionIndicator[ + { { beforeCells___Cell }, { selectedCells___Cell }, { afterCells___Cell } }, + before_String +] := { + beforeCells, + Cell @ Verbatim @ before, + selectedCells, + afterCells +}; + +insertSelectionIndicator // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*selectContextCells*) +selectContextCells // beginDefinition; + +selectContextCells[ nbo_NotebookObject ] := + selectContextCells @ Cells @ nbo; + +selectContextCells[ cells: { ___CellObject } ] := + selectContextCells @ cellInformation @ cells; + +selectContextCells[ { a: KeyValuePattern[ "CursorPosition" -> "AboveCell" ], after___ } ] := + selectContextCells0 @ <| "Before" -> { }, "Selected" -> { }, "After" -> { after } |>; + +selectContextCells[ { before___, a: KeyValuePattern[ "CursorPosition" -> "BelowCell" ], after___ } ] := + selectContextCells0 @ <| "Before" -> { before, a }, "Selected" -> { }, "After" -> { after } |>; + +selectContextCells[ { before___, a: KeyValuePattern[ "CursorPosition" -> _List ], after___ } ] := + selectContextCells0 @ <| "Before" -> { before }, "Selected" -> { a }, "After" -> { after } |>; + +selectContextCells[ { before___, a: Longest[ KeyValuePattern[ "CursorPosition" -> "CellBracket" ].. ], after___ } ] := + selectContextCells0 @ <| "Before" -> { before }, "Selected" -> { a }, "After" -> { after } |>; + +selectContextCells[ { all: KeyValuePattern[ "CursorPosition" -> None ]... } ] := + selectContextCells0 @ <| "Before" -> { all }, "Selected" -> { }, "After" -> { } |>; + +selectContextCells // endDefinition; + + +selectContextCells0 // beginDefinition; + +selectContextCells0[ KeyValuePattern @ { + "Before" -> before0_List, + "Selected" -> current_List, + "After" -> after0_List +} ] := + Module[ { before, after }, + before = Reverse @ Take[ Reverse @ before0, UpTo[ $maxCellsBeforeSelection ] ]; + after = Take[ after0, UpTo[ $maxCellsAfterSelection ] ]; + Map[ + Cases[ KeyValuePattern[ "CellObject" -> cell_CellObject ] :> cell ], + <| "Before" -> before, "Selected" -> current, "After" -> after |> + ] + ]; + +selectContextCells0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*getUserNotebook*) +getUserNotebook // beginDefinition; +getUserNotebook[ ] := FirstCase[ userNotebooks[ ], _NotebookObject, None ]; +getUserNotebook[ chatNB_NotebookObject ] := FirstCase[ userNotebooks @ chatNB, _NotebookObject, None ]; +getUserNotebook // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*userNotebooks*) +userNotebooks // beginDefinition; + +userNotebooks[ chatNB_NotebookObject ] := + DeleteCases[ userNotebooks[ ], chatNB ]; + +userNotebooks[ ] := + userNotebooks @ Notebooks[ ]; + +userNotebooks[ notebooks: { ___NotebookObject } ] := Enclose[ + Module[ { noPalettes, visible, included }, + + noPalettes = ConfirmMatch[ + selectByCurrentValue[ notebooks, WindowFrame, # =!= "Palette" & ], + { ___NotebookObject }, + "NoPalettes" + ]; + + visible = ConfirmMatch[ + selectByCurrentValue[ noPalettes, Visible, TrueQ ], + { ___NotebookObject }, + "Visible" + ]; + + included = ConfirmMatch[ + selectByCurrentValue[ visible, { TaggingRules, "ChatNotebookSettings" }, includedTagsQ ], + { ___NotebookObject }, + "NotExcluded" + ]; + + included + ], + throwInternalFailure +]; + +userNotebooks // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*userNotebookQ*) +userNotebookQ // beginDefinition; + +userNotebookQ[ nbo_NotebookObject ] := TrueQ @ And[ + CurrentValue[ nbo, WindowFrame ] =!= "Palette", + CurrentValue[ nbo, Visible ] === True, + includedTagsQ @ AbsoluteCurrentValue[ nbo, { TaggingRules, "ChatNotebookSettings" } ] +]; + +userNotebookQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*includedTagsQ*) +includedTagsQ // beginDefinition; +includedTagsQ[ KeyValuePattern[ "ExcludeFromChat" -> True ] ] := False; +includedTagsQ[ KeyValuePattern[ "WorkspaceChat" -> True ] ] := False; +includedTagsQ[ _ ] := True; +includedTagsQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*insertSelectionMarkers*) +insertSelectionMarkers // beginDefinition; + +insertSelectionMarkers[ cell_CellObject ] := + insertSelectionMarkers[ NotebookRead @ cell, cellInformation @ cell ]; + +insertSelectionMarkers[ cell_, KeyValuePattern[ "CursorPosition" -> pos_ ] ] := + insertSelectionMarkers[ cell, pos ]; + +insertSelectionMarkers[ cell: Cell[ content_, a___ ], { before0_Integer, after0_Integer } ] := + Module[ { before, after, result }, + before = before0; + after = after0; + result = Catch[ insertSelectionMarkers0[ { before, after }, content ], $insertTag ]; + If[ MissingQ @ result, fullSelection @ cell, Cell[ result, a ] ] + ]; + +insertSelectionMarkers[ cell_, "CellBracket"|None ] := + fullSelection @ cell; + +insertSelectionMarkers // endDefinition; + + +insertSelectionMarkers0 // beginDefinition; +insertSelectionMarkers0 // Attributes = { HoldFirst }; + +insertSelectionMarkers0[ state_, (h: BoxData|TextData|RowBox|StyleBox)[ box_, a___ ] ] := + h[ insertSelectionMarkers0[ state, box ], a ]; + +insertSelectionMarkers0[ { before_, after_ }, cell_Cell ] := + WithCleanup[ + cell, + before -= 1; + after -= 1; + ]; + +insertSelectionMarkers0[ state_, boxes_List ] := + insertSelectionMarkers0[ state, # ] & /@ boxes; + +insertSelectionMarkers0[ { before_, after_ }, str_String ] := + With[ { len = StringLength @ str }, + WithCleanup[ + Which[ + (* selection caret is in range and between characters *) + 0 <= before <= len && before === after, + WithCleanup[ + StringInsert[ str, $leftSelectionIndicator<>$rightSelectionIndicator, before + 1 ], + before = after = -1 + ], + + (* both are in range of current string *) + 0 <= before <= len && 0 <= after <= len, + WithCleanup[ + StringInsert[ + StringInsert[ str, $rightSelectionIndicator, after + 1 ], + $leftSelectionIndicator, + before + 1 + ], + before = after = -1 + ], + + (* beginning of selection is in range *) + 0 <= before <= len, + WithCleanup[ + StringInsert[ str, $leftSelectionIndicator, before + 1 ], + before = -1 + ], + + (* end of selection is in range *) + 0 <= after <= len, + WithCleanup[ + StringInsert[ str, $rightSelectionIndicator, after + 1 ], + after = -1 + ], + + (* selection is not in range *) + True, + str + ], + + (* update counters *) + before -= len; + after -= len; + ] + ]; + +insertSelectionMarkers0[ { _? Negative, _? Negative }, box_ ] := + box; + +insertSelectionMarkers0[ ___ ] := + Throw[ Missing[ "FullSelection" ], $insertTag ]; + +insertSelectionMarkers0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*fullSelection*) +fullSelection // beginDefinition; +fullSelection[ Cell[ a_, b___ ] ] := Cell[ fullSelection @ a, b ]; +fullSelection[ text_String ] := TextData @ { $leftSelectionIndicator, text, $rightSelectionIndicator }; +fullSelection[ BoxData[ { a___ }, b___ ] ] := BoxData[ { $leftSelectionIndicator, a, $rightSelectionIndicator }, b ]; +fullSelection[ BoxData[ a_, b___ ] ] := BoxData[ RowBox @ { $leftSelectionIndicator, a, $rightSelectionIndicator }, b ]; +fullSelection[ TextData[ text_ ] ] := TextData @ Flatten @ { $leftSelectionIndicator, text, $rightSelectionIndicator }; +fullSelection // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Package Footer*) +addToMXInitialization[ + Null +]; + +End[ ]; +EndPackage[ ]; diff --git a/Source/Chatbook/ChatModes/Evaluate.wl b/Source/Chatbook/ChatModes/Evaluate.wl new file mode 100644 index 00000000..6e773820 --- /dev/null +++ b/Source/Chatbook/ChatModes/Evaluate.wl @@ -0,0 +1,239 @@ +(* ::Section::Closed:: *) +(*Package Header*) +BeginPackage[ "Wolfram`Chatbook`ChatModes`Evaluate`" ]; +Begin[ "`Private`" ]; + +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`ChatModes`Common`" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Config*) +$$inlineChatInput = Cell[ __, "ChatInput" , ___ ]; +$$inlineChatOutput = Cell[ __, "ChatOutput", ___ ]; +$$inlineMessage = $$inlineChatInput|$$inlineChatOutput; +$$inlineMessages = { $$inlineMessage.. }; +$$inlineMessagesIn = { $$inlineMessage..., $$inlineChatInput }; +$$inlineMessagesOut = { $$inlineMessage..., $$inlineChatOutput }; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Evaluate Alternate Chat Inputs*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*evaluateWorkspaceChat*) +evaluateWorkspaceChat // beginDefinition; + +evaluateWorkspaceChat[ nbo_NotebookObject, Dynamic[ input: _Symbol|_CurrentValue ] ] := Enclose[ + Catch @ Module[ { text, uuid, cell, cellObject }, + If[ ! validInputStringQ @ input, input = ""; Throw @ Null ]; + text = input; + uuid = ConfirmBy[ CreateUUID[ ], StringQ, "UUID" ]; + cell = Cell[ BoxData @ TemplateBox[ { text }, "UserMessageBox" ], "ChatInput", CellTags -> uuid ]; + input = ""; + SelectionMove[ nbo, After, Notebook, AutoScroll -> True ]; + NotebookWrite[ nbo, cell ]; + cellObject = ConfirmMatch[ First[ Cells[ nbo, CellTags -> uuid ], $Failed ], _CellObject, "CellObject" ]; + CurrentValue[ cellObject, CellTags ] = { }; + ConfirmMatch[ ChatCellEvaluate[ cellObject, nbo ], _ChatObject|Null, "ChatCellEvaluate" ] + ], + throwInternalFailure +]; + +evaluateWorkspaceChat // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*evaluateInlineChat*) +evaluateInlineChat // beginDefinition; + +evaluateInlineChat[ + cell_CellObject, + root_CellObject, + selectionInfo_, + Dynamic[ input_ ], + Dynamic[ messageCells_ ] +] := Enclose[ + Catch @ Module[ { text, nbo, result }, + + If[ ! validInputStringQ @ input, input = ""; Throw @ Null ]; + text = input; + input = ""; + + ConfirmMatch[ AppendTo[ messageCells, formatInlineChatInput @ text ], { __Cell }, "MessageCells" ]; + + nbo = ConfirmMatch[ parentNotebook @ root, _NotebookObject, "ParentNotebook" ]; + + Block[ + { + $InlineChat = True, + $inlineChatState = <| + "CurrentInput" -> text, + "ParentCell" -> root, + "ParentNotebook" -> nbo, + "InlineChatCell" -> cell, + "SelectionInfo" -> selectionInfo, + "MessageCells" -> Dynamic @ messageCells + |> + }, + result = ConfirmMatch[ ChatCellEvaluate @ root, _ChatObject|Null, "ChatCellEvaluate" ] + ]; + + SessionSubmit @ moveToInlineChatInputField[ ]; + + result + ], + throwInternalFailure +]; + +evaluateInlineChat // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Overrides*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*createNewInlineOutput*) +createNewInlineOutput // beginDefinition; +createNewInlineOutput[ settings_, target_, cell_ ] := createNewInlineOutput0[ settings, cell, $inlineChatState ]; +createNewInlineOutput // endDefinition; + + +createNewInlineOutput0 // beginDefinition; + +createNewInlineOutput0[ + settings_, + cell_Cell, + KeyValuePattern @ { + "InlineChatCell" -> chatCell_, + "MessageCells" -> Dynamic[ messageCells_ ] + } +] := Enclose[ + If[ Length @ messageCells > 2, scrollInlineChat[ ] ]; + ConfirmMatch[ AppendTo[ messageCells, cell ], { __Cell }, "MessageCells" ]; + chatCell, + throwInternalFailure +]; + +createNewInlineOutput0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*writeInlineChatOutputCell*) +writeInlineChatOutputCell // beginDefinition; +writeInlineChatOutputCell[ cell_, new_Cell, settings_ ] := replaceLastInlineMessage[ settings, new ]; +writeInlineChatOutputCell // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*replaceLastInlineMessage*) +replaceLastInlineMessage // beginDefinition; + +replaceLastInlineMessage[ settings_, new_ ] := + replaceLastInlineMessage[ settings, new, $inlineChatState[ "MessageCells" ] ]; + +replaceLastInlineMessage[ settings_, cell_, Dynamic[ messageList_ ] ] := Enclose[ + Module[ { messages, keep, new }, + messages = ConfirmMatch[ messageList, $$inlineMessagesOut, "CurrentMessages" ]; + keep = Most @ messages; + new = ConfirmMatch[ formatStaticInlineOutput[ settings, cell ], $$inlineChatOutput, "NewCell" ]; + messageList = ConfirmMatch[ Append[ keep, new ], $$inlineMessagesOut, "MessageList" ]; + messageList + ], + throwInternalFailure +]; + +replaceLastInlineMessage // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatStaticInlineOutput*) +formatStaticInlineOutput // beginDefinition; + +formatStaticInlineOutput[ settings_, Cell[ text_, "ChatOutput", opts___ ] ] := + addInlineChatTaggingRules @ Cell[ + TextData @ { + Cell[ + BoxData @ assistantMessageBox @ Cell[ inlineTemplateBoxes @ text, Background -> None ], + Background -> None + ] + }, + "ChatOutput", + CellFrame -> 0, + Editable -> True, + Initialization -> None, + PrivateCellOptions -> { "ContentsOpacity" -> 1 }, + Selectable -> True, + opts + ]; + +formatStaticInlineOutput // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*addInlineChatTaggingRules*) +addInlineChatTaggingRules // beginDefinition; + +addInlineChatTaggingRules[ Cell[ a__, TaggingRules -> tags_, b___ ] ] := + Cell[ a, TaggingRules -> addInlineChatTaggingRules0 @ tags, b ]; + +addInlineChatTaggingRules[ Cell[ a___ ] ] := + Cell[ a, TaggingRules -> addInlineChatTaggingRules0 @ <| |> ]; + +addInlineChatTaggingRules // endDefinition; + + +addInlineChatTaggingRules0 // beginDefinition; + +addInlineChatTaggingRules0[ tags: KeyValuePattern[ "ChatNotebookSettings" -> as: KeyValuePattern @ { } ] ] := + <| tags, "ChatNotebookSettings" -> <| as, $inlineChatTaggingRules |> |>; + +addInlineChatTaggingRules0[ tags: KeyValuePattern @ { } ] := + <| tags, "ChatNotebookSettings" -> $inlineChatTaggingRules |>; + +addInlineChatTaggingRules0 // endDefinition; + + +$inlineChatTaggingRules := <| "InlineChat" -> True, "InlineChatRootCell" -> $inlineChatState[ "ParentCell" ] |>; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatInlineChatInput*) +formatInlineChatInput // beginDefinition; + +formatInlineChatInput[ text_String ] := + Block[ { $InlineChat = True }, + Cell[ + BoxData @ userMessageBox @ text, + "ChatInput", + CellFrame -> 0, + PrivateCellOptions -> { "ContentsOpacity" -> 1 } + ] + ]; + +formatInlineChatInput // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Misc Utilities*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*validInputStringQ*) +validInputStringQ // beginDefinition; +validInputStringQ[ input_String? StringQ ] := ! StringMatchQ[ input, WhitespaceCharacter... ]; +validInputStringQ[ _ ] := False +validInputStringQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Package Footer*) +addToMXInitialization[ + Null +]; + +End[ ]; +EndPackage[ ]; diff --git a/Source/Chatbook/ChatModes/ShowCodeAssistance.wl b/Source/Chatbook/ChatModes/ShowCodeAssistance.wl new file mode 100644 index 00000000..3899047d --- /dev/null +++ b/Source/Chatbook/ChatModes/ShowCodeAssistance.wl @@ -0,0 +1,192 @@ +(* ::Section::Closed:: *) +(*Package Header*) +BeginPackage[ "Wolfram`Chatbook`ChatModes`ShowCodeAssistance`" ]; +Begin[ "`Private`" ]; + +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`ChatModes`Common`" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Configuration*) +$workspaceChatWidth = 325; + +$workspaceChatNotebookOptions = Sequence[ + DefaultNewCellStyle -> "AutoMoveToChatInputField", + StyleDefinitions -> FrontEnd`FileName[ { "Wolfram" }, "WorkspaceChat.nb", CharacterEncoding -> "UTF-8" ] +]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*ShowCodeAssistance*) +ShowCodeAssistance // beginDefinition; +ShowCodeAssistance[ ] := catchMine @ ShowCodeAssistance[ "Window" ]; +ShowCodeAssistance[ "Window" ] := catchMine @ showCodeAssistanceWindow @ getUserNotebook[ ]; +ShowCodeAssistance[ "Inline" ] := catchMine @ showCodeAssistanceInline @ InputNotebook[ ]; +ShowCodeAssistance // endExportedDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Inline Code Assistance*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*showCodeAssistanceInline*) +showCodeAssistanceInline // beginDefinition; +showCodeAssistanceInline[ nbo_NotebookObject ] := attachInlineChatInput @ nbo; +showCodeAssistanceInline[ _ ] := MessageDialog[ "No notebook selected." ]; +showCodeAssistanceInline // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Code Assistance Window*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*showCodeAssistanceWindow*) +showCodeAssistanceWindow // beginDefinition; + +showCodeAssistanceWindow[ source_NotebookObject ] := Enclose[ + Module[ { current }, + current = ConfirmMatch[ findCurrentWorkspaceChat[ ], _NotebookObject | Missing[ "NotFound" ], "Existing" ]; + If[ MissingQ @ current, + ConfirmMatch[ createWorkspaceChat @ source, _NotebookObject, "New" ], + ConfirmMatch[ attachToLeft[ source, current ], _NotebookObject, "Attached" ] + ] + ], + throwInternalFailure +]; + +showCodeAssistanceWindow[ None ] := Enclose[ + Module[ { current }, + current = ConfirmMatch[ findCurrentWorkspaceChat[ ], _NotebookObject | Missing[ "NotFound" ], "Existing" ]; + If[ MissingQ @ current, + ConfirmMatch[ createWorkspaceChat[ ], _NotebookObject, "New" ], + current + ] + ], + throwInternalFailure +]; + +showCodeAssistanceWindow // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*attachToLeft*) +attachToLeft // beginDefinition; + +attachToLeft[ source_NotebookObject, current_NotebookObject ] := Enclose[ + Module[ { margins, left, bottom, top }, + + margins = ConfirmMatch[ windowMargins @ source, { { _, _ }, { _, _ } }, "Margins" ]; + + left = margins[[ 1, 1 ]]; + bottom = margins[[ 2, 1 ]]; + top = margins[[ 2, 2 ]]; + + If[ NonPositive[ left - $workspaceChatWidth ], + left = $workspaceChatWidth; + bottom = 0; + top = 0; + ]; + + SetOptions[ + current, + WindowMargins -> { { left - $workspaceChatWidth, Automatic }, { bottom, top } }, + WindowSize -> { $workspaceChatWidth, Automatic } + ]; + + SetSelectedNotebook @ current + ], + throwInternalFailure +]; + +attachToLeft // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*windowMargins*) +windowMargins // beginDefinition; +windowMargins[ nbo_NotebookObject ] := windowMargins[ nbo, AbsoluteCurrentValue[ nbo, WindowMargins ] ]; +windowMargins[ nbo_, margins: { { _, _ }, { _, _ } } ] := margins; +windowMargins[ nbo_, margins_? NumberQ ] := { { margins, margins }, { margins, margins } }; +windowMargins // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*findCurrentWorkspaceChat*) +findCurrentWorkspaceChat // beginDefinition; + +findCurrentWorkspaceChat[ ] := FirstCase[ + selectByCurrentValue[ Notebooks[ ], { TaggingRules, "ChatNotebookSettings", "WorkspaceChat" }, "Absolute" -> True ], + _NotebookObject, + Missing[ "NotFound" ] +]; + +findCurrentWorkspaceChat // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*CreateWorkspaceChat*) +CreateWorkspaceChat // beginDefinition; +CreateWorkspaceChat[ ] := catchMine @ createWorkspaceChat[ ]; +CreateWorkspaceChat[ nbo_NotebookObject ] := catchMine @ createWorkspaceChat @ nbo; +CreateWorkspaceChat // endExportedDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*createWorkspaceChat*) +createWorkspaceChat // beginDefinition; + +createWorkspaceChat[ ] := + createWorkspaceChat[ { } ]; + +createWorkspaceChat[ cells: { ___Cell } ] := Enclose[ + Module[ { nbo }, + nbo = ConfirmMatch[ + NotebookPut @ Notebook[ cells, $workspaceChatNotebookOptions ], + _NotebookObject, + "Notebook" + ]; + (* Do we need to move to input field here? *) + SetOptions[ + nbo, + WindowMargins -> { { 0, Automatic }, { 0, 0 } }, + WindowSize -> { $workspaceChatWidth, Automatic } + ]; + + nbo + ], + throwInternalFailure +]; + +createWorkspaceChat[ source_NotebookObject ] := + createWorkspaceChat[ source, { } ]; + +createWorkspaceChat[ source_NotebookObject, cells: { ___Cell } ] := Enclose[ + Module[ { nbo }, + + nbo = ConfirmMatch[ + NotebookPut @ Notebook[ cells, $workspaceChatNotebookOptions ], + _NotebookObject, + "Notebook" + ]; + + (* Do we need to move to input field here? *) + ConfirmMatch[ attachToLeft[ source, nbo ], _NotebookObject, "Attached" ] + ], + throwInternalFailure +]; + +createWorkspaceChat // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Package Footer*) +addToMXInitialization[ + Null +]; + +End[ ]; +EndPackage[ ]; diff --git a/Source/Chatbook/ChatModes/UI.wl b/Source/Chatbook/ChatModes/UI.wl new file mode 100644 index 00000000..bdb141f4 --- /dev/null +++ b/Source/Chatbook/ChatModes/UI.wl @@ -0,0 +1,640 @@ +(* ::Section::Closed:: *) +(*Package Header*) +BeginPackage[ "Wolfram`Chatbook`ChatModes`UI`" ]; +Begin[ "`Private`" ]; + +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`ChatModes`Common`" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Configuration*) +$inputFieldPaneMargins = 5; +$inputFieldGridMagnification = 0.8; +$inputFieldOuterBackground = GrayLevel[ 0.95 ]; +$initialInlineChatWidth = Scaled[ 0.5 ]; +$initialInlineChatHeight = UpTo[ 200 ]; + +$inputFieldOptions = Sequence[ + BoxID -> "AttachedChatInputField", + ImageSize -> { Scaled[ 1 ], { 25, Automatic } }, + FieldHint -> tr[ "AttachedChatFieldHint" ], + BaseStyle -> { "Text" }, + Appearance -> "Frameless" +]; + +$inputFieldFrameOptions = Sequence[ + Background -> White, + FrameMargins -> { { 5, 5 }, { 2, 2 } }, + FrameStyle -> Directive[ AbsoluteThickness[ 2 ], RGBColor[ "#a3c9f2" ] ] +]; + +$userImageParams = <| "size" -> 50, "default" -> "identicon", "rating" -> "G" |>; + +$defaultUserImage = Graphics[ + { + EdgeForm @ None, + FaceForm @ GrayLevel[ 0.8 ], + Disk[ { 0, 0.2 }, 2.35 ], + FaceForm @ White, + Disk[ { 0, 1 }, 1 ], + Disk[ { 0, -1.8 }, { 1.65, 2 } ] + }, + ImageSize -> 25, + PlotRange -> { { -2.4, 2.4 }, { -2.0, 2.8 } } +]; + +$messageAuthorImagePadding = { { 0, 0 }, { 0, 6 } }; + +$inputFieldBox = None; +$inlineChatScrollPosition = 0.0; +$lastScrollPosition = 0.0; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Workspace Chat*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*makeWorkspaceChatDockedCell*) +makeWorkspaceChatDockedCell // beginDefinition; + +makeWorkspaceChatDockedCell[ ] := Grid @ { + { + Button[ + "New", + SelectionMove[ EvaluationNotebook[ ], After, Notebook ]; + NotebookWrite[ EvaluationNotebook[ ], Cell[ "", "ChatDelimiter", CellFrameLabels -> None ] ] + ], + Button[ "Clear", NotebookDelete @ Cells @ EvaluationNotebook[ ] ], + Item[ "", ItemSize -> Fit ], + Button[ "Pop Out", popOutChatNB @ EvaluationNotebook[ ], Method -> "Queued" ] + } +}; + +makeWorkspaceChatDockedCell // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*attachWorkspaceChatInput*) +attachWorkspaceChatInput // beginDefinition; + +attachWorkspaceChatInput[ nbo_NotebookObject ] := Enclose[ + Module[ { attached }, + attached = ConfirmMatch[ + AttachCell[ nbo, $attachedWorkspaceChatInputCell, Bottom, 0, Bottom ], + _CellObject, + "Attach" + ]; + + attached + ], + throwInternalFailure +]; + +attachWorkspaceChatInput // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*$attachedWorkspaceChatInputCell*) +$attachedWorkspaceChatInputCell := $attachedWorkspaceChatInputCell = Cell[ + BoxData @ ToBoxes @ DynamicModule[ { thisNB }, + EventHandler[ + Pane[ + Grid[ + { + { + RawBoxes @ TemplateBox[ { }, "ChatIconUser" ], + Framed[ + InputField[ + Dynamic @ CurrentValue[ + EvaluationNotebook[ ], + { TaggingRules, "ChatInputString" } + ], + String, + $inputFieldOptions + ], + $inputFieldFrameOptions + ], + RawBoxes @ TemplateBox[ { RGBColor[ "#a3c9f2" ], 27, thisNB }, "WorkspaceSendChatButton" ] + } + }, + BaseStyle -> { Magnification -> $inputFieldGridMagnification } + ], + FrameMargins -> $inputFieldPaneMargins + ], + { + "ReturnKeyDown" :> ( + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ + "EvaluateWorkspaceChat", + thisNB, + Dynamic @ CurrentValue[ thisNB, { TaggingRules, "ChatInputString" } ] + ] + ) + }, + Method -> "Queued" + ], + Initialization :> (thisNB = EvaluationNotebook[ ]) + ], + "ChatInputField", + Background -> $inputFieldOuterBackground, + Selectable -> True +]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Inline Chat*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*attachInlineChatInput*) +attachInlineChatInput // beginDefinition; + +attachInlineChatInput[ nbo_NotebookObject ] := + If[ TrueQ @ userNotebookQ @ nbo, + attachInlineChatInput[ nbo, SelectedCells @ nbo ], + Null + ]; + +attachInlineChatInput[ nbo_NotebookObject, { root_CellObject } ] := Enclose[ + Module[ { selectionInfo, attached }, + + NotebookDelete @ $lastAttachedInlineChat; + NotebookDelete @ Cells[ nbo, AttachedCell -> True, CellStyle -> "AttachedChatInput" ]; + + selectionInfo = ConfirmMatch[ + getSelectionInfo @ root, + None | KeyValuePattern[ "CursorPosition" -> { _Integer, _Integer } ], + "SelectionInfo" + ]; + + $lastScrollPosition = 0.0; + $inlineChatScrollPosition = 0.0; + + (* TODO: Watch the root cell for changes and remove (or disable) the attached chat if cell changed *) + attached = ConfirmMatch[ + AttachCell[ + NotebookSelection @ nbo, + inlineChatInputCell[ root, selectionInfo ], + { Left, Bottom }, + 0, + { Left, Top }, + RemovalConditions -> { "EvaluatorQuit" } + ], + _CellObject, + "Attach" + ]; + + SelectionMove[ attached, Before, CellContents ]; + FrontEndExecute @ FrontEnd`FrontEndToken[ "MoveNextPlaceHolder" ]; + + $lastAttachedInlineChat = attached + ], + throwInternalFailure +]; + +(* FIXME: Need to handle multiple or no cell selections *) +attachInlineChatInput[ nbo_NotebookObject, { ___ } ] := Null; + +attachInlineChatInput // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*getSelectionInfo*) +getSelectionInfo // beginDefinition; + +getSelectionInfo[ cell_CellObject ] := getSelectionInfo[ cell, cellInformation[ cell, "CursorPosition" ] ]; +getSelectionInfo[ cell_, Except[ { _Integer, _Integer } ] ] := None; +getSelectionInfo[ cell_, pos_ ] := getSelectionInfo[ cell, pos, cellHash @ cell ]; + +getSelectionInfo[ cell_CellObject, pos: { _Integer, _Integer }, hash_String ] := <| + "CellObject" -> cell, + "CursorPosition" -> pos, + "Hash" -> hash +|>; + +getSelectionInfo // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*cellHash*) +cellHash // beginDefinition; +cellHash[ cell_CellObject ] := cellHash[ cell, FrontEndExecute @ FrontEnd`CryptoHash @ cell ]; +cellHash[ cell_CellObject, KeyValuePattern @ { "DirtiableContentsHash" -> hash_String } ] := hash; +cellHash // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*inlineChatInputCell*) +inlineChatInputCell // beginDefinition; + +inlineChatInputCell[ root_CellObject, selectionInfo_ ] := Cell[ + BoxData @ inlineTemplateBox @ TemplateBox[ + { + ToBoxes @ DynamicModule[ { messageCells = { }, cell }, + Dynamic[ + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ + "DisplayInlineChat", + cell, + root, + selectionInfo, + Dynamic[ messageCells ] + ] + ], + + UnsavedVariables :> { cell }, + + (* ParentCell and ParentNotebook do not work for cells attached to NotebookSelection[ ], + so we create temporary overrides here. *) + Initialization :> ( + cell = EvaluationCell[ ]; + parentCell[ cell ] = root; + parentNotebook[ cell ] = parentNotebook @ root; + ), + + Deinitialization :> Quiet[ + $inputFieldBox = None; + Unset @ parentCell @ cell; + Unset @ parentNotebook @ cell; + ] + ] + }, + "DropShadowPaneBox" + ], + "AttachedChatInput", + Background -> None, + Selectable -> True +]; + +inlineChatInputCell // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*displayInlineChat*) +displayInlineChat // beginDefinition; + +displayInlineChat[ cell_CellObject, root_CellObject, selectionInfo_, Dynamic[ messageCells_Symbol ] ] := + Module[ { inputField }, + + inputField = inlineChatInputField[ + cell, + root, + selectionInfo, + Dynamic @ CurrentValue[ cell, { TaggingRules, "ChatInputString" } ], + Dynamic @ messageCells + ]; + + displayInlineChatMessages[ messageCells, inputField ] + ]; + +displayInlineChat // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*inlineChatInputField*) +inlineChatInputField // beginDefinition; + +inlineChatInputField[ + cell_CellObject, + root_CellObject, + selectionInfo_, + Dynamic[ currentInput_ ], + Dynamic[ messageCells_ ] +] := + EventHandler[ + Pane[ + Grid[ + { + { + RawBoxes @ inlineTemplateBox @ TemplateBox[ { }, "ChatIconUser" ], + Framed[ + DynamicWrapper[ + InputField[ Dynamic @ currentInput, String, $inputFieldOptions ], + $inputFieldBox = EvaluationBox[ ] + ], + $inputFieldFrameOptions + ], + (* FIXME: this needs a custom button *) + RawBoxes @ inlineTemplateBox @ TemplateBox[ { RGBColor[ "#a3c9f2" ], 27 }, "SendChatButton" ], + Style[ + ActionMenu[ + "More", + { + "Close" :> NotebookDelete @ EvaluationCell[ ], + "View in Chat" :> ( + NotebookDelete @ EvaluationCell[ ]; + popOutWorkspaceChatNB @ messageCells + ) + }, + ImageSize -> { Automatic, 25 } + ], + Magnification -> 1 + ] + } + }, + BaseStyle -> { Magnification -> $inputFieldGridMagnification } + ], + FrameMargins -> $inputFieldPaneMargins + ], + { + "ReturnKeyDown" :> ( + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ + "EvaluateInlineChat", + cell, + root, + selectionInfo, + Dynamic @ currentInput, + Dynamic @ messageCells + ] + ) + }, + Method -> "Queued" + ]; + +inlineChatInputField // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*moveToInlineChatInputField*) +moveToInlineChatInputField // beginDefinition; + +moveToInlineChatInputField[ ] := + moveToInlineChatInputField @ $inputFieldBox; + +moveToInlineChatInputField[ box_BoxObject ] := Quiet @ Catch[ + SelectionMove[ box, Before, Expression ]; + FrontEnd`MoveCursorToInputField[ parentNotebook @ box, "AttachedChatInputField" ], + _ +]; + +moveToInlineChatInputField // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*displayInlineChatMessages*) +displayInlineChatMessages // beginDefinition; + +displayInlineChatMessages[ { }, inputField_ ] := + Pane[ inputField, ImageSize -> { Scaled[ 0.5 ], Automatic } ]; + +displayInlineChatMessages[ cells: { __Cell }, inputField_ ] := + DynamicModule[ { w, h, size }, + + (* TODO: use cell tagging rules instead so it remembers the size when refreshing *) + w = $initialInlineChatWidth; + h = $initialInlineChatHeight; + size = { w, h }; + + Column[ + { + Pane[ + Column[ + formatInlineMessageCells /@ cells, + Alignment -> Left, + BaseStyle -> { Magnification -> 0.8 }, + ItemSize -> { Fit, Automatic }, + Spacings -> 0.5 + ], + FrameMargins -> 5, + ImageSize -> Dynamic[ size, Function[ { w, h } = size = # ] ], + Scrollbars -> Automatic, + AppearanceElements -> { "ResizeArea" }, + ScrollPosition -> Dynamic[ + { 0, $inlineChatScrollPosition }, + Function[ $lastScrollPosition = $inlineChatScrollPosition = Last[ # ] ] + ] + ], + Pane[ inputField, ImageSize -> Dynamic[ { w, Automatic } ] ] + }, + Alignment -> Left + ], + Initialization :> ($inlineChatScrollPosition = $lastScrollPosition) + ]; + +displayInlineChatMessages // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*scrollInlineChat*) +scrollInlineChat // beginDefinition; +scrollInlineChat[ ] := scrollInlineChat[ 500 ]; +scrollInlineChat[ amount_ ] := (scrollInlineChat0[ amount ]; updateDynamics[ "InlineChatScrollPane" ]); +scrollInlineChat // endDefinition; + +scrollInlineChat0 // beginDefinition; +scrollInlineChat0[ amount_ ] := scrollInlineChat0[ amount, $lastScrollPosition ]; +scrollInlineChat0[ amount_? NumberQ, current_? NumberQ ] := $lastScrollPosition = current + amount; +scrollInlineChat0[ amount_? NumberQ, _ ] := $lastScrollPosition = amount; +scrollInlineChat0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatInlineMessageCells*) +formatInlineMessageCells // beginDefinition; + +formatInlineMessageCells[ cell: Cell[ __, "ChatInput", ___ ] ] := + Item[ + Grid[ + { { RawBoxes @ cell, Pane[ userImage[ ], ImageMargins -> $messageAuthorImagePadding ] } }, + Alignment -> { Right, Top } + ], + Alignment -> Right + ]; + +formatInlineMessageCells[ cell: Cell[ __, "ChatOutput", ___ ] ] := + Block[ { $InlineChat = True }, + Grid[ + { + { + Pane[ assistantImage[ ], ImageMargins -> $messageAuthorImagePadding ], + RawBoxes @ Append[ DeleteCases[ cell, Background -> _ ], Background -> None ] + } + }, + Alignment -> { Left, Top } + ] + ]; + +formatInlineMessageCells // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Input Field Movement*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*moveToChatInputField*) +moveToChatInputField // beginDefinition; + +(* TODO: support inline chat cells too *) +moveToChatInputField[ nbo_ ] := + moveToChatInputField[ nbo, $WorkspaceChat ]; + +moveToChatInputField[ nbo_NotebookObject, True ] := ( + moveToChatInputField0 @ nbo; (* TODO: Need to investigate why this is needed twice *) + (* FIXME: Maybe this should use `FrontEndExecute @ FrontEnd`FrontEndToken[ "MoveNextPlaceHolder" ]`? *) + moveToChatInputField0 @ nbo; +); + +moveToChatInputField[ nbo_NotebookObject, False ] := + Null; + +moveToChatInputField // endDefinition; + + +moveToChatInputField0 // beginDefinition; + +moveToChatInputField0[ nbo_NotebookObject ] := ( + SelectionMove[ + First[ Cells[ nbo, AttachedCell -> True, CellStyle -> "ChatInputField" ], $Failed ], + After, + CellContents + ]; + FrontEndExecute @ FrontEndToken[ nbo, "MovePrevious" ] +); + +moveToChatInputField0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Chat Message Labels*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*assistantMessageLabel*) +assistantMessageLabel // beginDefinition; +assistantMessageLabel[ ] := Grid[ { { assistantImage[ ], assistantName[ ] } }, Alignment -> { Automatic, Center } ]; +assistantMessageLabel // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*assistantName*) +assistantName // beginDefinition; +assistantName[ ] := "Code Assistant"; (* TODO *) +assistantName // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*assistantImage*) +assistantImage // beginDefinition; +assistantImage[ ] := assistantImage @ $InlineChat; +assistantImage[ True ] := inlineTemplateBox @ assistantImage0[ ]; +assistantImage[ _ ] := assistantImage0[ ]; +assistantImage // endDefinition; + + +assistantImage0 // beginDefinition; +assistantImage0[ ] := RawBoxes @ TemplateBox[ { }, "ChatIconCodeAssistant" ]; (* TODO *) +assistantImage0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*userMessageLabel*) +userMessageLabel // beginDefinition; +userMessageLabel[ ] := Grid[ { { userName[ ], userImage[ ] } }, Alignment -> { Automatic, Center } ]; +userMessageLabel // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*userName*) +userName // beginDefinition; +userName[ ] := SelectFirst[ { $CloudAccountName, $Username }, StringQ, "You" ]; +userName // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*userImage*) +userImage // beginDefinition; + +userImage[ ] := userImage[ $CloudUserID ]; + +userImage[ user_String ] := Enclose[ + Module[ { hash, url, image }, + hash = Hash[ ToLowerCase @ StringTrim @ user, "MD5", "HexString" ]; + url = ConfirmBy[ URLBuild[ { "https://www.gravatar.com/avatar/", hash }, $userImageParams ], StringQ, "URL" ]; + image = ConfirmBy[ Import @ url, ImageQ, "Image" ]; + userImage[ user ] = Show[ image, ImageSize -> 25 ] + ], + $defaultUserImage & +]; + +userImage[ other_ ] := + $defaultUserImage; + +userImage // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Chat Notebook Conversion*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*popOutWorkspaceChatNB*) +popOutWorkspaceChatNB // beginDefinition; + +popOutWorkspaceChatNB[ cells: { ___Cell } ] := Enclose[ + Module[ { nbo }, + NotebookClose @ findCurrentWorkspaceChat[ ]; + + nbo = ConfirmMatch[ + createWorkspaceChat[ EvaluationNotebook[ ], DeleteCases[ cells, CellDingbat -> _, { 2 } ] ], + _NotebookObject, + "Notebook" + ]; + + moveToChatInputField @ nbo + ], + throwInternalFailure +]; + +popOutWorkspaceChatNB // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*popOutChatNB*) +popOutChatNB // beginDefinition; +popOutChatNB[ nbo_NotebookObject ] := popOutChatNB @ NotebookGet @ nbo; +popOutChatNB[ Notebook[ cells_, ___ ] ] := popOutChatNB @ cells; +popOutChatNB[ Dynamic[ messageList_ ] ] := popOutChatNB @ messageList; +popOutChatNB[ cells: { ___Cell } ] := NotebookPut @ cellsToChatNB @ cells; +popOutChatNB // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*cellsToChatNB*) +cellsToChatNB // beginDefinition; + +cellsToChatNB[ cells: { ___Cell } ] := + Notebook[ cells /. $fromWorkspaceChatConversionRules, StyleDefinitions -> "Chatbook.nb" ]; + +cellsToChatNB // endDefinition; + + +$fromWorkspaceChatConversionRules := $fromWorkspaceChatConversionRules = Dispatch @ { + Cell[ BoxData @ TemplateBox[ { text_ }, "UserMessageBox", ___ ], "ChatInput", ___ ] :> + Cell[ Flatten @ TextData @ text, "ChatInput" ] + , + Cell[ + TextData @ Cell[ BoxData @ TemplateBox[ { Cell[ text_, ___ ] }, "AssistantMessageBox", ___ ], ___ ], + "ChatOutput", + ___ + ] :> Cell[ Flatten @ TextData @ text, "ChatOutput" ] + , + Cell[ + TextData @ { Cell[ BoxData @ TemplateBox[ { Cell[ text_, ___ ] }, "AssistantMessageBox", ___ ], ___ ] }, + "ChatOutput", + ___ + ] :> Cell[ Flatten @ TextData @ text, "ChatOutput" ] +}; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Package Footer*) +addToMXInitialization[ + $fromWorkspaceChatConversionRules +]; + +End[ ]; +EndPackage[ ]; diff --git a/Source/Chatbook/ChatState.wl b/Source/Chatbook/ChatState.wl new file mode 100644 index 00000000..b9aae92d --- /dev/null +++ b/Source/Chatbook/ChatState.wl @@ -0,0 +1,148 @@ +(* ::Section::Closed:: *) +(*Package Header*) +BeginPackage[ "Wolfram`Chatbook`ChatState`" ]; +Begin[ "`Private`" ]; + +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Chat State Evaluation Wrappers*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*withChatState*) +withChatState // beginDefinition; +withChatState // Attributes = { HoldFirst }; + +withChatState[ eval_ ] := + Block[ + { + $absoluteCurrentSettingsCache = <| |>, + $AutomaticAssistance = False, + $chatState = True, + $currentSettingsCache = <| |>, + $enableLLMServices = Automatic, + $WorkspaceChat = False, + withChatState = # &, + + (* Values used for token budgets during cell serialization: *) + $cellStringBudget = $cellStringBudget, + $conversionRules = $conversionRules, + $initialCellStringBudget = $initialCellStringBudget, + $multimodalMessages = $multimodalMessages, + $tokenBudget = $tokenBudget, + $tokenPressure = $tokenPressure + }, + $ChatHandlerData = <| |>; + $tokenBudgetLog = Internal`Bag[ ]; + (* cSpell: ignore multser *) + Internal`InheritedBlock[ { $evaluationCell, $evaluationNotebook }, + Quiet[ withToolBox @ withBasePromptBuilder @ eval, ServiceExecute::multser ] + ] + ]; + +withChatState // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*withChatStateAndFEObjects*) +withChatStateAndFEObjects // beginDefinition; +withChatStateAndFEObjects // Attributes = { HoldRest }; + +withChatStateAndFEObjects[ { cell_CellObject, nbo_NotebookObject }, eval_ ] := + withChatState @ withEvaluationNotebook[ nbo, withChatEvaluationCell[ cell, eval ] ]; + +withChatStateAndFEObjects[ { cell_CellObject, None }, eval_ ] := + withChatState @ withChatEvaluationCell[ cell, eval ]; + +(* Operator forms: *) +withChatStateAndFEObjects[ cell_CellObject ] := + withChatStateAndFEObjects[ { cell, None } ]; + +withChatStateAndFEObjects[ { cell_, nbo_ } ] := + Function[ eval, + withChatStateAndFEObjects[ { cell, nbo }, eval ], + HoldFirst + ]; + +withChatStateAndFEObjects // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*withChatEvaluationCell*) +withChatEvaluationCell // beginDefinition; +withChatEvaluationCell // Attributes = { HoldRest }; + +withChatEvaluationCell[ cell_CellObject, eval_ ] := + withChatState @ WithCleanup[ + $ChatEvaluationCell = cell + , + withEvaluationCell[ + cell, + (* Initialize settings cache: *) + AbsoluteCurrentChatSettings @ cell; + eval + ] + , + $ChatEvaluationCell = None; + If[ $CloudEvaluation, + (* Workaround for dynamic in send/stop button not updating in cloud: *) + NotebookWrite[ cell, NotebookRead @ cell, None, AutoScroll -> False ] + ] + ]; + +withChatEvaluationCell // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*forceRedrawCellFrameLabels*) +forceRedrawCellFrameLabels // beginDefinition; + +(* Workaround for dynamic in send/stop button not updating in cloud: *) +forceRedrawCellFrameLabels[ cell_CellObject ] /; $CloudEvaluation && chatInputCellQ @ cell := + Module[ { labels }, + labels = Replace[ + CurrentValue[ cell, CellFrameLabels ], + Except[ { { _, _ }, { _, _ } } ] :> $defaultCellFrameLabels + ]; + SetOptions[ cell, CellFrameLabels -> None ]; + SetOptions[ cell, CellFrameLabels -> labels ]; + ]; + +forceRedrawCellFrameLabels[ cell_ ] := Null; + +forceRedrawCellFrameLabels // endDefinition; + + +$defaultCellFrameLabels = { + { None, Cell[ BoxData @ TemplateBox[ { RGBColor[ "#a3c9f2" ], 20 }, "SendChatButton" ], Background -> None ] }, + { None, None } +}; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*withEvaluationCell*) +withEvaluationCell // beginDefinition; +withEvaluationCell // Attributes = { HoldRest }; +withEvaluationCell[ cell_CellObject, eval_ ] := Block[ { $evaluationCell = cell }, eval ] +withEvaluationCell // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*withEvaluationNotebook*) +withEvaluationNotebook // beginDefinition; +withEvaluationNotebook // Attributes = { HoldRest }; +withEvaluationNotebook[ nbo_NotebookObject, eval_ ] := Block[ { $evaluationNotebook = nbo }, eval ]; +withEvaluationNotebook // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Package Footer*) +addToMXInitialization[ + Null +]; + +End[ ]; +EndPackage[ ]; diff --git a/Source/Chatbook/Chatbook.wl b/Source/Chatbook/Chatbook.wl index cc2e449b..1cf36d17 100644 --- a/Source/Chatbook/Chatbook.wl +++ b/Source/Chatbook/Chatbook.wl @@ -38,8 +38,8 @@ Quiet[ General::shdw ]; -(* Set the paclet object for this paclet, ensuring that it corresponds to the one that's actually loaded: *) -Wolfram`Chatbook`Common`$thisPaclet = PacletObject @ File @ DirectoryName[ $InputFileName, 3 ]; - (* Redraw any dynamics that might might have pink-boxed while loading *) -Wolfram`Chatbook`Dynamics`updateDynamics[ All ]; \ No newline at end of file +Wolfram`Chatbook`Common`updateDynamics[ All ]; + +(* Set the paclet object for this paclet, ensuring that it corresponds to the one that's actually loaded: *) +Wolfram`Chatbook`Common`$thisPaclet = PacletObject @ File @ DirectoryName[ $InputFileName, 3 ]; \ No newline at end of file diff --git a/Source/Chatbook/CloudToolbar.wl b/Source/Chatbook/CloudToolbar.wl index c007d130..8d04a0fc 100644 --- a/Source/Chatbook/CloudToolbar.wl +++ b/Source/Chatbook/CloudToolbar.wl @@ -1,21 +1,11 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`CloudToolbar`" ]; - -HoldComplete[ - `makeChatCloudDockedCellContents; - `forceRefreshCloudPreferences; -]; - Begin[ "`Private`" ]; -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Dialogs`" ]; -Needs[ "Wolfram`Chatbook`Dynamics`" ]; -Needs[ "Wolfram`Chatbook`PreferencesContent`" ]; -Needs[ "Wolfram`Chatbook`Services`" ]; -Needs[ "Wolfram`Chatbook`UI`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`UI`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -62,7 +52,11 @@ makeChatCloudDockedCellContents // endDefinition; cloudCellInsertMenu // beginDefinition; cloudCellInsertMenu[ ] := ActionMenu[ - toolbarButtonLabel @ Row @ { "Insert Chat Cell", Spacer[ 5 ], RawBoxes @ TemplateBox[ { }, "ChatInputIcon" ] }, + toolbarButtonLabel @ Row @ { + tr[ "ChatToolbarInsertChatCell" ], + Spacer[ 5 ], + RawBoxes @ TemplateBox[ { }, "ChatInputIcon" ] + }, { insertStyleMenuItem[ "ChatInputIcon", "ChatInput", "'" ], insertStyleMenuItem[ "SideChatIcon", "SideChat", "' '" ], @@ -143,7 +137,11 @@ insertCellStyle // endDefinition; cloudPreferencesButton // beginDefinition; cloudPreferencesButton[ ] := Button[ - toolbarButtonLabel @ Row @ { "Chat Settings", Spacer[ 5 ], RawBoxes @ TemplateBox[ { }, "AdvancedSettings" ] }, + toolbarButtonLabel @ Row @ { + tr[ "ChatToolbarChatSettings" ], + Spacer[ 5 ], + RawBoxes @ TemplateBox[ { }, "AdvancedSettings" ] + }, toggleCloudPreferences @ EvaluationNotebook[ ], FrameMargins -> { { 0, 4 }, { 0, 0 } } ]; @@ -216,10 +214,12 @@ cloudModelSelector // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*$cloudChatBanner*) -$cloudChatBanner := $cloudChatBanner = cvExpand @ PaneSelector[ - { True -> $chatDrivenNotebookLabel, False -> $chatEnabledNotebookLabel }, - Dynamic @ TrueQ @ cv[ EvaluationNotebook[ ], "ChatDrivenNotebook" ], - ImageSize -> Automatic +$cloudChatBanner := Block[ { $CloudEvaluation = True }, + $cloudChatBanner = cvExpand @ PaneSelector[ + { True -> $chatDrivenNotebookLabel, False -> $chatEnabledNotebookLabel }, + Dynamic @ TrueQ @ cv[ EvaluationNotebook[ ], "ChatDrivenNotebook" ], + ImageSize -> Automatic + ] ]; (* ::**************************************************************************************************************:: *) @@ -230,7 +230,7 @@ $chatDrivenNotebookLabel := Grid[ { "", chatbookIcon[ "ChatDrivenNotebookIcon", False ], - Style[ "Chat-Driven Notebook", $notebookTypeLabelOptions ] + Style[ tr[ "ChatToolbarChatDrivenLabel" ], $notebookTypeLabelOptions ] } }, Alignment -> { Automatic, Center }, @@ -245,7 +245,7 @@ $chatEnabledNotebookLabel := Grid[ { "", chatbookIcon[ "ChatEnabledNotebookIcon", False ], - Style[ "Chat-Enabled Notebook", $notebookTypeLabelOptions ] + Style[ tr[ "ChatToolbarChatEnabledLabel" ], $notebookTypeLabelOptions ] } }, Alignment -> { Automatic, Center }, @@ -276,7 +276,7 @@ forceRefreshCloudPreferences // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $cloudChatBanner; ]; diff --git a/Source/Chatbook/Common.wl b/Source/Chatbook/Common.wl index 5d0ec20a..0c474d1b 100644 --- a/Source/Chatbook/Common.wl +++ b/Source/Chatbook/Common.wl @@ -5,6 +5,9 @@ BeginPackage[ "Wolfram`Chatbook`Common`" ]; (* :!CodeAnalysis::BeginBlock:: *) +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*Symbols defined in this file*) `$closedChatCellOptions; `$cloudNotebooks; `$debug; @@ -33,7 +36,20 @@ BeginPackage[ "Wolfram`Chatbook`Common`" ]; `$$unspecified; `$$feObj; `$$template; - +`$$complex; +`$$integer; +`$$rational; +`$$real; +`$$string; +`$$symbol; +`$$atomic; + +`tr; +`trRaw; +`trStringTemplate; +`trExprTemplate; + +`$catching; `$catchTopTag; `beginDefinition; `catchAlways; @@ -45,6 +61,7 @@ BeginPackage[ "Wolfram`Chatbook`Common`" ]; `importResourceFunction; `messageFailure; `messagePrint; +`setServiceCaller; `throwFailure; `throwInternalFailure; `throwMessageDialog; @@ -55,16 +72,26 @@ BeginPackage[ "Wolfram`Chatbook`Common`" ]; `inlineTemplateBoxes; `sufficientVersionQ; `insufficientVersionQ; +`addToMXInitialization; +`mxInitialize; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*Symbols defined elsewhere in the paclet*) +Get[ "Wolfram`Chatbook`CommonSymbols`" ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*Begin Private Context*) Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; -$cloudNotebooks := TrueQ @ CloudSystem`$CloudNotebooks; - (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Config*) +$cloudNotebooks := TrueQ @ CloudSystem`$CloudNotebooks; + $chatIndicatorSymbol = "\|01f4ac"; $chatDelimiterStyles = { "ChatBlockDivider", "ChatDelimiter", "ExcludedChatDelimiter" }; @@ -94,6 +121,14 @@ $versionRequirements = <| $mxFlag = Wolfram`ChatbookInternal`$BuildingMX; $resourceFunctionContext = "Wolfram`Chatbook`ResourceFunctions`"; +(* cSpell: ignore Deflatten *) +$resourceVersions = <| + "AssociationKeyDeflatten" -> "1.0.0", + "ClickToCopy" -> "1.0.0", + "GPTTokenizer" -> "1.1.0", + "MessageFailure" -> "1.0.0", + "ReplaceContext" -> "1.0.0" +|>; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) @@ -122,6 +157,112 @@ $$unspecified = _Missing | Automatic | Inherited; $$feObj = _FrontEndObject | $FrontEndSession | _NotebookObject | _CellObject | _BoxObject; $$template = _String|_TemplateObject|_TemplateExpression|_TemplateSequence; +(* Helper functions for held pattern tests: *) +u[ f_ ] := Function[ Null, f @ Unevaluated @ #, HoldAllComplete ]; +pt[ patt_, f_ ] := PatternTest[ patt, Evaluate @ u @ f ]; + +(* Atomic expressions (not including raw objects like Association etc): *) +$$complex = pt[ _Complex , AtomQ ]; +$$integer = pt[ _Integer , IntegerQ ]; +$$rational = pt[ _Rational, AtomQ ]; +$$real = pt[ _Real , Developer`RealQ ]; +$$string = pt[ _String , StringQ ]; +$$symbol = pt[ _Symbol , Developer`SymbolQ ]; +$$atomic = $$complex | $$integer | $$rational | $$real | $$string | $$symbol; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Text and Expression Resources*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*tr*) +(* Look up translations for `name` in text resources data files. *) +tr // beginDefinition; +tr[ name_? StringQ ] /; $CloudEvaluation := cloudTextResource @ name; +tr[ name_? StringQ ] := Dynamic @ FEPrivate`FrontEndResource[ "ChatbookStrings", name ]; +tr // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*trRaw*) +trRaw // beginDefinition; +trRaw[ name_? StringQ ] /; $CloudEvaluation := cloudTextResource @ name; +trRaw[ name_? StringQ ] := FrontEndResource[ "ChatbookStrings", name ]; +trRaw // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*trStringTemplate*) +(* Templated strings require the kernel *) +trStringTemplate // beginDefinition; +trStringTemplate[ name_? StringQ ] := StringTemplate @ trRaw @ name; +trStringTemplate // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*trExprTemplate*) +(* There might be a better way to implement this, but the rationale is we should avoid placing huge + expressions or linear syntax within text resource files. + The following is compatible with injection into Row or TextData expressions using numbered sequential slots. *) +trExprTemplate // beginDefinition; + +trExprTemplate[ name_? StringQ ] := + TemplateObject @ Splice @ StringSplit[ trRaw @ name, "`" ~~ d: DigitCharacter.. ~~ "`" :> TemplateSlot @ d ]; + +trExprTemplate // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*$cloudTextResources*) +$cloudTextResources := getCloudTextResources[ ]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*cloudTextResource*) +cloudTextResource // beginDefinition; +cloudTextResource[ name_String ] := cloudTextResource[ name, $cloudTextResources ]; +cloudTextResource[ name_String, resources_Association ] := cloudTextResource[ name, resources[ name ] ]; +cloudTextResource[ name_String, string_String ] := cloudTextResource[ name ] = string; +cloudTextResource // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*getCloudTextResources*) +getCloudTextResources // beginDefinition; + +getCloudTextResources[ ] := Enclose[ + Module[ { file, string, assoc }, + + file = ConfirmBy[ + FileNameJoin @ { $thisPaclet[ "Location" ], "FrontEnd", "TextResources", "ChatbookStrings.tr" }, + FileExistsQ, + "File" + ]; + + string = ConfirmBy[ ReadString @ file, StringQ, "String" ]; + + assoc = ConfirmBy[ + First[ + StringCases[ + string, + "@@resource ChatbookStrings" ~~ WhitespaceCharacter... ~~ rules: Shortest[ "{" ~~ ___ ~~ "}" ] :> + Association @ ToExpression @ rules, + 1 + ], + $Failed + ], + AssociationQ, + "Association" + ]; + + getCloudTextResources[ ] = assoc + ], + throwInternalFailure +]; + +getCloudTextResources // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Messages*) @@ -138,6 +279,7 @@ KeyValueMap[ Function[ MessageName[ Chatbook, #1 ] = #2 ], <| "Internal" -> "An unexpected error occurred. `1`", "InvalidAPIKey" -> "Invalid value for API key: `1`", "InvalidArguments" -> "Invalid arguments given for `1` in `2`.", + "InvalidConversionRules" -> "`1` is neither a list of replacement rules nor a valid dispatch table, and so cannot be used for replacing.", "InvalidExpressionURI" -> "The string \"`1`\" is not a valid expression URI.", "InvalidFrontEndScope" -> "The value `1` is not a valid scope for `2`.", "InvalidFunctions" -> "Invalid setting for ProcessingFunctions: `1`; using defaults instead.", @@ -376,16 +518,22 @@ importResourceFunction // beginDefinition; importResourceFunction::failure = "[ERROR] Failed to import resource function `1`. Aborting MX build."; importResourceFunction // Attributes = { HoldFirst }; -importResourceFunction[ symbol_Symbol, name_String ] /; $mxFlag := Enclose[ +importResourceFunction[ symbol_Symbol, name_String ] := + importResourceFunction[ symbol, name, Lookup[ $resourceVersions, name, "Latest" ] ]; + +importResourceFunction[ symbol_Symbol, name_String, version_String ] /; $mxFlag := Enclose[ Block[ { PrintTemporary }, Module[ { sourceContext, targetContext, definition, replaced, newSymbol }, - sourceContext = ConfirmBy[ ResourceFunction[ name, "Context" ], StringQ ]; + sourceContext = ConfirmBy[ ResourceFunction[ name, "Context", ResourceVersion -> version ], StringQ ]; targetContext = $resourceFunctionContext<>name<>"`"; definition = ConfirmMatch[ ResourceFunction[ name, "DefinitionList" ], _Language`DefinitionList ]; replaced = ConfirmMatch[ - ResourceFunction[ "ReplaceContext" ][ definition, sourceContext -> targetContext ], + ResourceFunction[ "ReplaceContext", ResourceVersion -> $resourceVersions[ "ReplaceContext" ] ][ + definition, + sourceContext -> targetContext + ], _Language`DefinitionList ]; @@ -399,8 +547,8 @@ importResourceFunction[ symbol_Symbol, name_String ] /; $mxFlag := Enclose[ (Message[ importResourceFunction::failure, name ]; Abort[ ]) & ]; -importResourceFunction[ symbol_Symbol, name_String ] := - symbol := symbol = Block[ { PrintTemporary }, ResourceFunction[ name, "Function" ] ]; +importResourceFunction[ symbol_Symbol, name_String, version_String ] := + symbol := symbol = Block[ { PrintTemporary }, ResourceFunction[ name, "Function", ResourceVersion -> version ] ]; importResourceFunction // endDefinition; @@ -427,13 +575,14 @@ catchTop[ eval_, sym_Symbol ] := Block[ { $ChatNotebookEvaluation = True, + $currentChatSettings = None, $messageSymbol = Replace[ $messageSymbol, Chatbook -> sym ], $catching = True, $failed = False, catchTop = # &, catchTopAs = (#1 &) & }, - Catch[ eval, $catchTopTag ] + Catch[ setServiceCaller @ eval, $catchTopTag ] ]; catchTop // endDefinition; @@ -521,7 +670,7 @@ messageFailure[ args___ ] := quiet = If[ TrueQ @ $failed, Quiet, Identity ]; message = messageFailure0; WithCleanup[ - StackInhibit @ convertCloudFailure @ quiet @ message @ args, + StackInhibit @ promoteSourceInfo @ convertCloudFailure @ quiet @ message @ args, If[ TrueQ @ $catching, $failed = True ] ] ]; @@ -552,6 +701,20 @@ convertCloudFailure[ failure_ ] := convertCloudFailure // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*promoteSourceInfo*) +promoteSourceInfo // beginDefinition; + +promoteSourceInfo[ Failure[ + "Chatbook::Internal", + as: KeyValuePattern[ "MessageParameters" :> { _, KeyValuePattern[ "Information" -> info_String ] } ] +] ] := Failure[ "Chatbook::Internal", <| as, "Source" -> info |> ]; + +promoteSourceInfo[ failure_ ] := failure; + +promoteSourceInfo // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*messagePrint*) @@ -589,11 +752,12 @@ makeInternalFailureData // Attributes = { HoldFirst }; makeInternalFailureData[ eval_, Failure[ tag_, as_Association ], args___ ] := StackInhibit @ Module[ { $stack = Stack[ _ ] }, - maskOpenAIKey @ <| - "Evaluation" :> eval, - "Failure" -> Failure[ tag, Association[ KeyTake[ as, "Information" ], as ] ], - "Arguments" -> { args }, - "Stack" :> $stack + maskOpenAIKey @ DeleteMissing @ <| + "Evaluation" :> eval, + "Information" -> as[ "Information" ], + "Failure" -> Failure[ tag, Association[ KeyTake[ as, "Information" ], as ] ], + "Arguments" -> { args }, + "Stack" :> $stack |> ]; @@ -606,13 +770,34 @@ makeInternalFailureData[ eval_, args___ ] := |> ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*setServiceCaller*) +setServiceCaller // beginDefinition; +setServiceCaller // Attributes = { HoldFirst }; + +setServiceCaller[ eval_ ] := ( + Quiet @ Needs[ "ServiceConnectionUtilities`" -> None ]; + setServiceCaller[ eval, ServiceConnectionUtilities`$Caller ] +); + +setServiceCaller[ eval_, { c___ } ] := + Block[ { ServiceConnectionUtilities`$Caller = { c, "Chatbook" }, setServiceCaller = # & }, + eval + ]; + +setServiceCaller[ eval_, _ ] := + setServiceCaller[ eval, { } ]; + +setServiceCaller // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Bug Report Link Generation*) $issuesURL = "https://github.com/WolframResearch/Chatbook/issues/new"; -$maxBugReportURLSize = 3500; +$maxBugReportURLSize = 3250; (* RFC 7230 recommends clients support 8000: https://www.rfc-editor.org/rfc/rfc7230#section-3.1.1 Long bug report links might not work in old versions of IE, @@ -624,6 +809,31 @@ $maxPartLength = 500; $thisPaclet := PacletObject[ "Wolfram/Chatbook" ]; $debugData := debugData @ $thisPaclet[ "PacletInfo" ]; $settingsData := maskOpenAIKey @ $settings; +$releaseID := $releaseID = getReleaseID @ $thisPaclet; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*getReleaseID*) +getReleaseID[ paclet_PacletObject ] := + getReleaseID[ paclet, paclet[ "ReleaseID" ] ]; + +getReleaseID[ paclet_PacletObject, "$RELEASE_ID$" | "None" | Except[ _String ] ] := + getReleaseID0 @ paclet[ "Location" ]; + +getReleaseID[ paclet_, id_String ] := id; + + +getReleaseID0[ dir_? DirectoryQ ] := + Module[ { stdOut, id }, + stdOut = Quiet @ RunProcess[ { "git", "rev-parse", "HEAD" }, "StandardOutput", ProcessDirectory -> dir ]; + id = If[ StringQ @ stdOut, StringTrim @ stdOut, "" ]; + If[ StringMatchQ[ id, Repeated[ HexadecimalCharacter, { 40 } ] ], + id, + "None" + ] + ]; + +getReleaseID0[ ___ ] := "None"; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) @@ -631,7 +841,8 @@ $settingsData := maskOpenAIKey @ $settings; debugData // beginDefinition; debugData[ as_Association? AssociationQ ] := <| - KeyTake[ as, { "Name", "Version", "ReleaseID" } ], + KeyTake[ as, { "Name", "Version" } ], + "ReleaseID" -> $releaseID, "EvaluationEnvironment" -> $EvaluationEnvironment, "FrontEndVersion" -> $frontEndVersion, "KernelVersion" -> SystemInformation[ "Kernel", "Version" ], @@ -664,17 +875,39 @@ bugReportBody[ as_Association? AssociationQ ] := "DebugData" -> associationMarkdown @ $debugData, "Stack" -> $bugReportStack, "Settings" -> associationMarkdown @ maskOpenAIKey @ $settings, - "InternalFailure" -> markdownCodeBlock @ $internalFailure + "InternalFailure" -> markdownCodeBlock @ $internalFailure, + "SourceLink" -> sourceLink @ $internalFailure |> ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*sourceLink*) +sourceLink[ KeyValuePattern[ "Information" -> info_String ] ] := sourceLink @ info; +sourceLink[ info_String ] := sourceLink @ StringSplit[ info, "@@" ]; +sourceLink[ { tag_String, source_String } ] := sourceLink @ { tag, StringSplit[ source, ":" ] }; +sourceLink[ { tag_String, { file_String, pos_String } } ] := sourceLink @ { tag, file, StringSplit[ pos, "-" ] }; + +sourceLink[ { tag_String, file_String, { lc1_String, lc2_String } } ] := + sourceLink @ { tag, file, StringSplit[ lc1, "," ], StringSplit[ lc2, "," ] }; + +sourceLink[ { tag_String, file_String, { l1_String, c1_String }, { l2_String, c2_String } } ] := + Module[ { id }, + id = Replace[ $releaseID, { "$RELEASE_ID$" | "None" | Except[ _String ] -> "main" } ]; + "\n\nhttps://github.com/WolframResearch/Chatbook/blob/"<>id<>"/"<>file<>"#L"<>l1<>"-L"<>l2 + ]; + +sourceLink[ ___ ] := ""; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*$bugReportBodyTemplate*) $bugReportBodyTemplate = StringTemplate[ "\ Describe the issue in detail here. Attach any relevant screenshots or files. \ The section below was automatically generated. \ -Remove any information that you do not wish to include in the report. +Remove any information that you do not wish to include in the report.\ +\ +%%SourceLink%%
Debug Data @@ -685,15 +918,15 @@ Remove any information that you do not wish to include in the report. %%Settings%% +## Failure Data + +%%InternalFailure%% + ## Stack Data ``` %%Stack%% ``` -## Failure Data - -%%InternalFailure%% -
", Delimiters -> "%%" ]; @@ -726,16 +959,37 @@ $bugReportStack := StringRiffle[ (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*$settings*) -$settings := Module[ { settings, styleInfo, assoc }, - settings = CurrentValue @ { TaggingRules, "ChatNotebookSettings" }; - styleInfo = CurrentValue @ { StyleDefinitions, "ChatStyleSheetInformation", TaggingRules }; - assoc = Association @ Select[ Association /@ { settings, styleInfo }, AssociationQ ]; - If[ AssociationQ @ assoc, - KeyDrop[ assoc, "OpenAIKey" ], - settings - ] +$settings := Quiet @ Module[ { settings, styleInfo, assoc }, + + settings = FirstCase[ + Unevaluated @ { + AbsoluteCurrentValue @ { TaggingRules, "ChatNotebookSettings" }, + CurrentValue @ { TaggingRules, "ChatNotebookSettings" } + }, + e_ :> With[ { as = Association @ e }, as /; AssociationQ @ as && as =!= <| |> ], + <| |> + ]; + + styleInfo = styleSheetInfo @ { "WorkspaceChatStylesheetInformation", "ChatStyleSheetInformation" }; + + assoc = Association @ Select[ Association /@ { settings, styleInfo }, AssociationQ ]; + If[ AssociationQ @ assoc, KeyDrop[ assoc, "OpenAIKey" ], settings ] ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*styleSheetInfo*) +styleSheetInfo[ name_String ] := Replace[ + CurrentValue @ { StyleDefinitions, name }, + { + KeyValuePattern[ TaggingRules -> tags: KeyValuePattern @ { } ] :> Association @ tags, + ___ :> <| |> + } +]; + +styleSheetInfo[ names: { ___String } ] := + Association @ Select[ styleSheetInfo /@ names, AssociationQ ]; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*trimURL*) @@ -869,9 +1123,12 @@ chatbookIcon // endDefinition; (*inlineTemplateBox*) inlineTemplateBox // beginDefinition; -inlineTemplateBox[ TemplateBox[ args_, name_String ] ] := +inlineTemplateBox[ box: TemplateBox[ args_, name_String ] ] := With[ { func = $templateBoxDisplayFunctions @ name }, - TemplateBox[ args, name, DisplayFunction -> func ] /; MatchQ[ func, _Function ] + ( + inlineTemplateBox[ Verbatim[ box ] ] = + inlineTemplateBoxes @ TemplateBox[ args, name, DisplayFunction -> func ] + ) /; MatchQ[ func, _Function ] ]; inlineTemplateBox[ RawBoxes[ box_TemplateBox ] ] := @@ -887,10 +1144,10 @@ inlineTemplateBox // endDefinition; inlineTemplateBoxes // beginDefinition; inlineTemplateBoxes[ expr_ ] := - ReplaceAll[ + ReplaceRepeated[ expr, TemplateBox[ args_, name_String ] :> - With[ { func = inlineTemplateBoxes @ $templateBoxDisplayFunctions @ name }, + With[ { func = $templateBoxDisplayFunctions @ name }, TemplateBox[ args, name, DisplayFunction -> func ] /; MatchQ[ func, _Function ] ] ]; @@ -931,13 +1188,45 @@ insufficientVersionQ[ id_String ] := insufficientVersionQ[ id ] = insufficientVe insufficientVersionQ[ id_, version_? NumberQ ] := insufficientVersionQ @ version; insufficientVersionQ // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*MX Build Utilities*) +$mxInitializations := $mxInitializations = Internal`Bag[ ]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*addToMXInitialization*) +addToMXInitialization // beginDefinition; +addToMXInitialization // Attributes = { HoldAllComplete }; +addToMXInitialization[ ] := Null; +addToMXInitialization[ Null ] := Null; +addToMXInitialization[ eval___ ] /; $mxFlag := Internal`StuffBag[ $mxInitializations, HoldComplete @ eval ]; +addToMXInitialization[ ___ ] := Null; +addToMXInitialization // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*mxInitialize*) +mxInitialize // beginDefinition; +mxInitialize // Attributes = { HoldAllComplete }; + +mxInitialize[ eval___ ] := + If[ TrueQ @ $mxFlag, + addToMXInitialization @ eval; + ReleaseHold @ Internal`BagPart[ $mxInitializations, All ]; + ]; + +mxInitialize // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $debug = False; $chatbookIcons; $templateBoxDisplayFunctions; + $cloudTextResources; + $releaseID; ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/CommonSymbols.wl b/Source/Chatbook/CommonSymbols.wl new file mode 100644 index 00000000..8728d39c --- /dev/null +++ b/Source/Chatbook/CommonSymbols.wl @@ -0,0 +1,265 @@ +(* cSpell: ignore Deflatten *) + +BeginPackage[ "Wolfram`Chatbook`Common`" ]; + +`$absoluteCurrentSettingsCache; +`$allowConnectionDialog; +`$alwaysOpen; +`$attachments; +`$autoOpen; +`$availableServices; +`$basePrompt; +`$basePromptComponents; +`$baseStyle; +`$cellStringBudget; +`$chatDataTag; +`$chatInputIndicator; +`$chatState; +`$cloudEvaluationNotebook; +`$cloudInlineReferenceButtons; +`$conversionRules; +`$corePersonaNames; +`$CurrentCell; +`$currentChatSettings; +`$currentSettingsCache; +`$customToolFormatter; +`$defaultChatSettings; +`$defaultChatTools; +`$defaultMaxCellStringLength; +`$defaultMaxOutputCellStringLength; +`$dialogInputAllowed; +`$dynamicSplitRules; +`$dynamicText; +`$enableLLMServices; +`$evaluationCell; +`$evaluationNotebook; +`$finalCell; +`$fullBasePrompt; +`$inDialog; +`$inEpilog; +`$initialCellStringBudget; +`$inlineChatState; +`$lastCellObject; +`$lastChatString; +`$lastMessages; +`$lastSettings; +`$lastTask; +`$leftSelectionIndicator; +`$longNameCharacters; +`$multimodalMessages; +`$nextTaskEvaluation; +`$preferencesScope; +`$resultCellCache; +`$rightSelectionIndicator; +`$sandboxKernelCommandLine; +`$selectedTools; +`$serviceCache; +`$servicesLoaded; +`$statelessProgressIndicator; +`$suppressButtonAppearance; +`$tinyHashLength; +`$tokenBudget; +`$tokenBudgetLog; +`$tokenPressure; +`$toolConfiguration; +`$toolEvaluationResults; +`$toolOptions; +`$toolResultStringLength; +`$useLLMServices; +`accentIncludedCells; +`acv; +`addHandlerArguments; +`addProcessingArguments; +`allowedMultimodalRoles; +`apiKeyDialog; +`applyHandlerFunction; +`applyProcessingFunction; +`assistantMessageBox; +`assistantMessageLabel; +`associationKeyDeflatten; +`attachInlineChatInput; +`attachMenuCell; +`attachWorkspaceChatInput; +`autoAssistQ; +`cachedTokenizer; +`cellInformation; +`cellOpenQ; +`cellPrint; +`cellPrintAfter; +`cellStyles; +`channelCleanup; +`chatExcludedQ; +`chatHandlerFunctionsKeys; +`chatInputCellQ; +`chatModelQ; +`checkEvaluationCell; +`chooseDefaultModelName; +`clearMinimizedChats; +`clickToCopy; +`compressUntilViewed; +`constructMessages; +`contextBlock; +`convertUTF8; +`createDialog; +`createFETask; +`createNewInlineOutput; +`createPreferencesContent; +`currentChatSettings; +`cv; +`cvExpand; +`dialogBody; +`dialogHeader; +`dialogSubHeader; +`displayInlineChat; +`documentationSearchAPI; +`dynamicAutoFormatQ; +`dynamicSplitQ; +`escapeMarkdownString; +`evaluateInlineChat; +`evaluateWorkspaceChat; +`expandMultimodalString; +`explodeCell; +`exportDataURI; +`expressionURIKey; +`expressionURIKeyQ; +`fastFileHash; +`feParentObject; +`filterChatCells; +`fixCloudCell; +`fixLineEndings; +`floatingButtonGrid; +`forceRefreshCloudPreferences; +`functionTemplateBoxes; +`getAvailableServiceNames; +`getBoxObjectFromBoxID; +`getChatGroupSettings; +`getHandlerFunctions; +`getInlineChatPrompt; +`getModelList; +`getPersonaIcon; +`getPersonaMenuIcon; +`getPrecedingDelimiter; +`getProcessingFunction; +`getProcessingFunctions; +`getServiceModelList; +`getTokenizer; +`getTokenizerName; +`getToolByName; +`getToolDisplayName; +`getToolFormattingFunction; +`getToolIcon; +`getUserNotebook; +`getWorkspacePrompt; +`graphicsQ; +`grayDialogButtonLabel; +`image2DQ; +`importDataURI; +`initFETaskWidget; +`initTools; +`inlineExpressionURIs; +`insertCodeBelow; +`insertFunctionInputBox; +`insertFunctionTemplate; +`insertModifierInputBox; +`insertModifierTemplate; +`insertPersonaInputBox; +`insertPersonaTemplate; +`insertTrailingFunctionInputBox; +`insertWLTemplate; +`logUsage; +`makeCellStringBudget; +`makeChatCloudDockedCellContents; +`makeChatMessages; +`makeExpressionURI; +`makeFailureString; +`makeInteractiveCodeCell; +`makeModelSelector; +`makeOutputDingbat; +`makeTokenBudget; +`makeToolConfiguration; +`makeToolResponseString; +`makeWorkspaceChatDockedCell; +`menuMagnification; +`modelDisplayName; +`modelListCachedQ; +`modifierTemplateBoxes; +`moveToChatInputField; +`multimodalModelQ; +`multimodalPacletsAvailable; +`needsBasePrompt; +`nextCell; +`notebookInformation; +`notebookRead; +`openerView; +`openPreferencesPage; +`parentCell; +`parentNotebook; +`parseInlineReferences; +`parseSimpleToolCallParameterStrings; +`personaDisplayName; +`personaTemplateBoxes; +`preprocessSandboxString; +`rasterize; +`rasterizeBlock; +`readString; +`redDialogButtonLabel; +`reformatTextData; +`relativeTimeString; +`removeBasePrompt; +`removeCellAccents; +`removeChatMenus; +`replaceCellContext; +`resizeMenuIcon; +`resizeMultimodalImage; +`resolveAutoSettings; +`resolveFullModelSpec; +`resolveInlineReferences; +`resolveTools; +`revertMultimodalContent; +`rootEvaluationCell; +`sandboxEvaluate; +`sandboxFormatter; +`scrollOutputQ; +`selectByCurrentValue; +`selectionEvaluateCreateCell; +`sendChat; +`sendFeedback; +`serviceIcon; +`setCV; +`simpleResultQ; +`simpleToolRequestParser; +`snapshotModelQ; +`standardizeMessageKeys; +`standardizeModelData; +`stringToBoxes; +`stringTrimMiddle; +`systemCredential; +`tinyHash; +`toAPIKey; +`toCompressedBoxes; +`toImageURI; +`toModelName; +`toolAutoFormatter; +`toolData; +`toolName; +`toolOptionValue; +`toolRequestParser; +`toolSelectedQ; +`toolsEnabledQ; +`topParentCell; +`trackedDynamic; +`truncateString; +`unsetCV; +`updateDynamics; +`userMessageBox; +`userMessageLabel; +`usingFrontEnd; +`withBasePromptBuilder; +`withChatState; +`withChatStateAndFEObjects; +`withToolBox; +`wlTemplateBoxes; +`writeInlineChatOutputCell; +`writeReformattedCell; + +EndPackage[ ]; \ No newline at end of file diff --git a/Source/Chatbook/CreateChatNotebook.wl b/Source/Chatbook/CreateChatNotebook.wl index 6a4ab766..27319e39 100644 --- a/Source/Chatbook/CreateChatNotebook.wl +++ b/Source/Chatbook/CreateChatNotebook.wl @@ -9,12 +9,9 @@ HoldComplete[ Begin[ "`Private`" ]; -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Formatting`" ]; -Needs[ "Wolfram`Chatbook`SendChat`" ]; -Needs[ "Wolfram`Chatbook`Settings`" ]; -Needs[ "Wolfram`Chatbook`UI`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`UI`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -29,6 +26,7 @@ $$createChatOptions = OptionsPattern[ { CreateChatNotebook, Notebook } ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*CreateChatNotebook*) +Needs[ "Wolfram`Chatbook`Settings`" ]; (* Needed for $defaultChatSettings *) CreateChatNotebook // Options = Normal[ $defaultChatSettings, Association ]; @@ -289,8 +287,8 @@ createMessageCell0 // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; End[ ]; diff --git a/Source/Chatbook/Dialogs.wl b/Source/Chatbook/Dialogs.wl index d5536c9e..feea7bfe 100644 --- a/Source/Chatbook/Dialogs.wl +++ b/Source/Chatbook/Dialogs.wl @@ -1,30 +1,10 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Dialogs`" ]; +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -`$baseStyle; - -`$inDialog; -`createDialog; - -`acv; -`cv; -`cvExpand; -`setCV; -`unsetCV; - -`headerStyle; -`dialogHeader; -`dialogSubHeader; -`dialogBody; - -`grayDialogButtonLabel; -`redDialogButtonLabel; - -Begin[ "`Private`" ]; - Needs[ "Wolfram`Chatbook`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; Needs[ "Wolfram`Chatbook`ResourceInstaller`" ]; @@ -318,7 +298,7 @@ unsetCV // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $cvRules; ]; diff --git a/Source/Chatbook/Dynamics.wl b/Source/Chatbook/Dynamics.wl index 899a382a..cc489f1b 100644 --- a/Source/Chatbook/Dynamics.wl +++ b/Source/Chatbook/Dynamics.wl @@ -1,15 +1,10 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Dynamics`" ]; +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -`trackedDynamic; -`trackedDynamicWrapper; -`updateDynamics; - -Begin[ "`Private`" ]; - Needs[ "Wolfram`Chatbook`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; @@ -17,12 +12,13 @@ Needs[ "Wolfram`Chatbook`Common`" ]; (* ::Section::Closed:: *) (*Configuration*) $dynamicTriggers = <| - "ChatBlock" :> $chatBlockTrigger, - "Models" :> $modelsTrigger, - "Personas" :> $personasTrigger, - "Preferences" :> $preferencesTrigger, - "Services" :> $servicesTrigger, - "Tools" :> $toolsTrigger + "ChatBlock" :> $chatBlockTrigger, + "InlineChatScrollPane" :> $inlineChatScrollPaneTrigger, + "Models" :> $modelsTrigger, + "Personas" :> $personasTrigger, + "Preferences" :> $preferencesTrigger, + "Services" :> $servicesTrigger, + "Tools" :> $toolsTrigger |>; Cases[ $dynamicTriggers, sym_Symbol :> (sym = 0) ]; @@ -141,8 +137,8 @@ updateDynamics // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Explode.wl b/Source/Chatbook/Explode.wl index 68cc2908..2ba6c867 100644 --- a/Source/Chatbook/Explode.wl +++ b/Source/Chatbook/Explode.wl @@ -1,15 +1,26 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Explode`" ]; - -`explodeCell; - Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -$$newCellStyle = "Section"|"Subsection"|"Subsubsection"|"Subsubsubsection"|"Item"|"Input"|"ExternalLanguage"|"Program"; +$$newCellStyle = Alternatives[ + "BlockQuote", + "ExternalLanguage", + "Input", + "Item", + "MarkdownDelimiter", + "Program", + "Section", + "Subsection", + "Subsubsection", + "Subsubsubsection", + "Text", + "TextTableForm", + "Title" +]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -39,6 +50,10 @@ explodeCell // endDefinition; (* ::Subsection::Closed:: *) (*$preprocessingRules*) $preprocessingRules := $preprocessingRules = Dispatch @ { + (* Remove "InlineSection" styling: *) + Cell[ BoxData @ PaneBox[ StyleBox[ text_, style_, ___ ], ___ ], "InlineSection", ___ ] :> + RuleCondition @ StyleBox[ extractText @ text, style ], + (* Convert TextRefLink to plain hyperlink: *) Cell @ BoxData[ TemplateBox[ { label_, uri_, ___ }, "TextRefLink" ], ___ ] :> Cell @ BoxData @ ButtonBox[ @@ -79,6 +94,12 @@ $preprocessingRules := $preprocessingRules = Dispatch @ { (* Remove nested cells: *) Cell @ BoxData[ cell_Cell, ___ ] :> cell, + StyleBox[ a_String, "InlineItem", b___ ] :> StyleBox[ "\n"<>a, b ], + + (* Format text tables: *) + Cell[ content__, "TextTableForm", opts: OptionsPattern[ ] ] :> + Cell[ content, "TextTableForm", "Text", opts ], + (* Remove extra style overrides from external language cells: *) Cell[ content_, "ExternalLanguage", OrderlessPatternSequence[ System`CellEvaluationLanguage -> lang_, __ ] ] :> Cell[ content, "ExternalLanguage", System`CellEvaluationLanguage -> lang ], @@ -98,9 +119,21 @@ $preprocessingRules := $preprocessingRules = Dispatch @ { { a, Cell @@ b, c }, (* Tiny line breaks: *) - StyleBox[ "\n", "TinyLineBreak", ___ ] :> "\n" + StyleBox[ "\n", "TinyLineBreak", ___ ] :> "\n", + + Cell[ boxes_, style: "MarkdownDelimiter"|"BlockQuote", a___ ] :> + Cell[ boxes, "Text", style, a ] }; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*extractText*) +extractText // beginDefinition; +extractText[ text_String ] := If[ StringMatchQ[ text, "\"" ~~ ___ ~~ "\"" ], ToExpression @ text, text ]; +extractText[ (Cell|StyleBox)[ text_, ___ ] ] := extractText @ text; +extractText[ text_ ] := extractText[ text ] = CellToString @ text; +extractText // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*regroupCells*) @@ -155,7 +188,7 @@ regroupCells // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $preprocessingRules; ]; diff --git a/Source/Chatbook/Feedback.wl b/Source/Chatbook/Feedback.wl index 62d4268b..4bc02512 100644 --- a/Source/Chatbook/Feedback.wl +++ b/Source/Chatbook/Feedback.wl @@ -1,23 +1,13 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Feedback`" ]; +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -HoldComplete[ - `sendFeedback; -]; - -Begin[ "`Private`" ]; - Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`ChatMessages`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Dialogs`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`SendChat`" ]; Needs[ "Wolfram`Chatbook`Serialization`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -42,7 +32,7 @@ sendFeedback[ cell_CellObject, positive: True|False ] := Enclose[ data = ConfirmBy[ createFeedbackData[ cell, positive ], AssociationQ, "FeedbackData" ]; ConfirmMatch[ createFeedbackDialog[ cell, data ], _NotebookObject, "FeedbackDialog" ] ], - throwInternalFailure[ sendFeedback[ cell, positive ], ## ] & + throwInternalFailure ]; sendFeedback // endDefinition; @@ -60,7 +50,7 @@ createFeedbackData[ cell_CellObject, positive: True|False ] := Enclose[ data = ConfirmBy[ BinaryDeserialize @ wxf, AssociationQ, "Data" ]; chatData = ConfirmBy[ Lookup[ data, "Data" ], AssociationQ, "ChatData" ]; systemData = ConfirmBy[ $debugData, AssociationQ, "SystemData" ]; - settings = ConfirmBy[ Association[ $settingsData, KeyDrop[ data, "Data" ] ], AssociationQ, "SettingsData" ]; + settings = ConfirmBy[ Association[ $settingsData, KeyDrop[ data, "Data" ] ], AssociationQ, "SettingsData" ]; image = ConfirmBy[ cellImage @ cell, ImageQ, "Image" ]; <| @@ -72,7 +62,7 @@ createFeedbackData[ cell_CellObject, positive: True|False ] := Enclose[ "ContentID" -> contentID @ { chatData, settings, systemData } |> ], - throwInternalFailure[ createFeedbackData[ cell, positive ], ##1 ] & + throwInternalFailure ]; createFeedbackData // endDefinition; @@ -92,7 +82,7 @@ cellImage[ cellObject_CellObject ] := Enclose[ (* cellImage[ cellObject ] = image *) image ], - throwInternalFailure[ cellImage @ cellObject, ## ] & + throwInternalFailure ]; cellImage // endDefinition; @@ -124,7 +114,7 @@ createFeedbackDialogContent[ cell_CellObject, Dynamic[ data_ ], Dynamic[ choices cvExpand @ Module[ { content }, content = Grid[ { - dialogHeader[ "Send Wolfram AI Chat Feedback" ], + dialogHeader[ tr[ "FeedbackDialogHeader" ] ], dialogBody[ Grid[ { @@ -136,7 +126,7 @@ createFeedbackDialogContent[ cell_CellObject, Dynamic[ data_ ], Dynamic[ choices False -> chatbookIcon[ "ThumbsDownActive", False ] } ], - "Sending feedback helps us improve our AI features." + tr[ "FeedbackDialogBodyThumbs" ] } }, Alignment -> { Left, Baseline } @@ -152,14 +142,14 @@ createFeedbackDialogContent[ cell_CellObject, Dynamic[ data_ ], Dynamic[ choices Dynamic @ data[ "Comment" ], String, ContinuousAction -> True, - FieldHint -> "Do you have additional feedback? (Optional)", + FieldHint -> tr[ "FeedbackDialogCommentFieldHint" ], ImageSize -> { 500, 60 } ], { Automatic, { 3, Automatic } } ], dialogBody[ Style[ - "Your chat history and feedback may be used for training purposes.", + tr[ "FeedbackDialogBodyUsedForTraining" ], FontColor -> GrayLevel[ 0.75 ], FontSize -> 12 ], @@ -167,7 +157,7 @@ createFeedbackDialogContent[ cell_CellObject, Dynamic[ data_ ], Dynamic[ choices ], dialogBody @ OpenerView[ { - "Preview data to be sent", + tr[ "FeedbackDialogBodyPreviewData" ], topRightOverlay[ Pane[ Dynamic @ generatePreviewData[ data, choices ], @@ -203,14 +193,14 @@ createFeedbackDialogContent[ cell_CellObject, Dynamic[ data_ ], Dynamic[ choices Grid[ { { Button[ - grayDialogButtonLabel[ "Cancel" ], + grayDialogButtonLabel[ tr[ "CancelButton" ] ], NotebookClose @ EvaluationNotebook[ ], Appearance -> "Suppressed", BaselinePosition -> Baseline, Method -> "Queued" ], Button[ - redDialogButtonLabel[ "Send" ], + redDialogButtonLabel[ tr[ "SendButton" ] ], sendDialogFeedback[ cell, EvaluationNotebook[ ], data, choices ], Appearance -> "Suppressed", BaselinePosition -> Baseline, @@ -252,7 +242,7 @@ createFeedbackDialogContent[ cell_CellObject, Dynamic[ data_ ], Dynamic[ choices { "None" -> content, "Submitting" -> ProgressIndicator[ Appearance -> "Necklace" ], - "Done" -> Style[ "Thanks for your feedback!", $baseStyle ], + "Done" -> Style[ tr[ "FeedbackDialogThanks" ], $baseStyle ], "Error" -> Style[ Dynamic[ CurrentValue[ EvaluationNotebook[ ], { TaggingRules, "ErrorText" } ] ], $baseStyle @@ -300,10 +290,13 @@ includedContentGrid[ Dynamic[ data_ ], Dynamic[ choices_ ] ] := Enclose[ Grid[ { { - "Included content:", + tr[ "FeedbackDialogContentIncludedLabel" ], PaneSelector[ { - True -> Style[ "Output image", FontColor -> GrayLevel[ 0.75 ] ], + True -> Style[ + tr[ "FeedbackDialogContentOutputImageLabel" ], + FontColor -> GrayLevel[ 0.75 ] + ], False -> "" }, Dynamic @ choices[ "CellImage" ] @@ -384,7 +377,7 @@ includedContentCheckboxes[ Dynamic[ data_ ], Dynamic[ choices_ ] ] := choices[ "Messages" ], Function[ choices[ "SystemMessage" ] = choices[ "ChatHistory" ] = #1; choices[ "Messages" ] = #1 ] ], - infoTooltip[ "Chat messages", "Chat messages involved in creating this chat output." ] + infoTooltip[ tr[ "FeedbackChatMessagesContent" ], tr[ "FeedbackChatMessagesTooltip" ] ] }, { "", @@ -392,17 +385,11 @@ includedContentCheckboxes[ Dynamic[ data_ ], Dynamic[ choices_ ] ] := { { Checkbox[ Dynamic @ choices[ "SystemMessage" ], Enabled -> Dynamic @ choices[ "Messages" ] ], - infoTooltip[ - "System message", - "The underlying system message used for giving instructions to the AI." - ] + infoTooltip[ tr[ "FeedbackSystemMessageContent" ], tr[ "FeedbackSystemMessageTooltip" ] ] }, { Checkbox[ Dynamic @ choices[ "ChatHistory" ], Enabled -> Dynamic @ choices[ "Messages" ] ], - infoTooltip[ - "Chat history used to generate this output", - "Additional messages that were used as conversation history to generate this output." - ] + infoTooltip[ tr[ "FeedbackChatHistoryContent" ], tr[ "FeedbackChatHistoryTooltip" ] ] } }, Alignment -> { Left, Baseline }, @@ -411,10 +398,7 @@ includedContentCheckboxes[ Dynamic[ data_ ], Dynamic[ choices_ ] ] := }, { Checkbox @ Dynamic @ choices[ "CellImage" ], - infoTooltip[ - "Image of chat output", - "A screenshot of the chat output, which can be used if feedback is related to the output's appearance." - ] + infoTooltip[ tr[ "FeedbackChatImageContent" ], tr[ "FeedbackChatImageTooltip" ] ] } }, Alignment -> { Left, Baseline }, @@ -834,8 +818,8 @@ toolJSON // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Formatting.wl b/Source/Chatbook/Formatting.wl index 106853a5..2934fb55 100644 --- a/Source/Chatbook/Formatting.wl +++ b/Source/Chatbook/Formatting.wl @@ -2,35 +2,10 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Formatting`" ]; - -(* cSpell: ignore TOOLCALL, ENDARGUMENTS, ENDRESULT *) - -Wolfram`Chatbook`FormatChatOutput; -Wolfram`Chatbook`FormatToolCall; -Wolfram`Chatbook`StringToBoxes; - -`$customToolFormatter; -`$dynamicSplitRules; -`$dynamicText; -`$reformattedCell; -`$resultCellCache; -`clickToCopy; -`floatingButtonGrid; -`insertCodeBelow; -`makeInteractiveCodeCell; -`reformatTextData; -`stringToBoxes; -`toolAutoFormatter; - Begin[ "`Private`" ]; -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`Sandbox`" ]; -Needs[ "Wolfram`Chatbook`Tools`" ]; - -(* FIXME: Use ParagraphSpacing to squeeze text closer together *) +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -52,10 +27,11 @@ $wlCodeString = Longest @ Alternatives[ $resultCellCache = <| |>; -sectionStyle[ 1 ] := "Section"; -sectionStyle[ 2 ] := "Subsection"; -sectionStyle[ 3 ] := "Subsubsection"; -sectionStyle[ 4 ] := "Subsubsubsection"; +sectionStyle[ 1 ] := "Title"; +sectionStyle[ 2 ] := "Section"; +sectionStyle[ 3 ] := "Subsection"; +sectionStyle[ 4 ] := "Subsubsection"; +sectionStyle[ 5 ] := "Subsubsubsection"; sectionStyle[ _ ] := "Subsubsubsubsection"; $tinyLineBreak = StyleBox[ "\n", "TinyLineBreak", FontSize -> 3 ]; @@ -76,11 +52,20 @@ $externalLanguageRules = Replace[ { 1 } ]; -$$mdRow1 = WhitespaceCharacter... ~~ "|" ~~ Except[ "\n" ]... ~~ "|" ~~ WhitespaceCharacter... ~~ ("\n"|EndOfString); +$$ws = Shortest[ WhitespaceCharacter... ]; +$$mdRow1 = $$ws ~~ "|" ~~ Except[ "\n" ]... ~~ "|" ~~ $$ws ~~ ("\n"|EndOfString); $$mdRow2 = Except[ "\n" ].. ~~ Repeated[ ("|" ~~ Except[ "\n" ]...), { 2, Infinity } ] ~~ ("\n"|EndOfString); $$mdRow = $$mdRow1 | $$mdRow2; $$mdTable = $$mdRow ~~ $$mdRow ..; +$$blockQuoteLine = StartOfLine ~~ ">" ~~ $$ws ~~ Except[ "\n" ].. ~~ ("\n"|EndOfString); +$$blockQuote = Longest[ $$blockQuoteLine.. ]; + +$$hyphenDelimiter = Repeated[ "-", { 3, Infinity } ]; +$$asteriskDelimiter = Repeated[ "*", { 3, Infinity } ]; +$$underscoreDelimiter = Repeated[ "_", { 3, Infinity } ]; +$$delimiter = StartOfLine ~~ ($$hyphenDelimiter|$$asteriskDelimiter|$$underscoreDelimiter) ~~ EndOfLine; + $chatGeneratedCellTag = "ChatGeneratedCell"; $simpleToolMethod := $ChatHandlerData[ "ChatNotebookSettings", "ToolMethod" ] === "Simple"; @@ -103,6 +88,32 @@ $autoOperatorRenderings = <| $expressionURIPlaceholder = "\[LeftSkeleton]\[Ellipsis]\[RightSkeleton]"; $freeformPromptBox = StyleBox[ "\[FreeformPrompt]", FontColor -> RGBColor[ "#ff6f00" ], FontSize -> 9 ]; + + $delimiterCell = Cell[ + BoxData @ TagBox[ + GridBox[ + { { TemplateBox[ { 0 }, "Spacer1" ] }, { TemplateBox[ { 0 }, "Spacer1" ] } }, + AutoDelete -> False, + GridBoxDividers -> { "Columns" -> { False, { True }, False }, "Rows" -> { False, { True }, False } }, + GridBoxItemSize -> { "Columns" -> { { Fit } }, "Rows" -> { { Automatic } } }, + FrameStyle -> Directive[ GrayLevel[ 0.8 ], AbsoluteThickness[ 1 ] ] + ], + "Grid" + ], + "MarkdownDelimiter", + Background -> None, + ShowStringCharacters -> False +]; + + +esc[ c_ ] := "\[EntityStart]" <> IntegerString @ FromDigits[ ToCharacterCode[ c, "UTF-8" ], 255 ] <> "\[EntityEnd]"; + +$mdEscapedCharacters = { "`", "$", "*", "_", "#", "|" }; +$$mdEscapedCharacter = Alternatives @@ Map[ "\\"<># &, $mdEscapedCharacters ]; + +$mdEscapeRules = "\\" <> # -> esc @ # & /@ $mdEscapedCharacters; +$mdUnescapeRules = esc @ # -> # & /@ $mdEscapedCharacters; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*StringToBoxes*) @@ -111,6 +122,20 @@ StringToBoxes[ string_String? StringQ ] := catchAlways[ stringToBoxes @ string, StringToBoxes[ string_String? StringQ, "WL" ] := catchAlways[ wlStringToBoxes @ string, StringToBoxes ]; StringToBoxes // endExportedDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*CachedBoxes*) +CachedBoxes // beginDefinition; +CachedBoxes[ expr_ ] := catchMine @ cachedBoxes @ Unevaluated @ expr; +CachedBoxes // endExportedDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*DisplayBase64Boxes*) +DisplayBase64Boxes // beginDefinition; +DisplayBase64Boxes[ b64_String ] := catchMine @ displayBase64Boxes @ b64; +DisplayBase64Boxes // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Chat Output Formatting*) @@ -168,12 +193,13 @@ formatToolCall // endDefinition; formatToolCall0 // beginDefinition; -formatToolCall0[ string_String, as_Association ] := Panel[ - makeToolCallBoxLabel @ as, - BaseStyle -> "Text", - Background -> GrayLevel[ 0.95 ], - ImageMargins -> 10 -]; +formatToolCall0[ string_String, as_Association ] := + Panel[ + makeToolCallBoxLabel @ as, + BaseStyle -> { "Text", LineBreakWithin -> False }, + Background -> GrayLevel[ 0.95 ], + ImageMargins -> { { 0, 0 }, { 10, 10 } } + ]; formatToolCall0[ string_String, failed_Failure ] := Framed[ failed, @@ -191,14 +217,47 @@ formatToolCall0 // endDefinition; (*reformatTextData*) reformatTextData // beginDefinition; +reformatTextData[ string_String ] /; StringContainsQ[ string, $$mdEscapedCharacter ] := + ReplaceAll[ + reformatTextData @ StringReplace[ string, $mdEscapeRules ], + s_String :> RuleCondition @ StringReplace[ s, $mdUnescapeRules ] + ]; + reformatTextData[ string_String ] := joinAdjacentStrings @ Flatten[ - makeResultCell /@ StringSplit[ string, $textDataFormatRules, IgnoreCase -> True ] + makeResultCell /@ discardBadToolCalls @ DeleteCases[ + StringSplit[ string, $textDataFormatRules, IgnoreCase -> True ], + "" + ] ]; reformatTextData[ other_ ] := other; reformatTextData // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*discardBadToolCalls*) +discardBadToolCalls // beginDefinition; + +discardBadToolCalls[ { + a___, + tc_inlineToolCallCell, + b: Except[ _inlineToolCallCell ]..., + $discardPreviousToolCall, + c___ +} ] := discardBadToolCalls @ { a, $lastDiscarded = discardedMaterial[ tc, b ], c }; + +discardBadToolCalls[ { a: Except[ _inlineToolCallCell ]..., $discardPreviousToolCall, b___ } ] := + discardBadToolCalls @ { a, b }; + +discardBadToolCalls[ { a___, discardedMaterial[ b___ ], discardedMaterial[ c___ ], d___ } ] := + discardBadToolCalls @ { a, $lastDiscarded = discardedMaterial[ b, c ], d }; + +discardBadToolCalls[ textData_List ] := + textData; + +discardBadToolCalls // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*makeResultCell*) @@ -217,6 +276,9 @@ makeResultCell // endDefinition; makeResultCell0 // beginDefinition; +makeResultCell0[ discardedMaterial[ stuff___ ] ] := + makeDiscardedMaterialCell @ stuff; + makeResultCell0[ str_String ] := formatTextString @ str; makeResultCell0[ codeBlockCell[ language_String, code_String ] ] := @@ -246,18 +308,16 @@ makeResultCell0[ imageCell[ alt_String, url_String ] ] := image[ alt, url ]; makeResultCell0[ hyperlinkCell[ label_String, url_String ] ] := hyperlink[ label, url ]; makeResultCell0[ bulletCell[ whitespace_String, item_String ] ] := Flatten @ { - $tinyLineBreak, + "\n", whitespace, - StyleBox[ "\[Bullet]", FontColor -> GrayLevel[ 0.5 ] ], + StyleBox[ "\[Bullet]", "InlineItem", FontColor -> GrayLevel[ 0.5 ] ], " ", - reformatTextData @ item, - $tinyLineBreak + formatTextString @ item }; makeResultCell0[ sectionCell[ n_, section_String ] ] := Flatten @ { "\n", - styleBox[ formatTextString @ section, sectionStyle @ n, "InlineSection", FontSize -> .8*Inherited ], - $tinyLineBreak + inlineSection[ section, sectionStyle @ n ] }; makeResultCell0[ inlineToolCallCell[ string_String ] ] := ( @@ -268,8 +328,99 @@ makeResultCell0[ inlineToolCallCell[ string_String ] ] := ( makeResultCell0[ tableCell[ string_String ] ] := makeTableCell @ string; +makeResultCell0[ delimiterCell[ ] ] := + $delimiterCell; + +makeResultCell0[ blockQuoteCell[ quote_String ] ] := Cell[ + BoxData @ GridBox[ + { + { + PaneBox[ + formatTextToBoxes @ StringDelete[ StringTrim @ quote, StartOfLine ~~ ">" ~~ " "... ], + ImageMargins -> 5, + ImageSize -> { Full, Automatic }, + BaseStyle -> { "Text", FontColor -> GrayLevel[ 0.35 ] } + ] + } + }, + AutoDelete -> False, + GridBoxBackground -> { "Columns" -> { { GrayLevel[ 1 ] } } }, + GridBoxDividers -> { + "ColumnsIndexed" -> { 1 -> Directive[ RGBColor[ 0.87, 0.94, 1 ], AbsoluteThickness[ 4 ] ] }, + "Rows" -> { { False } } + }, + GridBoxItemSize -> { "Columns" -> { { Automatic } }, "Rows" -> { { Automatic } } } + ], + "BlockQuote", + Background -> None +]; + makeResultCell0 // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*inlineSection*) +inlineSection // beginDefinition; + +inlineSection[ content_, style_String ] := + inlineSection[ content, style, sectionMargins @ style ]; + +inlineSection[ content_, style_String, margins: { { _, _ }, { _, _ } } ] := Cell[ + BoxData @ PaneBox[ + StyleBox[ formatTextToBoxes @ content, style, ShowStringCharacters -> False ], + ImageMargins -> margins + ], + "InlineSection", + Background -> None +]; + +inlineSection[ content_, style_String, { bottom_Integer, top_Integer } ] := + inlineSection[ content, style, { { 0, 0 }, { bottom, top } } ]; + +inlineSection // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*formatTextToBoxes*) +formatTextToBoxes // beginDefinition; +formatTextToBoxes[ text_String ] := formatTextToBoxes[ text, styleBox @ text ]; +formatTextToBoxes[ text_String, formatted_String ] := ToBoxes @ formatted; +formatTextToBoxes[ text_String, data: $$textData ] := Cell[ TextData @ Flatten @ { data }, Background -> None ]; +formatTextToBoxes // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*sectionMargins*) +sectionMargins // beginDefinition; +sectionMargins[ "Title"|"Section"|"Subsection"|"Subsubsection" ] := { { 0, 0 }, { 5, 15 } }; +sectionMargins[ _String ] := { { 0, 0 }, { 2, 5 } }; +sectionMargins // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makeDiscardedMaterialCell*) +makeDiscardedMaterialCell // beginDefinition; + +makeDiscardedMaterialCell[ stuff___ ] := { + Cell[ + BoxData @ TemplateBox[ + { + ToBoxes @ compressUntilViewed @ RawBoxes @ Cell[ + TextData @ joinAdjacentStrings @ Flatten[ makeResultCell /@ { stuff } ], + "Text", + Background -> None, + FontOpacity -> 0.5 + ] + }, + "DiscardedMaterialOpener" + ], + "DiscardedMaterial", + Background -> None + ], + "\n" +}; + +makeDiscardedMaterialCell // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) @@ -330,9 +481,8 @@ texUTF8Convert0 // endDefinition; makeTableCell // beginDefinition; makeTableCell[ table_String ] := Flatten @ { - $tinyLineBreak, - makeTableCell0 @ table, - $tinyLineBreak + "\n", + makeTableCell0 @ StringTrim @ table }; makeTableCell // endDefinition; @@ -348,7 +498,10 @@ makeTableCell0 @ { { __String? emptyTableItemQ }, { b__String? delimiterItemQ }, makeTableCell0[ { a_List, { b__String? delimiterItemQ }, c__ } ] := Cell[ - BoxData @ alignTable[ ToBoxes @ textTableForm[ { c }, TableHeadings -> { None, formatRaw /@ a } ], { b } ], + BoxData @ PaneBox[ + alignTable[ ToBoxes @ textTableForm[ { c }, TableHeadings -> { None, formatRaw /@ a } ], { b } ], + ImageMargins -> { { 0, 0 }, { 5, 5 } } + ], "TextTableForm" ]; @@ -500,7 +653,7 @@ floatingButtonGrid[ attached_, cell_, lang_ ] := RawBoxes @ TemplateBox[ { ToBoxes @ Grid[ { - { + checkTemplateBoxes @ { button[ evaluateLanguageLabel @ lang, insertCodeBelow[ cell, True ]; NotebookDelete @ attached ], button[ $insertInputButtonLabel, insertCodeBelow[ cell, False ]; NotebookDelete @ attached ], button[ $copyToClipboardButtonLabel, copyCode @ cell; NotebookDelete @ attached ] @@ -519,7 +672,7 @@ floatingButtonGrid[ string_, lang_ ] := RawBoxes @ TemplateBox[ { ToBoxes @ Grid[ { - { + checkTemplateBoxes @ { button[ evaluateLanguageLabel @ lang, insertCodeBelow[ string, True ] ], button[ $insertInputButtonLabel, insertCodeBelow[ string, False ] ], button[ $copyToClipboardButtonLabel, CopyToClipboard @ string ] @@ -535,6 +688,15 @@ floatingButtonGrid[ string_, lang_ ] := RawBoxes @ TemplateBox[ floatingButtonGrid // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*checkTemplateBoxes*) +checkTemplateBoxes // beginDefinition; +checkTemplateBoxes[ boxes_ ] := checkTemplateBoxes[ boxes, $InlineChat ]; +checkTemplateBoxes[ boxes_, True ] := checkTemplateBoxes[ Verbatim @ boxes, True ] = inlineTemplateBoxes @ boxes; +checkTemplateBoxes[ boxes_, _ ] := boxes; +checkTemplateBoxes // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*evaluateLanguageLabel*) @@ -542,7 +704,7 @@ evaluateLanguageLabel[ name_String ] := With[ { icon = $languageIcons @ name }, fancyTooltip[ MouseAppearance[ buttonMouseover[ buttonFrameDefault @ icon, buttonFrameActive @ icon ], "LinkHand" ], - "Insert content as new input cell below and evaluate" + tr[ "FormattingInsertContentAndEvaluateTooltip" ] ] /; MatchQ[ icon, _Graphics | _Image ] ]; @@ -568,7 +730,7 @@ $copyToClipboardButtonLabel := $copyToClipboardButtonLabel = fancyTooltip[ ], "LinkHand" ], - "Copy to clipboard" + tr[ "FormattingCopyToClipboardTooltip" ] ]; (* ::**************************************************************************************************************:: *) @@ -582,7 +744,7 @@ $insertInputButtonLabel := $insertInputButtonLabel = fancyTooltip[ ], "LinkHand" ], - "Insert content as new input cell below" + tr[ "FormattingInsertContentTooltip" ] ]; (* ::**************************************************************************************************************:: *) @@ -596,7 +758,7 @@ $insertEvaluateButtonLabel := $insertEvaluateButtonLabel = fancyTooltip[ ], "LinkHand" ], - "Insert content as new input cell below and evaluate" + tr[ "FormattingInsertContentAndEvaluateTooltip" ] ]; (* ::**************************************************************************************************************:: *) @@ -611,13 +773,17 @@ insertCodeBelow // beginDefinition; insertCodeBelow[ code_ ] := insertCodeBelow[ code, False ]; insertCodeBelow[ cell_CellObject, evaluate_ ] := - insertCodeBelow[ getCodeBlockContent @ cell, evaluate ]; + If[ TrueQ @ CurrentChatSettings[ cell, "WorkspaceChat" ], + insertCodeInUserNotebook[ parentNotebook @ cell, getCodeBlockContent @ cell, evaluate ], + insertCodeBelow[ getCodeBlockContent @ cell, evaluate ] + ]; insertCodeBelow[ cell_Cell, evaluate_ ] := Module[ { cellObj, nbo }, cellObj = topParentCell @ EvaluationCell[ ]; - nbo = parentNotebook @ cellObj; + nbo = parentNotebook @ cellObj; insertAfterChatGeneratedCells[ cellObj, cell ]; + NotebookDelete @ Cells[ nbo, AttachedCell -> True, CellStyle -> "AttachedChatInput" ]; If[ TrueQ @ evaluate, selectionEvaluateCreateCell @ nbo, SelectionMove[ nbo, After, CellContents ] @@ -629,6 +795,57 @@ insertCodeBelow[ string_String, evaluate_ ] := insertCodeBelow // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*insertCodeInUserNotebook*) +insertCodeInUserNotebook // beginDefinition; + +insertCodeInUserNotebook[ chatNB_NotebookObject, cell_Cell, evaluate_ ] := Enclose[ + Module[ { nbo, cellObj }, + nbo = ConfirmMatch[ getNotebookForCodeInsertion @ chatNB, _NotebookObject, "UserNotebook" ]; + cellObj = ConfirmMatch[ getLastSelectedCell @ nbo, _CellObject|None, "SelectedCell" ]; + + If[ cellObj === None + , + SelectionMove[ nbo, After, Cell, AutoScroll -> True ]; + NotebookWrite[ nbo, preprocessInsertedCell @ cell, All ] + , + insertAfterChatGeneratedCells[ cellObj, cell ] + ]; + + SetSelectedNotebook @ nbo; + + If[ TrueQ @ evaluate, + selectionEvaluateCreateCell @ nbo, + SelectionMove[ nbo, After, CellContents ] + ] + ], + throwInternalFailure +]; + +insertCodeInUserNotebook[ chatNB_NotebookObject, code_String, evaluate_ ] := + insertCodeInUserNotebook[ chatNB, reparseCodeBoxes @ Cell[ BoxData @ code, "Input" ], evaluate ]; + +insertCodeInUserNotebook // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*getNotebookForCodeInsertion*) +getNotebookForCodeInsertion // beginDefinition; +getNotebookForCodeInsertion[ chatNB_NotebookObject ] := getNotebookForCodeInsertion[ chatNB, getUserNotebook @ chatNB ]; +getNotebookForCodeInsertion[ _, userNB_NotebookObject ] := userNB; +getNotebookForCodeInsertion[ _, None ] := CreateNotebook[ ]; +getNotebookForCodeInsertion // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*getLastSelectedCell*) +getLastSelectedCell // beginDefinition; +getLastSelectedCell[ nbo_NotebookObject ] := getLastSelectedCell @ SelectedCells @ nbo; +getLastSelectedCell[ { ___, cell_CellObject } ] := cell; +getLastSelectedCell[ _ ] := None; +getLastSelectedCell // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*insertAfterChatGeneratedCells*) @@ -652,20 +869,33 @@ insertAfterChatGeneratedCells[ cellObj_CellObject, cell_Cell ] /; $cloudNotebook ]; insertAfterChatGeneratedCells[ cellObj_CellObject, cell_Cell ] := Enclose[ - Module[ { nbo, allCells, cellsAfter, tagged, inserted, insertionPoint }, + Module[ { nbo, allCells, cellsAfter, taggedQ, tagged, generated, skip, skipped, insertionPoint }, - nbo = ConfirmMatch[ parentNotebook @ cellObj, _NotebookObject, "ParentNotebook" ]; - allCells = ConfirmMatch[ Cells @ nbo, { __CellObject }, "AllCells" ]; + nbo = ConfirmMatch[ parentNotebook @ cellObj, _NotebookObject, "ParentNotebook" ]; + allCells = ConfirmMatch[ Cells @ nbo, { __CellObject }, "AllCells" ]; cellsAfter = Replace[ allCells, { { ___, cellObj, after___ } :> { after }, _ :> { } } ]; + taggedQ = MemberQ[ Flatten @ List @ #, $chatGeneratedCellTag ] &; tagged = ConfirmBy[ - AssociationThread[ cellsAfter -> Flatten @* List /@ CurrentValue[ cellsAfter, CellTags ] ], + AssociationThread[ cellsAfter -> taggedQ /@ CurrentValue[ cellsAfter, CellTags ] ], AssociationQ, "Tagged" ]; - inserted = ConfirmBy[ TakeWhile[ tagged, MemberQ[ $chatGeneratedCellTag ] ], AssociationQ, "Inserted" ]; - insertionPoint = ConfirmMatch[ Last[ Keys @ inserted, cellObj ], _CellObject, "InsertionPoint" ]; + generated = ConfirmBy[ + AssociationThread[ cellsAfter -> CurrentValue[ cellsAfter, GeneratedCell ] ], + AssociationQ, + "Generated" + ]; + + skip = ConfirmBy[ + Merge[ { tagged, generated }, Apply @ Or ], + AssociationQ, + "Skip" + ]; + + skipped = ConfirmBy[ TakeWhile[ skip, TrueQ ], AssociationQ, "Inserted" ]; + insertionPoint = ConfirmMatch[ Last[ Keys @ skipped, cellObj ], _CellObject, "InsertionPoint" ]; SelectionMove[ insertionPoint, After, Cell ]; NotebookWrite[ nbo, preprocessInsertedCell @ cell, All ]; @@ -747,7 +977,7 @@ getCodeBlockContent // endDefinition; reparseCodeBoxes // beginDefinition; reparseCodeBoxes[ Cell[ BoxData[ s_String ], a___ ] ] /; $cloudNotebooks := - Cell[ BoxData @ UsingFrontEnd @ stringToBoxes @ s, a ]; + Cell[ BoxData @ usingFrontEnd @ stringToBoxes @ s, a ]; reparseCodeBoxes[ cell_Cell ] := cell; @@ -831,10 +1061,12 @@ fancyTooltip[ expr_, tooltip_ ] := Tooltip[ (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Parsing Rules*) + +(* cSpell: ignore ENDRESULT *) $$endToolCall = Longest[ "ENDRESULT" ~~ (("(" ~~ (LetterCharacter|DigitCharacter).. ~~ ")") | "") ]; $$eol = " "... ~~ "\n"; -$$cmd = Repeated[ DigitCharacter|LetterCharacter|"_"|"$", { 1, 80 } ]; -$$simpleToolCommand = StartOfLine ~~ ("/" ~~ c: $$cmd) ~~ $$eol /; $simpleToolMethod && toolShortNameQ @ c; +$$cmd = Repeated[ Except[ WhitespaceCharacter ], { 1, 80 } ]; +$$simpleToolCommand = StartOfLine ~~ $$ws ~~ ("/" ~~ c: $$cmd) ~~ $$eol /; $simpleToolMethod && toolShortNameQ @ c; $$simpleToolCall = Shortest[ $$simpleToolCommand ~~ ___ ~~ ($$endToolCall|EndOfString) ]; @@ -846,6 +1078,8 @@ $$simpleToolCall = Shortest[ $$simpleToolCommand ~~ ___ ~~ ($$endToolCall|End (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*$textDataFormatRules*) + +(* cSpell: ignore TOOLCALL *) $textDataFormatRules = { StringExpression[ Longest[ "```" ~~ language: Except[ "\n" ]... ] ~~ (" "...) ~~ "\n", @@ -862,20 +1096,22 @@ $textDataFormatRules = { , tool: $$simpleToolCall :> inlineToolCallCell @ tool , - ("\n"|StartOfString) ~~ w:" "... ~~ "* " ~~ item: Longest[ Except[ "\n" ].. ] :> bulletCell[ w, item ], - ("\n"|StartOfString) ~~ h:"#".. ~~ " " ~~ sec: Longest[ Except[ "\n" ].. ] :> sectionCell[ StringLength @ h, sec ], + StartOfLine ~~ "/retry" ~~ (WhitespaceCharacter|EndOfString) :> $discardPreviousToolCall + , + ("\n"|StartOfString).. ~~ w:" "... ~~ ("* "|"- ") ~~ item: Longest[ Except[ "\n" ].. ] :> + bulletCell[ w, item ] + , + ("\n"|StartOfString).. ~~ h:"#".. ~~ " " ~~ sec: Longest[ Except[ "\n" ].. ] :> + sectionCell[ StringLength @ h, sec ] + , + $$delimiter :> delimiterCell[ ] + , table: $$mdTable :> tableCell @ table , + quote: $$blockQuote :> blockQuoteCell @ quote + , "[`" ~~ label: Except[ "[" ].. ~~ "`](" ~~ url: Except[ ")" ].. ~~ ")" :> "[" <> label <> "]("<>url<>")", - (* Escaped markdown characters: *) - "\\`" :> "`", - "\\$" :> "$", - "\\*" :> "*", - "\\_" :> "_", - "\\#" :> "#", - "\\|" :> "|", - "``" ~~ code__ ~~ "``" /; StringFreeQ[ code, "``" ] :> inlineCodeCell @ code, "`" ~~ code: Except[ WhitespaceCharacter ].. ~~ "`" /; inlineSyntaxQ @ code :> inlineCodeCell @ code, "`" ~~ code: Except[ "`"|"\n" ].. ~~ "`" :> inlineCodeCell @ code, @@ -936,12 +1172,36 @@ $stringFormatRules = { "__" ~~ text: Except[ "_" ].. ~~ "__" /; StringFreeQ[ text, "\n" ] :> styleBox[ text, FontWeight -> Bold ], + "~~" ~~ text: Except[ "~" ].. ~~ "~~" /; StringFreeQ[ text, "\n" ] :> + styleBox[ text, FontVariations -> { "StrikeThrough" -> True } ], + + "``" ~~ code__ ~~ "``" /; StringFreeQ[ code, "``" ] :> + makeResultCell @ inlineCodeCell @ code, + + "`" ~~ code: Except[ WhitespaceCharacter ].. ~~ "`" /; inlineSyntaxQ @ code :> + makeResultCell @ inlineCodeCell @ code, + + "`" ~~ code: Except[ "`"|"\n" ].. ~~ "`" :> + makeResultCell @ inlineCodeCell @ code, + "*" ~~ text: Except[ "*" ].. ~~ "*" /; StringFreeQ[ text, "\n" ] :> styleBox[ text, FontSlant -> Italic ], "_" ~~ text: Except[ "_" ].. ~~ "_" /; StringFreeQ[ text, "\n" ] :> styleBox[ text, FontSlant -> Italic ], + "$$" ~~ math__ ~~ "$$" /; StringFreeQ[ math, "$$" ] :> + makeResultCell @ mathCell @ math, + + "\\(" ~~ math__ ~~ "\\)" /; StringFreeQ[ math, "\\)" ] :> + makeResultCell @ mathCell @ math, + + "\\[" ~~ math__ ~~ "\\]" /; StringFreeQ[ math, "\\]" ] :> + makeResultCell @ mathCell @ math, + + "$" ~~ math: Except[ "$" ].. ~~ "$" /; probablyMathQ @ math :> + makeResultCell @ mathCell @ math, + "[" ~~ label: Except[ "[" ].. ~~ "](" ~~ url: Except[ ")" ].. ~~ ")" :> hyperlink[ label, url ], @@ -1032,12 +1292,14 @@ parseToolCallString // endDefinition; (*parsePartialToolCallString*) parsePartialToolCallString // beginDefinition; +(* TODO: define a `parsePartialSimpleToolCallString` that can also be used in `simpleToolRequestParser` *) + parsePartialToolCallString[ string_String ] /; $simpleToolMethod := Enclose[ Module[ { command, argString, tool, name, paramNames, argStrings, padded, params, result }, command = ConfirmBy[ StringReplace[ string, - StartOfString ~~ "/" ~~ cmd: LetterCharacter.. ~~ WhitespaceCharacter... ~~ "\n" ~~ ___ :> cmd + StartOfString ~~ $$ws ~~ ("/" ~~ cmd: $$cmd) ~~ $$eol ~~ ___ :> cmd ], toolShortNameQ, "Command" @@ -1046,8 +1308,16 @@ parsePartialToolCallString[ string_String ] /; $simpleToolMethod := Enclose[ argString = First[ StringCases[ string, - StartOfString ~~ "/" ~~ command ~~ WhitespaceCharacter... ~~ "\n" ~~ a___ ~~ ("/exec"|EndOfString) :> - a, + Shortest @ StringExpression[ + StartOfString, + $$ws, + "/", + command, + WhitespaceCharacter..., + "\n", + a___, + "/exec"|EndOfString + ] :> a, 1 ], Missing[ ] @@ -1057,10 +1327,12 @@ parsePartialToolCallString[ string_String ] /; $simpleToolMethod := Enclose[ name = ConfirmBy[ toolName @ tool, StringQ, "ToolName" ]; If[ StringQ @ argString, - paramNames = Keys @ ConfirmMatch[ tool[[ 1, "Parameters" ]], KeyValuePattern @ { }, "ParameterNames" ]; - argStrings = If[ Length @ paramNames === 1, { argString }, StringSplit[ argString, "\n" ] ]; - padded = PadRight[ argStrings, Length @ paramNames, "" ]; - params = ConfirmBy[ AssociationThread[ paramNames -> padded ], AssociationQ, "Parameters" ] + paramNames = Keys @ ConfirmMatch[ tool[ "Parameters" ], KeyValuePattern @ { }, "ParameterNames" ]; + params = ConfirmBy[ + parseSimpleToolCallParameterStrings[ paramNames, argString ], + AssociationQ, + "Parameters" + ] , params = <| |> ]; @@ -1113,7 +1385,6 @@ parseFullToolCallString // beginDefinition; parseFullToolCallString[ id_String, string_String ] := parseFullToolCallString[ id, $toolEvaluationResults[ id ], string ]; -(* FIXME: handle simple syntax too *) parseFullToolCallString[ id_, _Missing, string_String ] := parsePartialToolCallString @ string; @@ -1132,7 +1403,7 @@ parseFullToolCallString[ id_String, resp: HoldPattern[ _LLMToolResponse ], strin parseFullToolCallString[ id_String, tool: HoldPattern[ _LLMTool ], parameters_Association, output_, string_ ] := $lastFullParsed = <| "ID" -> id, - "Name" -> toolName[tool], + "Name" -> toolName @ tool, "DisplayName" -> getToolDisplayName @ tool, "Icon" -> getToolIcon @ tool, "FormattingFunction" -> getToolFormattingFunction @ tool, @@ -1158,7 +1429,7 @@ parseToolCallID[ string_String? StringQ ] := WhitespaceCharacter..., Alternatives[ "TOOLCALL:", - StartOfLine ~~ "/" ~~ cmd: LetterCharacter.. ~~ WhitespaceCharacter... ~~ "\n" /; + StartOfLine ~~ "/" ~~ cmd: Except[ WhitespaceCharacter ].. ~~ WhitespaceCharacter... ~~ "\n" /; toolShortNameQ @ cmd ], ___, @@ -1237,7 +1508,7 @@ makeToolCallBoxLabel0[ KeyValuePattern[ "Result" -> "" ], string_String, icon_ ] If[ MissingQ @ icon, Nothing, { - Spacer[ 5 ], + Spacer[ 0 ], toolCallIconPane @ icon } ] @@ -1249,7 +1520,7 @@ makeToolCallBoxLabel0[ as_, string_String, icon_ ] := Row @ Flatten @ { If[ MissingQ @ icon, Nothing, { - Spacer[ 5 ], + Spacer[ 0 ], toolCallIconPane @ icon } ] @@ -1378,11 +1649,11 @@ resolveToolFormatter[ as_Association ] := Append[ as, "FormattingFunction" -> re resolveToolFormatter // endDefinition; resolveToolFormatter0 // beginDefinition; -resolveToolFormatter0[ KeyValuePattern[ "FormattingFunction" -> f_ ] ] := resolveToolFormatter0 @ f; -resolveToolFormatter0[ Automatic ] := clickToCopy[ #1 ] &; -resolveToolFormatter0[ Inherited ] := toolAutoFormatter; -resolveToolFormatter0[ None ] := #1 &; -resolveToolFormatter0[ f_ ] := f; +resolveToolFormatter0[ as_Association ] := resolveToolFormatter0 @ Lookup[ as, "FormattingFunction", Inherited ]; +resolveToolFormatter0[ Automatic ] := clickToCopy[ #1 ] &; +resolveToolFormatter0[ Inherited ] := toolAutoFormatter; +resolveToolFormatter0[ None ] := #1 &; +resolveToolFormatter0[ f_ ] := f; resolveToolFormatter0 // endDefinition; (* ::**************************************************************************************************************:: *) @@ -1405,15 +1676,6 @@ toolAutoFormatter[ result_, ___ ] := result; toolAutoFormatter // endDefinition; -(* ::**************************************************************************************************************:: *) -(* ::Subsubsubsection::Closed:: *) -(*clickToCopy*) -clickToCopy // beginDefinition; -clickToCopy[ ClickToCopy[ args__ ] ] := clickToCopy @ args; -clickToCopy[ HoldForm[ expr_ ], a___ ] := clickToCopy[ Defer @ expr, a ]; -clickToCopy[ expr_, a___ ] := Grid[ { { ClickToCopy[ expr, a ], "" } }, Spacings -> 0, BaseStyle -> "Text" ]; -clickToCopy // endDefinition; - (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*makeToolCallOutputSection*) @@ -1722,6 +1984,9 @@ codeBlockFrame // endDefinition; styleBox // beginDefinition; styleBox[ text_String, a___ ] := styleBox[ formatTextString @ text, a ]; +styleBox[ { link: Cell @ BoxData[ TemplateBox[ { _, ___ }, "TextRefLink", ___ ], ___ ] }, ___ ] := link; +styleBox[ { text_String } ] := text; +styleBox[ { StyleBox[ text_ ], a___ } ] := styleBox @ { text, a }; styleBox[ { text: _ButtonBox|_String }, a___ ] := StyleBox[ text, a ]; styleBox[ { StyleBox[ text_, a___ ] }, b___ ] := DeleteDuplicates @ StyleBox[ text, a, b ]; styleBox[ { Cell[ text_, a___ ] }, b___ ] := DeleteDuplicates @ Cell[ text, a, b ]; @@ -1746,20 +2011,54 @@ image[ alt_String, url_String ] := Enclose[ keys = ConfirmMatch[ Keys @ $attachments, { ___String? StringQ }, "Keys" ]; key = SelectFirst[ keys, StringContainsQ[ url, #1, IgnoreCase -> True ] & ]; If[ StringQ @ key, - attachment[ alt, key ], - image[ alt, url, URLParse @ url ] + Cell[ + BoxData @ markdownImageBoxes[ + alt, + key, + Replace[ $attachments[ key ], HoldComplete[ expr_ ] :> expr ] + ], + Background -> None + ], + image[ alt, url, urlParse @ url ] ] ], - throwInternalFailure[ image[ alt, url ], ## ] & + throwInternalFailure ]; image[ alt_, url_, KeyValuePattern @ { "Scheme" -> "attachment"|"expression", "Domain" -> key_String } ] := attachment[ alt, key ]; -image[ alt_, url_, _ ] := importedImage[ alt, url ]; +image[ alt_, url_, KeyValuePattern @ { "Scheme" -> "file", "Path" -> path_String } ] := + importedImage[ alt, path ]; + +image[ alt_, url_, _ ] := + importedImage[ alt, url ]; image // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*urlParse*) +urlParse // beginDefinition; +urlParse[ url_String ] := With[ { parsed = localParse @ url }, parsed /; AssociationQ @ parsed ]; +urlParse[ url_String ] := URLParse @ url; +urlParse // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*localParse*) +localParse // beginDefinition; + +localParse[ uri_String ] /; StringStartsQ[ uri, ("attachment"|"file")~~"://" ] := + With[ { path = StringDelete[ uri, StartOfString ~~ ("attachment"|"file") ~~ "://" ] }, + <| "Scheme" -> "file", "Path" -> path |> /; FileExistsQ @ path + ]; + +localParse[ uri_String ] := + Missing[ "NotAvailable" ]; + +localParse // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*attachment*) @@ -1801,18 +2100,24 @@ attachmentBoxes // endDefinition; (*markdownImageBoxes*) markdownImageBoxes // beginDefinition; -markdownImageBoxes[ "", url_String, expr_ ] := TagBox[ - cachedBoxes @ expr, - "MarkdownImage", - AutoDelete -> True, - TaggingRules -> <| "CellToStringData" -> "![]("<>url<>")" |> +markdownImageBoxes[ "", url_String, expr_ ] := PaneBox[ + TagBox[ + cachedBoxes @ expr, + "MarkdownImage", + AutoDelete -> True, + TaggingRules -> <| "CellToStringData" -> "![]("<>url<>")" |> + ], + ImageMargins -> { { 0, 0 }, { 10, 10 } } ]; -markdownImageBoxes[ alt_String, url_String, expr_ ] := TagBox[ - TooltipBox[ cachedBoxes @ expr, ToString[ alt, InputForm ] ], - "MarkdownImage", - AutoDelete -> True, - TaggingRules -> <| "CellToStringData" -> "!["<>alt<>"]("<>url<>")" |> +markdownImageBoxes[ alt_String, url_String, expr_ ] := PaneBox[ + TagBox[ + TooltipBox[ cachedBoxes @ expr, ToString[ alt, InputForm ] ], + "MarkdownImage", + AutoDelete -> True, + TaggingRules -> <| "CellToStringData" -> "!["<>alt<>"]("<>url<>")" |> + ], + ImageMargins -> { { 0, 0 }, { 10, 10 } } ]; markdownImageBoxes // endDefinition; @@ -1839,9 +2144,23 @@ $missingImage = RawBoxes @ TemplateBox[ { }, "ImageNotFound" ]; (* ::Subsubsubsection::Closed:: *) (*importImage*) importImage // beginDefinition; -importImage[ url_String ] := importImage[ url ] = Quiet @ Import[ url, "Image" ]; +importImage[ url_String ] := importImage[ url ] = importImage0 @ url; importImage // endDefinition; +importImage0 // beginDefinition; +importImage0[ url_String ] := importImage0[ url, Quiet @ Import[ url, "Image" ] ]; +importImage0[ url_, image_Image ] := image; +importImage0[ url_String? cloudURLQ, _? FailureQ ] := Quiet @ Import[ CloudObject @ url, "Image" ]; +importImage0[ _, failed_ ] := failed; +importImage0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*cloudURLQ*) +cloudURLQ // beginDefinition; +cloudURLQ[ url_String ] := URLParse[ url, "Domain" ] === URLParse[ $CloudBase, "Domain" ]; +cloudURLQ // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*tooltip*) @@ -1871,7 +2190,7 @@ resizeImage0[ img_Image? ImageQ, dims: { _Integer, _Integer } ] /; Max @ dims > showResized @ ImageResize[ img, { UpTo @ $maxImageSize, UpTo @ $maxImageSize } ]; resizeImage0[ img_Image? ImageQ, dims: { _Integer, _Integer } ] := - Show[ img, ImageSize -> dims / 2 ]; + Show[ img, Options[ img, ImageSize ] ]; resizeImage0[ other_ ] := other; @@ -1899,11 +2218,144 @@ targetImageSize // endDefinition; (* ::Subsubsection::Closed:: *) (*cachedBoxes*) cachedBoxes // beginDefinition; -cachedBoxes[ e_ ] := With[ { h = Hash @ Unevaluated @ e }, Lookup[ $boxCache, h, $boxCache[ h ] = MakeBoxes @ e ] ]; + +cachedBoxes[ e_ ] := + With[ { h = Hash @ Unevaluated @ e }, + Lookup[ $boxCache, h, $boxCache[ h ] = checkBoxes @ MakeBoxes @ e ] + ]; + cachedBoxes // endDefinition; $boxCache = <| |>; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*checkBoxes*) +checkBoxes // beginDefinition; +checkBoxes[ e_ ] /; $CloudEvaluation && ! FreeQ[ e, _RasterBox ] := embeddedHTMLBoxes @ e; +checkBoxes[ e_ ] := e; +checkBoxes // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*embeddedHTMLBoxes*) +embeddedHTMLBoxes // beginDefinition; + +embeddedHTMLBoxes[ boxes_ ] := Enclose[ + Module[ { id, dynamic }, + id = ConfirmBy[ createBoxCacheReference @ boxes, IntegerQ, "ID" ]; + + dynamic = With[ { id = id, missing = $missingImage, waiting = $waiting }, + DynamicModule[ { b64, display }, + Dynamic @ Replace[ display, Except[ _RawBoxes ] -> waiting ], + Initialization :> ( + If[ TrueQ @ $dynamicText, + Null, + If[ ! StringQ @ b64, b64 = getBase64 @ id ]; + display = Replace[ displayBase64Boxes @ b64, Except[ _RawBoxes ] :> missing ] + ] + ), + SynchronousInitialization -> False, + UnsavedVariables :> { display } + ] + ]; + + TagBox[ ToBoxes @ dynamic, "DynamicEmbeddedHTMLBoxes" ] + ], + throwInternalFailure +]; + +embeddedHTMLBoxes // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*createBoxCacheReference*) +createBoxCacheReference // beginDefinition; +createBoxCacheReference[ boxes_ ] := With[ { id = Hash @ boxes }, $boxQueueCache[ id ] = boxes; id ]; +createBoxCacheReference // endDefinition; + +$boxQueueCache = <| |>; +$base64Cache = <| |>; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*getBase64*) +getBase64 // beginDefinition; + +getBase64[ id_ ] := getBase64[ id, $base64Cache[ id ] ]; +getBase64[ id_, b64_String ] := b64; +getBase64[ id_, m_Missing ] := getBase64[ id, m, $boxQueueCache[ id ] ]; +getBase64[ id_, _, _Missing ] := Missing[ "NotAvailable" ]; + +getBase64[ id_, _, boxes_ ] := + With[ { b64 = BaseEncode @ BinarySerialize[ RawBoxes @ boxes, PerformanceGoal -> "Size" ] }, + $base64Cache[ id ] = b64; + KeyDropFrom[ $boxQueueCache, id ]; + b64 + ]; + +getBase64 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*displayBase64Boxes*) +displayBase64Boxes // beginDefinition; + +displayBase64Boxes[ b64_String ] /; $dynamicText := $waiting; + +displayBase64Boxes[ b64_String ] := Enclose[ + Module[ { bytes, boxes, display }, + bytes = ConfirmBy[ BaseDecode @ b64, ByteArrayQ, "Bytes" ]; + boxes = ConfirmMatch[ BinaryDeserialize @ bytes, _RawBoxes, "Boxes" ]; + display = If[ TrueQ @ $CloudEvaluation, cloudEmbeddedHTMLImage @ boxes, boxes ]; + displayBase64Boxes[ b64 ] = ConfirmMatch[ display, _RawBoxes, "Display" ] + ], + throwInternalFailure +]; + +displayBase64Boxes[ _ ] := $waiting; + +displayBase64Boxes // endDefinition; + + +$waiting := $waiting = RawBoxes @ ToBoxes @ Panel[ + ProgressIndicator[ Appearance -> "Necklace" ], + ImageSize -> { 150, 150 }, + Alignment -> { Center, Center } +]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*cloudEmbeddedHTMLImage*) +cloudEmbeddedHTMLImage // beginDefinition; + +cloudEmbeddedHTMLImage[ expr_ ] := Enclose[ + usingFrontEnd @ Module[ { raster, size, resized, b64, width, height, embedSize, html, boxes }, + + raster = ConfirmBy[ rasterize[ expr, ImageResolution -> 144 ], image2DQ, "Raster" ]; + size = Max @ ConfirmMatch[ ImageDimensions @ raster, { _, _ }, "OriginalDimensions" ]; + resized = If[ size > 1000, ImageResize[ raster, { UpTo[ 1000 ], UpTo[ 1000 ] } ], raster ]; + b64 = ConfirmBy[ exportDataURI[ resized, "JPEG" ], StringQ, "Base64" ]; + { width, height } = Round[ ConfirmMatch[ ImageDimensions @ resized, { _, _ }, "Dimensions" ] / 2 ]; + embedSize = { width, height + 12 }; + + html = ConfirmBy[ + TemplateApply[ $embeddedImageTemplate, { b64, width, height } ], + StringQ, + "HTML" + ]; + + boxes = ToBoxes @ EmbeddedHTML[ html, ImageSize -> embedSize ]; + RawBoxes @ TagBox[ boxes, "CloudEmbeddedHTMLImage" ] + ], + throwInternalFailure +]; + +cloudEmbeddedHTMLImage // endDefinition; + + +$embeddedImageTemplate = "
"; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*hyperlink*) @@ -1988,7 +2440,7 @@ $languageIcons := $languageIcons = Enclose[ joinAdjacentStrings // beginDefinition; joinAdjacentStrings[ { content___, "\n"|StyleBox[ "\n", ___ ] } ] := joinAdjacentStrings @ { content }; joinAdjacentStrings[ { "\n"|StyleBox[ "\n", ___ ], content___ } ] := joinAdjacentStrings @ { content }; -joinAdjacentStrings[ content_List ] := joinAdjacentStrings0 /@ SplitBy[ content, StringQ ]; +joinAdjacentStrings[ content_List ] := trimWhitespace[ joinAdjacentStrings0 /@ SplitBy[ content, StringQ ] ]; joinAdjacentStrings // endDefinition; joinAdjacentStrings0 // beginDefinition; @@ -2000,6 +2452,43 @@ joinAdjacentStrings0[ { other___ } ] := other; joinAdjacentStrings0 // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*trimWhitespace*) +trimWhitespace // beginDefinition; +trimWhitespace[ { } ] := { }; +trimWhitespace[ { a_, b___, c_ } ] := { trimWhitespaceL @ a, b, trimWhitespaceR @ c }; +trimWhitespace[ { a_ } ] := { trimWhitespaceB @ a }; +trimWhitespace // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*trimWhitespaceB*) +trimWhitespaceB // beginDefinition; +trimWhitespaceB[ a_String ] := StringTrim @ a; +trimWhitespaceB[ other_ ] := trimWhitespaceR @ trimWhitespaceL @ other; +trimWhitespaceB // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*trimWhitespaceL*) +trimWhitespaceL // beginDefinition; +trimWhitespaceL[ a_String ] := StringDelete[ a, StartOfString ~~ WhitespaceCharacter.. ]; +trimWhitespaceL[ (h: Cell|StyleBox|TextData|BoxData)[ a_, b___ ] ] := h[ trimWhitespaceL @ a, b ]; +trimWhitespaceL[ { a_, b___ } ] := { trimWhitespaceL @ a, b }; +trimWhitespaceL[ other_ ] := other; +trimWhitespaceL // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*trimWhitespaceR*) +trimWhitespaceR // beginDefinition; +trimWhitespaceR[ a_String ] := StringDelete[ a, WhitespaceCharacter.. ~~ EndOfString ]; +trimWhitespaceR[ (h: Cell|StyleBox|TextData|BoxData)[ a_, b___ ] ] := h[ trimWhitespaceR @ a, b ]; +trimWhitespaceR[ { a___, b_ } ] := { a, trimWhitespaceR @ b }; +trimWhitespaceR[ other_ ] := other; +trimWhitespaceR // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*nameQ*) @@ -2045,10 +2534,33 @@ stringToBoxes[ s_String ] /; $dynamicText := StringReplace[ ]; stringToBoxes[ s_String ] := - adjustBoxSpacing @ MathLink`CallFrontEnd @ FrontEnd`ReparseBoxStructurePacket @ s; + adjustBoxSpacing @ stringToBoxes0 @ usingFrontEnd @ MathLink`CallFrontEnd @ FrontEnd`ReparseBoxStructurePacket @ s; stringToBoxes // endDefinition; + +stringToBoxes0 // beginDefinition; +stringToBoxes0[ RowBox @ { a___, b: "\n"|"\[IndentingNewLine]", c___ } ] := stringToBoxes0 @ { a, b, c }; +stringToBoxes0[ boxes_? boxDataQ ] := boxes; +stringToBoxes0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*boxDataQ*) +boxDataQ // beginDefinition; +boxDataQ[ _String? StringQ ] := True; +boxDataQ[ boxes_List ] := AllTrue[ boxes, boxDataQ ]; +boxDataQ[ (_? boxSymbolQ)[ ___ ] ] := True; +boxDataQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*boxSymbolQ*) +boxSymbolQ // beginDefinition; +boxSymbolQ[ RowBox ] := True; +boxSymbolQ[ s_Symbol ] := boxSymbolQ[ s ] = Context @ s === "System`" && StringEndsQ[ SymbolName @ s, "Box" ]; +boxSymbolQ // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*adjustBoxSpacing*) @@ -2060,14 +2572,65 @@ adjustBoxSpacing[ s_String ] /; $CloudEvaluation := Lookup[ $autoOperatorRenderi adjustBoxSpacing[ box_ ] := box; adjustBoxSpacing // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Alternate Chat Mode Styles*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*Template Boxes*) +$userMessageBoxTemplate := $userMessageBoxTemplate = + Function @ Evaluate @ inlineTemplateBox @ TemplateBox[ { # }, "UserMessageBox" ]; + +$assistantMessageBoxTemplate := $assistantMessageBoxTemplate = + Function @ Evaluate @ inlineTemplateBox @ TemplateBox[ { # }, "AssistantMessageBox" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*assistantMessageBox*) +assistantMessageBox // beginDefinition; + +assistantMessageBox[ box_ ] := + assistantMessageBox[ box, $InlineChat ]; + +assistantMessageBox[ box_, True ] := + With[ { template = $assistantMessageBoxTemplate @ box }, + template /; MatchQ[ template, TemplateBox[ __, DisplayFunction -> _, ___ ] ] + ]; + +assistantMessageBox[ box_, Except[ True ] ] := + TemplateBox[ { box }, "AssistantMessageBox" ]; + +assistantMessageBox // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*userMessageBox*) +userMessageBox // beginDefinition; + +userMessageBox[ box_ ] := + userMessageBox[ box, $InlineChat ]; + +userMessageBox[ box_, True ] := + With[ { template = $userMessageBoxTemplate @ box }, + template /; MatchQ[ template, TemplateBox[ __, DisplayFunction -> _, ___ ] ] + ]; + +userMessageBox[ box_, Except[ True ] ] := + TemplateBox[ { box }, "UserMessageBox" ]; + +userMessageBox // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $copyToClipboardButtonLabel; $insertInputButtonLabel; $insertEvaluateButtonLabel; $languageIcons; + $userMessageBoxTemplate; + $assistantMessageBoxTemplate; ]; End[ ]; diff --git a/Source/Chatbook/FrontEnd.wl b/Source/Chatbook/FrontEnd.wl index cb733d8a..ab4f7a39 100644 --- a/Source/Chatbook/FrontEnd.wl +++ b/Source/Chatbook/FrontEnd.wl @@ -2,46 +2,10 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`FrontEnd`" ]; - -`$dialogInputAllowed; -`$feTaskWidgetCell; -`$inEpilog; -`$suppressButtonAppearance; -`cellInformation; -`cellObjectQ; -`cellOpenQ; -`cellPrint; -`cellPrintAfter; -`cellStyles; -`checkEvaluationCell; -`compressUntilViewed; -`createFETask; -`feParentObject; -`fixCloudCell; -`flushFETasks; -`getBoxObjectFromBoxID; -`initFETaskWidget; -`nextCell; -`notebookRead; -`openerView; -`parentCell; -`parentNotebook; -`previousCell; -`rasterize; -`replaceCellContext; -`rootEvaluationCell; -`selectionEvaluateCreateCell; -`toCompressedBoxes; -`topLevelCellQ; -`topParentCell; -`withNoRenderUpdates; - Begin[ "`Private`" ]; -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Settings`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -161,12 +125,14 @@ createFETask // Attributes = { HoldFirst }; createFETask[ eval_ ] /; $cloudNotebooks := eval; -createFETask[ eval_ ] := ( - If[ $feTaskDebug, Internal`StuffBag[ $feTaskLog, <| "Task" -> Hold @ eval, "Created" -> AbsoluteTime[ ] |> ] ]; - AppendTo[ $feTasks, Hold @ eval ]; - ++$feTaskCreationCount; - ++$feTaskTrigger -); +createFETask[ eval_ ] := + With[ { inline = $InlineChat, state = $inlineChatState }, + If[ $feTaskDebug, Internal`StuffBag[ $feTaskLog, <| "Task" -> Hold @ eval, "Created" -> AbsoluteTime[ ] |> ] ]; + (* FIXME: This Block is a bit of a hack: *) + AppendTo[ $feTasks, Hold @ Block[ { $InlineChat = inline, $inlineChatState = state }, eval ] ]; + ++$feTaskCreationCount; + ++$feTaskTrigger + ]; createFETask // endDefinition; @@ -224,6 +190,17 @@ feParentObject // endDefinition; (* ::Section::Closed:: *) (*Cells*) +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*$evaluationCell*) +$evaluationCell := + With[ { cell = EvaluationCell[ ] }, + If[ TrueQ[ $chatState && MatchQ[ cell, _CellObject ] ], + $evaluationCell = cell, + cell + ] + ]; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*cellObjectQ*) @@ -285,6 +262,9 @@ rootEvaluationCell[ source_, cells: { __CellObject } ] := throwInternalFailure @ rootEvaluationCell[ source, cells ] ]; + +rootEvaluationCell[ cell_CellObject, None ] := None; + rootEvaluationCell // endDefinition; (* ::**************************************************************************************************************:: *) @@ -300,26 +280,265 @@ cellEvaluatingQ // endDefinition; (*cellInformation*) cellInformation // beginDefinition; -cellInformation[ nbo_NotebookObject ] := cellInformation @ Cells @ nbo; +cellInformation[ nbo_NotebookObject, a___ ] := + cellInformation[ Cells @ nbo, a ]; + +cellInformation[ cells: { ___CellObject } ] := Select[ + Map[ + Association, + Transpose @ { + Developer`CellInformation @ cells, + Thread[ "CellObject" -> cells ], + Thread[ "CellAutoOverwrite" -> CurrentValue[ cells, CellAutoOverwrite ] ], + Thread[ "ChatNotebookSettings" -> AbsoluteCurrentValue[ cells, { TaggingRules, "ChatNotebookSettings" } ] ] + } + ], + AssociationQ +]; + +cellInformation[ cell_CellObject ] := + With[ { info = Association @ Developer`CellInformation @ cell }, + If[ AssociationQ @ info, + Association[ + info, + "CellObject" -> cell, + "CellAutoOverwrite" -> CurrentValue[ cell, CellAutoOverwrite ], + "ChatNotebookSettings" -> AbsoluteCurrentValue[ cell, { TaggingRules, "ChatNotebookSettings" } ] + ], + Missing[ "NotAvailable" ] + ] + ]; + +cellInformation[ cells: { ___CellObject }, key_String ] := + Replace[ + cellInformation @ cells, + as: KeyValuePattern @ { } :> Lookup[ as, key, Missing[ "NotAvailable" ] ], + { 1 } + ]; + +cellInformation[ cell_CellObject, key_String ] := + Replace[ + cellInformation @ cell, + as: KeyValuePattern @ { } :> Lookup[ as, key, Missing[ "NotAvailable" ] ] + ]; + +cellInformation[ cells: { ___CellObject }, keys: { ___String } ] := + Replace[ + cellInformation @ cells, + as: KeyValuePattern @ { } :> KeyTake[ as, keys ], + { 1 } + ]; + +cellInformation[ cell_CellObject, keys: { ___String } ] := + Replace[ + cellInformation @ cell, + as: KeyValuePattern @ { } :> KeyTake[ as, keys ] + ]; + +cellInformation // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*notebookInformation*) +notebookInformation // beginDefinition; + +notebookInformation[ ] := + notebookInformation @ Notebooks[ ]; + +notebookInformation[ All ] := + notebookInformation @ Notebooks[ ]; + +notebookInformation[ nbo_NotebookObject ] := Enclose[ + Catch @ Module[ { throwIfClosed, info, visible, windowClickSelect, selected, input, settings }, + + throwIfClosed = Replace[ Missing[ "NotebookClosed", ___ ] | $Failed :> Throw @ missingNotebook @ nbo ]; + + info = ConfirmMatch[ throwIfClosed @ notebookInformation0 @ nbo, _? AssociationQ, "Info" ]; + + visible = ConfirmMatch[ + throwIfClosed @ AbsoluteCurrentValue[ nbo, Visible ], + True|False|Inherited, + "Visible" + ]; + + windowClickSelect = ConfirmMatch[ + throwIfClosed @ AbsoluteCurrentValue[ nbo, WindowClickSelect ], + True|False|Inherited, + "WindowClickSelect" + ]; -cellInformation[ cells: { ___CellObject } ] := Map[ - Association, - Transpose @ { - Developer`CellInformation @ cells, - Thread[ "CellObject" -> cells ], - Thread[ "CellAutoOverwrite" -> CurrentValue[ cells, CellAutoOverwrite ] ], - Thread[ "ChatNotebookSettings" -> AbsoluteCurrentValue[ cells, { TaggingRules, "ChatNotebookSettings" } ] ] - } + selected = SelectedNotebook[ ] === nbo; + input = InputNotebook[ ] === nbo; + + settings = ConfirmBy[ + throwIfClosed @ Association @ Replace[ + AbsoluteCurrentValue[ nbo, { TaggingRules, "ChatNotebookSettings" } ], + Inherited :> AbsoluteCurrentValue[ $FrontEnd, { TaggingRules, "ChatNotebookSettings" } ] + ], + AssociationQ, + "Settings" + ]; + + ConfirmBy[ + KeySort @ DeleteMissing @ <| + "ChatNotebookSettings" -> settings, + "ID" -> tinyHash @ nbo, + "InputNotebook" -> TrueQ @ input, + "NotebookObject" -> nbo, + "SelectedNotebook" -> TrueQ @ selected, + "Visible" -> TrueQ @ visible, + "WindowClickSelect" -> TrueQ @ windowClickSelect, + info + |>, + AssociationQ, + "Result" + ] + ], + throwInternalFailure ]; -cellInformation[ cell_CellObject ] := Association[ - Developer`CellInformation @ cell, - "CellObject" -> cell, - "CellAutoOverwrite" -> CurrentValue[ cell, CellAutoOverwrite ], - "ChatNotebookSettings" -> AbsoluteCurrentValue[ cell, { TaggingRules, "ChatNotebookSettings" } ] +(* Definition that's optimized for listable FE calls: *) +notebookInformation[ notebooks_List ] := + notebooksInformation @ notebooks; + +notebookInformation // endDefinition; + + +notebookInformation0 // beginDefinition; + +notebookInformation0[ nbo_NotebookObject ] := Enclose[ + Catch @ Module[ { info, as }, + info = NotebookInformation @ nbo; + If[ FailureQ @ info, Throw @ Missing[ "NotebookClosed", nbo ] ]; + as = ConfirmBy[ Association @ info, AssociationQ, "Association" ]; + ConfirmBy[ AssociationMap[ formatNotebookInformation, as ], AssociationQ, "Formatted" ] + ], + throwInternalFailure ]; -cellInformation // endDefinition; +notebookInformation0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*notebooksInformation*) +notebooksInformation // beginDefinition; + +notebooksInformation[ { } ] := { }; + +notebooksInformation[ notebooks: { __NotebookObject } ] := Enclose[ + Module[ + { nbObjects, visible, windowClickSelect, selected, input, id, settings, feSettings, info, transposed, result }, + + nbObjects = Thread[ "NotebookObject" -> notebooks ]; + visible = Thread[ "Visible" -> AbsoluteCurrentValue[ notebooks, Visible ] ]; + windowClickSelect = Thread[ "WindowClickSelect" -> AbsoluteCurrentValue[ notebooks, WindowClickSelect ] ]; + selected = Thread[ "SelectedNotebook" -> Map[ SameAs @ SelectedNotebook[ ], notebooks ] ]; + input = Thread[ "InputNotebook" -> Map[ SameAs @ InputNotebook[ ], notebooks ] ]; + id = Thread[ "ID" -> tinyHash /@ notebooks ]; + + settings = Thread[ + "ChatNotebookSettings" -> AbsoluteCurrentValue[ notebooks, { TaggingRules, "ChatNotebookSettings" } ] + ]; + + If[ MemberQ[ settings, "ChatNotebookSettings" -> Inherited ], + feSettings = AbsoluteCurrentValue[ $FrontEnd, { TaggingRules, "ChatNotebookSettings" } ]; + settings = Replace[ settings, Inherited -> feSettings, { 2 } ] + ]; + + info = notebookInformation0 /@ notebooks; + + transposed = ConfirmBy[ + Transpose @ { info, nbObjects, visible, windowClickSelect, selected, input, id, settings }, + ListQ, + "Transpose" + ]; + + result = ConfirmMatch[ + combineNotebookInfo /@ transposed, + { (_? AssociationQ | Missing[ "NotebookClosed", _NotebookObject ])... }, + "Result" + ]; + + ConfirmAssert[ Length @ result === Length @ notebooks, "LengthCheck" ]; + + result + ], + throwInternalFailure +]; + +notebooksInformation // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*combineNotebookInfo*) +combineNotebookInfo // beginDefinition; +combineNotebookInfo[ a: { $Failed | Missing[ "NotebookClosed", ___ ], ___ } ] := missingNotebook @ a; +combineNotebookInfo[ a_List ] := With[ { as = Association @ a }, KeySort @ DeleteMissing @ as /; notebookInfoQ @ as ]; +combineNotebookInfo[ a_List ] := missingNotebook @ a; +combineNotebookInfo // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*missingNotebook*) +missingNotebook // beginDefinition; +missingNotebook[ { _, "NotebookObject" -> nbo_NotebookObject, ___ } ] := missingNotebook @ nbo; +missingNotebook[ nbo_NotebookObject ] := Missing[ "NotebookClosed", nbo ]; +missingNotebook // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*notebookInfoQ*) +notebookInfoQ // beginDefinition; +notebookInfoQ[ as_Association? AssociationQ ] := FreeQ[ as, _FrontEnd`AbsoluteCurrentValue|$Failed, { 1 } ]; +notebookInfoQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatNotebookInformation*) +formatNotebookInformation // beginDefinition; +formatNotebookInformation[ (Rule|RuleDelayed)[ key_, value_ ] ] := formatNotebookInformation[ key, value ]; +formatNotebookInformation[ "Uri", value_ ] := formatNotebookInformation[ "FileName", value ]; +formatNotebookInformation[ key_, value_ ] := ToString @ key -> formatNotebookInformation0[ key, value ]; +formatNotebookInformation // endDefinition; + +formatNotebookInformation0 // beginDefinition; +formatNotebookInformation0[ "FileName", file_ ] := toFileName @ file; +formatNotebookInformation0[ "FileModificationTime", t_Real ] := formatNotebookInformation0[ "Timestamp", t ]; +formatNotebookInformation0[ "MemoryModificationTime", t_Real ] := formatNotebookInformation0[ "Timestamp", t ]; +formatNotebookInformation0[ "Timestamp", t_Real ] := TimeZoneConvert @ DateObject[ t, TimeZone -> 0 ]; +formatNotebookInformation0[ key_String, value_ ] := value; +formatNotebookInformation0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*toFileName*) +toFileName // beginDefinition; +toFileName[ file_ ] := toFileName[ file ] = toFileName0 @ file; +toFileName // endDefinition; + +toFileName0 // beginDefinition; +toFileName0[ file0_FrontEnd`FileName ] := With[ { file = ToFileName @ file0 }, toFileName0 @ file /; StringQ @ file ]; +toFileName0[ file_String ] := StringReplace[ file, "\\" -> "/" ]; +toFileName0[ file_ ] := file; +toFileName0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*fromFETimestamp*) +(* TODO: use this when passing notebook info to the LLM *) +fromFETimestamp // beginDefinition; + +fromFETimestamp[ t_Real ] := Enclose[ + Module[ { date, string, relative }, + date = ConfirmBy[ TimeZoneConvert @ DateObject[ t, TimeZone -> 0 ], DateObjectQ, "Date" ]; + string = ConfirmBy[ DateString[ date, { "ISODateTime", ".", "Millisecond" } ], StringQ, "String" ]; + relative = ConfirmBy[ relativeTimeString @ date, StringQ, "Relative" ]; + string<>" ("<>relative<>")" + ], + throwInternalFailure +]; + +fromFETimestamp // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) @@ -333,13 +552,38 @@ parentCell // endDefinition; (* ::Subsection::Closed:: *) (*nextCell*) nextCell // beginDefinition; -nextCell[ cell_CellObject ] /; $cloudNotebooks := nextCell[ cell, parentNotebook @ cell ]; -nextCell[ cell_CellObject ] := NextCell @ cell; -nextCell[ cell_CellObject, nbo_NotebookObject ] := nextCell[ cell, Cells @ nbo ]; -nextCell[ cell_, { ___, cell_, next_CellObject, ___ } ] := next; -nextCell[ _CellObject, ___ ] := None; +nextCell // Options = { CellStyle -> Automatic }; + +nextCell[ cell_CellObject, opts: OptionsPattern[ ] ] := + If[ TrueQ @ $cloudNotebooks, + cloudNextCell[ cell, OptionValue[ CellStyle ] ], + NextCell[ cell, opts ] + ]; + nextCell // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*cloudNextCell*) +cloudNextCell // beginDefinition; + +cloudNextCell[ cell_CellObject, style_ ] := + cloudNextCell[ cell, parentNotebook @ cell, style ]; + +cloudNextCell[ cell_CellObject, nbo_NotebookObject, style_ ] := + cloudNextCell[ cell, Cells @ nbo, style ]; + +cloudNextCell[ cell_, { ___, cell_, next_CellObject, ___ }, Automatic ] := + next; + +cloudNextCell[ cell_, { ___, cell_, after__CellObject }, style_ ] := + SelectFirst[ { after }, MemberQ[ cellStyles @ #, style ] &, None ]; + +cloudNextCell[ _CellObject, _, _ ] := + None; + +cloudNextCell // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*previousCell*) @@ -486,7 +730,9 @@ fixCloudCell // beginDefinition; fixCloudCell[ cell_ ] /; ! TrueQ @ $cloudNotebooks := cell; fixCloudCell[ Cell[ CellGroupData[ cells_, a___ ] ] ] := Cell[ CellGroupData[ fixCloudCell @ cells, a ] ]; fixCloudCell[ Cell[ text_, args___ ] ] := Cell[ applyCloudCellFixes @ text, args ]; +fixCloudCell[ content: _BoxData|_TextData|_String ] := applyCloudCellFixes @ content; fixCloudCell[ cells_List ] := fixCloudCell /@ cells; +fixCloudCell[ cell_ ] := cell; fixCloudCell // endDefinition; (* ::**************************************************************************************************************:: *) @@ -508,6 +754,26 @@ $cloudCellFixes := $cloudCellFixes = Dispatch @ { (* ::Section::Closed:: *) (*Notebooks*) +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*$evaluationNotebook*) +$evaluationNotebook := + With[ { nbo = evaluationNotebook[ ] }, + If[ TrueQ[ $chatState && MatchQ[ nbo, _NotebookObject ] ], + $evaluationNotebook = nbo, + nbo + ] + ]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*evaluationNotebook*) +evaluationNotebook // beginDefinition; +evaluationNotebook[ ] := evaluationNotebook @ $evaluationCell; +evaluationNotebook[ cell_CellObject ] := With[ { nbo = parentNotebook @ cell }, nbo /; MatchQ[ nbo, _NotebookObject ] ]; +evaluationNotebook[ _ ] := EvaluationNotebook[ ]; +evaluationNotebook // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*withNoRenderUpdates*) @@ -527,9 +793,21 @@ withNoRenderUpdates // endDefinition; (* ::Subsection::Closed:: *) (*parentNotebook*) parentNotebook // beginDefinition; -parentNotebook[ obj: _CellObject|_BoxObject ] := Notebooks @ obj; +parentNotebook[ obj: _CellObject|_BoxObject ] := parentNotebook[ obj, Notebooks @ obj ]; +parentNotebook[ obj_, nbo_NotebookObject ] := nbo; +parentNotebook[ obj_CellObject, _? FailureQ ] := tryInlineChatParent @ obj; +parentNotebook[ _, fail_ ] := fail; parentNotebook // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*tryInlineChatParent*) +tryInlineChatParent // beginDefinition; +tryInlineChatParent[ obj_CellObject ] := tryInlineChatParent[ obj, currentChatSettings[ obj, "InlineChatRootCell" ] ]; +tryInlineChatParent[ obj_, cell_CellObject ] := Notebooks @ cell; +tryInlineChatParent[ _, _ ] := $Failed; +tryInlineChatParent // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*notebookRead*) @@ -574,7 +852,12 @@ getBoxObjectFromBoxID[ cell_CellObject, uuid_ ] := ]; getBoxObjectFromBoxID[ nbo_NotebookObject, uuid_String ] := - MathLink`CallFrontEnd @ FrontEnd`BoxReferenceBoxObject @ FE`BoxReference[ nbo, { { uuid } } ]; + MathLink`CallFrontEnd @ FrontEnd`BoxReferenceBoxObject @ FE`BoxReference[ + nbo, + { { uuid } }, + FE`SearchStart -> "StartFromBeginning", + FE`SearchStop -> "StopAtEnd" + ]; getBoxObjectFromBoxID // endDefinition; @@ -643,95 +926,162 @@ openerView1[ args___ ] := Quiet[ compressUntilViewed // beginDefinition; compressUntilViewed[ expr_ ] := + compressUntilViewed[ Unevaluated @ expr, False ]; + +compressUntilViewed[ expr_, False ] := With[ { b64 = BaseEncode @ BinarySerialize[ Unevaluated @ expr, PerformanceGoal -> "Size" ] }, - If[ ByteCount @ b64 < ByteCount @ expr, - Dynamic[ BinaryDeserialize @ BaseDecode @ b64, SingleEvaluation -> True, DestroyAfterEvaluation -> True ], - expr + Dynamic[ BinaryDeserialize @ BaseDecode @ b64, SingleEvaluation -> True, DestroyAfterEvaluation -> True ] + ]; + +compressUntilViewed[ expr_, True ] := + With[ { b64 = BaseEncode @ BinarySerialize[ Unevaluated @ expr, PerformanceGoal -> "Size" ] }, + DynamicModule[ + { display }, + Dynamic[ Replace[ display, _Symbol :> ProgressIndicator[ Appearance -> "Percolate" ] ] ], + Initialization :> (display = BinaryDeserialize @ BaseDecode @ b64), + SynchronousInitialization -> False, + UnsavedVariables :> { display } ] ]; compressUntilViewed // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*$statelessProgressIndicator*) + +(* TODO: move this to the stylesheet *) +$statelessProgressIndicator = + With[ { clock := Clock[ 10, 1.5 ] }, + RawBoxes @ GraphicsBox[ + { + GrayLevel[ 0.75 ], + { + { + PointSize @ Dynamic @ FEPrivate`Which[ + FEPrivate`Less[ clock, 0 ], + 0.08, + FEPrivate`Less[ clock, 2 ], + 0.08 + 0.05 * clock, + FEPrivate`Less[ clock, 4 ], + 0.28 - (0.05 * clock), + True, + 0.08 + ], + PointBox @ { 0, 0 } + }, + { + PointSize @ Dynamic @ FEPrivate`Which[ + FEPrivate`Less[ clock, 1 ], + 0.08, + FEPrivate`Less[ clock, 3 ], + 0.03 + 0.05 * clock, + FEPrivate`Less[ clock, 5 ], + 0.33 - (0.05 * clock), + True, + 0.08 + ], + PointBox @ { 1, 0 } + }, + { + PointSize @ Dynamic @ FEPrivate`Which[ + FEPrivate`Less[ clock, 2 ], + 0.08, + FEPrivate`Less[ clock, 4 ], + -0.02 + 0.05 * clock, + FEPrivate`Less[ clock, 6 ], + 0.38 - (0.05 * clock), + True, + 0.08 + ], + PointBox @ { 2, 0 } + }, + { + PointSize @ Dynamic @ FEPrivate`Which[ + FEPrivate`Less[ clock, 3 ], + 0.08, + FEPrivate`Less[ clock, 5 ], + -0.07 + 0.05 * clock, + FEPrivate`Less[ clock, 7 ], + 0.43 - (0.05 * clock), + True, + 0.08 + ], + PointBox @ { 3, 0 } + }, + { + PointSize @ Dynamic @ FEPrivate`Which[ + FEPrivate`Less[ clock, 4 ], + 0.08, + FEPrivate`Less[ clock, 6 ], + -0.12 + 0.05 * clock, + FEPrivate`Less[ clock, 8 ], + 0.48 - (0.05 * clock), + True, + 0.08 + ], + PointBox @ { 4, 0 } + } + } + }, + AspectRatio -> Full, + ImageSize -> { 50, 12 }, + PlotRange -> { { -1, 5 }, { -1, 1 } } + ] + ]; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Misc*) (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) -(*rasterize*) -rasterize // beginDefinition; - -rasterize[ expr_ ] := - If[ TrueQ @ $CloudEvaluation, - cloudRasterize @ Unevaluated @ expr, - Rasterize @ Unevaluated @ expr - ]; - -(* rasterize[ expr_ ] := - With[ { id = CreateUUID[ ] }, - WithCleanup[ - PutAppend[ <| "ID" -> id, "Expression" :> expr, "Event" -> "Before" |>, CloudObject[ "tmp/rasterizeLog.wl" ] ], - TimeConstrained[ UsingFrontEnd @ Rasterize @ expr, 5, UsingFrontEnd @ Rasterize @ expr ], - PutAppend[ <| "ID" -> id, "Expression" :> expr, "Event" -> "After" |>, CloudObject[ "tmp/rasterizeLog.wl" ] ] +(*usingFrontEnd*) +usingFrontEnd // beginDefinition; +usingFrontEnd // Attributes = { HoldFirst }; + +usingFrontEnd[ eval_ ] := + Block[ { usingFrontEnd = # &, $usingFE = True }, + If[ TrueQ @ $CloudEvaluation, + PreemptProtect @ UsingFrontEnd @ eval, + UsingFrontEnd @ eval ] - ]; *) + ]; -rasterize // endDefinition; +usingFrontEnd // endDefinition; (* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*cloudRasterize*) -cloudRasterize // beginDefinition; +(* ::Subsection::Closed:: *) +(*rasterizeBlock*) +(* Ensures that any Rasterize calls that occur in `eval` will get wrapped in `PreemptProtect` when in cloud. *) +rasterizeBlock // beginDefinition; +rasterizeBlock // Attributes = { HoldFirst }; -cloudRasterize[ expr_, opts: OptionsPattern[ Rasterize ] ] := - Progress`EvaluateWithProgress[ - cloudRasterize0[ expr, opts ], - <| "Text" -> "Preparing image...", "ElapsedTime" -> Automatic |> - ]; +rasterizeBlock[ eval_ ] := Block[ { rasterizeBlock = # & }, + Internal`InheritedBlock[ { Rasterize }, -cloudRasterize // endDefinition; + Unprotect @ Rasterize; + PrependTo[ + DownValues @ Rasterize, + HoldPattern @ Rasterize[ a___ ] /; ! TrueQ @ $usingFE :> + usingFrontEnd @ Rasterize @ a + ]; -cloudRasterize0 // beginDefinition; + Protect @ Rasterize; -cloudRasterize0[ expr_, opts: OptionsPattern[ Rasterize ] ] := Enclose[ - Module[ { api, wxf, b64, req, img }, - api = ConfirmMatch[ getCloudRasterizer[ ], _CloudObject, "RasterizerAPI" ]; - wxf = ConfirmBy[ BinarySerialize[ Unevaluated @ expr, PerformanceGoal -> "Size" ], ByteArrayQ, "WXF" ]; - b64 = ConfirmBy[ BaseEncode @ wxf, StringQ, "Base64" ]; - req = HTTPRequest[ api, <| "Method" -> "POST", "Body" -> { "Expression" -> b64 } |> ]; - img = ConfirmBy[ URLExecute[ req, "PNG" ], ImageQ, "Image" ]; - cloudRasterize[ expr, opts ] = img - ], - throwInternalFailure + eval + ] ]; -cloudRasterize0 // endDefinition; +rasterizeBlock // endDefinition; (* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*getCloudRasterizer*) -getCloudRasterizer // beginDefinition; - -getCloudRasterizer[ ] := Enclose[ - getCloudRasterizer[ ] = ConfirmMatch[ - CloudDeploy[ - APIFunction[ - (* TODO: options and format *) - { "Expression" -> "String" }, - Rasterize @ BinaryDeserialize @ BaseDecode[ #Expression ] &, - "PNG" - ], - CloudObject @ $cloudRasterizerLocation, - EvaluationPrivileges -> None, - Permissions -> "Private" - ], - _CloudObject - ], - throwInternalFailure -]; - -getCloudRasterizer // endDefinition; +(* ::Subsection::Closed:: *) +(*rasterize*) +rasterize // beginDefinition; +rasterize[ expr_, opts___ ] := usingFrontEnd @ Rasterize[ Unevaluated @ expr, opts ]; +rasterize // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) @@ -751,7 +1101,7 @@ replaceCellContext // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $feTaskDebug = False; $cloudCellFixes; ]; diff --git a/Source/Chatbook/Handlers.wl b/Source/Chatbook/Handlers.wl index f58d3e7e..6bffb647 100644 --- a/Source/Chatbook/Handlers.wl +++ b/Source/Chatbook/Handlers.wl @@ -1,25 +1,12 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Handlers`" ]; +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -HoldComplete[ - `addHandlerArguments; - `addProcessingArguments; - `applyHandlerFunction; - `applyProcessingFunction; - `getHandlerFunction; - `getHandlerFunctions; - `getProcessingFunction; - `getProcessingFunctions; -]; - -Begin[ "`Private`" ]; - -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -251,8 +238,8 @@ resolveFunctions // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/InlineReferences.wl b/Source/Chatbook/InlineReferences.wl index 8e4a1354..0dbc2242 100644 --- a/Source/Chatbook/InlineReferences.wl +++ b/Source/Chatbook/InlineReferences.wl @@ -7,32 +7,16 @@ BeginPackage[ "Wolfram`Chatbook`InlineReferences`" ]; -`insertPersonaInputBox; -`insertFunctionInputBox; -`insertModifierInputBox; -`insertTrailingFunctionInputBox; - -`insertPersonaTemplate; -`insertFunctionTemplate; -`insertModifierTemplate; -`insertWLTemplate; - -`personaTemplateBoxes; +(* These symbols are hardcoded into the stylesheet and need to remain in this context: *) `functionTemplateBoxes; `modifierTemplateBoxes; +`personaTemplateBoxes; `wlTemplateBoxes; -`parseInlineReferences; -`resolveLastInlineReference; -`resolveInlineReferences; - -`$cloudInlineReferenceButtons; - Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; Needs[ "Wolfram`Chatbook`ResourceInstaller`" ]; Needs[ "Wolfram`Chatbook`Serialization`" ]; @@ -347,7 +331,7 @@ modifierInputBox[ args_List, uuid_ ] := ContinuousAction -> False, FieldCompletionFunction -> modifierCompletion, FieldSize -> { { 15, Infinity }, Automatic }, - FieldHint -> "PromptName", + FieldHint -> tr[ "InlineReferencesFieldHint" ], BaseStyle -> $inputFieldStyle, Appearance -> "Frameless", ContentPadding -> False, @@ -620,7 +604,7 @@ functionInputBox[ args_List, uuid_ ] := ContinuousAction -> False, FieldCompletionFunction -> functionCompletion, FieldSize -> { { 15, Infinity }, Automatic }, - FieldHint -> "PromptName", + FieldHint -> tr[ "InlineReferencesFieldHint" ], BaseStyle -> $inputFieldStyle, Appearance -> "Frameless", ContentPadding -> False, @@ -1600,7 +1584,7 @@ modifierTemplateBoxes[version: 1, input_, params_, state_, uuid_, opts: OptionsP System`CommitAction -> (modifierCommitAction[#, input, params, state]&), BaselinePosition -> Baseline, FieldSize -> { { 15, Infinity }, Automatic }, - FieldHint -> "PromptName", (* FIXME: Is this right? *) + FieldHint -> tr[ "InlineReferencesFieldHint" ], (* FIXME: Is this right? *) BaseStyle -> $inputFieldStyle, Appearance -> "Frameless", (*ContentPadding -> False,*) @@ -1815,7 +1799,7 @@ functionTemplateBoxes[version: 1, input_, params_, state_, uuid_, opts: OptionsP System`CommitAction -> (functionCommitAction[#, input, params, state]&), BaselinePosition -> Baseline, FieldSize -> { { 15, Infinity }, Automatic }, - FieldHint -> "PromptName", (* FIXME: Is this right? *) + FieldHint -> tr[ "InlineReferencesFieldHint" ], (* FIXME: Is this right? *) BaseStyle -> $inputFieldStyle, Appearance -> "Frameless", (*ContentPadding -> False,*) @@ -2132,10 +2116,10 @@ $cloudInlineReferenceButtons = Block[ { NotebookTools`Mousedown = Mouseover[ #1, Grid[ { { - Style[ "Insert:", "Text" ], + Style[ tr[ "InlineReferencesInsertLabel" ], "Text" ], Button[ First @ personaTemplateBoxes[ 1, "Persona", "Chosen", "PersonaInsertButton" ], - With[ { name = InputString[ "Enter a persona name" ], uuid = CreateUUID[ ] }, + With[ { name = InputString[ tr[ "InlineReferencesInsertPersonaPrompt" ] ], uuid = CreateUUID[ ] }, If[ MemberQ[ $personaNames, name ], NotebookWrite[ EvaluationNotebook[ ], @@ -2150,7 +2134,9 @@ $cloudInlineReferenceButtons = Block[ { NotebookTools`Mousedown = Mouseover[ #1, ] = name; , If[ StringQ @ name, - MessageDialog[ "No persona with name \""<>name<>"\" found.\"" ] + MessageDialog @ trStringTemplate[ "InlineReferencesInsertPersonaFail" ][ + <| "name" -> name |> + ] ] ] ], @@ -2159,7 +2145,7 @@ $cloudInlineReferenceButtons = Block[ { NotebookTools`Mousedown = Mouseover[ #1, ], Button[ First @ modifierTemplateBoxes[ 1, "Modifier", { }, "Chosen", "ModifierInsertButton" ], - With[ { s = InputString[ "Enter a modifier prompt" ], uuid = CreateUUID[ ] }, + With[ { s = InputString[ tr[ "InlineReferencesInsertModifierPrompt" ] ], uuid = CreateUUID[ ] }, Replace[ functionInputSetting @ s, { name_String, args___String } :> @@ -2176,7 +2162,9 @@ $cloudInlineReferenceButtons = Block[ { NotebookTools`Mousedown = Mouseover[ #1, ] , If[ StringQ @ name, - MessageDialog[ "No modifier with name \""<>name<>"\" found.\"" ] + MessageDialog @ trStringTemplate[ "InlineReferencesInsertModifierFail" ][ + <| "name" -> name |> + ] ] ] ] @@ -2186,7 +2174,7 @@ $cloudInlineReferenceButtons = Block[ { NotebookTools`Mousedown = Mouseover[ #1, ], Button[ First @ functionTemplateBoxes[ 1, "Function", { }, "Chosen", "FunctionInsertButton" ], - With[ { s = InputString[ "Enter a function prompt" ], uuid = CreateUUID[ ] }, + With[ { s = InputString[ tr[ "InlineReferencesInsertFunctionPrompt" ] ], uuid = CreateUUID[ ] }, Replace[ functionInputSetting @ s, { name_String, args___String } :> @@ -2203,7 +2191,9 @@ $cloudInlineReferenceButtons = Block[ { NotebookTools`Mousedown = Mouseover[ #1, ] , If[ StringQ @ name, - MessageDialog[ "No function with name \""<>name<>"\" found.\"" ] + MessageDialog @ trStringTemplate[ "InlineReferencesInsertFunctionFail" ][ + <| "name" -> name |> + ] ] ] ] @@ -2222,7 +2212,7 @@ $cloudInlineReferenceButtons = Block[ { NotebookTools`Mousedown = Mouseover[ #1, (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ Null ]; diff --git a/Source/Chatbook/Main.wl b/Source/Chatbook/Main.wl index 29cd3466..13c89aa5 100644 --- a/Source/Chatbook/Main.wl +++ b/Source/Chatbook/Main.wl @@ -10,22 +10,27 @@ BeginPackage[ "Wolfram`Chatbook`" ]; `$AvailableTools; `$ChatAbort; `$ChatbookContexts; +`$ChatEvaluationCell; `$ChatHandlerData; `$ChatNotebookEvaluation; `$ChatPost; `$ChatPre; +`$CurrentChatSettings; `$DefaultChatHandlerFunctions; `$DefaultChatProcessingFunctions; `$DefaultModel; `$DefaultToolOptions; `$DefaultTools; `$IncludedCellWidget; +`$InlineChat; `$InstalledTools; `$SandboxKernel; `$ToolFunctions; +`$WorkspaceChat; `AbsoluteCurrentChatSettings; `AppendURIInstructions; `BasePrompt; +`CachedBoxes; `CellToChatMessage; `Chatbook; `ChatbookAction; @@ -33,9 +38,11 @@ BeginPackage[ "Wolfram`Chatbook`" ]; `CreateChatDrivenNotebook; `CreateChatNotebook; `CurrentChatSettings; +`DisplayBase64Boxes; `FormatChatOutput; `FormatToolCall; `FormatToolResponse; +`FormatWolframAlphaPods; `GetChatHistory; `GetExpressionURI; `GetExpressionURIs; @@ -44,6 +51,7 @@ BeginPackage[ "Wolfram`Chatbook`" ]; `SandboxLinguisticAssistantData; `SetModel; `SetToolOptions; +`ShowCodeAssistance; `StringToBoxes; `WriteChatOutputCell; @@ -52,6 +60,8 @@ BeginPackage[ "Wolfram`Chatbook`" ]; (*Begin Private Context*) Begin[ "`Private`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; + (* Avoiding context aliasing due to bug 434990: *) Needs[ "GeneralUtilities`" -> None ]; @@ -76,57 +86,69 @@ Chatbook is a symbol for miscellaneous chat notebook messages.\ (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Load Files*) -Block[ { $ContextPath }, - Get[ "Wolfram`Chatbook`Common`" ]; - Get[ "Wolfram`Chatbook`Settings`" ]; - Get[ "Wolfram`Chatbook`ErrorUtils`" ]; - Get[ "Wolfram`Chatbook`Errors`" ]; - Get[ "Wolfram`Chatbook`CreateChatNotebook`" ]; - Get[ "Wolfram`Chatbook`Dynamics`" ]; - Get[ "Wolfram`Chatbook`Utils`" ]; - Get[ "Wolfram`Chatbook`FrontEnd`" ]; - Get[ "Wolfram`Chatbook`Serialization`" ]; - Get[ "Wolfram`Chatbook`UI`" ]; - Get[ "Wolfram`Chatbook`Sandbox`" ]; - Get[ "Wolfram`Chatbook`Tools`" ]; - Get[ "Wolfram`Chatbook`Formatting`" ]; - Get[ "Wolfram`Chatbook`Prompting`" ]; - Get[ "Wolfram`Chatbook`Explode`" ]; - Get[ "Wolfram`Chatbook`ChatGroups`" ]; - Get[ "Wolfram`Chatbook`ChatMessages`" ]; - Get[ "Wolfram`Chatbook`Services`" ]; - Get[ "Wolfram`Chatbook`SendChat`" ]; - Get[ "Wolfram`Chatbook`Feedback`" ]; - Get[ "Wolfram`Chatbook`Actions`" ]; - Get[ "Wolfram`Chatbook`Menus`" ]; - Get[ "Wolfram`Chatbook`ResourceInstaller`" ]; - Get[ "Wolfram`Chatbook`Personas`" ]; - Get[ "Wolfram`Chatbook`InlineReferences`" ]; - Get[ "Wolfram`Chatbook`PreferencesUtils`" ]; - Get[ "Wolfram`Chatbook`Models`" ]; - Get[ "Wolfram`Chatbook`Dialogs`" ]; - Get[ "Wolfram`Chatbook`ToolManager`" ]; - Get[ "Wolfram`Chatbook`PersonaManager`" ]; - Get[ "Wolfram`Chatbook`ChatHistory`" ]; - Get[ "Wolfram`Chatbook`CloudToolbar`" ]; -]; +$ChatbookContexts = { + "Wolfram`Chatbook`", + "Wolfram`Chatbook`Actions`", + "Wolfram`Chatbook`ChatGroups`", + "Wolfram`Chatbook`ChatHistory`", + "Wolfram`Chatbook`ChatMessages`", + "Wolfram`Chatbook`ChatModes`", + "Wolfram`Chatbook`ChatState`", + "Wolfram`Chatbook`CloudToolbar`", + "Wolfram`Chatbook`Common`", + "Wolfram`Chatbook`CreateChatNotebook`", + "Wolfram`Chatbook`Dialogs`", + "Wolfram`Chatbook`Dynamics`", + "Wolfram`Chatbook`Errors`", + "Wolfram`Chatbook`ErrorUtils`", + "Wolfram`Chatbook`Explode`", + "Wolfram`Chatbook`Feedback`", + "Wolfram`Chatbook`Formatting`", + "Wolfram`Chatbook`FrontEnd`", + "Wolfram`Chatbook`Handlers`", + "Wolfram`Chatbook`InlineReferences`", + "Wolfram`Chatbook`Menus`", + "Wolfram`Chatbook`Models`", + "Wolfram`Chatbook`PersonaManager`", + "Wolfram`Chatbook`Personas`", + "Wolfram`Chatbook`PreferencesContent`", + "Wolfram`Chatbook`PreferencesUtils`", + "Wolfram`Chatbook`Prompting`", + "Wolfram`Chatbook`ResourceInstaller`", + "Wolfram`Chatbook`Sandbox`", + "Wolfram`Chatbook`SendChat`", + "Wolfram`Chatbook`Serialization`", + "Wolfram`Chatbook`Services`", + "Wolfram`Chatbook`Settings`", + "Wolfram`Chatbook`ToolManager`", + "Wolfram`Chatbook`Tools`", + "Wolfram`Chatbook`UI`", + "Wolfram`Chatbook`Utils`" +}; + +Scan[ Needs[ # -> None ] &, $ChatbookContexts ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Protected Symbols*) Protect[ $AutomaticAssistance, + $ChatbookContexts, $ChatNotebookEvaluation, + $CurrentChatSettings, $DefaultChatHandlerFunctions, $DefaultChatProcessingFunctions, $DefaultModel, $DefaultToolOptions, $DefaultTools, + $InlineChat, $InstalledTools, $ToolFunctions, + $WorkspaceChat, AbsoluteCurrentChatSettings, AppendURIInstructions, BasePrompt, + CachedBoxes, CellToChatMessage, Chatbook, ChatbookAction, @@ -134,9 +156,11 @@ Protect[ CreateChatDrivenNotebook, CreateChatNotebook, CurrentChatSettings, + DisplayBase64Boxes, FormatChatOutput, FormatToolCall, FormatToolResponse, + FormatWolframAlphaPods, GetChatHistory, GetExpressionURI, GetExpressionURIs, @@ -144,21 +168,19 @@ Protect[ SandboxLinguisticAssistantData, SetModel, SetToolOptions, + ShowCodeAssistance, StringToBoxes, WriteChatOutputCell ]; -(* ::**************************************************************************************************************:: *) -(* ::Section::Closed:: *) -(*Subcontexts*) -$ChatbookContexts := $ChatbookContexts = Select[ Contexts[ "Wolfram`Chatbook`*" ], StringFreeQ[ "`Private`" ] ]; - (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $ChatbookContexts; ]; +mxInitialize[ ]; + End[ ]; EndPackage[ ]; diff --git a/Source/Chatbook/Menus.wl b/Source/Chatbook/Menus.wl index 5676a4b9..a36ffc05 100644 --- a/Source/Chatbook/Menus.wl +++ b/Source/Chatbook/Menus.wl @@ -10,11 +10,8 @@ BeginPackage[ "Wolfram`Chatbook`Menus`" ]; (* :!CodeAnalysis::BeginBlock:: *) HoldComplete[ - `attachMenuCell; `AttachSubmenu; `MakeMenu; - `menuMagnification; - `removeChatMenus; ]; Needs[ "GeneralUtilities`" -> None ]; @@ -34,7 +31,6 @@ Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; Needs[ "Wolfram`Chatbook`ErrorUtils`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -343,8 +339,8 @@ attachMenuCell // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Models.wl b/Source/Chatbook/Models.wl index a1357911..ed87d1b1 100644 --- a/Source/Chatbook/Models.wl +++ b/Source/Chatbook/Models.wl @@ -1,31 +1,14 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Models`" ]; - -(* cSpell: ignore chatgpt *) +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -HoldComplete[ - `chatModelQ; - `chooseDefaultModelName; - `getModelList; - `modelDisplayName; - `multimodalModelQ; - `snapshotModelQ; - `standardizeModelData; - `resolveFullModelSpec; - `toModelName; -]; - -Begin[ "`Private`" ]; - -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Actions`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Dynamics`" ]; -Needs[ "Wolfram`Chatbook`Services`" ]; -Needs[ "Wolfram`Chatbook`UI`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Actions`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`UI`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -169,6 +152,9 @@ toModelName[ name_String? StringQ ] := toModelName[ name ] = ] ]; +toModelName[ missing_Missing ] := + missing; + toModelName // endDefinition; toModelName0 // beginDefinition; @@ -180,31 +166,16 @@ toModelName0 // endDefinition; (* ::Subsection::Closed:: *) (*snapshotModelQ*) snapshotModelQ // beginDefinition; - -snapshotModelQ[ name_String? fineTunedModelQ ] := snapshotModelQ[ name ] = - snapshotModelQ @ StringSplit[ name, ":" ][[ 2 ]]; - -snapshotModelQ[ name_String? StringQ ] := snapshotModelQ[ name ] = - StringMatchQ[ - toModelName @ name, - Alternatives[ - "gpt-" ~~ __ ~~ "-" ~~ Repeated[ DigitCharacter, { 4 } ] ~~ (""|"-vision") ~~ (""|"-preview"), - "gpt-" ~~ __ ~~ "-" ~~ DatePattern @ { "Year", "Month", "Day" } ~~ (""|"-vision") ~~ (""|"-preview"), - __ ~~ "-" ~~ Repeated[ DigitCharacter, { 8 } ] - ] - ]; - -snapshotModelQ[ other_ ] := - With[ { name = toModelName @ other }, snapshotModelQ @ name /; StringQ @ name ]; - +snapshotModelQ[ model_ ] := snapshotModelQ[ model, modelNameData @ model ]; +snapshotModelQ[ model_, KeyValuePattern[ "Date" -> date_ ] ] := modelDateSpecQ @ date; snapshotModelQ // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*fineTunedModelQ*) fineTunedModelQ // beginDefinition; -fineTunedModelQ[ name_String ] := StringMatchQ[ toModelName @ name, "ft:"~~__~~":"~~__ ]; -fineTunedModelQ[ other_ ] := With[ { name = toModelName @ other }, fineTunedModelQ @ name /; StringQ @ name ]; +fineTunedModelQ[ model_ ] := fineTunedModelQ[ model, modelNameData @ model ]; +fineTunedModelQ[ model_, KeyValuePattern[ "FineTuned" -> bool: True|False ] ] := bool; fineTunedModelQ // endDefinition; (* ::**************************************************************************************************************:: *) @@ -213,20 +184,23 @@ fineTunedModelQ // endDefinition; (* FIXME: this should be a queryable property from LLMServices: *) multimodalModelQ // beginDefinition; +multimodalModelQ[ KeyValuePattern[ "Multimodal" -> multimodal_ ] ] := + TrueQ @ multimodal; + multimodalModelQ[ "gpt-4-turbo" ] := True; multimodalModelQ[ name_String? StringQ ] /; StringStartsQ[ name, "claude-3" ] := True; +multimodalModelQ[ name_String? StringQ ] /; StringStartsQ[ name, "gpt-4o"|"gpt-4o-mini" ] := + True; + multimodalModelQ[ name_String? StringQ ] /; StringStartsQ[ name, "gpt-4-turbo-" ] := StringMatchQ[ name, "gpt-4-turbo-"~~DatePattern @ { "Year", "Month", "Day" } ]; multimodalModelQ[ name_String? StringQ ] := - StringContainsQ[ toModelName @ name, "gpt-"~~$$modelVersion~~"-vision" ]; - -multimodalModelQ[ KeyValuePattern[ "Multimodal" -> multimodal_ ] ] := - TrueQ @ multimodal; + StringContainsQ[ toModelName @ name, WordBoundary~~"vision"~~WordBoundary, IgnoreCase -> True ]; multimodalModelQ[ other_ ] := With[ { name = toModelName @ other }, @@ -237,59 +211,232 @@ multimodalModelQ // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) -(*modelDisplayName*) -modelDisplayName // beginDefinition; +(*modelNameData*) +modelNameData // beginDefinition; + +modelNameData[ data: KeyValuePattern @ { + "Name" -> _String, + "BaseName" -> _String, + "Date" -> _? modelDateSpecQ | None, + "Preview" -> True|False, + "FineTuned" -> True|False, + "FineTuneName" -> _String|None, + "Organization" -> _String|None, + "ID" -> _String|None +} ] := modelNameData[ data ] = KeySort @ data; + +modelNameData[ as: KeyValuePattern[ "Name" -> name_String ] ] := + <| modelNameData @ name, DeleteCases[ as, $$unspecified|None ] |>; + +modelNameData[ model0_ ] := Enclose[ + Module[ { model, defaults, data }, + + model = ConfirmBy[ toModelName @ model0, StringQ, "Model" ]; + + defaults = <| + "Name" -> model, + "Date" -> None, + "Preview" -> False, + "FineTuned" -> False, + "FineTuneName" -> None, + "Organization" -> None, + "ID" -> None + |>; + + data = ConfirmBy[ + If[ StringMatchQ[ model, "ft:" ~~ __ ~~ ":" ~~ __ ], + fineTunedModelNameData @ model, + modelNameData0 @ model + ], + AssociationQ, + "Data" + ]; -modelDisplayName[ KeyValuePattern[ "DisplayName" -> name_String ] ] := - name; + data = <| defaults, data |>; + data[ "DisplayName" ] = ConfirmBy[ createModelDisplayName @ data, StringQ, "DisplayName" ]; + data //= KeySort; -modelDisplayName[ KeyValuePattern[ "Name" -> name_String ] ] := - modelDisplayName @ name; + modelNameData[ model0 ] = ConfirmBy[ data, AssociationQ, "FullData" ] + ], + throwInternalFailure +]; -modelDisplayName[{name_?StringQ, settings_?AssociationQ}] := - modelDisplayName[name] +modelNameData // endDefinition; -modelDisplayName[ model_String ] := modelDisplayName[ model ] = - If[ StringMatchQ[ model, "ft:"~~__~~":"~~__ ], - fineTunedModelName @ model, - modelDisplayName @ StringSplit[ model, "-"|" " ] - ]; -modelDisplayName[ { "gpt", rest___ } ] := - modelDisplayName @ { "GPT", rest }; +modelNameData0 // beginDefinition; -modelDisplayName[ { before__, date_String } ] /; StringMatchQ[ date, Repeated[ DigitCharacter, { 4 } ] ] := - modelDisplayName @ { before, DateObject @ Flatten @ { 0, ToExpression @ StringPartition[ date, 2 ] } }; +modelNameData0[ model_String ] := + modelNameData0 @ StringSplit[ + StringReplace[ model, "claude-"~~a:DigitCharacter..~~"-"~~b:DigitCharacter.. :> "claude-"<>a<>"."<>b ], + "-"|" " + ]; + +modelNameData0[ { "gpt", rest___ } ] := + modelNameData0 @ { "GPT", rest }; -modelDisplayName[ { before__, date_String } ] /; StringMatchQ[ date, Repeated[ DigitCharacter, { 8 } ] ] := - modelDisplayName @ { before, DateObject @ StringInsert[ date, "-", { 5, 7 } ] }; +modelNameData0[ { before__, s_String } ] := + With[ { date = modelDate @ s }, + <| "Date" -> date, modelNameData0 @ { before } |> /; modelDateSpecQ @ date + ]; -modelDisplayName[ { before__, y_String, m_String, d_String } ] := +modelNameData0[ { before__, y_String, m_String, d_String } ] := With[ { date = StringRiffle[ { y, m, d }, "-" ] }, - modelDisplayName @ { before, DateObject @ date } /; + <| "Date" -> DateObject @ date, modelNameData0 @ { before } |> /; StringMatchQ[ date, DatePattern @ { "Year", "Month", "Day" } ] ]; -modelDisplayName[ { before__, "preview" } ] := - modelDisplayName @ { before } <> " (Preview)"; +modelNameData0[ { before__, "preview" } ] := + <| "Preview" -> True, modelNameData0 @ { before } |>; + +modelNameData0[ { before__, s_String, "vision" } ] := + With[ { date = modelDate @ s }, + <| "Date" -> date, modelNameData0 @ { before, "vision" } |> /; modelDateSpecQ @ date + ]; -modelDisplayName[ { before__, "vision" } ] := - modelDisplayName @ { before } <> " Vision"; +modelNameData0[ { "GPT", version_String, rest___ } ] /; StringStartsQ[ version, DigitCharacter.. ] := + modelNameData0 @ { "GPT-"<>version, rest }; -modelDisplayName[ { before___, date_DateObject } ] := - modelDisplayName @ { - before, - "(" <> DateString[ date, "MonthName" ] <> " " <> DateString[ date, "DayShort" ] <> ")" - }; +(* cSpell: ignore omni *) +modelNameData0[ { "GPT-4o", rest___ } ] := + modelNameData0 @ { "GPT-4", "Omni", rest }; -modelDisplayName[ { "GPT", version_String, rest___ } ] /; StringStartsQ[ version, DigitCharacter.. ] := - modelDisplayName @ { "GPT-"<>version, rest }; +modelNameData0[ parts: { __String } ] := + <| "BaseName" -> StringRiffle @ Capitalize @ parts |>; -modelDisplayName[ parts: { __String } ] := - StringRiffle @ Capitalize @ parts; +modelNameData0 // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*modelDateSpecQ*) +modelDateSpecQ // beginDefinition; +modelDateSpecQ[ date_DateObject ] := DateObjectQ @ date; +modelDateSpecQ[ "Latest" ] := True; +modelDateSpecQ[ _ ] := False +modelDateSpecQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*createModelDisplayName*) +createModelDisplayName // beginDefinition; + +createModelDisplayName[ KeyValuePattern @ { + "BaseName" -> base_String, + "Date" -> date0_, + "Preview" -> preview0_, + "Organization" -> org0_, + "FineTuneName" -> name0_, + "ID" -> id0_ +} ] := + Module[ { date, preview, id, org, ftName, ftID }, + + date = Replace[ modelDateString @ date0, Except[ _String? StringQ ] -> Nothing ]; + preview = If[ TrueQ @ preview0, "(Preview)", Nothing ]; + id = If[ StringQ @ id0 && id0 =!= "", id0, Nothing ]; + org = If[ StringQ @ org0 && ! MatchQ[ org0, ""|"personal" ], org0, Nothing ]; + ftName = If[ StringQ @ name0 && name0 =!= "", name0, Nothing ]; + + ftID = Which[ + StringQ @ ftName && StringQ @ org, "(" <> StringRiffle[ { org, ftName }, ":" ] <> ")", + StringQ @ id || StringQ @ org, "(" <> StringRiffle[ { org, ftName, id }, ":" ] <> ")", + True, Nothing + ]; + + If[ StringQ @ ftID, date = Nothing ]; + + StringReplace[ + StringRiffle[ { base, date, preview, ftID }, " " ], + { + ") (Preview)" -> " Preview)", + ") (" -> ", " + } + ] + ]; + +createModelDisplayName // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*modelDateString*) +modelDateString // beginDefinition; +modelDateString[ None ] := None; +modelDateString[ "Latest" ] := "(Latest)"; +modelDateString[ date_DateObject ] := modelDateString[ date, Quiet @ DateString[ date, "LocaleDateShort" ] ]; +modelDateString[ date_DateObject, string_String ] := "(" <> string <> ")"; +modelDateString[ date_DateObject, _ ] := With[ { s = DateString @ date }, modelDateString[ date, s ] /; StringQ @ s ]; +modelDateString // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*fineTunedModelNameData*) +fineTunedModelNameData // beginDefinition; + +fineTunedModelNameData[ name_String ] := + fineTunedModelNameData @ StringSplit[ name, ":" ]; + +fineTunedModelNameData[ { "ft", model_, org_, name_, id_ } ] := <| + modelNameData0 @ model, + "Organization" -> org, + "ID" -> id, + "FineTuneName" -> name, + "FineTuned" -> True +|>; + +fineTunedModelNameData[ { "ft", rest__String } ] := + fineTunedModelNameData @ { rest }; + +fineTunedModelNameData[ other: { __String } ] := <| + modelNameData0 @ StringRiffle[ other, ":" ], + "FineTuned" -> True +|>; + +fineTunedModelNameData // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*modelDisplayName*) +modelDisplayName // beginDefinition; +modelDisplayName[ model_ ] := modelDisplayName[ model, modelNameData @ model ]; +modelDisplayName[ model_, KeyValuePattern[ "DisplayName" -> name_String ] ] := name; modelDisplayName // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*modelDate*) +modelDate // beginDefinition; + +modelDate[ KeyValuePattern[ "Date" -> date_? modelDateSpecQ ] ] := + date; + +modelDate[ KeyValuePattern[ "Name" -> name_String ] ] := + modelDate @ name; + +modelDate[ model_String ] := modelDate[ model ] = + modelDate @ StringSplit[ model, "-"|" " ]; + +modelDate[ { ___, "latest" } ] := + "Latest"; + +(* Hack for OpenAI's poor choice of 4 digit dates: *) +modelDate[ { ___, "0125" } ] := + DateObject @ { 2024, 1, 25 }; + +modelDate[ { ___, date_String } ] /; StringMatchQ[ date, Repeated[ DigitCharacter, { 4 } ] ] := + DateObject @ Flatten @ { 2023, ToExpression @ StringPartition[ date, 2 ] }; + +modelDate[ { ___, date_String } ] /; StringMatchQ[ date, Repeated[ DigitCharacter, { 8 } ] ] := + DateObject @ StringInsert[ date, "-", { 5, 7 } ]; + +modelDate[ { ___, y_String, m_String, d_String } ] := + With[ { date = StringRiffle[ { y, m, d }, "-" ] }, + DateObject @ StringRiffle[ { y, m, d }, "-" ] /; StringMatchQ[ date, DatePattern @ { "Year", "Month", "Day" } ] + ]; + +modelDate[ { ___String } ] := + None; + +modelDate // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*fineTunedModelName*) @@ -354,7 +501,9 @@ standardizeModelData[ name_String ] := standardizeModelData[ name ] = standardizeModelData @ <| "Name" -> name |>; standardizeModelData[ model: KeyValuePattern @ { } ] := - standardizeModelData[ model ] = <| + standardizeModelData[ model ] = KeySort @ <| + modelNameData @ model, + "Date" -> modelDate @ model, "DisplayName" -> modelDisplayName @ model, "FineTuned" -> fineTunedModelQ @ model, "Icon" -> modelIcon @ model, @@ -412,8 +561,8 @@ resolveFullModelSpec // beginDefinition; resolveFullModelSpec[ settings: KeyValuePattern[ "Model" -> model_ ] ] := resolveFullModelSpec @ model; -resolveFullModelSpec[ { service_String, Automatic } ] := - resolveFullModelSpec @ <| "Service" -> service, "Name" -> Automatic |>; +resolveFullModelSpec[ { service_String, name_ } ] := + resolveFullModelSpec @ <| "Service" -> service, "Name" -> name |>; resolveFullModelSpec[ model: KeyValuePattern @ { "Service" -> service_String, "Name" -> Automatic } ] := Enclose[ Catch @ Module[ { default, models, name }, @@ -470,8 +619,8 @@ standardizeModelName[name_String]:=name (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/PersonaManager.wl b/Source/Chatbook/PersonaManager.wl index 7ae75ab3..c82af5b5 100644 --- a/Source/Chatbook/PersonaManager.wl +++ b/Source/Chatbook/PersonaManager.wl @@ -10,9 +10,7 @@ BeginPackage[ "Wolfram`Chatbook`PersonaManager`" ]; Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`CloudToolbar`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Dialogs`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; Needs[ "Wolfram`Chatbook`ResourceInstaller`" ]; Needs[ "Wolfram`Chatbook`UI`" ]; @@ -29,7 +27,7 @@ CreatePersonaManagerDialog // beginDefinition; CreatePersonaManagerDialog[ args___ ] := createDialog[ CreatePersonaManagerPanel @ args, - WindowTitle -> "Add & Manage Personas" + WindowTitle -> tr[ "PersonaManagerTitle" ] ]; CreatePersonaManagerDialog // endDefinition; @@ -48,16 +46,16 @@ CreatePersonaManagerPanel[ ] := DynamicModule[{favorites, delimColor}, Framed[ Grid[ { - If[ TrueQ @ $inDialog, dialogHeader[ "Add & Manage Personas" ], Nothing ], + If[ TrueQ @ $inDialog, dialogHeader @ tr[ "PersonaManagerTitle" ], Nothing ], (* ----- Install Personas ----- *) - dialogSubHeader[ "Install Personas" ], + dialogSubHeader @ tr[ "PersonaManagerInstallPersonas" ], dialogBody[ Grid @ { { - "Install from", + tr[ "PersonaManagerInstallFrom" ], Button[ - grayDialogButtonLabel[ "Prompt Repository \[UpperRightArrow]" ], + grayDialogButtonLabel @ tr[ "PersonaManagerInstallFromPromptRepo" ], If[ $CloudEvaluation, SetOptions[ EvaluationNotebook[ ], DockedCells -> Inherited ] ]; ResourceInstallFromRepository[ "Prompt" ], Appearance -> "Suppressed", @@ -65,7 +63,7 @@ CreatePersonaManagerPanel[ ] := DynamicModule[{favorites, delimColor}, Method -> "Queued" ], Button[ - grayDialogButtonLabel[ "URL" ], + grayDialogButtonLabel @ tr[ "URLButton" ], If[ $CloudEvaluation, SetOptions[ EvaluationNotebook[ ], DockedCells -> Inherited ] ]; Block[ { PrintTemporary }, ResourceInstallFromURL[ "Prompt" ] ], Appearance -> "Suppressed", @@ -77,7 +75,7 @@ CreatePersonaManagerPanel[ ] := DynamicModule[{favorites, delimColor}, ], (* ----- Configure and Enable Personas ----- *) - dialogSubHeader[ "Manage and Enable Personas", { Automatic, { 5, Automatic } } ], + dialogSubHeader[ tr[ "PersonaManagerManagePersonas" ], { Automatic, { 5, Automatic } } ], { If[ $inDialog, Pane[#, AppearanceElements -> None, ImageSize -> {Full, UpTo[300]}, Scrollbars -> {False, Automatic}], # ]& @ Dynamic[ @@ -89,7 +87,16 @@ CreatePersonaManagerPanel[ ] := DynamicModule[{favorites, delimColor}, Join[ KeyTake[GetCachedPersonaData[ "IncludeHidden" -> False ], favorites], KeySort[GetCachedPersonaData[ "IncludeHidden" -> False ]]]], - {"", "In Menu", "", "Name", ""(*FITME*), (*"Description",*) "Version", ""}], + { + "", + tr[ "PersonaManagerInMenu" ], + "", + tr[ "PersonaManagerName" ], + "", + tr[ "PersonaManagerVersion" ], + "" + } + ], Alignment -> {{Center, Center, {Left}}, Center}, Background -> {{}, {RGBColor["#e5e5e5"], {White}}}, BaseStyle -> "DialogBody", @@ -119,7 +126,7 @@ CreatePersonaManagerPanel[ ] := DynamicModule[{favorites, delimColor}, { Item[ Button[(* give Default properties using specific FEExpression *) - redDialogButtonLabel[ "OK" ], + redDialogButtonLabel @ tr[ "OKButton" ], DialogReturn @ channelCleanup[ ], Appearance -> FEPrivate`FrontEndResource["FEExpressions", "DefaultSuppressMouseDownNinePatchAppearance"], ImageMargins -> {{0, 31}, {14, 14}}, @@ -217,19 +224,40 @@ formatPersonaData[ name_String, as_Association, link_, desc_, version_, icon_, o formatPersonaData // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatName*) formatName // beginDefinition; -formatName[ name_String ] := StringJoin[ Riffle[ DeleteCases[ StringTrim @ StringSplit[ name, RegularExpression[ "([A-Z])([a-z]+)" ] -> "$1$2 " ], "" ], " " ] ] -formatName[ origin_String, name_String, link_Missing ] := formatName[ name ] -formatName[ "PacletRepository", name_String, link_ ] := formatName[ name ] -formatName[ origin_String, name_String, link_ ] := + +formatName[ name_String ] := StringRiffle @ DeleteCases[ + StringTrim @ StringSplit[ name, RegularExpression[ "([A-Z])([a-z]+)" ] -> "$1$2 " ], + "" +]; + +formatName[ name: Except[ $$unspecified ] ] := + name; + +formatName[ origin_String, name: Except[ $$unspecified ], link_Missing ] := + formatName @ name; + +formatName[ "PacletRepository", name: Except[ $$unspecified ], link_ ] := + formatName @ name; + +formatName[ origin_String, name: Except[ $$unspecified ], link_ ] := Hyperlink[ Mouseover[ - Grid[{{formatName[ name ], chatbookIcon["PeelOff", False]}}], - Grid[{{formatName[ name ], chatbookIcon["PeelOff-hover", False]}}]], + Grid @ { { formatName @ name, chatbookIcon[ "PeelOff", False ] } }, + Grid @ { { formatName @ name, chatbookIcon[ "PeelOff-hover", False ] } } + ], link, - BaseStyle -> {LineBreakWithin -> False}]; + BaseStyle -> { LineBreakWithin -> False } + ]; + formatName // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatDescription*) formatDescription // beginDefinition; formatDescription[ _Missing ] := Style["\[LongDash]", FontColor -> GrayLevel[0.808]]; formatDescription[ desc_String ] := @@ -240,17 +268,26 @@ formatDescription[ desc_String ] := ]&[<|"nChars" -> 30|>]; formatDescription // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatVersion*) formatVersion // beginDefinition; formatVersion[ _Missing ] := Style["\[LongDash]", FontColor -> GrayLevel[0.808]]; formatVersion[ version: _String|None ] := version; formatVersion // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatIcon*) formatIcon // beginDefinition; formatIcon[ _Missing ] := ""; formatIcon[ KeyValuePattern[ "Default" -> icon_ ] ] := formatIcon @ icon; formatIcon[ icon_ ] := Pane[ icon, ImageSize -> { 20, 20 }, ImageSizeAction -> "ShrinkToFit" ]; formatIcon // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatPacletLink*) formatPacletLink // beginDefinition; formatPacletLink[ origin_String, url_, pacletName_ ] := Switch[origin, @@ -260,18 +297,21 @@ formatPacletLink[ origin_String, url_, pacletName_ ] := formatIcon @ Mouseover[chatbookIcon["PacletRepo", False], chatbookIcon["PacletRepo-hover", False]], $chatbookDocumentationURL, ImageMargins -> {{13, 0}, {0, 0}}], - "Persona installed from the Wolfram/Chatbook paclet. Visit page \[RightGuillemet]"], + tr[ "PersonaManagerOriginChatbookTooltip" ]], "PacletRepository", Tooltip[ Hyperlink[ formatIcon @ Mouseover[chatbookIcon["PacletRepo", False], chatbookIcon["PacletRepo-hover", False]], url, ImageMargins -> {{13, 0}, {0, 0}}], - StringTemplate["Persona installed from the `name` paclet. Visit page \[RightGuillemet]."][<|"name" -> pacletName|>]], + trStringTemplate[ "PersonaManagerOriginRepositoryTooltip" ][ <| "name" -> pacletName |> ]], _, ""]; formatPacletLink // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*addRemovePersonaListingCheckbox*) addRemovePersonaListingCheckbox // beginDefinition; addRemovePersonaListingCheckbox[ name_String ] := @@ -289,6 +329,9 @@ addRemovePersonaListingCheckbox[ name_String ] := addRemovePersonaListingCheckbox // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*uninstallButton*) uninstallButton // beginDefinition; uninstallButton[ name_String, installedQ_, pacletName_String ] := Button[ @@ -299,7 +342,7 @@ uninstallButton[ name_String, installedQ_, pacletName_String ] := "Disabled" -> Tooltip[ formatIcon @ chatbookIcon["Delete-disabled", False], - StringTemplate["This persona cannot be uninstalled because it is provided by the `1` paclet."][pacletName]]}, + trStringTemplate[ "PersonaManagerPersonaUninstallTooltip" ][ pacletName ]]}, Dynamic[Which[!installedQ, "Disabled", CurrentValue["MouseOver"], "Hover", True, "Default"]], ImageSize -> Automatic], Block[ { PrintTemporary }, @@ -316,8 +359,8 @@ uninstallButton // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Personas.wl b/Source/Chatbook/Personas.wl index 04933e7e..6a927402 100644 --- a/Source/Chatbook/Personas.wl +++ b/Source/Chatbook/Personas.wl @@ -26,8 +26,6 @@ GetPersonaData[] returns information about all locally installed personas, inclu Calling GetPersonaData[] will additionally regenerate the cache used by GetCachedPersonaData. "]; -`$corePersonaNames; - Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; @@ -35,7 +33,6 @@ Needs[ "Wolfram`Chatbook`Common`" ]; Needs[ "Wolfram`Chatbook`Errors`" ]; Needs[ "Wolfram`Chatbook`ErrorUtils`" ]; Needs[ "Wolfram`Chatbook`ResourceInstaller`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -158,7 +155,7 @@ GetPersonaData[] := Module[{ pacletPersonas = KeySort @ Flatten @ Map[loadPacletPersonas, paclets]; personas = Merge[{resourcePersonas, pacletPersonas}, First]; - $CachedPersonaData = RaiseConfirmMatch[ + $CachedPersonaData = fixFEResourceBoxes @ RaiseConfirmMatch[ (* Show core personas first *) standardizePersonaData /@ Join[KeyTake[personas, $corePersonaNames], KeySort[personas]], _Association? AssociationQ @@ -177,6 +174,13 @@ GetPersonaData[persona_?StringQ] := Module[{ GetPersonaData // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*fixFEResourceBoxes*) +fixFEResourceBoxes // beginDefinition; +fixFEResourceBoxes[ expr_ ] := expr /. Dynamic[ res_FEPrivate`FrontEndResource ] :> RawBoxes @ DynamicBox @ res; +fixFEResourceBoxes // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*loadPacletPersonas*) @@ -336,7 +340,7 @@ standardizePersonaData // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ loadPacletPersonas @ PacletObject[ "Wolfram/Chatbook" ]; ]; diff --git a/Source/Chatbook/PreferencesContent.wl b/Source/Chatbook/PreferencesContent.wl index 2d40c5e4..1e0d5605 100644 --- a/Source/Chatbook/PreferencesContent.wl +++ b/Source/Chatbook/PreferencesContent.wl @@ -1,29 +1,14 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`PreferencesContent`" ]; - -HoldComplete[ - `$cloudEvaluationNotebook; - `$preferencesScope; - `createPreferencesContent; - `makeModelSelector; - `makePersonaSelector; - `notebookSettingsPanel; - `openPreferencesPage; -]; - Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Dynamics`" ]; Needs[ "Wolfram`Chatbook`Errors`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; Needs[ "Wolfram`Chatbook`PersonaManager`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; Needs[ "Wolfram`Chatbook`PreferencesUtils`" ]; -Needs[ "Wolfram`Chatbook`Services`" ]; -Needs[ "Wolfram`Chatbook`Settings`" ]; Needs[ "Wolfram`Chatbook`ToolManager`" ]; Needs[ "Wolfram`Chatbook`UI`" ]; @@ -31,6 +16,7 @@ Needs[ "Wolfram`Chatbook`UI`" ]; (* ::Section::Closed:: *) (*Configuration*) $preferencesWidth = 640; +$cloudPreferencesHeight = 400; $cloudEvaluationNotebook = None; $preferencesPages = { "Notebooks", "Services", "Personas", "Tools" }; @@ -139,7 +125,11 @@ createPreferencesContent // beginDefinition; createPreferencesContent[ ] := Enclose[ Module[ { tabs, tabView, reset }, (* Retrieve the dynamic content for each preferences tab, confirming that it matches the expected types: *) - tabs = ConfirmMatch[ createTabViewTabs[ ], { { _String, _String -> _Dynamic|_DynamicModule }.. }, "Tabs" ]; + tabs = ConfirmMatch[ + createTabViewTabs[ ], + { { _String, _Dynamic|_String -> _Dynamic|_DynamicModule }.. }, + "Tabs" + ]; (* Create a TabView for the preferences content, with the tab state stored in the FE's private options: *) tabView = TabView[ @@ -156,7 +146,7 @@ createPreferencesContent[ ] := Enclose[ reset = Pane[ $resetButton, ImageMargins -> { { 20, 0 }, { 0, 10 } }, ImageSize -> $preferencesWidth ]; (* Arrange the TabView and reset button in a Grid layout with vertical spacers: *) - Grid[ + makeScrollableInCloud @ Grid[ { $verticalSpacer, { tabView, "" }, @@ -177,6 +167,22 @@ createPreferencesContent[ ] := Enclose[ createPreferencesContent // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makeScrollableInCloud*) +makeScrollableInCloud // beginDefinition; + +makeScrollableInCloud[ expr_ ] /; $CloudEvaluation := + Pane[ Pane[ expr, ImageMargins -> { { 0, 10 }, { 0, 0 } } ], + ImageSize -> { Automatic, $cloudPreferencesHeight }, + Scrollbars -> { None, True } + ]; + +makeScrollableInCloud[ expr_ ] := + Pane @ expr; + +makeScrollableInCloud // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*createTabViewTabs*) @@ -189,7 +195,7 @@ createTabViewTabs // endDefinition; (* ::Subsubsection::Closed:: *) (*createTabViewTab*) createTabViewTab // beginDefinition; -createTabViewTab[ name_String ] := { name, name -> preferencesContent @ name }; +createTabViewTab[ name_String ] := { name, tr[ "PreferencesContent" <> name <> "Tab" ] -> preferencesContent @ name }; createTabViewTab // endDefinition; (* ::**************************************************************************************************************:: *) @@ -258,7 +264,7 @@ createNotebookSettingsPanel[ ] := Enclose[ ]; (* Label for the interface section using a style from SystemDialog.nb: *) - interfaceLabel = subsectionText[ "Chat Notebook Cells" ]; + interfaceLabel = subsectionText @ tr[ "PreferencesContentSubsectionChat" ]; (* Retrieve and confirm the content for the chat notebook interface, ensuring it is not an error from makeInterfaceContent: *) @@ -269,7 +275,7 @@ createNotebookSettingsPanel[ ] := Enclose[ ]; (* Label for the features section using a style from SystemDialog.nb: *) - featuresLabel = subsectionText[ "Features" ]; + featuresLabel = subsectionText @ tr[ "PreferencesContentSubsectionFeatures" ]; (* Retrieve and confirm the content for the chat notebook features, ensuring it is not an error from makeFeaturesContent: *) @@ -369,7 +375,7 @@ makePersonaSelector0[ personas_Association? AssociationQ ] := makePersonaSelector0[ personas: { (_String -> _).. } ] := highlightControl[ Row @ { - "Persona:", + tr[ "PreferencesContentPersonaLabel" ], Spacer[ 3 ], PopupMenu[ scopedDynamic @ CurrentChatSettings[ $preferencesScope, "LLMEvaluator" ], personas ] }, @@ -435,10 +441,10 @@ makeModelSelector0[ services_Association? AssociationQ ] := Enclose[ highlightControl[ Row @ { - highlight[ "LLM Service:", serviceSelector, "ModelService" ], + highlight[ tr[ "PreferencesContentLLMServiceLabel" ], serviceSelector, "ModelService" ], Spacer[ 5 ], highlight[ - "Model:", + tr[ "PreferencesContentModelLabel" ], Dynamic[ If[ state === "Loading" || MatchQ[ modelSelector, _Symbol ], $loadingPopupMenu, modelSelector ], TrackedSymbols :> { state, modelSelector } @@ -485,7 +491,10 @@ makeServiceSelector[ extractServiceName @ CurrentChatSettings[ $preferencesScope, "Model" ], serviceSelectCallback[ Dynamic @ service, Dynamic @ model, Dynamic @ modelSelector, Dynamic @ state ] ], - KeyValueMap[ popupValue[ #1, #2[ "Service" ], #2[ "Icon" ] ] &, services ] + KeyValueMap[ + popupValue[ #1, #2[ "Service" ], #2[ "Icon" ] ] &, + DeleteCases[ services, KeyValuePattern[ "Hidden" -> True ] ] + ] ]; makeServiceSelector // endDefinition; @@ -650,7 +659,7 @@ serviceConnectButton[ Dynamic[ state_ ] ] := Button[ - "Connect for model list", + tr[ "PreferencesContentServiceConnectButton" ], Needs[ "Wolfram`LLMFunctions`" -> None ]; Replace[ (* cSpell: ignore genconerr *) @@ -719,8 +728,8 @@ makeAssistanceCheckbox[ ] := (CurrentChatSettings[ $preferencesScope, "Assistance" ] = #1) & ], infoTooltip[ - "Enable automatic assistance", - "If enabled, automatic AI provided suggestions will be added following evaluation results." + tr[ "PreferencesContentEnableAssistanceLabel" ], + tr[ "PreferencesContentEnableAssistanceTooltip" ] ] ], "Notebooks", @@ -737,7 +746,7 @@ makeTemperatureInput // beginDefinition; makeTemperatureInput[ ] := highlightControl[ prefsInputField[ - "Temperature:", + tr[ "PreferencesContentTemperatureLabel" ], scopedDynamic[ CurrentChatSettings[ $preferencesScope, "Temperature" ], { @@ -767,7 +776,7 @@ makeOpenAICompletionURLInput[ True ] := makeOpenAICompletionURLInput[ False ] := highlightControl[ prefsInputField[ - "Chat Completion URL:", + tr[ "PreferencesContentOpenAICompletionURLLabel" ], scopedDynamic[ (* cSpell: ignore AIAPI *) CurrentChatSettings[ $preferencesScope, "OpenAIAPICompletionURL" ], @@ -825,7 +834,7 @@ makeFormatCheckbox[ ] := highlightControl[ TrueQ @ CurrentChatSettings[ $preferencesScope, "AutoFormat" ], (CurrentChatSettings[ $preferencesScope, "AutoFormat" ] = #1) & ], - "Format chat output" + tr[ "PreferencesContentFormatOutputLabel" ] ], "Notebooks", "AutoFormat" @@ -844,10 +853,7 @@ makeIncludeHistoryCheckbox[ ] := highlightControl[ MatchQ[ CurrentChatSettings[ $preferencesScope, "IncludeHistory" ], True|Automatic ], (CurrentChatSettings[ $preferencesScope, "IncludeHistory" ] = #1) & ], - infoTooltip[ - "Include chat history", - "If enabled, cells preceding the chat input will be included as additional context for the LLM." - ] + infoTooltip[ tr[ "PreferencesContentIncludeHistoryLabel" ], tr[ "PreferencesContentIncludeHistoryTooltip" ] ] ], "Notebooks", "IncludeHistory" @@ -863,7 +869,7 @@ makeChatHistoryLengthInput // beginDefinition; makeChatHistoryLengthInput[ ] := highlightControl[ infoTooltip[ prefsInputField[ - "Chat history length:", + tr[ "PreferencesContentHistoryLengthLabel" ], scopedDynamic[ CurrentChatSettings[ $preferencesScope, "ChatHistoryLength" ], { @@ -876,7 +882,7 @@ makeChatHistoryLengthInput[ ] := highlightControl[ Number, ImageSize -> { 50, Automatic } ], - "Maximum number of cells to include in chat history" + tr[ "PreferencesContentHistoryLengthTooltip" ] ], "Notebooks", "ChatHistoryLength" @@ -895,10 +901,7 @@ makeMergeMessagesCheckbox[ ] := highlightControl[ MatchQ[ CurrentChatSettings[ $preferencesScope, "MergeMessages" ], True|Automatic ], (CurrentChatSettings[ $preferencesScope, "MergeMessages" ] = #1) & ], - infoTooltip[ - "Merge chat messages", - "If enabled, adjacent cells with the same author will be merged into a single chat message." - ] + infoTooltip[ tr[ "PreferencesContentMergeChatLabel" ], tr[ "PreferencesContentMergeChatTooltip" ] ] ], "Notebooks", "MergeMessages" @@ -942,13 +945,13 @@ makeMultimodalMenu[ ] := highlightControl[ Grid[ { { - Style[ "Enable multimodal content: ", "leadinText" ], + Style[ tr[ "PreferencesContentEnableMultimodalLabel" ], "leadinText" ], PopupMenu[ scopedDynamic @ CurrentChatSettings[ $preferencesScope, "Multimodal" ], { - Automatic -> "Automatic by model", - True -> "Always enabled", - False -> "Always disabled" + Automatic -> tr[ "EnabledByModel" ], + True -> tr[ "EnabledAlways" ], + False -> tr[ "EnabledNever" ] }, MenuStyle -> "controlText" ] @@ -972,13 +975,13 @@ makeToolsEnabledMenu[ ] := highlightControl[ Grid[ { { - Style[ "Enable tools: ", "leadinText" ], + Style[ tr[ "PreferencesContentEnableTools" ], "leadinText" ], PopupMenu[ scopedDynamic @ CurrentChatSettings[ $preferencesScope, "ToolsEnabled" ], { - Automatic -> "Automatic by model", - True -> "Always enabled", - False -> "Always disabled" + Automatic -> tr[ "EnabledByModel" ], + True -> tr[ "EnabledAlways" ], + False -> tr[ "EnabledNever" ] }, MenuStyle -> "controlText" ] @@ -1004,7 +1007,7 @@ makeToolCallFrequencySelector[ ] := highlightControl[ Grid[ { { - Style[ "Tool call frequency:", "leadinText" ], + Style[ tr[ "PreferencesContentToolCallFrequency" ], "leadinText" ], PopupMenu[ scopedDynamic[ type, @@ -1020,8 +1023,8 @@ makeToolCallFrequencySelector[ ] := highlightControl[ ] ], { - Automatic -> "Automatic", - "Custom" -> "Custom" + Automatic -> tr[ "Automatic" ], + "Custom" -> tr[ "Custom" ] }, MenuStyle -> "controlText" ], @@ -1032,7 +1035,7 @@ makeToolCallFrequencySelector[ ] := highlightControl[ { { Spacer[ 5 ], - Style[ "Rare", "defaultSubtext" ], + Style[ tr[ "Rare" ], "defaultSubtext" ], Slider[ scopedDynamic[ frequency, @@ -1046,7 +1049,7 @@ makeToolCallFrequencySelector[ ] := highlightControl[ ], ImageSize -> { 100, Automatic } ], - Style[ "Often", "defaultSubtext" ] + Style[ tr[ "Often" ], "defaultSubtext" ] } }, Spacings -> { 0.4, 0.7 } @@ -1085,7 +1088,7 @@ servicesSettingsPanel // beginDefinition; servicesSettingsPanel[ ] := Enclose[ Module[ { settingsLabel, settings, serviceGrid }, - settingsLabel = subsectionText[ "Registered Services" ]; + settingsLabel = subsectionText @ tr[ "PreferencesContentSubsectionRegisteredServices" ]; settings = ConfirmMatch[ makeModelSelector[ ], _Dynamic, "ServicesSettings" ]; serviceGrid = ConfirmMatch[ makeServiceGrid[ ], _Grid, "ServiceGrid" ]; @@ -1115,12 +1118,21 @@ makeServiceGrid // beginDefinition; makeServiceGrid[ ] := Grid[ Join[ - { { Spacer[ 1 ], "Service", SpanFromLeft, "Authentication", "", Spacer[ 1 ] } }, - KeyValueMap[ makeServiceGridRow, $availableServices ] + { + { + Spacer[ 1 ], + tr[ "PreferencesContentService" ], + SpanFromLeft, + tr[ "PreferencesContentAuthentication" ], + "", + Spacer[ 1 ] + } + }, + KeyValueMap[ makeServiceGridRow, DeleteCases[ $availableServices, KeyValuePattern[ "Hidden" -> True ] ] ] ], Alignment -> { Left, Baseline }, Background -> { { }, { GrayLevel[ 0.898 ], { White } } }, - ItemSize -> { { Automatic, Automatic, Scaled[ .3 ], Fit, Automatic }, Automatic }, + ItemSize -> { { Automatic, Automatic, Scaled[ 0.3 ], Fit, Automatic }, Automatic }, Dividers -> { True, All }, FrameStyle -> GrayLevel[ 0.898 ], Spacings -> { Automatic, 0.7 } @@ -1171,7 +1183,7 @@ deleteServiceButton[ service_String ] := Tooltip[ ], $deleteServiceButtonFrameOptions ], - "Unregister service connection" + tr[ "PreferencesContentUnregisterTooltip" ] ]; deleteServiceButton // endDefinition; @@ -1240,7 +1252,7 @@ connectOrDisconnectButton // beginDefinition; connectOrDisconnectButton[ service_String, "None", Dynamic[ display_ ] ] := Button[ - "Connect", + tr[ "ConnectButton" ], display = ProgressIndicator[ Appearance -> "Percolate" ]; clearConnectionCache[ service, False ]; Quiet[ Wolfram`LLMFunctions`APIs`Common`ConnectToService @ service, { ServiceConnect::genconerr } ]; @@ -1250,7 +1262,7 @@ connectOrDisconnectButton[ service_String, "None", Dynamic[ display_ ] ] := connectOrDisconnectButton[ service_String, "SystemCredential"|"Environment"|"ServiceConnect", Dynamic[ display_ ] ] := Button[ - "Disconnect", + tr[ "DisconnectButton" ], display = ProgressIndicator[ Appearance -> "Percolate" ]; disconnectService @ service; createServiceAuthenticationDisplay[ service, Dynamic @ display ], @@ -1731,8 +1743,8 @@ highlightColor // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; End[ ]; diff --git a/Source/Chatbook/Prompting.wl b/Source/Chatbook/Prompting.wl index a6ad8525..78ad36fa 100644 --- a/Source/Chatbook/Prompting.wl +++ b/Source/Chatbook/Prompting.wl @@ -1,14 +1,6 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Prompting`" ]; - -`$basePrompt; -`$basePromptComponents; -`$fullBasePrompt; -`needsBasePrompt; -`removeBasePrompt; -`withBasePromptBuilder; - Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; @@ -40,6 +32,7 @@ $basePromptOrder = { "Checkboxes", "CheckboxesIndeterminate", "ConversionFormatting", + "ExternalLanguageCells", "SpecialURI", "SpecialURIImporting", "SpecialURIAudio", @@ -52,7 +45,9 @@ $basePromptOrder = { "ModernMethods", "FunctionalStyle", "WolframLanguageStyle", - "WolframLanguageEvaluatorTool" + "WolframLanguageEvaluatorTool", + "EndTurnToken", + "EndTurnToolCall" }; $basePromptClasses = <| @@ -85,6 +80,7 @@ $basePromptDependencies = Append[ "GeneralInstructionsHeader" ] /@ <| "MarkdownImageBox" -> { "MessageConversionHeader" }, "MarkdownImageBoxImporting" -> { "MarkdownImageBox" }, "ConversionFormatting" -> { "MessageConversionHeader" }, + "ExternalLanguageCells" -> { "MessageConversionHeader" }, "SpecialURI" -> { }, "SpecialURIImporting" -> { "SpecialURI" }, "SpecialURIAudio" -> { "SpecialURI" }, @@ -96,7 +92,9 @@ $basePromptDependencies = Append[ "GeneralInstructionsHeader" ] /@ <| "ModernMethods" -> { }, "FunctionalStyle" -> { }, "WolframLanguageStyle" -> { "DocumentationLinkSyntax", "InlineSymbolLinks" }, - "WolframLanguageEvaluatorTool" -> { "WolframLanguageStyle" } + "WolframLanguageEvaluatorTool" -> { "WolframLanguageStyle" }, + "EndTurnToken" -> { }, + "EndTurnToolCall" -> { "EndTurnToken" } |>; (* ::**************************************************************************************************************:: *) @@ -201,6 +199,10 @@ $basePromptComponents[ "ConversionFormatting" ] = "\ ``Cell[TextData[{StyleBox[\"Styled\", FontSlant -> \"Italic\"], \" message\"}], \"ChatInput\"]`` \ becomes ``*Styled* message``."; +$basePromptComponents[ "ExternalLanguageCells" ] = "\ + * When you see code blocks denoted with languages other than Wolfram Language, they are external language cells, \ +which is a cell type that evaluates other languages through ExternalEvaluate returning a WL output."; + $basePromptComponents[ "SpecialURI" ] = "\ * You will occasionally see markdown links with special URI schemes, e.g. ![label](scheme://content-id) that represent \ interactive interface elements. You can use these in your responses to display the same elements to the user, but they \ @@ -250,6 +252,12 @@ $basePromptComponents[ "WolframLanguageStyle" ] = " $basePromptComponents[ "WolframLanguageEvaluatorTool" ] = "\ * If the user is asking for a result instead of code to produce that result, use the wolfram_language_evaluator tool"; +$basePromptComponents[ "EndTurnToken" ] = "\ +* Always end your turn by writing /end."; + +$basePromptComponents[ "EndTurnToolCall" ] = "\ +* If you are going to make a tool call, you must do so BEFORE ending your turn."; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Prompt Builder*) @@ -398,8 +406,8 @@ $collectedPromptComponents = AssociationMap[ $fullBasePrompt = $basePrompt; -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; End[ ]; diff --git a/Source/Chatbook/ResourceInstaller.wl b/Source/Chatbook/ResourceInstaller.wl index 685ef8e8..bd6ebcc2 100644 --- a/Source/Chatbook/ResourceInstaller.wl +++ b/Source/Chatbook/ResourceInstaller.wl @@ -11,13 +11,10 @@ BeginPackage[ "Wolfram`Chatbook`ResourceInstaller`" ]; `ResourceInstallLocation; `ResourceUninstall; -`channelCleanup; - Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Dynamics`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; $ContextAliases[ "pi`" ] = "Wolfram`Chatbook`PersonaInstaller`Private`"; @@ -290,7 +287,7 @@ ResourceInstallFromURL[ rtype: $$installableType|Automatic ] := catchMine @ Encl Module[ { url }, url = ConfirmMatch[ - DefinitionNotebookClient`FancyInputString[ "Prompt", "Enter a URL" ], (* FIXME: needs custom dialog *) + DefinitionNotebookClient`FancyInputString[ "Prompt", tr[ "ResourceInstallerFromURLPrompt" ] ], (* FIXME: needs custom dialog *) _String|$Canceled, "InputString" ]; @@ -833,7 +830,7 @@ invalidateCache // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $debug = False; ]; diff --git a/Source/Chatbook/Sandbox.wl b/Source/Chatbook/Sandbox.wl index 44d5f919..be44f2ec 100644 --- a/Source/Chatbook/Sandbox.wl +++ b/Source/Chatbook/Sandbox.wl @@ -1,27 +1,13 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Sandbox`" ]; - -(* cSpell: ignore noinit pacletreadonly playerpass sntx *) +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) (* :!CodeAnalysis::Disable::SuspiciousSessionSymbol:: *) -`$sandboxKernelCommandLine; -`fancyResultQ; -`inlineExpressionURIs; -`preprocessSandboxString; -`sandboxEvaluate; -`sandboxFormatter; -`simpleResultQ; - -Begin[ "`Private`" ]; - -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Formatting`" ]; -Needs[ "Wolfram`Chatbook`Tools`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; $ContextAliases[ "sp`" ] = "Wolfram`Chatbook`SandboxParsing`"; (* :!CodeAnalysis::Disable::UnexpectedLetterlikeCharacter:: *) @@ -36,9 +22,12 @@ $appendURIPrompt := toolOptionValue[ "WolframLanguageEvaluator", "Appen $includeDefinitions := toolOptionValue[ "WolframLanguageEvaluator", "IncludeDefinitions" ]; $sandboxEvaluationTimeout := toolOptionValue[ "WolframLanguageEvaluator", "EvaluationTimeConstraint" ]; $sandboxPingTimeout := toolOptionValue[ "WolframLanguageEvaluator", "PingTimeConstraint" ]; +$evaluatorMethod := toolOptionValue[ "WolframLanguageEvaluator", "Method" ]; $cloudEvaluatorLocation = "/Chatbook/Tools/WolframLanguageEvaluator/Evaluate"; $cloudLineNumber = 1; $cloudSession = None; +$maxSandboxMessages = 10; +$maxMessageParameterLength = 100; (* Tests for expressions that lose their initialized status when sending over a link: *) $initializationTests = Join[ @@ -76,7 +65,7 @@ $initializationTests = Join[ ] ]; - +(* cSpell: ignore noinit, pacletreadonly *) $sandboxKernelCommandLine := StringRiffle @ { ToString[ If[ $OperatingSystem === "Windows", @@ -264,6 +253,7 @@ startSandboxKernel[ ] := Enclose[ Scan[ LinkClose, Select[ Links[ ], sandboxKernelQ ] ]; + (* cSpell: ignore playerpass *) (* pwFile = FileNameJoin @ { $InstallationDirectory, "Configuration", "Licensing", "playerpass" }; *) kernel = ConfirmMatch[ LinkLaunch @ $sandboxKernelCommandLine, _LinkObject, "LinkLaunch" ]; @@ -449,11 +439,13 @@ sandboxEvaluate // beginDefinition; sandboxEvaluate[ KeyValuePattern[ "code" -> code_ ] ] := sandboxEvaluate @ code; sandboxEvaluate[ code_String ] := sandboxEvaluate @ toSandboxExpression @ code; sandboxEvaluate[ HoldComplete[ xs__, x_ ] ] := sandboxEvaluate @ HoldComplete @ CompoundExpression[ xs, x ]; -sandboxEvaluate[ HoldComplete[ evaluation_ ] ] /; $CloudEvaluation := cloudSandboxEvaluate @ HoldComplete @ evaluation; +sandboxEvaluate[ HoldComplete[ eval_ ] ] /; useCloudSandboxQ[ ] := cloudSandboxEvaluate @ HoldComplete @ eval; +sandboxEvaluate[ HoldComplete[ eval_ ] ] /; useSessionQ[ ] := sessionEvaluate @ HoldComplete @ eval; sandboxEvaluate[ HoldComplete[ evaluation_ ] ] := Enclose[ Module[ { kernel, null, packets, $sandboxTag, $timedOut, $kernelQuit, results, flat, initialized, final }, + $lastSandboxMethod = "Local"; $lastSandboxEvaluation = HoldComplete @ evaluation; kernel = ConfirmMatch[ getSandboxKernel[ ], _LinkObject, "GetKernel" ]; @@ -522,11 +514,31 @@ sandboxEvaluate[ HoldComplete[ evaluation_ ] ] := Enclose[ final[ "String" ] ] ], - throwInternalFailure[ sandboxEvaluate @ HoldComplete @ evaluation, ## ] & + throwInternalFailure ]; sandboxEvaluate // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*useCloudSandboxQ*) +useCloudSandboxQ // beginDefinition; +useCloudSandboxQ[ ] := useCloudSandboxQ @ $evaluatorMethod; +useCloudSandboxQ[ "Cloud" ] := True; +useCloudSandboxQ[ $$unspecified ] := TrueQ @ $CloudEvaluation; +useCloudSandboxQ[ _ ] := False; +useCloudSandboxQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*useSessionQ*) +useSessionQ // beginDefinition; +useSessionQ[ ] := useSessionQ @ $evaluatorMethod; +useSessionQ[ "Session"|None ] := True; +useSessionQ[ $$unspecified ] := False; +useSessionQ[ _ ] := False; +useSessionQ // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*deserializePacket*) @@ -548,6 +560,7 @@ cloudSandboxEvaluate // beginDefinition; cloudSandboxEvaluate[ HoldComplete[ evaluation_ ] ] := Enclose[ Catch @ Module[ { api, held, wxf, definitions, response, result, packets, initialized }, + $lastSandboxMethod = "Cloud"; $lastSandboxEvaluation = HoldComplete @ evaluation; api = ConfirmMatch[ getCloudEvaluatorAPI[ ], _CloudObject|_Failure, "CloudEvaluator" ]; @@ -727,6 +740,53 @@ deployCloudEvaluator[ target_CloudObject ] := With[ { messages = $messageOverrid deployCloudEvaluator // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*sessionEvaluate*) +sessionEvaluate // beginDefinition; + +sessionEvaluate[ HoldComplete[ eval0_ ] ] := Enclose[ + Module[ { response, eval, result, packets, initialized }, + + $lastSandboxMethod = "Session"; + $lastSandboxEvaluation = HoldComplete @ eval0; + + response = $Failed; + eval = makeLinkWriteEvaluation @ eval0; + + With[ { held = eval, tc = $sandboxEvaluationTimeout }, + response = evaluationData[ + HoldComplete @@ { + TimeConstrained[ + ReleaseHold @ held, + tc, + Failure[ + "EvaluationTimeExceeded", + <| + "MessageTemplate" -> "Evaluation exceeded the `1` second time limit.", + "MessageParameters" -> { tc } + |> + ] + ] + } + ] + ]; + + result = HoldComplete @@ ConfirmMatch[ Lookup[ response, "Result" ], _HoldComplete|_Hold, "Result" ]; + packets = TextPacket /@ response[ "OutputLog" ]; + initialized = result; + + $lastSandboxResult = <| + "String" -> sandboxResultString[ initialized, packets ], + "Result" -> sandboxResult @ initialized, + "Packets" -> packets + |> + ], + throwInternalFailure +]; + +sessionEvaluate // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*initializeExpressions*) @@ -1061,6 +1121,373 @@ sandboxStringNormalize // beginDefinition; sandboxStringNormalize[ s_String ] := s; sandboxStringNormalize // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*evaluationData*) +evaluationData // beginDefinition; +evaluationData // Attributes = { HoldAllComplete }; + +evaluationData[ eval_ ] := Enclose[ + Module[ { outputs, result, stopped, $fail }, + $suppressMessageCollection = False; + outputs = Internal`Bag[ ]; + result = $fail; + stopped = <| |>; + Internal`HandlerBlock[ + { "Message", evaluationMessageHandler[ stopped, outputs ] }, + Internal`HandlerBlock[ + { "Wolfram.System.Print.Veto", evaluationPrintHandler @ outputs }, + result = Quiet @ Quiet[ catchEverything @ eval, $stackTag::begin ] + ] + ]; + ConfirmAssert[ result =!= $fail, "EvaluationFailure" ]; + setOutput @ result; + ConfirmBy[ makeEvaluationResultData[ result, outputs ], AssociationQ, "ResultData" ] + ], + throwInternalFailure +]; + +evaluationData // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*setOutput*) +setOutput // beginDefinition; +setOutput // Attributes = { SequenceHold }; + +setOutput[ HoldComplete[ KeyValuePattern[ "Result" -> HoldComplete[ result_ ] ] ] ] := + setOutput[ Replace[ $Line, Except[ _Integer ] :> 1 ], HoldComplete @ result ]; + +setOutput[ HoldComplete[ fail_Failure ] ] := + setOutput[ Replace[ $Line, Except[ _Integer ] :> 1 ], HoldComplete @ fail ]; + +setOutput[ line_Integer, HoldComplete[ result___ ] ] := + WithCleanup[ + Unprotect @ Out, + Out[ line ] := result, + Protect @ Out; + $Line = line + 1 + ]; + +setOutput // endDefinition; + +(* TODO: Should probably also set things like In[], InString[], etc. *) + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*evaluationPrintHandler*) +evaluationPrintHandler // beginDefinition; +evaluationPrintHandler[ out_Internal`Bag ] := evaluationPrintHandler[ out, # ] &; +evaluationPrintHandler[ out_Internal`Bag, output_ ] := (Internal`StuffBag[ out, makePrintText @ output ]; False); +evaluationPrintHandler // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makePrintText*) +makePrintText // beginDefinition; +makePrintText[ out_ ] := makePrintText[ Replace[ $Line, Except[ _Integer ] :> 1 ], out ]; +makePrintText[ n_Integer, out_ ] := makePrintText[ "During evaluation of In[" <> ToString @ n <> "]:= ", out ]; +makePrintText[ lbl_String, HoldComplete[ out__ ] ] := StringJoin[ lbl, ToString @ Unevaluated @ SequenceForm @ out ]; +makePrintText[ lbl_, HoldComplete[ ] ] := ""; +makePrintText // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*evaluationMessageHandler*) +evaluationMessageHandler // beginDefinition; +evaluationMessageHandler // Attributes = { HoldFirst }; +(* `stopped` is a held association that's used to mark messages that have triggered a `General::stop`, and `outputs` + contains the message and print text to be inserted into to the tool output for the LLM. *) +evaluationMessageHandler[ stopped_, outputs_ ] := evaluationMessageHandler0[ stopped, outputs, # ] &; +evaluationMessageHandler // endDefinition; + + +evaluationMessageHandler0 // beginDefinition; +evaluationMessageHandler0 // Attributes = { HoldFirst }; + +(* Message is not from LLM code or we've collected too many, so we don't want to insert it into the tool response: *) +evaluationMessageHandler0[ _, _, _ ] /; $suppressMessageCollection := Null; + +(* cSpell: ignore newsym *) +(* Messages that are so frequent we don't want to waste time analyzing them: *) +evaluationMessageHandler0[ _, _, Hold[ Message[ $CharacterEncoding::utf8 | General::newsym, ___ ], _ ] ] := Null; + +(* Message already triggered a General::stop, so do nothing: *) +evaluationMessageHandler0[ stopped_, outputs_, Hold[ Message[ mn_, ___ ], _ ] ] /; stopped @ HoldComplete @ mn := Null; + +(* Message is locally quiet, so do nothing: *) +evaluationMessageHandler0[ _, _, Hold[ message_? messageQuietedQ, _ ] ] := Null; + +(* Message has triggered a `General::stop`, but it's locally quiet, so mark it and otherwise do nothing: *) +evaluationMessageHandler0[ stopped_, _, Hold[ Message[ General::stop, HoldForm[ msg_? messageQuietedQ ] ], _ ] ] := ( + stopped[ HoldComplete @ msg ] = True; + Null +); + +(* Already collected the max number of messages, so do nothing: *) +evaluationMessageHandler0[ _, outputs_Internal`Bag, _ ] /; Internal`BagLength @ outputs > $maxSandboxMessages := ( + $suppressMessageCollection = True; + Null +); + +(* Otherwise, collect message text: *) +evaluationMessageHandler0[ stopped_, outputs_, Hold[ message_, _ ] ] := + Block[ { $suppressMessageCollection = True }, (* Any messages occurring in here are not from LLM code *) + (* If message is General::stop, tag the message in its argument as stopped so it won't be collected again: *) + checkMessageStop[ stopped, message ]; + (* Create message text and save it: *) + Internal`StuffBag[ outputs, makeMessageText @ message ] + ]; + +evaluationMessageHandler0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*checkMessageStop*) +checkMessageStop // beginDefinition; +checkMessageStop // Attributes = { HoldAllComplete }; +checkMessageStop[ stopped_, Message[ General::stop, HoldForm[ stop_ ] ] ] := stopped[ HoldComplete @ stop ] = True; +checkMessageStop[ stopped_, _Message ] := Null; +checkMessageStop // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makeMessageText*) +makeMessageText // beginDefinition; +makeMessageText // Attributes = { HoldAllComplete }; + +makeMessageText[ Message[ mn: MessageName[ sym_Symbol, tag__String ], args0___ ] ] := + Module[ { template, label, args }, + template = SelectFirst[ { messageOverrideTemplate @ mn, mn, MessageName[ General, tag ] }, StringQ ]; + label = ToString @ Unevaluated @ mn; + args = HoldForm /@ Unevaluated @ { args0 }; + If[ StringQ @ template, + applyMessageTemplate[ label, template, args ], + undefinedMessageText[ label, args ] + ] + ]; + +makeMessageText // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*messageOverrideTemplate*) +messageOverrideTemplate // beginDefinition; +messageOverrideTemplate // Attributes = { HoldAllComplete }; +messageOverrideTemplate[ mn_MessageName ] := Lookup[ $messageOverrideTemplates, HoldComplete @ mn ]; +messageOverrideTemplate // endDefinition; + + +$messageOverrideTemplates := $messageOverrideTemplates = Association @ Cases[ + $messageOverrides, + HoldPattern[ mn_MessageName = template_String ] :> (HoldComplete @ mn -> template) +]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*applyMessageTemplate*) +applyMessageTemplate // beginDefinition; + +applyMessageTemplate[ label_String, template_String, args_List ] := + label <> ": " <> ToString @ StringForm[ template, Sequence @@ shortenMessageParameters @ args ]; + +applyMessageTemplate // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*shortenMessageParameters*) +shortenMessageParameters // beginDefinition; +shortenMessageParameters // Attributes = { HoldAllComplete }; +shortenMessageParameters[ { } ] := { }; +shortenMessageParameters[ args_List ] := shortenMessageParameter[ countLargeParameters @ args ] /@ Unevaluated @ args; +shortenMessageParameters // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*countLargeParameters*) +countLargeParameters // beginDefinition; +countLargeParameters // Attributes = { HoldFirst }; +countLargeParameters[ { } ] := 0; +countLargeParameters[ { args__ } ] := Length @ Select[ HoldComplete @ args, largeParameterQ ]; +countLargeParameters // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*largeParameterQ*) +largeParameterQ // beginDefinition; +largeParameterQ[ _String ] := True; +largeParameterQ[ $$atomic ] := False; +largeParameterQ[ HoldForm[ expr_ ] ] := largeParameterQ @ expr; +largeParameterQ[ _ ] := True; +largeParameterQ // Attributes = { HoldAllComplete }; +largeParameterQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*shortenMessageParameter*) +shortenMessageParameter // beginDefinition; + +shortenMessageParameter[ count_Integer? NonNegative ] := + With[ { len = Max[ 50, Ceiling[ $maxMessageParameterLength / Max[ 1, count ] ] ] }, + Function[ Null, shortenMessageParameter[ len, Unevaluated @ # ], HoldAllComplete ] + ]; + +shortenMessageParameter[ len_Integer? NonNegative, expr_ ] := + ToString[ Unevaluated @ Short @ expr, PageWidth -> len ]; + +shortenMessageParameter // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*undefinedMessageText*) +undefinedMessageText // beginDefinition; + +undefinedMessageText[ label_String, { args___ } ] := StringJoin[ + label, + ": ", + "-- Message text not found -- ", + "(" <> ToString[ # ] <> ")" & /@ { args } +]; + +undefinedMessageText // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*messageQuietedQ*) +messageQuietedQ // beginDefinition; +messageQuietedQ // Attributes = { HoldAllComplete }; + +messageQuietedQ[ Message[ msg_, ___ ] ] := + messageQuietedQ @ msg; + +messageQuietedQ[ msg: MessageName[ _Symbol, tag___ ] ] := + With[ { msgEval = msg }, + TrueQ @ Or[ + MatchQ[ msgEval, _$Off ], + inheritingOffQ[ msgEval, tag ], + messageQuietedQ0 @ msg + ] + ]; + +messageQuietedQ // endDefinition; + + +messageQuietedQ0 // beginDefinition; +messageQuietedQ0 // Attributes = { HoldAllComplete }; + +messageQuietedQ0[ msg: MessageName[ _Symbol, tag___ ] ] := + Module[ { stack, msgOrGeneral, msgPatt }, + + stack = localStack @ Lookup[ Internal`QuietStatus[ ], Stack ]; + msgOrGeneral = generalMessagePattern @ msg; + msgPatt = All | { ___, msgOrGeneral, ___ }; + + TrueQ @ And[ + (* check if msg is unquieted via third arg of Quiet: *) + FreeQ[ stack, { _, _, msgPatt }, 2 ], + (* check if msg is not quieted via second arg of Quiet: *) + ! FreeQ[ stack, { _, msgPatt, _ }, 2 ] + ] + ]; + +messageQuietedQ0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*inheritingOffQ*) +inheritingOffQ // beginDefinition; +inheritingOffQ[ _String, ___ ] := False; +inheritingOffQ[ msg_, tag_ ] := MatchQ[ MessageName[ General, tag ], _$Off ]; +inheritingOffQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*localStack*) +localStack // beginDefinition; +localStack[ HoldForm @ { ___, { ___, { $stackTag::begin }, ___ }, stack___ } ] := localStack @ HoldForm @ { stack }; +localStack[ HoldForm @ { stack___, { ___, { $stackTag::end }, ___ }, ___ } ] := localStack @ HoldForm @ { stack }; +localStack[ stack_ ] := stack; +localStack // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*generalMessagePattern*) +generalMessagePattern // beginDefinition; +generalMessagePattern // Attributes = { HoldAllComplete }; + +generalMessagePattern[ msg: MessageName[ _Symbol, tag___ ] ] := + If[ StringQ @ msg, + HoldPattern @ msg, + HoldPattern[ msg | MessageName[ General, tag ] ] + ]; + +generalMessagePattern // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*catchEverything*) +catchEverything // beginDefinition; +catchEverything // Attributes = { HoldAllComplete }; +catchEverything[ e_ ] := catchEverything0 @ CheckAbort[ Catch @ Catch[ contained @ e, _, uncaughtThrow ], $Aborted ]; +catchEverything // endDefinition; + + +catchEverything0 // beginDefinition; +catchEverything0 // Attributes = { SequenceHold }; + +catchEverything0[ contained[ result___ ] ] := + result; + +catchEverything0[ $Aborted ] := + makeHeldResultAssociation @ $Aborted; + +catchEverything0[ uncaughtThrow[ uncaught__ ] ] := ( + Message[ Throw::nocatch, HoldForm @ Throw @ uncaught ]; + makeHeldResultAssociation @ Hold @ Throw @ uncaught +); + +catchEverything0[ uncaught_ ] := + catchEverything0 @ uncaughtThrow @ uncaught; + +catchEverything0[ uncaught___ ] := + catchEverything0 @ uncaughtThrow @ Sequence @ uncaught; + +catchEverything0 // endDefinition; + +(* TODO: Figure out a reliable way to intercept Exit and Quit. + Note: Quit is locked in cloud, so we can't use a Block to redefine it. *) + +contained // Attributes = { SequenceHold }; +uncaughtThrow // Attributes = { HoldAllComplete }; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makeHeldResultAssociation*) +makeHeldResultAssociation // beginDefinition; +makeHeldResultAssociation // Attributes = { HoldAllComplete }; + +makeHeldResultAssociation[ e_ ] := + HoldComplete @@ { <| "Line" -> $Line, "Result" -> HoldComplete @ e, "Initialized" -> { } |> }; + +makeHeldResultAssociation // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makeEvaluationResultData*) +makeEvaluationResultData // beginDefinition; +makeEvaluationResultData // Attributes = { SequenceHold }; + +makeEvaluationResultData[ result_, outputs_Internal`Bag ] := + makeEvaluationResultData[ result, Internal`BagPart[ outputs, All ] ]; + +makeEvaluationResultData[ result_, outputs: { ___String } ] := + <| + "Result" :> result, + "OutputLog" -> outputs + |>; + +makeEvaluationResultData // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*linkWriteEvaluation*) @@ -1270,8 +1697,7 @@ addMessageHandler[ HoldComplete[ eval_ ] ] := eval ], (* cSpell: ignore usenl *) - If[ $issueNLMessage, Message[ General::usenl, $nlMessageType ] ]; - If[ MatchQ[ $MessageList, { __ } ], Message[ General::messages ] ] + If[ $issueNLMessage, Message[ General::usenl, $nlMessageType ] ] ] ] ]; @@ -1308,7 +1734,10 @@ sandboxResult // endDefinition; (* ::Subsection::Closed:: *) (*sandboxResultString*) sandboxResultString // beginDefinition; -sandboxResultString[ result_, packets_ ] := checkDocSearchMessageStrings @ sandboxResultString0[ result, packets ]; + +sandboxResultString[ result_, packets_ ] := + mergeComments @ appendRetryNotice @ checkDocSearchMessageStrings @ sandboxResultString0[ result, packets ]; + sandboxResultString // endDefinition; @@ -1354,6 +1783,39 @@ sandboxResultString0[ HoldComplete[ ] ] := "Null"; sandboxResultString0 // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*mergeComments*) +mergeComments // beginDefinition; + +mergeComments[ string_String ] := StringReplace[ + string, + { + "*)" ~~ WhitespaceCharacter... ~~ "\n" ~~ WhitespaceCharacter... ~~ "(*" -> "\n\n", + "*)" ~~ WhitespaceCharacter... ~~ "(*" -> "\n" + } +]; + +mergeComments // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*appendRetryNotice*) +appendRetryNotice // beginDefinition; + +appendRetryNotice[ string_String ] := + If[ StringContainsQ[ string, "General::messages" ], + string<>"\n\n"<>$retryMessage, + string + ]; + +appendRetryNotice // endDefinition; + +$retryMessage = "(* \ +IMPORTANT! If this tool call failed to provide the desired result for any reason, \ +you MUST write /retry before making the next tool call. \ +*)"; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*appendURIInstructions*) @@ -1365,9 +1827,27 @@ appendURIInstructions[ as: KeyValuePattern @ { "String" -> s_, "Result" -> expr_ appendURIInstructions[ string_String, expr_ ] /; $appendURIPrompt := appendURIInstructions0[ string, expr ]; -appendURIInstructions[ string_String, _ ] := +appendURIInstructions[ string_String, HoldComplete[ e_? simpleFormattingQ ] ] := string; +appendURIInstructions[ string_String, HoldComplete[ ___, expr_ ] ] := Enclose[ + Module[ { uri, key }, + uri = ConfirmBy[ + makeExpressionURI[ "expression", "Formatted Result", Unevaluated @ expr ], + StringQ, + "ExpressionURI" + ]; + + key = ConfirmBy[ expressionURIKey @ uri, StringQ, "ExpressionURIKey" ]; + + If[ StringContainsQ[ string, key ], + string, + string <> "\n\n(* "<> uri <>" *)" + ] + ], + throwInternalFailure +]; + appendURIInstructions // endDefinition; @@ -1416,7 +1896,7 @@ appendURIQ // Attributes = { HoldAllComplete }; appendURIQ[ expr_ ] := TrueQ @ Or[ ByteCount @ Unevaluated @ expr > 500, graphicsQ @ Unevaluated @ expr, - ! FreeQ[ Unevaluated @ expr, _Quantity|_Entity|_EntityClass|_EntityProperty|_DateObject ] + ! simpleFormattingQ @ expr ]; appendURIQ // endDefinition; @@ -1430,8 +1910,8 @@ checkDocSearchMessageStrings[ string_String ] := StringDelete[ string, $docSearc checkDocSearchMessageStrings // endDefinition; $docSearchMessageStrings = { - " Use the documentation_searcher tool to find solutions.", - " Use the documentation_searcher tool to find alternatives." + " Use the documentation searcher tool to find solutions.", + " Use the documentation searcher tool to find alternatives." }; (* ::**************************************************************************************************************:: *) @@ -1459,6 +1939,21 @@ simpleResultQ // Attributes = { HoldAllComplete }; simpleResultQ[ expr_ ] := FreeQ[ Unevaluated @ expr, _? fancyResultQ ]; simpleResultQ // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*simpleFormattingQ*) +simpleFormattingQ // beginDefinition; +simpleFormattingQ // Attributes = { HoldAllComplete }; +simpleFormattingQ[ _String ] := True; +simpleFormattingQ[ e_ ] := simpleFormattingQ[ HoldPattern @ Verbatim[ e ] ] = simpleFormattingQ0 @ MakeBoxes @ e; +simpleFormattingQ // endDefinition; + +simpleFormattingQ0 // beginDefinition; +simpleFormattingQ0[ _String ] := True; +simpleFormattingQ0[ RowBox[ boxes_List ] ] := AllTrue[ boxes, simpleFormattingQ0 ]; +simpleFormattingQ0[ ___ ] := False; +simpleFormattingQ0 // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*fancyResultQ*) @@ -1471,14 +1966,49 @@ fancyResultQ // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*makePacketMessages*) -$$noMessagePacket = _InputNamePacket|_MessagePacket|_OutputNamePacket|_ReturnExpressionPacket|_LinkRead|$Failed; - makePacketMessages // beginDefinition; -makePacketMessages[ line_, packets_List ] := makePacketMessages[ line, # ] & /@ packets; -makePacketMessages[ line_String, TextPacket[ text_String ] ] := text; -makePacketMessages[ line_, $$noMessagePacket ] := Nothing; + +makePacketMessages[ line_, packets_List ] := Enclose[ + Module[ { strings }, + $appendGeneralMessage = False; + strings = ConfirmMatch[ makePacketMessage /@ packets, { ___String }, "Strings" ]; + If[ ConfirmBy[ $appendGeneralMessage, BooleanQ, "AppendGeneralMessage" ], + Append[ strings, ConfirmBy[ $generalMessageText, StringQ, "GeneralMessage" ] ], + strings + ] + ], + throwInternalFailure +]; + makePacketMessages // endDefinition; + +$generalMessageText := Enclose[ + Module[ { string }, + string = ConfirmBy[ $messageOverrideTemplates[ HoldComplete[ General::messages ] ], StringQ, "String" ]; + $generalMessageText = "General::messages: " <> string + ], + throwInternalFailure @ $generalMessageText & +]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*makePacketMessage*) +$$noMessagePacket = _InputNamePacket|_MessagePacket|_OutputNamePacket|_ReturnExpressionPacket|_LinkRead|$Failed; + +makePacketMessage // beginDefinition; +makePacketMessage[ $$noMessagePacket ] := Nothing; +makePacketMessage[ TextPacket[ text_ ] ] := makePacketMessage @ text; + +makePacketMessage[ text_String ] := + If[ StringStartsQ[ text, Except[ WhitespaceCharacter ].. ~~ "::" ~~ Except[ WhitespaceCharacter ].. ], + $appendGeneralMessage = True; + text, + text + ]; + +makePacketMessage // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*sandboxFormatter*) @@ -1575,25 +2105,34 @@ smallBoxesQ // endDefinition; (*expandNLInputBoxes*) expandNLInputBoxes // beginDefinition; -expandNLInputBoxes[ code_String ] := expandNLInputBoxes @ stringToBoxes @ code; - -expandNLInputBoxes[ boxes_ ] := boxes /. { - RowBox @ { "\[FreeformPrompt]", "[", b__, "]" } :> With[ - { e = Quiet @ ToExpression[ RowBox @ { "HoldComplete", "[", b, "]" }, StandardForm, expandNLInputBoxes0 ] }, - e /; ! FailureQ @ e - ] -}; +expandNLInputBoxes[ boxes0_ ] := + Module[ { boxes }, + boxes = If[ StringQ @ boxes0, stringToBoxes @ boxes0, boxes0 ]; + boxes /. RowBox @ { "\[FreeformPrompt]", "[", b__, "]" } :> + With[ { expanded = expandNLInputBoxes0 @ b }, expanded /; ! FailureQ @ expanded ] + ]; expandNLInputBoxes // endDefinition; expandNLInputBoxes0 // beginDefinition; -expandNLInputBoxes0[ HoldComplete[ q_String ] ] := expandNLInputBoxes0 @ SandboxLinguisticAssistantData @ q; -expandNLInputBoxes0[ HoldComplete[ q_String, p_ ] ] := expandNLInputBoxes0 @ SandboxLinguisticAssistantData[ q, p ]; -expandNLInputBoxes0[ KeyValuePattern[ "Parse" -> HoldComplete[ expr_ ] ] ] := MakeBoxes @ expr; -expandNLInputBoxes0[ _ ] := $Failed; + +expandNLInputBoxes0[ boxes__ ] := Quiet @ ToExpression[ + RowBox @ { "System`HoldComplete", "[", boxes, "]" }, + StandardForm, + expandNLInputBoxes1 +]; + expandNLInputBoxes0 // endDefinition; + +expandNLInputBoxes1 // beginDefinition; +expandNLInputBoxes1[ HoldComplete[ q_String ] ] := expandNLInputBoxes1 @ SandboxLinguisticAssistantData @ q; +expandNLInputBoxes1[ HoldComplete[ q_String, p_ ] ] := expandNLInputBoxes1 @ SandboxLinguisticAssistantData[ q, p ]; +expandNLInputBoxes1[ KeyValuePattern[ "Parse" -> HoldComplete[ expr_ ] ] ] := MakeBoxes @ expr; +expandNLInputBoxes1[ _ ] := $Failed; +expandNLInputBoxes1 // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*AppendURIInstructions*) @@ -1608,9 +2147,11 @@ AppendURIInstructions // endExportedDefinition; (* Close previous sandbox kernel if package is being reloaded: *) Scan[ LinkClose, Select[ Links[ ], sandboxKernelQ ] ]; -If[ Wolfram`ChatbookInternal`$BuildingMX, - $messageOverrides; +addToMXInitialization[ + $generalMessageText; $initializationTest; + $messageOverrides; + $messageOverrideTemplates; ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/SendChat.wl b/Source/Chatbook/SendChat.wl index 5eea9e97..8c78060e 100644 --- a/Source/Chatbook/SendChat.wl +++ b/Source/Chatbook/SendChat.wl @@ -1,42 +1,15 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`SendChat`" ]; - -(* cSpell: ignore evaliator *) +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -HoldComplete[ - `$debugLog; - `chatHandlerFunctionsKeys; - `dynamicAutoFormatQ; - `makeOutputDingbat; - `scrollOutputQ; - `sendChat; - `toImageURI; - `writeReformattedCell; -]; - -Begin[ "`Private`" ]; - -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Actions`" ]; -Needs[ "Wolfram`Chatbook`ChatGroups`" ]; -Needs[ "Wolfram`Chatbook`ChatHistory`" ]; -Needs[ "Wolfram`Chatbook`ChatMessages`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Formatting`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`Handlers`" ]; -Needs[ "Wolfram`Chatbook`InlineReferences`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; -Needs[ "Wolfram`Chatbook`Personas`" ]; -Needs[ "Wolfram`Chatbook`Prompting`" ]; -Needs[ "Wolfram`Chatbook`Serialization`" ]; -Needs[ "Wolfram`Chatbook`Services`" ]; -Needs[ "Wolfram`Chatbook`Settings`" ]; -Needs[ "Wolfram`Chatbook`Tools`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Actions`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`Personas`" ]; +Needs[ "Wolfram`Chatbook`Serialization`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -85,11 +58,13 @@ sendChat[ evalCell_, nbo_, settings0_ ] /; $useLLMServices := catchTopAs[ Chatbo "HistoryAndTarget" ]; + $finishReason = None; $multimodalMessages = TrueQ @ settings[ "Multimodal" ]; $chatIndicatorSymbol = chatIndicatorSymbol @ settings; If[ TrueQ @ settings[ "EnableChatGroupSettings" ], - AppendTo[ settings, "ChatGroupSettings" -> getChatGroupSettings @ evalCell ] + AppendTo[ settings, "ChatGroupSettings" -> getChatGroupSettings @ evalCell ]; + $currentChatSettings = settings; ]; If[ ! settings[ "IncludeHistory" ], cells = { evalCell } ]; @@ -110,7 +85,8 @@ sendChat[ evalCell_, nbo_, settings0_ ] /; $useLLMServices := catchTopAs[ Chatbo If[ AssociationQ @ settings[ "LLMEvaluator" ], settings[ "LLMEvaluator" ] = Association[ settings[ "LLMEvaluator" ], persona ], settings = Association[ settings, persona ] - ] + ]; + $currentChatSettings = settings; ]; AppendTo[ settings, "Data" -> data ]; @@ -177,7 +153,7 @@ sendChat[ evalCell_, nbo_, settings0_ ] /; $useLLMServices := catchTopAs[ Chatbo task ], - throwInternalFailure[ sendChat[ evalCell, nbo, settings0 ], ## ] & + throwInternalFailure ]; @@ -201,11 +177,13 @@ sendChat[ evalCell_, nbo_, settings0_ ] := catchTopAs[ ChatbookAction ] @ Enclos "HistoryAndTarget" ]; + $finishReason = None; $multimodalMessages = TrueQ @ settings[ "Multimodal" ]; $chatIndicatorSymbol = chatIndicatorSymbol @ settings; If[ TrueQ @ settings[ "EnableChatGroupSettings" ], - AppendTo[ settings, "ChatGroupSettings" -> getChatGroupSettings @ evalCell ] + AppendTo[ settings, "ChatGroupSettings" -> getChatGroupSettings @ evalCell ]; + $currentChatSettings = settings; ]; id = Lookup[ settings, "ID" ]; @@ -233,7 +211,8 @@ sendChat[ evalCell_, nbo_, settings0_ ] := catchTopAs[ ChatbookAction ] @ Enclos If[ AssociationQ @ settings[ "LLMEvaluator" ], settings[ "LLMEvaluator" ] = Association[ settings[ "LLMEvaluator" ], persona ], settings = Association[ settings, persona ] - ] + ]; + $currentChatSettings = settings; ]; AppendTo[ settings, "Data" -> data ]; @@ -300,7 +279,7 @@ sendChat[ evalCell_, nbo_, settings0_ ] := catchTopAs[ ChatbookAction ] @ Enclos task ], - throwInternalFailure[ sendChat[ evalCell, nbo, settings0 ], ## ] & + throwInternalFailure ]; sendChat // endDefinition; @@ -337,14 +316,7 @@ makeHTTPRequest[ settings_Association? AssociationQ, messages: { __Association } "presence_penalty" -> presPenalty, "model" -> toModelName @ model, "stream" -> stream, - "stop" -> Select[ - DeleteDuplicates @ Flatten @ { - settings[ "StopTokens" ], - If[ settings[ "ToolMethod" ] === "Simple", { "\n/exec" }, "ENDTOOLCALL" ], - If[ TrueQ @ $AutomaticAssistance, "[INFO]", Nothing ] - }, - StringQ - ] + "stop" -> makeStopTokens @ settings |>, Automatic|_Missing ]; @@ -367,6 +339,23 @@ makeHTTPRequest[ settings_Association? AssociationQ, messages: { __Association } makeHTTPRequest // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makeStopTokens*) +makeStopTokens // beginDefinition; + +makeStopTokens[ settings_Association ] := + Select[ + DeleteDuplicates @ Flatten @ { + settings[ "StopTokens" ], + If[ settings[ "ToolMethod" ] === "Simple", { "\n/exec", "/end" }, { "ENDTOOLCALL", "/end" } ], + If[ TrueQ @ $AutomaticAssistance, "[INFO]", Nothing ] + }, + StringQ + ]; + +makeStopTokens // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*chatIndicatorSymbol*) @@ -517,7 +506,7 @@ chatSubmit // beginDefinition; chatSubmit // Attributes = { HoldFirst }; chatSubmit[ args__ ] := Quiet[ - chatSubmit0 @ args, + rasterizeBlock @ chatSubmit0 @ args, { (* cSpell: ignore wname, invm, invk *) ServiceConnections`SavedConnections::wname, @@ -594,21 +583,10 @@ makeLLMConfiguration // beginDefinition; makeLLMConfiguration[ as: KeyValuePattern[ "Model" -> model_String ] ] := makeLLMConfiguration @ Append[ as, "Model" -> { "OpenAI", model } ]; -(* FIXME: get valid claude keys using the following patterns: -ServiceConnectionUtilities`ConnectionInformation["Anthropic", "ProcessedRequests", "Chat", "Parameters"] -*) - makeLLMConfiguration[ as_Association ] := $lastLLMConfiguration = LLMConfiguration @ Association[ KeyTake[ as, { "Model", "MaxTokens", "Temperature", "PresencePenalty" } ], - "StopTokens" -> Select[ - DeleteDuplicates @ Flatten @ { - as[ "StopTokens" ], - If[ as[ "ToolMethod" ] === "Simple", { "\n/exec" }, "ENDTOOLCALL" ], - If[ TrueQ @ $AutomaticAssistance, "[INFO]", Nothing ] - }, - StringQ - ] + "StopTokens" -> makeStopTokens @ as ]; makeLLMConfiguration // endDefinition; @@ -639,7 +617,8 @@ chatHandlers[ container_, cellObject_, settings_ ] := dynamicSplit = dynamicSplitQ @ settings, handlers = getHandlerFunctions @ settings, useTasks = feTaskQ @ settings, - toolFormatter = getToolFormatter @ settings + toolFormatter = getToolFormatter @ settings, + stop = makeStopTokens @ settings }, { bodyChunkHandler = Lookup[ handlers, "BodyChunkReceived", None ], @@ -659,6 +638,7 @@ chatHandlers[ container_, cellObject_, settings_ ] := }, bodyChunkHandler[ #1 ]; Internal`StuffBag[ $debugLog, $lastStatus = #1 ]; + checkFinishReason[ #1 ]; writeChunk[ Dynamic @ container, cellObject, #1 ] ] ], @@ -674,7 +654,9 @@ chatHandlers[ container_, cellObject_, settings_ ] := }, taskFinishedHandler[ #1 ]; Internal`StuffBag[ $debugLog, $lastStatus = #1 ]; + checkFinishReason[ #1 ]; logUsage @ container; + trimStopTokens[ container, stop ]; checkResponse[ $settings, Unevaluated @ container, cellObject, #1 ] ] ] @@ -683,6 +665,41 @@ chatHandlers[ container_, cellObject_, settings_ ] := chatHandlers // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*trimStopTokens*) +trimStopTokens // beginDefinition; +trimStopTokens // Attributes = { HoldFirst }; + +trimStopTokens[ container_, stop: { ___String } ] := + With[ { full = container[ "FullContent" ], dynamic = container[ "DynamicContent" ] }, + ( + container[ "DynamicContent" ] = StringDelete[ dynamic, stop~~EndOfString ]; + container[ "FullContent" ] = StringDelete[ full , stop~~EndOfString ]; + ) /; StringQ @ full + ]; + +trimStopTokens[ container_, { ___String } ] := + Null; + +trimStopTokens // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*checkFinishReason*) +checkFinishReason // beginDefinition; + +checkFinishReason[ as_Association ] := checkFinishReason @ as[ "BodyChunk" ]; +checkFinishReason[ _Missing ] := Null; + +checkFinishReason[ chunk_String ] := + Module[ { reasons }, + reasons = StringCases[ chunk, "\"finish_reason\":\"" ~~ reason: Except[ "\"" ].. ~~ "\"" :> reason ]; + If[ MatchQ[ reasons, { ___, _String } ], $finishReason = Last @ reasons ] + ]; + +checkFinishReason // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*feTaskQ*) @@ -824,6 +841,7 @@ autoCorrect // beginDefinition; autoCorrect[ string_String ] := StringReplace[ string, $llmAutoCorrectRules ]; autoCorrect // endDefinition; +(* cSpell: ignore evaliator *) $llmAutoCorrectRules = Flatten @ { "wolfram_language_evaliator" -> "wolfram_language_evaluator", "\\!\\(\\*MarkdownImageBox[\"" ~~ Shortest[ uri__ ] ~~ "\"]\\)" :> uri, @@ -846,6 +864,7 @@ splitDynamicContent // Attributes = { HoldFirst }; (* NotebookLocationSpecifier isn't available before 13.3 and splitting isn't yet supported in cloud: *) splitDynamicContent[ container_, cell_ ] /; Or[ + $InlineChat, ! $dynamicSplit, insufficientVersionQ[ "DynamicSplit" ], $cloudNotebooks @@ -855,7 +874,7 @@ splitDynamicContent[ container_, cell_ ] := splitDynamicContent[ container, container[ "DynamicContent" ], cell, container[ "UUID" ] ]; splitDynamicContent[ container_, text_String, cell_, uuid_String ] := - splitDynamicContent[ container, StringSplit[ text, $dynamicSplitRules ], cell, uuid ]; + splitDynamicContent[ container, DeleteCases[ StringSplit[ text, $dynamicSplitRules ], "" ], cell, uuid ]; splitDynamicContent[ container_, { static__String, dynamic_String }, cell_, uuid_String ] := Enclose[ Catch @ Module[ { boxObject, settings, reformatted, write, nbo }, @@ -881,7 +900,7 @@ splitDynamicContent[ container_, { static__String, dynamic_String }, cell_, uuid "ReformatTextData" ]; - write = Cell[ TextData @ reformatted, Background -> None ]; + write = Cell[ TextData @ reformatted, "None", Background -> None ]; nbo = ConfirmMatch[ parentNotebook @ cell, _NotebookObject, "ParentNotebook" ]; container[ "DynamicContent" ] = dynamic; @@ -895,7 +914,7 @@ splitDynamicContent[ container_, { static__String, dynamic_String }, cell_, uuid ]; splitDynamicTaskFunction @ NotebookWrite[ System`NotebookLocationSpecifier[ boxObject, "Before" ], - StyleBox[ "\n" ], + Cell[ "\n", "None" ], None, AutoScroll -> False ]; @@ -905,7 +924,7 @@ splitDynamicContent[ container_, { static__String, dynamic_String }, cell_, uuid $lastDynamicUpdate = AbsoluteTime[ ]; ], - throwInternalFailure[ splitDynamicContent[ container, { static, dynamic }, cell, uuid ], ## ] & + throwInternalFailure ]; (* There's nothing we can write as static content yet: *) @@ -924,6 +943,8 @@ checkResponse[ settings: KeyValuePattern[ "ToolsEnabled" -> False ], container_, $nextTaskEvaluation = Hold @ writeResult[ settings, container, cell, as ] ]; +(* FIXME: Look for "finish_reason":"stop" and check if response ends in a WL code block. + If it does, process it as a tool call, since it wrote /exec after the code block. *) checkResponse[ settings_, container_, cell_, as_Association ] /; toolFreeQ[ settings, container ] := If[ TrueQ @ $AutomaticAssistance, writeResult[ settings, container, cell, as ], @@ -944,12 +965,14 @@ checkResponse // endDefinition; writeResult // beginDefinition; writeResult[ settings_, container_, cell_, as_Association ] := Enclose[ - Module[ { log, processed, body, data }, + Catch @ Module[ { log, processed, body, data }, If[ TrueQ @ $AutomaticAssistance, NotebookDelete @ Cells[ PreviousCell @ cell, AttachedCell -> True, CellStyle -> "MinimizedChatIcon" ] ]; + If[ settings[ "BypassResponseChecking" ], Throw @ writeReformattedCell[ settings, container, cell ] ]; + log = ConfirmMatch[ Internal`BagPart[ $debugLog, All ], { ___Association }, "DebugLog" ]; processed = StringJoin @ Cases[ log, KeyValuePattern[ "BodyChunkProcessed" -> s_String ] :> s ]; { body, data } = ConfirmMatch[ extractBodyData @ log, { _, _ }, "ExtractBodyData" ]; @@ -1090,7 +1113,10 @@ toolEvaluation // beginDefinition; toolEvaluation[ settings_, container_Symbol, cell_, as_Association ] := Enclose[ Module[ - { string, simple, parser, callPos, toolCall, toolResponse, output, messages, newMessages, req, toolID, task }, + { + string, simple, parser, callPos, toolCall, toolResponse, output, + messages, roles, response, newMessages, req, toolID, task + }, (* Ensure dynamic text is up to date: *) $dynamicTrigger++; @@ -1126,14 +1152,24 @@ toolEvaluation[ settings_, container_Symbol, cell_, as_Association ] := Enclose[ "Messages" ]; + roles = ConfirmMatch[ allowedMultimodalRoles @ settings, All | { __String }, "Roles" ]; + + response = + If[ roles === All || MemberQ[ roles, "System" ], + expandMultimodalString @ ToString @ output, + ToString @ output + ]; + newMessages = Join[ messages, { <| "Role" -> "assistant", "Content" -> appendToolCallEndToken[ settings, StringTrim @ string ] |>, - <| "Role" -> "system" , "Content" -> expandMultimodalString @ ToString @ output |> + makeToolResponseMessage[ settings, response ] } ]; + $finishReason = None; + req = If[ TrueQ @ $useLLMServices, ConfirmMatch[ constructMessages[ settings, newMessages ], { __Association }, "ConstructMessages" ], (* TODO: this path will be obsolete when LLMServices is widely available *) @@ -1171,6 +1207,42 @@ toolEvaluation // endDefinition; The user has already been provided with this result, so you do not need to repeat it. Reply with /end if the tool call provides a satisfactory answer, otherwise respond normally."; *) +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makeToolResponseMessage*) +makeToolResponseMessage // beginDefinition; +makeToolResponseMessage[ settings_, response_ ] := makeToolResponseMessage0[ serviceName @ settings, response ]; +makeToolResponseMessage // endDefinition; + +makeToolResponseMessage0 // beginDefinition; + +makeToolResponseMessage0[ "Anthropic"|"MistralAI", response_ ] := <| + "Role" -> "User", + "Content" -> Replace[ Flatten @ { "", response, "" }, { s__String } :> StringJoin @ s ] +|>; + +makeToolResponseMessage0[ service_String, response_ ] := + <| "Role" -> "System", "Content" -> response |>; + +makeToolResponseMessage0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*userToolResponseQ*) +userToolResponseQ // beginDefinition; +userToolResponseQ[ settings_ ] := MatchQ[ serviceName @ settings, "Anthropic"|"MistralAI" ]; +userToolResponseQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*serviceName*) +serviceName // beginDefinition; +serviceName[ KeyValuePattern[ "Model" -> model_ ] ] := serviceName @ model; +serviceName[ { service_String, _String | $$unspecified } ] := service; +serviceName[ KeyValuePattern[ "Service" -> service_String ] ] := service; +serviceName[ _String | _Association | $$unspecified ] := "OpenAI"; +serviceName // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*appendToolCallEndToken*) @@ -1510,6 +1582,9 @@ openChatCell // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*WriteChatOutputCell*) +WriteChatOutputCell[ cell_, new_Cell, info_ ] /; $InlineChat := + writeInlineChatOutputCell[ cell, new, info ]; + WriteChatOutputCell[ cell_CellObject, new_Cell, @@ -1529,6 +1604,7 @@ WriteChatOutputCell[ args___ ] := (* ::Subsubsection::Closed:: *) (*createNewChatOutput*) createNewChatOutput // beginDefinition; +createNewChatOutput[ settings_, target_, cell_Cell ] /; $InlineChat := createNewInlineOutput[ settings, target, cell ]; createNewChatOutput[ settings_, None, cell_Cell ] := cellPrint @ cell; createNewChatOutput[ settings_, target_, cell_Cell ] /; settings[ "TabbedOutput" ] === False := cellPrint @ cell; createNewChatOutput[ settings_, target_CellObject, cell_Cell ] := prepareChatOutputPage[ target, cell ]; @@ -1616,12 +1692,13 @@ activeAIAssistantCell[ reformat = dynamicAutoFormatQ @ settings, task = Lookup[ settings, "Task" ], formatter = getFormattingFunction @ settings, - cellTags = Replace[ cellTags0, Except[ _String | { ___String } ] :> Inherited ] + cellTags = Replace[ cellTags0, Except[ _String | { ___String } ] :> Inherited ], + outer = If[ TrueQ[ $WorkspaceChat||$InlineChat ], assistantMessageBox, # & ] }, Module[ { x = 0 }, ClearAttributes[ { x, cellObject }, Temporary ]; Cell[ - BoxData @ ToBoxes @ + BoxData @ outer @ ToBoxes @ If[ TrueQ @ reformat, Dynamic[ Refresh[ @@ -1661,9 +1738,10 @@ activeAIAssistantCell[ CellDingbat -> Cell[ BoxData @ makeActiveOutputDingbat @ settings, Background -> None ], Sequence @@ { } ], - CellTags -> cellTags, - CellTrayWidgets -> <| "ChatFeedback" -> <| "Visible" -> False |> |>, - TaggingRules -> <| "ChatNotebookSettings" -> smallSettings @ settings |> + CellTags -> cellTags, + CellTrayWidgets -> <| "ChatFeedback" -> <| "Visible" -> False |> |>, + PrivateCellOptions -> { "ContentsOpacity" -> 1 }, + TaggingRules -> <| "ChatNotebookSettings" -> smallSettings @ settings |> ] ] ]; @@ -1682,10 +1760,11 @@ activeAIAssistantCell[ task = Lookup[ settings, "Task" ], uuid = container[ "UUID" ], formatter = getFormattingFunction @ settings, - cellTags = Replace[ cellTags0, Except[ _String | { ___String } ] :> Inherited ] + cellTags = Replace[ cellTags0, Except[ _String | { ___String } ] :> Inherited ], + outer = If[ TrueQ[ $WorkspaceChat||$InlineChat ], assistantMessageBox, # & ] }, Cell[ - BoxData @ TagBox[ + BoxData @ outer @ TagBox[ ToBoxes @ Dynamic[ $dynamicTrigger; (* `$dynamicTrigger` is used to precisely control when the dynamic updates, otherwise we can get an @@ -1719,6 +1798,7 @@ activeAIAssistantCell[ Editable -> True, LanguageCategory -> None, LineIndent -> 0, + PrivateCellOptions -> { "ContentsOpacity" -> 1 }, Selectable -> True, ShowAutoSpellCheck -> False, ShowCursorTracker -> False, @@ -1789,7 +1869,7 @@ dynamicTextDisplay[ container_, formatter_, True ] := With[ $ChatHandlerData |> }, - formatter[ container[ "DynamicContent" ], data ] + conformToExpression @ formatter[ container[ "DynamicContent" ], data ] ]; dynamicTextDisplay[ container_, formatter_, False ] /; StringQ @ container[ "DynamicContent" ] := @@ -1986,9 +2066,6 @@ scrollOutputQ[ settings_Association ] := $$unspecified :> sufficientVersionQ[ "TrackScrollingWhenPlaced" ] ]; -scrollOutputQ[ settings_Association? scrollOutputQ, cell_CellObject ] := - cellInformation[ cell ][ "CursorPosition" ] === "BelowCell"; - scrollOutputQ[ settings_Association, cell_ ] := False; scrollOutputQ // endDefinition; @@ -2012,17 +2089,17 @@ scrollOutput // endDefinition; (*reformatCell*) reformatCell // beginDefinition; -reformatCell[ settings_, string_, tag_, open_, label_, pageData_, cellTags_, uuid_ ] := UsingFrontEnd @ Enclose[ - Module[ { formatter, toolFormatter, content, rules, dingbat }, +(* FIXME: why does this actually need UsingFrontEnd here? *) +reformatCell[ settings_, string_, tag_, open_, label_, pageData_, cellTags_, uuid_ ] := usingFrontEnd @ Enclose[ + Module[ { formatter, toolFormatter, content, rules, dingbat, outer }, formatter = Confirm[ getFormattingFunction @ settings, "GetFormattingFunction" ]; toolFormatter = Confirm[ getToolFormatter @ settings, "GetToolFormatter" ]; - (*FIXME: use specified ChatFormattingFunction here and figure out how to conform to TextData *) content = Block[ { $customToolFormatter = toolFormatter }, ConfirmMatch[ If[ TrueQ @ settings[ "AutoFormat" ], - TextData @ reformatTextData @ string, + conformToTextData @ formatter[ string, settings ], TextData @ string ], TextData[ _String | _List ], @@ -2038,8 +2115,18 @@ reformatCell[ settings_, string_, tag_, open_, label_, pageData_, cellTags_, uui dingbat = makeOutputDingbat @ settings; + outer = If[ TrueQ @ $WorkspaceChat, + TextData @ { + Cell[ + BoxData @ TemplateBox[ { Cell[ #, Background -> None ] }, "AssistantMessageBox" ], + Background -> None + ] + } &, + # & + ]; + Cell[ - content, + outer @ content, If[ TrueQ @ $AutomaticAssistance, Switch[ tag, "[ERROR]" , "AssistantOutputError", @@ -2074,6 +2161,33 @@ reformatCell[ settings_, string_, tag_, open_, label_, pageData_, cellTags_, uui reformatCell // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*conformToTextData*) +conformToTextData // beginDefinition; +conformToTextData[ text_TextData ] := text; +conformToTextData[ text_List ] := TextData @ Flatten @ Map[ conformToTextData0, Flatten @ { text } ]; +conformToTextData[ expr_ ] := conformToTextData @ { expr }; +conformToTextData // endDefinition; + + +conformToTextData0 // beginDefinition; +conformToTextData0[ text_String ] := text; +conformToTextData0[ (Cell|TextData)[ text_ ] ] := conformToTextData0 @ text; +conformToTextData0[ Cell[ text_, "ChatOutput" ] ] := conformToTextData0 @ text; +conformToTextData0[ text: $$textData ] := text; +conformToTextData0[ boxes_BoxData ] := Cell @ boxes; +conformToTextData0[ expr_ ] := With[ { b = ToBoxes @ expr }, conformToTextData0 @ b /; MatchQ[ b, $$textData ] ]; +conformToTextData0[ expr_ ] := Cell @ BoxData @ ToBoxes @ expr; +conformToTextData0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*conformToExpression*) +conformToExpression // beginDefinition; +conformToExpression[ expr_ ] := RawBoxes @ Cell @ conformToTextData @ expr; +conformToExpression // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*attachMinimizedIcon*) @@ -2425,7 +2539,7 @@ errorBoxes[ as___ ] := (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $autoSettingKeyPriority; ]; diff --git a/Source/Chatbook/Serialization.wl b/Source/Chatbook/Serialization.wl index b1fc8f03..e93fa08f 100644 --- a/Source/Chatbook/Serialization.wl +++ b/Source/Chatbook/Serialization.wl @@ -9,27 +9,25 @@ GeneralUtilities`SetUsage[ `CellToString, "\ CellToString[cell$] serializes a Cell expression as a string for use in chat.\ " ]; -`$CellToStringDebug; -`$CurrentCell; -`$chatInputIndicator; -`$defaultMaxCellStringLength; -`$defaultMaxOutputCellStringLength; -`$longNameCharacters; -`documentationSearchAPI; -`escapeMarkdownString; -`truncateString; - Begin[ "`Private`" ]; -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`ChatMessages`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`ErrorUtils`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; -Needs[ "Wolfram`Chatbook`Prompting`" ]; -Needs[ "Wolfram`Chatbook`Tools`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`ErrorUtils`" ]; + +(* TODO: + + There should be a way to pass custom serialization rules in chat settings, e.g. + ``` + "ConversionRules" -> { + _GraphicsBox -> "[Image]", + Cell[box_, "MyStyle"] :> formatMyStyle[box] + } + ``` + + These replacements should be done prior to calling `cellToString`, but need to be tagged in some way so we don't + try to serialize the results again via `fasterCellToString0`. +*) (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -38,8 +36,33 @@ Needs[ "Wolfram`Chatbook`Utils`" ]; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*Config*) -$$delimiterStyle = "PageBreak"|"ExampleDelimiter"|"GuideDelimiterSubsection"|"WorkflowDelimiter"; -$$itemStyle = "Item"|"Notes"|"FeaturedExampleMoreAbout"; +$$delimiterStyle = Alternatives[ + "Delimiter", + "ExampleDelimiter", + "GuideDelimiter", + "GuideDelimiterSubsection", + "GuideMoreAboutDelimiter", + "HistoryDelimiter", + "HowToDelimiter", + "KeyEventDelimiter", + "MarkdownDelimiter", + "MenuNameDelimiter", + "PageBreak", + "PageDelimiter", + "PointerEventDelimiter", + "RootMoreAboutDelimiter", + "WeakDivider", + "WorkflowDelimiter", + "WorkflowFooterBottomDelimiter", + "WorkflowFooterDelimiter", + "WorkflowFooterTopDelimiter", + "WorkflowGuideDelimiter", + "WorkflowHeaderDelimiter", + "WorkflowPlatformDelimiter" +]; + +$$itemStyle = "Item"|"Notes"|"FeaturedExampleMoreAbout"|"InterpreterNotes"|"BulletedText"|"MonographBulletedText"; + $$subItemStyle = "Subitem"; $$subSubItemStyle = "Subsubitem"; $$docSearchStyle = "ChatQuery"; @@ -61,11 +84,14 @@ $$noCellLabelStyle = Alternatives[ $$ignoredCellStyle = Alternatives[ "AnchorBarGrid", - "CitationContainerCell" + "CitationContainerCell", + "DiscardedMaterial" ]; (* Cell styles that will prevent wrapping BoxData in triple backticks: *) $$noCodeBlockStyle = Alternatives[ + "ChatInput", + "ChatOutput", "FunctionEssay", "GuideFunctionsSubsection", "NotebookImage", @@ -76,6 +102,9 @@ $$noCodeBlockStyle = Alternatives[ "UsageInputs" ]; +$maxInputFormByteCount = 2^18; +$maxStandardFormStringLength = 2^15; + (* Default character encoding for strings created from cells *) $cellCharacterEncoding = "Unicode"; @@ -108,6 +137,9 @@ $CellToStringDebug = False; $showStringCharacters = True; $inlineCode = False; +(* Replacement rules that are applied to the cell before serialization: *) +$conversionRules = None; + (* Add spacing around these operators *) $$spacedInfixOperator = Alternatives[ "^", "*", "+", "=", "|", "<", ">", "?", "/", ":", "!=", "@*", "^=", "&&", "*=", "-=", "->", "+=", "==", "~~", @@ -148,6 +180,9 @@ $escapedMarkdownCharacters = { "`", "$", "*", "_", "#", "|" }; [] () {} + - . ! *) +$leftSelectionIndicator = "\\["<>"BeginSelection"<>"]"; +$rightSelectionIndicator = "\\["<>"EndSelection"<>"]"; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*Conversion Rules*) @@ -157,14 +192,16 @@ $boxOp = <| SuperscriptBox -> "^", SubscriptBox -> "_" |>; (* How to choose TemplateBox arguments for serialization *) $templateBoxRules = <| + "AssistantMessageBox" -> First, "ChatCodeBlockTemplate" -> First, + "ConditionalExpression" -> makeExpressionString, "GrayLink" -> First, "HyperlinkDefault" -> First, "Key0" -> First, "Key1" -> (Riffle[ #, "-" ] &), "RowDefault" -> Identity, - "ConditionalExpression" -> makeExpressionString, - "TransferFunctionModelFull" -> makeExpressionString + "TransferFunctionModelFull" -> makeExpressionString, + "UserMessageBox" -> First |>; (* ::**************************************************************************************************************:: *) @@ -270,6 +307,8 @@ CellToString // Options = { "CharacterEncoding" -> $cellCharacterEncoding, "CharacterNormalization" -> "NFKC", (* FIXME: do this *) "ContentTypes" -> Automatic, + "ConversionRules" :> $conversionRules, + "CurrentSelection" -> None, (* TODO *) "Debug" :> $CellToStringDebug, "MaxCellStringLength" -> $maxCellStringLength, "MaxOutputCellStringLength" -> $maxOutputCellStringLength, @@ -311,7 +350,7 @@ CellToString[ cell_, opts: OptionsPattern[ ] ] := If[ ! StringQ @ $cellCharacterEncoding, $cellCharacterEncoding = "UTF-8" ]; WithCleanup[ StringTrim @ Replace[ - cellToString @ cell, + cellToString @ applyConversionRules[ cell, OptionValue[ "ConversionRules" ] ], (* TODO: give a failure here *) Except[ _String? StringQ ] :> "" ], @@ -323,6 +362,25 @@ CellToString[ cell_, opts: OptionsPattern[ ] ] := ]; (* :!CodeAnalysis::EndBlock:: *) +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*applyConversionRules*) +applyConversionRules // beginDefinition; +applyConversionRules[ cell_, rules_ ] := applyConversionRules[ cell, rules, makeConversionRules @ rules ]; +applyConversionRules[ cell_, rules_, None | { } ] := cell; +applyConversionRules[ cell_, rules_, dispatch_Dispatch? DispatchQ ] := ReplaceRepeated[ cell, dispatch ]; +applyConversionRules // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makeConversionRules*) +makeConversionRules // beginDefinition; +makeConversionRules[ None | { } ] := None; +makeConversionRules[ rules_ ] := makeConversionRules[ rules, Quiet @ Dispatch @ rules ]; +makeConversionRules[ rules_, dispatch_Dispatch? DispatchQ ] := makeConversionRules[ rules ] = dispatch; +makeConversionRules[ rules_, other_ ] := (messagePrint[ "InvalidConversionRules", rules ]; None); +makeConversionRules // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*toContentTypes*) @@ -473,13 +531,12 @@ cellToString[ Cell[ a__, "Message", "MSG", b___ ] ] := ] ]; -(* External language cells get converted to an equivalent ExternalEvaluate input *) +(* External language cells get converted to a code block with the corresponding language specifier *) cellToString[ Cell[ code_, "ExternalLanguage", ___, $$cellEvaluationLanguage -> lang_String, ___ ] ] := - Module[ { string }, - string = cellToString0 @ code; + With[ { string = cellToString0 @ code }, ( - needsBasePrompt[ "WolframLanguage" ]; - "ExternalEvaluate[\""<>lang<>"\", \""<>string<>"\"]" + needsBasePrompt[ "ExternalLanguageCells" ]; + "```"<>lang<>"\n"<>string<>"\n```" ) /; StringQ @ string ]; @@ -499,6 +556,9 @@ cellToString[ cell: Cell[ _BoxData, Except[ $$chatInputStyle|$$chatOutputStyle ] $multimodalImages && Count[ cell, $$graphicsBox, Infinity ] > $maxMarkdownBoxes := toMarkdownImageBox @ cell; +cellToString[ other_ ] := + cellToString0 @ other; + cellToString // endDefinition; (* Recursive serialization of the cell content *) @@ -579,6 +639,8 @@ $globalStringReplacements = { "\[RightAssociation]" -> "|>", "\[RightSkeleton]" -> "\:00BB", "\[Rule]" -> "->", + "\n\n" ~~ Longest[ "\n".. ] -> "\n\n", + "```\n```" -> "```\n\n```", "\n\n\t\n" -> "\n", "``$$" ~~ math__ ~~ "$$``" :> "$$"<>math<>"$$", link: ("``[" ~~ Except[ "]" ].. ~~ "](" ~~ Except[ ")" ].. ~~ ")``") :> StringTrim[ link, "``" ] @@ -642,6 +704,17 @@ fasterCellToString0[ (Cell|StyleBox)[ a_, $$subsubsectionStyle, ___ ] ] := "#### fasterCellToString0[ (Cell|StyleBox)[ a_, $$subsubsubsectionStyle, ___ ] ] := "##### "<>fasterCellToString0 @ a; fasterCellToString0[ (Cell|StyleBox)[ a_, $$subsubsubsubsectionStyle, ___ ] ] := "###### "<>fasterCellToString0 @ a; +fasterCellToString0[ Cell[ BoxData @ PaneBox[ StyleBox[ box_, style_String, ___ ], ___ ], "InlineSection", ___ ] ] := + Block[ { $showStringCharacters = False }, + StringJoin[ + "\n", + fasterCellToString0 @ Cell[ fasterCellToString0 @ box, style ], + "\n" + ] + ]; + +fasterCellToString0[ Cell[ __, $$delimiterStyle, ___ ] ] := $delimiterString; + (* ::**************************************************************************************************************:: *) (* ::Subsubsubsection::Closed:: *) (*Styles*) @@ -661,6 +734,15 @@ fasterCellToString0[ (box_)[ a__, BaseStyle -> { b___, ShowStringCharacters -> c (* ::Subsubsubsection::Closed:: *) (*String Normalization*) +(* Conversion Rules can specify Verbatim["..."] to prevent any further processing on strings: *) +fasterCellToString0[ Verbatim[ Verbatim ][ string_String? StringQ ] ] := string; + +(* Separate definition for comments, since we don't want to add spacing around operators, etc: *) +fasterCellToString0[ boxes: RowBox @ { "(*", ___, "*)" } ] := + With[ { flat = Flatten[ boxes //. RowBox[ a___ ] :> a ] }, + StringReplace[ StringJoin @ flat, FromCharacterCode[ 62371 ] -> "\n" ] /; MatchQ[ flat, { ___String } ] + ]; + (* Add spacing between RowBox elements that are comma separated *) fasterCellToString0[ "," ] := ", "; fasterCellToString0[ c: $$spacedInfixOperator ] := " "<>c<>" "; @@ -682,27 +764,32 @@ fasterCellToString0[ string_String ] /; StringContainsQ[ string, $$longNameChara fasterCellToString0 @ StringDelete[ StringReplace[ string, $longNameCharacters ], $$invisibleCharacter ]; (* StandardForm strings *) -fasterCellToString0[ s_String /; StringContainsQ[ s, "\!\(" ~~ Except[ "\)" ] .. ~~ "\)" ] ] := +fasterCellToString0[ s_String ] /; StringContainsQ[ + s, + a: ("\!\(" ~~ Except[ "\)" ] .. ~~ "\)") /; StringLength @ a < $maxStandardFormStringLength +] := Module[ { split }, split = StringSplit[ s, "\!\(" ~~ b: Except[ "\)" ].. ~~ "\)" :> - UsingFrontEnd @ MathLink`CallFrontEnd @ FrontEnd`ReparseBoxStructurePacket[ "\!\("<>b<>"\)" ] - ]; + usingFrontEnd @ MathLink`CallFrontEnd @ FrontEnd`ReparseBoxStructurePacket[ "\!\("<>b<>"\)" ] + ]; StringJoin[ fasterCellToString0 /@ split ] /; ! MatchQ[ split, { s } ] ]; -fasterCellToString0[ a_String /; StringMatchQ[ a, "\""~~___~~("\\!"|"\!")~~___~~"\"" ] ] := - With[ { res = ToString @ ToExpression[ a, InputForm ] }, - If[ TrueQ @ $showStringCharacters, - res, - StringReplace[ StringTrim[ res, "\"" ], { "\\\"" -> "\"" } ] - ] /; FreeQ[ res, s_String /; StringContainsQ[ s, ("\\!"|"\!") ] ] - ]; +fasterCellToString0[ a_String ] /; + StringLength @ a < $maxStandardFormStringLength && StringMatchQ[ a, "\""~~___~~("\\!"|"\!")~~___~~"\"" ] := + With[ { res = ToString @ ToExpression[ a, InputForm ] }, + If[ TrueQ @ $showStringCharacters, + res, + StringReplace[ StringTrim[ res, "\"" ], { "\\\"" -> "\"" } ] + ] /; FreeQ[ res, s_String /; StringContainsQ[ s, ("\\!"|"\!") ] ] + ]; -fasterCellToString0[ a_String /; StringContainsQ[ a, ("\\!"|"\!") ] ] := - With[ { res = stringToBoxes @ a }, res /; FreeQ[ res, s_String /; StringContainsQ[ s, ("\\!"|"\!") ] ] ]; +fasterCellToString0[ a_String ] /; + StringLength @ a < $maxStandardFormStringLength && StringContainsQ[ a, ("\\!"|"\!") ] := + With[ { res = stringToBoxes @ a }, res /; FreeQ[ res, s_String /; StringContainsQ[ s, ("\\!"|"\!") ] ] ]; (* Other strings *) fasterCellToString0[ a_String ] := @@ -717,6 +804,14 @@ fasterCellToString0[ a_String ] := fasterCellToString0[ a: { ___String } ] := StringJoin[ fasterCellToString0 /@ a ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*Current Selection*) +fasterCellToString0[ (Cell|StyleBox|TagBox)[ boxes_, "CurrentSelection", ___ ] ] := + StringJoin[ $leftSelectionIndicator, fasterCellToString0 @ boxes, $rightSelectionIndicator ]; + +(* TODO: Determine selection position from "CurrentSelection" option value *) + (* ::**************************************************************************************************************:: *) (* ::Subsubsubsection::Closed:: *) (*Inline References*) @@ -806,6 +901,13 @@ fasterCellToString0[ Cell[ "\[FreeformPrompt] " <> query ); +(* Control equals input *) +fasterCellToString0[ NamespaceBox[ + "LinguisticAssistant", + DynamicModuleBox[ { ___, Typeset`query$$|WolframAlphaClient`Private`query$$ = query_String, ___ }, __ ], + ___ +] ] := "\[FreeformPrompt][\""<>query<>"\"]"; + (* ::**************************************************************************************************************:: *) (* ::Subsubsubsection::Closed:: *) (*Graphics*) @@ -883,10 +985,11 @@ rasterizeGraphics // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsubsubsection::Closed:: *) (*Video*) -fasterCellToString0[ box: TemplateBox[ _, "VideoBox2", ___ ] ] /; $multimodalImages && $generateVideoPrompt := - generateVideoPrompt @ box; +fasterCellToString0[ box: TemplateBox[ _, "VideoBox1"|"VideoBox2", ___ ] ] /; + $multimodalImages && $generateVideoPrompt := + generateVideoPrompt @ box; -fasterCellToString0[ box: TemplateBox[ _, "VideoBox2", ___ ] ] := +fasterCellToString0[ box: TemplateBox[ _, "VideoBox1"|"VideoBox2", ___ ] ] := serializeVideo @ box; (* ::**************************************************************************************************************:: *) @@ -894,7 +997,7 @@ fasterCellToString0[ box: TemplateBox[ _, "VideoBox2", ___ ] ] := (*generateVideoPrompt*) generateVideoPrompt // beginDefinition; -generateVideoPrompt[ box: TemplateBox[ _, "VideoBox2", ___ ] ] := generateVideoPrompt[ box ] = +generateVideoPrompt[ box: TemplateBox[ _, "VideoBox1"|"VideoBox2", ___ ] ] := generateVideoPrompt[ box ] = With[ { video = Quiet @ ToExpression[ box, StandardForm ] }, If[ VideoQ @ video, generateVideoPrompt @ video, @@ -934,7 +1037,7 @@ generateVideoPrompt // endDefinition; (*serializeVideo*) serializeVideo // beginDefinition; -serializeVideo[ box: TemplateBox[ _, "VideoBox2", ___ ] ] := serializeVideo[ box ] = +serializeVideo[ box: TemplateBox[ _, "VideoBox1"|"VideoBox2", ___ ] ] := serializeVideo[ box ] = serializeVideo[ box, Quiet @ ToExpression[ box, StandardForm ] ]; serializeVideo[ box_, video_ ] := Enclose[ @@ -970,10 +1073,18 @@ serializeAudio[ content_, audio_ ] := Enclose[ serializeAudio // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*Block quotes*) +fasterCellToString0[ Cell[ boxes_, "BlockQuote", ___ ] ] := + With[ { string = fasterCellToString0 @ boxes }, + ("\n> " <> StringReplace[ string, "\n" -> "\n> " ]) /; StringQ @ string + ]; + (* ::**************************************************************************************************************:: *) (* ::Subsubsubsection::Closed:: *) (*Inline Code*) -fasterCellToString0[ TemplateBox[ { code_ }, "ChatCodeInlineTemplate" ] ] /; ! $inlineCode := +fasterCellToString0[ TemplateBox[ { code_ }, "ChatCodeInlineTemplate", ___ ] ] /; ! $inlineCode := Block[ { $escapeMarkdown = False, $inlineCode = True }, needsBasePrompt[ "DoubleBackticks" ]; "``" <> fasterCellToString0 @ code <> "``" @@ -989,7 +1100,7 @@ fasterCellToString0[ Cell[ BoxData[ link: TemplateBox[ _, $$refLinkTemplate, ___ ], ___ ], "InlineCode"|"InlineFormula", ___ ] ] /; ! $inlineCode := fasterCellToString0 @ link; -fasterCellToString0[ Cell[ code_, "InlineCode"|"InlineFormula", ___ ] ] /; ! $inlineCode := +fasterCellToString0[ (Cell|StyleBox)[ code_, "InlineCode"|"InlineFormula", ___ ] ] /; ! $inlineCode := Block[ { $escapeMarkdown = False, $inlineCode = True }, needsBasePrompt[ "DoubleBackticks" ]; "``" <> fasterCellToString0 @ code <> "``" @@ -1000,34 +1111,37 @@ fasterCellToString0[ Cell[ code_, "InlineCode"|"InlineFormula", ___ ] ] /; ! $in (*Template Boxes*) (* Messages *) -fasterCellToString0[ TemplateBox[ args: { _, _, str_String, ___ }, "MessageTemplate" ] ] := ( +fasterCellToString0[ TemplateBox[ args: { _, _, str_String, ___ }, "MessageTemplate", ___ ] ] := ( needsBasePrompt[ "WolframLanguage" ]; sowMessageData @ args; (* Look for stack trace data *) fasterCellToString0 @ str ); (* Large Outputs *) -fasterCellToString0[ TemplateBox[ KeyValuePattern[ "shortenedBoxes" -> boxes_ ], "OutputSizeLimitTemplate" ] ] := +fasterCellToString0[ TemplateBox[ KeyValuePattern[ "shortenedBoxes" -> boxes_ ], "OutputSizeLimitTemplate", ___ ] ] := fasterCellToString0 @ boxes; -fasterCellToString0[ TemplateBox[ { size_ }, "OutputSizeLimit`Skeleton" ] ] := +fasterCellToString0[ TemplateBox[ { size_ }, "OutputSizeLimit`Skeleton", ___ ] ] := " \[LeftSkeleton]" <> fasterCellToString0 @ size <> "\[RightSkeleton] "; (* Row *) fasterCellToString0[ TemplateBox[ args_, "RowDefault", ___ ] ] := fasterCellToString0 @ args; -fasterCellToString0[ TemplateBox[ { sep_, items__ }, "RowWithSeparator" ] ] := +fasterCellToString0[ TemplateBox[ { sep_, items__ }, "RowWithSeparator", ___ ] ] := fasterCellToString0 @ Riffle[ { items }, sep ]; (* Tooltips *) fasterCellToString0[ TemplateBox[ { a_, ___ }, "PrettyTooltipTemplate", ___ ] ] := fasterCellToString0 @ a; (* Control-Equal Input *) -fasterCellToString0[ TemplateBox[ KeyValuePattern[ "boxes" -> box_ ], "LinguisticAssistantTemplate" ] ] := +fasterCellToString0[ TemplateBox[ KeyValuePattern[ "query" -> query_String ], "LinguisticAssistantTemplate", ___ ] ] := + "\[FreeformPrompt][\""<>query<>"\"]"; + +fasterCellToString0[ TemplateBox[ KeyValuePattern[ "boxes" -> box_ ], "LinguisticAssistantTemplate", ___ ] ] := fasterCellToString0 @ box; (* NotebookObject *) fasterCellToString0[ - TemplateBox[ KeyValuePattern[ "label" -> label_String ], "NotebookObjectUUIDsUnsaved"|"NotebookObjectUUIDs" ] + TemplateBox[ KeyValuePattern[ "label" -> label_String ], "NotebookObjectUUIDsUnsaved"|"NotebookObjectUUIDs", ___ ] ] := ( needsBasePrompt[ "Notebooks" ]; "NotebookObject["<>label<>"]" @@ -1035,7 +1149,7 @@ fasterCellToString0[ (* Entity *) $$entityBoxType = "Entity"|"EntityClass"|"EntityProperty"|"EntityType"; -fasterCellToString0[ TemplateBox[ { _, box_, ___ }, $$entityBoxType ] ] := fasterCellToString0 @ box; +fasterCellToString0[ TemplateBox[ { _, box_, ___ }, $$entityBoxType, ___ ] ] := fasterCellToString0 @ box; fasterCellToString0[ TemplateBox[ _, "InertEntity", ___ ] ] := "\[LeftSkeleton]formatted entity\[RightSkeleton]"; (* Quantities *) @@ -1091,7 +1205,7 @@ fasterCellToString0[ box: TemplateBox[ { ___ }, $$inactiveTemplate, ___ ] ] := With[ { str = makeExpressionString @ box }, str /; StringQ @ str ]; (* Spacers *) -fasterCellToString0[ TemplateBox[ _, "Spacer1" ] ] := " "; +fasterCellToString0[ TemplateBox[ _, "Spacer1", ___ ] ] := " "; (* Links *) $$refLinkTemplate = Alternatives[ @@ -1112,6 +1226,7 @@ $$refLinkTemplate = Alternatives[ "StringTypeLink", "TealLink", "TextRefLink", + "WebLink", "WFOrangeLink" ]; @@ -1150,8 +1265,18 @@ fasterCellToString0[ ] ] := "[" <> fasterCellToString0 @ label <> "](" <> TextString @ url <> ")"; +fasterCellToString0[ TemplateBox[ { label_, url_String | URL[ url_String ] }, "HyperlinkURL", ___ ] ] := + Block[ { $showStringCharacters = False }, + "[" <> fasterCellToString0 @ label <> "](" <> url <> ")" + ]; + +fasterCellToString0[ TemplateBox[ { label_, { url_String | URL[ url_String ], _ }, _ }, "HyperlinkDefault", ___ ] ] := + Block[ { $showStringCharacters = False }, + "[" <> fasterCellToString0 @ label <> "](" <> url <> ")" + ]; + (* TeXAssistantTemplate *) -fasterCellToString0[ TemplateBox[ KeyValuePattern[ "input" -> string_ ], "TeXAssistantTemplate" ] ] := ( +fasterCellToString0[ TemplateBox[ KeyValuePattern[ "input" -> string_ ], "TeXAssistantTemplate", ___ ] ] := ( needsBasePrompt[ "Math" ]; "$$" <> string <> "$$" ); @@ -1347,7 +1472,7 @@ outputSizeLimitString // endDefinition; (* ::Subsubsubsection::Closed:: *) (*Iconized Expressions*) fasterCellToString0[ - InterpretationBox[ DynamicModuleBox[ { ___ }, iconized: TemplateBox[ _, "IconizedObject" ] ], ___ ] + InterpretationBox[ DynamicModuleBox[ { ___ }, iconized: TemplateBox[ _, "IconizedObject", ___ ] ], ___ ] ] := fasterCellToString0 @ iconized; fasterCellToString0[ TemplateBox[ { _, label_, ___ }, "IconizedObject", ___ ] ] := @@ -1356,14 +1481,29 @@ fasterCellToString0[ TemplateBox[ { _, label_, ___ }, "IconizedObject", ___ ] ] (* ::**************************************************************************************************************:: *) (* ::Subsubsubsection::Closed:: *) (*Definitions*) -fasterCellToString0[ InterpretationBox[ boxes_, (Definition|FullDefinition)[ _Symbol ], ___ ] ] := ( +fasterCellToString0[ InterpretationBox[ GridBox[ boxes_List, ___ ], (Definition|FullDefinition)[ ___ ], ___ ] ] := ( needsBasePrompt[ "WolframLanguage" ]; - fasterCellToString0 @ boxes + StringRiffle[ DeleteCases[ StringTrim[ fasterCellToString0 /@ gridFlatten @ boxes ], "" ], "\n\n" ] ); +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsubsection::Closed:: *) +(*gridFlatten*) +gridFlatten // beginDefinition; +gridFlatten[ GridBox[ grid_List, ___ ] ] := gridFlatten @ Flatten @ grid; +gridFlatten[ boxes_List ] := Flatten[ gridFlatten /@ boxes ]; +gridFlatten[ other_ ] := other; +gridFlatten // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsubsection::Closed:: *) (*Tables*) +fasterCellToString0[ GridBox[ { row: { ___ } }, ___ ] ] := + fasterCellToString0 @ RowBox @ Riffle[ row, "\t" ]; + +fasterCellToString0[ TagBox[ GridBox[ items_List, ___ ], "Column" ] ] := + StringRiffle[ fasterCellToString0 /@ items, "\n" ]; + (* Columns combined via row: *) fasterCellToString0[ box: GridBox[ grids: { { GridBox[ _? MatrixQ, ___ ].. } }, ___ ] ] := Module[ { subGrids, dim, reshaped, spliced }, @@ -1376,23 +1516,28 @@ fasterCellToString0[ box: GridBox[ grids: { { GridBox[ _? MatrixQ, ___ ].. } }, fasterCellToString0[ box: GridBox[ grid_? MatrixQ, ___ ] ] := Module[ { strings, tr, colSizes, padded, columns }, - strings = Map[ fasterCellToString0, grid, { 2 } ]; + strings = Block[ { $maxOutputCellStringLength = 2*$cellPageWidth, $inlineCode = True }, + Map[ truncateString@*escapeTableCharacters@*fasterCellToString0, grid, { 2 } ] + ]; ( tr = Transpose @ strings /. "\[Null]"|"\[InvisibleSpace]" -> ""; + tr = Select[ tr, AnyTrue[ #, Not @* StringMatchQ[ WhitespaceCharacter... ] ] & ]; colSizes = Max[ #, 1 ] & /@ Map[ StringLength, tr, { 2 } ]; - padded = Transpose @ Apply[ StringPadRight, Transpose @ { tr, colSizes }, { 1 } ]; + padded = padColumns[ colSizes, tr ]; columns = StringRiffle[ #, " | " ] & /@ padded; If[ TrueQ @ $columnHeadings, - StringRiffle[ "| "<>#<> " |" & /@ insertColumnDelimiter[ columns, colSizes, box ], "\n" ], - StringRiffle[ + riffleTableString[ "| "<>#<> " |" & /@ insertColumnDelimiter[ columns, colSizes, box ] ], + riffleTableString[ "| "<>#<> " |" & /@ Join[ { - StringRiffle[ StringRepeat[ " ", # ] & /@ colSizes, " | " ], + If[ AnyTrue[ colSizes, GreaterThan[ $cellPageWidth ] ], + StringRiffle[ StringRepeat[ " ", Min[ 3, # ] ] & /@ colSizes, " | " ], + StringRiffle[ StringRepeat[ " ", # ] & /@ colSizes, " | " ] + ], StringRiffle[ createAlignedDelimiters[ colSizes, box ], " | " ] }, columns - ], - "\n" + ] ] ] ) /; AllTrue[ strings, StringQ, 2 ] @@ -1401,7 +1546,87 @@ fasterCellToString0[ box: GridBox[ grid_? MatrixQ, ___ ] ] := fasterCellToString0[ TagBox[ grid_GridBox, { _, OutputFormsDump`HeadedColumns }, ___ ] ] := Block[ { $columnHeadings = True }, fasterCellToString0 @ grid ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsubsection::Closed:: *) +(*riffleTableString*) +riffleTableString // beginDefinition; + +riffleTableString[ rows: { ___String } ] := Enclose[ + Catch @ Module[ { count, lengths, max, a, b, remaining, removed, message }, + count = Length @ rows; + If[ count <= 3, Throw @ StringRiffle[ rows, "\n" ] ]; + lengths = StringLength @ rows; + + max = ConfirmMatch[ + Replace[ $maxCellStringLength, Except[ _Integer ] :> $defaultMaxCellStringLength ], + $$size, + "Max" + ]; + + If[ Total @ lengths <= max, Throw @ StringRiffle[ rows, "\n" ] ]; + a = Max[ LengthWhile[ Accumulate @ lengths, # <= Floor[ 2 * (max / 3) ] & ], 3 ]; + remaining = ConfirmMatch[ max - Total @ lengths[[ 1;;a ]], $$size, "Remaining" ]; + b = LengthWhile[ Accumulate @ Reverse @ lengths, # <= remaining & ]; + removed = ConfirmMatch[ count - (a + b), $$size, "Removed" ]; + If[ removed === 0, Throw @ StringRiffle[ rows, "\n" ] ]; + + message = ConfirmBy[ + Replace[ + removed, + { + 1 :> "one row removed", + _? Positive :> ToString @ removed <> " rows removed" + } + ], + StringQ, + "Message" + ]; + + StringRiffle[ + Join[ + rows[[ 1;;a ]], + { "\[LeftSkeleton]" <> message <> "\[RightSkeleton]" }, + rows[[ -b ;; All ]] + ], + "\n" + ] + ], + throwInternalFailure +]; + +riffleTableString // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsubsection::Closed:: *) +(*padColumns*) +padColumns // beginDefinition; + +padColumns[ colSizes0_, tr_ ] := + Module[ { colSizes }, + colSizes = If[ AnyTrue[ colSizes0, GreaterThan[ $cellPageWidth ] ], Clip[ colSizes0, { 1, 3 } ], colSizes0 ]; + Transpose @ Apply[ padColumn, Transpose @ { tr, colSizes }, { 1 } ] + ]; + +padColumns // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsubsection::Closed:: *) +(*padColumn*) +padColumn // beginDefinition; +padColumn[ string_String, size_Integer ] := If[ StringLength @ string >= size, string, StringPadRight[ string, size ] ]; +padColumn[ strings_List, size_Integer ] := padColumn[ #, size ] & /@ strings; +padColumn // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsubsection::Closed:: *) +(*escapeTableCharacters*) +escapeTableCharacters // beginDefinition; +escapeTableCharacters[ str_String ] := StringReplace[ str, { "|" -> "\\|", "\n" -> " " } ]; +escapeTableCharacters // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsubsection::Closed:: *) +(*insertColumnDelimiter*) insertColumnDelimiter // beginDefinition; insertColumnDelimiter[ { headings_String, rows__String }, colSizes: { __Integer }, box_ ] := { @@ -1414,14 +1639,19 @@ insertColumnDelimiter[ rows_List, _List, box_ ] := rows; insertColumnDelimiter // endDefinition; - +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsubsection::Closed:: *) +(*createAlignedDelimiters*) createAlignedDelimiters // beginDefinition; createAlignedDelimiters[ colSizes_, GridBox[ ___, GridBoxAlignment -> { ___, "Columns" -> alignments_, ___ }, ___ ] ] := createAlignedDelimiters[ colSizes, alignments ]; createAlignedDelimiters[ colSizes_, _GridBox ] := - StringRepeat[ "-", Max[ #, 1 ] ] & /@ colSizes; + If[ AnyTrue[ colSizes, GreaterThan[ $cellPageWidth ] ], + StringRepeat[ "-", Min[ 3, Max[ #, 1 ] ] ] & /@ colSizes, + StringRepeat[ "-", Min[ $cellPageWidth, Max[ #, 1 ] ] ] & /@ colSizes + ]; createAlignedDelimiters[ colSizes_List, alignments_List ] /; Length @ colSizes === Length @ alignments := createAlignedDelimiter @@@ Transpose @ { @@ -1441,14 +1671,22 @@ createAlignedDelimiters[ colSizes_List, { a: Except[ { _ } ]..., { repeat_ }, b: full = Join[ { a }, expanded, { b } ]; alignments = Take[ full, UpTo @ total ]; createAlignedDelimiter @@@ Transpose @ { - colSizes, + If[ AnyTrue[ colSizes, GreaterThan[ $cellPageWidth ] ], Clip[ colSizes, { 1, 3 } ], colSizes ], Replace[ alignments, { (Center|"Center").. } :> ConstantArray[ Automatic, total ] ] } ]; -createAlignedDelimiters // endDefinition; +createAlignedDelimiters[ colSizes_List, { alignment: Except[ _List ] } ] := + createAlignedDelimiters[ colSizes, ConstantArray[ alignment, Length @ colSizes ] ]; +createAlignedDelimiters[ colSizes_List, alignments_List ] /; Length @ alignments < Length @ colSizes := + createAlignedDelimiters[ colSizes, PadRight[ alignments, Length @ colSizes, Automatic ] ]; + +createAlignedDelimiters // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsubsection::Closed:: *) +(*createAlignedDelimiter*) createAlignedDelimiter // beginDefinition; createAlignedDelimiter[ size_Integer, "Left" | Left ] := ":" <> StringRepeat[ "-", Max[ size-1, 1 ] ]; createAlignedDelimiter[ size_Integer, "Right" | Right ] := StringRepeat[ "-", Max[ size-1, 1 ] ] <> ":"; @@ -1732,6 +1970,8 @@ $$ignoredBox = Alternatives[ Cell[ __, "NotesThumbnails", ___ ] , Cell[ __, "TutorialJumpBox", ___ ] + , + Cell[ __, $$ignoredCellStyle, ___ ] ]; @@ -1753,7 +1993,7 @@ fasterCellToString0[ ] := string; fasterCellToString0[ BoxData[ boxes_List, ___ ] ] := - With[ { strings = fasterCellToString0 /@ boxes }, + With[ { strings = fasterCellToString0 /@ DeleteCases[ boxes, "\n" ] }, StringRiffle[ strings, "\n" ] /; AllTrue[ strings, StringQ ] ]; @@ -1829,7 +2069,10 @@ fasterCellToString0[ Cell[ ] ] := Block[ { $escapeMarkdown = False }, "```" <> lang <> "\n" <> fasterCellToString0 @ box <> "\n```" ]; fasterCellToString0[ Cell[ BoxData[ boxes_, ___ ], "ChatCodeBlock", ___ ] ] := - Block[ { $escapeMarkdown = False }, "```\n" <> fasterCellToString0 @ boxes <> "\n```" ]; + Module[ { string }, + string = Block[ { $escapeMarkdown = False }, fasterCellToString0 @ boxes ]; + If[ StringMatchQ[ string, "```" ~~ __ ~~ "```" ], string, "```\n"<>string<>"\n```" ] + ]; fasterCellToString0[ _[ __, @@ -1880,7 +2123,7 @@ slowCellToString[ cell_Cell ] := Module[ { format, plain, string }, format = If[ TrueQ @ $showStringCharacters, "InputText", "PlainText" ]; - plain = Quiet @ UsingFrontEnd @ FrontEndExecute @ FrontEnd`ExportPacket[ cell, format ]; + plain = Quiet @ usingFrontEnd @ FrontEndExecute @ FrontEnd`ExportPacket[ cell, format ]; string = Replace[ plain, { { s_String? StringQ, ___ } :> s, ___ :> $Failed } ]; If[ StringQ @ string, @@ -1909,6 +2152,14 @@ $exportPacketStringReplacements = { (* ::Subsubsection::Closed:: *) (*inputFormString*) inputFormString // SetFallthroughError; + +inputFormString[ expr: h_[ args___ ], opts: OptionsPattern[ ] ] /; + ByteCount @ Unevaluated @ expr > $maxInputFormByteCount := + StringJoin[ + inputFormString @ Unevaluated @ h, + "[\[LeftSkeleton]", ToString @ Length @ HoldComplete @ args, "\[RightSkeleton]]" + ]; + inputFormString[ expr_, opts: OptionsPattern[ ] ] := StringReplace[ ToString[ Unevaluated @ expr, InputForm, @@ -1957,7 +2208,7 @@ stringToBoxes[ string_String ] := stringToBoxes[ string, (* TODO: there could be a kernel implementation of this *) - Quiet @ UsingFrontEnd @ MathLink`CallFrontEnd @ FrontEnd`UndocumentedTestFEParserPacket[ string, True ] + Quiet @ usingFrontEnd @ MathLink`CallFrontEnd @ FrontEnd`UndocumentedTestFEParserPacket[ string, True ] ]; stringToBoxes[ string_, { BoxData[ boxes_, ___ ], ___ } ] := boxes; @@ -1968,6 +2219,9 @@ stringToBoxes[ string_, other_ ] := string; (*makeGraphicsString*) makeGraphicsString // SetFallthroughError; +makeGraphicsString[ DynamicBox[ import_FEPrivate`ImportImage, ___ ] ] := + ToString[ RawBoxes @ DynamicBox @ import, StandardForm ]; + makeGraphicsString[ gfx_ ] := makeGraphicsString[ gfx, makeGraphicsExpression @ gfx ]; makeGraphicsString[ gfx_, HoldComplete[ expr: _Graphics|_Graphics3D|_Image|_Image3D|_Graph ] ] := @@ -2027,6 +2281,7 @@ escapeMarkdownCharactersQ[ ___ ] := True; (* ::Subsubsection::Closed:: *) (*truncateString*) truncateString // beginDefinition; +truncateString[ str_String? truncatedTableStringQ ] := str; truncateString[ str_String ] := truncateString[ str, $maxOutputCellStringLength ]; truncateString[ str_String, Automatic ] := truncateString[ str, $defaultMaxOutputCellStringLength ]; truncateString[ str_String, max: $$size ] := stringTrimMiddle[ str, max ]; @@ -2034,6 +2289,25 @@ truncateString[ other_ ] := other; truncateString[ other_, _Integer ] := other; truncateString // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*truncatedTableStringQ*) +truncatedTableStringQ // beginDefinition; + +truncatedTableStringQ[ str_String ] := TrueQ @ And[ + StringStartsQ[ str, "|" ], + StringMatchQ[ + str, + StringExpression[ + Shortest[ ("| " ~~ Except[ "\n" ].. ~~ " |\n").. ], + "\[LeftSkeleton]" ~~ ("one row removed" | (DigitCharacter.. ~~ " rows removed")) ~~ "\[RightSkeleton]\n", + Shortest[ ("| " ~~ Except[ "\n" ].. ~~ " |" ~~ ("\n"|EndOfString))... ] + ] + ] +]; + +truncatedTableStringQ // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*truncateStackString*) @@ -2291,6 +2565,7 @@ formatMetadata[ ___ ] := (* ::Subsubsection::Closed:: *) (*codeBlockQ*) codeBlockQ // beginDefinition; +codeBlockQ[ Cell[ _, OptionsPattern[ ] ] ] := False; codeBlockQ[ Cell[ __, $$noCodeBlockStyle, ___ ] ] := False; codeBlockQ[ Cell[ __, "Program", ___ ] ] := True; codeBlockQ[ Cell[ __, CellTags -> { ___, "CheckboxCell", ___ }, ___ ] ] := False; @@ -2384,8 +2659,8 @@ firstMatchingCellGroup[ nb_, patt_, "Content" ] := Catch[ (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; End[ ]; diff --git a/Source/Chatbook/Services.wl b/Source/Chatbook/Services.wl index fab8515b..398af209 100644 --- a/Source/Chatbook/Services.wl +++ b/Source/Chatbook/Services.wl @@ -1,29 +1,13 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Services`" ]; +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -HoldComplete[ - `$allowConnectionDialog; - `$availableServices; - `$enableLLMServices; - `$serviceCache; - `$servicesLoaded; - `$useLLMServices; - `getAvailableServiceNames; - `getAvailableServices; - `getServiceModelList; - `modelListCachedQ; -]; - -Begin[ "`Private`" ]; - -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Dynamics`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; -Needs[ "Wolfram`Chatbook`UI`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`UI`" ]; $ContextAliases[ "llm`" ] = "LLMServices`"; @@ -33,7 +17,7 @@ $ContextAliases[ "llm`" ] = "LLMServices`"; $allowConnectionDialog = True; $enableLLMServices = Automatic; $modelListCache = <| |>; -$modelSortOrder = { "Snapshot", "FineTuned", "DisplayName" }; +$modelSortOrder = { "Preview", "Snapshot", "FineTuned", "Date", "DisplayName" }; $servicesLoaded = False; $useLLMServices := MatchQ[ $enableLLMServices, Automatic|True ] && TrueQ @ $llmServicesAvailable; $serviceCache = None; @@ -70,8 +54,17 @@ $availableServiceNames := getAvailableServiceNames[ ]; (* ::Subsection::Closed:: *) (*getAvailableServiceNames*) getAvailableServiceNames // beginDefinition; -getAvailableServiceNames[ ] := getAvailableServiceNames @ $availableServices; -getAvailableServiceNames[ services_Association ] := Keys @ services; +getAvailableServiceNames // Options = { "IncludeHidden" -> True }; + +getAvailableServiceNames[ opts: OptionsPattern[ ] ] := + getAvailableServiceNames[ $availableServices, opts ]; + +getAvailableServiceNames[ services_Association, opts: OptionsPattern[ ] ] := + If[ TrueQ @ OptionValue[ "IncludeHidden" ], + Keys @ services, + Keys @ DeleteCases[ services, KeyValuePattern[ "Hidden" -> True ] ] + ]; + getAvailableServiceNames // endDefinition; (* ::**************************************************************************************************************:: *) @@ -277,8 +270,8 @@ getOpenAIChatModels // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Settings.wl b/Source/Chatbook/Settings.wl index d64a298b..2bb349a6 100644 --- a/Source/Chatbook/Settings.wl +++ b/Source/Chatbook/Settings.wl @@ -1,34 +1,16 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Settings`" ]; +Begin[ "`Private`" ]; (* :!CodeAnalysis::BeginBlock:: *) -HoldComplete[ - `$defaultChatSettings; - `currentChatSettings; - `dynamicSplitQ; - `getPrecedingDelimiter; - `multimodalPacletsAvailable; - `resolveAutoSettings; - `toolsEnabledQ; -]; - -Begin[ "`Private`" ]; - Needs[ "Wolfram`Chatbook`" ]; Needs[ "Wolfram`Chatbook`Actions`" ]; -Needs[ "Wolfram`Chatbook`ChatMessages`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`Handlers`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; Needs[ "Wolfram`Chatbook`ResourceInstaller`" ]; -Needs[ "Wolfram`Chatbook`SendChat`" ]; Needs[ "Wolfram`Chatbook`Serialization`" ]; -Needs[ "Wolfram`Chatbook`Services`" ]; -Needs[ "Wolfram`Chatbook`Tools`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -37,52 +19,57 @@ $cloudInheritanceFix := $cloudNotebooks; (* cSpell: ignore AIAPI *) $defaultChatSettings = <| - "Assistance" -> Automatic, - "Authentication" -> Automatic, - "AutoFormat" -> True, - "BasePrompt" -> Automatic, - "ChatContextPreprompt" -> Automatic, - "ChatDrivenNotebook" -> False, - "ChatHistoryLength" -> 100, - "ChatInputIndicator" -> Automatic, - "DynamicAutoFormat" -> Automatic, - "EnableChatGroupSettings" -> False, - "EnableLLMServices" -> Automatic, (* TODO: remove this once LLMServices is widely available *) - "FrequencyPenalty" -> 0.1, - "HandlerFunctions" :> $DefaultChatHandlerFunctions, - "HandlerFunctionsKeys" -> Automatic, - "IncludeHistory" -> Automatic, - "InitialChatCell" -> True, - "LLMEvaluator" -> "CodeAssistant", - "MaxCellStringLength" -> Automatic, - "MaxContextTokens" -> Automatic, - "MaxOutputCellStringLength" -> Automatic, - "MaxTokens" -> Automatic, - "MergeMessages" -> True, - "Model" :> $DefaultModel, - "Multimodal" -> Automatic, - "NotebookWriteMethod" -> Automatic, - "OpenAIAPICompletionURL" -> "https://api.openai.com/v1/chat/completions", - "OpenAIKey" -> Automatic, (* TODO: remove this once LLMServices is widely available *) - "PresencePenalty" -> 0.1, - "ProcessingFunctions" :> $DefaultChatProcessingFunctions, - "Prompts" -> { }, - "SetCellDingbat" -> True, - "ShowMinimized" -> Automatic, - "StreamingOutputMethod" -> Automatic, - "TargetCloudObject" -> Automatic, - "Temperature" -> 0.7, - "TokenBudgetMultiplier" -> Automatic, - "Tokenizer" -> Automatic, - "ToolCallFrequency" -> Automatic, - "ToolMethod" -> Automatic, - "ToolOptions" :> $DefaultToolOptions, - "Tools" -> Automatic, - "ToolSelectionType" -> <| |>, - "ToolsEnabled" -> Automatic, - "TopP" -> 1, - "TrackScrollingWhenPlaced" -> Automatic, - "VisiblePersonas" -> $corePersonaNames + "Assistance" -> Automatic, + "Authentication" -> Automatic, + "AutoFormat" -> True, + "BasePrompt" -> Automatic, + "BypassResponseChecking" -> False, + "ChatContextPreprompt" -> Automatic, + "ChatDrivenNotebook" -> False, + "ChatHistoryLength" -> 1000, + "ChatInputIndicator" -> Automatic, + "ConversionRules" -> None, + "DynamicAutoFormat" -> Automatic, + "EnableChatGroupSettings" -> False, + "EnableLLMServices" -> Automatic, + "FrequencyPenalty" -> 0.1, + "HandlerFunctions" :> $DefaultChatHandlerFunctions, + "HandlerFunctionsKeys" -> Automatic, + "IncludeHistory" -> Automatic, + "InitialChatCell" -> True, + "LLMEvaluator" -> "CodeAssistant", + "MaxCellStringLength" -> Automatic, + "MaxContextTokens" -> Automatic, + "MaxOutputCellStringLength" -> Automatic, + "MaxTokens" -> Automatic, + "MergeMessages" -> True, + "Model" :> $DefaultModel, + "Multimodal" -> Automatic, + "NotebookWriteMethod" -> Automatic, + "OpenAIAPICompletionURL" -> "https://api.openai.com/v1/chat/completions", + "OpenAIKey" -> Automatic, + "PresencePenalty" -> 0.1, + "ProcessingFunctions" :> $DefaultChatProcessingFunctions, + "Prompts" -> { }, + "SetCellDingbat" -> True, + "ShowMinimized" -> Automatic, + "StreamingOutputMethod" -> Automatic, + "TabbedOutput" -> True, (* TODO: define a "MaxOutputPages" setting *) + "TargetCloudObject" -> Automatic, + "Temperature" -> 0.7, + "TokenBudgetMultiplier" -> Automatic, + "Tokenizer" -> Automatic, + "ToolCallExamplePromptStyle" -> Automatic, + "ToolCallFrequency" -> Automatic, + "ToolExamplePrompt" -> Automatic, + "ToolMethod" -> Automatic, + "ToolOptions" :> $DefaultToolOptions, + "Tools" -> Automatic, + "ToolSelectionType" -> <| |>, + "ToolsEnabled" -> Automatic, + "TopP" -> 1, + "TrackScrollingWhenPlaced" -> Automatic, + "VisiblePersonas" -> $corePersonaNames |>; $cachedGlobalSettings := $cachedGlobalSettings = getGlobalSettingsFile[ ]; @@ -99,6 +86,10 @@ $nonInheritedPersonaValues = { "ServiceDefaultModel" }; +$currentChatSettings = None; +$currentSettingsCache = None; +$absoluteCurrentSettingsCache = None; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*Argument Patterns*) @@ -111,7 +102,7 @@ $$frontEndObject = HoldPattern[ $FrontEnd | _FrontEndObject ]; $ChatAbort = None; $ChatPost = None; $ChatPre = None; -$DefaultModel = <| "Service" -> "OpenAI", "Name" -> "gpt-4" |>; +$DefaultModel = <| "Service" -> "OpenAI", "Name" -> "gpt-4o" |>; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) @@ -134,15 +125,54 @@ $DefaultChatProcessingFunctions = <| "WriteChatOutputCell" -> WriteChatOutputCell |>; +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*$CurrentChatSettings*) +$CurrentChatSettings := If[ AssociationQ @ $currentChatSettings, $currentChatSettings, AbsoluteCurrentChatSettings[ ] ]; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*AbsoluteCurrentChatSettings*) AbsoluteCurrentChatSettings // beginDefinition; -AbsoluteCurrentChatSettings[ ] := AbsoluteCurrentChatSettings @ $FrontEnd; -AbsoluteCurrentChatSettings[ obj: $$feObj ] := resolveAutoSettings @ currentChatSettings @ obj; -AbsoluteCurrentChatSettings[ obj: $$feObj, keys__String ] := AbsoluteCurrentChatSettings[ obj ][ keys ]; +AbsoluteCurrentChatSettings[ ] := catchMine @ AbsoluteCurrentChatSettings @ $FrontEnd; +AbsoluteCurrentChatSettings[ obj: $$feObj ] := catchMine @ absoluteCurrentChatSettings @ obj; +AbsoluteCurrentChatSettings[ obj: $$feObj, keys__String ] := catchMine @ absoluteCurrentChatSettings[ obj, keys ]; AbsoluteCurrentChatSettings // endExportedDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*absoluteCurrentChatSettings*) +absoluteCurrentChatSettings // beginDefinition; + +absoluteCurrentChatSettings[ obj: $$feObj ] := Enclose[ + Catch @ Module[ { cached, settings }, + cached = $absoluteCurrentSettingsCache @ obj; + If[ AssociationQ @ cached, Throw @ cached ]; + settings = ConfirmBy[ absoluteCurrentChatSettings0 @ obj, AssociationQ, "Settings" ]; + If[ AssociationQ @ $absoluteCurrentSettingsCache, + $absoluteCurrentSettingsCache[ obj ] = settings, + settings + ] + ], + throwInternalFailure +]; + +absoluteCurrentChatSettings[ obj: $$feObj, keys__ ] := Enclose[ + Module[ { settings }, + settings = ConfirmBy[ absoluteCurrentChatSettings @ obj, AssociationQ, "Settings" ]; + Replace[ settings @ keys, _Missing -> Inherited ] + ], + throwInternalFailure +]; + +absoluteCurrentChatSettings // endDefinition; + + +absoluteCurrentChatSettings0 // beginDefinition; +absoluteCurrentChatSettings0[ ] := absoluteCurrentChatSettings0 @ $FrontEnd; +absoluteCurrentChatSettings0[ obj: $$feObj ] := resolveAutoSettings @ currentChatSettings @ obj; +absoluteCurrentChatSettings0 // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*resolveAutoSettings*) @@ -156,6 +186,8 @@ resolveAutoSettings[ settings: KeyValuePattern[ "ResolvedAutoSettings" -> True ] resolveAutoSettings[ settings0_Association ] := Enclose[ Module[ { persona, combined, settings, resolved }, + If[ $catching, $currentChatSettings = settings0 ]; + persona = ConfirmMatch[ getLLMEvaluator @ settings0, _String |_Association | None, "LLMEvaluator" ]; combined = If[ AssociationQ @ persona, @@ -195,7 +227,18 @@ resolveAutoSettings[ settings0_Association ] := Enclose[ "Resolved" ]; - If[ TrueQ @ $chatState, addHandlerArguments[ "ChatNotebookSettings" -> resolved ] ]; + If[ $chatState, + addHandlerArguments[ "ChatNotebookSettings" -> resolved ]; + + (* TODO: this is not ideal *) + $multimodalMessages = TrueQ @ resolved[ "Multimodal" ]; + $tokenBudget = makeTokenBudget @ resolved; + $tokenPressure = 0.0; + $initialCellStringBudget = makeCellStringBudget @ resolved; + $cellStringBudget = $initialCellStringBudget; + $conversionRules = resolved[ "ConversionRules" ]; + ]; + If[ $catching, $currentChatSettings = resolved ]; resolved ], @@ -212,12 +255,19 @@ resolveAutoSettings0[ settings: KeyValuePattern[ _ :> _ ] ] := resolveAutoSettings @ AssociationMap[ Apply @ Rule, settings ]; resolveAutoSettings0[ settings_Association ] := Enclose[ - Module[ { auto, sorted, resolved }, + Module[ { auto, sorted, resolved, result }, auto = ConfirmBy[ Select[ settings, SameAs @ Automatic ], AssociationQ, "Auto" ]; sorted = ConfirmBy[ <| KeyTake[ auto, $autoSettingKeyPriority ], auto |>, AssociationQ, "Sorted" ]; resolved = ConfirmBy[ Fold[ resolveAutoSetting, settings, Normal @ sorted ], AssociationQ, "Resolved" ]; - If[ resolved[ "Assistance" ] && $chatState, $AutomaticAssistance = True ]; - ConfirmBy[ resolveTools @ KeySort @ resolved, AssociationQ, "ResolveTools" ] + If[ $chatState, + If[ resolved[ "Assistance" ], $AutomaticAssistance = True ]; + If[ resolved[ "WorkspaceChat" ], $WorkspaceChat = True ]; + ]; + result = ConfirmBy[ resolveTools @ KeySort @ resolved, AssociationQ, "ResolveTools" ]; + If[ result[ "ToolMethod" ] === Automatic, + result[ "ToolMethod" ] = chooseToolMethod @ result + ]; + result ], throwInternalFailure ]; @@ -240,41 +290,45 @@ resolveAutoSetting[ settings_, key_ -> value_ ] := <| settings, key -> resolveAu resolveAutoSetting // endDefinition; resolveAutoSetting0 // beginDefinition; -resolveAutoSetting0[ as_, "Assistance" ] := False; -resolveAutoSetting0[ as_, "DynamicAutoFormat" ] := dynamicAutoFormatQ @ as; -resolveAutoSetting0[ as_, "ChatInputIndicator" ] := "\|01f4ac"; -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_, "TokenBudgetMultiplier" ] := 1; -resolveAutoSetting0[ as_, "Tokenizer" ] := getTokenizer @ as; -resolveAutoSetting0[ as_, "TokenizerName" ] := getTokenizerName @ as; -resolveAutoSetting0[ as_, "ToolCallFrequency" ] := Automatic; -resolveAutoSetting0[ as_, "ToolsEnabled" ] := toolsEnabledQ @ as; -resolveAutoSetting0[ as_, "TrackScrollingWhenPlaced" ] := scrollOutputQ @ as; -resolveAutoSetting0[ as_, key_String ] := Automatic; +resolveAutoSetting0[ as_, "Assistance" ] := False; +resolveAutoSetting0[ as_, "ChatInputIndicator" ] := "\|01f4ac"; +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_, "TokenBudgetMultiplier" ] := 1; +resolveAutoSetting0[ as_, "Tokenizer" ] := getTokenizer @ as; +resolveAutoSetting0[ as_, "TokenizerName" ] := getTokenizerName @ as; +resolveAutoSetting0[ as_, "ToolCallExamplePromptStyle" ] := chooseToolExamplePromptStyle @ as; +resolveAutoSetting0[ as_, "ToolCallFrequency" ] := Automatic; +resolveAutoSetting0[ as_, "ToolExamplePrompt" ] := chooseToolExamplePromptSpec @ as; +resolveAutoSetting0[ as_, "ToolsEnabled" ] := toolsEnabledQ @ as; +resolveAutoSetting0[ as_, "TrackScrollingWhenPlaced" ] := scrollOutputQ @ as; +resolveAutoSetting0[ as_, key_String ] := Automatic; resolveAutoSetting0 // endDefinition; (* Settings that require other settings to be resolved first: *) $autoSettingKeyDependencies = <| - "HandlerFunctionsKeys" -> "EnableLLMServices", - "MaxCellStringLength" -> { "Model", "MaxContextTokens" }, - "MaxContextTokens" -> "Model", - "MaxOutputCellStringLength" -> "MaxCellStringLength", - "MaxTokens" -> "Model", - "Multimodal" -> { "EnableLLMServices", "Model" }, - "Tokenizer" -> "TokenizerName", - "TokenizerName" -> "Model", - "Tools" -> { "LLMEvaluator", "ToolsEnabled" }, - "ToolsEnabled" -> { "Model", "ToolCallFrequency" } + "HandlerFunctionsKeys" -> "EnableLLMServices", + "MaxCellStringLength" -> { "Model", "MaxContextTokens" }, + "MaxContextTokens" -> "Model", + "MaxOutputCellStringLength" -> "MaxCellStringLength", + "MaxTokens" -> "Model", + "Multimodal" -> { "EnableLLMServices", "Model" }, + "Tokenizer" -> "TokenizerName", + "TokenizerName" -> "Model", + "ToolCallExamplePromptStyle" -> "Model", + "ToolExamplePrompt" -> "Model", + "Tools" -> { "LLMEvaluator", "ToolsEnabled" }, + "ToolsEnabled" -> { "Model", "ToolCallFrequency" } |>; (* Sort topologically so dependencies will be satisfied in order: *) @@ -294,6 +348,61 @@ $autoSettingKeyPriority := Enclose[ * ChatContextPreprompt *) +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*chooseToolMethod*) +chooseToolMethod // beginDefinition; +chooseToolMethod[ as_Association ] := chooseToolMethod[ as, as[ "Tools" ] ]; +chooseToolMethod[ as_, tools_List ] := If[ AllTrue[ tools, simpleToolQ ], "Simple", Automatic ]; +chooseToolMethod[ as_, _ ] := Automatic; +chooseToolMethod // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*simpleToolQ*) +simpleToolQ // beginDefinition; +simpleToolQ[ tool_ ] := simpleToolQ[ tool, $DefaultTools ]; +simpleToolQ[ name_String, default_Association ] := KeyExistsQ[ default, name ]; +simpleToolQ[ tool_LLMTool, default_Association ] := MemberQ[ default, tool ]; +simpleToolQ[ _, default_Association ] := False; +simpleToolQ // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*chooseToolExamplePromptSpec*) +chooseToolExamplePromptSpec // beginDefinition; +chooseToolExamplePromptSpec[ as_Association ] := chooseToolExamplePromptSpec[ as, as[ "Model" ] ]; +chooseToolExamplePromptSpec[ as_, model_String ] := autoToolExamplePromptSpec[ "OpenAI" ]; +chooseToolExamplePromptSpec[ as_, { service_String, _String } ] := autoToolExamplePromptSpec @ service; +chooseToolExamplePromptSpec[ as_, model_Association ] := autoToolExamplePromptSpec @ model[ "Service" ]; +chooseToolExamplePromptSpec // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*autoToolExamplePromptSpec*) +autoToolExamplePromptSpec // beginDefinition; +autoToolExamplePromptSpec[ _ ] := Automatic; +autoToolExamplePromptSpec // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*chooseToolExamplePromptStyle*) +chooseToolExamplePromptStyle // beginDefinition; +chooseToolExamplePromptStyle[ as_Association ] := chooseToolExamplePromptStyle[ as, as[ "Model" ] ]; +chooseToolExamplePromptStyle[ as_, model_String ] := autoToolExamplePromptStyle[ "OpenAI" ]; +chooseToolExamplePromptStyle[ as_, { service_String, _String } ] := autoToolExamplePromptStyle @ service; +chooseToolExamplePromptStyle[ as_, model_Association ] := autoToolExamplePromptStyle @ model[ "Service" ]; +chooseToolExamplePromptStyle // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*autoToolExamplePromptStyle*) +autoToolExamplePromptStyle // beginDefinition; +autoToolExamplePromptStyle[ "AzureOpenAI"|"OpenAI" ] := "ChatML"; +autoToolExamplePromptStyle[ "Anthropic" ] := "XML"; +autoToolExamplePromptStyle[ _ ] := "Basic"; (* TODO: measure performance of other models to choose the best option *) +autoToolExamplePromptStyle // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*chooseMaxCellStringLength*) @@ -323,15 +432,19 @@ autoMaxContextTokens // endDefinition; autoMaxContextTokens0 // beginDefinition; autoMaxContextTokens0[ name_String ] := autoMaxContextTokens0 @ StringSplit[ name, "-"|Whitespace ]; -autoMaxContextTokens0[ { ___, "gpt", "4", "vision" , ___ } ] := 2^17; -autoMaxContextTokens0[ { ___, "gpt", "4", "turbo" , ___ } ] := 2^17; -autoMaxContextTokens0[ { ___, "claude", "2" , ___ } ] := 10^5; -autoMaxContextTokens0[ { ___, "16k" , ___ } ] := 2^14; -autoMaxContextTokens0[ { ___, "32k" , ___ } ] := 2^15; -autoMaxContextTokens0[ { ___, "gpt", "4" , ___ } ] := 2^13; -autoMaxContextTokens0[ { ___, "gpt", "3.5" , ___ } ] := 2^12; -autoMaxContextTokens0[ { ___, "chat", "bison", "001", ___ } ] := 20000; -autoMaxContextTokens0[ _List ] := 2^12; +autoMaxContextTokens0[ { ___, "gpt", "4o" , ___ } ] := 2^17; +autoMaxContextTokens0[ { ___, "gpt", "4", "vision" , ___ } ] := 2^17; +autoMaxContextTokens0[ { ___, "gpt", "4", "turbo" , ___ } ] := 2^17; +autoMaxContextTokens0[ { ___, "claude", "2" , ___ } ] := 10^5; +autoMaxContextTokens0[ { ___, "claude", "2.1"|"3" , ___ } ] := 2*10^5; +autoMaxContextTokens0[ { ___, "16k" , ___ } ] := 2^14; +autoMaxContextTokens0[ { ___, "32k" , ___ } ] := 2^15; +autoMaxContextTokens0[ { ___, "gpt", "4" , ___ } ] := 2^13; +autoMaxContextTokens0[ { ___, "gpt", "3.5" , ___ } ] := 2^12; +autoMaxContextTokens0[ { ___, "chat", "bison", "001" , ___ } ] := 20000; +autoMaxContextTokens0[ { ___, "gemini", ___, "pro", "vision", ___ } ] := 12288; +autoMaxContextTokens0[ { ___, "gemini", ___, "pro" , ___ } ] := 30720; +autoMaxContextTokens0[ _List ] := 2^12; autoMaxContextTokens0 // endDefinition; (* ::**************************************************************************************************************:: *) @@ -438,12 +551,20 @@ getNamedLLMEvaluator // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*toolsEnabledQ*) +$$disabledToolsModel = Alternatives[ + ___ ~~ "gpt-3" ~~ ___, + "chat-bison-001", + "claude-instant-1.2", + "gemini-1.0-pro" ~~ ___, + "gemini-pro-vision", + "gemini-pro" +]; + toolsEnabledQ[ KeyValuePattern[ "ToolsEnabled" -> enabled: True|False ] ] := enabled; toolsEnabledQ[ KeyValuePattern[ "ToolCallFrequency" -> freq: (_Integer|_Real)? NonPositive ] ] := False; toolsEnabledQ[ KeyValuePattern[ "Model" -> model_ ] ] := toolsEnabledQ @ toModelName @ model; toolsEnabledQ[ model: KeyValuePattern @ { "Service" -> _, "Name" -> _ } ] := toolsEnabledQ @ toModelName @ model; -toolsEnabledQ[ "chat-bison-001" ] := False; -toolsEnabledQ[ model_String ] := ! TrueQ @ StringContainsQ[ model, "gpt-3", IgnoreCase -> True ]; +toolsEnabledQ[ model_String ] := ! StringMatchQ[ model, $$disabledToolsModel, IgnoreCase -> True ]; toolsEnabledQ[ ___ ] := False; (* ::**************************************************************************************************************:: *) @@ -583,25 +704,37 @@ setCurrentChatSettings0 // endDefinition; setCurrentChatSettings1 // beginDefinition; -setCurrentChatSettings1[ scope: $$feObj, Inherited ] := +setCurrentChatSettings1[ scope: $$feObj, Inherited ] := WithCleanup[ If[ TrueQ @ $CloudEvaluation, setCurrentChatSettingsCloud[ scope, Inherited ], CurrentValue[ scope, { TaggingRules, "ChatNotebookSettings" } ] = Inherited - ]; + ], + (* Invalidate cache *) + $currentSettingsCache = <| |> + (* Note: It may be more slightly more efficient to just invalidate for the given `scope`, but that would require + also finding scopes that `scope` inherits from and invalidating those as well. This is much simpler. *) +]; setCurrentChatSettings1[ scope: $$feObj, value_ ] := With[ { as = Association @ value }, - If[ TrueQ @ $CloudEvaluation, - setCurrentChatSettingsCloud[ scope, as ], - CurrentValue[ scope, { TaggingRules, "ChatNotebookSettings" } ] = as + WithCleanup[ + If[ TrueQ @ $CloudEvaluation, + setCurrentChatSettingsCloud[ scope, as ], + CurrentValue[ scope, { TaggingRules, "ChatNotebookSettings" } ] = as + ], + (* Invalidate cache *) + $currentSettingsCache = <| |> ] /; AssociationQ @ as ]; -setCurrentChatSettings1[ scope: $$feObj, key_String? StringQ, value_ ] := +setCurrentChatSettings1[ scope: $$feObj, key_String? StringQ, value_ ] := WithCleanup[ If[ TrueQ @ $CloudEvaluation, setCurrentChatSettingsCloud[ scope, key, value ], CurrentValue[ scope, { TaggingRules, "ChatNotebookSettings", key } ] = value - ]; + ], + (* Invalidate cache *) + $currentSettingsCache = <| |> +]; setCurrentChatSettings1 // endDefinition; @@ -782,14 +915,8 @@ unsetCurrentChatSettings[ obj: $$feObj, key_ ] := throwFailure[ unsetCurrentChatSettings // endDefinition; unsetCurrentChatSettings0 // beginDefinition; - -(* FIXME: make this work in cloud *) -unsetCurrentChatSettings0[ obj: $$feObj ] := - (CurrentValue[ obj, { TaggingRules, "ChatNotebookSettings" } ] = Inherited); - -unsetCurrentChatSettings0[ obj: $$feObj, key_? StringQ ] := - (CurrentValue[ obj, { TaggingRules, "ChatNotebookSettings" } ] = Inherited); - +unsetCurrentChatSettings0[ obj: $$feObj ] := setCurrentChatSettings[ obj, Inherited ]; +unsetCurrentChatSettings0[ obj: $$feObj, key_? StringQ ] := setCurrentChatSettings[ obj, key, Inherited ]; unsetCurrentChatSettings0 // endDefinition; (* ::**************************************************************************************************************:: *) @@ -797,37 +924,68 @@ unsetCurrentChatSettings0 // endDefinition; (*currentChatSettings*) currentChatSettings // beginDefinition; -currentChatSettings[ fe: $$frontEndObject ] /; $cloudNotebooks := +currentChatSettings[ obj: $$feObj ] := Enclose[ + Catch @ Module[ { cached, settings }, + cached = $currentSettingsCache @ obj; + If[ AssociationQ @ cached, Throw @ cached ]; + settings = ConfirmBy[ currentChatSettings0 @ obj, AssociationQ, "Settings" ]; + If[ AssociationQ @ $currentSettingsCache, + $currentSettingsCache[ obj ] = settings, + settings + ] + ], + throwInternalFailure +]; + +currentChatSettings[ obj: $$feObj, key_ ] := Enclose[ + Catch @ Module[ { cached }, + cached = $currentSettingsCache @ obj; + If[ AssociationQ @ cached && KeyExistsQ[ cached, key ], Throw @ cached @ key ]; + If[ AssociationQ @ $currentSettingsCache, + Lookup[ ConfirmBy[ currentChatSettings @ obj, AssociationQ, "Settings" ], key, Inherited ], + currentChatSettings0[ obj, key ] + ] + ], + throwInternalFailure +]; + +currentChatSettings // endDefinition; + + +currentChatSettings0 // beginDefinition; + +currentChatSettings0[ fe: $$frontEndObject ] /; $CloudEvaluation := getGlobalChatSettings[ ]; -currentChatSettings[ fe: $$frontEndObject, key_String ] /; $cloudNotebooks := +currentChatSettings0[ fe: $$frontEndObject, key_String ] /; $CloudEvaluation := getGlobalChatSettings[ key ]; -currentChatSettings[ obj: _NotebookObject|_FrontEndObject|$FrontEndSession ] := ( +currentChatSettings0[ obj: _NotebookObject|_FrontEndObject|$FrontEndSession ] := ( verifyInheritance @ obj; - currentChatSettings0 @ obj + currentChatSettings1 @ obj ); -currentChatSettings[ obj: _NotebookObject|_FrontEndObject|$FrontEndSession, key_String ] := ( +currentChatSettings0[ obj: _NotebookObject|_FrontEndObject|$FrontEndSession, key_String ] := ( verifyInheritance @ obj; - currentChatSettings0[ obj, key ] + currentChatSettings1[ obj, key ] ); -currentChatSettings[ cell0_CellObject ] := Catch @ Enclose[ - Module[ { cell, cellInfo, styles, nbo, delimiter, settings }, +currentChatSettings0[ cell0_CellObject ] := Catch @ Enclose[ + Catch @ Module[ { cell, cellInfo, styles, nbo, delimiter, settings }, verifyInheritance @ cell0; - cell = cell0; - cellInfo = ConfirmBy[ cellInformation @ cell, AssociationQ, "CellInformation" ]; - styles = ConfirmMatch[ Flatten @ List @ Lookup[ cellInfo, "Style" ], { ___String } ]; + cell = cell0; + cellInfo = ConfirmMatch[ cellInformation @ cell, _Association|_Missing, "CellInformation" ]; + If[ MissingQ @ cellInfo, Throw @ Missing[ "NotAvailable" ] ]; + styles = ConfirmMatch[ Flatten @ List @ Lookup[ cellInfo, "Style" ], { ___String } ]; If[ MemberQ[ styles, $$nestedCellStyle ], cell = ConfirmMatch[ topParentCell @ cell, _CellObject, "ParentCell" ]; styles = cellStyles @ cell; ]; - If[ cellInfo[ "ChatNotebookSettings", "ChatDelimiter" ], Throw @ currentChatSettings0 @ cell ]; + If[ cellInfo[ "ChatNotebookSettings", "ChatDelimiter" ], Throw @ currentChatSettings1 @ cell ]; nbo = ConfirmMatch[ parentNotebook @ cell, _NotebookObject, "ParentNotebook" ]; @@ -849,24 +1007,25 @@ currentChatSettings[ cell0_CellObject ] := Catch @ Enclose[ "CombinedSettings" ] ], - throwInternalFailure[ currentChatSettings @ cell0, ## ] & + throwInternalFailure ]; -currentChatSettings[ cell0_CellObject, key_String ] := Catch @ Enclose[ - Module[ { cell, cellInfo, styles, nbo, cells, delimiter, values }, +currentChatSettings0[ cell0_CellObject, key_String ] := Catch @ Enclose[ + Catch @ Module[ { cell, cellInfo, styles, nbo, cells, delimiter, values }, verifyInheritance @ cell0; - cell = cell0; - cellInfo = ConfirmBy[ cellInformation @ cell, AssociationQ, "CellInformation" ]; - styles = ConfirmMatch[ Flatten @ List @ Lookup[ cellInfo, "Style" ], { ___String } ]; + cell = cell0; + cellInfo = ConfirmMatch[ cellInformation @ cell, _Association|_Missing, "CellInformation" ]; + If[ MissingQ @ cellInfo, Throw @ Missing[ "NotAvailable" ] ]; + styles = ConfirmMatch[ Flatten @ List @ Lookup[ cellInfo, "Style" ], { ___String } ]; If[ MemberQ[ styles, $$nestedCellStyle ], cell = ConfirmMatch[ topParentCell @ cell, _CellObject, "ParentCell" ]; styles = cellStyles @ cell; ]; - If[ cellInfo[ "ChatNotebookSettings", "ChatDelimiter" ], Throw @ currentChatSettings0[ cell, key ] ]; + If[ cellInfo[ "ChatNotebookSettings", "ChatDelimiter" ], Throw @ currentChatSettings1[ cell, key ] ]; nbo = ConfirmMatch[ parentNotebook @ cell, _NotebookObject, "ParentNotebook" ]; cells = ConfirmMatch[ Cells @ nbo, { __CellObject }, "ChatCells" ]; @@ -899,15 +1058,15 @@ currentChatSettings[ cell0_CellObject, key_String ] := Catch @ Enclose[ ] ] ], - throwInternalFailure[ currentChatSettings[ cell0, key ], ## ] & + throwInternalFailure ]; -currentChatSettings // endDefinition; +currentChatSettings0 // endDefinition; -currentChatSettings0 // beginDefinition; +currentChatSettings1 // beginDefinition; -currentChatSettings0[ obj: _CellObject|_NotebookObject|_FrontEndObject|$FrontEndSession ] := +currentChatSettings1[ obj: _CellObject|_NotebookObject|_FrontEndObject|$FrontEndSession ] := mergeChatSettings @ Map[ evaluateSettings, { @@ -920,12 +1079,12 @@ currentChatSettings0[ obj: _CellObject|_NotebookObject|_FrontEndObject|$FrontEnd } ]; -currentChatSettings0[ obj: _CellObject|_NotebookObject|_FrontEndObject|$FrontEndSession, key_String ] := Replace[ +currentChatSettings1[ obj: _CellObject|_NotebookObject|_FrontEndObject|$FrontEndSession, key_String ] := Replace[ absoluteCurrentValue[ obj, { TaggingRules, "ChatNotebookSettings", key } ], Inherited :> Lookup[ $cachedGlobalSettings, key, Lookup[ $defaultChatSettings, key, Inherited ] ] ]; -currentChatSettings0 // endDefinition; +currentChatSettings1 // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) @@ -964,7 +1123,9 @@ mergeChatSettings[ a_List ] := mergeChatSettings[ a ] = mergeChatSettings0 @ a / mergeChatSettings // endDefinition; mergeChatSettings0 // beginDefinition; -mergeChatSettings0[ { a___, Inherited.., b___ } ] := mergeChatSettings0 @ { a, b }; +mergeChatSettings0[ { a___, (Inherited|ParentList).., b___ } ] := mergeChatSettings0 @ { a, b }; +mergeChatSettings0[ { a___, { b___ }, { c___, ParentList, d___ } } ] := mergeChatSettings0 @ { a, { c, b, d } }; +mergeChatSettings0[ { a___, b: Except[ $$unspecified ], { c___, ParentList, d___ } } ] := mergeChatSettings0 @ { a, { c, b, d } }; mergeChatSettings0[ { a_? AssociationQ, b__? AssociationQ } ] := DeleteMissing @ Merge[ { a, b }, mergeChatSettings0 ]; mergeChatSettings0[ { a___, Except[ _? AssociationQ ].., b__? AssociationQ } ] := mergeChatSettings0 @ { a, b }; mergeChatSettings0[ { __, e: Except[ _? AssociationQ ] } ] := e; @@ -1000,13 +1161,16 @@ getPrecedingDelimiter[ cell_CellObject, nbo_, { before0___CellObject, cell_, ___ If[ MissingQ @ pos, Missing[ "NotAvailable" ], Extract[ before, pos ] ] ]; +getPrecedingDelimiter[ cell_CellObject, nbo_, cells: { ___CellObject } ] /; ! MemberQ[ cells, cell ] := + Missing[ "NotAvailable" ]; + getPrecedingDelimiter // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*verifyInheritance*) verifyInheritance // beginDefinition; -verifyInheritance[ obj_ ] /; $SynchronousEvaluation || $cloudNotebooks := True; +verifyInheritance[ obj_ ] /; $SynchronousEvaluation || $CloudEvaluation := True; verifyInheritance[ obj_? inheritingQ ] := True; verifyInheritance[ obj: $$feObj ] := With[ { verified = verifyInheritance0 @ obj }, inheritingQ @ obj ]; verifyInheritance // endDefinition; @@ -1140,7 +1304,7 @@ associationComplement // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $mergeSettingsDispatch; ]; diff --git a/Source/Chatbook/ToolManager.wl b/Source/Chatbook/ToolManager.wl index ff6caa2b..aee9a049 100644 --- a/Source/Chatbook/ToolManager.wl +++ b/Source/Chatbook/ToolManager.wl @@ -11,15 +11,8 @@ Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Dialogs`" ]; -Needs[ "Wolfram`Chatbook`Dynamics`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; Needs[ "Wolfram`Chatbook`ResourceInstaller`" ]; -Needs[ "Wolfram`Chatbook`SendChat`" ]; -Needs[ "Wolfram`Chatbook`Settings`" ]; -Needs[ "Wolfram`Chatbook`Tools`" ]; Needs[ "Wolfram`Chatbook`UI`" ]; (* ::**************************************************************************************************************:: *) @@ -40,7 +33,7 @@ CreateLLMToolManagerDialog // beginDefinition; CreateLLMToolManagerDialog[ args___ ] := createDialog[ CreateLLMToolManagerPanel @ args, - WindowTitle -> "Add & Manage Tools" + WindowTitle -> tr[ "ToolManagerTitle" ] ]; CreateLLMToolManagerDialog // endDefinition; @@ -159,10 +152,10 @@ CreateLLMToolManagerPanel[ tools0_List, personas_List ] := Background -> GrayLevel[ 0.898 ] ], { - Row @ { Spacer[ 4 ], "Tool" }, + Row @ { Spacer[ 4 ], tr[ "ToolManagerTool" ] }, Row @ { Spacer[ 4 ], - "Enabled for\[VeryThinSpace]:", + tr[ "ToolManagerEnabledFor" ], Spacer[ 5 ], personaNameDisp[ personaDisplayNames, Dynamic @ column ] } @@ -798,13 +791,14 @@ deleteButton0[ colBin_, row_, tool_Association ] := Button[ Dynamic @ iconData[ "Bin", colBin ], attachOverlay[ { - Style[ "Delete Tool", "DialogHeader", FontSize -> 16, FontWeight -> "DemiBold" ], + Style[ tr[ "ToolManagerDeleteTool" ], "DialogHeader", FontSize -> 16, FontWeight -> "DemiBold" ], Row @ { inlineTemplateBox @ tool[ "Icon" ], Spacer[ 5 ], tool[ "CanonicalName" ] }, { - redDialogButtonLabel[ " Cancel " ], - Hold[ NotebookDelete @ EvaluationCell[ ] ], - grayDialogButtonLabel[ " Delete " ], - Hold[ deleteTool @ tool; NotebookDelete @ EvaluationCell[ ] ] + redDialogButtonLabel @ Row @ { " ", tr[ "CancelButton" ], " " }, + Hold @ NotebookDelete @ EvaluationCell[ ], + grayDialogButtonLabel @ Row @ { " ", tr[ "DeleteButton" ], " " }, + Hold[ deleteTool @ tool; + NotebookDelete @ EvaluationCell[ ] ] } }, FrameMargins -> { 13 * { 1, 1 }, 10 * { 1, 1 } }, @@ -825,13 +819,13 @@ deleteButton0 // endDefinition; nonDeletableTooltip // beginDefinition; nonDeletableTooltip[ KeyValuePattern @ { "CanonicalName" -> name_String, "Origin" -> "BuiltIn" } ] := - name<>" is a built-in tool and cannot be deleted."; + trStringTemplate[ "ToolManagerTooltipNonDeletable1" ][ <| "name" -> name |> ]; nonDeletableTooltip[ KeyValuePattern @ { "CanonicalName" -> name_String, "Origin" -> "Persona", "PersonaName" -> persona_String -} ] := name<>" is provided by the persona "<>persona<>" and cannot be deleted separately."; +} ] := trStringTemplate[ "ToolManagerTooltipNonDeletable2" ][ <| "name" -> name, "persona" -> persona |> ]; nonDeletableTooltip // endDefinition; @@ -841,7 +835,7 @@ nonDeletableTooltip // endDefinition; nonConfigurableTooltip // beginDefinition; nonConfigurableTooltip[ KeyValuePattern[ "CanonicalName" -> name_String ] ] := - name<>" does not have any configurable parameters."; + trStringTemplate[ "ToolManagerTooltipNonConfigurable" ][ <| "name" -> name |> ]; nonConfigurableTooltip // endDefinition; @@ -998,10 +992,10 @@ rightColControl[ setCV[ scope, "ToolSelectionType", toolName, # ] & ], { - Inherited -> "Enabled by persona", + Inherited -> tr[ "ToolManagerEnabledByPersona" ], Delimiter, - None -> "Never enabled", - All -> "Always enabled" + None -> tr[ "ToolManagerEnabledNever" ], + All -> tr[ "ToolManagerEnabledAlways" ] }, "", PaneSelector[ @@ -1033,7 +1027,7 @@ rightColControl[ Join[ Map[ Nest[ Unevaluated, Splice @ { #, Spacer[ 5 ] }, 2 ] &, - { "Always", "Always", "Never", "Never" } + { tr[ "Always" ], tr[ "Always" ], tr[ "Never" ], tr[ "Never" ] } ], { "", "" } ], @@ -1139,9 +1133,9 @@ scopeSelector[ Dynamic[ scopeMode_ ] ] := ActionMenu[ grayDialogButtonLabel @ Row @ { PaneSelector[ { - ($FrontEnd &) -> "Global", - FE`Evaluate @* FEPrivate`LastActiveUserNotebook -> "Selected Notebook", - SelectedCells @* FE`Evaluate @* FEPrivate`LastActiveUserNotebook -> "Selected Cells" + ($FrontEnd &) -> tr[ "ScopeGlobal" ], + FE`Evaluate @* FEPrivate`LastActiveUserNotebook -> tr[ "ScopeNotebook" ], + SelectedCells @* FE`Evaluate @* FEPrivate`LastActiveUserNotebook -> tr[ "ScopeCells" ] }, Dynamic @ scopeMode, BaselinePosition -> Baseline, @@ -1151,9 +1145,9 @@ scopeSelector[ Dynamic[ scopeMode_ ] ] := ActionMenu[ " \[DownPointer]" }, { - "Global" :> (scopeMode = $FrontEnd &), - "Selected Notebook" :> (scopeMode = FE`Evaluate @* FEPrivate`LastActiveUserNotebook), - "Selected Cells" :> (scopeMode = SelectedCells @* FE`Evaluate @* FEPrivate`LastActiveUserNotebook) + tr[ "ScopeGlobal" ] :> (scopeMode = $FrontEnd &), + tr[ "ScopeNotebook" ] :> (scopeMode = FE`Evaluate @* FEPrivate`LastActiveUserNotebook), + tr[ "ScopeCells" ] :> (scopeMode = SelectedCells @* FE`Evaluate @* FEPrivate`LastActiveUserNotebook) }, Appearance -> "Frameless", BaselinePosition -> Baseline @@ -1169,8 +1163,9 @@ personaNameDisp // beginDefinition; personaNameDisp[ personaNames_, Dynamic[ column_ ] ] := With[ { allowedIndices = Range @ Length @ personaNames }, PaneSelector[ - { True -> Dynamic @ FEPrivate`Part[ personaNames, column ], False -> "" }, - Dynamic @ FEPrivate`MemberQ[ allowedIndices, column ], + Thread[ allowedIndices -> personaNames ], + Dynamic @ column, + "", BaseStyle -> { FontColor -> GrayLevel[ 0.5 ], $baseStyle }, ImageSize -> Automatic ] @@ -1200,7 +1195,7 @@ iconData // endDefinition; (* ::Subsubsection::Closed:: *) (*titleSection*) titleSection // beginDefinition; -titleSection[ ] := If[ TrueQ @ $inDialog, dialogHeader[ "Add & Manage LLM Tools" ], Nothing ]; +titleSection[ ] := If[ TrueQ @ $inDialog, dialogHeader @ tr[ "ToolManagerTitle" ], Nothing ]; titleSection // endDefinition; (* ::**************************************************************************************************************:: *) @@ -1209,13 +1204,13 @@ titleSection // endDefinition; installToolsSection // beginDefinition; installToolsSection[ ] := Sequence[ - dialogSubHeader[ "Install Tools" ], + dialogSubHeader @ tr[ "ToolManagerInstallTools" ], dialogBody[ Grid @ { { - "Install from", + tr[ "ToolManagerInstallFrom" ], Button[ - grayDialogButtonLabel[ "LLM Tool Repository \[UpperRightArrow]" ], + grayDialogButtonLabel @ tr[ "ToolManagerInstallFromLLMToolRepo" ], If[ $CloudEvaluation, SetOptions[ EvaluationNotebook[ ], DockedCells -> Inherited ] ]; ResourceInstallFromRepository[ "LLMTool" ], Appearance -> "Suppressed", @@ -1223,7 +1218,7 @@ installToolsSection[ ] := Sequence[ Method -> "Queued" ], Button[ - grayDialogButtonLabel[ "URL" ], + grayDialogButtonLabel @ tr[ "URLButton" ], If[ $CloudEvaluation, SetOptions[ EvaluationNotebook[ ], DockedCells -> Inherited ] ]; Block[ { PrintTemporary }, ResourceInstallFromURL[ "LLMTool" ] ], Appearance -> "Suppressed", @@ -1247,7 +1242,7 @@ manageAndEnableToolsSection[ Dynamic[ scopeMode_ ] ] := Sequence[ dialogBody[ Grid @ { { - "Show enabled tools for:", + tr[ "ToolManagerShowEnabledFor" ], scopeSelector @ Dynamic @ scopeMode, Dynamic @ catchAlways @ toolModelWarning @ scopeMode[ ] } @@ -1256,7 +1251,7 @@ manageAndEnableToolsSection[ Dynamic[ scopeMode_ ] ] := Sequence[ ] ]; -manageAndEnableToolsSection[ ] := dialogSubHeader[ "Manage and Enable Tools" ]; +manageAndEnableToolsSection[ ] := dialogSubHeader @ tr[ "ToolManagerManageTools" ]; manageAndEnableToolsSection // endDefinition; @@ -1271,15 +1266,15 @@ dialogButtonSection[ ] := Item[ Framed[ Button[ - redDialogButtonLabel[ "OK" ], + redDialogButtonLabel @ tr[ "OKButton" ], NotebookClose @ EvaluationNotebook[ ], - Appearance -> "Suppressed", + Appearance -> "Suppressed", BaselinePosition -> Baseline, - Method -> "Queued" + Method -> "Queued" ], + Alignment -> { Center, Center }, FrameStyle -> None, - ImageSize -> { 100, 50 }, - Alignment -> { Center, Center } + ImageSize -> { 100, 50 } ], Alignment -> { Right, Automatic } ], @@ -1411,9 +1406,9 @@ cloudToolEnablePopup[ name_String ] := ] ], { - All -> "Always enabled", - Inherited -> "Automatic by persona", - None -> "Never enabled" + All -> tr[ "EnabledAlways" ], + Inherited -> tr[ "EnabledByPersona" ], + None -> tr[ "EnabledNever2" ] } ]; @@ -1464,8 +1459,8 @@ $cloudDeleteToolButtonLabel = Mouseover[ (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Tools/ChatPreferences.wl b/Source/Chatbook/Tools/ChatPreferences.wl index a837b038..d9cd96fd 100644 --- a/Source/Chatbook/Tools/ChatPreferences.wl +++ b/Source/Chatbook/Tools/ChatPreferences.wl @@ -7,16 +7,10 @@ BeginPackage[ "Wolfram`Chatbook`Tools`" ]; Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`ChatMessages`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Formatting`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; -Needs[ "Wolfram`Chatbook`Prompting`" ]; Needs[ "Wolfram`Chatbook`ResourceInstaller`" ]; -Needs[ "Wolfram`Chatbook`Sandbox`" ]; Needs[ "Wolfram`Chatbook`Serialization`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -238,8 +232,8 @@ setPrefModel // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Tools/Common.wl b/Source/Chatbook/Tools/Common.wl index 47f7f4ca..7430800f 100644 --- a/Source/Chatbook/Tools/Common.wl +++ b/Source/Chatbook/Tools/Common.wl @@ -7,17 +7,10 @@ BeginPackage[ "Wolfram`Chatbook`Tools`" ]; Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`ChatMessages`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Formatting`" ]; -Needs[ "Wolfram`Chatbook`Handlers`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; -Needs[ "Wolfram`Chatbook`Prompting`" ]; Needs[ "Wolfram`Chatbook`ResourceInstaller`" ]; -Needs[ "Wolfram`Chatbook`Sandbox`" ]; Needs[ "Wolfram`Chatbook`Serialization`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; HoldComplete[ System`LLMTool; @@ -61,17 +54,22 @@ $ToolFunctions = <| (* ::Section::Closed:: *) (*Tool Configuration*) $defaultWebTextLength = 12000; -$maximumWAPodByteCount = 1000000; $toolResultStringLength := Ceiling[ $initialCellStringBudget/2 ]; $webSessionVisible = False; $DefaultToolOptions = <| + "WolframAlpha" -> <| + "DefaultPods" -> False, + "FoldPods" -> False, + "MaxPodByteCount" -> 1000000 + |>, "WolframLanguageEvaluator" -> <| - "AppendURIPrompt" -> False, "AllowedExecutePaths" -> Automatic, "AllowedReadPaths" -> All, "AllowedWritePaths" -> Automatic, + "AppendURIPrompt" -> False, "EvaluationTimeConstraint" -> 60, + "Method" -> Automatic, "PingTimeConstraint" -> 30 |>, "WebFetcher" -> <| @@ -136,13 +134,30 @@ $appearanceRulesKeys = Keys @ $autoAppearanceRules; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Default Tools*) -$defaultChatTools := If[ TrueQ @ $CloudEvaluation, - KeyDrop[ $defaultChatTools0, $cloudUnsupportedTools ], - $defaultChatTools0 - ]; +$defaultChatTools := ( + reevaluateToolExpressions[ ]; + If[ TrueQ @ $CloudEvaluation, + KeyDrop[ $defaultChatTools0, $cloudUnsupportedTools ], + $defaultChatTools0 + ] +); $defaultChatTools0 = <| |>; +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*reevaluateToolExpressions*) +reevaluateToolExpressions // beginDefinition; + +reevaluateToolExpressions[ ] := + If[ TrueQ @ Wolfram`ChatbookInternal`$BuildingMX, + Null, + $defaultChatTools0 = AssociationMap[ Identity, $defaultChatTools0 ]; + reevaluateToolExpressions[ ] = Null + ]; + +reevaluateToolExpressions // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Installed Tools*) @@ -189,6 +204,7 @@ toolName[ name_String, "Machine" ] := toMachineToolName @ name; toolName[ name_String, "Canonical" ] := toCanonicalToolName @ name; toolName[ name_String, "Display" ] := toDisplayToolName @ name; toolName[ tools_List, type_ ] := toolName[ #, type ] & /@ tools; +toolName[ Inherited|ParentList, type_ ] := Missing[ "NotAvailable" ]; toolName // endDefinition; (* ::**************************************************************************************************************:: *) @@ -273,12 +289,16 @@ toolDefaultIcon // endDefinition; (*toolDefaultData*) toolDefaultData // beginDefinition; -toolDefaultData[ name_String ] := <| - "CanonicalName" -> toCanonicalToolName @ name, - "DisplayName" -> toDisplayToolName @ name, - "Name" -> toMachineToolName @ name, - "Icon" -> $defaultToolIcon -|>; +toolDefaultData[ name_String ] := + With[ { mName = toMachineToolName @ name }, + <| + "CanonicalName" -> toCanonicalToolName @ name, + "DisplayName" -> toDisplayToolName @ name, + "Name" -> mName, + "ShortName" -> mName, + "Icon" -> $defaultToolIcon + |> + ]; toolDefaultData // endDefinition; @@ -327,6 +347,18 @@ toDisplayToolName // endDefinition; formatToolCallExample // beginDefinition; formatToolCallExample[ name_String, params_Association ] := + formatToolCallExample[ name, params, $ChatHandlerData[ "ChatNotebookSettings", "ToolMethod" ] ]; + +formatToolCallExample[ name_String, params_Association, "Simple" ] := Enclose[ + Module[ { command, values }, + command = ConfirmBy[ toolShortName @ name, StringQ, "Command" ]; + values = ConfirmMatch[ Values @ params, { ___String }, "Values" ]; + TemplateApply[ "/`1`\n`2`\n/exec", { command, StringRiffle[ values, "\n" ] } ] + ], + throwInternalFailure +]; + +formatToolCallExample[ name_String, params_Association, _ ] := TemplateApply[ (* cSpell: ignore TOOLCALL, ENDARGUMENTS, ENDTOOLCALL *) "TOOLCALL: `1`\n`2`\nENDARGUMENTS\nENDTOOLCALL", @@ -481,16 +513,20 @@ getToolNames[ as_Association ] := getToolNames[ tools_, None ] := { }; (* Persona wants default tools *) -getToolNames[ tools_, Automatic|Inherited ] := getToolNames @ tools; +getToolNames[ tools_, Automatic|Inherited|ParentList ] := getToolNames @ tools; (* Persona declares an explicit list of tools *) getToolNames[ Automatic|None|Inherited, personaTools_List ] := getToolNames @ personaTools; +(* Persona inherits tools: *) +getToolNames[ { parent___ }, { a___, ParentList, b___ } ] := getToolNames @ { a, parent, b }; + (* The user has specified an explicit list of tools as well, so include them *) getToolNames[ tools_List, personaTools_List ] := Union[ getToolNames @ tools, getToolNames @ personaTools ]; (* Get name of each tool *) -getToolNames[ tools_List ] := DeleteDuplicates @ Flatten[ getCachedToolName /@ tools ]; +getToolNames[ tools_List ] := + DeleteDuplicates @ Flatten[ getCachedToolName /@ DeleteCases[ tools, $$unspecified|ParentList ] ]; (* Default tools *) getToolNames[ Automatic|Inherited ] := Keys @ $DefaultTools; @@ -518,7 +554,7 @@ getCachedToolName[ tool: HoldPattern[ _LLMTool ] ] := Enclose[ $toolBox[ name ] = tool; name ], - throwInternalFailure[ getCachedToolName @ tool, ## ] & + throwInternalFailure ]; getCachedToolName[ name_String ] := @@ -675,13 +711,99 @@ $toolConfiguration := $toolConfiguration = LLMConfiguration @ <| "Tools" -> Valu (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*toolRequestParser*) -toolRequestParser := toolRequestParser = - Quiet[ Check[ $toolConfiguration[ "ToolRequestParser" ], - Wolfram`LLMFunctions`LLMConfiguration`$DefaultTextualToolMethod[ "ToolRequestParser" ], - LLMConfiguration::invprop - ], - LLMConfiguration::invprop - ]; +toolRequestParser // beginDefinition; + +toolRequestParser[ content_String ] := Enclose[ + Catch @ Module[ { calls, toolName, paramsJSON, rawCallString, callPosition, bag, params }, + + calls = StringCases[ + content, + StringExpression[ + StartOfString, + Longest[ ___ ], + callString: StringExpression[ + "TOOLCALL: ", + Shortest[ toolNameStr__ ], + EndOfLine, + Shortest[ paramsStr__ ], + "ENDARGUMENTS", + WhitespaceCharacter..., + EndOfString + ] + ] :> { StringTrim @ toolNameStr, paramsStr, StringTrim @ callString } + ]; + + If[ Length @ calls =!= 1, Throw @ None ]; + { toolName, paramsJSON, rawCallString } = First @ calls; + callPosition = Last @ StringPosition[ content, rawCallString ]; + bag = Internal`Bag[ ]; + + params = Quiet @ Internal`HandlerBlock[ { "Message", jsonMessageHandler @ bag }, + Developer`ReadRawJSONString @ paramsJSON + ]; + + If[ FailureQ @ params, + Throw @ { callPosition, Failure[ "InvalidJSON", <| "Message" -> makeJSONFailureMessage @ bag |> ] } + ]; + + { + callPosition, + System`LLMToolRequest[ toolName, Normal @ params, rawCallString<>"\nENDTOOLCALL" ] + } + ], + throwInternalFailure +]; + +toolRequestParser // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*makeJSONFailureMessage*) +makeJSONFailureMessage // beginDefinition; + +makeJSONFailureMessage[ bag_Internal`Bag ] := + makeJSONFailureMessage @ Internal`BagPart[ bag, All ]; + +makeJSONFailureMessage[ messages: { __String } ] := StringRiffle[ + Flatten @ { "Parsing arguments as JSON failed with the following messages:", "\t" <> # & /@ messages }, + "\n" +]; + +makeJSONFailureMessage[ ___ ] := + "Arguments were not valid JSON."; + +makeJSONFailureMessage // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*jsonMessageHandler*) +jsonMessageHandler // beginDefinition; + +jsonMessageHandler[ bag_Internal`Bag ] := + jsonMessageHandler[ bag, # ] &; + +jsonMessageHandler[ + bag_Internal`Bag, + Hold[ Message[ msg: MessageName[ Developer`ReadRawJSONString, tag__ ], params___ ], _ ] +] := Enclose[ + Module[ { template, args, string }, + template = ConfirmBy[ If[ StringQ @ msg, msg, MessageName[ General, tag ] ], StringQ ]; + args = ConfirmMatch[ messageParameterString /@ Unevaluated @ { params }, { ___String } ]; + string = ConfirmBy[ TemplateApply[ template, args ], StringQ ]; + Internal`StuffBag[ bag, string ] + ], + throwInternalFailure +]; + +jsonMessageHandler // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*messageParameterString*) +messageParameterString // beginDefinition; +messageParameterString // Attributes = { HoldAllComplete }; +messageParameterString[ expr_ ] := ToString[ Unevaluated @ Short[ expr, 1 ], PageWidth -> 80 ]; +messageParameterString // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) @@ -689,11 +811,7 @@ toolRequestParser := toolRequestParser = simpleToolRequestParser // beginDefinition; simpleToolRequestParser[ string_String ] := Enclose[ - Catch @ Module[ - { - tools, commands, calls, command, argString, callString, callPos, tool, name, paramNames, argStrings, - padded, params - }, + Catch @ Module[ { tools, commands, calls, command, argString, callString, callPos, tool, name, paramNames, params }, tools = ConfirmMatch[ Values @ $selectedTools, { ___LLMTool }, "Tools" ]; commands = ConfirmMatch[ toolShortName /@ tools, { ___String }, "Commands" ]; @@ -701,8 +819,14 @@ simpleToolRequestParser[ string_String ] := Enclose[ (* TODO: return failure when trying to use an invalid tool command string *) calls = StringCases[ StringDelete[ string, "/" ~~ commands ~~ ___ ~~ "/exec" ], - Longest[ StartOfString ~~ ___ ~~ StartOfLine ~~ s: ("/" ~~ (cmd: commands) ~~ args___) ~~ EndOfString ] :> - { StringTrim @ cmd, StringTrim @ args, s } + Longest @ StringExpression[ + StartOfString, + ___, + StartOfLine, + WhitespaceCharacter..., + s: ("/" ~~ cmd: commands ~~ args___), + EndOfString + ] :> { StringTrim @ cmd, StringTrim @ args, s } ]; If[ calls === { }, Throw @ None ]; @@ -712,14 +836,10 @@ simpleToolRequestParser[ string_String ] := Enclose[ callPos = ConfirmMatch[ Last[ StringPosition[ string, callString ], $Failed ], { __Integer }, "CallPosition" ]; tool = ConfirmMatch[ AssociationThread[ commands -> tools ][ command ], _LLMTool, "Tool" ]; - name = ConfirmBy[ tool[[ 1, "Name" ]], StringQ, "ToolName" ]; - - paramNames = Keys @ ConfirmMatch[ tool[[ 1, "Parameters" ]], KeyValuePattern @ { }, "ParameterNames" ]; - argStrings = If[ Length @ paramNames === 1, { argString }, StringSplit[ argString, "\n" ] ]; - If[ Length @ argStrings > Length @ paramNames, Throw @ None ]; + name = ConfirmBy[ tool[ "Name" ], StringQ, "ToolName" ]; - padded = PadRight[ argStrings, Length @ paramNames, "" ]; - params = Normal @ ConfirmBy[ AssociationThread[ paramNames -> padded ], AssociationQ, "Parameters" ]; + paramNames = Keys @ ConfirmMatch[ tool[ "Parameters" ], KeyValuePattern @ { }, "ParameterNames" ]; + params = ConfirmBy[ parseSimpleToolCallParameterStrings[ paramNames, argString ], AssociationQ, "Parameters" ]; { callPos, LLMToolRequest[ name, params, callString ] } ], @@ -728,11 +848,57 @@ simpleToolRequestParser[ string_String ] := Enclose[ simpleToolRequestParser // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*parseSimpleToolCallParameterStrings*) +parseSimpleToolCallParameterStrings // beginDefinition; + +parseSimpleToolCallParameterStrings[ { param_String }, argString_String ] := + <| param -> StringDelete[ argString, StartOfString ~~ WhitespaceCharacter... ~~ param ~~ ":" ~~ " "... ] |>; + +parseSimpleToolCallParameterStrings[ paramNames: { __String }, argString_String ] := Enclose[ + Catch @ Module[ { namedSplit, defaults, pairs }, + namedSplit = StringSplit[ argString, StartOfLine ~~ (" "|"\t")... ~~ p: paramNames ~~ ":" ~~ " "... :> p ]; + If[ OddQ @ Length @ namedSplit, Throw @ parseSimpleToolCallParameterStrings0[ paramNames, argString ] ]; + defaults = AssociationMap[ "" &, paramNames ]; + pairs = ConfirmMatch[ Partition[ namedSplit, 2 ], { { _String, _String } .. }, "Pairs" ]; + ConfirmBy[ <| defaults, Rule @@@ pairs |>, AssociationQ, "Parameters" ] + ], + throwInternalFailure +]; + +parseSimpleToolCallParameterStrings // endDefinition; + + +parseSimpleToolCallParameterStrings0 // beginDefinition; + +parseSimpleToolCallParameterStrings0[ paramNames: { __String }, argString_String ] := Enclose[ + Module[ { split, padded }, + split = StringSplit[ argString, "\n" ]; + padded = PadRight[ split, Length @ paramNames, "" ]; + ConfirmBy[ AssociationThread[ paramNames -> padded ], AssociationQ, "Parameters" ] + ], + throwInternalFailure +]; + +parseSimpleToolCallParameterStrings0 // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*toolShortName*) toolShortName // beginDefinition; -toolShortName[ $$llmToolH[ as_Association, ___ ] ] := Lookup[ as, "ShortName", Lookup[ as, "Name" ] ]; + +toolShortName[ $$llmToolH[ as_Association, ___ ] ] := + toolShortName @ as; + +toolShortName[ as_Association ] := + Lookup[ as, "ShortName", Lookup[ as, "Name" ] ]; + +toolShortName[ name_String ] := + With[ { tool = getToolByName @ name }, + toolShortName @ tool /; MatchQ[ tool, $$llmTool ] + ]; + toolShortName // endDefinition; (* ::**************************************************************************************************************:: *) @@ -794,11 +960,19 @@ getToolPostPrompt // endDefinition; (* ::Subsubsection::Closed:: *) (*getToolExamplePrompt*) getToolExamplePrompt // beginDefinition; -getToolExamplePrompt[ as_Association ] := getToolExamplePrompt[ as, as[ "ToolMethod" ], as[ "ToolExamplePrompt" ] ]; -getToolExamplePrompt[ as_, "Simple", $$unspecified ] := Nothing; -getToolExamplePrompt[ as_, method_, $$unspecified ] := $fullExamples; -getToolExamplePrompt[ as_, method_, prompt: $$template ] := prompt; -getToolExamplePrompt[ as_, method_, None ] := Nothing; + +getToolExamplePrompt[ as_Association ] := + getToolExamplePrompt[ as, as[ "ToolMethod" ], as[ "ToolExamplePrompt" ], as[ "ToolCallExamplePromptStyle" ] ]; + +getToolExamplePrompt[ as_, method_, $$unspecified, style_String ] := + Block[ { $messageTemplateType = style }, $fullExamples ]; + +getToolExamplePrompt[ as_, method_, prompt: $$template, style_ ] := + prompt; + +getToolExamplePrompt[ as_, method_, None, style_ ] := + Nothing; + getToolExamplePrompt // endDefinition; (* ::**************************************************************************************************************:: *) @@ -843,7 +1017,19 @@ You did not create these tools, so you do not know what they can and cannot do. You should try to avoid mentioning tools by name in your response and instead speak generally about their function. \ For example, if there were a number_adder tool, you would instead talk about \"adding numbers\". If you must mention \ -a tool by name, you should use the DisplayName property instead of the tool name."; +a tool by name, you should use the DisplayName property instead of the tool name. + +IMPORTANT! If a tool call fails to give the desired result for any reason, \ +you MUST write /retry before making the next tool call: + +/retry +TOOLCALL: + +ENDARGUMENTS +ENDTOOLCALL + +This will hide the previous tool call in a collapsed section that the user can open if they wish to see prior attempts. +If you fail to do this, the user will have a hard time knowing which tool calls contain the correct results."; $toolListing = { @@ -915,7 +1101,7 @@ simpleToolSchema[ as_Association ] := Enclose[ data = ConfirmBy[ toolData @ as, AssociationQ, "Data" ]; name = ConfirmBy[ toolName[ data, "Display" ], StringQ, "Name" ]; - command = ConfirmBy[ Lookup[ data, "ShortName", toolName[ data, "Canonical" ] ], StringQ, "ShortName" ]; + command = ConfirmBy[ toolShortName @ data, StringQ, "ShortName" ]; description = ConfirmBy[ data[ "Description" ], StringQ, "Description" ]; args = ConfirmMatch[ as[ "Parameters" ], KeyValuePattern @ { }, "Arguments" ]; argStrings = ConfirmMatch[ simpleArgStrings @ args, { __String }, "ArgStrings" ]; @@ -1026,8 +1212,8 @@ $toolFrequencyExplanations = <| (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Tools/DefaultTools.wl b/Source/Chatbook/Tools/DefaultTools.wl index 34380eca..38dea119 100644 --- a/Source/Chatbook/Tools/DefaultTools.wl +++ b/Source/Chatbook/Tools/DefaultTools.wl @@ -10,17 +10,10 @@ BeginPackage[ "Wolfram`Chatbook`Tools`" ]; Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`ChatMessages`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Formatting`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; -Needs[ "Wolfram`Chatbook`Prompting`" ]; Needs[ "Wolfram`Chatbook`ResourceInstaller`" ]; -Needs[ "Wolfram`Chatbook`Sandbox`" ]; Needs[ "Wolfram`Chatbook`Serialization`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) @@ -67,6 +60,7 @@ Follow up search results with the documentation lookup tool to get the full info $defaultChatTools0[ "DocumentationSearcher" ] = <| toolDefaultData[ "DocumentationSearcher" ], + "ShortName" -> "doc_search", "Icon" -> RawBoxes @ TemplateBox[ { }, "ToolIconDocumentationSearcher" ], "Description" -> $documentationSearchDescription, "Function" -> documentationSearch, @@ -98,6 +92,7 @@ documentationSearch // endDefinition; (*DocumentationLookup*) $defaultChatTools0[ "DocumentationLookup" ] = <| toolDefaultData[ "DocumentationLookup" ], + "ShortName" -> "doc_lookup", "Icon" -> RawBoxes @ TemplateBox[ { }, "ToolIconDocumentationLookup" ], "Description" -> "Get documentation pages for Wolfram Language symbols.", "Function" -> documentationLookup, @@ -253,32 +248,18 @@ $defaultChatTools0[ "WolframLanguageEvaluator" ] = <| (* ::Subsubsection::Closed:: *) (*wolframLanguageEvaluator*) wolframLanguageEvaluator // beginDefinition; -wolframLanguageEvaluator[ code_String ] := wolframLanguageEvaluator[ code, sandboxEvaluate @ code ]; -wolframLanguageEvaluator[ code_, result_Association ] := KeyTake[ result, { "Result", "String" } ]; + +wolframLanguageEvaluator[ code_String ] := + Block[ { $ChatNotebookEvaluation = True }, wolframLanguageEvaluator[ code, sandboxEvaluate @ code ] ]; + +wolframLanguageEvaluator[ code_, result_Association ] := + KeyTake[ result, { "Result", "String" } ]; + wolframLanguageEvaluator // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*Wolfram Alpha*) - -(* $wolframAlphaDescription = "Get Wolfram|Alpha results - -## Wolfram Alpha Tool Guidelines -- Understands natural language queries about entities in chemistry, physics, geography, history, art, astronomy, and more. -- Performs mathematical calculations, date and unit conversions, formula solving, etc. -- Convert inputs to simplified keyword queries whenever possible (e.g. convert \"how many people live in France\" to \"France population\"). -- Use ONLY single-letter variable names, with or without integer subscript (e.g., n, n1, n_1). -- Use named physical constants (e.g., 'speed of light') without numerical substitution. -- Include a space between compound units (e.g., \"\[CapitalOmega] m\" for \"ohm*meter\"). -- To solve for a variable in an equation with units, consider solving a corresponding equation without units; exclude counting units (e.g., books), include genuine units (e.g., kg). -- If data for multiple properties is needed, make separate calls for each property. -- If a Wolfram Alpha result is not relevant to the query: - -- If Wolfram provides multiple 'Assumptions' for a query, choose the more relevant one(s) without explaining the initial result. If you are unsure, ask the user to choose. - -- Re-send the exact same 'input' with NO modifications, and add the 'assumption' parameter, formatted as a list, with the relevant values. - -- ONLY simplify or rephrase the initial query if a more relevant 'Assumption' or other input suggestions are not provided. - -- Do not explain each step unless user input is needed. Proceed directly to making a better API call based on the available assumptions. - "; *) - $wolframAlphaDescription = "\ Use natural language queries with Wolfram|Alpha to get up-to-date computational results about entities in chemistry, \ physics, geography, history, art, astronomy, and more."; @@ -314,457 +295,12 @@ $defaultChatTools0[ "WolframAlpha" ] = <| } |>; -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*getWolframAlphaText*) -getWolframAlphaText // beginDefinition; - -getWolframAlphaText[ as_Association ] := - getWolframAlphaText[ as[ "query" ], as[ "steps" ] ]; - -getWolframAlphaText[ query_String, steps: True|False|_Missing ] := - Module[ { result, data, string }, - result = wolframAlpha[ query, steps ]; - data = WolframAlpha[ - query, - { All, { "Title", "Plaintext", "ComputableData", "Content" } }, - PodStates -> { If[ TrueQ @ steps, "Step-by-step solution", Nothing ] } - ]; - string = getWolframAlphaText[ query, steps, data ]; - getWolframAlphaText[ query, steps ] = <| "Result" -> result, "String" -> string |> - ]; - -getWolframAlphaText[ query_String, steps_, { } ] := - "No results returned"; - -getWolframAlphaText[ query_String, steps_, info_List ] := - getWolframAlphaText[ query, steps, associationKeyDeflatten[ makeKeySequenceRule /@ info ] ]; - -getWolframAlphaText[ query_String, steps_, as_Association? AssociationQ ] := - getWolframAlphaText[ query, steps, waResultText @ as ]; - -getWolframAlphaText[ query_String, steps_, result_String ] := - escapeMarkdownString @ result; - -getWolframAlphaText // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*wolframAlpha*) -wolframAlpha // beginDefinition; -wolframAlpha[ args___ ] /; $cloudNotebooks := fasterWolframAlphaPods @ args; -(* wolframAlpha[ args___ ] := wolframAlpha[ args ] = WolframAlpha @ args; *) -wolframAlpha[ args___ ] := fasterWolframAlphaPods @ args; -wolframAlpha // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*fasterWolframAlphaPods*) -fasterWolframAlphaPods // beginDefinition; - -fasterWolframAlphaPods[ query_String, steps: True|False|_Missing ] := Enclose[ - Catch @ Module[ { titlesAndCells, grouped, small, formatted, framed }, - titlesAndCells = Confirm[ - WolframAlpha[ - query, - { All, { "Title", "Cell" } }, - PodStates -> { If[ TrueQ @ steps, "Step-by-step solution", Nothing ] } - ], - "WolframAlpha" - ]; - If[ titlesAndCells === { }, Throw @ Missing[ "NoResults" ] ]; - grouped = DeleteCases[ SortBy[ #1, podOrder ] & /@ GroupBy[ titlesAndCells, podKey ], CellSize -> _, Infinity ]; - small = Select[ grouped, ByteCount @ # < $maximumWAPodByteCount & ]; - formatted = ConfirmMatch[ formatPods[ query, small ], { (_Framed|_RawBoxes|_Item).. }, "Formatted" ]; - - framed = Framed[ - Column[ formatted, Alignment -> Left, Spacings -> { { 1 }, -2 -> 0.5, -1 -> 0 } ], - Background -> GrayLevel[ 0.95 ], - FrameMargins -> { { 10, 10 }, { 10, 10 } }, - FrameStyle -> GrayLevel[ 0.8 ], - RoundingRadius -> 3, - TaggingRules -> <| "WolframAlphaPods" -> True |> - ]; - fasterWolframAlphaPods[ query, steps ] = framed - ], - throwInternalFailure -]; - -fasterWolframAlphaPods // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*podOrder*) -podOrder // beginDefinition; -podOrder[ key_ -> _ ] := podOrder @ key; -podOrder[ { { _String, idx_Integer }, _String } ] := idx; -podOrder // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*podKey*) -podKey // beginDefinition; -podKey[ key_ -> _ ] := podKey @ key; -podKey[ { { key_String, _Integer }, _String } ] := key; -podKey // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*formatPods*) -formatPods // beginDefinition; - -formatPods[ query_, as: KeyValuePattern @ { "Input" -> input_, "Result" -> result_ } ] /; $cloudNotebooks := Enclose[ - Module[ { rest }, - rest = Values @ KeyDrop[ as, { "Input", "Result" } ]; - Flatten @ { - formatPod @ input, - formatPod @ result, - If[ rest === { }, - Nothing, - openerView[ - { - MouseAppearance[ - Style[ "More details", "Text", FontColor -> GrayLevel[ 0.4 ], FontSize -> 12 ], - "LinkHand" - ], - Column[ - Append[ formatPod /@ rest, waFooterMenu @ query ], - Alignment -> Left, - Spacings -> { { 1 }, -2 -> 0.5, -1 -> 0 } - ] - }, - Method -> "Active" - ] - ] - } - ], - throwInternalFailure -]; - -formatPods[ query_, as_Association ] /; $cloudNotebooks && Length @ as > 3 := Enclose[ - Module[ { show, hide }, - { show, hide } = ConfirmMatch[ TakeDrop[ as, 3 ], { _Association, _Association }, "TakeDrop" ]; - Flatten @ { - formatPod /@ Values @ show, - openerView[ - { - MouseAppearance[ - Style[ "More details", "Text", FontColor -> GrayLevel[ 0.4 ], FontSize -> 12 ], - "LinkHand" - ], - Column[ - Append[ formatPod /@ Values @ hide, waFooterMenu @ query ], - Alignment -> Left, - Spacings -> { { 1 }, -2 -> 0.5, -1 -> 0 } - ] - }, - Method -> "Active" - ] - } - ], - throwInternalFailure -]; - -formatPods[ query_, grouped_Association ] := - Append[ Map[ formatPod, Values @ grouped ], waFooterMenu @ query ]; - -formatPods // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*waFooterMenu*) -waFooterMenu // beginDefinition; - -(* cSpell: ignore Localizable *) -waFooterMenu[ query_String ] := Item[ - DynamicModule[ { display }, - display = Button[ - Dynamic @ RawBoxes @ FEPrivate`FrontEndResource[ "FEBitmaps", "CirclePlusIconScalable" ], - Null, - Appearance -> None - ]; - Grid[ - { - { - Hyperlink[ - Dynamic @ RawBoxes @ FEPrivate`FrontEndResource[ "WALocalizableBitmaps", "WolframAlpha" ], - "https://www.wolframalpha.com", - Alignment -> Left - ], - Pane[ - Dynamic @ display, - FrameMargins -> { { 0, If[ $CloudEvaluation, 23, 3 ] }, { 0, 0 } } - ] - } - }, - Spacings -> 0.5 - ], - SynchronousInitialization -> False, - Initialization :> - If[ ! MatchQ[ display, _Tooltip ], - Needs[ "Wolfram`Chatbook`" -> None ]; - display = Replace[ makeWebLinksMenu @ query, Except[ _Tooltip ] :> "" ] - ] - ], - Alignment -> Right -]; - -waFooterMenu // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*makeWebLinksMenu*) -makeWebLinksMenu // beginDefinition; - -makeWebLinksMenu[ query_String ] /; $dynamicText := - Nothing; - -makeWebLinksMenu[ query_String ] := Enclose[ - Module[ { sources, url, actions }, - - sources = ConfirmMatch[ WolframAlpha[ query, "Sources" ], KeyValuePattern @ { } ]; - - (* cSpell: ignore wolframalpha *) - url = URLBuild @ <| - "Scheme" -> "https", - "Domain" -> "www.wolframalpha.com", - "Path" -> { "", "input" }, - "Query" -> { "i" -> query } - |>; - - actions = With[ { u = url }, - Flatten @ { - "Web version" :> NotebookLocate @ { URL @ u, None }, - If[ sources === { }, - Nothing, - { - Delimiter, - KeyValueMap[ - Row @ { "Source information: " <> #1 } :> NotebookLocate @ { URL[ #2 ], None } &, - Association @ sources - ] - } - ] - } - ]; - - makeWebLinksMenu @ actions - ], - "" & -]; - -makeWebLinksMenu[ actions: { (_RuleDelayed|Delimiter).. } ] := Tooltip[ - ActionMenu[ - Dynamic @ RawBoxes @ FEPrivate`FrontEndResource[ "FEBitmaps", "CirclePlusIconScalable" ], - actions, - Appearance -> None - ], - "Links" -]; - -makeWebLinksMenu[ ___ ] := ""; - -makeWebLinksMenu // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*getWASources*) -getWASources // beginDefinition; -getWASources[ query_String ] := getWASources[ query, WolframAlpha[ query, "Sources" ] ]; -getWASources[ query_String, sources: KeyValuePattern @ { } ] := getWASources[ query ] = sources; -getWASources[ query_String, _ ] := $Failed; -getWASources // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*formatPod*) -formatPod // beginDefinition; - -formatPod[ pod_ ] /; ByteCount @ pod > $maximumWAPodByteCount := - Nothing; - -formatPod[ content_List ] := Framed[ - Column[ formatPodItem /@ content, Alignment -> Left ], - Background -> White, - FrameMargins -> 5, - FrameStyle -> GrayLevel[ 0.8 ], - ImageSize -> { Scaled[ 1 ], Automatic }, - ImageMargins -> If[ $CloudEvaluation, { { 0, 25 }, { 0, 0 } }, 0 ], - RoundingRadius -> 3 -]; - -formatPod // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*formatPodItem*) -formatPodItem // beginDefinition; - -formatPodItem[ key_ -> value_ ] := - formatPodItem[ key, value ]; - -formatPodItem[ { _, "Title" }, title_String ] := - Style[ StringTrim[ title, ":" ] <> ":", "Text", FontColor -> GrayLevel[ 0.4 ], FontSize -> 12 ]; - -formatPodItem[ { _, "Cell" }, cell_ ] /; ByteCount @ cell > 1000000 := - With[ - { raster = rasterizeWAPod @ cell }, - { dim = ImageDimensions @ raster }, - Pane[ - Show[ raster, ImageSize -> dim ], - ImageSize -> { UpTo[ 550 ], Automatic }, - ImageSizeAction -> "ShrinkToFit", - ImageMargins -> { { 10, 0 }, { 0, 0 } } - ] /; ByteCount @ raster < ByteCount @ cell - ]; - -formatPodItem[ { _, "Cell" }, cell_ ] := - Pane[ cell, ImageMargins -> { { 10, 0 }, { 0, 0 } } ]; - -formatPodItem // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*rasterizeWAPod*) -rasterizeWAPod // beginDefinition; -rasterizeWAPod[ expr_ ] := rasterizeWAPod[ expr ] = ImageCrop @ rasterize[ expr, ImageResolution -> 72 ]; -rasterizeWAPod // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*cloudUsingFrontEnd*) -cloudUsingFrontEnd // beginDefinition; -cloudUsingFrontEnd // Attributes = { HoldFirst }; - -(* cloudUsingFrontEnd[ eval_ ] := - Module[ { fe }, - Quiet[ - WithCleanup[ - Developer`UninstallFrontEnd[ ]; - fe = Developer`InstallFrontEnd[ Developer`ForceLaunch -> True ] - , - MathLink`FrontEndBlock[ eval, fe ] - , - Developer`UninstallFrontEnd[ ] - ], - LinkObject::linkn - ] - ]; *) -cloudUsingFrontEnd[ eval_ ] := eval; - -cloudUsingFrontEnd // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*wolframAlphaResultFormatter*) -wolframAlphaResultFormatter // beginDefinition; - -wolframAlphaResultFormatter[ query_String, "Parameters", "query" ] := - clickToCopy @ query; - -wolframAlphaResultFormatter[ KeyValuePattern[ "Result" -> result_ ], "Result" ] := - wolframAlphaResultFormatter[ result, "Result" ]; - -wolframAlphaResultFormatter[ result_, ___ ] := - result; - -wolframAlphaResultFormatter // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsubsection::Closed:: *) -(*makeKeySequenceRule*) -makeKeySequenceRule // beginDefinition; -makeKeySequenceRule[ { _, "Cell"|"Position"|"Scanner" } -> _ ] := Nothing; -makeKeySequenceRule[ key_ -> value_ ] := makeKeySequence @ key -> value; -makeKeySequenceRule // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsubsection::Closed:: *) -(*makeKeySequence*) -makeKeySequence // beginDefinition; - -makeKeySequence[ { { path_String, n_Integer }, key_String } ] := - makeKeySequence @ Flatten @ { Reverse @ StringSplit[ path, ":" ], n, key }; - -makeKeySequence[ { path__String, 0, key_String } ] := - { path, key }; - -makeKeySequence[ { path__String, n_Integer, key_String } ] := - { path, "Data", n, key }; - -makeKeySequence // endDefinition; - -(* ::**************************************************************************************************************:: *) -(* ::Subsubsubsection::Closed:: *) -(*waResultText*) -waResultText // beginDefinition; -waResultText[ as_ ] := Block[ { $level = 1 }, StringRiffle[ Flatten @ Values[ waResultText0 /@ as ], "\n" ] ]; -waResultText // endDefinition; - - -waResultText0 // beginDefinition; - -waResultText0[ as: KeyValuePattern @ { "Title" -> title_String, "Data" -> data_ } ] := - StringRepeat[ "#", $level ] <> " " <> title <> "\n" <> waResultText0 @ data; - -waResultText0[ as: KeyValuePattern[ _Integer -> _ ] ] := - waResultText0 /@ Values @ KeySort @ KeySelect[ as, IntegerQ ]; - -waResultText0[ as: KeyValuePattern @ { "Content"|"ComputableData" -> expr_ } ] /; - ! FreeQ[ Unevaluated @ expr, _Missing ] := - Replace[ Lookup[ as, "Plaintext" ], Except[ _String ] :> Nothing ]; - -waResultText0[ KeyValuePattern @ { "Plaintext" -> text_String, "ComputableData" -> Hold[ expr_ ] } ] := - If[ ByteCount @ Unevaluated @ expr >= 500, - If[ StringFreeQ[ text, "["|"]"|"\n" ], - makeExpressionURI[ text, Unevaluated @ expr ] <> "\n", - text <> "\n" <> makeExpressionURI[ Unevaluated @ expr ] <> "\n" - ], - text <> "\n" - ]; - -waResultText0[ as: KeyValuePattern @ { "Plaintext" -> text_String, "ComputableData" -> expr: Except[ _Hold ] } ] := - waResultText0 @ Append[ as, "ComputableData" -> Hold @ expr ]; - -waResultText0[ KeyValuePattern @ { "Plaintext" -> text_String, "Content" -> content_ } ] := - If[ ByteCount @ content >= 500, - If[ StringFreeQ[ text, "["|"]"|"\n" ], - makeExpressionURI[ text, Unevaluated @ content ] <> "\n", - text <> "\n" <> makeExpressionURI[ Unevaluated @ content ] <> "\n" - ], - text <> "\n" - ]; - -waResultText0[ as_Association ] /; Length @ as === 1 := - waResultText0 @ First @ as; - -waResultText0[ as_Association ] := - KeyValueMap[ - Function[ - StringJoin[ - StringRepeat[ "#", $level ], - " ", - ToString[ #1 ], - "\n", - Block[ { $level = $level + 1 }, waResultText0[ #2 ] ] - ] - ], - as - ]; - -waResultText0[ expr_ ] := - With[ { s = ToString[ Unevaluated @ expr, InputForm ] }, s <> "\n" /; StringLength @ s <= 100 ]; - -waResultText0[ expr_ ] := - makeExpressionURI @ Unevaluated @ expr <> "\n"; - -waResultText0 // endDefinition; - (* ::**************************************************************************************************************:: *) (* ::Subsection::Closed:: *) (*WebSearch*) $defaultChatTools0[ "WebSearcher" ] = <| toolDefaultData[ "WebSearcher" ], + "ShortName" -> "web_search", "Icon" -> RawBoxes @ TemplateBox[ { }, "ToolIconWebSearcher" ], "Description" -> "Search the web.", "Function" -> webSearch, @@ -784,10 +320,10 @@ $defaultChatTools0[ "WebSearcher" ] = <| (*webSearch*) webSearch // beginDefinition; -webSearch[ KeyValuePattern[ "query" -> query_ ] ] := webSearch @ query; -webSearch[ query_String ] := Block[ { PrintTemporary }, webSearch @ SearchQueryString @ query ]; +webSearch[ KeyValuePattern[ "query" -> query_ ] ] := + Block[ { PrintTemporary }, webSearch @ query ]; -webSearch[ query_SearchQueryString ] := Enclose[ +webSearch[ query_String ] := Enclose[ Catch @ Module[ { result, json, string }, result = ConfirmMatch[ webSearch0 @ query, _Dataset|_Failure, "WebSearch" ]; @@ -801,7 +337,7 @@ webSearch[ query_SearchQueryString ] := Enclose[ <| "Result" -> result, "String" -> string |> ], - throwInternalFailure[ webSearch @ query, ## ] & + throwInternalFailure ]; webSearch // endDefinition; @@ -809,7 +345,7 @@ webSearch // endDefinition; webSearch0 // beginDefinition; -webSearch0[ query_SearchQueryString ] := Enclose[ +webSearch0[ query_String ] := Enclose[ Module[ { opts, raw, result, held, $unavailable }, opts = Sequence @@ ConfirmMatch[ toolOptions[ "WebSearcher" ], { $$optionsSequence }, "Options" ]; result = Quiet[ @@ -831,7 +367,7 @@ webSearch0[ query_SearchQueryString ] := Enclose[ } ] ], - throwInternalFailure[ webImageSearch0 @ query, ## ] & + throwInternalFailure ]; webSearch0 // endDefinition; @@ -859,6 +395,7 @@ web_fetcher tool."; (*WebFetch*) $defaultChatTools0[ "WebFetcher" ] = <| toolDefaultData[ "WebFetcher" ], + "ShortName" -> "web_fetch", "Icon" -> RawBoxes @ TemplateBox[ { }, "ToolIconWebFetcher" ], "Description" -> "Fetch plain text or image links from a URL.", "Function" -> webFetch, @@ -980,6 +517,7 @@ startWebSession // endDefinition; (*WebImageSearch*) $defaultChatTools0[ "WebImageSearcher" ] = <| toolDefaultData[ "WebImageSearcher" ], + "ShortName" -> "img_search", "Icon" -> RawBoxes @ TemplateBox[ { }, "ToolIconWebImageSearcher" ], "Description" -> "Search the web for images.", "Function" -> webImageSearch, @@ -999,9 +537,8 @@ $defaultChatTools0[ "WebImageSearcher" ] = <| (*webImageSearch*) webImageSearch // beginDefinition; -webImageSearch[ KeyValuePattern[ "query" -> query_ ] ] := webImageSearch @ query; -webImageSearch[ query_String ] := Block[ { PrintTemporary }, webImageSearch @ SearchQueryString @ query ]; -webImageSearch[ query_SearchQueryString ] := webImageSearch[ query, webImageSearch0[ query ] ]; +webImageSearch[ KeyValuePattern[ "query" -> query_ ] ] := Block[ { PrintTemporary }, webImageSearch @ query ]; +webImageSearch[ query_String ] := webImageSearch[ query, webImageSearch0[ query ] ]; webImageSearch[ query_, { } ] := <| "Result" -> { }, @@ -1023,7 +560,7 @@ webImageSearch // endDefinition; webImageSearch0 // beginDefinition; -webImageSearch0[ query_SearchQueryString ] := Enclose[ +webImageSearch0[ query_String ] := Enclose[ Module[ { opts, raw, result, held, $unavailable }, opts = Sequence @@ ConfirmMatch[ toolOptions[ "WebImageSearcher" ], { $$optionsSequence }, "Options" ]; result = Quiet[ @@ -1045,7 +582,7 @@ webImageSearch0[ query_SearchQueryString ] := Enclose[ } ] ], - throwInternalFailure[ webImageSearch0 @ query, ## ] & + throwInternalFailure ]; webImageSearch0 // endDefinition; @@ -1061,8 +598,11 @@ $fullExamples := With[ { keys = $fullExamplesKeys }, If[ keys === { }, "", + needsBasePrompt[ "EndTurnToolCall" ]; StringJoin[ - "## Full examples\n\n---\n\n", + "## Full examples\n\n", + "The following are brief conversation examples that demonstrate how you can use tools in a ", + "conversation with the user.\n\n---\n\n", StringRiffle[ Values @ KeyTake[ $fullExamples0, $fullExamplesKeys ], "\n\n---\n\n" ], "\n\n---\n" ] @@ -1103,173 +643,269 @@ $fullExamples0 = <| |>; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) -(*AstroGraphicsDocumentation*) -$fullExamples0[ "AstroGraphicsDocumentation" ] = TemplateApply[ "\ -[user] -How do I use AstroGraphics? +(*Example Templates*) +$chatMessageTemplates = <| |>; +$messageTemplateType = "Basic"; -[assistant] -Let me check the documentation for you. One moment... -`1` +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*Basic*) +$chatMessageTemplates[ "Basic" ] = <| |>; +$chatMessageTemplates[ "Basic", "User" ] = "User: %%1%%"; +$chatMessageTemplates[ "Basic", "Assistant" ] = "Assistant: %%1%%\n/end"; +$chatMessageTemplates[ "Basic", "System" ] = "System: %%1%%"; -[system] -Usage -AstroGraphics[primitives, options] represents a two-dimensional view of space and the celestial sphere. +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*Instruct*) +$chatMessageTemplates[ "Instruct" ] = <| |>; +$chatMessageTemplates[ "Instruct", "User" ] = "[INST]%%1%%[/INST]"; +$chatMessageTemplates[ "Instruct", "Assistant" ] = "%%1%%\n/end"; +$chatMessageTemplates[ "Instruct", "System" ] = "[INST]%%1%%[/INST]"; -Basic Examples -... +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*Zephyr*) +$chatMessageTemplates[ "Zephyr" ] = <| |>; +$chatMessageTemplates[ "Zephyr", "User" ] = "<|user|>\n%%1%%"; +$chatMessageTemplates[ "Zephyr", "Assistant" ] = "<|assistant|>\n%%1%%\n/end"; +$chatMessageTemplates[ "Zephyr", "System" ] = "<|system|>\n%%1%%"; -[assistant] -To use [AstroGraphics](paclet:ref/AstroGraphics), you need to provide a list of graphics primitives and options. \ -For example, ...", -{ - formatToolCallExample[ "DocumentationLookup", <| "names" -> "AstroGraphics" |> ] -} ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*Phi*) +$chatMessageTemplates[ "Phi" ] = <| |>; +$chatMessageTemplates[ "Phi", "User" ] = "<|user|>\n%%1%%<|end|>"; +$chatMessageTemplates[ "Phi", "Assistant" ] = "<|assistant|>\n%%1%%\n/end<|end|>"; +$chatMessageTemplates[ "Phi", "System" ] = "<|user|>\n%%1%%<|end|>"; (* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*NaturalLanguageInput*) -$fullExamples0[ "NaturalLanguageInput" ] = "\ -[user] -How far away is NYC from Boston? - -[assistant] -"<>formatToolCallExample[ - "WolframLanguageEvaluator", - <| - "code" -> "GeoDistance[\[FreeformPrompt][\"Boston, MA\"], \[FreeformPrompt][\"New York City\"]]" - |> -]<>" - -[system] -Quantity[164.41, \"Miles\"] - -[assistant] -It's 164.41 miles from Boston to New York City. - -[user] -If I made the trip in 3h 17m, how fast was I going? - -[assistant] -"<>formatToolCallExample[ - "WolframLanguageEvaluator", - <| "code" -> "\[FreeformPrompt][\"164.41 Miles\"] / \[FreeformPrompt][\"3h 17m\"]" |> -]<>"\ - -[system] -Quantity[50.071, \"Miles\" / \"Hours\"] - -[assistant] -You were going 50.071 miles per hour. - -[user] -What time would I arrive if I left right now? - -[assistant] -"<>formatToolCallExample[ - "WolframLanguageEvaluator", - <| "code" -> "\[FreeformPrompt][\"3h 17m from now\"]" |> -]; +(* ::Subsubsubsection::Closed:: *) +(*Boxed*) +$chatMessageTemplates[ "Boxed" ] = <| |>; +$chatMessageTemplates[ "Boxed", "User" ] = "[user]\n%%1%%"; +$chatMessageTemplates[ "Boxed", "Assistant" ] = "[assistant]\n%%1%%\n/end"; +$chatMessageTemplates[ "Boxed", "System" ] = "[system]\n%%1%%"; (* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*FileSystemTree*) -$fullExamples0[ "FileSystemTree" ] = "\ -[user] -What's the best way to generate a tree of files in a given directory? +(* ::Subsubsubsection::Closed:: *) +(*ChatML*) +$chatMessageTemplates[ "ChatML" ] = <| |>; +$chatMessageTemplates[ "ChatML", "User" ] = "<|im_start|>user\n%%1%%<|im_end|>"; +$chatMessageTemplates[ "ChatML", "Assistant" ] = "<|im_start|>assistant\n%%1%%\n/end<|im_end|>"; +$chatMessageTemplates[ "ChatML", "System" ] = "<|im_start|>system\n%%1%%<|im_end|>"; -[assistant] -"<>formatToolCallExample[ "DocumentationSearcher", <| "query" -> "tree of files" |> ]<>" +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*XML*) +$chatMessageTemplates[ "XML" ] = <| |>; +$chatMessageTemplates[ "XML", "User" ] = "%%1%%"; +$chatMessageTemplates[ "XML", "Assistant" ] = "%%1%%\n/end"; +$chatMessageTemplates[ "XML", "System" ] = "%%1%%"; -[system] -* FileSystemTree - (score: 9.9) FileSystemTree[root] gives a tree whose keys are ... -* Tree Drawing - (score: 3.0) ... +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*messageTemplate*) +messageTemplate // beginDefinition; -[assistant] -"<>formatToolCallExample[ "DocumentationLookup", <| "names" -> "FileSystemTree" |> ]<>" +messageTemplate[ id_String ] := Enclose[ + StringTemplate[ + ConfirmBy[ $chatMessageTemplates[ $messageTemplateType, id ], StringQ, "TemplateString" ], + Delimiters -> "%%" + ], + throwInternalFailure +]; -..."; +messageTemplate // endDefinition; (* ::**************************************************************************************************************:: *) -(* ::Subsubsection::Closed:: *) -(*FractionalDerivatives*) -$fullExamples0[ "FractionalDerivatives" ] = "\ -[user] -Calculate the half-order fractional derivative of x^n with respect to x. +(* ::Subsubsubsection::Closed:: *) +(*user*) +user // beginDefinition; +user[ a_List ] := TemplateApply[ messageTemplate[ "User" ], StringRiffle[ TextString /@ Flatten @ a, "\n" ] ]; +user[ a_String ] := user @ { a }; +user // endDefinition; -[assistant] -"<>formatToolCallExample[ "DocumentationSearcher", <| "query" -> "fractional derivatives" |> ]<>" +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*assistant*) +assistant // beginDefinition; +assistant[ { a___, "tool" -> { name_String, as_Association }, b___ } ] := assistant @ { a, toolCall[ name, as ], b }; +assistant[ a_List ] := TemplateApply[ messageTemplate[ "Assistant" ], StringRiffle[ TextString /@ Flatten @ a, "\n" ] ]; +assistant[ a_String ] := assistant @ { a }; +assistant // endDefinition; -[system] -* FractionalD - (score: 9.5) FractionalD[f, {x, a}] gives ... -* NFractionalD - (score: 9.2) ... +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*system*) +system // beginDefinition; +system[ a_List ] := TemplateApply[ messageTemplate[ "System" ], StringRiffle[ TextString /@ Flatten @ a, "\n" ] ]; +system[ a_String ] := system @ { a }; +system // endDefinition; -[assistant] -"<>formatToolCallExample[ "DocumentationLookup", <| "names" -> "FractionalD" |> ]<>" +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*toolCall*) +toolCall // beginDefinition; +toolCall[ args__ ] := formatToolCallExample @ args; +toolCall // endDefinition; -[system] -Usage -FractionalD[f, {x, a}] gives the Riemann-Liouville fractional derivative D_x^a f(x) of order a of the function f. +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*toolExample*) +toolExample // beginDefinition; +toolExample[ rules: (_Rule|_String).. ] := StringRiffle[ toolExample0 /@ { rules }, "\n\n" ]; +toolExample // endDefinition; -Basic Examples - +toolExample0 // beginDefinition; +toolExample0[ "user" -> message_ ] := user @ message; +toolExample0[ "assistant" -> message_ ] := assistant @ message; +toolExample0[ "system" -> message_ ] := system @ message; +toolExample0[ prompt_String ] := prompt; +toolExample0 // endDefinition; -[assistant] -"<>formatToolCallExample[ "WolframLanguageEvaluator", <| "code" -> "FractionalD[x^n, {x, 1/2}]" |> ]<>" +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*AstroGraphicsDocumentation*) +$fullExamples0[ "AstroGraphicsDocumentation" ] := toolExample[ + "user" -> "How do I use AstroGraphics?", + "assistant" -> { + "Let me check the documentation for you. One moment...", + "tool" -> { "DocumentationLookup", <| "names" -> "AstroGraphics" |> } + }, + "system" -> { + "Usage", + "AstroGraphics[primitives, options] represents a two-dimensional view of space and the celestial sphere.", + "", + "Basic Examples", + "..." + }, + "assistant" -> "To use [AstroGraphics](paclet:ref/AstroGraphics), you need to..." +]; -[system] -Out[n]= Piecewise[...] +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*NaturalLanguageInput*) +$fullExamples0[ "NaturalLanguageInput" ] := toolExample[ + "user" -> "How far away is NYC from Boston?", + "assistant" -> { + "tool" -> { + "WolframLanguageEvaluator", + <| "code" -> "GeoDistance[\[FreeformPrompt][\"Boston, MA\"], \[FreeformPrompt][\"New York City\"]]" |> + } + }, + "system" -> "Quantity[164.41, \"Miles\"]", + "assistant" -> "It's 164.41 miles from Boston to New York City.", + "user" -> "If I made the trip in 3h 17m, how fast was I going?", + "assistant" -> { + "tool" -> { + "WolframLanguageEvaluator", + <| "code" -> "\[FreeformPrompt][\"164.41 Miles\"] / \[FreeformPrompt][\"3h 17m\"]" |> + } + }, + "system" -> "Quantity[50.071, \"Miles\" / \"Hours\"]", + "assistant" -> "You were going 50.071 miles per hour.", + "user" -> "What time would I arrive if I left right now?", + "assistant" -> { + "tool" -> { + "WolframLanguageEvaluator", + <| "code" -> "\[FreeformPrompt][\"3h 17m from now\"]" |> + } + } +]; -![Formatted Result](expression://content-{id}) +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*FileSystemTree*) +$fullExamples0[ "FileSystemTree" ] := toolExample[ + "user" -> "What's the best way to generate a tree of files in a given directory?", + "assistant" -> { + "tool" -> { "DocumentationSearcher", <| "query" -> "tree of files" |> } + }, + "system" -> { + "* FileSystemTree - (score: 9.9) FileSystemTree[root] gives a tree whose keys are ...", + "* Tree Drawing - (score: 3.0) ..." + }, + "assistant" -> { + "tool" -> { "DocumentationLookup", <| "names" -> "FileSystemTree" |> } + }, + "..." +]; -[assistant] -The half-order fractional derivative of $$x^n$$ with respect to $$x$$ is given by: -![Fractional Derivative](expression://content-{id}) -"; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*FractionalDerivatives*) +$fullExamples0[ "FractionalDerivatives" ] := toolExample[ + "user" -> "Calculate the half-order fractional derivative of x^n with respect to x.", + "assistant" -> { + "tool" -> { "DocumentationSearcher", <| "query" -> "fractional derivatives" |> } + }, + "system" -> { + "* FractionalD - (score: 9.5) FractionalD[f, {x, a}] gives ...", + "* NFractionalD - (score: 9.2) ..." + }, + "assistant" -> { + "tool" -> { "DocumentationLookup", <| "names" -> "FractionalD" |> } + }, + "system" -> { + "Usage", + "FractionalD[f, {x, a}] gives the Riemann-Liouville fractional derivative D_x^a f(x) of order a of the function f.", + "", + "Basic Examples", + "..." + }, + "assistant" -> { + "tool" -> { + "WolframLanguageEvaluator", + <| "code" -> "FractionalD[x^n, {x, 1/2}]" |> + } + }, + "system" -> { + "Out[n]= Piecewise[...]\n", + "![Formatted Result](expression://content-{id})" + }, + "assistant" -> { + "The half-order fractional derivative of $$x^n$$ with respect to $$x$$ is given by:", + "![Fractional Derivative](expression://content-{id})" + } +]; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*PlotEvaluate*) -$fullExamples0[ "PlotEvaluate" ] = StringJoin[ "\ -[user] -Plot sin(x) from -5 to 5 - -[assistant] -", formatToolCallExample[ - "WolframLanguageEvaluator", - <| "code" -> "Plot[Sin[x], {x, -5, 5}, AxesLabel -> {\"x\", \"sin(x)\"}]" |> -], " - -[system] -Out[n]= ![image](attachment://content-{id}) - -[assistant] -Here's the plot of $$\\sin{x}$$ from -5 to 5: -![Plot](attachment://content-{id})" +$fullExamples0[ "PlotEvaluate" ] := toolExample[ + "user" -> "Plot sin(x) from -5 to 5", + "assistant" -> { + "tool" -> { + "WolframLanguageEvaluator", + <| "code" -> "Plot[Sin[x], {x, -5, 5}, AxesLabel -> {\"x\", \"sin(x)\"}" |> + } + }, + "system" -> "Out[n]= ![image](attachment://content-{id})", + "assistant" -> { + "Here's the plot of $$\\sin{x}$$ from -5 to 5:", + "![Plot](attachment://content-{id})" + } ]; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*TemporaryDirectory*) -$fullExamples0[ "TemporaryDirectory" ] = "\ -[user] -Where is the temporary directory located? - -[assistant] -"<>formatToolCallExample[ "DocumentationSearcher", <| "query" -> "location of temporary directory" |> ]<>" - -[system] -* $TemporaryDirectory - (score: 9.6) $TemporaryDirectory gives the main system directory for temporary files. -* CreateDirectory - (score: 8.5) CreateDirectory[\"dir\"] creates ... - -[assistant] -"<>formatToolCallExample[ "WolframLanguageEvaluator", <| "code" -> "$TemporaryDirectory" |> ]<>" - -[system] -Out[n]= \"C:\\Users\\UserName\\AppData\\Local\\Temp\" - -[assistant] -The temporary directory is located at C:\\Users\\UserName\\AppData\\Local\\Temp."; +$fullExamples0[ "TemporaryDirectory" ] := toolExample[ + "user" -> "Where is the temporary directory located?", + "assistant" -> { + "tool" -> { "DocumentationSearcher", <| "query" -> "location of temporary directory" |> } + }, + "system" -> { + "* $TemporaryDirectory - (score: 9.6) $TemporaryDirectory gives the main system directory for temporary files.", + "* CreateDirectory - (score: 8.5) CreateDirectory[\"dir\"] creates ..." + }, + "assistant" -> { + "tool" -> { "WolframLanguageEvaluator", <| "code" -> "$TemporaryDirectory" |> } + }, + "system" -> "Out[n]= \"C:\\Users\\UserName\\AppData\\Local\\Temp\"", + "assistant" -> "The temporary directory is located at C:\\Users\\UserName\\AppData\\Local\\Temp." +]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -1302,7 +938,8 @@ GetExpressionURIs[ str_String, wrapper_, opts: OptionsPattern[ ] ] := catchMine @ Block[ { $uriTooltip = OptionValue @ Tooltip }, StringSplit[ str, - link: Shortest[ "![" ~~ __ ~~ "](" ~~ __ ~~ ")" ] :> catchAlways @ GetExpressionURI[ link, wrapper ] + link: Shortest[ "![" ~~ __ ~~ "](" ~~ __ ~~ ")" ] /; expressionURIQ @ link :> + catchAlways @ GetExpressionURI[ link, wrapper ] ] ]; @@ -1370,6 +1007,13 @@ getExpressionURI0[ tooltip_, uri_String, as_ ] := getExpressionURI0 // endDefinition; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*expressionURIQ*) +expressionURIQ // beginDefinition; +expressionURIQ[ str_String ] := expressionURIKeyQ @ expressionURIKey @ str; +expressionURIQ // endDefinition; + (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*expressionURIKeyQ*) @@ -1606,11 +1250,12 @@ getToolFormattingFunction // endDefinition; (*Package Footer*) (* Sort tools to their default ordering: *) -$defaultChatTools0 = Block[ { LLMTool }, - LLMTool[ #, { } ] & /@ Association[ KeyTake[ $defaultChatTools0, $defaultToolOrder ], $defaultChatTools0 ] +$defaultChatTools0 = Map[ + LLMTool[ #, { } ] &, + <| KeyTake[ $defaultChatTools0, $defaultToolOrder ], $defaultChatTools0 |> ]; -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ $toolConfiguration; ]; diff --git a/Source/Chatbook/Tools/ToolOptions.wl b/Source/Chatbook/Tools/ToolOptions.wl index cbce76de..0dcd0691 100644 --- a/Source/Chatbook/Tools/ToolOptions.wl +++ b/Source/Chatbook/Tools/ToolOptions.wl @@ -7,16 +7,10 @@ BeginPackage[ "Wolfram`Chatbook`Tools`" ]; Begin[ "`Private`" ]; Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`ChatMessages`" ]; Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Formatting`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; Needs[ "Wolfram`Chatbook`Personas`" ]; -Needs[ "Wolfram`Chatbook`Prompting`" ]; Needs[ "Wolfram`Chatbook`ResourceInstaller`" ]; -Needs[ "Wolfram`Chatbook`Sandbox`" ]; Needs[ "Wolfram`Chatbook`Serialization`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -90,8 +84,8 @@ toOptionKey // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Tools/Tools.wl b/Source/Chatbook/Tools/Tools.wl index 91458448..aee7251a 100644 --- a/Source/Chatbook/Tools/Tools.wl +++ b/Source/Chatbook/Tools/Tools.wl @@ -1,36 +1,6 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Tools`" ]; - -HoldComplete[ - `$attachments; - `$defaultChatTools; - `$selectedTools; - `$toolConfiguration; - `$toolEvaluationResults; - `$toolOptions; - `$toolResultStringLength; - `expressionURIKey; - `expressionURIKeyQ; - `getToolByName; - `getToolDisplayName; - `getToolFormattingFunction; - `getToolIcon; - `initTools; - `makeExpressionURI; - `makeToolConfiguration; - `makeToolResponseString; - `resolveTools; - `simpleToolRequestParser; - `toolData; - `toolName; - `toolOptionValue; - `toolRequestParser; - `toolSelectedQ; - `toolShortName; - `withToolBox; -]; - Begin[ "`Private`" ]; (* ::**************************************************************************************************************:: *) @@ -40,12 +10,13 @@ Get[ "Wolfram`Chatbook`Tools`Common`" ]; Get[ "Wolfram`Chatbook`Tools`ToolOptions`" ]; Get[ "Wolfram`Chatbook`Tools`DefaultTools`" ]; Get[ "Wolfram`Chatbook`Tools`ChatPreferences`" ]; +Get[ "Wolfram`Chatbook`Tools`WolframAlpha`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Tools/WolframAlpha.wl b/Source/Chatbook/Tools/WolframAlpha.wl new file mode 100644 index 00000000..1c12dfcc --- /dev/null +++ b/Source/Chatbook/Tools/WolframAlpha.wl @@ -0,0 +1,570 @@ +(* ::Section::Closed:: *) +(*Package Header*) +BeginPackage[ "Wolfram`Chatbook`Tools`" ]; +Begin[ "`Private`" ]; + +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Configuration*) +$defaultPods := toolOptionValue[ "WolframAlpha", "DefaultPods" ]; +$foldPods := toolOptionValue[ "WolframAlpha", "FoldPods" ]; +$maximumWAPodByteCount := toolOptionValue[ "WolframAlpha", "MaxPodByteCount" ]; + +$moreDetailsPlusIcon = RawBoxes @ TemplateBox[ { RGBColor[ "#678e9c" ] }, "DiscardedMaterialOpenerIcon" ]; +$moreDetailsMinusIcon = RawBoxes @ TemplateBox[ { RGBColor[ "#678e9c" ] }, "DiscardedMaterialCloserIcon" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Wolfram Alpha Results*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*getWolframAlphaText*) +getWolframAlphaText // beginDefinition; + +getWolframAlphaText[ as_Association ] := + getWolframAlphaText[ as[ "query" ], as[ "steps" ] ]; + +getWolframAlphaText[ query_String, steps: True|False|_Missing ] := + Module[ { result, data, string }, + result = wolframAlpha[ query, steps ]; + data = WolframAlpha[ + query, + { All, { "Title", "Plaintext", "ComputableData", "Content" } }, + PodStates -> { If[ TrueQ @ steps, "Step-by-step solution", Nothing ] } + ]; + string = getWolframAlphaText[ query, steps, data ]; + getWolframAlphaText[ query, steps ] = <| "Result" -> result, "String" -> string |> + ]; + +getWolframAlphaText[ query_String, steps_, { } ] := + "No results returned"; + +(* cSpell: ignore deflatten *) +getWolframAlphaText[ query_String, steps_, info_List ] := + getWolframAlphaText[ query, steps, associationKeyDeflatten[ makeKeySequenceRule /@ info ] ]; + +getWolframAlphaText[ query_String, steps_, as_Association? AssociationQ ] := + getWolframAlphaText[ query, steps, waResultText @ as ]; + +getWolframAlphaText[ query_String, steps_, result_String ] := + result; + +getWolframAlphaText // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*wolframAlpha*) +wolframAlpha // beginDefinition; +wolframAlpha[ args___ ] /; $defaultPods := defaultPods @ args; +wolframAlpha[ args___ ] := fasterWolframAlphaPods @ args; +wolframAlpha // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*defaultPods*) +defaultPods // beginDefinition; +defaultPods[ args___ ] := defaultPods[ args ] = WolframAlpha @ args; +defaultPods // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*fasterWolframAlphaPods*) +fasterWolframAlphaPods // beginDefinition; + +fasterWolframAlphaPods[ query_String, steps: True|False|_Missing ] := Enclose[ + Catch @ Module[ { titlesAndCells, grouped }, + titlesAndCells = Confirm[ + WolframAlpha[ + query, + { All, { "Title", "Cell" } }, + PodStates -> { If[ TrueQ @ steps, "Step-by-step solution", Nothing ] } + ], + "WolframAlpha" + ]; + If[ titlesAndCells === { }, Throw @ Missing[ "NoResults" ] ]; + grouped = DeleteCases[ SortBy[ #1, podOrder ] & /@ GroupBy[ titlesAndCells, podKey ], CellSize -> _, Infinity ]; + fasterWolframAlphaPods[ query, steps ] = <| "Query" -> query, "Pods" -> grouped |> + ], + throwInternalFailure +]; + +fasterWolframAlphaPods // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*podOrder*) +podOrder // beginDefinition; +podOrder[ key_ -> _ ] := podOrder @ key; +podOrder[ { { _String, idx_Integer }, _String } ] := idx; +podOrder // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*podKey*) +podKey // beginDefinition; +podKey[ key_ -> _ ] := podKey @ key; +podKey[ { { key_String, _Integer }, _String } ] := key; +podKey // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*waResultText*) +waResultText // beginDefinition; +waResultText[ as_ ] := Block[ { $level = 1 }, StringRiffle[ Flatten @ Values[ waResultText0 /@ as ], "\n" ] ]; +waResultText // endDefinition; + + +waResultText0 // beginDefinition; + +waResultText0[ as: KeyValuePattern @ { "Title" -> title_String, "Data" -> data_ } ] := + StringRepeat[ "#", $level ] <> " " <> title <> "\n" <> waResultText0 @ data; + +waResultText0[ as: KeyValuePattern[ _Integer -> _ ] ] := + waResultText0 /@ Values @ KeySort @ KeySelect[ as, IntegerQ ]; + +waResultText0[ as: KeyValuePattern @ { "Content"|"ComputableData" -> expr_ } ] /; + ! FreeQ[ Unevaluated @ expr, _Missing ] := + Replace[ Lookup[ as, "Plaintext" ], Except[ _String ] :> Nothing ]; + +waResultText0[ KeyValuePattern @ { "Plaintext" -> text_String, "ComputableData" -> Hold[ expr_ ] } ] := + If[ ByteCount @ Unevaluated @ expr >= 500, + If[ StringFreeQ[ text, "["|"]"|"\n" ], + makeExpressionURI[ text, Unevaluated @ expr ] <> "\n", + escapeMarkdownString @ text <> "\n" <> makeExpressionURI[ Unevaluated @ expr ] <> "\n" + ], + escapeMarkdownString @ text <> "\n" + ]; + +waResultText0[ as: KeyValuePattern @ { "Plaintext" -> text_String, "ComputableData" -> expr: Except[ _Hold ] } ] := + waResultText0 @ Append[ as, "ComputableData" -> Hold @ expr ]; + +waResultText0[ KeyValuePattern @ { "Plaintext" -> text_String, "Content" -> content_ } ] := + If[ ByteCount @ content >= 500, + If[ StringFreeQ[ text, "["|"]"|"\n" ], + makeExpressionURI[ text, Unevaluated @ content ] <> "\n", + escapeMarkdownString @ text <> "\n" <> makeExpressionURI[ Unevaluated @ content ] <> "\n" + ], + escapeMarkdownString @ text <> "\n" + ]; + +waResultText0[ as_Association ] /; Length @ as === 1 := + waResultText0 @ First @ as; + +waResultText0[ as_Association ] := + KeyValueMap[ + Function[ + StringJoin[ + StringRepeat[ "#", $level ], + " ", + ToString[ #1 ], + "\n", + Block[ { $level = $level + 1 }, waResultText0[ #2 ] ] + ] + ], + as + ]; + +waResultText0[ expr_ ] := + With[ { s = ToString[ Unevaluated @ expr, InputForm ] }, + escapeMarkdownString @ s <> "\n" /; StringLength @ s <= 100 + ]; + +waResultText0[ expr_ ] := + makeExpressionURI @ Unevaluated @ expr <> "\n"; + +waResultText0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Formatting*) +FormatWolframAlphaPods = formatWolframAlphaPods; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*wolframAlphaResultFormatter*) +wolframAlphaResultFormatter // beginDefinition; + +wolframAlphaResultFormatter[ query_String, "Parameters", "query" ] := + clickToCopy @ query; + +wolframAlphaResultFormatter[ KeyValuePattern[ "Result" -> result_ ], "Result" ] := + wolframAlphaResultFormatter[ result, "Result" ]; + +wolframAlphaResultFormatter[ result_, "Result" ] := + formatWolframAlphaPods @ result; + +wolframAlphaResultFormatter[ expr_, ___ ] := + expr; + +wolframAlphaResultFormatter // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*formatWolframAlphaPods*) +formatWolframAlphaPods // beginDefinition; + +formatWolframAlphaPods[ expr: _Missing|_Failure|$Failed ] := + expr; + +formatWolframAlphaPods[ info_Association ] := + formatWolframAlphaPods[ info[ "Query" ], info[ "Pods" ], $dynamicText ]; + +formatWolframAlphaPods[ query_, grouped_Association, dynamic_ ] := Enclose[ + Module[ { formatted, framed }, + formatted = ConfirmBy[ formatPods[ query, grouped ], ListQ, "Formatted" ]; + + framed = Framed[ + Column[ formatted, Alignment -> Left, Spacings -> { { }, { { 1 }, -2 -> 0.5, -1 -> 0 } } ], + Background -> GrayLevel[ 1 ], + FrameMargins -> 0, + FrameStyle -> GrayLevel[ 1 ], + RoundingRadius -> 0, + TaggingRules -> <| "WolframAlphaPods" -> True |> + ]; + + Verbatim[ formatWolframAlphaPods[ query, grouped, dynamic ] ] = framed + ], + throwInternalFailure +]; + +formatWolframAlphaPods // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*formatPods*) +formatPods // beginDefinition; +formatPods[ args__ ] := Block[ { $foldPods = toolOptionValue[ "WolframAlpha", "FoldPods" ] }, formatPods0 @ args ]; +formatPods // endDefinition; + +formatPods0 // beginDefinition; + +formatPods0[ query_, as: KeyValuePattern @ { "Input" -> input_, "Result" -> result_ } ] /; $foldPods := Enclose[ + Module[ { rest }, + rest = Values @ KeyDrop[ as, { "Input", "Result" } ]; + Flatten @ { + formatPod @ input, + formatPod @ result, + If[ rest === { }, + Nothing, + podMoreDetailsOpener[ + query, + Column[ + formatPod /@ rest, + Alignment -> Left, + Spacings -> { { }, 1 } + ] + ] + ] + } + ], + throwInternalFailure +]; + +formatPods0[ query_, as_Association ] /; $foldPods && Length @ as > 3 := Enclose[ + Module[ { show, hide }, + { show, hide } = ConfirmMatch[ TakeDrop[ as, 3 ], { _Association, _Association }, "TakeDrop" ]; + Flatten @ { + formatPod /@ Values @ show, + podMoreDetailsOpener[ + query, + Column[ + formatPod /@ Values @ hide, + Alignment -> Left, + Spacings -> { { }, 1 } + ] + ] + } + ], + throwInternalFailure +]; + +formatPods0[ query_, grouped_Association ] := + Append[ Map[ formatPod, Values @ grouped ], waFooterMenu @ query ]; + +formatPods0 // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatPod*) +formatPod // beginDefinition; + +formatPod[ content_List ] := Framed[ + Column[ formatPodItem /@ content, Alignment -> Left ], + Background -> White, + FrameMargins -> 5, + FrameStyle -> GrayLevel[ 0.8 ], + ImageSize -> { Scaled[ 1 ], Automatic }, + ImageMargins -> If[ $CloudEvaluation, { { 0, 25 }, { 0, 0 } }, 0 ], + RoundingRadius -> 3 +]; + +formatPod // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*formatPodItem*) +formatPodItem // beginDefinition; + +formatPodItem[ key_ -> value_ ] := + formatPodItem[ key, value ]; + +formatPodItem[ { _, "Title" }, title_String ] := + Style[ StringTrim[ title, ":" ] <> ":", "Text", FontColor -> RGBColor[ "#678e9c" ], FontSize -> 12 ]; + +formatPodItem[ { _, "Cell" }, cell_ ] /; ByteCount @ cell > $maximumWAPodByteCount := + Pane[ + If[ TrueQ @ $dynamicText, + $statelessProgressIndicator, + compressUntilViewed[ cell, True ] + ], + ImageMargins -> { { 10, 0 }, { 0, 0 } } + ]; + +formatPodItem[ { _, "Cell" }, cell_ ] := + Pane[ cell, ImageMargins -> { { 10, 0 }, { 0, 0 } } ]; + +formatPodItem // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*podMoreDetailsOpener*) +podMoreDetailsOpener // beginDefinition; +podMoreDetailsOpener // Attributes = { HoldAll }; + +podMoreDetailsOpener[ query_, hidden_ ] /; $dynamicText := ""; + +podMoreDetailsOpener[ query_, hidden_ ] := + DynamicModule[ { expand = False, menu }, + menu = waFooterMenu @ query; + PaneSelector[ + { + False -> Grid[ + { { podShowMoreDetailsButton @ Dynamic @ expand, Item[ "", ItemSize -> Fit ], menu } }, + Alignment -> { { Left, Right }, Baseline } + ], + True -> Column[ + Flatten @ { + Grid[ + { { podHideMoreDetailsButton @ Dynamic @ expand, Item[ "", ItemSize -> Fit ] } }, + Alignment -> { { Left, Right }, Baseline } + ], + compressUntilViewed[ hidden, True ], + menu + }, + Alignment -> Left + ] + }, + Dynamic @ expand, + ImageSize -> Automatic + ] + ]; + +podMoreDetailsOpener // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*podShowMoreDetailsButton*) +podShowMoreDetailsButton // beginDefinition; + +podShowMoreDetailsButton[ Dynamic[ expand_ ] ] := Button[ + MouseAppearance[ + Framed[ + Style[ + Row @ { $moreDetailsPlusIcon, " Show more details" }, + "Text", + FontColor -> RGBColor[ "#678e9c" ], + FontSize -> 12 + ], + FrameMargins -> { { 6, 6 }, { 2, 2 } }, + FrameStyle -> RGBColor[ "#678e9c" ], + RoundingRadius -> 3 + ], + "LinkHand" + ], + expand = True, + Appearance -> "Suppressed", + ImageMargins -> { { 0, 0 }, { 0, 10 } } +]; + +podShowMoreDetailsButton // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*podHideMoreDetailsButton*) +podHideMoreDetailsButton // beginDefinition; + +podHideMoreDetailsButton[ Dynamic[ expand_ ] ] := Button[ + MouseAppearance[ + Framed[ + Style[ + Row @ { $moreDetailsMinusIcon, " Hide more details" }, + "Text", + FontColor -> RGBColor[ "#678e9c" ], + FontSize -> 12 + ], + FrameMargins -> { { 6, 6 }, { 2, 2 } }, + FrameStyle -> RGBColor[ "#678e9c" ], + RoundingRadius -> 3 + ], + "LinkHand" + ], + expand = False, + Appearance -> "Suppressed", + ImageMargins -> { { 0, 0 }, { 10, 10 } } +]; + +podHideMoreDetailsButton // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Links Menu*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*waFooterMenu*) +waFooterMenu // beginDefinition; + +(* cSpell: ignore Localizable *) +waFooterMenu[ query_String ] := Item[ + Style[ + DynamicModule[ { display }, + display = Button[ + Dynamic @ RawBoxes @ FEPrivate`FrontEndResource[ "FEBitmaps", "CirclePlusIconScalable" ], + Null, + Appearance -> None + ]; + Grid[ + { + { + Hyperlink[ + Dynamic @ RawBoxes @ FEPrivate`FrontEndResource[ "WALocalizableBitmaps", "WolframAlpha" ], + "https://www.wolframalpha.com", + Alignment -> Left + ], + Pane[ + Dynamic @ display, + FrameMargins -> { { 0, If[ $CloudEvaluation, 23, 3 ] }, { 0, 0 } } + ] + } + }, + Spacings -> 0.5 + ], + SynchronousInitialization -> False, + Initialization :> + If[ ! MatchQ[ display, _Tooltip ], + Needs[ "Wolfram`Chatbook`" -> None ]; + display = Replace[ makeWebLinksMenu @ query, Except[ _Tooltip ] :> "" ] + ] + ], + "WolframAlphaLinksMenu" + ], + Alignment -> Right +]; + +waFooterMenu // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*makeWebLinksMenu*) +makeWebLinksMenu // beginDefinition; + +makeWebLinksMenu[ query_String ] /; $dynamicText := + Nothing; + +makeWebLinksMenu[ query_String ] := Enclose[ + Module[ { sources, url, actions }, + + sources = ConfirmMatch[ getWASources @ query, KeyValuePattern @ { } ]; + + (* cSpell: ignore wolframalpha *) + url = URLBuild @ <| + "Scheme" -> "https", + "Domain" -> "www.wolframalpha.com", + "Path" -> { "", "input" }, + "Query" -> { "i" -> query } + |>; + + actions = With[ { u = url }, + Flatten @ { + "Web version" :> NotebookLocate @ { URL @ u, None }, + If[ sources === { }, + Nothing, + { + Delimiter, + KeyValueMap[ + Row @ { "Source information: " <> #1 } :> NotebookLocate @ { URL[ #2 ], None } &, + Association @ sources + ] + } + ] + } + ]; + + makeWebLinksMenu @ actions + ], + "" & +]; + +makeWebLinksMenu[ actions: { (_RuleDelayed|Delimiter).. } ] := Tooltip[ + ActionMenu[ + Dynamic @ RawBoxes @ FEPrivate`FrontEndResource[ "FEBitmaps", "CirclePlusIconScalable" ], + actions, + Appearance -> None + ], + tr[ "DefaultToolsLinks" ] +]; + +makeWebLinksMenu[ ___ ] := ""; + +makeWebLinksMenu // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsection::Closed:: *) +(*getWASources*) +getWASources // beginDefinition; +getWASources[ query_String ] := getWASources[ query, WolframAlpha[ query, "Sources" ] ]; +getWASources[ query_String, sources: KeyValuePattern @ { } ] := getWASources[ query ] = sources; +getWASources[ query_String, _ ] := $Failed; +getWASources // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Misc Utilities*) + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*makeKeySequenceRule*) +makeKeySequenceRule // beginDefinition; +makeKeySequenceRule[ { _, "Cell"|"Position"|"Scanner" } -> _ ] := Nothing; +makeKeySequenceRule[ key_ -> value_ ] := makeKeySequence @ key -> value; +makeKeySequenceRule // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Subsection::Closed:: *) +(*makeKeySequence*) +makeKeySequence // beginDefinition; + +makeKeySequence[ { { path_String, n_Integer }, key_String } ] := + makeKeySequence @ Flatten @ { Reverse @ StringSplit[ path, ":" ], n, key }; + +makeKeySequence[ { path__String, 0, key_String } ] := + { path, key }; + +makeKeySequence[ { path__String, n_Integer, key_String } ] := + { path, "Data", n, key }; + +makeKeySequence // endDefinition; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*Package Footer*) +addToMXInitialization[ + Null +]; + +End[ ]; +EndPackage[ ]; diff --git a/Source/Chatbook/UI.wl b/Source/Chatbook/UI.wl index 551b6fee..a48c739a 100644 --- a/Source/Chatbook/UI.wl +++ b/Source/Chatbook/UI.wl @@ -22,41 +22,17 @@ GeneralUtilities`SetUsage[CreateToolbarContent, " CreateToolbarContent[] is called by the NotebookToolbar to generate the content of the 'Notebook AI Settings' attached menu. "] -HoldComplete[ - `getModelMenuIcon; - `getPersonaIcon; - `getPersonaMenuIcon; - `labeledCheckbox; - `makeAutomaticResultAnalysisCheckbox; - `makeTemperatureSlider; - `makeToolCallFrequencySlider; - `modelGroupName; - `personaDisplayName; - `resizeMenuIcon; - `serviceIcon; - `showSnapshotModelsQ; - `tr; -]; - Begin["`Private`"] -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Actions`" ]; -Needs[ "Wolfram`Chatbook`CloudToolbar`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`Dynamics`" ]; -Needs[ "Wolfram`Chatbook`Errors`" ]; -Needs[ "Wolfram`Chatbook`ErrorUtils`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; -Needs[ "Wolfram`Chatbook`Menus`" ]; -Needs[ "Wolfram`Chatbook`Models`" ]; -Needs[ "Wolfram`Chatbook`Personas`" ]; -Needs[ "Wolfram`Chatbook`PreferencesContent`" ]; -Needs[ "Wolfram`Chatbook`PreferencesUtils`" ]; -Needs[ "Wolfram`Chatbook`Serialization`" ]; -Needs[ "Wolfram`Chatbook`Services`" ]; -Needs[ "Wolfram`Chatbook`Settings`" ]; -Needs[ "Wolfram`Chatbook`Utils`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Actions`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; +Needs[ "Wolfram`Chatbook`Errors`" ]; +Needs[ "Wolfram`Chatbook`ErrorUtils`" ]; +Needs[ "Wolfram`Chatbook`Menus`" ]; +Needs[ "Wolfram`Chatbook`Personas`" ]; +Needs[ "Wolfram`Chatbook`PreferencesUtils`" ]; +Needs[ "Wolfram`Chatbook`Serialization`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -168,17 +144,12 @@ tryMakeChatEnabledNotebook[ _ :> RaiseConfirmMatch[ ChoiceDialog[ Column[{ - Item[Magnify["\[WarningSign]", 5], Alignment -> Center], + Item[Magnify["\[WarningSign]", 3], Alignment -> Center], "", - RawBoxes @ Cell[ - "Enabling Chat Notebook functionality will destroy the" <> - " private styles defined in this notebook, and replace" <> - " them with the shared Chatbook stylesheet.", - "Text" - ], + tr[ "UITryEnableChatDialogMainText" ], "", - RawBoxes @ Cell["Are you sure you wish to continue?", "Text"] - }], + tr[ "UITryEnableChatDialogConfirm" ] + }, BaseStyle -> {"DialogTextBasic", FontSize -> 15, LineIndent -> 0}, Spacings -> {0, 0}], Background -> White ], _?BooleanQ @@ -202,8 +173,8 @@ tryMakeChatEnabledNotebook[ SetFallthroughError[makeEnableAIChatFeaturesLabel] -makeEnableAIChatFeaturesLabel[enabled_?BooleanQ] := - labeledCheckbox[enabled, "Enable AI Chat Features", !enabled] +makeEnableAIChatFeaturesLabel[ enabled_? BooleanQ ] := + labeledCheckbox[ enabled, tr[ "UIEnableChatFeatures" ], ! enabled ]; (*====================================*) @@ -260,18 +231,12 @@ makeAutomaticResultAnalysisCheckbox[ }] }, labeledCheckbox[ - Dynamic[ - autoAssistQ[target], - setterFunction - ], - Row[{ - "Do automatic result analysis", - Spacer[3], - Tooltip[ - chatbookIcon["InformationTooltip", False], - "If enabled, automatic AI provided suggestions will be added following evaluation results." - ] - }] + Dynamic[ autoAssistQ @ target, setterFunction ], + Row @ { + tr[ "UIAutomaticAnalysisLabel" ], + Spacer[ 3 ], + Tooltip[ chatbookIcon[ "InformationTooltip", False ], tr[ "UIAutomaticAnalysisTooltip" ] ] + } ] ] @@ -315,13 +280,13 @@ makeToolCallFrequencySlider[ obj_ ] := ] ] ], - Style[ "Choose automatically", "ChatMenuLabel" ] + Style[ tr[ "UIAdvancedChooseAutomatically" ], "ChatMenuLabel" ] ]; slider = Pane[ Grid[ { { - Style[ "Rare", "ChatMenuLabel", FontSize -> 12 ], + Style[ tr[ "Rare" ], "ChatMenuLabel", FontSize -> 12 ], Slider[ Dynamic[ Replace[ currentChatSettings[ obj, "ToolCallFrequency" ], Automatic -> 0.5 ], @@ -331,7 +296,7 @@ makeToolCallFrequencySlider[ obj_ ] := ImageSize -> { 100, Automatic }, ImageMargins -> { { 0, 0 }, { 5, 5 } } ], - Style[ "Often", "ChatMenuLabel", FontSize -> 12 ] + Style[ tr[ "Often" ], "ChatMenuLabel", FontSize -> 12 ] } }, Spacings -> { { 0, { 0.5 }, 0 }, 0 }, @@ -381,12 +346,6 @@ showSnapshotModelsQ[] := "ShowSnapshotModels" }] - -(*========================================================*) - -(* TODO: Make this look up translations for `name` in text resources data files. *) -tr[name_?StringQ] := name - (* @@ -491,18 +450,18 @@ MakeChatInputCellDingbat[] := (* ::Subsection::Closed:: *) (*MakeChatDelimiterCellDingbat*) MakeChatDelimiterCellDingbat[ ] := - DynamicModule[ { cell }, - trackedDynamic[ MakeChatDelimiterCellDingbat @ cell, { "ChatBlock" } ], + DynamicModule[ { Wolfram`ChatNB`cell }, + trackedDynamic[ MakeChatDelimiterCellDingbat @ Wolfram`ChatNB`cell, { "ChatBlock" } ], Initialization :> ( - cell = EvaluationCell[ ]; + Wolfram`ChatNB`cell = EvaluationCell[ ]; Needs[ "Wolfram`Chatbook`" -> None ]; - updateDynamics[ "ChatBlock" ] + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ "UpdateDynamics", "ChatBlock" ] ), Deinitialization :> ( Needs[ "Wolfram`Chatbook`" -> None ]; - updateDynamics[ "ChatBlock" ] + Symbol[ "Wolfram`Chatbook`ChatbookAction" ][ "UpdateDynamics", "ChatBlock" ] ), - UnsavedVariables :> { cell } + UnsavedVariables :> { Wolfram`ChatNB`cell } ]; MakeChatDelimiterCellDingbat[cell_CellObject] := Module[{ @@ -753,7 +712,7 @@ makeChatActionMenuContent[ advancedSettingsMenu = Join[ { - "Temperature", + tr[ "UIAdvancedTemperature" ], { None, makeTemperatureSlider[tempValue], @@ -761,14 +720,14 @@ makeChatActionMenuContent[ } }, { - "Tool Call Frequency", + tr[ "UIAdvancedToolCallFrequency" ], { None, makeToolCallFrequencySlider[toolValue], None } }, - {"Roles"}, + { tr[ "UIAdvancedRoles" ] }, Map[ entry |-> ConfirmReplace[entry, { {role_?StringQ, icon_} :> { @@ -795,7 +754,7 @@ makeChatActionMenuContent[ (*------------------------------------*) menuItems = Join[ - {"Personas"}, + { tr[ "UIPersonas" ] }, KeyValueMap[ {persona, personaSettings} |-> With[{ icon = getPersonaMenuIcon[personaSettings] @@ -815,23 +774,23 @@ makeChatActionMenuContent[ Delimiter, { alignedMenuIcon[getIcon["ChatBlockSettingsMenuIcon"]], - "Chat Block Settings\[Ellipsis]", + tr[ "UIChatBlockSettings" ], "OpenChatBlockSettings" } }] }], Delimiter, - {alignedMenuIcon[getIcon["PersonaOther"]], "Add & Manage Personas\[Ellipsis]", "PersonaManage"}, - {alignedMenuIcon[getIcon["ToolManagerRepository"]], "Add & Manage Tools\[Ellipsis]", "ToolManage"}, + {alignedMenuIcon[getIcon["PersonaOther"]], tr[ "UIAddAndManagePersonas" ], "PersonaManage"}, + {alignedMenuIcon[getIcon["ToolManagerRepository"]], tr[ "UIAddAndManageTools" ], "ToolManage"}, Delimiter, <| - "Label" -> "Models", + "Label" -> tr[ "UIModels" ], "Type" -> "Submenu", "Icon" -> alignedMenuIcon @ getIcon[ "ChatBlockSettingsMenuIcon" ], "Data" :> createServiceMenu[ targetObj, ParentCell @ EvaluationCell[ ] ] |>, <| - "Label" -> "Advanced Settings", + "Label" -> tr[ "UIAdvancedSettings" ], "Type" -> "Submenu", "Icon" -> alignedMenuIcon @ getIcon[ "AdvancedSettings" ], "Data" -> advancedSettingsMenu @@ -892,8 +851,8 @@ createServiceMenu[ obj_, root_ ] := With[ { model = currentChatSettings[ obj, "Model" ] }, MakeMenu[ Join[ - { "Services" }, - (createServiceItem[ obj, model, root, #1 ] &) /@ getAvailableServiceNames[ ] + { tr[ "UIModelsServices" ] }, + (createServiceItem[ obj, model, root, #1 ] &) /@ getAvailableServiceNames[ "IncludeHidden" -> False ] ], GrayLevel[ 0.85 ], 140 @@ -921,30 +880,57 @@ createServiceItem // endDefinition; (*serviceIcon*) serviceIcon // beginDefinition; -serviceIcon[ KeyValuePattern[ "Service" -> service_String ], service_String ] := - alignedMenuIcon[ $currentSelectionCheck, serviceIcon @ service ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*Definitions for the model submenu*) + +(* OpenAI is the only service that can have raw strings as a model spec: *) +serviceIcon[ model_String, "OpenAI" ] := + alignedMenuIcon[ $currentSelectionCheck, serviceIcon[ "OpenAI" ] ]; -serviceIcon[ _String, "OpenAI" ] := - alignedMenuIcon[ $currentSelectionCheck, serviceIcon @ "OpenAI" ]; +(* Show a checkmark if the currently selected model belongs to this service: *) +serviceIcon[ model: KeyValuePattern[ "Service" -> service_String ], service_String ] := + alignedMenuIcon[ $currentSelectionCheck, serviceIcon @ service ]; -serviceIcon[ _, service_String ] := +(* Otherwise hide the checkmark: *) +serviceIcon[ model_, service_String ] := alignedMenuIcon[ Style[ $currentSelectionCheck, ShowContents -> False ], serviceIcon @ service ]; -serviceIcon[ KeyValuePattern @ { "Service" -> _String, "Icon" -> icon: Except[ "" ] } ] := +$currentSelectionCheck = Style[ "\[Checkmark]", FontColor -> GrayLevel[ 0.25 ] ]; + +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*Services specified as associations*) +(* These services have template box definitions for icons built into the chatbook stylesheet: *) +serviceIcon[ KeyValuePattern[ "Service" -> service: "OpenAI"|"Anthropic"|"PaLM" ] ] := + serviceIcon @ service; + +(* Evaluate delayed icon specs: *) +serviceIcon[ as: KeyValuePattern[ "Icon" :> icon_ ] ] := + serviceIcon @ <| as, "Icon" -> icon |>; + +(* Use the icon specified in the service specification: *) +serviceIcon[ KeyValuePattern @ { "Service" -> _String, "Icon" -> icon: Except[ ""|$$unspecified ] } ] := icon; +(* Fallback to name-based icon: *) serviceIcon[ KeyValuePattern[ "Service" -> service_String ] ] := serviceIcon @ service; -serviceIcon[ "OpenAI" ] := chatbookIcon[ "ServiceIconOpenAI" , True ]; -serviceIcon[ "Anthropic" ] := chatbookIcon[ "ServiceIconAnthropic", True ]; -serviceIcon[ "PaLM" ] := chatbookIcon[ "ServiceIconPaLM" , True ]; +(* ::**************************************************************************************************************:: *) +(* ::Subsubsubsection::Closed:: *) +(*Services specified as strings*) + +(* Services with icons defined in template boxes: *) +serviceIcon[ "OpenAI" ] := chatbookIcon[ "ServiceIconOpenAI" , True ]; +serviceIcon[ "Anthropic" ] := chatbookIcon[ "ServiceIconAnthropic", True ]; +serviceIcon[ "PaLM" ] := chatbookIcon[ "ServiceIconPaLM" , True ]; + +(* Otherwise look in registered service info for an icon: *) serviceIcon[ service_String ] := Replace[ $availableServices[ service, "Icon" ], $$unspecified -> "" ]; serviceIcon // endDefinition; -$currentSelectionCheck = Style[ "\[Checkmark]", FontColor -> GrayLevel[ 0.25 ] ]; - (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*dynamicModelMenu*) @@ -965,7 +951,7 @@ dynamicModelMenu[ obj_, root_, model_, service_ ] := None, Pane[ Column @ { - Style[ "Getting available models\[Ellipsis]", "ChatMenuLabel" ], + Style[ tr[ "UIModelsGet" ], "ChatMenuLabel" ], ProgressIndicator[ Appearance -> "Percolate" ] }, ImageMargins -> 5 @@ -1015,7 +1001,7 @@ makeServiceModelMenu[ Dynamic[ display_ ], obj_, root_, currentModel_, service_S { service }, { Spacer[ 0 ], - "Connect for model list", + tr[ "UIModelsNoList" ], Hold[ display = simpleModelMenuDisplay[ service, ProgressIndicator[ Appearance -> "Percolate" ] ]; makeServiceModelMenu[ @@ -1078,8 +1064,9 @@ menuModelGroup // endDefinition; (* ::Subsubsection::Closed:: *) (*modelGroupName*) modelGroupName // beginDefinition; -modelGroupName[ KeyValuePattern[ "FineTuned" -> True ] ] := "Fine Tuned Models"; -modelGroupName[ KeyValuePattern[ "Snapshot" -> True ] ] := "Snapshot Models"; +modelGroupName[ KeyValuePattern[ "FineTuned" -> True ] ] := trRaw[ "UIModelsFineTuned" ]; +modelGroupName[ KeyValuePattern[ "Preview" -> True ] ] := trRaw[ "UIModelsPreview" ]; +modelGroupName[ KeyValuePattern[ "Snapshot" -> True ] ] := trRaw[ "UIModelsSnapshot" ]; modelGroupName[ _ ] := None; modelGroupName // endDefinition; @@ -1130,11 +1117,11 @@ setModel // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) -(*absoluteCurrentValue*) -SetFallthroughError[absoluteCurrentValue] +(*absoluteCurrentValueOrigin*) +SetFallthroughError[absoluteCurrentValueOrigin] -absoluteCurrentValue[cell_, {TaggingRules, "ChatNotebookSettings", key_}] := currentChatSettings[cell, key] -absoluteCurrentValue[cell_, keyPath_] := AbsoluteCurrentValue[cell, keyPath] +absoluteCurrentValueOrigin[cell_, {TaggingRules, "ChatNotebookSettings", key_}] := currentChatSettings[cell, key] +absoluteCurrentValueOrigin[cell_, keyPath_] := AbsoluteCurrentValue[cell, keyPath] (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) @@ -1157,7 +1144,7 @@ currentValueOrigin[ value, inlineValue }, - value = absoluteCurrentValue[targetObj, keyPath]; + value = absoluteCurrentValueOrigin[targetObj, keyPath]; (* This was causing dynamics to update on every keystroke, so it's disabled for now: *) (* inlineValue = nestedLookup[ @@ -1265,12 +1252,24 @@ styleListItem[ (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) (*personaDisplayName*) -SetFallthroughError[personaDisplayName] +personaDisplayName // beginDefinition; + +personaDisplayName[ name_String ] := + personaDisplayName[ name, GetCachedPersonaData @ name ]; + +personaDisplayName[ name_String, data_Association ] := + personaDisplayName[ name, data[ "DisplayName" ] ]; + +personaDisplayName[ name_String, Dynamic @ FEPrivate`FrontEndResource[ "ChatbookStrings", id_ ] ] /; $CloudEvaluation := + tr @ id; + +personaDisplayName[ name_String, displayName: Except[ $$unspecified ] ] := + displayName; + +personaDisplayName[ name_String, _ ] := + name; -personaDisplayName[name_String] := personaDisplayName[name, GetCachedPersonaData[name]] -personaDisplayName[name_String, data_Association] := personaDisplayName[name, data["DisplayName"]] -personaDisplayName[name_String, displayName_String] := displayName -personaDisplayName[name_String, _] := name +personaDisplayName // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Subsubsection::Closed:: *) @@ -1358,8 +1357,8 @@ nestedLookup[as_, keys_] := nestedLookup[as, keys, Missing["KeySequenceAbsent", (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, - Null; +addToMXInitialization[ + Null ]; (* :!CodeAnalysis::EndBlock:: *) diff --git a/Source/Chatbook/Utils.wl b/Source/Chatbook/Utils.wl index 1e768742..5436c386 100644 --- a/Source/Chatbook/Utils.wl +++ b/Source/Chatbook/Utils.wl @@ -1,35 +1,10 @@ (* ::Section::Closed:: *) (*Package Header*) BeginPackage[ "Wolfram`Chatbook`Utils`" ]; - -HoldComplete[ - `$tinyHashLength; - `associationKeyDeflatten; - `clickToCopy; - `contextBlock; - `convertUTF8; - `exportDataURI; - `fastFileHash; - `fileFormatQ; - `fixLineEndings; - `formatToMIMEType; - `getPinkBoxErrors; - `graphicsQ; - `image2DQ; - `importDataURI; - `makeFailureString; - `mimeTypeToFormat; - `readString; - `stringTrimMiddle; - `tinyHash; - `validGraphicsQ; -]; - Begin[ "`Private`" ]; -Needs[ "Wolfram`Chatbook`" ]; -Needs[ "Wolfram`Chatbook`Common`" ]; -Needs[ "Wolfram`Chatbook`FrontEnd`" ]; +Needs[ "Wolfram`Chatbook`" ]; +Needs[ "Wolfram`Chatbook`Common`" ]; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) @@ -49,6 +24,18 @@ importResourceFunction[ associationKeyDeflatten, "AssociationKeyDeflatten" ]; (* https://resources.wolframcloud.com/FunctionRepository/resources/ClickToCopy *) importResourceFunction[ clickToCopy, "ClickToCopy" ]; +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*RelativeTimeString*) +(* https://resources.wolframcloud.com/FunctionRepository/resources/RelativeTimeString *) +importResourceFunction[ relativeTimeString, "RelativeTimeString" ]; + +(* ::**************************************************************************************************************:: *) +(* ::Section::Closed:: *) +(*SelectByCurrentValue*) +(* https://resources.wolframcloud.com/FunctionRepository/resources/SelectByCurrentValue *) +importResourceFunction[ selectByCurrentValue, "SelectByCurrentValue" ]; + (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Strings*) @@ -218,6 +205,9 @@ graphicsQ[ ___ ] := False; graphicsBoxQ[ _GraphicsBox|_Graphics3DBox ] := True; graphicsBoxQ[ $$graphicsBoxIgnoredHead[ box_, ___ ] ] := graphicsBoxQ @ Unevaluated @ box; graphicsBoxQ[ TemplateBox[ { box_, ___ }, $$graphicsBoxIgnoredTemplates, ___ ] ] := graphicsBoxQ @ Unevaluated @ box; +graphicsBoxQ[ RowBox[ boxes_List ] ] := AnyTrue[ boxes, graphicsBoxQ ]; +graphicsBoxQ[ TemplateBox[ boxes_List, "RowDefault", ___ ] ] := AnyTrue[ boxes, graphicsBoxQ ]; +graphicsBoxQ[ GridBox[ boxes_List, ___ ] ] := AnyTrue[ Flatten @ boxes, graphicsBoxQ ]; graphicsBoxQ[ ___ ] := False; (* ::**************************************************************************************************************:: *) @@ -390,7 +380,7 @@ exportDataURI[ data_, fmt_String ] := exportDataURI[ data_, fmt_String, mime_String ] := Enclose[ Module[ { base64 }, - base64 = ConfirmBy[ UsingFrontEnd @ ExportString[ data, { "Base64", fmt } ], StringQ, "Base64" ]; + base64 = ConfirmBy[ usingFrontEnd @ ExportString[ data, { "Base64", fmt } ], StringQ, "Base64" ]; "data:" <> mime <> ";base64," <> StringDelete[ base64, "\n" ] ], throwInternalFailure @@ -432,7 +422,7 @@ tinyHash // endDefinition; (* ::**************************************************************************************************************:: *) (* ::Section::Closed:: *) (*Package Footer*) -If[ Wolfram`ChatbookInternal`$BuildingMX, +addToMXInitialization[ Scan[ fileFormatQ, $fileFormats ]; ]; diff --git a/Source/Startup/Begin/BeginStartup.wl b/Source/Startup/Begin/BeginStartup.wl index 1b4b78ad..dc3d999d 100644 --- a/Source/Startup/Begin/BeginStartup.wl +++ b/Source/Startup/Begin/BeginStartup.wl @@ -3,6 +3,7 @@ loading code, which clears names in the Wolfram`Chatbook` context *) Wolfram`ChatbookStartupDump`$ContextInfo = {$Context, $ContextPath, $ContextAliases}; +Wolfram`ChatbookStartupDump`$versionString = TextString @ $VersionNumber <> "." <> TextString @ $ReleaseNumber; (*----------------------------------------*) (* Add File > New > Chat-Enabled Notebook *) @@ -14,41 +15,64 @@ Wolfram`ChatbookStartupDump`$ContextInfo = {$Context, $ContextPath, $ContextAlia In v13.3.1 and later, these menu commands are built-in to the FE's MenuSetup.tr global menus definitions. *) -If[!PacletNewerQ[ToString[$VersionNumber] <> "." <> ToString[$ReleaseNumber], "13.3.0"], +If[ ! PacletNewerQ[ Wolfram`ChatbookStartupDump`$versionString, "13.3.0" ], + Once[ + FrontEndExecute @ { + FrontEnd`AddMenuCommands[ + "New", + { + MenuItem[ + "Chat-Enabled Notebook", + FrontEnd`KernelExecute[ + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`CreateChatNotebook" ][ ] + ], + FrontEnd`MenuEvaluator -> Automatic, + FrontEnd`MenuKey[ "n", FrontEnd`Modifiers -> { FrontEnd`Command, FrontEnd`Option } ] + ] + } + ] + }, + "FrontEndSession" + ] +] + +(*--------------------------------*) +(* Adds Help > Code Assistance... *) +(*--------------------------------*) +(* Once code assistance is ready, this "14.1.0" can be changed to "14.0.0" to enable it for 14.1 users: *) +If[ PacletNewerQ[ Wolfram`ChatbookStartupDump`$versionString, "14.1.0" ], Once[ - FrontEndExecute[{ - FrontEnd`AddMenuCommands["New", { - MenuItem[ - "Chat-Enabled Notebook", - FrontEnd`KernelExecute[( - Needs["Wolfram`Chatbook`" -> None]; - Wolfram`Chatbook`CreateChatNotebook[] - )], - FrontEnd`MenuEvaluator -> Automatic, - FrontEnd`MenuKey["n", FrontEnd`Modifiers -> {FrontEnd`Command, FrontEnd`Option}] - ], - MenuItem[ - "Chat-Driven Notebook", - FrontEnd`KernelExecute[( - Needs["Wolfram`Chatbook`" -> None]; - Wolfram`Chatbook`CreateChatDrivenNotebook[] - )], - FrontEnd`MenuEvaluator -> Automatic - ] - }] - (* FIXME: figure out how to make this work: - FrontEnd`AddMenuCommands["Paclet Repository Item", { - MenuItem[ - "Prompt Repository Item", - FrontEnd`KernelExecute[{ - Needs["ResourceSystemClient`" -> None]; - ResourceSystemClient`CreateResourceNotebook["Prompt", "SuppressProgressBar" -> True] - }], - MenuEvaluator -> Automatic, - Method -> "Queued" - ] - }]*) - }], + FrontEndExecute @ { + FrontEnd`AddMenuCommands[ + "OpenHelpLink", + { + MenuItem[ + "Code Assistance Chat\[Ellipsis]", + FrontEnd`KernelExecute[ + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ShowCodeAssistance" ][ "Window" ] + ], + FrontEnd`MenuEvaluator -> Automatic, + Evaluate[ + If[ $OperatingSystem === "MacOSX", + FrontEnd`MenuKey[ "'", FrontEnd`Modifiers -> { FrontEnd`Control } ], + FrontEnd`MenuKey[ "'", FrontEnd`Modifiers -> { FrontEnd`Command } ] + ] + ] + ], + MenuItem[ + "Code Assistance for Selection", + FrontEnd`KernelExecute[ + Needs[ "Wolfram`Chatbook`" -> None ]; + Symbol[ "Wolfram`Chatbook`ShowCodeAssistance" ][ "Inline" ] + ], + FrontEnd`MenuEvaluator -> Automatic, + FrontEnd`MenuKey[ "'", FrontEnd`Modifiers -> { FrontEnd`Control, FrontEnd`Shift } ] + ] + } + ] + }, "FrontEndSession" ] ]