@ash-cloud/ash-ui 0.2.4 → 0.2.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 CHANGED
@@ -1269,6 +1269,128 @@ function JsonDisplay({ value, maxHeight, className }) {
1269
1269
  const formatted = JSON.stringify(value, null, 2);
1270
1270
  return /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { maxHeight, className, children: formatted });
1271
1271
  }
1272
+ var ChatDisplayModeContext = react.createContext(null);
1273
+ function useChatDisplayMode() {
1274
+ const ctx = react.useContext(ChatDisplayModeContext);
1275
+ if (!ctx) {
1276
+ return {
1277
+ mode: "debug",
1278
+ toggleMode: () => {
1279
+ },
1280
+ setMode: () => {
1281
+ },
1282
+ toolDescriptions: {},
1283
+ getUserDescription: () => null
1284
+ };
1285
+ }
1286
+ return ctx;
1287
+ }
1288
+ function ChatDisplayModeProvider({
1289
+ children,
1290
+ defaultMode = "user",
1291
+ storageKey = "ash-display-mode",
1292
+ toolDescriptions = {}
1293
+ }) {
1294
+ const [mode, setModeState] = react.useState(() => {
1295
+ if (typeof window !== "undefined") {
1296
+ const stored = localStorage.getItem(storageKey);
1297
+ if (stored === "user" || stored === "debug") return stored;
1298
+ }
1299
+ return defaultMode;
1300
+ });
1301
+ react.useEffect(() => {
1302
+ if (typeof window !== "undefined") {
1303
+ localStorage.setItem(storageKey, mode);
1304
+ }
1305
+ }, [mode, storageKey]);
1306
+ const toggleMode = () => setModeState((m) => m === "user" ? "debug" : "user");
1307
+ const setMode = (m) => setModeState(m);
1308
+ const getUserDescription = (toolName, input) => {
1309
+ if (toolDescriptions[toolName]) {
1310
+ const desc = toolDescriptions[toolName];
1311
+ return typeof desc === "function" ? desc(input) : desc;
1312
+ }
1313
+ for (const [pattern, desc] of Object.entries(toolDescriptions)) {
1314
+ if (toolName.includes(pattern)) {
1315
+ return typeof desc === "function" ? desc(input) : desc;
1316
+ }
1317
+ }
1318
+ return null;
1319
+ };
1320
+ return /* @__PURE__ */ jsxRuntime.jsx(
1321
+ ChatDisplayModeContext.Provider,
1322
+ {
1323
+ value: {
1324
+ mode,
1325
+ toggleMode,
1326
+ setMode,
1327
+ toolDescriptions,
1328
+ getUserDescription
1329
+ },
1330
+ children
1331
+ }
1332
+ );
1333
+ }
1334
+ function DisplayModeToggle({ className }) {
1335
+ const { mode, toggleMode } = useChatDisplayMode();
1336
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1337
+ "button",
1338
+ {
1339
+ onClick: toggleMode,
1340
+ className: cn("ash-display-mode-toggle", className),
1341
+ title: mode === "user" ? "Switch to debug mode" : "Switch to user mode",
1342
+ children: [
1343
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ash-display-mode-icon", children: mode === "user" ? /* @__PURE__ */ jsxRuntime.jsxs(
1344
+ "svg",
1345
+ {
1346
+ className: "w-4 h-4",
1347
+ fill: "none",
1348
+ stroke: "currentColor",
1349
+ viewBox: "0 0 24 24",
1350
+ children: [
1351
+ /* @__PURE__ */ jsxRuntime.jsx(
1352
+ "path",
1353
+ {
1354
+ strokeLinecap: "round",
1355
+ strokeLinejoin: "round",
1356
+ strokeWidth: 2,
1357
+ d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z"
1358
+ }
1359
+ ),
1360
+ /* @__PURE__ */ jsxRuntime.jsx(
1361
+ "path",
1362
+ {
1363
+ strokeLinecap: "round",
1364
+ strokeLinejoin: "round",
1365
+ strokeWidth: 2,
1366
+ d: "M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
1367
+ }
1368
+ )
1369
+ ]
1370
+ }
1371
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1372
+ "svg",
1373
+ {
1374
+ className: "w-4 h-4",
1375
+ fill: "none",
1376
+ stroke: "currentColor",
1377
+ viewBox: "0 0 24 24",
1378
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1379
+ "path",
1380
+ {
1381
+ strokeLinecap: "round",
1382
+ strokeLinejoin: "round",
1383
+ strokeWidth: 2,
1384
+ d: "M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
1385
+ }
1386
+ )
1387
+ }
1388
+ ) }),
1389
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ash-display-mode-label", children: mode === "user" ? "User" : "Debug" })
1390
+ ]
1391
+ }
1392
+ );
1393
+ }
1272
1394
  var ToolContext = react.createContext(null);
