diff --git a/.gitignore b/.gitignore
index 0a97c9dd1..4ede4dca6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,8 @@ docs/prd/
docs/roadmap/
docs/gongzonghao/
docs/bussniss/
+docs/oem/
+
# Issues tracking (internal use only)
.issues/
@@ -63,3 +65,8 @@ openspec
# Build artifacts (alternate cargo target dirs)
src-tauri/target*/
+
+logo-lime.png
+
+lime.db
+
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 22d2e2a87..92d234e7f 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,8 +1,10 @@
-## Lime v0.89.0
+## Lime v0.89.1
### ✨ 主要更新
- **品牌正式更名为 Lime**:主程序名称、仓库链接、安装包命名、Tauri `productName` / `identifier`、深链 scheme、浏览器桥扩展目录与发布文案已统一从 `Proxycast` 切换到 `Lime`
+- **品牌图标与启动形象刷新**:应用图标、安装包图标、通知图标与启动页专用 Logo 已统一替换为新的青柠小龙虾主视觉,启动页继续保留独立图像资源
+- **ThemeWorkbench 侧边栏完成职责拆分**:上下文面板、工作流面板、执行日志与编排状态拆成独立构建模块,侧边栏主组件进一步收口
- **版本事实源继续收口**:统一 `package.json`、Cargo workspace / package、两份 Tauri 配置与 `RELEASE_NOTES.md` 的版本入口,发布流程继续只读取这一套版本源
- **运行时命名继续收口**:Tool Calling、Web Search、Durable Memory、workspace sandbox、真实测试与浏览器桥接等运行时环境变量统一以 `LIME_*` / `__LIME_*` 为现役事实源,旧 `PROXYCAST_*` 仅保留兼容读取
- **生态入口同步完成**:README、插件升级入口、About 页、扩展说明与下载地址等对外入口统一使用 `Lime`
@@ -28,4 +30,4 @@
---
-**完整变更**: v0.88.0...v0.89.0
+**完整变更**: v0.89.0...v0.89.1
diff --git a/lime-claw.png b/lime-claw.png
new file mode 100644
index 000000000..87daf40a1
Binary files /dev/null and b/lime-claw.png differ
diff --git a/package.json b/package.json
index 2f1f05a6e..dfda46a31 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "lime",
"private": true,
- "version": "0.89.0",
+ "version": "0.89.1",
"type": "module",
"engines": {
"node": ">=22.0.0"
diff --git a/public/icon.png b/public/icon.png
new file mode 100644
index 000000000..6c43e5485
Binary files /dev/null and b/public/icon.png differ
diff --git a/public/logo-splash.png b/public/logo-splash.png
index 032e89e46..110f754f7 100644
Binary files a/public/logo-splash.png and b/public/logo-splash.png differ
diff --git a/public/logo.png b/public/logo.png
index cf14b17a7..6c43e5485 100644
Binary files a/public/logo.png and b/public/logo.png differ
diff --git a/public/vite.svg b/public/vite.svg
deleted file mode 100644
index 6a4109910..000000000
--- a/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index 7c479fe15..8dcb69f64 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -5071,7 +5071,7 @@ dependencies = [
[[package]]
name = "lime"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"anyhow",
"arboard",
@@ -5174,7 +5174,7 @@ dependencies = [
[[package]]
name = "lime-agent"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"aster-core",
"async-trait",
@@ -5199,7 +5199,7 @@ dependencies = [
[[package]]
name = "lime-browser-runtime"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"chrono",
"futures",
@@ -5216,7 +5216,7 @@ dependencies = [
[[package]]
name = "lime-config"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"async-trait",
"lime-core",
@@ -5232,7 +5232,7 @@ dependencies = [
[[package]]
name = "lime-core"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"aster-models",
"async-trait",
@@ -5272,7 +5272,7 @@ dependencies = [
[[package]]
name = "lime-credential"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"axum 0.7.9",
"base64 0.22.1",
@@ -5307,7 +5307,7 @@ dependencies = [
[[package]]
name = "lime-gateway"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -5328,7 +5328,7 @@ dependencies = [
[[package]]
name = "lime-infra"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"chrono",
"dashmap 5.5.3",
@@ -5348,7 +5348,7 @@ dependencies = [
[[package]]
name = "lime-mcp"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"async-trait",
"dirs 5.0.1",
@@ -5380,7 +5380,7 @@ dependencies = [
[[package]]
name = "lime-processor"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"async-trait",
"lime-core",
@@ -5399,7 +5399,7 @@ dependencies = [
[[package]]
name = "lime-providers"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"anyhow",
"async-stream",
@@ -5453,7 +5453,7 @@ dependencies = [
[[package]]
name = "lime-server"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"aster-core",
"async-stream",
@@ -5498,7 +5498,7 @@ dependencies = [
[[package]]
name = "lime-server-utils"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"axum 0.7.9",
"futures",
@@ -5513,7 +5513,7 @@ dependencies = [
[[package]]
name = "lime-services"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"anyhow",
"aster-core",
@@ -5555,7 +5555,7 @@ dependencies = [
[[package]]
name = "lime-skills"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"async-trait",
"dirs 5.0.1",
@@ -5573,7 +5573,7 @@ dependencies = [
[[package]]
name = "lime-terminal"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"async-trait",
"base64 0.22.1",
@@ -5600,7 +5600,7 @@ dependencies = [
[[package]]
name = "lime-websocket"
-version = "0.89.0"
+version = "0.89.1"
dependencies = [
"axum 0.7.9",
"chrono",
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 150b761b4..38a040985 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -3,7 +3,7 @@ members = ["crates/*"]
resolver = "2"
[workspace.package]
-version = "0.89.0"
+version = "0.89.1"
edition = "2021"
authors = ["coso"]
repository = "https://github.com/aiclientproxy/lime"
@@ -191,7 +191,7 @@ version = "2.4"
[package]
name = "lime"
-version = "0.89.0"
+version = "0.89.1"
description = "AI API Proxy Desktop App"
authors = ["you"]
edition = "2021"
diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png
index 2a4faff18..498d870d8 100644
Binary files a/src-tauri/icons/128x128.png and b/src-tauri/icons/128x128.png differ
diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png
index bda5fda39..580f8c981 100644
Binary files a/src-tauri/icons/128x128@2x.png and b/src-tauri/icons/128x128@2x.png differ
diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png
index 0c8012a14..dfa273813 100644
Binary files a/src-tauri/icons/32x32.png and b/src-tauri/icons/32x32.png differ
diff --git a/src-tauri/icons/64x64.png b/src-tauri/icons/64x64.png
index 5efab6a5c..6712a979a 100644
Binary files a/src-tauri/icons/64x64.png and b/src-tauri/icons/64x64.png differ
diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png
index 0f695699a..64dea9199 100644
Binary files a/src-tauri/icons/Square107x107Logo.png and b/src-tauri/icons/Square107x107Logo.png differ
diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png
index 1e590689e..fbfff8631 100644
Binary files a/src-tauri/icons/Square142x142Logo.png and b/src-tauri/icons/Square142x142Logo.png differ
diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png
index bb51a844a..f7807486b 100644
Binary files a/src-tauri/icons/Square150x150Logo.png and b/src-tauri/icons/Square150x150Logo.png differ
diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png
index 7d3577aa1..cec981255 100644
Binary files a/src-tauri/icons/Square284x284Logo.png and b/src-tauri/icons/Square284x284Logo.png differ
diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png
index 2b132f254..cbc30fd3e 100644
Binary files a/src-tauri/icons/Square30x30Logo.png and b/src-tauri/icons/Square30x30Logo.png differ
diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png
index b6f5d9fd7..834149a0e 100644
Binary files a/src-tauri/icons/Square310x310Logo.png and b/src-tauri/icons/Square310x310Logo.png differ
diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png
index 5b64ef61d..c96583e69 100644
Binary files a/src-tauri/icons/Square44x44Logo.png and b/src-tauri/icons/Square44x44Logo.png differ
diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png
index 465b03cce..936fe3731 100644
Binary files a/src-tauri/icons/Square71x71Logo.png and b/src-tauri/icons/Square71x71Logo.png differ
diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png
index d5dc68250..a8ce35ebb 100644
Binary files a/src-tauri/icons/Square89x89Logo.png and b/src-tauri/icons/Square89x89Logo.png differ
diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png
index 724883cc2..b091cf9e0 100644
Binary files a/src-tauri/icons/StoreLogo.png and b/src-tauri/icons/StoreLogo.png differ
diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png
index 7e49dc8a3..509fbeaac 100644
Binary files a/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png and b/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png differ
diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png
index ff64b1920..772a368a0 100644
Binary files a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png and b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png
index 7e49dc8a3..fabf63f9c 100644
Binary files a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png and b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png
index e593a85b5..2b29a0813 100644
Binary files a/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png and b/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png differ
diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png
index 5422ba007..1a64f037f 100644
Binary files a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png and b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png
index e593a85b5..9ab9d814d 100644
Binary files a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png and b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png
index 64aa676b7..c56e8c9cd 100644
Binary files a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png and b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png
index ae74f98ba..26e81ff6b 100644
Binary files a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png and b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png
index 64aa676b7..1cdfe25f0 100644
Binary files a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png and b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png
index 785e9e508..a849f1a82 100644
Binary files a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png and b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png
index 54a5726ce..f9ee50fa4 100644
Binary files a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png and b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png
index 785e9e508..c07a03c90 100644
Binary files a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png and b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png
index 0e1bdc8e7..dd8f14253 100644
Binary files a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png and b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png
index e3527a3a5..38fc662f5 100644
Binary files a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png and b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png
index 0e1bdc8e7..7af18da65 100644
Binary files a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png and b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/src-tauri/icons/android/values/ic_launcher_background.xml b/src-tauri/icons/android/values/ic_launcher_background.xml
index ea9c223a6..c8472d041 100644
--- a/src-tauri/icons/android/values/ic_launcher_background.xml
+++ b/src-tauri/icons/android/values/ic_launcher_background.xml
@@ -1,4 +1,4 @@
- #fff
+ #f7f9d7
\ No newline at end of file
diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns
index 6dcb21619..952180eac 100644
Binary files a/src-tauri/icons/icon.icns and b/src-tauri/icons/icon.icns differ
diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico
index f3350d6d7..7ac0b62a3 100644
Binary files a/src-tauri/icons/icon.ico and b/src-tauri/icons/icon.ico differ
diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png
index cf14b17a7..103155d85 100644
Binary files a/src-tauri/icons/icon.png and b/src-tauri/icons/icon.png differ
diff --git a/src-tauri/icons/ios/AppIcon-20x20@1x.png b/src-tauri/icons/ios/AppIcon-20x20@1x.png
index 081427459..9d7357501 100644
Binary files a/src-tauri/icons/ios/AppIcon-20x20@1x.png and b/src-tauri/icons/ios/AppIcon-20x20@1x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/src-tauri/icons/ios/AppIcon-20x20@2x-1.png
index 38168805a..424873d0c 100644
Binary files a/src-tauri/icons/ios/AppIcon-20x20@2x-1.png and b/src-tauri/icons/ios/AppIcon-20x20@2x-1.png differ
diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x.png b/src-tauri/icons/ios/AppIcon-20x20@2x.png
index 38168805a..424873d0c 100644
Binary files a/src-tauri/icons/ios/AppIcon-20x20@2x.png and b/src-tauri/icons/ios/AppIcon-20x20@2x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-20x20@3x.png b/src-tauri/icons/ios/AppIcon-20x20@3x.png
index f85259367..87b56e23c 100644
Binary files a/src-tauri/icons/ios/AppIcon-20x20@3x.png and b/src-tauri/icons/ios/AppIcon-20x20@3x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-29x29@1x.png b/src-tauri/icons/ios/AppIcon-29x29@1x.png
index 861f6079d..0183beb9f 100644
Binary files a/src-tauri/icons/ios/AppIcon-29x29@1x.png and b/src-tauri/icons/ios/AppIcon-29x29@1x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/src-tauri/icons/ios/AppIcon-29x29@2x-1.png
index d4310dd0d..d74bdcf19 100644
Binary files a/src-tauri/icons/ios/AppIcon-29x29@2x-1.png and b/src-tauri/icons/ios/AppIcon-29x29@2x-1.png differ
diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x.png b/src-tauri/icons/ios/AppIcon-29x29@2x.png
index d4310dd0d..d74bdcf19 100644
Binary files a/src-tauri/icons/ios/AppIcon-29x29@2x.png and b/src-tauri/icons/ios/AppIcon-29x29@2x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-29x29@3x.png b/src-tauri/icons/ios/AppIcon-29x29@3x.png
index e10149d64..f79a4ed1f 100644
Binary files a/src-tauri/icons/ios/AppIcon-29x29@3x.png and b/src-tauri/icons/ios/AppIcon-29x29@3x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-40x40@1x.png b/src-tauri/icons/ios/AppIcon-40x40@1x.png
index 38168805a..424873d0c 100644
Binary files a/src-tauri/icons/ios/AppIcon-40x40@1x.png and b/src-tauri/icons/ios/AppIcon-40x40@1x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/src-tauri/icons/ios/AppIcon-40x40@2x-1.png
index a1332e36b..ffc4fd576 100644
Binary files a/src-tauri/icons/ios/AppIcon-40x40@2x-1.png and b/src-tauri/icons/ios/AppIcon-40x40@2x-1.png differ
diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x.png b/src-tauri/icons/ios/AppIcon-40x40@2x.png
index a1332e36b..ffc4fd576 100644
Binary files a/src-tauri/icons/ios/AppIcon-40x40@2x.png and b/src-tauri/icons/ios/AppIcon-40x40@2x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-40x40@3x.png b/src-tauri/icons/ios/AppIcon-40x40@3x.png
index 780605a51..a2abb123c 100644
Binary files a/src-tauri/icons/ios/AppIcon-40x40@3x.png and b/src-tauri/icons/ios/AppIcon-40x40@3x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-512@2x.png b/src-tauri/icons/ios/AppIcon-512@2x.png
index 044e5d72e..cb8aa7113 100644
Binary files a/src-tauri/icons/ios/AppIcon-512@2x.png and b/src-tauri/icons/ios/AppIcon-512@2x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-60x60@2x.png b/src-tauri/icons/ios/AppIcon-60x60@2x.png
index 780605a51..a2abb123c 100644
Binary files a/src-tauri/icons/ios/AppIcon-60x60@2x.png and b/src-tauri/icons/ios/AppIcon-60x60@2x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-60x60@3x.png b/src-tauri/icons/ios/AppIcon-60x60@3x.png
index 022defd24..4cff0a45c 100644
Binary files a/src-tauri/icons/ios/AppIcon-60x60@3x.png and b/src-tauri/icons/ios/AppIcon-60x60@3x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-76x76@1x.png b/src-tauri/icons/ios/AppIcon-76x76@1x.png
index b18b2d7bc..674fcc172 100644
Binary files a/src-tauri/icons/ios/AppIcon-76x76@1x.png and b/src-tauri/icons/ios/AppIcon-76x76@1x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-76x76@2x.png b/src-tauri/icons/ios/AppIcon-76x76@2x.png
index 15be3489d..a9cfa572b 100644
Binary files a/src-tauri/icons/ios/AppIcon-76x76@2x.png and b/src-tauri/icons/ios/AppIcon-76x76@2x.png differ
diff --git a/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
index fa51def78..7b36d76ec 100644
Binary files a/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png and b/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png differ
diff --git a/src-tauri/tauri.conf.headless.json b/src-tauri/tauri.conf.headless.json
index d1a31ebca..dbd2871c8 100644
--- a/src-tauri/tauri.conf.headless.json
+++ b/src-tauri/tauri.conf.headless.json
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lime",
- "version": "0.89.0",
+ "version": "0.89.1",
"identifier": "com.lime.app",
"build": {
"beforeDevCommand": "npm run dev:web-bridge",
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 5ccae1a73..ee89143b7 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lime",
- "version": "0.89.0",
+ "version": "0.89.1",
"identifier": "com.lime.app",
"build": {
"beforeDevCommand": "npm run dev",
diff --git a/src/components/agent/chat/components/ThemeWorkbenchSidebar.tsx b/src/components/agent/chat/components/ThemeWorkbenchSidebar.tsx
index 042cd5860..de11be735 100644
--- a/src/components/agent/chat/components/ThemeWorkbenchSidebar.tsx
+++ b/src/components/agent/chat/components/ThemeWorkbenchSidebar.tsx
@@ -1,186 +1,49 @@
-import React, {
- memo,
- type ReactNode,
- useMemo,
- useState,
-} from "react";
-import type { StepStatus } from "@/components/content-creator/types";
-import type { SkillDetailInfo } from "@/lib/api/skill-execution";
-import type { TopicBranchItem, TopicBranchStatus } from "../hooks/useTopicBranchBoard";
-import type { SidebarActivityLog } from "../hooks/useThemeContextWorkspace";
-import type { Message } from "../types";
-import type { AgentRun } from "@/lib/api/executionRun";
+import React, { memo, useState } from "react";
import {
ThemeWorkbenchSidebarShell,
type ThemeWorkbenchSidebarTab,
} from "./ThemeWorkbenchSidebarShell";
import { ThemeWorkbenchSidebarPanels } from "./ThemeWorkbenchSidebarPanels";
-import type {
- ThemeWorkbenchContextBudget,
- ThemeWorkbenchContextItem,
-} from "./themeWorkbenchContextData";
-import {
- parseThemeWorkbenchRunMetadataSummary,
- type ThemeWorkbenchCreationTaskEvent,
-} from "./themeWorkbenchWorkflowData";
-import { useThemeWorkbenchContextPanelState } from "./useThemeWorkbenchContextPanelState";
-import { useThemeWorkbenchArtifactActions } from "./useThemeWorkbenchArtifactActions";
-import { useThemeWorkbenchExecLogState } from "./useThemeWorkbenchExecLogState";
-import { useThemeWorkbenchSidebarTelemetry } from "./useThemeWorkbenchSidebarTelemetry";
-import { useThemeWorkbenchWorkflowPanelState } from "./useThemeWorkbenchWorkflowPanelState";
-import {
- formatThemeWorkbenchRunMetadata,
- writeThemeWorkbenchClipboardText,
-} from "./themeWorkbenchSidebarShared";
-
-type BranchMode = "topic" | "version";
-
-interface ThemeWorkbenchSidebarProps {
- branchMode?: BranchMode;
- onNewTopic: () => void;
- onSwitchTopic: (topicId: string) => void;
- onDeleteTopic: (topicId: string) => void;
- branchItems: TopicBranchItem[];
- onSetBranchStatus: (topicId: string, status: TopicBranchStatus) => void;
- workflowSteps: Array<{ id: string; title: string; status: StepStatus }>;
- contextSearchQuery: string;
- onContextSearchQueryChange: (value: string) => void;
- contextSearchMode: "web" | "social";
- onContextSearchModeChange: (value: "web" | "social") => void;
- contextSearchLoading: boolean;
- contextSearchError?: string | null;
- contextSearchBlockedReason?: string | null;
- onSubmitContextSearch: () => Promise | void;
- onAddTextContext?: (payload: {
- content: string;
- name?: string;
- }) => Promise | void;
- onAddLinkContext?: (payload: {
- url: string;
- name?: string;
- }) => Promise | void;
- onAddFileContext?: (payload: {
- path: string;
- name?: string;
- }) => Promise | void;
- onAddImage?: () => Promise | void;
- onImportDocument?: () => Promise | void;
- contextItems: ThemeWorkbenchContextItem[];
- onToggleContextActive: (contextId: string) => void;
- onViewContextDetail?: (contextId: string) => void;
- contextBudget: ThemeWorkbenchContextBudget;
- activityLogs: SidebarActivityLog[];
- creationTaskEvents?: ThemeWorkbenchCreationTaskEvent[];
- onViewRunDetail?: (runId: string) => void;
- activeRunDetail?: AgentRun | null;
- activeRunDetailLoading?: boolean;
- onRequestCollapse?: () => void;
- historyHasMore?: boolean;
- historyLoading?: boolean;
- onLoadMoreHistory?: () => void;
- skillDetailMap?: Record;
- headerActionSlot?: ReactNode;
- topSlot?: ReactNode;
- /** 完整的对话消息列表,用于执行日志 tab */
- messages?: Message[];
-}
+import { buildThemeWorkbenchSidebarOrchestrationSource } from "./buildThemeWorkbenchSidebarOrchestrationSource";
+import { createThemeWorkbenchSidebarOrchestrationInput } from "./themeWorkbenchSidebarOrchestrationContract";
+import { type ThemeWorkbenchSidebarProps } from "./themeWorkbenchSidebarContract";
+import { areThemeWorkbenchSidebarPropsEqual } from "./themeWorkbenchSidebarComparator";
+import { useThemeWorkbenchSidebarOrchestration } from "./useThemeWorkbenchSidebarOrchestration";
function ThemeWorkbenchSidebarComponent({
branchMode = "version",
- onNewTopic,
- onSwitchTopic,
- onDeleteTopic,
- branchItems,
- onSetBranchStatus,
- workflowSteps,
- contextSearchQuery,
- onContextSearchQueryChange,
- contextSearchMode,
- onContextSearchModeChange,
- contextSearchLoading,
- contextSearchError,
- contextSearchBlockedReason,
- onSubmitContextSearch,
- onAddTextContext,
- onAddLinkContext,
- onAddFileContext,
- onAddImage,
- onImportDocument,
- contextItems,
- onToggleContextActive,
- onViewContextDetail,
- contextBudget,
- activityLogs,
- creationTaskEvents = [],
- onViewRunDetail,
- activeRunDetail,
- activeRunDetailLoading = false,
onRequestCollapse,
- historyHasMore = false,
- historyLoading = false,
- onLoadMoreHistory,
- skillDetailMap = {},
headerActionSlot,
topSlot,
- messages = [],
+ ...props
}: ThemeWorkbenchSidebarProps) {
const [activeTab, setActiveTab] = useState("context");
const isVersionMode = branchMode === "version";
- const runMetadataText = useMemo(
- () => formatThemeWorkbenchRunMetadata(activeRunDetail?.metadata ?? null),
- [activeRunDetail?.metadata],
+ const orchestrationInput = createThemeWorkbenchSidebarOrchestrationInput(
+ buildThemeWorkbenchSidebarOrchestrationSource({
+ isVersionMode,
+ props,
+ }),
);
- const runMetadataSummary = useMemo(
- () => parseThemeWorkbenchRunMetadataSummary(activeRunDetail?.metadata ?? null),
- [activeRunDetail?.metadata],
- );
- const runDetailSessionId = activeRunDetail?.session_id?.trim() || null;
- const { handleRevealArtifactInFinder, handleOpenArtifactWithDefaultApp } =
- useThemeWorkbenchArtifactActions({
- runDetailSessionId,
- });
- const workflowPanelState = useThemeWorkbenchWorkflowPanelState({
- workflowSteps,
- activityLogs,
- creationTaskEvents,
- runMetadataSummary,
- });
- const contextPanelState = useThemeWorkbenchContextPanelState({
- contextItems,
- contextSearchQuery,
- contextSearchLoading,
- contextSearchBlockedReason,
- onAddTextContext,
- onAddLinkContext,
- onAddFileContext,
- });
-
- useThemeWorkbenchSidebarTelemetry({
+ const {
+ branchCount,
+ activeContextCount,
+ visibleExecLogCount,
+ contextPanelProps,
+ workflowPanelProps,
+ execLogProps,
+ } = useThemeWorkbenchSidebarOrchestration({
activeTab,
- showActivityLogs: workflowPanelState.showActivityLogs,
- contextSearchLoading,
- branchItemsCount: branchItems.length,
- workflowStepsCount: workflowSteps.length,
- contextItemsCount: contextItems.length,
- activeContextCount: contextPanelState.activeContextItems.length,
- activityLogsCount: activityLogs.length,
- creationTaskEventsCount: creationTaskEvents.length,
- hasActiveRunDetail: Boolean(activeRunDetail),
- });
- const execLogState = useThemeWorkbenchExecLogState({
- messages,
- groupedActivityLogs: workflowPanelState.groupedActivityLogs,
- groupedCreationTaskEvents: workflowPanelState.groupedCreationTaskEvents,
- skillDetailMap,
+ input: orchestrationInput,
});
return (
);
}
-function areThemeWorkbenchSidebarPropsEqual(
- previous: ThemeWorkbenchSidebarProps,
- next: ThemeWorkbenchSidebarProps,
-): boolean {
- return (
- previous.branchMode === next.branchMode &&
- previous.onNewTopic === next.onNewTopic &&
- previous.onSwitchTopic === next.onSwitchTopic &&
- previous.onDeleteTopic === next.onDeleteTopic &&
- previous.branchItems === next.branchItems &&
- previous.onSetBranchStatus === next.onSetBranchStatus &&
- previous.workflowSteps === next.workflowSteps &&
- previous.contextSearchQuery === next.contextSearchQuery &&
- previous.onContextSearchQueryChange === next.onContextSearchQueryChange &&
- previous.contextSearchMode === next.contextSearchMode &&
- previous.onContextSearchModeChange === next.onContextSearchModeChange &&
- previous.contextSearchLoading === next.contextSearchLoading &&
- previous.contextSearchError === next.contextSearchError &&
- previous.contextSearchBlockedReason === next.contextSearchBlockedReason &&
- previous.onSubmitContextSearch === next.onSubmitContextSearch &&
- previous.onAddTextContext === next.onAddTextContext &&
- previous.onAddLinkContext === next.onAddLinkContext &&
- previous.onAddFileContext === next.onAddFileContext &&
- previous.onAddImage === next.onAddImage &&
- previous.onImportDocument === next.onImportDocument &&
- previous.contextItems === next.contextItems &&
- previous.onToggleContextActive === next.onToggleContextActive &&
- previous.contextBudget.activeCount === next.contextBudget.activeCount &&
- previous.contextBudget.activeCountLimit === next.contextBudget.activeCountLimit &&
- previous.contextBudget.estimatedTokens === next.contextBudget.estimatedTokens &&
- previous.contextBudget.tokenLimit === next.contextBudget.tokenLimit &&
- previous.activityLogs === next.activityLogs &&
- previous.creationTaskEvents === next.creationTaskEvents &&
- previous.onViewRunDetail === next.onViewRunDetail &&
- previous.activeRunDetail === next.activeRunDetail &&
- previous.activeRunDetailLoading === next.activeRunDetailLoading &&
- previous.onRequestCollapse === next.onRequestCollapse &&
- previous.historyHasMore === next.historyHasMore &&
- previous.historyLoading === next.historyLoading &&
- previous.onLoadMoreHistory === next.onLoadMoreHistory &&
- previous.skillDetailMap === next.skillDetailMap &&
- previous.headerActionSlot === next.headerActionSlot &&
- previous.topSlot === next.topSlot &&
- previous.messages === next.messages
- );
-}
-
export const ThemeWorkbenchSidebar = memo(
ThemeWorkbenchSidebarComponent,
areThemeWorkbenchSidebarPropsEqual,
diff --git a/src/components/agent/chat/components/ThemeWorkbenchSidebarPanels.tsx b/src/components/agent/chat/components/ThemeWorkbenchSidebarPanels.tsx
index b7937bc9a..7b70782ce 100644
--- a/src/components/agent/chat/components/ThemeWorkbenchSidebarPanels.tsx
+++ b/src/components/agent/chat/components/ThemeWorkbenchSidebarPanels.tsx
@@ -1,170 +1,28 @@
-import type { ComponentProps } from "react";
-import type { AgentRun } from "@/lib/api/executionRun";
import { ThemeWorkbenchContextPanel } from "./ThemeWorkbenchContextPanel";
import { ThemeWorkbenchExecLog } from "./ThemeWorkbenchExecLog";
import { ThemeWorkbenchWorkflowPanel } from "./ThemeWorkbenchWorkflowPanel";
import type { ThemeWorkbenchSidebarTab } from "./ThemeWorkbenchSidebarShell";
-import type {
- ThemeWorkbenchContextBudget,
- ThemeWorkbenchContextItem,
-} from "./themeWorkbenchContextData";
-import type { ThemeWorkbenchRunMetadataSummary } from "./themeWorkbenchWorkflowData";
-import type { ThemeWorkbenchContextPanelState } from "./useThemeWorkbenchContextPanelState";
-import type { ThemeWorkbenchExecLogState } from "./useThemeWorkbenchExecLogState";
-import type { ThemeWorkbenchWorkflowPanelState } from "./useThemeWorkbenchWorkflowPanelState";
+import type { ThemeWorkbenchSidebarContentProps } from "./themeWorkbenchSidebarContentContract";
-interface ThemeWorkbenchSidebarPanelsProps {
+export interface ThemeWorkbenchSidebarPanelsProps
+ extends ThemeWorkbenchSidebarContentProps {
activeTab: ThemeWorkbenchSidebarTab;
- contextState: ThemeWorkbenchContextPanelState;
- contextConfig: {
- contextItems: ThemeWorkbenchContextItem[];
- contextBudget: ThemeWorkbenchContextBudget;
- contextSearchQuery: string;
- contextSearchMode: "web" | "social";
- contextSearchLoading: boolean;
- contextSearchError?: string | null;
- contextSearchBlockedReason?: string | null;
- onContextSearchQueryChange: (value: string) => void;
- onContextSearchModeChange: (value: "web" | "social") => void;
- onSubmitContextSearch: () => Promise | void;
- onToggleContextActive: (contextId: string) => void;
- onViewContextDetail?: (contextId: string) => void;
- };
- workflowState: ThemeWorkbenchWorkflowPanelState;
- workflowConfig: {
- isVersionMode: boolean;
- onNewTopic: () => void;
- onSwitchTopic: (topicId: string) => void;
- onDeleteTopic: (topicId: string) => void;
- branchItems: ComponentProps["branchItems"];
- onSetBranchStatus: ComponentProps<
- typeof ThemeWorkbenchWorkflowPanel
- >["onSetBranchStatus"];
- workflowSteps: ComponentProps["workflowSteps"];
- onAddImage?: () => Promise | void;
- onImportDocument?: () => Promise | void;
- creationTaskEventsCount: number;
- onViewRunDetail?: (runId: string) => void;
- activeRunDetail?: AgentRun | null;
- activeRunDetailLoading?: boolean;
- runMetadataText: string;
- runMetadataSummary: ThemeWorkbenchRunMetadataSummary;
- onCopyText: (text: string) => Promise | void;
- onRevealArtifactInFinder: (
- artifactPath: string,
- sessionId?: string | null,
- ) => Promise | void;
- onOpenArtifactWithDefaultApp: (
- artifactPath: string,
- sessionId?: string | null,
- ) => Promise | void;
- };
- execLogState: ThemeWorkbenchExecLogState;
- execLogConfig: {
- onLoadMoreHistory?: () => void;
- historyHasMore: boolean;
- historyLoading: boolean;
- };
}
export function ThemeWorkbenchSidebarPanels({
activeTab,
- contextState,
- contextConfig,
- workflowState,
- workflowConfig,
- execLogState,
- execLogConfig,
+ contextPanelProps,
+ workflowPanelProps,
+ execLogProps,
}: ThemeWorkbenchSidebarPanelsProps) {
if (activeTab === "context") {
- return (
-
- );
+ return ;
}
if (activeTab === "workflow") {
- return (
-
- );
+ return ;
}
if (activeTab === "log") {
- return (
-
- );
+ return ;
}
return null;
}
diff --git a/src/components/agent/chat/components/buildThemeWorkbenchContextPanelProps.ts b/src/components/agent/chat/components/buildThemeWorkbenchContextPanelProps.ts
new file mode 100644
index 000000000..6aee72547
--- /dev/null
+++ b/src/components/agent/chat/components/buildThemeWorkbenchContextPanelProps.ts
@@ -0,0 +1,75 @@
+import type { ThemeWorkbenchSidebarContextPanelProps } from "./themeWorkbenchSidebarContentContract";
+import type { ThemeWorkbenchContextPanelState } from "./useThemeWorkbenchContextPanelState";
+
+export interface BuildThemeWorkbenchContextPanelPropsParams {
+ contextPanelState: ThemeWorkbenchContextPanelState;
+ contextBudget: ThemeWorkbenchSidebarContextPanelProps["contextBudget"];
+ contextItems: ThemeWorkbenchSidebarContextPanelProps["contextItems"];
+ contextSearchBlockedReason?: ThemeWorkbenchSidebarContextPanelProps["contextSearchBlockedReason"];
+ contextSearchError?: ThemeWorkbenchSidebarContextPanelProps["contextSearchError"];
+ contextSearchLoading: ThemeWorkbenchSidebarContextPanelProps["contextSearchLoading"];
+ contextSearchMode: ThemeWorkbenchSidebarContextPanelProps["contextSearchMode"];
+ contextSearchQuery: ThemeWorkbenchSidebarContextPanelProps["contextSearchQuery"];
+ onContextSearchModeChange: ThemeWorkbenchSidebarContextPanelProps["onContextSearchModeChange"];
+ onContextSearchQueryChange: ThemeWorkbenchSidebarContextPanelProps["onContextSearchQueryChange"];
+ onSubmitContextSearch: ThemeWorkbenchSidebarContextPanelProps["onSubmitContextSearch"];
+ onToggleContextActive: ThemeWorkbenchSidebarContextPanelProps["onToggleContextActive"];
+ onViewContextDetail?: ThemeWorkbenchSidebarContextPanelProps["onViewContextDetail"];
+}
+
+export function buildThemeWorkbenchContextPanelProps({
+ contextBudget,
+ contextItems,
+ contextPanelState,
+ contextSearchBlockedReason,
+ contextSearchError,
+ contextSearchLoading,
+ contextSearchMode,
+ contextSearchQuery,
+ onContextSearchModeChange,
+ onContextSearchQueryChange,
+ onSubmitContextSearch,
+ onToggleContextActive,
+ onViewContextDetail,
+}: BuildThemeWorkbenchContextPanelPropsParams): ThemeWorkbenchSidebarContextPanelProps {
+ return {
+ contextItems,
+ searchContextItems: contextPanelState.searchContextItems,
+ orderedContextItems: contextPanelState.orderedContextItems,
+ selectedSearchResult: contextPanelState.selectedSearchResult,
+ latestSearchLabel: contextPanelState.latestSearchLabel,
+ contextBudget,
+ contextSearchQuery,
+ contextSearchMode,
+ contextSearchLoading,
+ contextSearchError,
+ contextSearchBlockedReason,
+ isSearchActionDisabled: contextPanelState.isSearchActionDisabled,
+ searchInputRef: contextPanelState.searchInputRef,
+ onContextSearchQueryChange,
+ onContextSearchModeChange,
+ onSubmitContextSearch,
+ onOpenAddContextDialog: contextPanelState.openAddContextDialog,
+ onSelectSearchResult: contextPanelState.handleSelectSearchResult,
+ onToggleContextActive,
+ onViewContextDetail,
+ addContextDialogOpen: contextPanelState.addContextDialogOpen,
+ addTextDialogOpen: contextPanelState.addTextDialogOpen,
+ addLinkDialogOpen: contextPanelState.addLinkDialogOpen,
+ contextDraftText: contextPanelState.contextDraftText,
+ contextDraftLink: contextPanelState.contextDraftLink,
+ contextCreateLoading: contextPanelState.contextCreateLoading,
+ contextCreateError: contextPanelState.contextCreateError,
+ contextDropActive: contextPanelState.contextDropActive,
+ onCloseAllContextDialogs: contextPanelState.closeAllContextDialogs,
+ onChooseContextFile: contextPanelState.handleChooseContextFile,
+ onDropContextFile: contextPanelState.handleDropContextFile,
+ onOpenTextContextDialog: contextPanelState.openTextContextDialog,
+ onOpenLinkContextDialog: contextPanelState.openLinkContextDialog,
+ onContextDraftTextChange: contextPanelState.handleContextDraftTextChange,
+ onContextDraftLinkChange: contextPanelState.handleContextDraftLinkChange,
+ onContextDropActiveChange: contextPanelState.handleContextDropActiveChange,
+ onSubmitTextContext: contextPanelState.handleSubmitTextContext,
+ onSubmitLinkContext: contextPanelState.handleSubmitLinkContext,
+ };
+}
diff --git a/src/components/agent/chat/components/buildThemeWorkbenchExecLogProps.ts b/src/components/agent/chat/components/buildThemeWorkbenchExecLogProps.ts
new file mode 100644
index 000000000..29431b51f
--- /dev/null
+++ b/src/components/agent/chat/components/buildThemeWorkbenchExecLogProps.ts
@@ -0,0 +1,26 @@
+import type { ThemeWorkbenchSidebarExecLogProps } from "./themeWorkbenchSidebarContentContract";
+import type { ThemeWorkbenchExecLogState } from "./useThemeWorkbenchExecLogState";
+
+export interface BuildThemeWorkbenchExecLogPropsParams {
+ execLogState: ThemeWorkbenchExecLogState;
+ historyHasMore?: ThemeWorkbenchSidebarExecLogProps["historyHasMore"];
+ historyLoading?: ThemeWorkbenchSidebarExecLogProps["historyLoading"];
+ onLoadMoreHistory?: ThemeWorkbenchSidebarExecLogProps["onLoadMoreHistory"];
+}
+
+export function buildThemeWorkbenchExecLogProps({
+ execLogState,
+ historyHasMore = false,
+ historyLoading = false,
+ onLoadMoreHistory,
+}: BuildThemeWorkbenchExecLogPropsParams): ThemeWorkbenchSidebarExecLogProps {
+ return {
+ entries: execLogState.visibleExecLogEntries,
+ totalEntriesCount: execLogState.execLogEntries.length,
+ wasCleared: execLogState.wasExecLogCleared,
+ onClear: execLogState.clearExecLog,
+ onLoadMoreHistory,
+ historyHasMore,
+ historyLoading,
+ };
+}
diff --git a/src/components/agent/chat/components/buildThemeWorkbenchSidebarOrchestrationSource.ts b/src/components/agent/chat/components/buildThemeWorkbenchSidebarOrchestrationSource.ts
new file mode 100644
index 000000000..db8cd03db
--- /dev/null
+++ b/src/components/agent/chat/components/buildThemeWorkbenchSidebarOrchestrationSource.ts
@@ -0,0 +1,64 @@
+import type {
+ ThemeWorkbenchSidebarContextContract,
+ ThemeWorkbenchSidebarExecLogContract,
+ ThemeWorkbenchSidebarWorkflowContract,
+} from "./themeWorkbenchSidebarContract";
+import type { ThemeWorkbenchSidebarOrchestrationSource } from "./themeWorkbenchSidebarOrchestrationContract";
+
+type ThemeWorkbenchSidebarOrchestrationSourceProps =
+ ThemeWorkbenchSidebarContextContract &
+ ThemeWorkbenchSidebarWorkflowContract &
+ ThemeWorkbenchSidebarExecLogContract;
+
+interface BuildThemeWorkbenchSidebarOrchestrationSourceParams {
+ isVersionMode: boolean;
+ props: ThemeWorkbenchSidebarOrchestrationSourceProps;
+}
+
+export function buildThemeWorkbenchSidebarOrchestrationSource({
+ isVersionMode,
+ props,
+}: BuildThemeWorkbenchSidebarOrchestrationSourceParams): ThemeWorkbenchSidebarOrchestrationSource {
+ return {
+ isVersionMode,
+ context: {
+ contextBudget: props.contextBudget,
+ contextItems: props.contextItems,
+ contextSearchBlockedReason: props.contextSearchBlockedReason,
+ contextSearchError: props.contextSearchError,
+ contextSearchLoading: props.contextSearchLoading,
+ contextSearchMode: props.contextSearchMode,
+ contextSearchQuery: props.contextSearchQuery,
+ onAddFileContext: props.onAddFileContext,
+ onAddLinkContext: props.onAddLinkContext,
+ onAddTextContext: props.onAddTextContext,
+ onContextSearchModeChange: props.onContextSearchModeChange,
+ onContextSearchQueryChange: props.onContextSearchQueryChange,
+ onSubmitContextSearch: props.onSubmitContextSearch,
+ onToggleContextActive: props.onToggleContextActive,
+ onViewContextDetail: props.onViewContextDetail,
+ },
+ workflow: {
+ activeRunDetail: props.activeRunDetail,
+ activeRunDetailLoading: props.activeRunDetailLoading,
+ activityLogs: props.activityLogs,
+ branchItems: props.branchItems,
+ creationTaskEvents: props.creationTaskEvents,
+ onAddImage: props.onAddImage,
+ onDeleteTopic: props.onDeleteTopic,
+ onImportDocument: props.onImportDocument,
+ onNewTopic: props.onNewTopic,
+ onSetBranchStatus: props.onSetBranchStatus,
+ onSwitchTopic: props.onSwitchTopic,
+ onViewRunDetail: props.onViewRunDetail,
+ workflowSteps: props.workflowSteps,
+ },
+ execLog: {
+ historyHasMore: props.historyHasMore,
+ historyLoading: props.historyLoading,
+ messages: props.messages,
+ onLoadMoreHistory: props.onLoadMoreHistory,
+ skillDetailMap: props.skillDetailMap,
+ },
+ };
+}
diff --git a/src/components/agent/chat/components/buildThemeWorkbenchWorkflowPanelProps.ts b/src/components/agent/chat/components/buildThemeWorkbenchWorkflowPanelProps.ts
new file mode 100644
index 000000000..9d94109e4
--- /dev/null
+++ b/src/components/agent/chat/components/buildThemeWorkbenchWorkflowPanelProps.ts
@@ -0,0 +1,77 @@
+import type { ThemeWorkbenchSidebarWorkflowPanelProps } from "./themeWorkbenchSidebarContentContract";
+import { writeThemeWorkbenchClipboardText } from "./themeWorkbenchSidebarShared";
+import type { ThemeWorkbenchWorkflowPanelState } from "./useThemeWorkbenchWorkflowPanelState";
+
+export interface BuildThemeWorkbenchWorkflowPanelPropsParams {
+ isVersionMode: ThemeWorkbenchSidebarWorkflowPanelProps["isVersionMode"];
+ activeRunDetail: ThemeWorkbenchSidebarWorkflowPanelProps["activeRunDetail"];
+ activeRunDetailLoading: ThemeWorkbenchSidebarWorkflowPanelProps["activeRunDetailLoading"];
+ branchItems: ThemeWorkbenchSidebarWorkflowPanelProps["branchItems"];
+ creationTaskEventsCount: ThemeWorkbenchSidebarWorkflowPanelProps["creationTaskEventsCount"];
+ onAddImage?: ThemeWorkbenchSidebarWorkflowPanelProps["onAddImage"];
+ onDeleteTopic: ThemeWorkbenchSidebarWorkflowPanelProps["onDeleteTopic"];
+ onImportDocument?: ThemeWorkbenchSidebarWorkflowPanelProps["onImportDocument"];
+ onNewTopic: ThemeWorkbenchSidebarWorkflowPanelProps["onNewTopic"];
+ onOpenArtifactWithDefaultApp: (
+ artifactPath: string,
+ sessionId?: string | null,
+ ) => Promise | void;
+ onRevealArtifactInFinder: (
+ artifactPath: string,
+ sessionId?: string | null,
+ ) => Promise | void;
+ onSetBranchStatus: ThemeWorkbenchSidebarWorkflowPanelProps["onSetBranchStatus"];
+ onSwitchTopic: ThemeWorkbenchSidebarWorkflowPanelProps["onSwitchTopic"];
+ onViewRunDetail?: ThemeWorkbenchSidebarWorkflowPanelProps["onViewRunDetail"];
+ workflowPanelState: ThemeWorkbenchWorkflowPanelState;
+ workflowSteps: ThemeWorkbenchSidebarWorkflowPanelProps["workflowSteps"];
+}
+
+export function buildThemeWorkbenchWorkflowPanelProps({
+ isVersionMode,
+ branchItems,
+ creationTaskEventsCount,
+ onAddImage,
+ onDeleteTopic,
+ onImportDocument,
+ onNewTopic,
+ onOpenArtifactWithDefaultApp,
+ onRevealArtifactInFinder,
+ onSetBranchStatus,
+ onSwitchTopic,
+ onViewRunDetail,
+ workflowPanelState,
+ workflowSteps,
+ activeRunDetail,
+ activeRunDetailLoading,
+}: BuildThemeWorkbenchWorkflowPanelPropsParams): ThemeWorkbenchSidebarWorkflowPanelProps {
+ return {
+ isVersionMode,
+ onNewTopic,
+ onSwitchTopic,
+ onDeleteTopic,
+ branchItems,
+ onSetBranchStatus,
+ workflowSteps,
+ completedSteps: workflowPanelState.completedSteps,
+ progressPercent: workflowPanelState.progressPercent,
+ onAddImage,
+ onImportDocument,
+ creationTaskEventsCount,
+ showCreationTasks: workflowPanelState.showCreationTasks,
+ onToggleCreationTasks: workflowPanelState.toggleCreationTasks,
+ groupedCreationTaskEvents: workflowPanelState.groupedCreationTaskEvents,
+ showActivityLogs: workflowPanelState.showActivityLogs,
+ onToggleActivityLogs: workflowPanelState.toggleActivityLogs,
+ groupedActivityLogs: workflowPanelState.groupedActivityLogs,
+ onViewRunDetail,
+ activeRunDetail,
+ activeRunDetailLoading,
+ activeRunStagesLabel: workflowPanelState.activeRunStagesLabel,
+ runMetadataText: workflowPanelState.runMetadataText,
+ runMetadataSummary: workflowPanelState.runMetadataSummary,
+ onCopyText: writeThemeWorkbenchClipboardText,
+ onRevealArtifactInFinder,
+ onOpenArtifactWithDefaultApp,
+ };
+}
diff --git a/src/components/agent/chat/components/themeWorkbenchSidebarComparator.ts b/src/components/agent/chat/components/themeWorkbenchSidebarComparator.ts
new file mode 100644
index 000000000..e92f78bdb
--- /dev/null
+++ b/src/components/agent/chat/components/themeWorkbenchSidebarComparator.ts
@@ -0,0 +1,103 @@
+import type {
+ ThemeWorkbenchSidebarContextContract,
+ ThemeWorkbenchSidebarExecLogContract,
+ ThemeWorkbenchSidebarProps,
+ ThemeWorkbenchSidebarShellContract,
+ ThemeWorkbenchSidebarWorkflowContract,
+} from "./themeWorkbenchSidebarContract";
+
+function areThemeWorkbenchContextBudgetsEqual(
+ previous: ThemeWorkbenchSidebarProps["contextBudget"],
+ next: ThemeWorkbenchSidebarProps["contextBudget"],
+): boolean {
+ return (
+ previous.activeCount === next.activeCount &&
+ previous.activeCountLimit === next.activeCountLimit &&
+ previous.estimatedTokens === next.estimatedTokens &&
+ previous.tokenLimit === next.tokenLimit
+ );
+}
+
+function areThemeWorkbenchSidebarShellPropsEqual(
+ previous: ThemeWorkbenchSidebarShellContract,
+ next: ThemeWorkbenchSidebarShellContract,
+): boolean {
+ return (
+ previous.branchMode === next.branchMode &&
+ previous.onRequestCollapse === next.onRequestCollapse &&
+ previous.headerActionSlot === next.headerActionSlot &&
+ previous.topSlot === next.topSlot
+ );
+}
+
+function areThemeWorkbenchSidebarContextPropsEqual(
+ previous: ThemeWorkbenchSidebarContextContract,
+ next: ThemeWorkbenchSidebarContextContract,
+): boolean {
+ return (
+ previous.contextSearchQuery === next.contextSearchQuery &&
+ previous.onContextSearchQueryChange === next.onContextSearchQueryChange &&
+ previous.contextSearchMode === next.contextSearchMode &&
+ previous.onContextSearchModeChange === next.onContextSearchModeChange &&
+ previous.contextSearchLoading === next.contextSearchLoading &&
+ previous.contextSearchError === next.contextSearchError &&
+ previous.contextSearchBlockedReason === next.contextSearchBlockedReason &&
+ previous.onSubmitContextSearch === next.onSubmitContextSearch &&
+ previous.onAddTextContext === next.onAddTextContext &&
+ previous.onAddLinkContext === next.onAddLinkContext &&
+ previous.onAddFileContext === next.onAddFileContext &&
+ previous.contextItems === next.contextItems &&
+ previous.onToggleContextActive === next.onToggleContextActive &&
+ previous.onViewContextDetail === next.onViewContextDetail &&
+ areThemeWorkbenchContextBudgetsEqual(
+ previous.contextBudget,
+ next.contextBudget,
+ )
+ );
+}
+
+function areThemeWorkbenchSidebarWorkflowPropsEqual(
+ previous: ThemeWorkbenchSidebarWorkflowContract,
+ next: ThemeWorkbenchSidebarWorkflowContract,
+): boolean {
+ return (
+ previous.onNewTopic === next.onNewTopic &&
+ previous.onSwitchTopic === next.onSwitchTopic &&
+ previous.onDeleteTopic === next.onDeleteTopic &&
+ previous.branchItems === next.branchItems &&
+ previous.onSetBranchStatus === next.onSetBranchStatus &&
+ previous.workflowSteps === next.workflowSteps &&
+ previous.onAddImage === next.onAddImage &&
+ previous.onImportDocument === next.onImportDocument &&
+ previous.activityLogs === next.activityLogs &&
+ previous.creationTaskEvents === next.creationTaskEvents &&
+ previous.onViewRunDetail === next.onViewRunDetail &&
+ previous.activeRunDetail === next.activeRunDetail &&
+ previous.activeRunDetailLoading === next.activeRunDetailLoading
+ );
+}
+
+function areThemeWorkbenchSidebarExecLogPropsEqual(
+ previous: ThemeWorkbenchSidebarExecLogContract,
+ next: ThemeWorkbenchSidebarExecLogContract,
+): boolean {
+ return (
+ previous.historyHasMore === next.historyHasMore &&
+ previous.historyLoading === next.historyLoading &&
+ previous.onLoadMoreHistory === next.onLoadMoreHistory &&
+ previous.skillDetailMap === next.skillDetailMap &&
+ previous.messages === next.messages
+ );
+}
+
+export function areThemeWorkbenchSidebarPropsEqual(
+ previous: ThemeWorkbenchSidebarProps,
+ next: ThemeWorkbenchSidebarProps,
+): boolean {
+ return (
+ areThemeWorkbenchSidebarShellPropsEqual(previous, next) &&
+ areThemeWorkbenchSidebarContextPropsEqual(previous, next) &&
+ areThemeWorkbenchSidebarWorkflowPropsEqual(previous, next) &&
+ areThemeWorkbenchSidebarExecLogPropsEqual(previous, next)
+ );
+}
diff --git a/src/components/agent/chat/components/themeWorkbenchSidebarContentContract.ts b/src/components/agent/chat/components/themeWorkbenchSidebarContentContract.ts
new file mode 100644
index 000000000..31ddfd9d6
--- /dev/null
+++ b/src/components/agent/chat/components/themeWorkbenchSidebarContentContract.ts
@@ -0,0 +1,22 @@
+import type { ComponentProps } from "react";
+import { ThemeWorkbenchContextPanel } from "./ThemeWorkbenchContextPanel";
+import { ThemeWorkbenchExecLog } from "./ThemeWorkbenchExecLog";
+import { ThemeWorkbenchWorkflowPanel } from "./ThemeWorkbenchWorkflowPanel";
+
+export type ThemeWorkbenchSidebarContextPanelProps = ComponentProps<
+ typeof ThemeWorkbenchContextPanel
+>;
+
+export type ThemeWorkbenchSidebarWorkflowPanelProps = ComponentProps<
+ typeof ThemeWorkbenchWorkflowPanel
+>;
+
+export type ThemeWorkbenchSidebarExecLogProps = ComponentProps<
+ typeof ThemeWorkbenchExecLog
+>;
+
+export interface ThemeWorkbenchSidebarContentProps {
+ contextPanelProps: ThemeWorkbenchSidebarContextPanelProps;
+ workflowPanelProps: ThemeWorkbenchSidebarWorkflowPanelProps;
+ execLogProps: ThemeWorkbenchSidebarExecLogProps;
+}
diff --git a/src/components/agent/chat/components/themeWorkbenchSidebarContract.ts b/src/components/agent/chat/components/themeWorkbenchSidebarContract.ts
new file mode 100644
index 000000000..d15405a0c
--- /dev/null
+++ b/src/components/agent/chat/components/themeWorkbenchSidebarContract.ts
@@ -0,0 +1,77 @@
+import type { ReactNode } from "react";
+import type { StepStatus } from "@/components/content-creator/types";
+import type { SkillDetailInfo } from "@/lib/api/skill-execution";
+import type { AgentRun } from "@/lib/api/executionRun";
+import type {
+ TopicBranchItem,
+ TopicBranchStatus,
+} from "../hooks/useTopicBranchBoard";
+import type { SidebarActivityLog } from "../hooks/useThemeContextWorkspace";
+import type { Message } from "../types";
+import type {
+ ThemeWorkbenchContextBudget,
+ ThemeWorkbenchContextItem,
+} from "./themeWorkbenchContextData";
+import type { ThemeWorkbenchCreationTaskEvent } from "./themeWorkbenchWorkflowData";
+import type {
+ ThemeWorkbenchAddFileContextAction,
+ ThemeWorkbenchAddLinkContextAction,
+ ThemeWorkbenchAddTextContextAction,
+} from "./useThemeWorkbenchContextPanelState";
+
+export type BranchMode = "topic" | "version";
+
+export interface ThemeWorkbenchSidebarShellContract {
+ branchMode?: BranchMode;
+ onRequestCollapse?: () => void;
+ headerActionSlot?: ReactNode;
+ topSlot?: ReactNode;
+}
+
+export interface ThemeWorkbenchSidebarWorkflowContract {
+ onNewTopic: () => void;
+ onSwitchTopic: (topicId: string) => void;
+ onDeleteTopic: (topicId: string) => void;
+ branchItems: TopicBranchItem[];
+ onSetBranchStatus: (topicId: string, status: TopicBranchStatus) => void;
+ workflowSteps: Array<{ id: string; title: string; status: StepStatus }>;
+ onAddImage?: () => Promise | void;
+ onImportDocument?: () => Promise | void;
+ activityLogs: SidebarActivityLog[];
+ creationTaskEvents?: ThemeWorkbenchCreationTaskEvent[];
+ onViewRunDetail?: (runId: string) => void;
+ activeRunDetail?: AgentRun | null;
+ activeRunDetailLoading?: boolean;
+}
+
+export interface ThemeWorkbenchSidebarContextContract {
+ contextSearchQuery: string;
+ onContextSearchQueryChange: (value: string) => void;
+ contextSearchMode: "web" | "social";
+ onContextSearchModeChange: (value: "web" | "social") => void;
+ contextSearchLoading: boolean;
+ contextSearchError?: string | null;
+ contextSearchBlockedReason?: string | null;
+ onSubmitContextSearch: () => Promise | void;
+ onAddTextContext?: ThemeWorkbenchAddTextContextAction;
+ onAddLinkContext?: ThemeWorkbenchAddLinkContextAction;
+ onAddFileContext?: ThemeWorkbenchAddFileContextAction;
+ contextItems: ThemeWorkbenchContextItem[];
+ onToggleContextActive: (contextId: string) => void;
+ onViewContextDetail?: (contextId: string) => void;
+ contextBudget: ThemeWorkbenchContextBudget;
+}
+
+export interface ThemeWorkbenchSidebarExecLogContract {
+ historyHasMore?: boolean;
+ historyLoading?: boolean;
+ onLoadMoreHistory?: () => void;
+ skillDetailMap?: Record;
+ messages?: Message[];
+}
+
+export interface ThemeWorkbenchSidebarProps
+ extends ThemeWorkbenchSidebarShellContract,
+ ThemeWorkbenchSidebarWorkflowContract,
+ ThemeWorkbenchSidebarContextContract,
+ ThemeWorkbenchSidebarExecLogContract {}
diff --git a/src/components/agent/chat/components/themeWorkbenchSidebarOrchestrationContract.ts b/src/components/agent/chat/components/themeWorkbenchSidebarOrchestrationContract.ts
new file mode 100644
index 000000000..6f15976ed
--- /dev/null
+++ b/src/components/agent/chat/components/themeWorkbenchSidebarOrchestrationContract.ts
@@ -0,0 +1,102 @@
+import type { SkillDetailInfo } from "@/lib/api/skill-execution";
+import type { SidebarActivityLog } from "../hooks/useThemeContextWorkspace";
+import type { Message } from "../types";
+import type { BuildThemeWorkbenchContextPanelPropsParams } from "./buildThemeWorkbenchContextPanelProps";
+import type { BuildThemeWorkbenchExecLogPropsParams } from "./buildThemeWorkbenchExecLogProps";
+import type { BuildThemeWorkbenchWorkflowPanelPropsParams } from "./buildThemeWorkbenchWorkflowPanelProps";
+import type { ThemeWorkbenchCreationTaskEvent } from "./themeWorkbenchWorkflowData";
+import type {
+ ThemeWorkbenchAddFileContextAction,
+ ThemeWorkbenchAddLinkContextAction,
+ ThemeWorkbenchAddTextContextAction,
+} from "./useThemeWorkbenchContextPanelState";
+
+export interface ThemeWorkbenchSidebarContextOrchestrationInput
+ extends Omit {
+ onAddTextContext?: ThemeWorkbenchAddTextContextAction;
+ onAddLinkContext?: ThemeWorkbenchAddLinkContextAction;
+ onAddFileContext?: ThemeWorkbenchAddFileContextAction;
+}
+
+export interface ThemeWorkbenchSidebarWorkflowOrchestrationInput
+ extends Omit<
+ BuildThemeWorkbenchWorkflowPanelPropsParams,
+ | "creationTaskEventsCount"
+ | "isVersionMode"
+ | "onOpenArtifactWithDefaultApp"
+ | "onRevealArtifactInFinder"
+ | "workflowPanelState"
+ > {
+ activityLogs: SidebarActivityLog[];
+ creationTaskEvents: ThemeWorkbenchCreationTaskEvent[];
+}
+
+export interface ThemeWorkbenchSidebarExecLogOrchestrationInput
+ extends Omit {
+ messages: Message[];
+ skillDetailMap: Record;
+}
+
+export interface ThemeWorkbenchSidebarOrchestrationInput {
+ isVersionMode: boolean;
+ context: ThemeWorkbenchSidebarContextOrchestrationInput;
+ workflow: ThemeWorkbenchSidebarWorkflowOrchestrationInput;
+ execLog: ThemeWorkbenchSidebarExecLogOrchestrationInput;
+}
+
+export type ThemeWorkbenchSidebarContextOrchestrationSource =
+ ThemeWorkbenchSidebarContextOrchestrationInput;
+
+export interface ThemeWorkbenchSidebarWorkflowOrchestrationSource
+ extends Omit<
+ ThemeWorkbenchSidebarWorkflowOrchestrationInput,
+ "creationTaskEvents"
+ > {
+ creationTaskEvents?: ThemeWorkbenchCreationTaskEvent[];
+}
+
+export interface ThemeWorkbenchSidebarExecLogOrchestrationSource
+ extends Omit<
+ ThemeWorkbenchSidebarExecLogOrchestrationInput,
+ "messages" | "skillDetailMap"
+ > {
+ messages?: Message[];
+ skillDetailMap?: Record;
+}
+
+export interface ThemeWorkbenchSidebarOrchestrationSource {
+ isVersionMode: boolean;
+ context: ThemeWorkbenchSidebarContextOrchestrationSource;
+ workflow: ThemeWorkbenchSidebarWorkflowOrchestrationSource;
+ execLog: ThemeWorkbenchSidebarExecLogOrchestrationSource;
+}
+
+export function createThemeWorkbenchSidebarOrchestrationInput(
+ source: ThemeWorkbenchSidebarOrchestrationSource,
+): ThemeWorkbenchSidebarOrchestrationInput {
+ const { isVersionMode, context, workflow, execLog } = source;
+ const { creationTaskEvents = [], activeRunDetailLoading = false } = workflow;
+ const {
+ historyHasMore = false,
+ historyLoading = false,
+ messages = [],
+ skillDetailMap = {},
+ } = execLog;
+
+ return {
+ isVersionMode,
+ context,
+ workflow: {
+ ...workflow,
+ activeRunDetailLoading,
+ creationTaskEvents,
+ },
+ execLog: {
+ ...execLog,
+ historyHasMore,
+ historyLoading,
+ messages,
+ skillDetailMap,
+ },
+ };
+}
diff --git a/src/components/agent/chat/components/themeWorkbenchSidebarShared.ts b/src/components/agent/chat/components/themeWorkbenchSidebarShared.ts
index 209c82a27..c2df9b498 100644
--- a/src/components/agent/chat/components/themeWorkbenchSidebarShared.ts
+++ b/src/components/agent/chat/components/themeWorkbenchSidebarShared.ts
@@ -1,15 +1,3 @@
-export function formatThemeWorkbenchRunMetadata(raw: string | null): string {
- if (!raw || !raw.trim()) {
- return "-";
- }
- try {
- const parsed = JSON.parse(raw);
- return JSON.stringify(parsed, null, 2);
- } catch {
- return raw;
- }
-}
-
export function formatThemeWorkbenchActionErrorMessage(
prefix: string,
error: unknown,
diff --git a/src/components/agent/chat/components/themeWorkbenchWorkflowData.ts b/src/components/agent/chat/components/themeWorkbenchWorkflowData.ts
index a95268d13..885d53884 100644
--- a/src/components/agent/chat/components/themeWorkbenchWorkflowData.ts
+++ b/src/components/agent/chat/components/themeWorkbenchWorkflowData.ts
@@ -40,6 +40,18 @@ export interface ThemeWorkbenchRunMetadataSummary {
artifactPaths: string[];
}
+export function formatThemeWorkbenchRunMetadata(raw: string | null): string {
+ if (!raw || !raw.trim()) {
+ return "-";
+ }
+ try {
+ const parsed = JSON.parse(raw);
+ return JSON.stringify(parsed, null, 2);
+ } catch {
+ return raw;
+ }
+}
+
function normalizeArtifactPaths(raw?: string[]): string[] {
if (!Array.isArray(raw)) {
return [];
diff --git a/src/components/agent/chat/components/useThemeWorkbenchContextPanelState.ts b/src/components/agent/chat/components/useThemeWorkbenchContextPanelState.ts
index e03bac1f5..cabd21d1c 100644
--- a/src/components/agent/chat/components/useThemeWorkbenchContextPanelState.ts
+++ b/src/components/agent/chat/components/useThemeWorkbenchContextPanelState.ts
@@ -21,17 +21,17 @@ import {
resolveThemeWorkbenchFileNameFromPath,
} from "./themeWorkbenchSidebarShared";
-type AddTextContextHandler = (payload: {
+export type ThemeWorkbenchAddTextContextAction = (payload: {
content: string;
name?: string;
}) => Promise | void;
-type AddLinkContextHandler = (payload: {
+export type ThemeWorkbenchAddLinkContextAction = (payload: {
url: string;
name?: string;
}) => Promise | void;
-type AddFileContextHandler = (payload: {
+export type ThemeWorkbenchAddFileContextAction = (payload: {
path: string;
name?: string;
}) => Promise | void;
@@ -41,9 +41,9 @@ interface UseThemeWorkbenchContextPanelStateParams {
contextSearchQuery: string;
contextSearchLoading: boolean;
contextSearchBlockedReason?: string | null;
- onAddTextContext?: AddTextContextHandler;
- onAddLinkContext?: AddLinkContextHandler;
- onAddFileContext?: AddFileContextHandler;
+ onAddTextContext?: ThemeWorkbenchAddTextContextAction;
+ onAddLinkContext?: ThemeWorkbenchAddLinkContextAction;
+ onAddFileContext?: ThemeWorkbenchAddFileContextAction;
}
export interface ThemeWorkbenchContextPanelState {
diff --git a/src/components/agent/chat/components/useThemeWorkbenchSidebarOrchestration.ts b/src/components/agent/chat/components/useThemeWorkbenchSidebarOrchestration.ts
new file mode 100644
index 000000000..1ae7b114b
--- /dev/null
+++ b/src/components/agent/chat/components/useThemeWorkbenchSidebarOrchestration.ts
@@ -0,0 +1,122 @@
+import type { ThemeWorkbenchSidebarTab } from "./ThemeWorkbenchSidebarShell";
+import type { ThemeWorkbenchSidebarContentProps } from "./themeWorkbenchSidebarContentContract";
+import type { ThemeWorkbenchSidebarOrchestrationInput } from "./themeWorkbenchSidebarOrchestrationContract";
+import { buildThemeWorkbenchContextPanelProps } from "./buildThemeWorkbenchContextPanelProps";
+import { buildThemeWorkbenchExecLogProps } from "./buildThemeWorkbenchExecLogProps";
+import { buildThemeWorkbenchWorkflowPanelProps } from "./buildThemeWorkbenchWorkflowPanelProps";
+import { useThemeWorkbenchArtifactActions } from "./useThemeWorkbenchArtifactActions";
+import { useThemeWorkbenchContextPanelState } from "./useThemeWorkbenchContextPanelState";
+import { useThemeWorkbenchExecLogState } from "./useThemeWorkbenchExecLogState";
+import { useThemeWorkbenchSidebarTelemetry } from "./useThemeWorkbenchSidebarTelemetry";
+import { useThemeWorkbenchWorkflowPanelState } from "./useThemeWorkbenchWorkflowPanelState";
+
+interface UseThemeWorkbenchSidebarOrchestrationParams {
+ activeTab: ThemeWorkbenchSidebarTab;
+ input: ThemeWorkbenchSidebarOrchestrationInput;
+}
+
+export interface ThemeWorkbenchSidebarOrchestration {
+ branchCount: number;
+ isVersionMode: boolean;
+ activeContextCount: number;
+ visibleExecLogCount: number;
+ contextPanelProps: ThemeWorkbenchSidebarContentProps["contextPanelProps"];
+ workflowPanelProps: ThemeWorkbenchSidebarContentProps["workflowPanelProps"];
+ execLogProps: ThemeWorkbenchSidebarContentProps["execLogProps"];
+}
+
+export function useThemeWorkbenchSidebarOrchestration({
+ activeTab,
+ input,
+}: UseThemeWorkbenchSidebarOrchestrationParams): ThemeWorkbenchSidebarOrchestration {
+ const { isVersionMode, context, workflow, execLog } = input;
+ const branchCount = workflow.branchItems.length;
+ const runDetailSessionId = workflow.activeRunDetail?.session_id?.trim() || null;
+ const { handleRevealArtifactInFinder, handleOpenArtifactWithDefaultApp } =
+ useThemeWorkbenchArtifactActions({
+ runDetailSessionId,
+ });
+
+ const workflowPanelState = useThemeWorkbenchWorkflowPanelState({
+ workflowSteps: workflow.workflowSteps,
+ activityLogs: workflow.activityLogs,
+ creationTaskEvents: workflow.creationTaskEvents,
+ activeRunMetadata: workflow.activeRunDetail?.metadata ?? null,
+ });
+
+ const contextPanelState = useThemeWorkbenchContextPanelState({
+ contextItems: context.contextItems,
+ contextSearchQuery: context.contextSearchQuery,
+ contextSearchLoading: context.contextSearchLoading,
+ contextSearchBlockedReason: context.contextSearchBlockedReason,
+ onAddTextContext: context.onAddTextContext,
+ onAddLinkContext: context.onAddLinkContext,
+ onAddFileContext: context.onAddFileContext,
+ });
+
+ useThemeWorkbenchSidebarTelemetry({
+ activeTab,
+ showActivityLogs: workflowPanelState.showActivityLogs,
+ contextSearchLoading: context.contextSearchLoading,
+ branchItemsCount: branchCount,
+ workflowStepsCount: workflow.workflowSteps.length,
+ contextItemsCount: context.contextItems.length,
+ activeContextCount: contextPanelState.activeContextItems.length,
+ activityLogsCount: workflow.activityLogs.length,
+ creationTaskEventsCount: workflow.creationTaskEvents.length,
+ hasActiveRunDetail: Boolean(workflow.activeRunDetail),
+ });
+
+ const execLogState = useThemeWorkbenchExecLogState({
+ messages: execLog.messages,
+ groupedActivityLogs: workflowPanelState.groupedActivityLogs,
+ groupedCreationTaskEvents: workflowPanelState.groupedCreationTaskEvents,
+ skillDetailMap: execLog.skillDetailMap,
+ });
+
+ return {
+ branchCount,
+ isVersionMode,
+ activeContextCount: contextPanelState.activeContextItems.length,
+ visibleExecLogCount: execLogState.visibleExecLogEntries.length,
+ contextPanelProps: buildThemeWorkbenchContextPanelProps({
+ contextBudget: context.contextBudget,
+ contextItems: context.contextItems,
+ contextPanelState,
+ contextSearchBlockedReason: context.contextSearchBlockedReason,
+ contextSearchError: context.contextSearchError,
+ contextSearchLoading: context.contextSearchLoading,
+ contextSearchMode: context.contextSearchMode,
+ contextSearchQuery: context.contextSearchQuery,
+ onContextSearchModeChange: context.onContextSearchModeChange,
+ onContextSearchQueryChange: context.onContextSearchQueryChange,
+ onSubmitContextSearch: context.onSubmitContextSearch,
+ onToggleContextActive: context.onToggleContextActive,
+ onViewContextDetail: context.onViewContextDetail,
+ }),
+ workflowPanelProps: buildThemeWorkbenchWorkflowPanelProps({
+ isVersionMode,
+ branchItems: workflow.branchItems,
+ creationTaskEventsCount: workflow.creationTaskEvents.length,
+ onAddImage: workflow.onAddImage,
+ onDeleteTopic: workflow.onDeleteTopic,
+ onImportDocument: workflow.onImportDocument,
+ onNewTopic: workflow.onNewTopic,
+ onOpenArtifactWithDefaultApp: handleOpenArtifactWithDefaultApp,
+ onRevealArtifactInFinder: handleRevealArtifactInFinder,
+ onSetBranchStatus: workflow.onSetBranchStatus,
+ onSwitchTopic: workflow.onSwitchTopic,
+ onViewRunDetail: workflow.onViewRunDetail,
+ workflowPanelState,
+ workflowSteps: workflow.workflowSteps,
+ activeRunDetail: workflow.activeRunDetail,
+ activeRunDetailLoading: workflow.activeRunDetailLoading,
+ }),
+ execLogProps: buildThemeWorkbenchExecLogProps({
+ execLogState,
+ historyHasMore: execLog.historyHasMore,
+ historyLoading: execLog.historyLoading,
+ onLoadMoreHistory: execLog.onLoadMoreHistory,
+ }),
+ };
+}
diff --git a/src/components/agent/chat/components/useThemeWorkbenchWorkflowPanelState.ts b/src/components/agent/chat/components/useThemeWorkbenchWorkflowPanelState.ts
index e40a0d838..f2b5566da 100644
--- a/src/components/agent/chat/components/useThemeWorkbenchWorkflowPanelState.ts
+++ b/src/components/agent/chat/components/useThemeWorkbenchWorkflowPanelState.ts
@@ -4,7 +4,9 @@ import type { SidebarActivityLog } from "../hooks/useThemeContextWorkspace";
import {
buildThemeWorkbenchActivityLogGroups,
buildThemeWorkbenchCreationTaskGroups,
+ formatThemeWorkbenchRunMetadata,
formatThemeWorkbenchStagesLabel,
+ parseThemeWorkbenchRunMetadataSummary,
type ThemeWorkbenchCreationTaskEvent,
type ThemeWorkbenchRunMetadataSummary,
} from "./themeWorkbenchWorkflowData";
@@ -13,7 +15,7 @@ interface UseThemeWorkbenchWorkflowPanelStateParams {
workflowSteps: Array<{ id: string; title: string; status: StepStatus }>;
activityLogs: SidebarActivityLog[];
creationTaskEvents: ThemeWorkbenchCreationTaskEvent[];
- runMetadataSummary: ThemeWorkbenchRunMetadataSummary;
+ activeRunMetadata: string | null;
}
export interface ThemeWorkbenchWorkflowPanelState {
@@ -24,6 +26,8 @@ export interface ThemeWorkbenchWorkflowPanelState {
typeof buildThemeWorkbenchCreationTaskGroups
>;
activeRunStagesLabel: string | null;
+ runMetadataText: string;
+ runMetadataSummary: ThemeWorkbenchRunMetadataSummary;
showActivityLogs: boolean;
showCreationTasks: boolean;
toggleActivityLogs: () => void;
@@ -34,7 +38,7 @@ export function useThemeWorkbenchWorkflowPanelState({
workflowSteps,
activityLogs,
creationTaskEvents,
- runMetadataSummary,
+ activeRunMetadata,
}: UseThemeWorkbenchWorkflowPanelStateParams): ThemeWorkbenchWorkflowPanelState {
const [showActivityLogs, setShowActivityLogs] = useState(false);
const [showCreationTasks, setShowCreationTasks] = useState(true);
@@ -57,6 +61,16 @@ export function useThemeWorkbenchWorkflowPanelState({
[creationTaskEvents],
);
+ const runMetadataSummary = useMemo(
+ () => parseThemeWorkbenchRunMetadataSummary(activeRunMetadata),
+ [activeRunMetadata],
+ );
+
+ const runMetadataText = useMemo(
+ () => formatThemeWorkbenchRunMetadata(activeRunMetadata),
+ [activeRunMetadata],
+ );
+
const activeRunStagesLabel = useMemo(
() => formatThemeWorkbenchStagesLabel(runMetadataSummary.stages),
[runMetadataSummary.stages],
@@ -76,6 +90,8 @@ export function useThemeWorkbenchWorkflowPanelState({
groupedActivityLogs,
groupedCreationTaskEvents,
activeRunStagesLabel,
+ runMetadataText,
+ runMetadataSummary,
showActivityLogs,
showCreationTasks,
toggleActivityLogs,