@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,895 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAgentTask,
|
|
3
|
+
startAgentTaskStep,
|
|
4
|
+
getAgentTaskWithSteps,
|
|
5
|
+
checkpointAgentTaskStep
|
|
6
|
+
} from '../../api/taskStore.js'
|
|
7
|
+
import { webApi } from '../../api/web-bridge.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* executeAgentTool
|
|
11
|
+
* Menangani ladder eksekusi berbagai jenis tool:
|
|
12
|
+
* - Sub-agents (spawn_subagent, message_agent, wait_subagents, send_message, list_subagents, kill_subagent)
|
|
13
|
+
* - Durable Tasks (create_agent_task)
|
|
14
|
+
* - Plugin & Ekstensi (list-plugins, read-tools, read-skill)
|
|
15
|
+
* - Native OS / Browser Tools (fallback via window.api.executeNativeTool)
|
|
16
|
+
*/
|
|
17
|
+
export async function executeAgentTool({
|
|
18
|
+
tool,
|
|
19
|
+
rawArgs: incomingArgs,
|
|
20
|
+
config,
|
|
21
|
+
context,
|
|
22
|
+
activeSessionNum,
|
|
23
|
+
activeTopic,
|
|
24
|
+
userInput,
|
|
25
|
+
durableTask,
|
|
26
|
+
durableActiveStep: incomingDurableActiveStep = null,
|
|
27
|
+
agenticProcessId,
|
|
28
|
+
targetPushProcess,
|
|
29
|
+
targetSetChatData,
|
|
30
|
+
currentSignal,
|
|
31
|
+
abortControllerRef,
|
|
32
|
+
getCurrentTimeInfo,
|
|
33
|
+
activeTaskObjectiveRef
|
|
34
|
+
}) {
|
|
35
|
+
let res
|
|
36
|
+
let updatedDurableTask = durableTask
|
|
37
|
+
let durableActiveStep = incomingDurableActiveStep
|
|
38
|
+
|
|
39
|
+
// Sanitasi parameter reason: simpan untuk timeline UI dan buang sebelum dikirim ke fungsi native
|
|
40
|
+
let rawArgs = incomingArgs
|
|
41
|
+
let execReason = null
|
|
42
|
+
if (incomingArgs && typeof incomingArgs === 'object' && !Array.isArray(incomingArgs)) {
|
|
43
|
+
rawArgs = { ...incomingArgs }
|
|
44
|
+
if (rawArgs.reason) {
|
|
45
|
+
execReason = String(rawArgs.reason).trim()
|
|
46
|
+
delete rawArgs.reason
|
|
47
|
+
}
|
|
48
|
+
} else if (typeof incomingArgs === 'string') {
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(incomingArgs)
|
|
51
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed) && parsed.reason) {
|
|
52
|
+
execReason = String(parsed.reason).trim()
|
|
53
|
+
delete parsed.reason
|
|
54
|
+
rawArgs = JSON.stringify(parsed)
|
|
55
|
+
}
|
|
56
|
+
} catch (_) {}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (currentSignal?.aborted) {
|
|
60
|
+
throw new Error('AbortError')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (tool === 'spawn_subagent') {
|
|
64
|
+
const { subagentStore } = await import('../../api/subagent/subagentStore.js')
|
|
65
|
+
const { runSubagentTurn } = await import('../../api/subagent/subagentExecutor.js')
|
|
66
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
67
|
+
const name = a.name || 'Specialist-Agent'
|
|
68
|
+
const role = a.role || 'Technical Specialist'
|
|
69
|
+
const goal = a.goal || 'Selesaikan misi teknis'
|
|
70
|
+
const initialMessage = a.initial_message || goal
|
|
71
|
+
const rawTools = a.tools
|
|
72
|
+
const tools = Array.isArray(rawTools)
|
|
73
|
+
? rawTools
|
|
74
|
+
: rawTools
|
|
75
|
+
? String(rawTools)
|
|
76
|
+
.split(',')
|
|
77
|
+
.map((t) => t.trim())
|
|
78
|
+
.filter(Boolean)
|
|
79
|
+
: ['*']
|
|
80
|
+
|
|
81
|
+
const originatingSessionId = String(
|
|
82
|
+
context?.sessionId || activeSessionNum || activeTopic?.id || 1
|
|
83
|
+
)
|
|
84
|
+
const originatingSessionTitle =
|
|
85
|
+
context?.sessionTitle ||
|
|
86
|
+
activeTopic?.title ||
|
|
87
|
+
activeTopic?.name ||
|
|
88
|
+
(originatingSessionId === '1' ? 'Main Thread' : `Sesi #${originatingSessionId}`)
|
|
89
|
+
|
|
90
|
+
const sub = await subagentStore.createSubagent({
|
|
91
|
+
name,
|
|
92
|
+
role,
|
|
93
|
+
goal,
|
|
94
|
+
allowedTools: tools,
|
|
95
|
+
parentSessionId: originatingSessionId,
|
|
96
|
+
parentSessionTitle: originatingSessionTitle
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
if (sub.isExisting && sub.wasRunning) {
|
|
100
|
+
res = {
|
|
101
|
+
success: true,
|
|
102
|
+
data: `[SUB-AGENT @${sub.name} SUDAH AKTIF BERJALAN]\n- ID: ${sub.id}\n- Role: ${sub.role}\n- Status: ${sub.status}\nSub-agent @${sub.name} saat ini sedang aktif mengerjakan tugas sebelumnya. Tidak ada duplikasi yang dibuat. Gunakan 'message_agent' jika ingin menambahkan pesan ke agen ini, atau tunggu hingga laporannya selesai.`
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
runSubagentTurn(sub.id, initialMessage, 'lead').catch((err) => {
|
|
106
|
+
console.error(`[Sub-Agent ${sub.id}] Background execution error:`, err)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
res = {
|
|
110
|
+
success: true,
|
|
111
|
+
data: `[SUB-AGENT BERHASIL DILUNCURKAN SECARA ASINKRON (NON-BLOCKING)]\n- Nama: ${sub.name}\n- ID: ${sub.id}\n- Role: ${sub.role}\n- Goal: ${sub.goal}\nSub-agent telah mulai bekerja secara mandiri di background. Kamu TIDAK PERLU menunggu (dilarang mem-blocking). Langsung beritahu user bahwa tugas telah didelegasikan ke @${sub.name} dan dia akan melapor secara otomatis via push notification ketika selesai.`
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} else if (tool === 'create_agent_task') {
|
|
115
|
+
if (durableTask) {
|
|
116
|
+
res = {
|
|
117
|
+
success: false,
|
|
118
|
+
error: `[DILARANG]: Alur kerja '${durableTask.title}' (${durableTask.id}) sudah aktif dalam giliran ini. DILARANG membuat task baru dengan 'create_agent_task'! Fokus selesaikan tahapan alur kerja yang sedang berjalan menggunakan 'mark_done_task' atau berikan respon jawaban akhir jika seluruh tahap sudah selesai.`
|
|
119
|
+
}
|
|
120
|
+
return { res, durableTask, durableActiveStep }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
124
|
+
const title = a.title || 'Workflow'
|
|
125
|
+
const objective = a.objective || userInput
|
|
126
|
+
|
|
127
|
+
if (!Array.isArray(a.steps) || a.steps.length === 0) {
|
|
128
|
+
res = {
|
|
129
|
+
success: false,
|
|
130
|
+
error:
|
|
131
|
+
"Parameter 'steps' wajib berupa array minimal 1 langkah terstruktur (berisi id, title, objective, deliverable)."
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
const stepsInput = a.steps
|
|
135
|
+
const newTaskId = `task-${Date.now()}`
|
|
136
|
+
|
|
137
|
+
let artifactRoot = null
|
|
138
|
+
try {
|
|
139
|
+
const resp = await fetch('/api/tasks/artifacts-dir').then((r) => r.json())
|
|
140
|
+
if (resp?.success && resp?.data) {
|
|
141
|
+
const cleanBase = resp.data.replace(/[\\/]+$/, '')
|
|
142
|
+
const sep = cleanBase.includes('\\') ? '\\' : '/'
|
|
143
|
+
artifactRoot = `${cleanBase}${sep}${newTaskId}`
|
|
144
|
+
await fetch('/api/tasks/ensure-dir', {
|
|
145
|
+
method: 'POST',
|
|
146
|
+
headers: { 'Content-Type': 'application/json' },
|
|
147
|
+
body: JSON.stringify({ dirPath: artifactRoot })
|
|
148
|
+
}).catch(() => {})
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
void err
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!artifactRoot && context?.workspaceRoot) {
|
|
155
|
+
const cleanWs = context.workspaceRoot.replace(/[\\/]+$/, '')
|
|
156
|
+
const sep = cleanWs.includes('\\') ? '\\' : '/'
|
|
157
|
+
artifactRoot = `${cleanWs}${sep}.mark${sep}tasks${sep}${newTaskId}`
|
|
158
|
+
await fetch('/api/tasks/ensure-dir', {
|
|
159
|
+
method: 'POST',
|
|
160
|
+
headers: { 'Content-Type': 'application/json' },
|
|
161
|
+
body: JSON.stringify({ dirPath: artifactRoot })
|
|
162
|
+
}).catch(() => {})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const pathSep = (artifactRoot || '').includes('\\') ? '\\' : '/'
|
|
166
|
+
|
|
167
|
+
updatedDurableTask = await createAgentTask({
|
|
168
|
+
id: newTaskId,
|
|
169
|
+
title,
|
|
170
|
+
objective,
|
|
171
|
+
mode: 'durable',
|
|
172
|
+
artifactRoot,
|
|
173
|
+
steps: stepsInput.map((step, idx) => ({
|
|
174
|
+
id: step.id || `step-${idx + 1}`,
|
|
175
|
+
title: step.title || `Langkah ${idx + 1}`,
|
|
176
|
+
objective: step.objective || objective,
|
|
177
|
+
deliverable: step.deliverable || 'Output kerja',
|
|
178
|
+
acceptanceCriteria: Array.isArray(step.acceptanceCriteria)
|
|
179
|
+
? step.acceptanceCriteria
|
|
180
|
+
: ['Selesai sesuai instruksi'],
|
|
181
|
+
artifactPath: artifactRoot
|
|
182
|
+
? `${artifactRoot}${pathSep}${step.id || `step-${idx + 1}`}.md`
|
|
183
|
+
: null
|
|
184
|
+
}))
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
durableActiveStep = await startAgentTaskStep(
|
|
188
|
+
updatedDurableTask.id,
|
|
189
|
+
updatedDurableTask.activeStepId
|
|
190
|
+
)
|
|
191
|
+
if (activeTaskObjectiveRef) {
|
|
192
|
+
activeTaskObjectiveRef.current =
|
|
193
|
+
durableActiveStep?.objective || updatedDurableTask.objective
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (targetPushProcess) {
|
|
197
|
+
targetPushProcess({
|
|
198
|
+
id: agenticProcessId,
|
|
199
|
+
type: 'planning',
|
|
200
|
+
status: 'active',
|
|
201
|
+
data: {
|
|
202
|
+
steps: stepsInput.map((step) => ({ task: step.title })),
|
|
203
|
+
currentStep: 0,
|
|
204
|
+
reasoning: `Task Workflow dibuat: ${title}`
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (targetSetChatData) {
|
|
210
|
+
targetSetChatData((prev) => [
|
|
211
|
+
...prev.filter((item) => !item.isThinking),
|
|
212
|
+
{
|
|
213
|
+
role: 'ai',
|
|
214
|
+
isPlanSteps: true,
|
|
215
|
+
taskId: updatedDurableTask.id,
|
|
216
|
+
taskTitle: title,
|
|
217
|
+
taskObjective: objective,
|
|
218
|
+
artifactRoot,
|
|
219
|
+
taskStatus: 'running',
|
|
220
|
+
plan: (updatedDurableTask.steps && updatedDurableTask.steps.length > 0
|
|
221
|
+
? updatedDurableTask.steps
|
|
222
|
+
: stepsInput
|
|
223
|
+
).map((step, idx) => ({
|
|
224
|
+
id: step.id || `${updatedDurableTask.id}-step-${idx + 1}`,
|
|
225
|
+
stepIndex: idx,
|
|
226
|
+
index: idx,
|
|
227
|
+
title: step.title || step.objective || `Tahap ${idx + 1}`,
|
|
228
|
+
task: step.title || step.objective || `Tahap ${idx + 1}`,
|
|
229
|
+
objective: step.objective || objective,
|
|
230
|
+
deliverable: step.deliverable || 'Output kerja',
|
|
231
|
+
acceptanceCriteria: Array.isArray(step.acceptanceCriteria)
|
|
232
|
+
? step.acceptanceCriteria
|
|
233
|
+
: [],
|
|
234
|
+
artifactPath:
|
|
235
|
+
step.artifactPath ||
|
|
236
|
+
(artifactRoot
|
|
237
|
+
? `${artifactRoot}${pathSep}${step.id || `step-${idx + 1}`}.md`
|
|
238
|
+
: null),
|
|
239
|
+
status: idx === 0 ? 'running' : 'pending'
|
|
240
|
+
})),
|
|
241
|
+
currentStep: 0,
|
|
242
|
+
reasoning: `Task Workflow diaktifkan: ${title}`,
|
|
243
|
+
timestamp: getCurrentTimeInfo ? getCurrentTimeInfo() : '',
|
|
244
|
+
created_at: Date.now()
|
|
245
|
+
}
|
|
246
|
+
])
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
res = {
|
|
250
|
+
success: true,
|
|
251
|
+
data: `[TASK WORKFLOW DIAKTIFKAN - TUGAS BERHASIL DIBUAT]:\n- Task ID: ${updatedDurableTask.id}\n- Judul: "${title}"\n- Total Steps: ${stepsInput.length}\n\n>>> TAHAP AKTIF SAAT INI (Tahap 1): "${durableActiveStep?.title}"\n- Sasaran: ${durableActiveStep?.objective}\n- Target Deliverable: ${durableActiveStep?.deliverable}\n\nPETUNJUK EKSEKUSI TAHAP 1:\n1. Kerjakan sasaran Tahap 1 terlebih dahulu di direktori workspace menggunakan tool yang relevan (seperti 'write-file' untuk membuat file, susun arsitektur, buat aset/kode). DILARANG LANGSUNG MEMANGGIL 'mark_done_task' SEBELUM PEKERJAAN ATAU FILE DELIVERABLE TAHAP INI SELESAI DIBUAT DI WORKSPACE!\n2. DILARANG mencari atau membaca kode internal aplikasi MARK!\n3. WAJIB UJI & VERIFIKASI SEBELUM TANDAI SELESAI: Lakukan pengujian/verifikasi hasil kerja terlebih dahulu (cek file/kode, uji jalan script/sintaks). Setelah teruji berhasil, barulah PANGGIL TOOL 'mark_done_task' dengan parameter stepIndex: 1, artifactContent, dan verificationProof (bukti hasil uji konkret)!`
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
} else if (tool === 'mark_done_task') {
|
|
255
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
256
|
+
const taskId = a.taskId || durableTask?.id
|
|
257
|
+
|
|
258
|
+
if (!taskId) {
|
|
259
|
+
res = {
|
|
260
|
+
success: false,
|
|
261
|
+
error: "Parameter 'taskId' wajib disertakan atau harus ada alur kerja aktif."
|
|
262
|
+
}
|
|
263
|
+
} else {
|
|
264
|
+
const taskWithSteps = await getAgentTaskWithSteps(taskId)
|
|
265
|
+
if (!taskWithSteps) {
|
|
266
|
+
res = { success: false, error: `Task dengan ID '${taskId}' tidak ditemukan.` }
|
|
267
|
+
} else {
|
|
268
|
+
const steps = taskWithSteps.steps || []
|
|
269
|
+
|
|
270
|
+
// 1. Resolusi stepNum: jika tidak disertakan atau NaN, otomatis ambil step aktif saat ini
|
|
271
|
+
let parsedStep = parseInt(
|
|
272
|
+
a.stepIndex ?? a.step_index ?? a.step ?? a.stepNumber ?? a.index,
|
|
273
|
+
10
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
let currentStep = null
|
|
277
|
+
if (!isNaN(parsedStep) && parsedStep >= 1) {
|
|
278
|
+
currentStep =
|
|
279
|
+
steps.find((s) => (s.stepIndex ?? s.index ?? 0) === parsedStep - 1) ||
|
|
280
|
+
steps[parsedStep - 1]
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Jika stepNum belum ketemu atau tidak valid, cari step yang sedang aktif atau belum selesai
|
|
284
|
+
if (!currentStep) {
|
|
285
|
+
currentStep =
|
|
286
|
+
steps.find((s) => s.status === 'running' && s.status !== 'completed') ||
|
|
287
|
+
steps.find((s) => s.status !== 'completed') ||
|
|
288
|
+
steps.find((s) => s.id === taskWithSteps.activeStepId) ||
|
|
289
|
+
steps[0]
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (!currentStep) {
|
|
293
|
+
res = {
|
|
294
|
+
success: false,
|
|
295
|
+
error: `Tidak ada tahap yang dapat diselesaikan di alur kerja '${taskId}'.`
|
|
296
|
+
}
|
|
297
|
+
} else {
|
|
298
|
+
const stepNum =
|
|
299
|
+
(currentStep.stepIndex ??
|
|
300
|
+
currentStep.step_index ??
|
|
301
|
+
currentStep.index ??
|
|
302
|
+
steps.indexOf(currentStep)) + 1
|
|
303
|
+
|
|
304
|
+
// 2. Cegah Re-Mark Done / Cicilan Draf: Tahap yang sudah selesai dilarang di-mark_done_task ulang
|
|
305
|
+
if (currentStep.status === 'completed') {
|
|
306
|
+
const nextPending = steps.find((s) => s.status !== 'completed')
|
|
307
|
+
if (nextPending) {
|
|
308
|
+
const nextIdx = (nextPending.stepIndex ?? nextPending.index ?? 0) + 1
|
|
309
|
+
res = {
|
|
310
|
+
success: false,
|
|
311
|
+
error: `[DITOLAK - TAHAP ${stepNum} SUDAH SELESAI]: Tahap ${stepNum} ("${currentStep.title}") SUDAH SELESAI sebelumnya! DILARANG memanggil 'mark_done_task' berulang kali untuk tahap yang sama. 'mark_done_task' BUKAN alat untuk menyimpan draf atau cicilan progress. Kamu WAJIB LANGSUNG berpindah mengerjakan Tahap ${nextIdx}: "${nextPending.title}"!`
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
res,
|
|
315
|
+
durableTask: updatedDurableTask,
|
|
316
|
+
durableActiveStep
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// 3. Validasi verifikasi dan pengujian sebelum menandai tahap selesai
|
|
322
|
+
const verificationProof =
|
|
323
|
+
typeof a.verificationProof === 'string' && a.verificationProof.trim()
|
|
324
|
+
? a.verificationProof.trim()
|
|
325
|
+
: typeof a.testResult === 'string' && a.testResult.trim()
|
|
326
|
+
? a.testResult.trim()
|
|
327
|
+
: typeof a.proof === 'string' && a.proof.trim()
|
|
328
|
+
? a.proof.trim()
|
|
329
|
+
: ''
|
|
330
|
+
|
|
331
|
+
if (!verificationProof || verificationProof.length < 15) {
|
|
332
|
+
res = {
|
|
333
|
+
success: false,
|
|
334
|
+
error: `[VERIFIKASI WAJIB]: Tahap ${stepNum} ("${currentStep.title}") DITOLAK untuk ditandai selesai karena belum diverifikasi atau diuji! Kamu wajib menjalankan pengujian/verifikasi hasil pekerjaan terlebih dahulu di workspace (seperti memeriksa file dengan read-file, mengecek sintaks, atau menjalankan test dengan run-powershell). Setelah pengujian berhasil, panggil kembali 'mark_done_task' dengan parameter 'verificationProof' yang merangkum bukti uji konkret.`
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
res,
|
|
338
|
+
durableTask: updatedDurableTask,
|
|
339
|
+
durableActiveStep
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 3. Resolusi konten deliverable artefak dan ringkasan
|
|
344
|
+
let summary = typeof a.summary === 'string' ? a.summary.trim() : ''
|
|
345
|
+
let artifactContent =
|
|
346
|
+
typeof a.artifactContent === 'string' && a.artifactContent.trim()
|
|
347
|
+
? a.artifactContent
|
|
348
|
+
: typeof a.artifact === 'string' && a.artifact.trim()
|
|
349
|
+
? a.artifact
|
|
350
|
+
: typeof a.content === 'string' && a.content.trim()
|
|
351
|
+
? a.content
|
|
352
|
+
: ''
|
|
353
|
+
|
|
354
|
+
if (!artifactContent && summary) {
|
|
355
|
+
artifactContent = `# Deliverable: ${currentStep.title}\n\n**Sasaran:** ${currentStep.objective || '-'}\n**Target Deliverable:** ${currentStep.deliverable || '-'}\n\n### Ringkasan Pengerjaan:\n${summary}\n\n### Bukti Pengujian & Verifikasi:\n${verificationProof}`
|
|
356
|
+
} else if (!artifactContent) {
|
|
357
|
+
artifactContent = `# Deliverable: ${currentStep.title}\n\n**Sasaran:** ${currentStep.objective || '-'}\n**Target Deliverable:** ${currentStep.deliverable || '-'}\n\nTahap telah diselesaikan dan diverifikasi sesuai kriteria penerimaan.\n\n### Bukti Pengujian & Verifikasi:\n${verificationProof}`
|
|
358
|
+
if (!summary) summary = `Tahap ${stepNum} selesai & terverifikasi: ${currentStep.title}`
|
|
359
|
+
} else if (
|
|
360
|
+
!artifactContent.includes('Bukti Pengujian') &&
|
|
361
|
+
!artifactContent.includes('Verifikasi')
|
|
362
|
+
) {
|
|
363
|
+
artifactContent += `\n\n### Bukti Pengujian & Verifikasi:\n${verificationProof}`
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (!summary) {
|
|
367
|
+
summary = `Tahap ${stepNum} selesai & terverifikasi: ${currentStep.title}`
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// 3. Tulis file artefak markdown ke disk jika artifactRoot ada
|
|
371
|
+
let finalArtifactPath = currentStep.artifactPath
|
|
372
|
+
const artifactRoot = taskWithSteps.artifactRoot
|
|
373
|
+
if (artifactRoot && window.api?.executeNativeTool) {
|
|
374
|
+
const pathSep = artifactRoot.includes('\\') ? '\\' : '/'
|
|
375
|
+
finalArtifactPath = `${artifactRoot}${pathSep}step_${stepNum}.md`
|
|
376
|
+
try {
|
|
377
|
+
await window.api.executeNativeTool(
|
|
378
|
+
'write-file',
|
|
379
|
+
{ path: finalArtifactPath, content: artifactContent },
|
|
380
|
+
{ workspaceRoot: context?.workspaceRoot }
|
|
381
|
+
)
|
|
382
|
+
} catch (err) {
|
|
383
|
+
console.warn('[executeAgentTool] Gagal menulis artefak:', err)
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// 4. Auto-complete semua tahap SEBELUM tahap ini jika ada yang terlewat
|
|
388
|
+
for (let i = 0; i < steps.length; i++) {
|
|
389
|
+
const priorStep = steps[i]
|
|
390
|
+
const priorIdx = priorStep.stepIndex ?? priorStep.step_index ?? priorStep.index ?? i
|
|
391
|
+
if (priorIdx < stepNum - 1 && priorStep.status !== 'completed') {
|
|
392
|
+
try {
|
|
393
|
+
await checkpointAgentTaskStep(taskId, priorStep.id, {
|
|
394
|
+
status: 'completed',
|
|
395
|
+
outputSummary:
|
|
396
|
+
priorStep.outputSummary || `Tahap ${priorIdx + 1} selesai: ${priorStep.title}`
|
|
397
|
+
})
|
|
398
|
+
} catch (pErr) {
|
|
399
|
+
console.warn('[executeAgentTool] Gagal checkpoint tahap sebelumnya:', pErr)
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// 5. Checkpoint step saat ini menjadi completed
|
|
405
|
+
const checkpointed = await checkpointAgentTaskStep(taskId, currentStep.id, {
|
|
406
|
+
status: 'completed',
|
|
407
|
+
artifactPath: finalArtifactPath,
|
|
408
|
+
outputSummary: summary
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
updatedDurableTask = checkpointed
|
|
412
|
+
const nextStep = checkpointed?.steps?.find((s) => s.id === checkpointed.activeStepId)
|
|
413
|
+
durableActiveStep = nextStep || null
|
|
414
|
+
if (activeTaskObjectiveRef) {
|
|
415
|
+
activeTaskObjectiveRef.current = nextStep ? nextStep.objective : null
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// 6. Perbarui tampilan ChatData secara real-time
|
|
419
|
+
const nextStepIdx = nextStep
|
|
420
|
+
? (nextStep.stepIndex ?? nextStep.step_index ?? nextStep.index ?? stepNum)
|
|
421
|
+
: null
|
|
422
|
+
|
|
423
|
+
if (targetSetChatData) {
|
|
424
|
+
targetSetChatData((prev) =>
|
|
425
|
+
prev.map((msg) => {
|
|
426
|
+
if (!msg.isPlanSteps || msg.taskId !== taskId) return msg
|
|
427
|
+
const updatedPlan = (msg.plan || []).map((s, idx) => {
|
|
428
|
+
const sIdx = s.stepIndex ?? s.step_index ?? s.index ?? idx
|
|
429
|
+
// Jika ini tahap yang diselesaikan ATAU tahap sebelumnya: tandai completed!
|
|
430
|
+
if (s.id === currentStep.id || sIdx <= stepNum - 1) {
|
|
431
|
+
return {
|
|
432
|
+
...s,
|
|
433
|
+
status: 'completed',
|
|
434
|
+
artifactPath:
|
|
435
|
+
s.id === currentStep.id || sIdx === stepNum - 1
|
|
436
|
+
? finalArtifactPath
|
|
437
|
+
: s.artifactPath || null,
|
|
438
|
+
outputSummary:
|
|
439
|
+
s.id === currentStep.id || sIdx === stepNum - 1
|
|
440
|
+
? summary
|
|
441
|
+
: s.outputSummary || `Tahap ${sIdx + 1} selesai`
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if (nextStep && (s.id === nextStep.id || sIdx === nextStepIdx)) {
|
|
445
|
+
return { ...s, status: 'running' }
|
|
446
|
+
}
|
|
447
|
+
return s
|
|
448
|
+
})
|
|
449
|
+
return {
|
|
450
|
+
...msg,
|
|
451
|
+
taskStatus: nextStep ? 'running' : 'completed',
|
|
452
|
+
currentStep: nextStep ? nextStepIdx : (msg.plan || []).length,
|
|
453
|
+
plan: updatedPlan
|
|
454
|
+
}
|
|
455
|
+
})
|
|
456
|
+
)
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (nextStep) {
|
|
460
|
+
const nextIdx = nextStepIdx + 1
|
|
461
|
+
res = {
|
|
462
|
+
success: true,
|
|
463
|
+
data: `[TAHAP ${stepNum} BERHASIL DISELESAIKAN]: Artefak telah disimpan ke '${finalArtifactPath || 'database'}'.\n\n>>> TAHAP AKTIF SELANJUTNYA (Tahap ${nextIdx}): "${nextStep.title}"\n- Sasaran: ${nextStep.objective}\n- Target Deliverable: ${nextStep.deliverable}\nSekarang fokus kerjakan tahap ${nextIdx} menggunakan tools yang sesuai di workspace. Uji dan verifikasi hasil sebelum memanggil 'mark_done_task' dengan parameter 'verificationProof'!`
|
|
464
|
+
}
|
|
465
|
+
} else {
|
|
466
|
+
res = {
|
|
467
|
+
success: true,
|
|
468
|
+
data: `[SELURUH TAHAPAN ALUR KERJA TELAH TUNTAS]: Semua ${steps.length} langkah dalam alur kerja '${taskWithSteps.title}' berhasil diselesaikan dengan sempurna! Sekarang berikan jawaban akhir ringkasan menyeluruh kepada pengguna.`
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
} else if (tool === 'read_task') {
|
|
475
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
476
|
+
const requestedId = a.taskId || durableTask?.id
|
|
477
|
+
const stepNum =
|
|
478
|
+
a.stepIndex !== undefined && a.stepIndex !== null ? parseInt(a.stepIndex, 10) : null
|
|
479
|
+
|
|
480
|
+
let taskWithSteps = null
|
|
481
|
+
if (requestedId) {
|
|
482
|
+
taskWithSteps = await getAgentTaskWithSteps(requestedId)
|
|
483
|
+
}
|
|
484
|
+
if (!taskWithSteps && durableTask?.id) {
|
|
485
|
+
taskWithSteps = await getAgentTaskWithSteps(durableTask.id)
|
|
486
|
+
}
|
|
487
|
+
if (!taskWithSteps) {
|
|
488
|
+
const running = await listAgentTasks({ status: 'running', limit: 1 })
|
|
489
|
+
if (running && running[0]) {
|
|
490
|
+
taskWithSteps = await getAgentTaskWithSteps(running[0].id)
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (!taskWithSteps) {
|
|
495
|
+
res = {
|
|
496
|
+
success: false,
|
|
497
|
+
error: `Task dengan ID '${requestedId || 'aktif'}' tidak ditemukan di sistem.`
|
|
498
|
+
}
|
|
499
|
+
} else {
|
|
500
|
+
const steps = taskWithSteps.steps || []
|
|
501
|
+
if (stepNum !== null && !isNaN(stepNum)) {
|
|
502
|
+
const step =
|
|
503
|
+
steps.find((s) => (s.stepIndex ?? s.index ?? 0) === stepNum - 1) || steps[stepNum - 1]
|
|
504
|
+
if (!step) {
|
|
505
|
+
res = {
|
|
506
|
+
success: false,
|
|
507
|
+
error: `Tahap ke-${stepNum} tidak ditemukan di task '${taskId}'.`
|
|
508
|
+
}
|
|
509
|
+
} else {
|
|
510
|
+
let artifactText = ''
|
|
511
|
+
if (step.artifactPath && window.api?.executeNativeTool) {
|
|
512
|
+
try {
|
|
513
|
+
const readRes = await window.api.executeNativeTool('read-file', {
|
|
514
|
+
path: step.artifactPath,
|
|
515
|
+
raw: true
|
|
516
|
+
})
|
|
517
|
+
if (readRes && readRes.success) {
|
|
518
|
+
artifactText = readRes.content || ''
|
|
519
|
+
}
|
|
520
|
+
} catch (err) {
|
|
521
|
+
console.warn('[read_task] Gagal membaca artefak dari disk:', err)
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
res = {
|
|
526
|
+
success: true,
|
|
527
|
+
data: `[ARTEFAK TAHAP ${stepNum}: "${step.title}"]\n- Status: ${step.status}\n- Sasaran: ${step.objective}\n- Deliverable: ${step.deliverable}\n- File Path: ${step.artifactPath || 'N/A'}\n\n--- ISI ARTEFAK DOKUMEN ---\n${artifactText || step.outputSummary || '(Artefak belum tersedia atau kosong)'}`
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
} else {
|
|
531
|
+
// Ringkasan semua step
|
|
532
|
+
const stepsSummary = steps
|
|
533
|
+
.map(
|
|
534
|
+
(s, i) =>
|
|
535
|
+
`${i + 1}. [${s.status.toUpperCase()}] ${s.title}\n - Sasaran: ${s.objective}\n - Deliverable: ${s.deliverable}\n - Artefak: ${s.artifactPath || 'N/A'}`
|
|
536
|
+
)
|
|
537
|
+
.join('\n\n')
|
|
538
|
+
|
|
539
|
+
res = {
|
|
540
|
+
success: true,
|
|
541
|
+
data: `[INFORMASI ALUR KERJA: "${taskWithSteps.title}"]\n- Task ID: ${taskWithSteps.id}\n- Sasaran Utama: ${taskWithSteps.objective}\n- Status: ${taskWithSteps.status}\n- Progres: ${steps.filter((s) => s.status === 'completed').length}/${steps.length} selesai\n\nDAFTAR TAHAP:\n${stepsSummary}\n\n[PERINGATAN ALUR KERJA]: DILARANG memanggil 'read_task' berulang kali untuk membaca pekerjaanmu sendiri! Kamu WAJIB langsung fokus membuat deliverable fisik tahap aktif berikutnya di workspace!`
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
} else if (tool === 'message_agent') {
|
|
546
|
+
const { subagentStore } = await import('../../api/subagent/subagentStore.js')
|
|
547
|
+
const { runSubagentTurn } = await import('../../api/subagent/subagentExecutor.js')
|
|
548
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
549
|
+
const targetQuery = a.target_agent || a.targetAgent || ''
|
|
550
|
+
const msgText = a.message || ''
|
|
551
|
+
|
|
552
|
+
if (!targetQuery || !msgText) {
|
|
553
|
+
res = {
|
|
554
|
+
success: false,
|
|
555
|
+
error: 'Parameter message_agent tidak lengkap (target_agent dan message wajib ada).'
|
|
556
|
+
}
|
|
557
|
+
} else {
|
|
558
|
+
const allAgents = await subagentStore.listSubagents()
|
|
559
|
+
const targetAgent = allAgents.find(
|
|
560
|
+
(s) =>
|
|
561
|
+
s.id === targetQuery ||
|
|
562
|
+
s.name.toLowerCase() === targetQuery.toLowerCase() ||
|
|
563
|
+
s.name.toLowerCase().replace(/^@/, '') === targetQuery.toLowerCase().replace(/^@/, '')
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
if (!targetAgent) {
|
|
567
|
+
res = {
|
|
568
|
+
success: false,
|
|
569
|
+
error: `Sub-agent dengan nama/ID '${targetQuery}' tidak ditemukan. Gunakan 'list_subagents' untuk memeriksa daftar agen aktif.`
|
|
570
|
+
}
|
|
571
|
+
} else {
|
|
572
|
+
const runResult = await runSubagentTurn(targetAgent.id, msgText, 'lead')
|
|
573
|
+
if (runResult.success) {
|
|
574
|
+
res = {
|
|
575
|
+
success: true,
|
|
576
|
+
data: `[BALASAN DARI @${targetAgent.name} (${targetAgent.id})]:\n"${runResult.reply}"\n${runResult.thought ? `(Reasoning: ${runResult.thought})\n` : ''}`
|
|
577
|
+
}
|
|
578
|
+
} else {
|
|
579
|
+
res = {
|
|
580
|
+
success: false,
|
|
581
|
+
error: `Sub-agent @${targetAgent.name} error: ${runResult.error}`
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
} else if (tool === 'wait_subagents') {
|
|
587
|
+
const { subagentStore } = await import('../../api/subagent/subagentStore.js')
|
|
588
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
589
|
+
const targetIdsRaw = a.targets || 'all'
|
|
590
|
+
const maxWaitSeconds = Number(a.timeout || 40) || 40
|
|
591
|
+
|
|
592
|
+
let targetIds = []
|
|
593
|
+
if (targetIdsRaw === 'all' || !targetIdsRaw) {
|
|
594
|
+
const running = await subagentStore.listSubagents('running')
|
|
595
|
+
targetIds = running.map((s) => s.id)
|
|
596
|
+
} else {
|
|
597
|
+
targetIds = Array.isArray(targetIdsRaw)
|
|
598
|
+
? targetIdsRaw
|
|
599
|
+
: String(targetIdsRaw)
|
|
600
|
+
.split(',')
|
|
601
|
+
.map((id) => id.trim())
|
|
602
|
+
.filter(Boolean)
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (targetIds.length === 0) {
|
|
606
|
+
const all = await subagentStore.listSubagents()
|
|
607
|
+
const summary = all
|
|
608
|
+
.slice(0, 5)
|
|
609
|
+
.map(
|
|
610
|
+
(s) =>
|
|
611
|
+
`- [${s.name} (${s.id})]: Status=${s.status}\n Hasil: ${s.finalAnswer || '(Belum ada laporan)'}`
|
|
612
|
+
)
|
|
613
|
+
.join('\n\n')
|
|
614
|
+
res = {
|
|
615
|
+
success: true,
|
|
616
|
+
data: `Tidak ada sub-agent yang sedang berjalan.\nRiwayat sub-agent:\n${summary || 'Kosong'}`
|
|
617
|
+
}
|
|
618
|
+
} else {
|
|
619
|
+
const startTime = Date.now()
|
|
620
|
+
let allDone = false
|
|
621
|
+
let finalAgents = []
|
|
622
|
+
|
|
623
|
+
while (Date.now() - startTime < maxWaitSeconds * 1000) {
|
|
624
|
+
if (currentSignal?.aborted) break
|
|
625
|
+
const agents = await Promise.all(targetIds.map((id) => subagentStore.getSubagent(id)))
|
|
626
|
+
finalAgents = agents.filter(Boolean)
|
|
627
|
+
|
|
628
|
+
const hasFailed = finalAgents.some((a) => a.status === 'failed' || a.status === 'killed')
|
|
629
|
+
if (hasFailed) break
|
|
630
|
+
|
|
631
|
+
const stillRunning = finalAgents.some((a) => a.status === 'running')
|
|
632
|
+
if (!stillRunning) {
|
|
633
|
+
allDone = true
|
|
634
|
+
break
|
|
635
|
+
}
|
|
636
|
+
await new Promise((r) => setTimeout(r, 1500))
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
const failedAgents = finalAgents.filter((a) => a.status === 'failed' || a.status === 'killed')
|
|
640
|
+
const runningAgents = finalAgents.filter((a) => a.status === 'running')
|
|
641
|
+
|
|
642
|
+
const reports = finalAgents
|
|
643
|
+
.map((a) => {
|
|
644
|
+
const isFailed = a.status === 'failed' || a.status === 'killed'
|
|
645
|
+
const isRunning = a.status === 'running'
|
|
646
|
+
const statusTag = isFailed
|
|
647
|
+
? `[PERHATIAN: STATUS ${a.status.toUpperCase()} - GAGAL/PERLU RETRY DENGAN send_message]`
|
|
648
|
+
: isRunning
|
|
649
|
+
? `[STATUS: RUNNING - SEDANG BERJALAN DI BACKGROUND]`
|
|
650
|
+
: `[STATUS: COMPLETED - SELESAI]`
|
|
651
|
+
return `### LAPORAN ${a.name} (${a.role}) - ID: ${a.id}\nStatus: ${statusTag} (Total Turns: ${a.turnCount || 0})\nGoal: ${a.goal}\nHasil Akhir:\n${a.finalAnswer || (isFailed ? 'Eksekusi agen ini terhenti atau mengalami kegagalan sebelum mencapai goal.' : isRunning ? '(Sedang aktif memproses langkah di background secara paralel)' : '(Belum ada output)')}`
|
|
652
|
+
})
|
|
653
|
+
.join('\n\n---\n\n')
|
|
654
|
+
|
|
655
|
+
let statusSummary = allDone ? 'SEMUA SELESAI' : 'WAKTU HABIS SEBAGIAN'
|
|
656
|
+
let failPrompt = ''
|
|
657
|
+
if (failedAgents.length > 0) {
|
|
658
|
+
const failedInfo = failedAgents.map((a) => `"${a.id}" (${a.name})`).join(', ')
|
|
659
|
+
failPrompt = `\n\n[PENGINGAT ORCHESTRATOR - EARLY FAIL INTERRUPT]: Sub-agent ${failedInfo} GAGAL saat sub-agent lain masih bekerja! Kamu WAJIB SEGERA mengirim pesan instruksi perbaikan/query alternatif ke ID tersebut menggunakan 'send_message' (format: "subagent_id", message: "instruksi").`
|
|
660
|
+
} else if (runningAgents.length > 0) {
|
|
661
|
+
failPrompt = `\n\n[PENGINGAT ORCHESTRATOR]: Masih ada ${runningAgents.length} sub-agent yang sedang bekerja di background. Jika kamu butuh menunggu mereka, panggil kembali 'wait_subagents'.`
|
|
662
|
+
} else {
|
|
663
|
+
failPrompt = `\n\n[PENGINGAT ORCHESTRATOR - PROTOKOL PEER-REVIEW & PIPELINE RELAY]: Sub-agent telah memberikan laporan. Sebagai Lead Orchestrator:\n1. RELAY DATA: Kamu BISA meneruskan/menyalurkan temuan dari satu agen ke agen lain yang membutuhkan via 'send_message'.\n2. REVIEW KRITIS: Evaluasi temuan agen secara mendalam sebelum menyusun kesimpulan akhir.`
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
res = {
|
|
667
|
+
success: true,
|
|
668
|
+
data: `[STATUS SUB-AGENTS (${statusSummary})]:\n\n${reports}${failPrompt}`
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
} else if (tool === 'send_message') {
|
|
672
|
+
const { runSubagentTurn } = await import('../../api/subagent/subagentExecutor.js')
|
|
673
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
674
|
+
const targetId = a.subagent_id || ''
|
|
675
|
+
const msgText = a.message || ''
|
|
676
|
+
|
|
677
|
+
if (!targetId || !msgText) {
|
|
678
|
+
res = {
|
|
679
|
+
success: false,
|
|
680
|
+
error: 'Parameter send_message tidak lengkap (subagent_id dan message wajib ada).'
|
|
681
|
+
}
|
|
682
|
+
} else {
|
|
683
|
+
const runResult = await runSubagentTurn(targetId, msgText)
|
|
684
|
+
if (runResult.success) {
|
|
685
|
+
res = {
|
|
686
|
+
success: true,
|
|
687
|
+
data: `[BALASAN EVALUASI DARI SUB-AGENT (${targetId})]:\n"${runResult.reply}"\n${runResult.thought ? `(Pemikiran: ${runResult.thought})\n` : ''}Evaluasi apakah hasil pendalaman ini sudah memenuhi standar kualitas tinggi.`
|
|
688
|
+
}
|
|
689
|
+
} else {
|
|
690
|
+
res = { success: false, error: `Sub-Agent error: ${runResult.error}` }
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
} else if (tool === 'list_subagents') {
|
|
694
|
+
const { subagentStore } = await import('../../api/subagent/subagentStore.js')
|
|
695
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
696
|
+
const filter = a.status || (typeof rawArgs === 'string' ? rawArgs.trim().toLowerCase() : null)
|
|
697
|
+
const list = await subagentStore.listSubagents(filter)
|
|
698
|
+
if (!list || list.length === 0) {
|
|
699
|
+
res = { success: true, data: 'Tidak ada sub-agent yang aktif/tersedia saat ini.' }
|
|
700
|
+
} else {
|
|
701
|
+
const summary = list
|
|
702
|
+
.map(
|
|
703
|
+
(s) =>
|
|
704
|
+
`- [${s.id}] ${s.name} (${s.role}): Status=${s.status}, Turns=${s.turnCount || 0}, Goal="${s.goal}"\n Hasil: ${s.finalAnswer ? s.finalAnswer.slice(0, 150) + '...' : '(Belum ada)'}`
|
|
705
|
+
)
|
|
706
|
+
.join('\n\n')
|
|
707
|
+
res = { success: true, data: `Daftar Sub-Agent Terdaftar:\n${summary}` }
|
|
708
|
+
}
|
|
709
|
+
} else if (tool === 'kill_subagent') {
|
|
710
|
+
const { killSubagentExecution } = await import('../../api/subagent/subagentExecutor.js')
|
|
711
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
712
|
+
const targetId = a.subagent_id || (typeof rawArgs === 'string' ? rawArgs.trim() : '')
|
|
713
|
+
if (!targetId) {
|
|
714
|
+
res = { success: false, error: 'Sebutkan subagent_id yang ingin dihentikan.' }
|
|
715
|
+
} else {
|
|
716
|
+
killSubagentExecution(targetId)
|
|
717
|
+
res = { success: true, data: `Sub-agent ${targetId} berhasil dihentikan paksa.` }
|
|
718
|
+
}
|
|
719
|
+
} else if (tool === 'list-plugins') {
|
|
720
|
+
try {
|
|
721
|
+
const plugins = await window.api.getPlugins()
|
|
722
|
+
if (!plugins || plugins.length === 0) {
|
|
723
|
+
res = {
|
|
724
|
+
success: true,
|
|
725
|
+
data: 'Belum ada custom plugin lokal yang terpasang di Documents/Mark Plugins.'
|
|
726
|
+
}
|
|
727
|
+
} else {
|
|
728
|
+
const summary = plugins
|
|
729
|
+
.map((p) => {
|
|
730
|
+
const acts = (p.actions || [])
|
|
731
|
+
.map((a) => ` * ${a.name}: ${a.description || a.triggerHint || ''}`)
|
|
732
|
+
.join('\n')
|
|
733
|
+
return `- Plugin "${p.name}" (v${p.version || '1.0.0'}, Status: ${p.isEnabled !== false ? 'AKTIF' : 'NONAKTIF'}):\n Deskripsi: ${p.description || '-'}\n Actions:\n${acts || ' (Tidak ada action)'}`
|
|
734
|
+
})
|
|
735
|
+
.join('\n\n')
|
|
736
|
+
res = { success: true, data: `Daftar Custom Plugin Terpasang:\n${summary}` }
|
|
737
|
+
}
|
|
738
|
+
} catch (pErr) {
|
|
739
|
+
res = { success: false, error: `Gagal memuat plugin: ${pErr.message}` }
|
|
740
|
+
}
|
|
741
|
+
} else if (tool === 'read-tools') {
|
|
742
|
+
const { definition: groups = {} } = await webApi.getGroupTools()
|
|
743
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
744
|
+
const groupName = (a.group_name || (typeof rawArgs === 'string' ? rawArgs : '') || '').trim()
|
|
745
|
+
if (!groupName) {
|
|
746
|
+
res = {
|
|
747
|
+
success: false,
|
|
748
|
+
message: 'Harap sebutkan group_name yang ingin dimuat (misal: "advanced_browser").'
|
|
749
|
+
}
|
|
750
|
+
} else if (groups[groupName]) {
|
|
751
|
+
const toolDescriptions = Object.entries(groups[groupName].tools)
|
|
752
|
+
.map(([k, v]) => `- ${k}: ${v}`)
|
|
753
|
+
.join('\n')
|
|
754
|
+
res = {
|
|
755
|
+
success: true,
|
|
756
|
+
loaded_group: groupName,
|
|
757
|
+
message: `BERHASIL MEMUAT GRUP TOOL: ${groupName}.\nDokumentasi tool:\n${toolDescriptions}`
|
|
758
|
+
}
|
|
759
|
+
} else {
|
|
760
|
+
let matchedPlugin = null
|
|
761
|
+
try {
|
|
762
|
+
if (typeof window !== 'undefined' && window.api && window.api.getPlugins) {
|
|
763
|
+
const plugins = await window.api.getPlugins()
|
|
764
|
+
matchedPlugin = (plugins || []).find((p) => p.name === groupName && p.isEnabled !== false)
|
|
765
|
+
}
|
|
766
|
+
} catch {
|
|
767
|
+
// ignore
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
if (matchedPlugin) {
|
|
771
|
+
const actionDescs = (matchedPlugin.actions || [])
|
|
772
|
+
.map(
|
|
773
|
+
(act) =>
|
|
774
|
+
`- plugin-${matchedPlugin.name}-${act.name}: ${act.description || act.triggerHint || ''}`
|
|
775
|
+
)
|
|
776
|
+
.join('\n')
|
|
777
|
+
res = {
|
|
778
|
+
success: true,
|
|
779
|
+
loaded_group: groupName,
|
|
780
|
+
message: `BERHASIL MEMUAT GRUP PLUGIN: ${groupName}.\nDeskripsi: ${matchedPlugin.description || '-'}\nDaftar Tool/Action:\n${actionDescs || ' (Tidak ada action)'}`
|
|
781
|
+
}
|
|
782
|
+
} else {
|
|
783
|
+
res = {
|
|
784
|
+
success: false,
|
|
785
|
+
message: `Grup tool "${groupName}" tidak ditemukan.`
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
} else if (tool === 'read-skill') {
|
|
790
|
+
const a = typeof rawArgs === 'object' && rawArgs !== null ? rawArgs : {}
|
|
791
|
+
const skillName = (a.skill_name || (typeof rawArgs === 'string' ? rawArgs : '') || '').trim()
|
|
792
|
+
if (!skillName) {
|
|
793
|
+
res = { success: false, message: 'Harap sebutkan skill_name yang ingin dibaca.' }
|
|
794
|
+
} else {
|
|
795
|
+
const { getLearnedSkill, getAllLearnedSkills } = await import('../../api/db.js')
|
|
796
|
+
let learned = await getLearnedSkill(skillName)
|
|
797
|
+
if (!learned || !learned.content) {
|
|
798
|
+
try {
|
|
799
|
+
const allLearned = await getAllLearnedSkills()
|
|
800
|
+
learned = (allLearned || []).find(
|
|
801
|
+
(s) =>
|
|
802
|
+
s.name?.toLowerCase() === skillName.toLowerCase() ||
|
|
803
|
+
s.id?.toLowerCase() === skillName.toLowerCase()
|
|
804
|
+
)
|
|
805
|
+
} catch {
|
|
806
|
+
// ignore
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
if (learned && learned.content) {
|
|
811
|
+
res = {
|
|
812
|
+
success: true,
|
|
813
|
+
data: `[PEDOMAN PROSEDUR KEAHLIAN (LEARNED): ${skillName.toUpperCase()}]\n${learned.content}`
|
|
814
|
+
}
|
|
815
|
+
} else {
|
|
816
|
+
const { NATIVE_SKILLS } = await import('../../components/core/native-skills.js')
|
|
817
|
+
const nativeSkill = (NATIVE_SKILLS || []).find(
|
|
818
|
+
(s) => s.name.toLowerCase() === skillName.toLowerCase()
|
|
819
|
+
)
|
|
820
|
+
if (nativeSkill && nativeSkill.content) {
|
|
821
|
+
res = {
|
|
822
|
+
success: true,
|
|
823
|
+
data: `[PEDOMAN SKILL BAWAAN: ${skillName.toUpperCase()}]\n${nativeSkill.content}`
|
|
824
|
+
}
|
|
825
|
+
} else {
|
|
826
|
+
let skillData = null
|
|
827
|
+
if (window.api && window.api.readSkill) {
|
|
828
|
+
try {
|
|
829
|
+
skillData = await window.api.readSkill(skillName)
|
|
830
|
+
} catch {
|
|
831
|
+
// ignore
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
if (!skillData) {
|
|
835
|
+
try {
|
|
836
|
+
const { webApi } = await import('../../api/web-bridge.js')
|
|
837
|
+
const serverSkill = await webApi.executeNativeTool('read-skill', {
|
|
838
|
+
skill_name: skillName
|
|
839
|
+
})
|
|
840
|
+
if (serverSkill && serverSkill.success && (serverSkill.content || serverSkill.data)) {
|
|
841
|
+
skillData = serverSkill.content || serverSkill.data
|
|
842
|
+
}
|
|
843
|
+
} catch {
|
|
844
|
+
// ignore
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
if (skillData) {
|
|
849
|
+
const content = typeof skillData === 'string' ? skillData : skillData.content
|
|
850
|
+
const basePath =
|
|
851
|
+
typeof skillData === 'object' && skillData.basePath ? skillData.basePath : ''
|
|
852
|
+
res = {
|
|
853
|
+
success: true,
|
|
854
|
+
data: `[PEDOMAN SKILL (FILE): ${skillName.toUpperCase()}]\n${basePath ? `[BASE PATH: ${basePath}]\n` : ''}${content}`
|
|
855
|
+
}
|
|
856
|
+
} else {
|
|
857
|
+
res = {
|
|
858
|
+
success: false,
|
|
859
|
+
message: `Skill "${skillName}" tidak ditemukan di direktori Mark Skills maupun basis data. PENTING: DILARANG mencoba memanggil tool 'read-skill' lagi untuk skill ini. Segera lanjutkan menyelesaikan instruksi user secara mandiri menggunakan tool umum yang relevan atau langsung berikan respon.`
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
} else if (typeof tool === 'string' && tool.startsWith('plugin-')) {
|
|
866
|
+
const pluginPromise = window.api?.executePlugin
|
|
867
|
+
? window.api.executePlugin(tool, rawArgs)
|
|
868
|
+
: webApi.executePluginAction(tool, rawArgs)
|
|
869
|
+
const abortPromise = new Promise((_, reject) => {
|
|
870
|
+
const onAbort = () => reject(new Error('AbortError'))
|
|
871
|
+
if (currentSignal?.aborted) return onAbort()
|
|
872
|
+
currentSignal?.addEventListener('abort', onAbort)
|
|
873
|
+
})
|
|
874
|
+
res = await Promise.race([pluginPromise, abortPromise])
|
|
875
|
+
} else {
|
|
876
|
+
const activeConfig = {
|
|
877
|
+
...(Array.isArray(config) ? config[0] : config),
|
|
878
|
+
workspaceRoot: context?.workspaceRoot
|
|
879
|
+
}
|
|
880
|
+
const nativePromise = window.api.executeNativeTool(tool, rawArgs, activeConfig)
|
|
881
|
+
const abortPromise = new Promise((_, reject) => {
|
|
882
|
+
const onAbort = () => reject(new Error('AbortError'))
|
|
883
|
+
if (currentSignal?.aborted) return onAbort()
|
|
884
|
+
currentSignal?.addEventListener('abort', onAbort)
|
|
885
|
+
})
|
|
886
|
+
res = await Promise.race([nativePromise, abortPromise])
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
return {
|
|
890
|
+
res,
|
|
891
|
+
durableTask: updatedDurableTask,
|
|
892
|
+
durableActiveStep,
|
|
893
|
+
reason: execReason
|
|
894
|
+
}
|
|
895
|
+
}
|