1273
1395
  function useTool() {
1274
1396
  const context = react.useContext(ToolContext);
@@ -1285,6 +1407,7 @@ function Tool({
1285
1407
  variant = "default"
1286
1408
  }) {
1287
1409
  const [isExpanded, setIsExpanded] = react.useState(defaultExpanded);
1410
+ const { mode, getUserDescription } = useChatDisplayMode();
1288
1411
  const toggleExpanded = () => setIsExpanded((prev) => !prev);
1289
1412
  const contextValue = {
1290
1413
  toolInvocation,
@@ -1296,6 +1419,27 @@ function Tool({
1296
1419
  const isErrorResult = Boolean(
1297
1420
  toolInvocation.result && typeof toolInvocation.result === "object" && "error" in toolInvocation.result
1298
1421
  );
1422
+ if (mode === "user") {
1423
+ const userDesc = getUserDescription(toolInvocation.toolName, toolInvocation.args) || formatToolName(toolInvocation.toolName);
1424
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1425
+ "div",
1426
+ {
1427
+ className: cn(
1428
+ "ash-tool ash-tool-user-mode",
1429
+ "flex items-center gap-2 px-3 py-1.5",
1430
+ "text-[var(--ash-font-size-xs,11px)]",
1431
+ "text-[var(--ash-text-muted,rgba(255,255,255,0.5))]",
1432
+ className
1433
+ ),
1434
+ "data-tool-name": toolInvocation.toolName,
1435
+ "data-tool-state": toolInvocation.state,
1436
+ children: [
1437
+ /* @__PURE__ */ jsxRuntime.jsx(StatusIndicator, { status, size: "xs" }),
1438
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: userDesc })
1439
+ ]
1440
+ }
1441
+ );
1442
+ }
1299
1443
  return /* @__PURE__ */ jsxRuntime.jsx(ToolContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
1300
1444
  "div",
1301
1445
  {
@@ -3130,6 +3274,9 @@ function isErrorEntry(entry) {
3130
3274
  function isWidgetEntry(entry) {
3131
3275
  return entry.type === "widget";
3132
3276
  }
3277
+ function isSystemMessage(entry) {
3278
+ return entry.type === "system_message";
3279
+ }
3133
3280
  var DEFAULT_STYLE_CONFIG = {
3134
3281
  userVariant: "bubble",
3135
3282
  assistantVariant: "bubble",
@@ -3263,7 +3410,7 @@ function messageToNormalizedEntry(message) {
3263
3410
  return {
3264
3411
  id,
3265
3412
  timestamp,
3266
- entryType: { type: "assistant_message" },
3413
+ entryType: { type: "system_message" },
3267
3414
  content
3268
3415
  };
3269
3416
  }
@@ -3666,6 +3813,8 @@ function useAgentChat(options) {
3666
3813
  onSessionEnd,
3667
3814
  onError,
3668
3815
  onSandboxLog,
3816
+ canUseTool,
3817
+ resolveToolPermission,
3669
3818
  onReconnect,
3670
3819
  maxReconnectAttempts = 3,
3671
3820
  reconnectBaseDelay = 1e3,
@@ -3699,6 +3848,23 @@ function useAgentChat(options) {
3699
3848
  const emitStreamingEntries = react.useCallback((newEntries) => {
3700
3849
  setStreamingEntries([...newEntries]);
3701
3850
  }, []);
3851
+ const handleToolPermission = react.useCallback(async (event) => {
3852
+ if (event.type !== "tool_permission") return;
3853
+ if (!canUseTool) return;
3854
+ if (!event.requestId || !event.sessionId || !event.toolName) return;
3855
+ const request = {
3856
+ requestId: event.requestId,
3857
+ sessionId: event.sessionId,
3858
+ toolName: event.toolName,
3859
+ input: event.input
3860
+ };
3861
+ const allow = await canUseTool(request);
3862
+ if (!resolveToolPermission) {
3863
+ console.warn("[useAgentChat] resolveToolPermission not provided for tool permission response");
3864
+ return;
3865
+ }
3866
+ await resolveToolPermission(request, allow);
3867
+ }, [canUseTool, resolveToolPermission]);
3702
3868
  const createTextEntry = react.useCallback((id, content) => ({
3703
3869
  id,
3704
3870
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -3857,6 +4023,7 @@ function useAgentChat(options) {
3857
4023
  for await (const event of stream) {
3858
4024
  if (controller.signal.aborted) break;
3859
4025
  eventCountRef.current++;
4026
+ await handleToolPermission(event);
3860
4027
  localStreamingEntries = processEvent(event, localStreamingEntries);
3861
4028
  emitStreamingEntries(localStreamingEntries);
3862
4029
  if (event.type === "complete" || event.type === "session_end" || event.type === "error") {
@@ -3890,9 +4057,10 @@ function useAgentChat(options) {
3890
4057
  }
3891
4058
  return false;
3892
4059
  }
3893
- }, [subscribeToSession, maxReconnectAttempts, reconnectBaseDelay, onReconnect, processEvent, emitStreamingEntries]);
3894
- const send = react.useCallback(async (prompt) => {
4060
+ }, [subscribeToSession, maxReconnectAttempts, reconnectBaseDelay, onReconnect, processEvent, emitStreamingEntries, handleToolPermission]);
4061
+ const send = react.useCallback(async (prompt, sendOptions) => {
3895
4062
  if (isStreaming) return;
4063
+ const role = sendOptions?.role ?? "user";
3896
4064
  let finalPrompt = prompt;
3897
4065
  let additionalMetadata = {};
3898
4066
  let additionalContext;
@@ -3938,13 +4106,15 @@ function useAgentChat(options) {
3938
4106
  setError(null);
3939
4107
  reconnectAttemptsRef.current = 0;
3940
4108
  eventCountRef.current = 0;
3941
- const userEntry = {
3942
- id: `user-${Date.now()}-${Math.random().toString(36).slice(2)}`,
3943
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3944
- entryType: { type: "user_message" },
3945
- content: prompt
3946
- };
3947
- setHistoryEntries((prev) => [...prev, userEntry]);
4109
+ if (role !== "system") {
4110
+ const userEntry = {
4111
+ id: `user-${Date.now()}-${Math.random().toString(36).slice(2)}`,
4112
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4113
+ entryType: { type: "user_message" },
4114
+ content: prompt
4115
+ };
4116
+ setHistoryEntries((prev) => [...prev, userEntry]);
4117
+ }
3948
4118
  resetStreamingState();
3949
4119
  const controller = new AbortController();
3950
4120
  abortControllerRef.current = controller;
@@ -3954,7 +4124,8 @@ function useAgentChat(options) {
3954
4124
  const stream = createStream(finalPrompt, sessionId || void 0, {
3955
4125
  signal: controller.signal,
3956
4126
  metadata: Object.keys(additionalMetadata).length > 0 ? additionalMetadata : void 0,
3957
- sessionContext: additionalContext
4127
+ sessionContext: additionalContext,
4128
+ role: role !== "user" ? role : void 0
3958
4129
  });
3959
4130
  for await (const event of stream) {
3960
4131
  if (controller.signal.aborted) break;
@@ -3969,6 +4140,7 @@ function useAgentChat(options) {
3969
4140
  console.error("[useAgentChat] onEvent error:", err);
3970
4141
  }
3971
4142
  }
4143
+ await handleToolPermission(event);
3972
4144
  let processedEvent = event;
3973
4145
  if (middleware?.length) {
3974
4146
  processedEvent = await applyEventMiddleware(middleware, event);
@@ -4018,7 +4190,7 @@ function useAgentChat(options) {
4018
4190
  abortControllerRef.current = null;
4019
4191
  resetStreamingState();
4020
4192
  }
4021
- }, [isStreaming, sessionId, historyEntries, streamingEntries, createStream, subscribeToSession, processEvent, emitStreamingEntries, resetStreamingState, onError, attemptReconnect, onBeforeSend, onEvent, middleware]);
4193
+ }, [isStreaming, sessionId, historyEntries, streamingEntries, createStream, subscribeToSession, processEvent, emitStreamingEntries, resetStreamingState, onError, attemptReconnect, onBeforeSend, onEvent, middleware, handleToolPermission]);
4022
4194
  const stop = react.useCallback(() => {
4023
4195
  reconnectAttemptsRef.current = maxReconnectAttempts + 1;
4024
4196
  setIsReconnecting(false);
@@ -4069,6 +4241,8 @@ function useChat(options) {
4069
4241
  initialSessionId,
4070
4242
  initialMessages = [],
4071
4243
  onToolCall,
4244
+ canUseTool,
4245
+ resolveToolPermission,
4072
4246
  onFinish,
4073
4247
  onError,
4074
4248
  onSessionStart,
@@ -4103,6 +4277,23 @@ function useChat(options) {
4103
4277
  return prev;
4104
4278
  });
4105
4279
  }, []);
4280
+ const handleToolPermission = react.useCallback(async (event) => {
4281
+ if (event.type !== "tool_permission") return;
4282
+ if (!canUseTool) return;
4283
+ if (!event.requestId || !event.sessionId || !event.toolName) return;
4284
+ const request = {
4285
+ requestId: event.requestId,
4286
+ sessionId: event.sessionId,
4287
+ toolName: event.toolName,
4288
+ input: event.input
4289
+ };
4290
+ const allow = await canUseTool(request);
4291
+ if (!resolveToolPermission) {
4292
+ console.warn("[useChat] resolveToolPermission not provided for tool permission response");
4293
+ return;
4294
+ }
4295
+ await resolveToolPermission(request, allow);
4296
+ }, [canUseTool, resolveToolPermission]);
4106
4297
  const processEvent = react.useCallback((event) => {
4107
4298
  switch (event.type) {
4108
4299
  case "session_start":
@@ -4222,6 +4413,7 @@ function useChat(options) {
4222
4413
  const stream = createStream(finalPrompt, sessionIdRef.current || void 0, streamOptions);
4223
4414
  for await (const event of stream) {
4224
4415
  if (controller.signal.aborted) break;
4416
+ await handleToolPermission(event);
4225
4417
  let processedEvent = event;
4226
4418
  if (middleware?.length) {
4227
4419
  processedEvent = await applyEventMiddleware(middleware, event);
@@ -4251,7 +4443,7 @@ function useChat(options) {
4251
4443
  abortControllerRef.current = null;
4252
4444
  currentAssistantMessageRef.current = null;
4253
4445
  }
4254
- }, [isLoading, createStream, processEvent, middleware, onError]);
4446
+ }, [isLoading, createStream, processEvent, middleware, onError, handleToolPermission]);
4255
4447
  const stop = react.useCallback(() => {
4256
4448
  reconnectAttemptsRef.current = maxReconnectAttempts + 1;
4257
4449
  setIsReconnecting(false);
@@ -4392,6 +4584,7 @@ exports.Attachments = Attachments;
4392
4584
  exports.BotIcon = BotIcon;
4393
4585
  exports.BrainIcon = BrainIcon;
4394
4586
  exports.BugIcon = BugIcon;
4587
+ exports.ChatDisplayModeProvider = ChatDisplayModeProvider;
4395
4588
  exports.CheckCircleIcon = CheckCircleIcon;
4396
4589
  exports.CheckIcon = CheckIcon;
4397
4590
  exports.ChevronDownIcon = ChevronDownIcon;
@@ -4410,6 +4603,7 @@ exports.ConversationLoadMore = ConversationLoadMore;
4410
4603
  exports.ConversationScrollButton = ConversationScrollButton;
4411
4604
  exports.CopyIcon = CopyIcon;
4412
4605
  exports.DEFAULT_STYLE_CONFIG = DEFAULT_STYLE_CONFIG;
4606
+ exports.DisplayModeToggle = DisplayModeToggle;
4413
4607
  exports.EditIcon = EditIcon;
4414
4608
  exports.EnvVarsPanel = EnvVarsPanel;
4415
4609
  exports.ErrorIcon = ErrorIcon;
@@ -4503,6 +4697,7 @@ exports.isGenericToolAction = isGenericToolAction;
4503
4697
  exports.isGlobAction = isGlobAction;
4504
4698
  exports.isMcpToolAction = isMcpToolAction;
4505
4699
  exports.isSearchAction = isSearchAction;
4700
+ exports.isSystemMessage = isSystemMessage;
4506
4701
  exports.isTodoWriteAction = isTodoWriteAction;
4507
4702
  exports.isToolCallEntry = isToolCallEntry;
4508
4703
  exports.isWebFetchAction = isWebFetchAction;
@@ -4529,6 +4724,7 @@ exports.updateToolCallWithResult = updateToolCallWithResult;
4529
4724
  exports.useAgentChat = useAgentChat;
4530
4725
  exports.useAttachment = useAttachment;
4531
4726
  exports.useChat = useChat;
4727
+ exports.useChatDisplayMode = useChatDisplayMode;
4532
4728
  exports.useConversation = useConversation;
4533
4729
  exports.useFileUpload = useFileUpload;
4534
4730
  exports.useLongTextConversion = useLongTextConversion;