@gendive/chatllm 0.17.29 → 0.17.31

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.
@@ -1003,6 +1003,11 @@ interface MessageListProps {
1003
1003
  * @Todo vibecode - pending 항목 스킵
1004
1004
  */
1005
1005
  onChecklistSkip?: (messageId: string, stepIndex: number) => void;
1006
+ /**
1007
+ * @description 현재 실행 중인 스킬 정보 (도구 실행 로딩 표시용)
1008
+ * @Todo vibecode - 메시지 리스트 하단에 도구 실행 상태 인디케이터
1009
+ */
1010
+ activeSkillExecution?: SkillExecution | null;
1006
1011
  }
1007
1012
  interface MessageBubbleProps {
1008
1013
  message: ChatMessage;
@@ -1003,6 +1003,11 @@ interface MessageListProps {
1003
1003
  * @Todo vibecode - pending 항목 스킵
1004
1004
  */
1005
1005
  onChecklistSkip?: (messageId: string, stepIndex: number) => void;
1006
+ /**
1007
+ * @description 현재 실행 중인 스킬 정보 (도구 실행 로딩 표시용)
1008
+ * @Todo vibecode - 메시지 리스트 하단에 도구 실행 상태 인디케이터
1009
+ */
1010
+ activeSkillExecution?: SkillExecution | null;
1006
1011
  }
1007
1012
  interface MessageBubbleProps {
1008
1013
  message: ChatMessage;
@@ -2125,32 +2125,52 @@ ${projectMemoryContext}`);
2125
2125
  parts.push("");
2126
2126
  parts.push(`## \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 \uC790\uB3D9 \uC2E4\uD589 \uAE30\uB2A5
2127
2127
 
2128
- \uBCF5\uD569 \uC791\uC5C5(\uC870\uC0AC, \uBE44\uAD50 \uBD84\uC11D, \uB2E4\uB2E8\uACC4 \uC791\uC5C5)\uC744 \uC694\uCCAD\uBC1B\uC73C\uBA74 <checklist> \uD0DC\uADF8\uB85C \uC2E4\uD589 \uACC4\uD68D\uC744 \uC791\uC131\uD558\uC138\uC694.
2129
- \uC2DC\uC2A4\uD15C\uC774 \uAC01 \uB2E8\uACC4\uB97C \uC790\uB3D9\uC73C\uB85C \uD558\uB098\uC529 \uC2E4\uD589\uD569\uB2C8\uB2E4.
2128
+ **\uC911\uC694: \uC544\uB798 \uC870\uAC74\uC5D0 \uD574\uB2F9\uD558\uBA74 \uBC18\uB4DC\uC2DC <checklist> \uD0DC\uADF8\uB97C \uC0AC\uC6A9\uD558\uC138\uC694.**
2129
+
2130
+ \uB2E4\uC74C \uC694\uCCAD\uC5D0\uB294 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8\uB97C \uC0AC\uC6A9\uD558\uC138\uC694:
2131
+ - \uC5EC\uB7EC \uB300\uC0C1\uC744 \uAC80\uC0C9/\uC870\uC0AC\uD558\uB294 \uC694\uCCAD (\uC608: "A\uC640 B \uAC80\uC0C9\uD574\uC918", "XX \uAD00\uB828 \uC11C\uBE44\uC2A4 \uCC3E\uC544\uC918")
2132
+ - \uBE44\uAD50 \uBD84\uC11D \uC694\uCCAD (\uC608: "A\uC0AC\uC640 B\uC0AC \uBE44\uAD50\uD574\uC918")
2133
+ - \uBCF4\uACE0\uC11C/\uB9AC\uD3EC\uD2B8 \uC791\uC131 \uC694\uCCAD
2134
+ - 3\uB2E8\uACC4 \uC774\uC0C1\uC758 \uBCF5\uD569 \uC791\uC5C5
2135
+
2136
+ \uC2DC\uC2A4\uD15C\uC774 \uAC01 \uB2E8\uACC4\uB97C \uC790\uB3D9\uC73C\uB85C \uD558\uB098\uC529 \uC2E4\uD589\uD569\uB2C8\uB2E4. \uB2F9\uC2E0\uC740 \uACC4\uD68D\uB9CC \uC138\uC6B0\uBA74 \uB429\uB2C8\uB2E4.
2130
2137
 
2131
2138
  **\uD615\uC2DD:**
2139
+ \uC9E7\uC740 \uC548\uB0B4 \uBA54\uC2DC\uC9C0
2140
+
2132
2141
  <checklist>
2133
2142
  <step>1\uB2E8\uACC4 \uC81C\uBAA9</step>
2134
2143
  <step>2\uB2E8\uACC4 \uC81C\uBAA9</step>
2135
2144
  <step>3\uB2E8\uACC4 \uC81C\uBAA9</step>
2136
2145
  </checklist>
2137
2146
 
2138
- **\uC608\uC2DC - "A\uC0AC\uC640 B\uC0AC \uBE44\uAD50 \uBD84\uC11D\uD574\uC918":**
2139
- \uB124, \uBE44\uAD50 \uBD84\uC11D\uC744 \uC9C4\uD589\uD558\uACA0\uC2B5\uB2C8\uB2E4.
2147
+ **\uC608\uC2DC 1 - "\uB370\uBE0C\uB2E4\uC774\uBE0C\uC640 \uC820\uB2E4\uC774\uBE0C \uAC80\uC0C9\uD558\uACE0 \uBCF4\uACE0\uC11C \uC791\uC131\uD574\uC918":**
2148
+ \uB124, \uC870\uC0AC\uB97C \uC9C4\uD589\uD558\uACA0\uC2B5\uB2C8\uB2E4.
2149
+
2150
+ <checklist>
2151
+ <step>\uB370\uBE0C\uB2E4\uC774\uBE0C \uC11C\uBE44\uC2A4 \uC815\uBCF4 \uC870\uC0AC</step>
2152
+ <step>\uC820\uB2E4\uC774\uBE0C \uC11C\uBE44\uC2A4 \uC815\uBCF4 \uC870\uC0AC</step>
2153
+ <step>\uC720\uC0AC \uC11C\uBE44\uC2A4 \uC870\uC0AC</step>
2154
+ <step>\uBE44\uAD50 \uBD84\uC11D\uD45C \uC791\uC131</step>
2155
+ <step>\uC885\uD569 \uBCF4\uACE0\uC11C \uC791\uC131</step>
2156
+ </checklist>
2157
+
2158
+ **\uC608\uC2DC 2 - "\uC6B0\uB9AC \uC11C\uBE44\uC2A4 \uB9C8\uCF00\uD305 \uC804\uB7B5 \uC138\uC6CC\uC918":**
2159
+ \uB9C8\uCF00\uD305 \uC804\uB7B5\uC744 \uB2E8\uACC4\uBCC4\uB85C \uC218\uB9BD\uD558\uACA0\uC2B5\uB2C8\uB2E4.
2140
2160
 
2141
2161
  <checklist>
2142
- <step>A\uC0AC \uC815\uBCF4 \uC870\uC0AC</step>
2143
- <step>B\uC0AC \uC815\uBCF4 \uC870\uC0AC</step>
2144
- <step>\uB450 \uD68C\uC0AC \uBE44\uAD50 \uBD84\uC11D\uD45C \uC791\uC131</step>
2145
- <step>\uC885\uD569 \uACB0\uB860 \uBC0F \uCD94\uCC9C</step>
2162
+ <step>\uD604\uC7AC \uC11C\uBE44\uC2A4 \uBD84\uC11D</step>
2163
+ <step>\uD0C0\uAC9F \uACE0\uAC1D \uC815\uC758</step>
2164
+ <step>\uACBD\uC7C1\uC0AC \uBCA4\uCE58\uB9C8\uD0B9</step>
2165
+ <step>\uB9C8\uCF00\uD305 \uC804\uB7B5 \uC218\uB9BD</step>
2146
2166
  </checklist>
2147
2167
 
2148
2168
  **\uADDC\uCE59:**
2149
- - 2~8\uB2E8\uACC4\uAC00 \uC801\uC808 (\uB108\uBB34 \uC801\uAC70\uB098 \uB9CE\uC73C\uBA74 \uC548 \uB428)
2169
+ - 2~8\uB2E8\uACC4\uAC00 \uC801\uC808
2150
2170
  - \uAC01 \uB2E8\uACC4\uB294 \uAD6C\uCCB4\uC801\uC774\uACE0 \uC2E4\uD589 \uAC00\uB2A5\uD55C \uC791\uC5C5
2151
2171
  - \uB2E8\uC21C \uC9C8\uBB38\uC774\uB098 \uD55C \uBC88\uC5D0 \uB2F5\uD560 \uC218 \uC788\uB294 \uC694\uCCAD\uC5D0\uB294 \uC0AC\uC6A9 \uAE08\uC9C0
2152
- - <checklist> \uD0DC\uADF8 \uC55E\uC5D0 \uC9E7\uC740 \uC548\uB0B4 \uBA54\uC2DC\uC9C0\uB97C \uD3EC\uD568
2153
- - \uAC80\uC0C9/\uC870\uC0AC, \uBE44\uAD50 \uBD84\uC11D, \uBCF4\uACE0\uC11C \uC791\uC131, \uB2E4\uB2E8\uACC4 \uC791\uC5C5\uC5D0 \uC801\uADF9 \uC0AC\uC6A9`);
2172
+ - <checklist> \uD0DC\uADF8 \uC55E\uC5D0 \uBC18\uB4DC\uC2DC \uC9E7\uC740 \uC548\uB0B4 \uBA54\uC2DC\uC9C0\uB97C \uD3EC\uD568\uD558\uC138\uC694
2173
+ - \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 \uD0DC\uADF8 \uB4A4\uC5D0 \uCD94\uAC00 \uD14D\uC2A4\uD2B8\uB97C \uC791\uC131\uD558\uC9C0 \uB9C8\uC138\uC694`);
2154
2174
  }
