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%%
-