@mazees/mark 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +29 -0
- package/README.md +209 -0
- package/bin/mark.js +27 -0
- package/out/renderer/assets/icon-DHo2CYph.svg +1 -0
- package/out/renderer/assets/index-G2fADWO-.js +4768 -0
- package/out/renderer/assets/index-f3mVse3c.css +1 -0
- package/out/renderer/assets/music-cover-CG4vi3kZ.png +0 -0
- package/out/renderer/assets/poppins-devanagari-400-normal-CJDn6rn8.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-400-normal-CqVvlrh5.woff +0 -0
- package/out/renderer/assets/poppins-devanagari-500-normal-BIdkeU1p.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-500-normal-DMPDjHtT.woff +0 -0
- package/out/renderer/assets/poppins-devanagari-600-normal-ClASKHrr.woff +0 -0
- package/out/renderer/assets/poppins-devanagari-600-normal-STEjXBNN.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-700-normal-O-jipLrW.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-700-normal-fHs-vx92.woff +0 -0
- package/out/renderer/assets/poppins-latin-400-normal-BOb3E3N0.woff +0 -0
- package/out/renderer/assets/poppins-latin-400-normal-cpxAROuN.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-500-normal-C8OXljZJ.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-500-normal-DGXqpDMm.woff +0 -0
- package/out/renderer/assets/poppins-latin-600-normal-BJdTmd5m.woff +0 -0
- package/out/renderer/assets/poppins-latin-600-normal-zEkxB9Mr.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-700-normal-BVuQR_eA.woff +0 -0
- package/out/renderer/assets/poppins-latin-700-normal-Qrb0O0WB.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-400-normal-DaBSavcJ.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-400-normal-by3JarPu.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-500-normal-CK-6C4Hw.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-500-normal-CgAe2rWW.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-600-normal-CAhIAdZj.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-600-normal-Df5ffKXP.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-700-normal-DctTR6Tg.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-700-normal-cby-RkWa.woff2 +0 -0
- package/out/renderer/favicon.ico +0 -0
- package/out/renderer/icon-256.png +0 -0
- package/out/renderer/icon.svg +1 -0
- package/out/renderer/index.html +25 -0
- package/out/renderer/manifest.json +25 -0
- package/out/renderer/robot-simulator.html +1640 -0
- package/package.json +106 -0
- package/src/cli/index.js +332 -0
- package/src/cli/monitor.js +413 -0
- package/src/cli/theme.js +347 -0
- package/src/launcher/MarkTray.cs +227 -0
- package/src/main/browser-agent.js +1132 -0
- package/src/main/git-service.js +90 -0
- package/src/main/google/google-calendar.js +69 -0
- package/src/main/google/google-drive.js +263 -0
- package/src/main/google/google-gmail.js +131 -0
- package/src/main/google/google-service.js +241 -0
- package/src/main/node-tools.js +23 -0
- package/src/main/pc-agent-scripts/mouse-locker.ps1 +76 -0
- package/src/main/pc-agent-scripts/ocr-region.ps1 +185 -0
- package/src/main/pc-agent-scripts/pc-daemon.ps1 +726 -0
- package/src/main/pc-agent-scripts/pc-overlay.ps1 +253 -0
- package/src/main/pc-agent-scripts/pick-folder.ps1 +33 -0
- package/src/main/pc-agent-scripts/read-ui.ps1 +181 -0
- package/src/main/pc-agent-scripts/take-screenshot.ps1 +24 -0
- package/src/main/pc-agent-scripts/win-action.ps1 +380 -0
- package/src/main/plugins/plugin-loader.js +306 -0
- package/src/main/skills/skill-manager.js +265 -0
- package/src/main/syntax-validator.js +455 -0
- package/src/main/task-daemon.js +117 -0
- package/src/main/telegram/telegram-service.js +835 -0
- package/src/main/tools/browser-tools.js +516 -0
- package/src/main/tools/file-tools.js +1126 -0
- package/src/main/tools/git-tools.js +79 -0
- package/src/main/tools/google-tools.js +566 -0
- package/src/main/tools/index.js +36 -0
- package/src/main/tools/media-tools.js +42 -0
- package/src/main/tools/system-tools.js +295 -0
- package/src/main/tools/task-tools.js +73 -0
- package/src/main/tools/telegram-tools.js +101 -0
- package/src/renderer/index.html +24 -0
- package/src/renderer/public/favicon.ico +0 -0
- package/src/renderer/public/icon-256.png +0 -0
- package/src/renderer/public/icon.svg +1 -0
- package/src/renderer/public/manifest.json +25 -0
- package/src/renderer/public/robot-simulator.html +1640 -0
- package/src/renderer/src/App.jsx +304 -0
- package/src/renderer/src/api/ai/awareness.js +294 -0
- package/src/renderer/src/api/ai/chatSummarizer.js +79 -0
- package/src/renderer/src/api/ai/contextCompactor.js +129 -0
- package/src/renderer/src/api/ai/contextManager.js +1130 -0
- package/src/renderer/src/api/ai/core.js +167 -0
- package/src/renderer/src/api/ai/index.js +4 -0
- package/src/renderer/src/api/ai/memoryGroomer.js +101 -0
- package/src/renderer/src/api/ai/persona.js +115 -0
- package/src/renderer/src/api/ai/planning.js +317 -0
- package/src/renderer/src/api/ai/relationship.js +177 -0
- package/src/renderer/src/api/ai/skillSynthesizer.js +168 -0
- package/src/renderer/src/api/ai/tools.js +167 -0
- package/src/renderer/src/api/ai/utils.js +359 -0
- package/src/renderer/src/api/db.js +1013 -0
- package/src/renderer/src/api/oramaStore.js +592 -0
- package/src/renderer/src/api/ragPipeline.js +87 -0
- package/src/renderer/src/api/subagent/subagentExecutor.js +780 -0
- package/src/renderer/src/api/subagent/subagentPrompt.js +44 -0
- package/src/renderer/src/api/subagent/subagentStore.js +173 -0
- package/src/renderer/src/api/taskExecutor.js +18 -0
- package/src/renderer/src/api/taskStore.js +315 -0
- package/src/renderer/src/api/tools/core-tools.js +707 -0
- package/src/renderer/src/api/tools/index.js +151 -0
- package/src/renderer/src/api/turnPairMigrator.js +200 -0
- package/src/renderer/src/api/vectorMemory.js +136 -0
- package/src/renderer/src/api/wakeWord.js +101 -0
- package/src/renderer/src/api/web-bridge.js +885 -0
- package/src/renderer/src/api/webSpeech.js +178 -0
- package/src/renderer/src/api/workspaceRag.js +76 -0
- package/src/renderer/src/assets/electron.svg +10 -0
- package/src/renderer/src/assets/icon.svg +1 -0
- package/src/renderer/src/assets/main.css +589 -0
- package/src/renderer/src/assets/music-cover.png +0 -0
- package/src/renderer/src/assets/wavy-lines.svg +25 -0
- package/src/renderer/src/components/Chat/ApprovalBubble.jsx +127 -0
- package/src/renderer/src/components/Chat/CodeBlock.jsx +83 -0
- package/src/renderer/src/components/Chat/DurableTaskBubble.jsx +455 -0
- package/src/renderer/src/components/Chat/FileDiffModal.jsx +328 -0
- package/src/renderer/src/components/Chat/GeminiWidgets.jsx +82 -0
- package/src/renderer/src/components/Chat/MemoryFooterBubble.jsx +34 -0
- package/src/renderer/src/components/Chat/MessageBubble.jsx +459 -0
- package/src/renderer/src/components/Chat/PluginExecutionBubble.jsx +41 -0
- package/src/renderer/src/components/Chat/ThinkingBubble.jsx +316 -0
- package/src/renderer/src/components/Chat/YoutubeSearchBubble.jsx +43 -0
- package/src/renderer/src/components/Chat/YoutubeSummaryBubble.jsx +40 -0
- package/src/renderer/src/components/Chat/index.js +11 -0
- package/src/renderer/src/components/ChatList.jsx +434 -0
- package/src/renderer/src/components/GlobalCameraManager.jsx +67 -0
- package/src/renderer/src/components/Versions.jsx +15 -0
- package/src/renderer/src/components/YoutubeMusicPlayer.jsx +375 -0
- package/src/renderer/src/components/camera/CameraPreview.jsx +236 -0
- package/src/renderer/src/components/config/AiEngineSection.jsx +363 -0
- package/src/renderer/src/components/config/CameraSection.jsx +100 -0
- package/src/renderer/src/components/config/PermissionsSection.jsx +130 -0
- package/src/renderer/src/components/config/ShortcutSection.jsx +102 -0
- package/src/renderer/src/components/config/VoiceSection.jsx +110 -0
- package/src/renderer/src/components/config/index.js +5 -0
- package/src/renderer/src/components/core/Avatar.jsx +2197 -0
- package/src/renderer/src/components/core/ConfirmModal.jsx +80 -0
- package/src/renderer/src/components/core/DraggableHoloCard.jsx +125 -0
- package/src/renderer/src/components/core/FloatingMenu.jsx +272 -0
- package/src/renderer/src/components/core/HoloCard.jsx +64 -0
- package/src/renderer/src/components/core/InputBar.jsx +1346 -0
- package/src/renderer/src/components/core/ProcessPanel.jsx +216 -0
- package/src/renderer/src/components/core/ResponseArea.jsx +149 -0
- package/src/renderer/src/components/core/StatusIndicator.jsx +59 -0
- package/src/renderer/src/components/core/ThoughtNeuralFlow.jsx +168 -0
- package/src/renderer/src/components/core/ToolClustersDeck.jsx +210 -0
- package/src/renderer/src/components/core/native-skills.js +43 -0
- package/src/renderer/src/components/neural-core/EmotionalCortexLobe.jsx +359 -0
- package/src/renderer/src/components/neural-core/NodeDissectionModal.jsx +57 -0
- package/src/renderer/src/components/neural-core/ProceduralMatrixLobe.jsx +193 -0
- package/src/renderer/src/components/neural-core/ProceduralSkillModal.jsx +53 -0
- package/src/renderer/src/components/neural-core/ResetAiModal.jsx +198 -0
- package/src/renderer/src/components/neural-core/SynapticMemoryLobe.jsx +204 -0
- package/src/renderer/src/components/neural-core/traitMeta.js +102 -0
- package/src/renderer/src/components/subagent/AgentChatFeed.jsx +603 -0
- package/src/renderer/src/components/subagent/AgentInspector.jsx +224 -0
- package/src/renderer/src/components/subagent/AgentSidebar.jsx +216 -0
- package/src/renderer/src/components/subagent/SubagentIntercom.jsx +572 -0
- package/src/renderer/src/components/subagent/SubagentTopologyMap.jsx +423 -0
- package/src/renderer/src/contexts/ApprovalContext.jsx +425 -0
- package/src/renderer/src/contexts/ChatContext.jsx +61 -0
- package/src/renderer/src/contexts/YoutubeMusicContext.jsx +333 -0
- package/src/renderer/src/data/faqData.js +202 -0
- package/src/renderer/src/hooks/agent/executeAgentTool.js +895 -0
- package/src/renderer/src/hooks/agent/index.js +4 -0
- package/src/renderer/src/hooks/agent/useMarkMusic.js +75 -0
- package/src/renderer/src/hooks/agent/useMarkPlan.js +2739 -0
- package/src/renderer/src/hooks/agent/useMarkState.js +173 -0
- package/src/renderer/src/hooks/agent/useMarkYoutube.js +82 -0
- package/src/renderer/src/hooks/agent/useRelationalGrowth.js +201 -0
- package/src/renderer/src/hooks/telegram/useTelegramBot.js +63 -0
- package/src/renderer/src/hooks/useAwareness.js +289 -0
- package/src/renderer/src/hooks/useChatArchiver.js +52 -0
- package/src/renderer/src/hooks/useConfirm.jsx +68 -0
- package/src/renderer/src/hooks/useMarkAgent.js +454 -0
- package/src/renderer/src/hooks/useMemoryGroomer.js +152 -0
- package/src/renderer/src/hooks/useVAD.js +511 -0
- package/src/renderer/src/hooks/useWebSpeechWakeWord.js +122 -0
- package/src/renderer/src/main.jsx +12 -0
- package/src/renderer/src/pages/ChatStudio.jsx +922 -0
- package/src/renderer/src/pages/Configuration.jsx +360 -0
- package/src/renderer/src/pages/GoogleWorkspace.jsx +293 -0
- package/src/renderer/src/pages/Guidebook.jsx +917 -0
- package/src/renderer/src/pages/Knowledge.jsx +241 -0
- package/src/renderer/src/pages/MarkHome.jsx +491 -0
- package/src/renderer/src/pages/NeuralCore.jsx +786 -0
- package/src/renderer/src/pages/Plugins.jsx +630 -0
- package/src/renderer/src/pages/SkillEditor.jsx +380 -0
- package/src/renderer/src/pages/Skills.jsx +219 -0
- package/src/renderer/src/pages/Subagents.jsx +342 -0
- package/src/renderer/src/pages/TelegramBot.jsx +343 -0
- package/src/renderer/src/utils/chatContentParser.js +203 -0
- package/src/renderer/src/utils/toolClusters.js +201 -0
- package/src/server/bin/sha3_wasm_bg.wasm +0 -0
- package/src/server/config-manager.js +57 -0
- package/src/server/index.js +195 -0
- package/src/server/launcher.js +87 -0
- package/src/server/memory/db-store.js +758 -0
- package/src/server/memory/orama-store.js +177 -0
- package/src/server/memory/vector-engine.js +109 -0
- package/src/server/routes/ai.routes.js +280 -0
- package/src/server/routes/awareness.routes.js +62 -0
- package/src/server/routes/chat.routes.js +61 -0
- package/src/server/routes/config.routes.js +41 -0
- package/src/server/routes/index.js +35 -0
- package/src/server/routes/integrations.routes.js +116 -0
- package/src/server/routes/memory.routes.js +256 -0
- package/src/server/routes/plugins.routes.js +72 -0
- package/src/server/routes/skills.routes.js +139 -0
- package/src/server/routes/subagents.routes.js +70 -0
- package/src/server/routes/tasks.routes.js +175 -0
- package/src/server/routes/workspace.routes.js +127 -0
- package/src/server/services/ai/ai-utils.js +161 -0
- package/src/server/services/ai/openai-provider.js +757 -0
- package/src/server/services/ai/web-provider.js +729 -0
- package/src/server/services/ai-bridge.js +46 -0
- package/src/server/services/deepseek-web.js +956 -0
- package/src/server/services/gemini-web.js +170 -0
- package/src/server/services/notification-service.js +91 -0
- package/src/server/services/updater.js +125 -0
- package/src/server/tools/awareness-tracker.js +292 -0
- package/src/server/tools/group-tools.js +1164 -0
- package/src/server/tools/media-tools.js +244 -0
- package/src/server/tools/pc-agent.js +327 -0
- package/src/server/tools/screen-service.js +51 -0
- package/src/server/ws-hub.js +168 -0
- package/src/shared/parsers/mark-tag-parser.js +275 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef } from 'react'
|
|
2
|
+
import Markdown from 'react-markdown'
|
|
3
|
+
import remarkGfm from 'remark-gfm'
|
|
4
|
+
import { CodeBlock } from '../Chat/CodeBlock'
|
|
5
|
+
import { subagentStore } from '../../api/subagent/subagentStore'
|
|
6
|
+
import {
|
|
7
|
+
Bot,
|
|
8
|
+
Send,
|
|
9
|
+
Square,
|
|
10
|
+
Terminal,
|
|
11
|
+
Brain,
|
|
12
|
+
X,
|
|
13
|
+
Clock,
|
|
14
|
+
ArrowDown,
|
|
15
|
+
ChevronDown,
|
|
16
|
+
ChevronUp,
|
|
17
|
+
Loader2
|
|
18
|
+
} from 'lucide-react'
|
|
19
|
+
import { runSubagentTurn, killSubagentExecution } from '../../api/subagent/subagentExecutor'
|
|
20
|
+
import { useConfirm } from '../../hooks/useConfirm'
|
|
21
|
+
|
|
22
|
+
const markdownComponents = {
|
|
23
|
+
code({ node, inline, className, children, ...props }) {
|
|
24
|
+
const match = /language-(\w+)/.exec(className || '')
|
|
25
|
+
return !inline ? (
|
|
26
|
+
<CodeBlock match={match} children={children} />
|
|
27
|
+
) : (
|
|
28
|
+
<code
|
|
29
|
+
className="bg-base-300/90 text-accent font-mono text-[11px] px-1.5 py-0.5 rounded border border-base-content/10"
|
|
30
|
+
{...props}
|
|
31
|
+
>
|
|
32
|
+
{children}
|
|
33
|
+
</code>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Komponen Single Unified Bubble untuk Sub-Agent
|
|
39
|
+
function SubagentUnifiedBubble({ turn, subagentName, isRunning }) {
|
|
40
|
+
const [isThoughtOpen, setIsThoughtOpen] = useState(false)
|
|
41
|
+
const [isStepsOpen, setIsStepsOpen] = useState(false)
|
|
42
|
+
const [openStepIdx, setOpenStepIdx] = useState(null)
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="chat chat-start animate-fade-in">
|
|
46
|
+
<div className="chat-image avatar placeholder">
|
|
47
|
+
<div className="w-8 h-8 rounded-2xl text-[10px] font-bold shadow-md flex items-center justify-center bg-primary/20 text-primary border border-primary/30">
|
|
48
|
+
SUB
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<div className="chat-header text-[11px] opacity-50 mb-1 flex items-center gap-1.5">
|
|
52
|
+
<span>{subagentName}</span>
|
|
53
|
+
<span className="text-[10px]">
|
|
54
|
+
{new Date(turn.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
|
|
55
|
+
</span>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div className="chat-bubble bg-base-200/95 text-base-content border border-base-content/15 shadow-xl max-w-[88%] rounded-2xl p-4 space-y-3.5">
|
|
59
|
+
{/* 1. Dropdown Thought (Reasoning Analisis) */}
|
|
60
|
+
{turn.thoughts && turn.thoughts.length > 0 && (
|
|
61
|
+
<div className="bg-base-300/80 rounded-xl border border-base-content/10 overflow-hidden text-xs select-none shadow-sm">
|
|
62
|
+
<button
|
|
63
|
+
type="button"
|
|
64
|
+
onClick={() => setIsThoughtOpen(!isThoughtOpen)}
|
|
65
|
+
className="w-full px-3.5 py-2.5 flex items-center justify-between hover:bg-base-content/5 transition-colors text-left"
|
|
66
|
+
>
|
|
67
|
+
<div className="flex items-center gap-2 font-semibold text-accent text-[11px]">
|
|
68
|
+
<Brain className="w-3.5 h-3.5 shrink-0" />
|
|
69
|
+
<span>
|
|
70
|
+
Pemikiran Sub-Agent
|
|
71
|
+
</span>
|
|
72
|
+
</div>
|
|
73
|
+
<div className="flex items-center gap-1 text-[10px] text-base-content/50">
|
|
74
|
+
<span>{isThoughtOpen ? 'Tutup' : 'Lihat'}</span>
|
|
75
|
+
{isThoughtOpen ? (
|
|
76
|
+
<ChevronUp className="w-3 h-3" />
|
|
77
|
+
) : (
|
|
78
|
+
<ChevronDown className="w-3 h-3" />
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
</button>
|
|
82
|
+
{isThoughtOpen && (
|
|
83
|
+
<div className="p-3.5 bg-base-100/90 border-t border-base-content/10 space-y-2 text-[11px] text-base-content/90 whitespace-pre-wrap leading-relaxed">
|
|
84
|
+
<div className="border-l-2 border-accent pl-2.5 py-0.5">
|
|
85
|
+
{turn.thoughts[turn.thoughts.length - 1] || ''}
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
89
|
+
</div>
|
|
90
|
+
)}
|
|
91
|
+
|
|
92
|
+
{/* 2. Dropdown Langkah Eksekusi (Tools) */}
|
|
93
|
+
{turn.steps && turn.steps.length > 0 && (
|
|
94
|
+
<div className="bg-base-300/80 rounded-xl border border-base-content/10 overflow-hidden text-xs select-none shadow-sm">
|
|
95
|
+
<button
|
|
96
|
+
type="button"
|
|
97
|
+
onClick={() => setIsStepsOpen(!isStepsOpen)}
|
|
98
|
+
className="w-full px-3.5 py-2.5 flex items-center justify-between hover:bg-base-content/5 transition-colors text-left"
|
|
99
|
+
>
|
|
100
|
+
<div className="flex items-center gap-2 font-semibold text-warning text-[11px]">
|
|
101
|
+
<Terminal className="w-3.5 h-3.5 shrink-0" />
|
|
102
|
+
<span>Langkah Eksekusi ({turn.steps.length})</span>
|
|
103
|
+
</div>
|
|
104
|
+
<div className="flex items-center gap-1 text-[10px] text-base-content/50">
|
|
105
|
+
<span>{isStepsOpen ? 'Tutup' : 'Lihat'}</span>
|
|
106
|
+
{isStepsOpen ? (
|
|
107
|
+
<ChevronUp className="w-3 h-3" />
|
|
108
|
+
) : (
|
|
109
|
+
<ChevronDown className="w-3 h-3" />
|
|
110
|
+
)}
|
|
111
|
+
</div>
|
|
112
|
+
</button>
|
|
113
|
+
|
|
114
|
+
{isStepsOpen && (
|
|
115
|
+
<div className="p-3.5 bg-base-100/90 border-t border-base-content/10 space-y-2 font-mono text-[11px]">
|
|
116
|
+
{turn.steps.map((step, idx) => {
|
|
117
|
+
const isObsOpen = openStepIdx === idx
|
|
118
|
+
return (
|
|
119
|
+
<div
|
|
120
|
+
key={idx}
|
|
121
|
+
className="space-y-1 bg-base-200/50 p-2 rounded-lg border border-base-content/5"
|
|
122
|
+
>
|
|
123
|
+
<div
|
|
124
|
+
onClick={() => step.observation && setOpenStepIdx(isObsOpen ? null : idx)}
|
|
125
|
+
className={`flex items-start gap-1.5 py-0.5 ${step.observation ? 'cursor-pointer hover:text-primary transition-colors' : ''}`}
|
|
126
|
+
>
|
|
127
|
+
<span className="text-warning font-semibold shrink-0">{idx + 1}.</span>
|
|
128
|
+
<span className="text-primary font-semibold shrink-0">{step.tool}</span>
|
|
129
|
+
<span className="text-base-content/40 shrink-0">:</span>
|
|
130
|
+
<span
|
|
131
|
+
className={`text-base-content/90 break-all flex-1 ${isObsOpen ? '' : 'truncate'}`}
|
|
132
|
+
>
|
|
133
|
+
{step.query || ''}
|
|
134
|
+
</span>
|
|
135
|
+
{step.observation &&
|
|
136
|
+
(isObsOpen ? (
|
|
137
|
+
<ChevronUp className="w-3 h-3" />
|
|
138
|
+
) : (
|
|
139
|
+
<ChevronDown className="w-3 h-3" />
|
|
140
|
+
))}
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
{isObsOpen && step.observation && (
|
|
144
|
+
<div className="p-2.5 bg-black/40 rounded-lg text-base-content/80 whitespace-pre-wrap break-all text-[10px] max-h-44 overflow-y-auto mt-1 border border-base-content/10 font-mono">
|
|
145
|
+
{(typeof step.observation === 'string' ? step.observation : JSON.stringify(step.observation)).replace(/^\[OBSERVATION\]:\s*/, '')}
|
|
146
|
+
</div>
|
|
147
|
+
)}
|
|
148
|
+
</div>
|
|
149
|
+
)
|
|
150
|
+
})}
|
|
151
|
+
</div>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
)}
|
|
155
|
+
|
|
156
|
+
{/* 3. Final Content / Answer or Loading */}
|
|
157
|
+
{turn.answer ? (
|
|
158
|
+
<div className="prose prose-invert prose-sm max-w-none text-xs leading-relaxed font-normal pt-1 text-base-content/95">
|
|
159
|
+
<Markdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
|
|
160
|
+
{turn.answer
|
|
161
|
+
.replace(/^\[DARI LEAD AGENT \(MARK\)\]:\s*/, '')
|
|
162
|
+
.replace(/^\[DARI CREATOR \/ USER \(MADA\)\]:\s*/, '')}
|
|
163
|
+
</Markdown>
|
|
164
|
+
</div>
|
|
165
|
+
) : isRunning ? (
|
|
166
|
+
<div className="flex items-center gap-2 text-xs text-base-content/75 py-1 font-mono">
|
|
167
|
+
<Loader2 className="w-3.5 h-3.5 animate-spin text-primary shrink-0" />
|
|
168
|
+
<span className="text-[11px]">Memproses langkah...</span>
|
|
169
|
+
</div>
|
|
170
|
+
) : null}
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Helper untuk mengelompokkan pesan mentah menjadi satu bubble per giliran
|
|
177
|
+
function groupSubagentMessages(rawMessages) {
|
|
178
|
+
if (!Array.isArray(rawMessages)) return []
|
|
179
|
+
const grouped = []
|
|
180
|
+
let currentSubTurn = null
|
|
181
|
+
|
|
182
|
+
for (const msg of rawMessages) {
|
|
183
|
+
if (msg.sender === 'user' || msg.sender === 'mark') {
|
|
184
|
+
if (currentSubTurn) {
|
|
185
|
+
grouped.push(currentSubTurn)
|
|
186
|
+
currentSubTurn = null
|
|
187
|
+
}
|
|
188
|
+
grouped.push({
|
|
189
|
+
type: 'dialogue',
|
|
190
|
+
id: msg.id,
|
|
191
|
+
sender: msg.sender,
|
|
192
|
+
content: msg.content,
|
|
193
|
+
timestamp: msg.timestamp
|
|
194
|
+
})
|
|
195
|
+
} else if (msg.sender === 'subagent') {
|
|
196
|
+
let parsed = {}
|
|
197
|
+
try {
|
|
198
|
+
parsed = typeof msg.content === 'object' ? msg.content : JSON.parse(msg.content)
|
|
199
|
+
} catch (e) {
|
|
200
|
+
parsed = { answer: msg.content }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const thought = msg.thought || parsed.thought
|
|
204
|
+
const action = msg.action || parsed.action
|
|
205
|
+
const answer = parsed.answer || (action ? null : msg.content)
|
|
206
|
+
|
|
207
|
+
if (!currentSubTurn) {
|
|
208
|
+
currentSubTurn = {
|
|
209
|
+
type: 'subagent_turn',
|
|
210
|
+
id: msg.id,
|
|
211
|
+
sender: 'subagent',
|
|
212
|
+
timestamp: msg.timestamp,
|
|
213
|
+
thoughts: [],
|
|
214
|
+
steps: [],
|
|
215
|
+
answer: null
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (thought && !currentSubTurn.thoughts.includes(thought)) {
|
|
220
|
+
currentSubTurn.thoughts.push(thought)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (action) {
|
|
224
|
+
const acts = Array.isArray(action) ? action : [action]
|
|
225
|
+
acts.forEach((act) => {
|
|
226
|
+
if (act?.tool) {
|
|
227
|
+
currentSubTurn.steps.push({
|
|
228
|
+
tool: act.tool,
|
|
229
|
+
query: act.query || '',
|
|
230
|
+
observation: null
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (answer) {
|
|
237
|
+
currentSubTurn.answer = answer
|
|
238
|
+
}
|
|
239
|
+
} else if (msg.sender === 'tool') {
|
|
240
|
+
if (currentSubTurn && currentSubTurn.steps.length > 0) {
|
|
241
|
+
const lastStepWithoutObs = [...currentSubTurn.steps].reverse().find((s) => !s.observation)
|
|
242
|
+
if (lastStepWithoutObs) {
|
|
243
|
+
lastStepWithoutObs.observation = msg.content
|
|
244
|
+
} else {
|
|
245
|
+
currentSubTurn.steps[currentSubTurn.steps.length - 1].observation = msg.content
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
if (!currentSubTurn) {
|
|
249
|
+
currentSubTurn = {
|
|
250
|
+
type: 'subagent_turn',
|
|
251
|
+
id: msg.id,
|
|
252
|
+
sender: 'subagent',
|
|
253
|
+
timestamp: msg.timestamp,
|
|
254
|
+
thoughts: [],
|
|
255
|
+
steps: [{ tool: 'tool-execution', query: '', observation: msg.content }],
|
|
256
|
+
answer: null
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (currentSubTurn) {
|
|
264
|
+
grouped.push(currentSubTurn)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return grouped
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export default function SubagentIntercom({ subagentId, onClose }) {
|
|
271
|
+
const [subagent, setSubagent] = useState(null)
|
|
272
|
+
const [messages, setMessages] = useState([])
|
|
273
|
+
const [inputText, setInputText] = useState('')
|
|
274
|
+
const [isSending, setIsSending] = useState(false)
|
|
275
|
+
const [showScrollBottomBtn, setShowScrollBottomBtn] = useState(false)
|
|
276
|
+
|
|
277
|
+
const messagesEndRef = useRef(null)
|
|
278
|
+
const containerRef = useRef(null)
|
|
279
|
+
const isAutoScrollRef = useRef(true)
|
|
280
|
+
const prevMsgCountRef = useRef(0)
|
|
281
|
+
|
|
282
|
+
const loadData = async () => {
|
|
283
|
+
if (!subagentId) return
|
|
284
|
+
try {
|
|
285
|
+
const sub = await subagentStore.getSubagent(subagentId)
|
|
286
|
+
const msgs = await subagentStore.getMessages(subagentId)
|
|
287
|
+
setSubagent(sub)
|
|
288
|
+
setMessages(msgs || [])
|
|
289
|
+
} catch (err) {
|
|
290
|
+
console.error('[SubagentIntercom] Load error:', err)
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const scrollToBottom = (behavior = 'smooth') => {
|
|
295
|
+
if (messagesEndRef.current) {
|
|
296
|
+
messagesEndRef.current.scrollIntoView({ behavior })
|
|
297
|
+
isAutoScrollRef.current = true
|
|
298
|
+
setShowScrollBottomBtn(false)
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const handleScroll = () => {
|
|
303
|
+
if (!containerRef.current) return
|
|
304
|
+
const { scrollTop, scrollHeight, clientHeight } = containerRef.current
|
|
305
|
+
const isAtBottom = scrollHeight - scrollTop - clientHeight < 60
|
|
306
|
+
isAutoScrollRef.current = isAtBottom
|
|
307
|
+
setShowScrollBottomBtn(!isAtBottom)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Reset scroll dan muat data ketika subagentId berubah
|
|
311
|
+
useEffect(() => {
|
|
312
|
+
prevMsgCountRef.current = 0
|
|
313
|
+
isAutoScrollRef.current = true
|
|
314
|
+
setShowScrollBottomBtn(false)
|
|
315
|
+
loadData().then(() => {
|
|
316
|
+
setTimeout(() => scrollToBottom('auto'), 50)
|
|
317
|
+
})
|
|
318
|
+
const interval = setInterval(loadData, 1000)
|
|
319
|
+
return () => clearInterval(interval)
|
|
320
|
+
}, [subagentId])
|
|
321
|
+
|
|
322
|
+
// Hanya auto-scroll jika ada pesan baru DAN user sedang berada di posisi bawah
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
if (messages.length > prevMsgCountRef.current) {
|
|
325
|
+
if (isAutoScrollRef.current) {
|
|
326
|
+
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
|
|
327
|
+
}
|
|
328
|
+
prevMsgCountRef.current = messages.length
|
|
329
|
+
}
|
|
330
|
+
}, [messages.length])
|
|
331
|
+
|
|
332
|
+
const { confirm, ModalComponent } = useConfirm()
|
|
333
|
+
|
|
334
|
+
const handleSendMessage = async (e) => {
|
|
335
|
+
e?.preventDefault()
|
|
336
|
+
if (!inputText.trim() || isSending) return
|
|
337
|
+
|
|
338
|
+
const textToSend = inputText.trim()
|
|
339
|
+
setInputText('')
|
|
340
|
+
setIsSending(true)
|
|
341
|
+
isAutoScrollRef.current = true
|
|
342
|
+
setShowScrollBottomBtn(false)
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
await runSubagentTurn(subagentId, textToSend, 'user')
|
|
346
|
+
await loadData()
|
|
347
|
+
setTimeout(() => scrollToBottom('smooth'), 50)
|
|
348
|
+
} catch (err) {
|
|
349
|
+
console.error('[SubagentIntercom] Send error:', err)
|
|
350
|
+
} finally {
|
|
351
|
+
setIsSending(false)
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const handleKill = async () => {
|
|
356
|
+
const result = await confirm({
|
|
357
|
+
title: 'Hentikan Eksekusi Sub-Agent',
|
|
358
|
+
message: 'Apakah kamu yakin ingin menghentikan eksekusi sub-agent ini secara paksa?',
|
|
359
|
+
isError: true,
|
|
360
|
+
confirmText: 'Hentikan',
|
|
361
|
+
cancelText: 'Batal'
|
|
362
|
+
})
|
|
363
|
+
if (result?.isConfirmed) {
|
|
364
|
+
killSubagentExecution(subagentId)
|
|
365
|
+
loadData()
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (!subagent) return null
|
|
370
|
+
|
|
371
|
+
const isRunning = subagent.status === 'running'
|
|
372
|
+
const groupedTurns = groupSubagentMessages(messages)
|
|
373
|
+
|
|
374
|
+
return (
|
|
375
|
+
<div className="flex flex-col h-full bg-base-300/60 rounded-3xl overflow-hidden select-none border border-base-content/10 relative font-['Poppins',sans-serif]">
|
|
376
|
+
{/* Header Intercom */}
|
|
377
|
+
<div className="p-4 bg-base-200/90 backdrop-blur-md border-b border-base-content/10 flex items-center justify-between flex-none z-10">
|
|
378
|
+
<div className="flex items-center gap-3">
|
|
379
|
+
<div className="p-2.5 bg-primary/20 text-primary rounded-2xl shadow-inner border border-primary/20">
|
|
380
|
+
<Bot className="w-5 h-5" />
|
|
381
|
+
</div>
|
|
382
|
+
<div>
|
|
383
|
+
<div className="flex items-center gap-2">
|
|
384
|
+
<h3 className="font-bold text-sm tracking-wide">{subagent.name}</h3>
|
|
385
|
+
<span
|
|
386
|
+
className={`badge badge-xs font-semibold uppercase tracking-wider ${
|
|
387
|
+
isRunning
|
|
388
|
+
? 'badge-warning animate-pulse'
|
|
389
|
+
: subagent.status === 'idle'
|
|
390
|
+
? 'badge-info'
|
|
391
|
+
: subagent.status === 'failed'
|
|
392
|
+
? 'badge-error'
|
|
393
|
+
: 'badge-success'
|
|
394
|
+
}`}
|
|
395
|
+
>
|
|
396
|
+
{subagent.status}
|
|
397
|
+
</span>
|
|
398
|
+
<span className="text-[10px] text-base-content/40 font-mono">[{subagent.id}]</span>
|
|
399
|
+
</div>
|
|
400
|
+
<p className="text-xs text-base-content/60">{subagent.role}</p>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
|
|
404
|
+
{/* Action Controls */}
|
|
405
|
+
<div className="flex items-center gap-2">
|
|
406
|
+
{isRunning && (
|
|
407
|
+
<button
|
|
408
|
+
onClick={handleKill}
|
|
409
|
+
className="btn btn-error btn-xs btn-outline gap-1 rounded-xl"
|
|
410
|
+
title="Hentikan Paksa"
|
|
411
|
+
>
|
|
412
|
+
<Square className="w-3 h-3" /> Stop
|
|
413
|
+
</button>
|
|
414
|
+
)}
|
|
415
|
+
{onClose && (
|
|
416
|
+
<button
|
|
417
|
+
onClick={onClose}
|
|
418
|
+
className="btn btn-ghost btn-sm btn-circle text-base-content/60 hover:text-base-content hover:bg-base-content/10"
|
|
419
|
+
title="Tutup Panel"
|
|
420
|
+
>
|
|
421
|
+
<X className="w-4 h-4" />
|
|
422
|
+
</button>
|
|
423
|
+
)}
|
|
424
|
+
</div>
|
|
425
|
+
</div>
|
|
426
|
+
|
|
427
|
+
{/* Goal & Mission Info Strip */}
|
|
428
|
+
<div className="px-5 py-3 bg-base-200/40 border-b border-base-content/5 text-xs flex items-center justify-between gap-4 flex-none z-10">
|
|
429
|
+
<div className="flex items-center gap-2 truncate">
|
|
430
|
+
<span className="font-bold text-primary shrink-0 uppercase text-[10px] tracking-wider">
|
|
431
|
+
Mission Goal:
|
|
432
|
+
</span>
|
|
433
|
+
<span className="text-base-content/80 truncate font-medium">{subagent.goal}</span>
|
|
434
|
+
</div>
|
|
435
|
+
<div className="flex items-center gap-1.5 text-[11px] text-base-content/40 font-mono shrink-0">
|
|
436
|
+
<Clock className="w-3 h-3" />
|
|
437
|
+
<span>Turns: {subagent.turnCount || 0}</span>
|
|
438
|
+
</div>
|
|
439
|
+
</div>
|
|
440
|
+
|
|
441
|
+
{/* Message Feed Container */}
|
|
442
|
+
<div
|
|
443
|
+
ref={containerRef}
|
|
444
|
+
onScroll={handleScroll}
|
|
445
|
+
className="flex-1 p-5 overflow-y-auto space-y-4 relative"
|
|
446
|
+
>
|
|
447
|
+
{groupedTurns.map((item, idx) => {
|
|
448
|
+
if (item.type === 'subagent_turn') {
|
|
449
|
+
const isLastTurn = idx === groupedTurns.length - 1
|
|
450
|
+
return (
|
|
451
|
+
<SubagentUnifiedBubble
|
|
452
|
+
key={item.id}
|
|
453
|
+
turn={item}
|
|
454
|
+
subagentName={subagent.name}
|
|
455
|
+
isRunning={isRunning && isLastTurn}
|
|
456
|
+
/>
|
|
457
|
+
)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const isUser = item.sender === 'user'
|
|
461
|
+
const isMark = item.sender === 'mark'
|
|
462
|
+
|
|
463
|
+
return (
|
|
464
|
+
<div key={item.id} className="chat chat-end animate-fade-in">
|
|
465
|
+
<div className="chat-image avatar placeholder">
|
|
466
|
+
<div
|
|
467
|
+
className={`w-8 h-8 rounded-2xl text-[10px] font-bold shadow-md flex items-center justify-center ${
|
|
468
|
+
isUser
|
|
469
|
+
? 'bg-accent text-accent-content border border-accent/40 shadow-accent/20'
|
|
470
|
+
: 'bg-primary text-primary-content border border-primary/30'
|
|
471
|
+
}`}
|
|
472
|
+
>
|
|
473
|
+
{isUser ? 'USER' : 'MARK'}
|
|
474
|
+
</div>
|
|
475
|
+
</div>
|
|
476
|
+
<div className="chat-header text-[11px] opacity-50 mb-1 flex items-center gap-1.5">
|
|
477
|
+
<span className={isUser ? 'text-accent font-semibold' : ''}>
|
|
478
|
+
{isUser ? 'Creator (Mada)' : 'Lead Agent (Mark)'}
|
|
479
|
+
</span>
|
|
480
|
+
<span className="text-[10px]">
|
|
481
|
+
{new Date(item.timestamp).toLocaleTimeString([], {
|
|
482
|
+
hour: '2-digit',
|
|
483
|
+
minute: '2-digit'
|
|
484
|
+
})}
|
|
485
|
+
</span>
|
|
486
|
+
</div>
|
|
487
|
+
<div
|
|
488
|
+
className={`chat-bubble text-xs leading-relaxed max-w-[85%] rounded-2xl shadow-md p-3.5 ${
|
|
489
|
+
isUser
|
|
490
|
+
? 'bg-accent text-accent-content font-medium border border-accent/40 shadow-accent/20'
|
|
491
|
+
: 'bg-primary text-primary-content border border-primary/30'
|
|
492
|
+
}`}
|
|
493
|
+
>
|
|
494
|
+
<div className="whitespace-pre-wrap leading-relaxed font-normal">
|
|
495
|
+
{item.content
|
|
496
|
+
.replace(/^\[DARI LEAD AGENT \(MARK\)\]:\s*/, '')
|
|
497
|
+
.replace(/^\[DARI CREATOR \/ USER \(MADA\)\]:\s*/, '')}
|
|
498
|
+
</div>
|
|
499
|
+
</div>
|
|
500
|
+
</div>
|
|
501
|
+
)
|
|
502
|
+
})}
|
|
503
|
+
|
|
504
|
+
{/* Initial Loading State hanya jika belum ada bubble giliran sub-agent yang aktif */}
|
|
505
|
+
{isRunning &&
|
|
506
|
+
(groupedTurns.length === 0 ||
|
|
507
|
+
groupedTurns[groupedTurns.length - 1]?.type !== 'subagent_turn') && (
|
|
508
|
+
<div className="chat chat-start animate-fade-in">
|
|
509
|
+
<div className="chat-image avatar placeholder">
|
|
510
|
+
<div className="w-8 h-8 rounded-2xl text-[10px] font-bold shadow-md flex items-center justify-center bg-primary/20 text-primary border border-primary/30">
|
|
511
|
+
SUB
|
|
512
|
+
</div>
|
|
513
|
+
</div>
|
|
514
|
+
<div className="chat-header text-[11px] opacity-50 mb-1">
|
|
515
|
+
<span>{subagent.name}</span>
|
|
516
|
+
</div>
|
|
517
|
+
<div className="chat-bubble bg-base-200/95 text-base-content border border-base-content/15 text-xs flex items-center gap-2.5 py-2.5 px-4 shadow-md">
|
|
518
|
+
<Loader2 className="w-3.5 h-3.5 animate-spin text-primary" />
|
|
519
|
+
<span className="font-mono text-[11px] text-base-content/80">
|
|
520
|
+
Memproses langkah...
|
|
521
|
+
</span>
|
|
522
|
+
</div>
|
|
523
|
+
</div>
|
|
524
|
+
)}
|
|
525
|
+
|
|
526
|
+
<div ref={messagesEndRef} />
|
|
527
|
+
</div>
|
|
528
|
+
|
|
529
|
+
{/* Floating Scroll-to-Bottom Button */}
|
|
530
|
+
{showScrollBottomBtn && (
|
|
531
|
+
<button
|
|
532
|
+
onClick={() => scrollToBottom('smooth')}
|
|
533
|
+
className="absolute bottom-20 right-6 btn btn-circle btn-sm btn-primary shadow-xl shadow-primary/30 z-20 animate-bounce"
|
|
534
|
+
title="Scroll ke bawah"
|
|
535
|
+
>
|
|
536
|
+
<ArrowDown className="w-4 h-4" />
|
|
537
|
+
</button>
|
|
538
|
+
)}
|
|
539
|
+
|
|
540
|
+
{/* User Intervention Whisper Input */}
|
|
541
|
+
<form
|
|
542
|
+
onSubmit={handleSendMessage}
|
|
543
|
+
className="p-3.5 bg-base-200/90 border-t border-base-content/10 flex items-center gap-2 flex-none backdrop-blur-md z-10"
|
|
544
|
+
>
|
|
545
|
+
<input
|
|
546
|
+
type="text"
|
|
547
|
+
value={inputText}
|
|
548
|
+
onChange={(e) => setInputText(e.target.value)}
|
|
549
|
+
placeholder="Ketik instruksi/arahan langsung sebagai Creator (Mada)..."
|
|
550
|
+
disabled={isSending}
|
|
551
|
+
className="input input-sm input-bordered flex-1 rounded-xl bg-base-100/70 focus:bg-base-100 text-xs shadow-inner"
|
|
552
|
+
/>
|
|
553
|
+
<button
|
|
554
|
+
type="submit"
|
|
555
|
+
disabled={!inputText.trim() || isSending}
|
|
556
|
+
className="btn btn-accent btn-sm rounded-xl px-4 gap-1.5 shadow-md shadow-accent/20 font-semibold"
|
|
557
|
+
>
|
|
558
|
+
{isSending ? (
|
|
559
|
+
<span className="loading loading-spinner loading-xs" />
|
|
560
|
+
) : (
|
|
561
|
+
<>
|
|
562
|
+
<Send className="w-3.5 h-3.5" /> Kirim
|
|
563
|
+
</>
|
|
564
|
+
)}
|
|
565
|
+
</button>
|
|
566
|
+
</form>
|
|
567
|
+
|
|
568
|
+
{/* Confirmation Modal */}
|
|
569
|
+
<ModalComponent />
|
|
570
|
+
</div>
|
|
571
|
+
)
|
|
572
|
+
}
|