2155
2175
  return parts.length > 0 ? parts.join("\n") : "";
2156
2176
  }, [personalization, globalMemory, useGlobalMemoryEnabled, enablePoll, enableChecklist, buildSkillsPrompt, enableProjects, projectHook.currentProject, projectMemory]);
@@ -2935,6 +2955,7 @@ ${attachmentContext}
2935
2955
  }
2936
2956
  if (detectedSkill && !resolvedSkills[detectedSkill.name]) {
2937
2957
  console.warn(`[useChatUI] \uC2A4\uD0AC "${detectedSkill.name}" \uAC10\uC9C0\uB418\uC5C8\uC73C\uB098 \uBBF8\uB4F1\uB85D. \uB4F1\uB85D\uB41C \uC2A4\uD0AC:`, Object.keys(resolvedSkills));
2958
+ accumulatedContent = skillCleanContent;
2938
2959
  setSessions(
2939
2960
  (prev) => prev.map((s) => {
2940
2961
  if (s.id !== capturedSessionId) return s;
@@ -2949,84 +2970,157 @@ ${attachmentContext}
2949
2970
  );
2950
2971
  }
2951
2972
  if (detectedSkill && resolvedSkills[detectedSkill.name]) {
2952
- setSessions(
2953
- (prev) => prev.map((s) => {
2954
- if (s.id !== capturedSessionId) return s;
2955
- return {
2956
- ...s,
2957
- messages: s.messages.map((m) => {
2958
- if (m.id !== assistantMessageId) return m;
2959
- return {
2960
- ...m,
2961
- content: skillCleanContent,
2962
- skillExecution: {
2963
- skillName: detectedSkill.name,
2964
- params: detectedSkill.params,
2965
- status: "executing"
2966
- }
2967
- };
2968
- })
2969
- };
2970
- })
2971
- );
2972
- let streamedReport = "";
2973
- const { result } = await handleSkillCall(assistantContent, {
2974
- onProgress: (progress) => {
2975
- setSessions(
2976
- (prev) => prev.map((s) => {
2977
- if (s.id !== capturedSessionId) return s;
2978
- return {
2979
- ...s,
2980
- messages: s.messages.map((m) => {
2981
- if (m.id !== assistantMessageId) return m;
2982
- return {
2983
- ...m,
2984
- skillExecution: { ...m.skillExecution, progress }
2985
- };
2986
- })
2987
- };
2988
- })
2989
- );
2990
- },
2991
- onStream: (chunk) => {
2992
- streamedReport += chunk;
2993
- setSessions(
2994
- (prev) => prev.map((s) => {
2995
- if (s.id !== capturedSessionId) return s;
2996
- return {
2997
- ...s,
2998
- messages: s.messages.map((m) => {
2999
- if (m.id !== assistantMessageId) return m;
3000
- return { ...m, content: streamedReport };
3001
- })
3002
- };
3003
- })
3004
- );
3005
- },
3006
- signal: abortControllerRef.current?.signal
3007
- });
3008
- if (result) {
3009
- if (result.metadata?.__toolResult__) {
3010
- const resultType = result.metadata.resultType;
3011
- const toolName = result.metadata.toolName;
3012
- const toolLabel = result.metadata.toolLabel;
3013
- const toolIcon = result.metadata.toolIcon;
3014
- const parts = [];
3015
- if (skillCleanContent.trim()) {
3016
- parts.push({ type: "text", content: skillCleanContent });
2973
+ if (activeChecklistRef.current) {
2974
+ console.log("[useChatUI] \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 \uB2E8\uACC4 \uB0B4 \uC2A4\uD0AC \uC2E4\uD589:", detectedSkill.name);
2975
+ accumulatedContent = skillCleanContent;
2976
+ setSessions(
2977
+ (prev) => prev.map((s) => {
2978
+ if (s.id !== capturedSessionId) return s;
2979
+ return { ...s, messages: s.messages.map((m) => m.id !== assistantMessageId ? m : { ...m, content: skillCleanContent }) };
2980
+ })
2981
+ );
2982
+ try {
2983
+ const { result: skillResult } = await handleSkillCall(assistantContent, {
2984
+ signal: abortControllerRef.current?.signal
2985
+ });
2986
+ if (skillResult?.content) {
2987
+ accumulatedContent = skillResult.content;
3017
2988
  }
3018
- parts.push({
3019
- type: "tool_result",
3020
- toolName,
3021
- label: toolLabel,
3022
- icon: toolIcon,
3023
- result: {
3024
- type: resultType,
3025
- content: result.content,
3026
- metadata: result.metadata,
3027
- sources: result.sources
2989
+ } catch (e) {
2990
+ console.warn("[useChatUI] \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 \uB0B4 \uC2A4\uD0AC \uC2E4\uD589 \uC2E4\uD328:", e);
2991
+ }
2992
+ } else {
2993
+ setSessions(
2994
+ (prev) => prev.map((s) => {
2995
+ if (s.id !== capturedSessionId) return s;
2996
+ return {
2997
+ ...s,
2998
+ messages: s.messages.map((m) => {
2999
+ if (m.id !== assistantMessageId) return m;
3000
+ return {
3001
+ ...m,
3002
+ content: skillCleanContent,
3003
+ skillExecution: {
3004
+ skillName: detectedSkill.name,
3005
+ params: detectedSkill.params,
3006
+ status: "executing"
3007
+ }
3008
+ };
3009
+ })
3010
+ };
3011
+ })
3012
+ );
3013
+ let streamedReport = "";
3014
+ const { result } = await handleSkillCall(assistantContent, {
3015
+ onProgress: (progress) => {
3016
+ setSessions(
3017
+ (prev) => prev.map((s) => {
3018
+ if (s.id !== capturedSessionId) return s;
3019
+ return {
3020
+ ...s,
3021
+ messages: s.messages.map((m) => {
3022
+ if (m.id !== assistantMessageId) return m;
3023
+ return {
3024
+ ...m,
3025
+ skillExecution: { ...m.skillExecution, progress }
3026
+ };
3027
+ })
3028
+ };
3029
+ })
3030
+ );
3031
+ },
3032
+ onStream: (chunk) => {
3033
+ streamedReport += chunk;
3034
+ setSessions(
3035
+ (prev) => prev.map((s) => {
3036
+ if (s.id !== capturedSessionId) return s;
3037
+ return {
3038
+ ...s,
3039
+ messages: s.messages.map((m) => {
3040
+ if (m.id !== assistantMessageId) return m;
3041
+ return { ...m, content: streamedReport };
3042
+ })
3043
+ };
3044
+ })
3045
+ );
3046
+ },
3047
+ signal: abortControllerRef.current?.signal
3048
+ });
3049
+ if (result) {
3050
+ if (result.metadata?.__toolResult__) {
3051
+ const resultType = result.metadata.resultType;
3052
+ const toolName = result.metadata.toolName;
3053
+ const toolLabel = result.metadata.toolLabel;
3054
+ const toolIcon = result.metadata.toolIcon;
3055
+ const parts = [];
3056
+ if (skillCleanContent.trim()) {
3057
+ parts.push({ type: "text", content: skillCleanContent });
3028
3058
  }
3029
- });
3059
+ parts.push({
3060
+ type: "tool_result",
3061
+ toolName,
3062
+ label: toolLabel,
3063
+ icon: toolIcon,
3064
+ result: {
3065
+ type: resultType,
3066
+ content: result.content,
3067
+ metadata: result.metadata,
3068
+ sources: result.sources
3069
+ }
3070
+ });
3071
+ setSessions(
3072
+ (prev) => prev.map((s) => {
3073
+ if (s.id !== capturedSessionId) return s;
3074
+ return {
3075
+ ...s,
3076
+ messages: s.messages.map((m) => {
3077
+ if (m.id !== assistantMessageId) return m;
3078
+ return {
3079
+ ...m,
3080
+ contentParts: parts,
3081
+ skillExecution: {
3082
+ ...m.skillExecution,
3083
+ status: "done",
3084
+ result
3085
+ }
3086
+ };
3087
+ })
3088
+ };
3089
+ })
3090
+ );
3091
+ if (resultType === "image" || resultType === "file") {
3092
+ saveMessagesOnEarlyReturn();
3093
+ setIsLoading(false);
3094
+ abortControllerRef.current = null;
3095
+ return;
3096
+ }
3097
+ let shouldContinue = continueAfterToolResult;
3098
+ if (onSkillCompleteRef.current) {
3099
+ const decision = onSkillCompleteRef.current(toolName, result);
3100
+ shouldContinue = decision === "continue";
3101
+ }
3102
+ if (!shouldContinue) {
3103
+ saveMessagesOnEarlyReturn();
3104
+ setIsLoading(false);
3105
+ abortControllerRef.current = null;
3106
+ return;
3107
+ }
3108
+ skipNextSkillParsingRef.current = true;
3109
+ saveMessagesOnEarlyReturn();
3110
+ const feedbackPrompt = resultType === "error" ? `\uB3C4\uAD6C "${toolName}" \uC2E4\uD589 \uC911 \uC624\uB958 \uBC1C\uC0DD: ${result.content}
3111
+
3112
+ \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC624\uB958\uB97C \uC548\uB0B4\uD574\uC8FC\uC138\uC694. skill_use \uD0DC\uADF8\uB294 \uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694.` : `\uB3C4\uAD6C "${toolName}" \uACB0\uACFC:
3113
+
3114
+ ${result.content}
3115
+
3116
+ \uC704 \uACB0\uACFC\uB97C \uBC14\uD0D5\uC73C\uB85C \uB2F5\uBCC0\uD574\uC8FC\uC138\uC694. skill_use \uD0DC\uADF8\uB294 \uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694.`;
3117
+ setTimeout(() => {
3118
+ sendMessage(feedbackPrompt, { hiddenUserMessage: true });
3119
+ }, 100);
3120
+ setIsLoading(false);
3121
+ abortControllerRef.current = null;
3122
+ return;
3123
+ }
3030
3124
  setSessions(
3031
3125
  (prev) => prev.map((s) => {
3032
3126
  if (s.id !== capturedSessionId) return s;
@@ -3036,7 +3130,7 @@ ${attachmentContext}
3036
3130
  if (m.id !== assistantMessageId) return m;
3037
3131
  return {
3038
3132
  ...m,
3039
- contentParts: parts,
3133
+ sources: result.sources || m.sources,
3040
3134
  skillExecution: {
3041
3135
  ...m.skillExecution,
3042
3136
  status: "done",
@@ -3047,18 +3141,18 @@ ${attachmentContext}
3047
3141
  };
3048
3142
  })
3049
3143
  );
3050
- if (resultType === "image" || resultType === "file") {
3144
+ if (streamedReport) {
3051
3145
  saveMessagesOnEarlyReturn();
3052
3146
  setIsLoading(false);
3053
3147
  abortControllerRef.current = null;
3054
3148
  return;
3055
3149
  }
3056
- let shouldContinue = continueAfterToolResult;
3150
+ let shouldContinueSkill = continueAfterToolResult;
3057
3151
  if (onSkillCompleteRef.current) {
3058
- const decision = onSkillCompleteRef.current(toolName, result);
3059
- shouldContinue = decision === "continue";
3152
+ const decision = onSkillCompleteRef.current(detectedSkill.name, result);
3153
+ shouldContinueSkill = decision === "continue";
3060
3154
  }
3061
- if (!shouldContinue) {
3155
+ if (!shouldContinueSkill) {
3062
3156
  saveMessagesOnEarlyReturn();
3063
3157
  setIsLoading(false);
3064
3158
  abortControllerRef.current = null;
@@ -3066,70 +3160,18 @@ ${attachmentContext}
3066
3160
  }
3067
3161
  skipNextSkillParsingRef.current = true;
3068
3162
  saveMessagesOnEarlyReturn();
3069
- const feedbackPrompt = resultType === "error" ? `\uB3C4\uAD6C "${toolName}" \uC2E4\uD589 \uC911 \uC624\uB958 \uBC1C\uC0DD: ${result.content}
3070
-
3071
- \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC624\uB958\uB97C \uC548\uB0B4\uD574\uC8FC\uC138\uC694. skill_use \uD0DC\uADF8\uB294 \uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694.` : `\uB3C4\uAD6C "${toolName}" \uACB0\uACFC:
3163
+ const resultPrompt = `\uC2A4\uD0AC "${detectedSkill.name}" \uC2E4\uD589 \uACB0\uACFC:
3072
3164
 
3073
3165
  ${result.content}
3074
3166
 
3075
- \uC704 \uACB0\uACFC\uB97C \uBC14\uD0D5\uC73C\uB85C \uB2F5\uBCC0\uD574\uC8FC\uC138\uC694. skill_use \uD0DC\uADF8\uB294 \uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694.`;
3167
+ \uC704 \uACB0\uACFC\uB97C \uBC14\uD0D5\uC73C\uB85C \uC0AC\uC6A9\uC790\uC758 \uC6D0\uB798 \uC9C8\uBB38\uC5D0 \uB2F5\uBCC0\uD574\uC8FC\uC138\uC694. skill_use \uD0DC\uADF8\uB294 \uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694.`;
3076
3168
  setTimeout(() => {
3077
- sendMessage(feedbackPrompt, { hiddenUserMessage: true });
3169
+ sendMessage(resultPrompt, { hiddenUserMessage: true });
3078
3170
  }, 100);
3079
3171
  setIsLoading(false);
3080
3172
  abortControllerRef.current = null;
3081
3173
  return;
3082
3174
  }
3083
- setSessions(
3084
- (prev) => prev.map((s) => {
3085
- if (s.id !== capturedSessionId) return s;
3086
- return {
3087
- ...s,
3088
- messages: s.messages.map((m) => {
3089
- if (m.id !== assistantMessageId) return m;
3090
- return {
3091
- ...m,
3092
- sources: result.sources || m.sources,
3093
- skillExecution: {
3094
- ...m.skillExecution,
3095
- status: "done",
3096
- result
3097
- }
3098
- };
3099
- })
3100
- };
3101
- })
3102
- );
3103
- if (streamedReport) {
3104
- saveMessagesOnEarlyReturn();
3105
- setIsLoading(false);
3106
- abortControllerRef.current = null;
3107
- return;
3108
- }
3109
- let shouldContinueSkill = continueAfterToolResult;
3110
- if (onSkillCompleteRef.current) {
3111
- const decision = onSkillCompleteRef.current(detectedSkill.name, result);
3112
- shouldContinueSkill = decision === "continue";
3113
- }
3114
- if (!shouldContinueSkill) {
3115
- saveMessagesOnEarlyReturn();
3116
- setIsLoading(false);
3117
- abortControllerRef.current = null;
3118
- return;
3119
- }
3120
- skipNextSkillParsingRef.current = true;
3121
- saveMessagesOnEarlyReturn();
3122
- const resultPrompt = `\uC2A4\uD0AC "${detectedSkill.name}" \uC2E4\uD589 \uACB0\uACFC:
3123
-
3124
- ${result.content}
3125
-
3126
- \uC704 \uACB0\uACFC\uB97C \uBC14\uD0D5\uC73C\uB85C \uC0AC\uC6A9\uC790\uC758 \uC6D0\uB798 \uC9C8\uBB38\uC5D0 \uB2F5\uBCC0\uD574\uC8FC\uC138\uC694. skill_use \uD0DC\uADF8\uB294 \uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694.`;
3127
- setTimeout(() => {
3128
- sendMessage(resultPrompt, { hiddenUserMessage: true });
3129
- }, 100);
3130
- setIsLoading(false);
3131
- abortControllerRef.current = null;
3132
- return;
3133
3175
  }
3134
3176
  }
3135
3177
  }
@@ -9730,7 +9772,8 @@ var MessageList = ({
9730
9772
  onPollSubmit,
9731
9773
  onChecklistAbort,
9732
9774
  onChecklistRetry,
9733
- onChecklistSkip
9775
+ onChecklistSkip,
9776
+ activeSkillExecution
9734
9777
  }) => {
9735
9778
  const messagesEndRef = (0, import_react18.useRef)(null);
9736
9779
  const containerRef = (0, import_react18.useRef)(null);
@@ -9852,6 +9895,61 @@ var MessageList = ({
9852
9895
  message.id
9853
9896
  );
9854
9897
  }),
9898
+ activeSkillExecution && activeSkillExecution.status === "executing" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
9899
+ "div",
9900
+ {
9901
+ style: {
9902
+ display: "flex",
9903
+ alignItems: "center",
9904
+ gap: "10px",
9905
+ padding: "12px 20px",
9906
+ margin: "8px auto",
9907
+ maxWidth: "680px",
9908
+ width: "100%"
9909
+ },
9910
+ children: [
9911
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9912
+ "div",
9913
+ {
9914
+ style: {
9915
+ width: "20px",
9916
+ height: "20px",
9917
+ borderRadius: "50%",
9918
+ border: "2px solid var(--chatllm-primary, #3584FA)",
9919
+ borderTopColor: "transparent",
9920
+ animation: "chatllm-spin 0.8s linear infinite",
9921
+ flexShrink: 0
9922
+ }
9923
+ }
9924
+ ),
9925
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9926
+ "span",
9927
+ {
9928
+ style: {
9929
+ fontSize: "13px",
9930
+ fontWeight: 500,
9931
+ color: "var(--chatllm-text-muted, #94a3b8)"
9932
+ },
9933
+ children: activeSkillExecution.progress?.phaseLabel || `${activeSkillExecution.skillName} \uC2E4\uD589 \uC911...`
9934
+ }
9935
+ ),
9936
+ activeSkillExecution.progress?.percentage != null && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
9937
+ "span",
9938
+ {
9939
+ style: {
9940
+ fontSize: "12px",
9941
+ color: "var(--chatllm-primary, #3584FA)",
9942
+ fontWeight: 600
9943
+ },
9944
+ children: [
9945
+ activeSkillExecution.progress.percentage,
9946
+ "%"
9947
+ ]
9948
+ }
9949
+ )
9950
+ ]
9951
+ }
9952
+ ),
9855
9953
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref: messagesEndRef })
9856
9954
  ]
9857
9955
  }
@@ -12011,7 +12109,8 @@ var ChatUIView = ({
12011
12109
  onPollSubmit: handlePollSubmit,
12012
12110
  onChecklistAbort: handleChecklistAbort,
12013
12111
  onChecklistRetry: handleChecklistRetry,
12014
- onChecklistSkip: handleChecklistSkip
12112
+ onChecklistSkip: handleChecklistSkip,
12113
+ activeSkillExecution
12015
12114
  }
12016
12115
  ),
12017
12116
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(