@ash-cloud/ash-ui 0.0.4 → 0.0.6
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/dist/index.cjs +240 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +189 -4
- package/dist/index.d.ts +189 -4
- package/dist/index.js +239 -2
- package/dist/index.js.map +1 -1
- package/dist/styles-full.css +1 -0
- package/dist/styles.css +1 -1
- package/dist/types.cjs +4 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +87 -2
- package/dist/types.d.ts +87 -2
- package/dist/types.js +4 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.cts +1 -0
- package/dist/utils.d.ts +1 -0
- package/package.json +6 -3
package/dist/index.cjs
CHANGED
|
@@ -1742,6 +1742,9 @@ function isToolCallEntry(entry) {
|
|
|
1742
1742
|
function isErrorEntry(entry) {
|
|
1743
1743
|
return entry.type === "error";
|
|
1744
1744
|
}
|
|
1745
|
+
function isWidgetEntry(entry) {
|
|
1746
|
+
return entry.type === "widget";
|
|
1747
|
+
}
|
|
1745
1748
|
var DEFAULT_DISPLAY_CONFIG = {
|
|
1746
1749
|
mode: "inline",
|
|
1747
1750
|
breakEveryNToolCalls: 0,
|
|
@@ -1797,10 +1800,25 @@ function MessageList({
|
|
|
1797
1800
|
streamingContent,
|
|
1798
1801
|
displayConfig: displayConfigProp,
|
|
1799
1802
|
onOptionSelect,
|
|
1803
|
+
renderWidget,
|
|
1804
|
+
onWidgetAction,
|
|
1800
1805
|
className
|
|
1801
1806
|
}) {
|
|
1802
1807
|
const contextConfig = useDisplayConfig();
|
|
1803
1808
|
const config = displayConfigProp || contextConfig;
|
|
1809
|
+
const createWidgetActionHandler = react.useCallback(
|
|
1810
|
+
(entryId, widgetType) => {
|
|
1811
|
+
if (!onWidgetAction) return void 0;
|
|
1812
|
+
return (action) => {
|
|
1813
|
+
onWidgetAction({
|
|
1814
|
+
...action,
|
|
1815
|
+
entryId,
|
|
1816
|
+
widgetType
|
|
1817
|
+
});
|
|
1818
|
+
};
|
|
1819
|
+
},
|
|
1820
|
+
[onWidgetAction]
|
|
1821
|
+
);
|
|
1804
1822
|
const groupedEntries = react.useMemo(() => {
|
|
1805
1823
|
if (config.mode === "inline") {
|
|
1806
1824
|
return entries.map((entry) => ({
|
|
@@ -1814,7 +1832,20 @@ function MessageList({
|
|
|
1814
1832
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex-1 overflow-y-auto p-4 space-y-4 ash-scrollbar", className), children: [
|
|
1815
1833
|
groupedEntries.map((groupedEntry) => {
|
|
1816
1834
|
if (groupedEntry.type === "single") {
|
|
1817
|
-
|
|
1835
|
+
const entry = groupedEntry.entry;
|
|
1836
|
+
if (entry.entryType.type === "widget" && renderWidget) {
|
|
1837
|
+
const widgetEntry = entry.entryType;
|
|
1838
|
+
const widgetContent = renderWidget({
|
|
1839
|
+
entry,
|
|
1840
|
+
widgetType: widgetEntry.widgetType,
|
|
1841
|
+
widgetData: widgetEntry.widgetData,
|
|
1842
|
+
onAction: createWidgetActionHandler(entry.id, widgetEntry.widgetType)
|
|
1843
|
+
});
|
|
1844
|
+
if (widgetContent !== null) {
|
|
1845
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ash-animate-fade-in", children: widgetContent }, entry.id);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MessageEntry, { entry, onOptionSelect }, entry.id);
|
|
1818
1849
|
}
|
|
1819
1850
|
const toolCalls = extractToolCallsFromGroup(groupedEntry.entries);
|
|
1820
1851
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 ash-animate-fade-in", children: [
|
|
@@ -2942,6 +2973,212 @@ function useFileUpload({
|
|
|
2942
2973
|
openFilePicker
|
|
2943
2974
|
};
|
|
2944
2975
|
}
|
|
2976
|
+
function useAgentChat(options) {
|
|
2977
|
+
const {
|
|
2978
|
+
createStream,
|
|
2979
|
+
initialSessionId,
|
|
2980
|
+
initialEntries = [],
|
|
2981
|
+
onSessionStart,
|
|
2982
|
+
onSessionEnd,
|
|
2983
|
+
onError,
|
|
2984
|
+
onSandboxLog
|
|
2985
|
+
} = options;
|
|
2986
|
+
const [historyEntries, setHistoryEntries] = react.useState(initialEntries);
|
|
2987
|
+
const [streamingEntries, setStreamingEntries] = react.useState([]);
|
|
2988
|
+
const [isStreaming, setIsStreaming] = react.useState(false);
|
|
2989
|
+
const [error, setError] = react.useState(null);
|
|
2990
|
+
const [sessionId, setSessionId] = react.useState(initialSessionId || null);
|
|
2991
|
+
const abortControllerRef = react.useRef(null);
|
|
2992
|
+
const currentTextRef = react.useRef("");
|
|
2993
|
+
const currentTextIdRef = react.useRef(null);
|
|
2994
|
+
const pendingToolCallsRef = react.useRef(/* @__PURE__ */ new Map());
|
|
2995
|
+
const hadToolCallSinceTextRef = react.useRef(false);
|
|
2996
|
+
const entries = [...historyEntries, ...streamingEntries];
|
|
2997
|
+
const emitStreamingEntries = react.useCallback((newEntries) => {
|
|
2998
|
+
setStreamingEntries([...newEntries]);
|
|
2999
|
+
}, []);
|
|
3000
|
+
const createTextEntry = react.useCallback((id, content) => ({
|
|
3001
|
+
id,
|
|
3002
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3003
|
+
entryType: { type: "assistant_message" },
|
|
3004
|
+
content
|
|
3005
|
+
}), []);
|
|
3006
|
+
const resetStreamingState = react.useCallback(() => {
|
|
3007
|
+
currentTextRef.current = "";
|
|
3008
|
+
currentTextIdRef.current = null;
|
|
3009
|
+
pendingToolCallsRef.current.clear();
|
|
3010
|
+
hadToolCallSinceTextRef.current = false;
|
|
3011
|
+
setStreamingEntries([]);
|
|
3012
|
+
}, []);
|
|
3013
|
+
const processEvent = react.useCallback((event, streamEntries) => {
|
|
3014
|
+
const newEntries = [...streamEntries];
|
|
3015
|
+
switch (event.type) {
|
|
3016
|
+
case "session_start":
|
|
3017
|
+
if (event.sessionId) {
|
|
3018
|
+
setSessionId(event.sessionId);
|
|
3019
|
+
onSessionStart?.(event.sessionId);
|
|
3020
|
+
}
|
|
3021
|
+
break;
|
|
3022
|
+
case "text_delta":
|
|
3023
|
+
if (event.delta) {
|
|
3024
|
+
if (hadToolCallSinceTextRef.current && currentTextIdRef.current) {
|
|
3025
|
+
currentTextRef.current = "";
|
|
3026
|
+
currentTextIdRef.current = null;
|
|
3027
|
+
hadToolCallSinceTextRef.current = false;
|
|
3028
|
+
}
|
|
3029
|
+
currentTextRef.current += event.delta;
|
|
3030
|
+
if (!currentTextIdRef.current) {
|
|
3031
|
+
currentTextIdRef.current = `text-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
3032
|
+
newEntries.push(createTextEntry(currentTextIdRef.current, currentTextRef.current));
|
|
3033
|
+
} else {
|
|
3034
|
+
const entryIndex = newEntries.findIndex((e) => e.id === currentTextIdRef.current);
|
|
3035
|
+
if (entryIndex !== -1) {
|
|
3036
|
+
newEntries[entryIndex] = createTextEntry(currentTextIdRef.current, currentTextRef.current);
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
break;
|
|
3041
|
+
case "tool_use":
|
|
3042
|
+
if (event.toolId && event.toolName) {
|
|
3043
|
+
currentTextRef.current = "";
|
|
3044
|
+
currentTextIdRef.current = null;
|
|
3045
|
+
hadToolCallSinceTextRef.current = true;
|
|
3046
|
+
const toolCall = createToolCall({
|
|
3047
|
+
id: event.toolId,
|
|
3048
|
+
name: event.toolName,
|
|
3049
|
+
input: event.input
|
|
3050
|
+
});
|
|
3051
|
+
const entry = {
|
|
3052
|
+
id: event.toolId,
|
|
3053
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3054
|
+
entryType: { type: "tool_call", toolCall },
|
|
3055
|
+
content: toolCall.summary
|
|
3056
|
+
};
|
|
3057
|
+
const entryIndex = newEntries.length;
|
|
3058
|
+
newEntries.push(entry);
|
|
3059
|
+
pendingToolCallsRef.current.set(event.toolId, { entryIndex, toolCall });
|
|
3060
|
+
}
|
|
3061
|
+
break;
|
|
3062
|
+
case "tool_result":
|
|
3063
|
+
if (event.toolId) {
|
|
3064
|
+
const pending = pendingToolCallsRef.current.get(event.toolId);
|
|
3065
|
+
if (pending) {
|
|
3066
|
+
const updatedToolCall = updateToolCallWithResult(
|
|
3067
|
+
pending.toolCall,
|
|
3068
|
+
event.toolResult,
|
|
3069
|
+
event.isError
|
|
3070
|
+
);
|
|
3071
|
+
const existingEntry = newEntries[pending.entryIndex];
|
|
3072
|
+
if (existingEntry && existingEntry.entryType.type === "tool_call") {
|
|
3073
|
+
newEntries[pending.entryIndex] = {
|
|
3074
|
+
...existingEntry,
|
|
3075
|
+
entryType: { type: "tool_call", toolCall: updatedToolCall }
|
|
3076
|
+
};
|
|
3077
|
+
}
|
|
3078
|
+
pendingToolCallsRef.current.delete(event.toolId);
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
break;
|
|
3082
|
+
case "sandbox_log":
|
|
3083
|
+
if (event.entry) {
|
|
3084
|
+
onSandboxLog?.(event.entry);
|
|
3085
|
+
}
|
|
3086
|
+
break;
|
|
3087
|
+
case "error":
|
|
3088
|
+
if (event.error) {
|
|
3089
|
+
setError(event.error);
|
|
3090
|
+
onError?.(event.error);
|
|
3091
|
+
newEntries.push({
|
|
3092
|
+
id: `error-${Date.now()}`,
|
|
3093
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3094
|
+
entryType: { type: "error", message: event.error, code: event.code },
|
|
3095
|
+
content: event.error
|
|
3096
|
+
});
|
|
3097
|
+
}
|
|
3098
|
+
break;
|
|
3099
|
+
case "session_end":
|
|
3100
|
+
onSessionEnd?.(event.sessionId || sessionId || "", event.status || "completed");
|
|
3101
|
+
break;
|
|
3102
|
+
case "complete":
|
|
3103
|
+
if (newEntries.length > 0) {
|
|
3104
|
+
setHistoryEntries((prev) => [...prev, ...newEntries]);
|
|
3105
|
+
}
|
|
3106
|
+
resetStreamingState();
|
|
3107
|
+
return [];
|
|
3108
|
+
}
|
|
3109
|
+
return newEntries;
|
|
3110
|
+
}, [sessionId, onSessionStart, onSessionEnd, onError, onSandboxLog, createTextEntry, resetStreamingState]);
|
|
3111
|
+
const send = react.useCallback(async (prompt) => {
|
|
3112
|
+
if (isStreaming) return;
|
|
3113
|
+
setIsStreaming(true);
|
|
3114
|
+
setError(null);
|
|
3115
|
+
const userEntry = {
|
|
3116
|
+
id: `user-${Date.now()}`,
|
|
3117
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3118
|
+
entryType: { type: "user_message" },
|
|
3119
|
+
content: prompt
|
|
3120
|
+
};
|
|
3121
|
+
setHistoryEntries((prev) => [...prev, userEntry]);
|
|
3122
|
+
resetStreamingState();
|
|
3123
|
+
const controller = new AbortController();
|
|
3124
|
+
abortControllerRef.current = controller;
|
|
3125
|
+
let localStreamingEntries = [];
|
|
3126
|
+
try {
|
|
3127
|
+
const stream = createStream(prompt, sessionId || void 0);
|
|
3128
|
+
for await (const event of stream) {
|
|
3129
|
+
if (controller.signal.aborted) break;
|
|
3130
|
+
localStreamingEntries = processEvent(event, localStreamingEntries);
|
|
3131
|
+
emitStreamingEntries(localStreamingEntries);
|
|
3132
|
+
}
|
|
3133
|
+
if (localStreamingEntries.length > 0) {
|
|
3134
|
+
setHistoryEntries((prev) => [...prev, ...localStreamingEntries]);
|
|
3135
|
+
setStreamingEntries([]);
|
|
3136
|
+
}
|
|
3137
|
+
} catch (err) {
|
|
3138
|
+
if (err.name !== "AbortError") {
|
|
3139
|
+
const errorMessage = err instanceof Error ? err.message : "Unknown error";
|
|
3140
|
+
setError(errorMessage);
|
|
3141
|
+
onError?.(errorMessage);
|
|
3142
|
+
}
|
|
3143
|
+
} finally {
|
|
3144
|
+
setIsStreaming(false);
|
|
3145
|
+
abortControllerRef.current = null;
|
|
3146
|
+
resetStreamingState();
|
|
3147
|
+
}
|
|
3148
|
+
}, [isStreaming, sessionId, createStream, processEvent, emitStreamingEntries, resetStreamingState, onError]);
|
|
3149
|
+
const stop = react.useCallback(() => {
|
|
3150
|
+
if (abortControllerRef.current) {
|
|
3151
|
+
abortControllerRef.current.abort();
|
|
3152
|
+
}
|
|
3153
|
+
}, []);
|
|
3154
|
+
const clear = react.useCallback(() => {
|
|
3155
|
+
setHistoryEntries([]);
|
|
3156
|
+
resetStreamingState();
|
|
3157
|
+
setSessionId(initialSessionId || null);
|
|
3158
|
+
setError(null);
|
|
3159
|
+
}, [initialSessionId, resetStreamingState]);
|
|
3160
|
+
const setEntries = react.useCallback((newEntries) => {
|
|
3161
|
+
resetStreamingState();
|
|
3162
|
+
setHistoryEntries(newEntries);
|
|
3163
|
+
}, [resetStreamingState]);
|
|
3164
|
+
react.useEffect(() => {
|
|
3165
|
+
return () => {
|
|
3166
|
+
if (abortControllerRef.current) {
|
|
3167
|
+
abortControllerRef.current.abort();
|
|
3168
|
+
}
|
|
3169
|
+
};
|
|
3170
|
+
}, []);
|
|
3171
|
+
return {
|
|
3172
|
+
entries,
|
|
3173
|
+
isStreaming,
|
|
3174
|
+
error,
|
|
3175
|
+
sessionId,
|
|
3176
|
+
send,
|
|
3177
|
+
stop,
|
|
3178
|
+
clear,
|
|
3179
|
+
setEntries
|
|
3180
|
+
};
|
|
3181
|
+
}
|
|
2945
3182
|
|
|
2946
3183
|
exports.ActionIcon = ActionIcon;
|
|
2947
3184
|
exports.AlertCircleIcon = AlertCircleIcon;
|
|
@@ -3036,6 +3273,7 @@ exports.isTodoWriteAction = isTodoWriteAction;
|
|
|
3036
3273
|
exports.isToolCallEntry = isToolCallEntry;
|
|
3037
3274
|
exports.isWebFetchAction = isWebFetchAction;
|
|
3038
3275
|
exports.isWebSearchAction = isWebSearchAction;
|
|
3276
|
+
exports.isWidgetEntry = isWidgetEntry;
|
|
3039
3277
|
exports.keyframes = keyframes;
|
|
3040
3278
|
exports.keyframesCss = keyframesCss;
|
|
3041
3279
|
exports.mapToolToActionType = mapToolToActionType;
|
|
@@ -3050,6 +3288,7 @@ exports.transitions = transitions;
|
|
|
3050
3288
|
exports.truncate = truncate;
|
|
3051
3289
|
exports.typography = typography;
|
|
3052
3290
|
exports.updateToolCallWithResult = updateToolCallWithResult;
|
|
3291
|
+
exports.useAgentChat = useAgentChat;
|
|
3053
3292
|
exports.useDisplayConfig = useDisplayConfig;
|
|
3054
3293
|
exports.useDisplayMode = useDisplayMode;
|
|
3055
3294
|
exports.useFileUpload = useFileUpload;
|