@cadraos/sdk 0.1.11-test → 0.1.13

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.
@@ -1,6 +1,7 @@
1
1
  import { createContext, forwardRef, useState, useRef, useImperativeHandle, useCallback, useEffect, useMemo, useContext } from 'react';
2
2
  import { fetchEventSource } from '@microsoft/fetch-event-source';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+ import { createPortal } from 'react-dom';
4
5
  import ReactMarkdown from 'react-markdown';
5
6
  import remarkGfm from 'remark-gfm';
6
7
 
@@ -581,9 +582,11 @@ var DEFAULT_STREAMING_CONFIG = {
581
582
  activityTimeoutMs: 3e4,
582
583
  pollingIntervalMs: 2e3
583
584
  };
585
+ var DEFAULT_POLLING_ENABLED = true;
584
586
  var ExecutionStreamControllerImpl = class {
585
587
  options;
586
588
  config;
589
+ pollingEnabled;
587
590
  sseClient = null;
588
591
  status = "connecting";
589
592
  reconnectAttempts = 0;
@@ -617,6 +620,7 @@ var ExecutionStreamControllerImpl = class {
617
620
  constructor(options) {
618
621
  this.options = options;
619
622
  this.config = { ...DEFAULT_STREAMING_CONFIG, ...options.config };
623
+ this.pollingEnabled = options.pollingEnabled ?? DEFAULT_POLLING_ENABLED;
620
624
  }
621
625
  /**
622
626
  * Get the last event ID (for resume support)
@@ -957,15 +961,61 @@ var ExecutionStreamControllerImpl = class {
957
961
  if (this.status === "closed") {
958
962
  return;
959
963
  }
964
+ await this.recoverState();
965
+ if (this.status === "closed") {
966
+ return;
967
+ }
960
968
  try {
961
969
  await this.connectSSE();
962
970
  } catch {
963
971
  await this.handleConnectionError(error);
964
972
  }
965
973
  } else {
966
- this.status = "fallback_polling";
967
- this.emit("connectionChange", { connected: false, usingFallback: true });
968
- this.startPolling();
974
+ if (this.pollingEnabled) {
975
+ this.status = "fallback_polling";
976
+ this.emit("connectionChange", { connected: false, usingFallback: true });
977
+ this.startPolling();
978
+ } else {
979
+ this.handleError({
980
+ error: "SSE connection failed and polling is disabled",
981
+ errorCode: "connection_failed"
982
+ });
983
+ }
984
+ }
985
+ }
986
+ /**
987
+ * Recover state by checking execution status.
988
+ *
989
+ * Called during reconnection to catch any events missed while SSE was down.
990
+ * If the execution completed while disconnected, emits completion immediately.
991
+ * Otherwise, emits any new logs that weren't seen via SSE.
992
+ */
993
+ async recoverState() {
994
+ try {
995
+ const execution = await this.options.getExecution(this.options.executionId);
996
+ if (execution.logs) {
997
+ for (const log of execution.logs) {
998
+ if (!this.seenEventIds.has(log.uuid)) {
999
+ this.seenEventIds.add(log.uuid);
1000
+ this.emit("log", log);
1001
+ }
1002
+ }
1003
+ }
1004
+ if (execution.status === "completed") {
1005
+ this.stopPolling();
1006
+ this.handleComplete(execution);
1007
+ return;
1008
+ }
1009
+ if (execution.status === "failed" || execution.status === "cancelled") {
1010
+ this.stopPolling();
1011
+ this.handleError({
1012
+ error: execution.error ?? `Execution ${execution.status}`,
1013
+ errorCode: execution.status
1014
+ });
1015
+ return;
1016
+ }
1017
+ } catch (err) {
1018
+ console.warn("[SDK:StreamController] State recovery failed (non-fatal):", err);
969
1019
  }
970
1020
  }
971
1021
  /**
@@ -2817,12 +2867,54 @@ function useExecutionStream(options) {
2817
2867
  }
2818
2868
 
2819
2869
  // src/chat/hooks/useAgentChat.ts
2870
+ var __DEV__ = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
2820
2871
  var SILENT_TOOL_NAMES = /* @__PURE__ */ new Set([
2821
2872
  "check_delegations"
2822
2873
  ]);
2823
2874
  function generateId() {
2824
2875
  return `msg-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
2825
2876
  }
2877
+ function extractImagesFromResult(result, sourceToolCallId) {
2878
+ if (!result) return [];
2879
+ let data = result;
2880
+ if (typeof result === "string") {
2881
+ try {
2882
+ data = JSON.parse(result);
2883
+ } catch {
2884
+ if (/\.(png|jpg|jpeg|gif|webp|svg|bmp)(\?.*)?$/i.test(result) || result.startsWith("data:image/")) {
2885
+ return [{ url: result, sourceToolCallId }];
2886
+ }
2887
+ return [];
2888
+ }
2889
+ }
2890
+ if (typeof data !== "object" || data === null) return [];
2891
+ const obj = data;
2892
+ if (Array.isArray(obj.images)) {
2893
+ return obj.images.filter((img) => typeof img.url === "string").map((img) => ({
2894
+ url: img.url,
2895
+ alt: img.alt || img.prompt || void 0,
2896
+ filename: img.filename,
2897
+ sourceToolCallId
2898
+ }));
2899
+ }
2900
+ if (typeof obj.url === "string" && /\.(png|jpg|jpeg|gif|webp|svg|bmp)(\?.*)?$/i.test(obj.url)) {
2901
+ return [{ url: obj.url, alt: obj.alt, sourceToolCallId }];
2902
+ }
2903
+ if (typeof obj.imageUrl === "string") {
2904
+ return [{ url: obj.imageUrl, alt: obj.alt, sourceToolCallId }];
2905
+ }
2906
+ return [];
2907
+ }
2908
+ function deriveImagesFromToolCalls(toolCalls) {
2909
+ if (!toolCalls) return [];
2910
+ const images = [];
2911
+ for (const tc of toolCalls) {
2912
+ if (tc.status === "completed" && tc.result) {
2913
+ images.push(...extractImagesFromResult(tc.result, tc.id));
2914
+ }
2915
+ }
2916
+ return images;
2917
+ }
2826
2918
  function historyToMessage(historyMsg) {
2827
2919
  return {
2828
2920
  id: historyMsg.uuid,
@@ -2863,7 +2955,9 @@ function useAgentChat(options) {
2863
2955
  // Deprecated, but still supported
2864
2956
  onToolCall,
2865
2957
  onToolResult,
2866
- onClarification
2958
+ onClarification,
2959
+ pollingInterval,
2960
+ pollingEnabled
2867
2961
  } = options;
2868
2962
  const contextConfig = useChatConfigOptional();
2869
2963
  const adapter = propsAdapter ?? contextConfig?.adapter;
@@ -2895,8 +2989,14 @@ function useAgentChat(options) {
2895
2989
  const streamingMessageIdRef = useRef(null);
2896
2990
  const pendingToolCallsRef = useRef(/* @__PURE__ */ new Map());
2897
2991
  const lastMessageContentRef = useRef("");
2992
+ const finalizedRef = useRef(false);
2898
2993
  const firedToolResultsRef = useRef(/* @__PURE__ */ new Set());
2899
2994
  const streamControllerRef = useRef(null);
2995
+ const pendingDelegationsRef = useRef(/* @__PURE__ */ new Map());
2996
+ const onDelegationRef = useRef(options.onDelegation);
2997
+ useEffect(() => {
2998
+ onDelegationRef.current = options.onDelegation;
2999
+ }, [options.onDelegation]);
2900
3000
  const updateStreamingMessage = useCallback((content) => {
2901
3001
  if (!streamingMessageIdRef.current) return;
2902
3002
  setMessages(
@@ -2925,25 +3025,72 @@ function useAgentChat(options) {
2925
3025
  });
2926
3026
  });
2927
3027
  }, []);
2928
- const finalizeStreamingMessage = useCallback((terminalStatus = "completed") => {
3028
+ const addDelegationEvent = useCallback((delegation) => {
3029
+ setMessages((prev) => {
3030
+ const targetId = streamingMessageIdRef.current ?? [...prev].reverse().find((m) => m.role === "assistant")?.id;
3031
+ if (!targetId) return prev;
3032
+ return prev.map((msg) => {
3033
+ if (msg.id !== targetId) return msg;
3034
+ const existing = msg.delegationEvents ?? [];
3035
+ if (delegation.type === "delegation_completed" && delegation.handoffId) {
3036
+ const updatedEvents = existing.map(
3037
+ (de) => de.handoffId === delegation.handoffId ? { ...de, ...delegation, status: delegation.status ?? "completed" } : de
3038
+ );
3039
+ const hasMatch = existing.some((de) => de.handoffId === delegation.handoffId);
3040
+ return {
3041
+ ...msg,
3042
+ delegationEvents: hasMatch ? updatedEvents : [...existing, delegation]
3043
+ };
3044
+ }
3045
+ return { ...msg, delegationEvents: [...existing, delegation] };
3046
+ });
3047
+ });
3048
+ }, []);
3049
+ const updateMessageImages = useCallback(() => {
3050
+ setMessages((prev) => {
3051
+ const targetId = streamingMessageIdRef.current ?? [...prev].reverse().find((m) => m.role === "assistant")?.id;
3052
+ if (!targetId) return prev;
3053
+ return prev.map((msg) => {
3054
+ if (msg.id !== targetId) return msg;
3055
+ const images = deriveImagesFromToolCalls(msg.toolCalls);
3056
+ return images.length > 0 ? { ...msg, images } : msg;
3057
+ });
3058
+ });
3059
+ }, []);
3060
+ const finalizeStreamingMessage = useCallback((finalOutput) => {
2929
3061
  if (!streamingMessageIdRef.current) return;
2930
- setMessages(
2931
- (prev) => prev.map((msg) => {
2932
- if (msg.id !== streamingMessageIdRef.current) return msg;
3062
+ finalizedRef.current = true;
3063
+ const streamMsgId = streamingMessageIdRef.current;
3064
+ setMessages((prev) => {
3065
+ const resolvedContent = finalOutput || streamingContentRef.current || "";
3066
+ const duplicateExists = resolvedContent && prev.some(
3067
+ (msg) => msg.id !== streamMsgId && msg.role === "assistant" && !msg.isStreaming && msg.content === resolvedContent
3068
+ );
3069
+ if (duplicateExists) {
3070
+ return prev.filter((msg) => msg.id !== streamMsgId);
3071
+ }
3072
+ return prev.map((msg) => {
3073
+ if (msg.id !== streamMsgId) return msg;
2933
3074
  const updatedToolCalls = msg.toolCalls?.map(
2934
- (tc) => tc.status === "running" || tc.status === "pending" ? { ...tc, status: terminalStatus } : tc
3075
+ (tc) => tc.status === "running" || tc.status === "pending" ? { ...tc, status: "completed" } : tc
2935
3076
  );
2936
- return { ...msg, isStreaming: false, toolCalls: updatedToolCalls };
2937
- })
2938
- );
3077
+ return {
3078
+ ...msg,
3079
+ content: resolvedContent || msg.content,
3080
+ isStreaming: false,
3081
+ toolCalls: updatedToolCalls
3082
+ };
3083
+ });
3084
+ });
2939
3085
  streamingMessageIdRef.current = null;
2940
3086
  streamingContentRef.current = "";
2941
3087
  pendingToolCallsRef.current.clear();
2942
3088
  firedToolResultsRef.current.clear();
3089
+ pendingDelegationsRef.current.clear();
2943
3090
  }, []);
2944
3091
  const handleExecutionLog = useCallback(
2945
3092
  (log) => {
2946
- console.log("[useAgentChat] handleExecutionLog:", log.type, log.metadata);
3093
+ if (__DEV__) console.log("[useAgentChat] handleExecutionLog:", log.type, log.metadata);
2947
3094
  switch (log.type) {
2948
3095
  // Primary handlers for ai-saas-api worker log types
2949
3096
  case "llm_response": {
@@ -2963,11 +3110,46 @@ function useAgentChat(options) {
2963
3110
  }
2964
3111
  break;
2965
3112
  }
3113
+ case "delegation": {
3114
+ const delegationType = log.metadata?.delegationType;
3115
+ if (delegationType === "started" || delegationType === "delegation_started") {
3116
+ const delegation = {
3117
+ type: "delegation_started",
3118
+ handoffId: log.metadata?.handoffId,
3119
+ toAgent: log.metadata?.targetAgentName || log.metadata?.targetAgentUuid,
3120
+ targetAgentUuid: log.metadata?.targetAgentUuid,
3121
+ taskPreview: log.metadata?.taskPreview,
3122
+ timestamp: new Date(log.timestamp || Date.now()),
3123
+ status: "active"
3124
+ };
3125
+ if (delegation.handoffId) {
3126
+ pendingDelegationsRef.current.set(delegation.handoffId, delegation);
3127
+ }
3128
+ addDelegationEvent(delegation);
3129
+ onDelegationRef.current?.(delegation);
3130
+ } else if (delegationType === "completed" || delegationType === "delegation_completed") {
3131
+ const delegation = {
3132
+ type: "delegation_completed",
3133
+ handoffId: log.metadata?.handoffId,
3134
+ resultPreview: log.metadata?.resultPreview,
3135
+ timestamp: new Date(log.timestamp || Date.now()),
3136
+ status: log.metadata?.status === "failed" ? "failed" : "completed",
3137
+ durationMs: log.durationMs
3138
+ };
3139
+ if (delegation.handoffId) {
3140
+ pendingDelegationsRef.current.delete(delegation.handoffId);
3141
+ }
3142
+ addDelegationEvent(delegation);
3143
+ onDelegationRef.current?.(delegation);
3144
+ }
3145
+ break;
3146
+ }
2966
3147
  case "info":
2967
3148
  case "system":
2968
- console.log("[useAgentChat] Status:", log.type, log.title);
3149
+ if (__DEV__) console.log("[useAgentChat] Status:", log.type, log.title);
2969
3150
  break;
2970
3151
  case "tool_call": {
3152
+ if (finalizedRef.current) break;
2971
3153
  const toolName = log.metadata?.toolName;
2972
3154
  if (SILENT_TOOL_NAMES.has(toolName)) break;
2973
3155
  const toolCallId = log.metadata?.toolCallId || `tool-${Date.now()}`;
@@ -3022,17 +3204,18 @@ function useAgentChat(options) {
3022
3204
  firedToolResultsRef.current.add(resultToolCallId);
3023
3205
  }
3024
3206
  onToolResultRef.current?.(resultToolName, result, durationMs);
3207
+ updateMessageImages();
3025
3208
  break;
3026
3209
  }
3027
3210
  default:
3028
- console.log("[useAgentChat] Unhandled log type:", log.type, log);
3211
+ if (__DEV__) console.log("[useAgentChat] Unhandled log type:", log.type, log);
3029
3212
  }
3030
3213
  },
3031
- [updateStreamingMessage, updateToolCall]
3214
+ [updateStreamingMessage, updateToolCall, updateMessageImages, addDelegationEvent]
3032
3215
  );
3033
3216
  const handleStreamLog = useCallback(
3034
3217
  (log) => {
3035
- console.log("[useAgentChat] handleStreamLog:", log.logType, log.metadata);
3218
+ if (__DEV__) console.log("[useAgentChat] handleStreamLog:", log.logType, log.metadata);
3036
3219
  switch (log.logType) {
3037
3220
  case "llm_response": {
3038
3221
  const llmText = log.metadata?.text || "";
@@ -3051,9 +3234,42 @@ function useAgentChat(options) {
3051
3234
  }
3052
3235
  break;
3053
3236
  }
3237
+ case "delegation_started": {
3238
+ const delegation = {
3239
+ type: "delegation_started",
3240
+ handoffId: log.metadata?.handoffId,
3241
+ toAgent: log.metadata?.targetAgentName || log.metadata?.targetAgentUuid,
3242
+ targetAgentUuid: log.metadata?.targetAgentUuid,
3243
+ taskPreview: log.metadata?.taskPreview,
3244
+ timestamp: new Date(log.timestamp || Date.now()),
3245
+ status: "active"
3246
+ };
3247
+ if (delegation.handoffId) {
3248
+ pendingDelegationsRef.current.set(delegation.handoffId, delegation);
3249
+ }
3250
+ addDelegationEvent(delegation);
3251
+ onDelegationRef.current?.(delegation);
3252
+ break;
3253
+ }
3254
+ case "delegation_completed": {
3255
+ const delegation = {
3256
+ type: "delegation_completed",
3257
+ handoffId: log.metadata?.handoffId,
3258
+ resultPreview: log.metadata?.resultPreview,
3259
+ timestamp: new Date(log.timestamp || Date.now()),
3260
+ status: log.metadata?.status === "failed" ? "failed" : "completed",
3261
+ durationMs: log.durationMs
3262
+ };
3263
+ if (delegation.handoffId) {
3264
+ pendingDelegationsRef.current.delete(delegation.handoffId);
3265
+ }
3266
+ addDelegationEvent(delegation);
3267
+ onDelegationRef.current?.(delegation);
3268
+ break;
3269
+ }
3054
3270
  case "info":
3055
3271
  case "system":
3056
- console.log("[useAgentChat] Status:", log.logType, log.message);
3272
+ if (__DEV__) console.log("[useAgentChat] Status:", log.logType, log.message);
3057
3273
  break;
3058
3274
  case "response_text":
3059
3275
  case "text_chunk": {
@@ -3063,6 +3279,7 @@ function useAgentChat(options) {
3063
3279
  break;
3064
3280
  }
3065
3281
  case "tool_call": {
3282
+ if (finalizedRef.current) break;
3066
3283
  const toolName = log.metadata?.toolName;
3067
3284
  if (SILENT_TOOL_NAMES.has(toolName)) break;
3068
3285
  const toolCallId = log.metadata?.toolCallId || `tool-${Date.now()}`;
@@ -3117,6 +3334,7 @@ function useAgentChat(options) {
3117
3334
  firedToolResultsRef.current.add(resultToolCallId);
3118
3335
  }
3119
3336
  onToolResultRef.current?.(resultToolName, result, durationMs);
3337
+ updateMessageImages();
3120
3338
  break;
3121
3339
  }
3122
3340
  case "final_response": {
@@ -3128,10 +3346,10 @@ function useAgentChat(options) {
3128
3346
  break;
3129
3347
  }
3130
3348
  default:
3131
- console.log("[useAgentChat] Unknown log type:", log.logType, log);
3349
+ if (__DEV__) console.log("[useAgentChat] Unknown log type:", log.logType, log);
3132
3350
  }
3133
3351
  },
3134
- [updateStreamingMessage, updateToolCall]
3352
+ [updateStreamingMessage, updateToolCall, updateMessageImages, addDelegationEvent]
3135
3353
  );
3136
3354
  const handleClarification = useCallback(
3137
3355
  (data) => {
@@ -3140,17 +3358,23 @@ function useAgentChat(options) {
3140
3358
  },
3141
3359
  [onClarification]
3142
3360
  );
3143
- const handleComplete = useCallback(() => {
3144
- console.log("[useAgentChat] handleComplete called");
3361
+ const completedRef = useRef(false);
3362
+ const handleComplete = useCallback((finalOutput) => {
3363
+ if (completedRef.current) {
3364
+ if (__DEV__) console.log("[useAgentChat] handleComplete: skipping duplicate complete");
3365
+ return;
3366
+ }
3367
+ completedRef.current = true;
3368
+ if (__DEV__) console.log("[useAgentChat] handleComplete called");
3145
3369
  setIsLoading(false);
3146
3370
  setIsStreamControllerConnected(false);
3147
- finalizeStreamingMessage();
3371
+ finalizeStreamingMessage(finalOutput);
3148
3372
  setCurrentExecutionId(null);
3149
3373
  streamControllerRef.current = null;
3150
3374
  }, [finalizeStreamingMessage]);
3151
3375
  const handleError = useCallback(
3152
3376
  (errorMsg) => {
3153
- console.log("[useAgentChat] handleError called:", errorMsg);
3377
+ if (__DEV__) console.log("[useAgentChat] handleError called:", errorMsg);
3154
3378
  const chatError = {
3155
3379
  code: "EXECUTION_ERROR",
3156
3380
  message: errorMsg,
@@ -3159,7 +3383,7 @@ function useAgentChat(options) {
3159
3383
  setError(chatError);
3160
3384
  setIsLoading(false);
3161
3385
  setIsStreamControllerConnected(false);
3162
- finalizeStreamingMessage("failed");
3386
+ finalizeStreamingMessage();
3163
3387
  setCurrentExecutionId(null);
3164
3388
  streamControllerRef.current = null;
3165
3389
  onError?.(chatError);
@@ -3189,43 +3413,39 @@ function useAgentChat(options) {
3189
3413
  if (pollingExecutionIdRef.current === executionId) return;
3190
3414
  stopPolling();
3191
3415
  pollingExecutionIdRef.current = executionId;
3192
- console.log("[useAgentChat] Starting polling fallback for:", executionId);
3416
+ if (__DEV__) console.log("[useAgentChat] Starting polling fallback for:", executionId);
3193
3417
  const poll = async () => {
3194
3418
  if (pollingExecutionIdRef.current !== executionId) return;
3195
3419
  try {
3196
3420
  const execution = await adapter.getExecution(executionId);
3197
3421
  if (execution.status === "completed") {
3198
- console.log("[useAgentChat] Polling: execution completed");
3199
- if (execution.result) {
3200
- streamingContentRef.current = execution.result;
3201
- updateStreamingMessage(execution.result);
3202
- }
3422
+ if (__DEV__) console.log("[useAgentChat] Polling: execution completed");
3203
3423
  stopPolling();
3204
- handleComplete();
3424
+ handleComplete(execution.result || void 0);
3205
3425
  } else if (execution.status === "failed") {
3206
- console.log("[useAgentChat] Polling: execution failed");
3426
+ if (__DEV__) console.log("[useAgentChat] Polling: execution failed");
3207
3427
  stopPolling();
3208
3428
  handleError(execution.error || "Execution failed");
3209
3429
  }
3210
3430
  } catch (err) {
3211
- console.warn("[useAgentChat] Polling error (will retry):", err);
3431
+ if (__DEV__) console.warn("[useAgentChat] Polling error (will retry):", err);
3212
3432
  }
3213
3433
  };
3214
3434
  poll();
3215
- pollingIntervalRef.current = setInterval(poll, 2e3);
3216
- }, [adapter, stopPolling, updateStreamingMessage, handleComplete, handleError]);
3435
+ pollingIntervalRef.current = setInterval(poll, pollingInterval ?? 2e3);
3436
+ }, [adapter, stopPolling, handleComplete, handleError, pollingInterval]);
3217
3437
  useEffect(() => {
3218
- if (!useStreamController && isUsingFallback && currentExecutionId && isLoading) {
3219
- console.log("[useAgentChat] SSE fallback detected, activating polling");
3438
+ if (!useStreamController && isUsingFallback && currentExecutionId && isLoading && pollingEnabled !== false) {
3439
+ if (__DEV__) console.log("[useAgentChat] SSE fallback detected, activating polling");
3220
3440
  startPolling(currentExecutionId);
3221
3441
  }
3222
- }, [useStreamController, isUsingFallback, currentExecutionId, isLoading, startPolling]);
3442
+ }, [useStreamController, isUsingFallback, currentExecutionId, isLoading, startPolling, pollingEnabled]);
3223
3443
  const sseTimeoutRef = useRef(null);
3224
3444
  useEffect(() => {
3225
- if (!useStreamController && currentExecutionId && isLoading && !legacyIsConnected && !isUsingFallback) {
3445
+ if (!useStreamController && currentExecutionId && isLoading && !legacyIsConnected && !isUsingFallback && pollingEnabled !== false) {
3226
3446
  sseTimeoutRef.current = setTimeout(() => {
3227
3447
  if (!legacyIsConnected && currentExecutionId && isLoading) {
3228
- console.log("[useAgentChat] SSE connection timeout, activating polling fallback");
3448
+ if (__DEV__) console.log("[useAgentChat] SSE connection timeout, activating polling fallback");
3229
3449
  startPolling(currentExecutionId);
3230
3450
  }
3231
3451
  }, 1e4);
@@ -3236,7 +3456,7 @@ function useAgentChat(options) {
3236
3456
  sseTimeoutRef.current = null;
3237
3457
  }
3238
3458
  };
3239
- }, [useStreamController, currentExecutionId, isLoading, legacyIsConnected, isUsingFallback, startPolling]);
3459
+ }, [useStreamController, currentExecutionId, isLoading, legacyIsConnected, isUsingFallback, startPolling, pollingEnabled]);
3240
3460
  useEffect(() => {
3241
3461
  if (!currentExecutionId) {
3242
3462
  stopPolling();
@@ -3252,7 +3472,7 @@ function useAgentChat(options) {
3252
3472
  streamControllerRef.current.cancel();
3253
3473
  streamControllerRef.current = null;
3254
3474
  }
3255
- console.log("[useAgentChat] Creating stream controller for:", executionId);
3475
+ if (__DEV__) console.log("[useAgentChat] Creating stream controller for:", executionId);
3256
3476
  const controller = adapter.createStream(executionId, sessionId);
3257
3477
  streamControllerRef.current = controller;
3258
3478
  controller.on("log", (log) => {
@@ -3303,6 +3523,34 @@ function useAgentChat(options) {
3303
3523
  }
3304
3524
  firedToolResultsRef.current.add(toolCallId);
3305
3525
  onToolResultRef.current?.(toolName, data.result, data.durationMs);
3526
+ updateMessageImages();
3527
+ });
3528
+ controller.on("delegationStarted", (data) => {
3529
+ const delegation = {
3530
+ type: "delegation_started",
3531
+ handoffId: data.handoffId,
3532
+ toAgent: data.targetAgentName || data.targetAgentUuid,
3533
+ targetAgentUuid: data.targetAgentUuid,
3534
+ taskPreview: data.taskPreview,
3535
+ timestamp: new Date(data.timestamp),
3536
+ status: "active"
3537
+ };
3538
+ pendingDelegationsRef.current.set(data.handoffId, delegation);
3539
+ addDelegationEvent(delegation);
3540
+ onDelegationRef.current?.(delegation);
3541
+ });
3542
+ controller.on("delegationCompleted", (data) => {
3543
+ const delegation = {
3544
+ type: "delegation_completed",
3545
+ handoffId: data.handoffId,
3546
+ resultPreview: data.resultPreview,
3547
+ timestamp: new Date(data.timestamp),
3548
+ status: data.status === "failed" ? "failed" : "completed",
3549
+ durationMs: data.durationMs
3550
+ };
3551
+ pendingDelegationsRef.current.delete(data.handoffId);
3552
+ addDelegationEvent(delegation);
3553
+ onDelegationRef.current?.(delegation);
3306
3554
  });
3307
3555
  controller.on("textDelta", (data) => {
3308
3556
  streamingContentRef.current += data.delta;
@@ -3316,11 +3564,8 @@ function useAgentChat(options) {
3316
3564
  });
3317
3565
  });
3318
3566
  controller.on("complete", ({ execution }) => {
3319
- if (execution?.output && !streamingContentRef.current) {
3320
- streamingContentRef.current = execution.output;
3321
- updateStreamingMessage(execution.output);
3322
- }
3323
- handleComplete();
3567
+ const output = execution?.output || void 0;
3568
+ handleComplete(output);
3324
3569
  });
3325
3570
  controller.on("error", (errorEvent) => {
3326
3571
  handleError(errorEvent.error);
@@ -3334,7 +3579,7 @@ function useAgentChat(options) {
3334
3579
  });
3335
3580
  setIsStreamControllerConnected(true);
3336
3581
  },
3337
- [adapter, handleExecutionLog, updateStreamingMessage, updateToolCall, handleClarification, handleComplete, handleError]
3582
+ [adapter, handleExecutionLog, updateStreamingMessage, updateToolCall, updateMessageImages, addDelegationEvent, handleClarification, handleComplete, handleError]
3338
3583
  );
3339
3584
  const sendMessage = useCallback(
3340
3585
  async (content, options2) => {
@@ -3364,8 +3609,10 @@ function useAgentChat(options) {
3364
3609
  setMessages((prev) => [...prev, assistantMessage]);
3365
3610
  streamingMessageIdRef.current = assistantMessageId;
3366
3611
  streamingContentRef.current = "";
3612
+ completedRef.current = false;
3613
+ finalizedRef.current = false;
3367
3614
  try {
3368
- console.log("[useAgentChat] Starting execution...", { agentId, sessionId: currentSessionId });
3615
+ if (__DEV__) console.log("[useAgentChat] Starting execution...", { agentId, sessionId: currentSessionId });
3369
3616
  const result = await adapter.startExecution({
3370
3617
  agentId,
3371
3618
  teamId,
@@ -3373,7 +3620,7 @@ function useAgentChat(options) {
3373
3620
  content: content.trim(),
3374
3621
  attachmentUuids
3375
3622
  });
3376
- console.log("[useAgentChat] Execution started:", result);
3623
+ if (__DEV__) console.log("[useAgentChat] Execution started:", result);
3377
3624
  if (!currentSessionId && result.sessionId) {
3378
3625
  internallyCreatedSessionRef.current = result.sessionId;
3379
3626
  setCurrentSessionId(result.sessionId);
@@ -3384,7 +3631,7 @@ function useAgentChat(options) {
3384
3631
  connectStreamController(result.executionId, result.sessionId || currentSessionId || void 0);
3385
3632
  setCurrentExecutionId(result.executionId);
3386
3633
  } else {
3387
- console.log("[useAgentChat] Setting executionId:", result.executionId);
3634
+ if (__DEV__) console.log("[useAgentChat] Setting executionId:", result.executionId);
3388
3635
  setCurrentExecutionId(result.executionId);
3389
3636
  }
3390
3637
  } catch (err) {
@@ -3444,6 +3691,7 @@ function useAgentChat(options) {
3444
3691
  setMessages([]);
3445
3692
  setCurrentSessionId(null);
3446
3693
  hasLoadedInitialSession.current = false;
3694
+ lastLoadedSessionRef.current = null;
3447
3695
  internallyCreatedSessionRef.current = null;
3448
3696
  }, []);
3449
3697
  const loadSession = useCallback(
@@ -3539,15 +3787,20 @@ function useAgentChat(options) {
3539
3787
  },
3540
3788
  [adapter, onError]
3541
3789
  );
3790
+ const lastLoadedSessionRef = useRef(null);
3542
3791
  useEffect(() => {
3543
- if (initialSessionId && !hasLoadedInitialSession.current) {
3544
- if (internallyCreatedSessionRef.current === initialSessionId) {
3545
- hasLoadedInitialSession.current = true;
3546
- return;
3547
- }
3792
+ if (!initialSessionId) return;
3793
+ if (internallyCreatedSessionRef.current === initialSessionId) {
3794
+ lastLoadedSessionRef.current = initialSessionId;
3548
3795
  hasLoadedInitialSession.current = true;
3549
- loadSession(initialSessionId);
3796
+ return;
3797
+ }
3798
+ if (lastLoadedSessionRef.current === initialSessionId && hasLoadedInitialSession.current) {
3799
+ return;
3550
3800
  }
3801
+ lastLoadedSessionRef.current = initialSessionId;
3802
+ hasLoadedInitialSession.current = true;
3803
+ loadSession(initialSessionId);
3551
3804
  }, [initialSessionId, loadSession]);
3552
3805
  useEffect(() => {
3553
3806
  return () => {
@@ -3563,6 +3816,16 @@ function useAgentChat(options) {
3563
3816
  }
3564
3817
  return !!currentExecutionId && legacyIsConnected;
3565
3818
  }, [useStreamController, currentExecutionId, isStreamControllerConnected, legacyIsConnected]);
3819
+ const activeDelegation = useMemo(() => {
3820
+ for (let i = messages.length - 1; i >= 0; i--) {
3821
+ const msg = messages[i];
3822
+ if (msg.delegationEvents) {
3823
+ const active = msg.delegationEvents.find((de) => de.status === "active");
3824
+ if (active) return active;
3825
+ }
3826
+ }
3827
+ return null;
3828
+ }, [messages]);
3566
3829
  return {
3567
3830
  messages,
3568
3831
  isLoading,
@@ -3571,6 +3834,7 @@ function useAgentChat(options) {
3571
3834
  error,
3572
3835
  sessionId: currentSessionId,
3573
3836
  clarification,
3837
+ activeDelegation,
3574
3838
  sendMessage,
3575
3839
  respondToClarification,
3576
3840
  cancel,
@@ -3762,6 +4026,24 @@ function useFileAttachments(options) {
3762
4026
  console.log("[useFileAttachments] prepareForSubmit result:", aiUuids);
3763
4027
  return aiUuids;
3764
4028
  }, [onSubmitUpload, onError]);
4029
+ const addExternalFile = useCallback(
4030
+ (opts) => {
4031
+ const category = opts.category || (opts.mimeType.startsWith("image/") ? "image" : "document");
4032
+ const placeholderFile = new File([], opts.filename, { type: opts.mimeType });
4033
+ const newAttachment = {
4034
+ uuid: opts.uuid,
4035
+ file: placeholderFile,
4036
+ status: "ready",
4037
+ progress: 100,
4038
+ category,
4039
+ previewUrl: opts.previewUrl,
4040
+ hasThumbnail: category === "image",
4041
+ actualSize: opts.size
4042
+ };
4043
+ setFiles((prev) => [...prev, newAttachment]);
4044
+ },
4045
+ []
4046
+ );
3765
4047
  const clear = useCallback(() => {
3766
4048
  for (const file of filesRef.current) {
3767
4049
  if (file.previewUrl) {
@@ -3787,6 +4069,7 @@ function useFileAttachments(options) {
3787
4069
  files,
3788
4070
  dropZoneProps,
3789
4071
  removeFile,
4072
+ addExternalFile,
3790
4073
  getReadyUuids,
3791
4074
  getReadyUrls,
3792
4075
  prepareForSubmit,
@@ -4426,18 +4709,30 @@ function ChatContainer({
4426
4709
  children,
4427
4710
  maxHeight = "600px",
4428
4711
  className,
4429
- theme = "system"
4712
+ theme = "system",
4713
+ layout = "fixed"
4430
4714
  }) {
4431
4715
  const maxHeightValue = typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight;
4716
+ const isFill = layout === "fill";
4432
4717
  return /* @__PURE__ */ jsx(
4433
4718
  "div",
4434
4719
  {
4435
4720
  className: cn2(
4436
- "flex flex-col bg-white dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden",
4721
+ "cadra-chat-container flex flex-col overflow-hidden",
4722
+ // Default colors use CSS custom properties with Tailwind fallbacks.
4723
+ // Consumers can override via CSS: --chat-bg, --chat-border, --chat-border-radius
4724
+ !isFill && "rounded-lg border",
4725
+ isFill && "flex-1 min-h-0",
4437
4726
  className
4438
4727
  ),
4439
- style: { maxHeight: maxHeightValue },
4728
+ style: {
4729
+ ...!isFill ? { maxHeight: maxHeightValue } : void 0,
4730
+ // CSS custom properties for theming — consumers set these to override
4731
+ backgroundColor: "var(--chat-bg, var(--background, #fff))",
4732
+ borderColor: !isFill ? "var(--chat-border, var(--border, #e5e7eb))" : void 0
4733
+ },
4440
4734
  "data-theme": theme,
4735
+ "data-layout": layout,
4441
4736
  children
4442
4737
  }
4443
4738
  );
@@ -5124,7 +5419,7 @@ var FileDropZone = forwardRef(
5124
5419
  {
5125
5420
  ref: dropZoneRef,
5126
5421
  "data-dropzone": "wrapper",
5127
- className: cn4("relative w-full h-full", className),
5422
+ className: cn4("relative flex flex-col flex-1 min-h-0", className),
5128
5423
  style: { minHeight: "inherit" },
5129
5424
  children: [
5130
5425
  /* @__PURE__ */ jsx(
@@ -5409,6 +5704,380 @@ function AskUserPrompt({
5409
5704
  function cn6(...classes) {
5410
5705
  return classes.filter(Boolean).join(" ");
5411
5706
  }
5707
+ function formatDuration(ms) {
5708
+ if (ms < 1e3) return `${ms}ms`;
5709
+ return `${(ms / 1e3).toFixed(1)}s`;
5710
+ }
5711
+ function DelegationProgress({
5712
+ event,
5713
+ className
5714
+ }) {
5715
+ const statusIcon = useMemo(() => {
5716
+ switch (event.status) {
5717
+ case "active":
5718
+ return /* @__PURE__ */ jsx(LoadingSpinner, { className: "h-4 w-4 text-blue-500" });
5719
+ case "completed":
5720
+ return /* @__PURE__ */ jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-500" });
5721
+ case "failed":
5722
+ return /* @__PURE__ */ jsx(AlertCircleIcon, { className: "h-4 w-4 text-red-500" });
5723
+ default:
5724
+ return /* @__PURE__ */ jsx(LoadingSpinner, { className: "h-4 w-4 text-gray-400" });
5725
+ }
5726
+ }, [event.status]);
5727
+ const statusColor = useMemo(() => {
5728
+ switch (event.status) {
5729
+ case "active":
5730
+ return "border-blue-200 dark:border-blue-800 bg-blue-50/50 dark:bg-blue-950/20";
5731
+ case "completed":
5732
+ return "border-green-200 dark:border-green-800 bg-green-50/50 dark:bg-green-950/20";
5733
+ case "failed":
5734
+ return "border-red-200 dark:border-red-800 bg-red-50/50 dark:bg-red-950/20";
5735
+ default:
5736
+ return "border-gray-200 dark:border-gray-700";
5737
+ }
5738
+ }, [event.status]);
5739
+ return /* @__PURE__ */ jsx(
5740
+ "div",
5741
+ {
5742
+ className: cn6(
5743
+ "rounded-lg border text-sm px-3 py-2",
5744
+ statusColor,
5745
+ className
5746
+ ),
5747
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
5748
+ statusIcon,
5749
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
5750
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
5751
+ event.fromAgent && /* @__PURE__ */ jsxs(Fragment, { children: [
5752
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700 dark:text-gray-300 truncate", children: event.fromAgent }),
5753
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400 dark:text-gray-500 flex-shrink-0", children: "\u2192" })
5754
+ ] }),
5755
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-900 dark:text-gray-100 truncate", children: event.toAgent || event.targetAgentUuid || "Specialist" })
5756
+ ] }),
5757
+ event.taskPreview && event.status === "active" && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 truncate mt-0.5", children: event.taskPreview }),
5758
+ event.resultPreview && event.status === "completed" && /* @__PURE__ */ jsx("p", { className: "text-xs text-green-600 dark:text-green-400 truncate mt-0.5", children: event.resultPreview })
5759
+ ] }),
5760
+ event.durationMs !== void 0 && event.status !== "active" && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400 flex-shrink-0", children: formatDuration(event.durationMs) })
5761
+ ] })
5762
+ }
5763
+ );
5764
+ }
5765
+ function DelegationProgressList({
5766
+ events,
5767
+ className
5768
+ }) {
5769
+ if (!events || events.length === 0) return null;
5770
+ return /* @__PURE__ */ jsx("div", { className: cn6("space-y-2", className), children: events.map((event, index) => /* @__PURE__ */ jsx(
5771
+ DelegationProgress,
5772
+ {
5773
+ event
5774
+ },
5775
+ event.handoffId || `delegation-${index}`
5776
+ )) });
5777
+ }
5778
+ function ImageLightbox({
5779
+ images,
5780
+ currentIndex,
5781
+ onClose,
5782
+ onPrev,
5783
+ onNext,
5784
+ className
5785
+ }) {
5786
+ const currentImage = images[currentIndex];
5787
+ const hasMultiple = images.length > 1;
5788
+ const [container, setContainer] = useState(null);
5789
+ useEffect(() => {
5790
+ const el = document.createElement("div");
5791
+ el.id = "cadra-lightbox-root";
5792
+ el.style.position = "fixed";
5793
+ el.style.inset = "0";
5794
+ el.style.zIndex = "999999";
5795
+ el.style.pointerEvents = "auto";
5796
+ document.body.appendChild(el);
5797
+ setContainer(el);
5798
+ return () => {
5799
+ document.body.removeChild(el);
5800
+ };
5801
+ }, []);
5802
+ const onCloseRef = useRef(onClose);
5803
+ const onPrevRef = useRef(onPrev);
5804
+ const onNextRef = useRef(onNext);
5805
+ onCloseRef.current = onClose;
5806
+ onPrevRef.current = onPrev;
5807
+ onNextRef.current = onNext;
5808
+ useEffect(() => {
5809
+ function handleKeyDown(e) {
5810
+ switch (e.key) {
5811
+ case "Escape":
5812
+ e.preventDefault();
5813
+ e.stopPropagation();
5814
+ onCloseRef.current();
5815
+ break;
5816
+ case "ArrowLeft":
5817
+ if (hasMultiple) onPrevRef.current();
5818
+ break;
5819
+ case "ArrowRight":
5820
+ if (hasMultiple) onNextRef.current();
5821
+ break;
5822
+ }
5823
+ }
5824
+ document.addEventListener("keydown", handleKeyDown, true);
5825
+ return () => document.removeEventListener("keydown", handleKeyDown, true);
5826
+ }, [hasMultiple]);
5827
+ useEffect(() => {
5828
+ const originalOverflow = document.body.style.overflow;
5829
+ document.body.style.overflow = "hidden";
5830
+ return () => {
5831
+ document.body.style.overflow = originalOverflow;
5832
+ };
5833
+ }, []);
5834
+ useEffect(() => {
5835
+ if (!container) return;
5836
+ function handleClick(e) {
5837
+ const target = e.target;
5838
+ if (target.dataset.lightboxBackdrop === "true") {
5839
+ e.preventDefault();
5840
+ e.stopPropagation();
5841
+ onCloseRef.current();
5842
+ }
5843
+ }
5844
+ container.addEventListener("click", handleClick, true);
5845
+ return () => container.removeEventListener("click", handleClick, true);
5846
+ }, [container]);
5847
+ const handleDownload = useCallback(async () => {
5848
+ if (!currentImage) return;
5849
+ const filename = currentImage.filename || `image-${currentIndex + 1}`;
5850
+ try {
5851
+ const response = await fetch(currentImage.url);
5852
+ const blob = await response.blob();
5853
+ const blobUrl = URL.createObjectURL(blob);
5854
+ const link = document.createElement("a");
5855
+ link.href = blobUrl;
5856
+ link.download = filename;
5857
+ document.body.appendChild(link);
5858
+ link.click();
5859
+ document.body.removeChild(link);
5860
+ URL.revokeObjectURL(blobUrl);
5861
+ } catch {
5862
+ window.open(currentImage.url, "_blank");
5863
+ }
5864
+ }, [currentImage, currentIndex]);
5865
+ const handleClose = useCallback(() => {
5866
+ onCloseRef.current();
5867
+ }, []);
5868
+ if (!currentImage || !container) return null;
5869
+ return createPortal(
5870
+ /* @__PURE__ */ jsxs(
5871
+ "div",
5872
+ {
5873
+ "data-lightbox-backdrop": "true",
5874
+ className: `absolute inset-0 flex items-center justify-center bg-black/90 ${className || ""}`,
5875
+ style: { cursor: "zoom-out" },
5876
+ children: [
5877
+ /* @__PURE__ */ jsxs(
5878
+ "div",
5879
+ {
5880
+ className: "absolute top-0 left-0 right-0 flex items-center justify-between p-4",
5881
+ style: { zIndex: 10 },
5882
+ children: [
5883
+ /* @__PURE__ */ jsx("div", { className: "text-white text-sm", children: hasMultiple && /* @__PURE__ */ jsxs("span", { children: [
5884
+ currentIndex + 1,
5885
+ " / ",
5886
+ images.length
5887
+ ] }) }),
5888
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
5889
+ /* @__PURE__ */ jsx(
5890
+ "button",
5891
+ {
5892
+ type: "button",
5893
+ onClick: (e) => {
5894
+ e.stopPropagation();
5895
+ handleDownload();
5896
+ },
5897
+ className: "p-2 rounded-full bg-white/10 hover:bg-white/20 text-white transition-colors",
5898
+ style: { cursor: "pointer", pointerEvents: "auto" },
5899
+ "aria-label": "Download image",
5900
+ children: /* @__PURE__ */ jsx(DownloadIcon, { className: "h-5 w-5" })
5901
+ }
5902
+ ),
5903
+ /* @__PURE__ */ jsx(
5904
+ "button",
5905
+ {
5906
+ type: "button",
5907
+ onClick: (e) => {
5908
+ e.stopPropagation();
5909
+ handleClose();
5910
+ },
5911
+ className: "p-2 rounded-full bg-white/10 hover:bg-white/20 text-white transition-colors",
5912
+ style: { cursor: "pointer", pointerEvents: "auto" },
5913
+ "aria-label": "Close lightbox",
5914
+ children: /* @__PURE__ */ jsx(XIcon, { className: "h-5 w-5" })
5915
+ }
5916
+ )
5917
+ ] })
5918
+ ]
5919
+ }
5920
+ ),
5921
+ hasMultiple && /* @__PURE__ */ jsx(
5922
+ "button",
5923
+ {
5924
+ type: "button",
5925
+ onClick: (e) => {
5926
+ e.stopPropagation();
5927
+ onPrev();
5928
+ },
5929
+ className: "absolute left-4 top-1/2 -translate-y-1/2 p-2 rounded-full bg-white/10 hover:bg-white/20 text-white transition-colors",
5930
+ style: { zIndex: 10, cursor: "pointer", pointerEvents: "auto" },
5931
+ "aria-label": "Previous image",
5932
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "h-6 w-6" })
5933
+ }
5934
+ ),
5935
+ /* @__PURE__ */ jsx(
5936
+ "img",
5937
+ {
5938
+ src: currentImage.url,
5939
+ alt: currentImage.alt || `Image ${currentIndex + 1}`,
5940
+ className: "max-w-[90vw] max-h-[85vh] object-contain select-none",
5941
+ style: { cursor: "default", pointerEvents: "auto" },
5942
+ draggable: false
5943
+ }
5944
+ ),
5945
+ hasMultiple && /* @__PURE__ */ jsx(
5946
+ "button",
5947
+ {
5948
+ type: "button",
5949
+ onClick: (e) => {
5950
+ e.stopPropagation();
5951
+ onNext();
5952
+ },
5953
+ className: "absolute right-4 top-1/2 -translate-y-1/2 p-2 rounded-full bg-white/10 hover:bg-white/20 text-white transition-colors",
5954
+ style: { zIndex: 10, cursor: "pointer", pointerEvents: "auto" },
5955
+ "aria-label": "Next image",
5956
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-6 w-6" })
5957
+ }
5958
+ ),
5959
+ currentImage.alt && /* @__PURE__ */ jsx(
5960
+ "div",
5961
+ {
5962
+ className: "absolute bottom-0 left-0 right-0 p-4 text-center",
5963
+ style: { zIndex: 10, pointerEvents: "none" },
5964
+ children: /* @__PURE__ */ jsx("p", { className: "text-white text-sm bg-black/50 inline-block px-3 py-1 rounded-full", children: currentImage.alt })
5965
+ }
5966
+ )
5967
+ ]
5968
+ }
5969
+ ),
5970
+ container
5971
+ );
5972
+ }
5973
+ function cn7(...classes) {
5974
+ return classes.filter(Boolean).join(" ");
5975
+ }
5976
+ function ImageWithLoading({ src, alt, className, onClick }) {
5977
+ const [isLoaded, setIsLoaded] = useState(false);
5978
+ const [hasError, setHasError] = useState(false);
5979
+ return /* @__PURE__ */ jsxs(
5980
+ "div",
5981
+ {
5982
+ className: cn7(
5983
+ "relative overflow-hidden rounded-lg",
5984
+ className
5985
+ ),
5986
+ children: [
5987
+ !isLoaded && !hasError && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 animate-pulse bg-gray-200 dark:bg-gray-700 rounded-lg" }),
5988
+ hasError && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-gray-400 dark:text-gray-500 text-sm rounded-lg bg-gray-100 dark:bg-gray-800", children: "Failed to load" }),
5989
+ /* @__PURE__ */ jsx(
5990
+ "img",
5991
+ {
5992
+ src,
5993
+ alt,
5994
+ loading: "lazy",
5995
+ className: cn7(
5996
+ "w-full h-auto max-h-[280px] object-cover rounded-lg shadow-sm transition-opacity duration-200",
5997
+ isLoaded ? "opacity-100" : "opacity-0"
5998
+ ),
5999
+ onLoad: () => setIsLoaded(true),
6000
+ onError: () => setHasError(true),
6001
+ onClick,
6002
+ style: onClick ? { cursor: "pointer" } : void 0
6003
+ }
6004
+ )
6005
+ ]
6006
+ }
6007
+ );
6008
+ }
6009
+ function ImageGallery({
6010
+ images,
6011
+ onImageClick,
6012
+ className
6013
+ }) {
6014
+ const [lightboxIndex, setLightboxIndex] = useState(null);
6015
+ const handleImageClick = useCallback(
6016
+ (image, index) => {
6017
+ if (onImageClick) {
6018
+ onImageClick(image);
6019
+ } else {
6020
+ setLightboxIndex(index);
6021
+ }
6022
+ },
6023
+ [onImageClick]
6024
+ );
6025
+ const handleLightboxClose = useCallback(() => {
6026
+ setLightboxIndex(null);
6027
+ }, []);
6028
+ const handleLightboxPrev = useCallback(() => {
6029
+ setLightboxIndex(
6030
+ (prev) => prev !== null ? (prev - 1 + images.length) % images.length : null
6031
+ );
6032
+ }, [images.length]);
6033
+ const handleLightboxNext = useCallback(() => {
6034
+ setLightboxIndex(
6035
+ (prev) => prev !== null ? (prev + 1) % images.length : null
6036
+ );
6037
+ }, [images.length]);
6038
+ if (!images || images.length === 0) return null;
6039
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6040
+ /* @__PURE__ */ jsx(
6041
+ "div",
6042
+ {
6043
+ className: cn7(
6044
+ "grid gap-2",
6045
+ images.length === 1 ? "grid-cols-1" : images.length === 2 ? "grid-cols-2" : "grid-cols-2 sm:grid-cols-3",
6046
+ className
6047
+ ),
6048
+ children: images.map((image, index) => /* @__PURE__ */ jsx(
6049
+ "button",
6050
+ {
6051
+ type: "button",
6052
+ onClick: () => handleImageClick(image, index),
6053
+ className: "block rounded-lg overflow-hidden transition-transform hover:scale-[1.02] text-left",
6054
+ children: /* @__PURE__ */ jsx(
6055
+ ImageWithLoading,
6056
+ {
6057
+ src: image.url,
6058
+ alt: image.alt || `Image ${index + 1}`
6059
+ }
6060
+ )
6061
+ },
6062
+ `${image.url}-${index}`
6063
+ ))
6064
+ }
6065
+ ),
6066
+ lightboxIndex !== null && !onImageClick && /* @__PURE__ */ jsx(
6067
+ ImageLightbox,
6068
+ {
6069
+ images,
6070
+ currentIndex: lightboxIndex,
6071
+ onClose: handleLightboxClose,
6072
+ onPrev: handleLightboxPrev,
6073
+ onNext: handleLightboxNext
6074
+ }
6075
+ )
6076
+ ] });
6077
+ }
6078
+ function cn8(...classes) {
6079
+ return classes.filter(Boolean).join(" ");
6080
+ }
5412
6081
  function MarkdownContent({
5413
6082
  content,
5414
6083
  className,
@@ -5428,11 +6097,11 @@ function MarkdownContent({
5428
6097
  h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mt-3 mb-1 first:mt-0", children }),
5429
6098
  h4: ({ children }) => /* @__PURE__ */ jsx("h4", { className: "text-base font-semibold mt-2 mb-1 first:mt-0", children }),
5430
6099
  // Paragraphs
5431
- p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "mb-2 last:mb-0 leading-relaxed", children }),
6100
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "mb-1.5 last:mb-0", children }),
5432
6101
  // Lists
5433
- ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside mb-2 space-y-1", children }),
5434
- ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "list-decimal list-inside mb-2 space-y-1", children }),
5435
- li: ({ children }) => /* @__PURE__ */ jsx("li", { className: "leading-relaxed", children }),
6102
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside mb-1.5 last:mb-0", children }),
6103
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "list-decimal list-inside mb-1.5 last:mb-0", children }),
6104
+ li: ({ children }) => /* @__PURE__ */ jsx("li", { className: "", children }),
5436
6105
  // Links
5437
6106
  a: ({ href, children }) => /* @__PURE__ */ jsx(
5438
6107
  "a",
@@ -5467,7 +6136,7 @@ function MarkdownContent({
5467
6136
  if (isCodeBlock) {
5468
6137
  return /* @__PURE__ */ jsxs("div", { className: "relative my-2", children: [
5469
6138
  language && /* @__PURE__ */ jsx("div", { className: "absolute top-0 right-0 px-2 py-1 text-xs font-mono text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-800 rounded-bl rounded-tr border-b border-l border-gray-200 dark:border-gray-700", children: language }),
5470
- /* @__PURE__ */ jsx("pre", { className: "bg-gray-100 dark:bg-gray-800 rounded-lg p-4 overflow-x-auto text-sm", children: /* @__PURE__ */ jsx("code", { className: cn6("font-mono", codeClassName), ...props, children }) })
6139
+ /* @__PURE__ */ jsx("pre", { className: "bg-gray-100 dark:bg-gray-800 rounded-lg p-4 overflow-x-auto text-sm", children: /* @__PURE__ */ jsx("code", { className: cn8("font-mono", codeClassName), ...props, children }) })
5471
6140
  ] });
5472
6141
  }
5473
6142
  return /* @__PURE__ */ jsx(
@@ -5514,7 +6183,7 @@ function MarkdownContent({
5514
6183
  () => customComponents ? { ...defaultComponents, ...customComponents } : defaultComponents,
5515
6184
  [defaultComponents, customComponents]
5516
6185
  );
5517
- return /* @__PURE__ */ jsx("div", { className: cn6("prose prose-sm dark:prose-invert max-w-none", className), children: /* @__PURE__ */ jsx(
6186
+ return /* @__PURE__ */ jsx("div", { className: cn8("max-w-none text-sm leading-relaxed", className), children: /* @__PURE__ */ jsx(
5518
6187
  ReactMarkdown,
5519
6188
  {
5520
6189
  remarkPlugins: [remarkGfm],
@@ -5524,6 +6193,58 @@ function MarkdownContent({
5524
6193
  }
5525
6194
  ) });
5526
6195
  }
6196
+ function cn9(...classes) {
6197
+ return classes.filter(Boolean).join(" ");
6198
+ }
6199
+ function ThinkingBlock({
6200
+ block,
6201
+ defaultExpanded = false,
6202
+ className
6203
+ }) {
6204
+ const [isExpanded, setIsExpanded] = useState(defaultExpanded);
6205
+ return /* @__PURE__ */ jsxs(
6206
+ "div",
6207
+ {
6208
+ className: cn9(
6209
+ "rounded-lg border",
6210
+ "border-purple-200 dark:border-purple-800",
6211
+ "bg-purple-50/50 dark:bg-purple-950/20",
6212
+ className
6213
+ ),
6214
+ children: [
6215
+ /* @__PURE__ */ jsxs(
6216
+ "button",
6217
+ {
6218
+ type: "button",
6219
+ onClick: () => setIsExpanded(!isExpanded),
6220
+ className: "w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-purple-100/50 dark:hover:bg-purple-900/30 transition-colors rounded-lg",
6221
+ children: [
6222
+ isExpanded ? /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4 text-purple-400 flex-shrink-0" }) : /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-4 w-4 text-purple-400 flex-shrink-0" }),
6223
+ /* @__PURE__ */ jsx(SparklesIcon, { className: "h-4 w-4 text-purple-500 flex-shrink-0" }),
6224
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-purple-700 dark:text-purple-300", children: "Thinking" })
6225
+ ]
6226
+ }
6227
+ ),
6228
+ isExpanded && /* @__PURE__ */ jsx("div", { className: "px-3 pb-3 border-t border-purple-200 dark:border-purple-800", children: /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-purple-800 dark:text-purple-200 whitespace-pre-wrap font-mono leading-relaxed", children: block.content }) })
6229
+ ]
6230
+ }
6231
+ );
6232
+ }
6233
+ function ThinkingBlockList({
6234
+ blocks,
6235
+ defaultExpanded = false,
6236
+ className
6237
+ }) {
6238
+ if (!blocks || blocks.length === 0) return null;
6239
+ return /* @__PURE__ */ jsx("div", { className: cn9("space-y-2", className), children: blocks.map((block) => /* @__PURE__ */ jsx(
6240
+ ThinkingBlock,
6241
+ {
6242
+ block,
6243
+ defaultExpanded
6244
+ },
6245
+ block.id
6246
+ )) });
6247
+ }
5527
6248
  var INTERNAL_TOOL_NAMES = /* @__PURE__ */ new Set([
5528
6249
  "update_task_list",
5529
6250
  "create_task",
@@ -5540,7 +6261,8 @@ var INTERNAL_TOOL_NAMES = /* @__PURE__ */ new Set([
5540
6261
  "check_task_status",
5541
6262
  "assign_task",
5542
6263
  "update_plan",
5543
- "check_delegations"
6264
+ "check_delegations",
6265
+ "activate_skill"
5544
6266
  ]);
5545
6267
  function isInternalTool(toolName) {
5546
6268
  if (!toolName) return false;
@@ -5554,11 +6276,20 @@ function isInternalTool(toolName) {
5554
6276
  }
5555
6277
  return false;
5556
6278
  }
5557
- function cn7(...classes) {
6279
+ function cn10(...classes) {
5558
6280
  return classes.filter(Boolean).join(" ");
5559
6281
  }
5560
6282
  function formatToolName(toolName) {
5561
6283
  if (!toolName) return toolName;
6284
+ if (toolName.includes(".")) {
6285
+ const segments = toolName.split(".");
6286
+ const uniqueSegments = segments.filter(
6287
+ (seg, idx) => idx === 0 || seg.toLowerCase().trim() !== segments[idx - 1]?.toLowerCase().trim()
6288
+ );
6289
+ const bestSegment = uniqueSegments[uniqueSegments.length - 1]?.trim() || toolName;
6290
+ if (bestSegment.includes(" ")) return bestSegment;
6291
+ return formatToolName(bestSegment);
6292
+ }
5562
6293
  const prefixesToRemove = [
5563
6294
  "skills_api_",
5564
6295
  "tools_api_",
@@ -5603,7 +6334,7 @@ function formatToolName(toolName) {
5603
6334
  }
5604
6335
  return uniqueWords.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
5605
6336
  }
5606
- function formatDuration(ms) {
6337
+ function formatDuration2(ms) {
5607
6338
  if (ms < 1e3) {
5608
6339
  return `${ms}ms`;
5609
6340
  }
@@ -5624,7 +6355,7 @@ function formatJsonPreview(data, maxLength = 100) {
5624
6355
  return String(data);
5625
6356
  }
5626
6357
  }
5627
- function extractImagesFromResult(result) {
6358
+ function extractImagesFromResult2(result) {
5628
6359
  if (!result) return [];
5629
6360
  let data = result;
5630
6361
  if (typeof result === "string") {
@@ -5663,14 +6394,23 @@ function ToolCallEntry({
5663
6394
  compact = false
5664
6395
  }) {
5665
6396
  const [isExpanded, setIsExpanded] = useState(false);
6397
+ const [lightboxIndex, setLightboxIndex] = useState(null);
5666
6398
  const formattedName = useMemo(
5667
6399
  () => formatToolName(toolCall.name),
5668
6400
  [toolCall.name]
5669
6401
  );
5670
6402
  const resultImages = useMemo(
5671
- () => toolCall.status === "completed" && toolCall.result ? extractImagesFromResult(toolCall.result) : [],
6403
+ () => toolCall.status === "completed" && toolCall.result ? extractImagesFromResult2(toolCall.result) : [],
5672
6404
  [toolCall.status, toolCall.result]
5673
6405
  );
6406
+ const lightboxImages = useMemo(
6407
+ () => resultImages.map((img) => ({
6408
+ url: img.url,
6409
+ alt: img.alt || img.prompt,
6410
+ filename: img.alt || img.prompt
6411
+ })),
6412
+ [resultImages]
6413
+ );
5674
6414
  const hasImages = resultImages.length > 0;
5675
6415
  const statusIcon = useMemo(() => {
5676
6416
  switch (toolCall.status) {
@@ -5704,14 +6444,14 @@ function ToolCallEntry({
5704
6444
  return /* @__PURE__ */ jsxs(
5705
6445
  "div",
5706
6446
  {
5707
- className: cn7(
6447
+ className: cn10(
5708
6448
  "inline-flex items-center gap-1.5 text-xs text-gray-500 dark:text-gray-400",
5709
6449
  className
5710
6450
  ),
5711
6451
  children: [
5712
6452
  /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: statusIcon }),
5713
6453
  /* @__PURE__ */ jsx("span", { children: formattedName }),
5714
- toolCall.durationMs !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-gray-400 dark:text-gray-500", children: formatDuration(toolCall.durationMs) })
6454
+ toolCall.durationMs !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-gray-400 dark:text-gray-500", children: formatDuration2(toolCall.durationMs) })
5715
6455
  ]
5716
6456
  }
5717
6457
  );
@@ -5719,7 +6459,7 @@ function ToolCallEntry({
5719
6459
  return /* @__PURE__ */ jsxs(
5720
6460
  "div",
5721
6461
  {
5722
- className: cn7(
6462
+ className: cn10(
5723
6463
  "rounded-lg border text-sm",
5724
6464
  statusColor,
5725
6465
  className
@@ -5735,52 +6475,61 @@ function ToolCallEntry({
5735
6475
  isExpanded ? /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4 text-gray-400 flex-shrink-0" }) : /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-4 w-4 text-gray-400 flex-shrink-0" }),
5736
6476
  /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: statusIcon }),
5737
6477
  /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-900 dark:text-gray-100 truncate", children: formattedName }),
5738
- toolCall.status === "completed" && toolCall.durationMs !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-gray-500 dark:text-gray-400 flex-shrink-0", children: formatDuration(toolCall.durationMs) }),
6478
+ toolCall.status === "completed" && toolCall.durationMs !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-gray-500 dark:text-gray-400 flex-shrink-0", children: formatDuration2(toolCall.durationMs) }),
5739
6479
  toolCall.status === "failed" && toolCall.error && /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-red-600 dark:text-red-400 truncate max-w-[150px]", children: toolCall.error })
5740
6480
  ]
5741
6481
  }
5742
6482
  ),
5743
- hasImages && /* @__PURE__ */ jsx("div", { className: "px-3 pb-2", children: /* @__PURE__ */ jsx("div", { className: cn7(
5744
- "grid gap-2",
5745
- resultImages.length === 1 ? "grid-cols-1" : "grid-cols-2"
5746
- ), children: resultImages.map((img, idx) => {
5747
- const altText = img.alt || img.prompt || `Generated image ${idx + 1}`;
5748
- const imageElement = /* @__PURE__ */ jsxs(Fragment, { children: [
5749
- /* @__PURE__ */ jsx(
5750
- "img",
5751
- {
5752
- src: img.thumbnailUrl || img.url,
5753
- alt: altText,
5754
- className: "w-full h-auto max-h-[300px] object-contain bg-gray-50 dark:bg-gray-900",
5755
- loading: "lazy"
5756
- }
5757
- ),
5758
- img.prompt && /* @__PURE__ */ jsx("div", { className: "px-2 py-1 text-xs text-gray-500 dark:text-gray-400 truncate bg-gray-50 dark:bg-gray-800 border-t border-gray-200 dark:border-gray-700", children: img.prompt })
5759
- ] });
5760
- if (onImageClick) {
6483
+ hasImages && /* @__PURE__ */ jsxs("div", { className: "px-3 pb-3", children: [
6484
+ /* @__PURE__ */ jsx("div", { className: cn10(
6485
+ "grid gap-3",
6486
+ resultImages.length === 1 ? "grid-cols-1 max-w-sm" : resultImages.length === 2 ? "grid-cols-2" : "grid-cols-2 sm:grid-cols-3"
6487
+ ), children: resultImages.map((img, idx) => {
6488
+ const altText = img.alt || img.prompt || `Generated image ${idx + 1}`;
6489
+ const imageElement = /* @__PURE__ */ jsxs("div", { className: "group relative", children: [
6490
+ /* @__PURE__ */ jsx(
6491
+ "img",
6492
+ {
6493
+ src: img.thumbnailUrl || img.url,
6494
+ alt: altText,
6495
+ className: "w-full h-auto max-h-[280px] object-cover rounded-lg shadow-sm",
6496
+ loading: "lazy"
6497
+ }
6498
+ ),
6499
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-lg bg-black/0 group-hover:bg-black/10 dark:group-hover:bg-white/5 transition-colors" })
6500
+ ] });
5761
6501
  return /* @__PURE__ */ jsx(
5762
6502
  "button",
5763
6503
  {
5764
6504
  type: "button",
5765
- onClick: () => onImageClick({ url: img.url, alt: altText, filename: altText }),
5766
- className: "block rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700 hover:border-blue-400 dark:hover:border-blue-600 transition-colors cursor-pointer text-left",
6505
+ onClick: () => {
6506
+ if (onImageClick) {
6507
+ onImageClick({ url: img.url, alt: altText, filename: altText });
6508
+ } else {
6509
+ setLightboxIndex(idx);
6510
+ }
6511
+ },
6512
+ className: "block rounded-lg overflow-hidden cursor-pointer text-left transition-transform hover:scale-[1.02]",
5767
6513
  children: imageElement
5768
6514
  },
5769
6515
  idx
5770
6516
  );
5771
- }
5772
- return /* @__PURE__ */ jsx(
5773
- "a",
6517
+ }) }),
6518
+ lightboxIndex !== null && !onImageClick && /* @__PURE__ */ jsx(
6519
+ ImageLightbox,
5774
6520
  {
5775
- href: img.url,
5776
- target: "_blank",
5777
- rel: "noopener noreferrer",
5778
- className: "block rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700 hover:border-blue-400 dark:hover:border-blue-600 transition-colors",
5779
- children: imageElement
5780
- },
5781
- idx
5782
- );
5783
- }) }) }),
6521
+ images: lightboxImages,
6522
+ currentIndex: lightboxIndex,
6523
+ onClose: () => setLightboxIndex(null),
6524
+ onPrev: () => setLightboxIndex(
6525
+ (prev) => prev !== null ? (prev - 1 + lightboxImages.length) % lightboxImages.length : null
6526
+ ),
6527
+ onNext: () => setLightboxIndex(
6528
+ (prev) => prev !== null ? (prev + 1) % lightboxImages.length : null
6529
+ )
6530
+ }
6531
+ )
6532
+ ] }),
5784
6533
  isExpanded && /* @__PURE__ */ jsxs("div", { className: "border-t border-gray-200 dark:border-gray-700 px-3 py-2 space-y-2", children: [
5785
6534
  toolCall.args && Object.keys(toolCall.args).length > 0 && /* @__PURE__ */ jsxs("div", { children: [
5786
6535
  /* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-gray-500 dark:text-gray-400 mb-1", children: "Input" }),
@@ -5799,22 +6548,185 @@ function ToolCallEntry({
5799
6548
  }
5800
6549
  );
5801
6550
  }
5802
- function cn8(...classes) {
6551
+ function cn11(...classes) {
5803
6552
  return classes.filter(Boolean).join(" ");
5804
6553
  }
6554
+ function normalizeToolNameForGrouping(name) {
6555
+ const lastSegment = name.includes(".") ? name.split(".").pop() : name;
6556
+ return lastSegment.toLowerCase().replace(/[^a-z0-9]/g, "");
6557
+ }
6558
+ function groupToolCalls(toolCalls) {
6559
+ const byNormalizedName = /* @__PURE__ */ new Map();
6560
+ const nameOrder = [];
6561
+ for (const tc of toolCalls) {
6562
+ const key = normalizeToolNameForGrouping(tc.name);
6563
+ if (!byNormalizedName.has(key)) {
6564
+ byNormalizedName.set(key, []);
6565
+ nameOrder.push(key);
6566
+ }
6567
+ byNormalizedName.get(key).push(tc);
6568
+ }
6569
+ const groups = [];
6570
+ for (const key of nameOrder) {
6571
+ const calls = byNormalizedName.get(key);
6572
+ if (calls.length === 1) {
6573
+ groups.push({ type: "single", toolCall: calls[0] });
6574
+ } else {
6575
+ groups.push({ type: "group", name: calls[0].name, toolCalls: calls });
6576
+ }
6577
+ }
6578
+ return groups;
6579
+ }
6580
+ function ToolCallList({ toolCalls, toolCallVerbosity, onImageClick, renderToolCall }) {
6581
+ const visibleToolCalls = useMemo(() => {
6582
+ if (toolCallVerbosity !== "compact") return toolCalls;
6583
+ return toolCalls.filter((tc) => !isInternalTool(tc.name));
6584
+ }, [toolCalls, toolCallVerbosity]);
6585
+ const grouped = useMemo(() => groupToolCalls(visibleToolCalls), [visibleToolCalls]);
6586
+ return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: grouped.map((group) => {
6587
+ if (group.type === "single") {
6588
+ const toolCall = group.toolCall;
6589
+ const defaultRender = () => /* @__PURE__ */ jsx(
6590
+ ToolCallEntry,
6591
+ {
6592
+ toolCall,
6593
+ onImageClick
6594
+ },
6595
+ toolCall.id
6596
+ );
6597
+ if (renderToolCall) {
6598
+ return /* @__PURE__ */ jsx("div", { children: renderToolCall(toolCall, defaultRender) }, toolCall.id);
6599
+ }
6600
+ return /* @__PURE__ */ jsx("div", { children: defaultRender() }, toolCall.id);
6601
+ }
6602
+ const completed = group.toolCalls.filter((tc) => tc.status === "completed" || tc.status === "failed");
6603
+ const running = group.toolCalls.filter((tc) => tc.status !== "completed" && tc.status !== "failed");
6604
+ const allImages = completed.flatMap(
6605
+ (tc) => tc.result ? extractImagesFromResult2(tc.result) : []
6606
+ );
6607
+ const hasImages = allImages.length > 0;
6608
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
6609
+ running.length > 0 && running[0] && /* @__PURE__ */ jsx(
6610
+ ToolCallEntry,
6611
+ {
6612
+ toolCall: {
6613
+ ...running[0],
6614
+ name: running.length > 1 ? `${running[0].name} (${running.length})` : running[0].name
6615
+ },
6616
+ onImageClick
6617
+ },
6618
+ running[0].id
6619
+ ),
6620
+ completed.length > 0 && hasImages && /* @__PURE__ */ jsx(
6621
+ GroupedImageGallery,
6622
+ {
6623
+ images: allImages,
6624
+ completedCount: completed.length,
6625
+ onImageClick
6626
+ }
6627
+ ),
6628
+ completed.length > 0 && !hasImages && completed.map((tc) => {
6629
+ const defaultRender = () => /* @__PURE__ */ jsx(ToolCallEntry, { toolCall: tc, onImageClick }, tc.id);
6630
+ if (renderToolCall) {
6631
+ return /* @__PURE__ */ jsx("div", { children: renderToolCall(tc, defaultRender) }, tc.id);
6632
+ }
6633
+ return /* @__PURE__ */ jsx("div", { children: defaultRender() }, tc.id);
6634
+ })
6635
+ ] }, `group-${group.name}-${group.toolCalls[0]?.id}`);
6636
+ }) });
6637
+ }
6638
+ function GroupedImageGallery({
6639
+ images,
6640
+ completedCount,
6641
+ onImageClick
6642
+ }) {
6643
+ const [lightboxIndex, setLightboxIndex] = useState(null);
6644
+ const lightboxImages = useMemo(
6645
+ () => images.map((img) => ({
6646
+ url: img.url,
6647
+ alt: img.alt || img.prompt,
6648
+ filename: img.alt || img.prompt
6649
+ })),
6650
+ [images]
6651
+ );
6652
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
6653
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400 px-1", children: [
6654
+ /* @__PURE__ */ jsx("span", { className: "h-4 w-4 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "h-4 w-4 text-green-500", children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) }) }),
6655
+ /* @__PURE__ */ jsxs("span", { children: [
6656
+ completedCount,
6657
+ " image",
6658
+ completedCount !== 1 ? "s" : "",
6659
+ " generated"
6660
+ ] })
6661
+ ] }),
6662
+ /* @__PURE__ */ jsx("div", { className: cn11(
6663
+ "grid gap-3",
6664
+ images.length === 1 ? "grid-cols-1 max-w-sm" : images.length === 2 ? "grid-cols-2" : "grid-cols-2 sm:grid-cols-3"
6665
+ ), children: images.map((img, idx) => {
6666
+ const altText = img.alt || img.prompt || `Generated image ${idx + 1}`;
6667
+ return /* @__PURE__ */ jsx(
6668
+ "button",
6669
+ {
6670
+ type: "button",
6671
+ onClick: () => {
6672
+ if (onImageClick) {
6673
+ onImageClick({ url: img.url, alt: altText, filename: altText });
6674
+ } else {
6675
+ setLightboxIndex(idx);
6676
+ }
6677
+ },
6678
+ className: "block rounded-lg overflow-hidden cursor-pointer text-left transition-transform hover:scale-[1.02] group",
6679
+ children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
6680
+ /* @__PURE__ */ jsx(
6681
+ "img",
6682
+ {
6683
+ src: img.thumbnailUrl || img.url,
6684
+ alt: altText,
6685
+ className: "w-full h-auto max-h-[280px] object-cover rounded-lg shadow-sm",
6686
+ loading: "lazy"
6687
+ }
6688
+ ),
6689
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-lg bg-black/0 group-hover:bg-black/10 dark:group-hover:bg-white/5 transition-colors" })
6690
+ ] })
6691
+ },
6692
+ `${img.url}-${idx}`
6693
+ );
6694
+ }) }),
6695
+ lightboxIndex !== null && !onImageClick && /* @__PURE__ */ jsx(
6696
+ ImageLightbox,
6697
+ {
6698
+ images: lightboxImages,
6699
+ currentIndex: lightboxIndex,
6700
+ onClose: () => setLightboxIndex(null),
6701
+ onPrev: () => setLightboxIndex(
6702
+ (prev) => prev !== null ? (prev - 1 + lightboxImages.length) % lightboxImages.length : null
6703
+ ),
6704
+ onNext: () => setLightboxIndex(
6705
+ (prev) => prev !== null ? (prev + 1) % lightboxImages.length : null
6706
+ )
6707
+ }
6708
+ )
6709
+ ] });
6710
+ }
5805
6711
  function ChatMessage({
5806
6712
  message,
5807
6713
  enableMarkdown = true,
5808
6714
  showToolCalls = true,
5809
- toolCallVerbosity,
6715
+ toolCallVerbosity = "compact",
5810
6716
  className,
5811
6717
  markdownComponents,
5812
6718
  markdownUrlTransform,
5813
6719
  markdownContentTransform,
5814
- onImageClick
6720
+ onImageClick,
6721
+ showThinking = true,
6722
+ showDelegation = true,
6723
+ showImages = true,
6724
+ renderToolCall,
6725
+ variant = "bubble"
5815
6726
  }) {
5816
6727
  const isUser = message.role === "user";
5817
6728
  const isAssistant = message.role === "assistant";
6729
+ const isFlat = variant === "flat";
5818
6730
  const formattedTime = useMemo(() => {
5819
6731
  const date = message.timestamp instanceof Date ? message.timestamp : new Date(message.timestamp);
5820
6732
  return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
@@ -5822,113 +6734,119 @@ function ChatMessage({
5822
6734
  return /* @__PURE__ */ jsxs(
5823
6735
  "div",
5824
6736
  {
5825
- className: cn8(
5826
- "flex gap-3 p-4",
5827
- isUser ? "flex-row-reverse" : "flex-row",
6737
+ className: cn11(
6738
+ "cadra-chat-message flex gap-3",
6739
+ isFlat ? "py-5 px-4" : "p-4",
6740
+ // Bubble: user messages right-aligned. Flat: always left-aligned.
6741
+ !isFlat && isUser ? "flex-row-reverse" : "flex-row",
6742
+ // Flat variant: subtle row background for user messages
6743
+ isFlat && isUser && "chat-message-user-row",
5828
6744
  className
5829
6745
  ),
6746
+ style: isFlat && isUser ? {
6747
+ backgroundColor: "var(--chat-user-row-bg, rgba(128, 128, 128, 0.08))"
6748
+ } : void 0,
6749
+ "data-role": message.role,
5830
6750
  children: [
5831
6751
  /* @__PURE__ */ jsx(
5832
6752
  "div",
5833
6753
  {
5834
- className: cn8(
5835
- "flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center",
5836
- isUser ? "bg-blue-500 text-white" : "bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300"
5837
- ),
6754
+ className: "flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center shadow-sm",
6755
+ style: {
6756
+ backgroundColor: isUser ? "var(--chat-user-avatar-bg, #3b82f6)" : "var(--chat-assistant-avatar-bg, #e5e7eb)",
6757
+ color: isUser ? "var(--chat-user-avatar-text, #fff)" : "var(--chat-assistant-avatar-text, #4b5563)"
6758
+ },
5838
6759
  children: isUser ? /* @__PURE__ */ jsx(UserIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(BotIcon, { className: "h-4 w-4" })
5839
6760
  }
5840
6761
  ),
5841
6762
  /* @__PURE__ */ jsxs(
5842
6763
  "div",
5843
6764
  {
5844
- className: cn8(
5845
- "flex-1 min-w-0 space-y-2",
5846
- isUser ? "text-right" : "text-left"
6765
+ className: cn11(
6766
+ "flex-1 min-w-0",
6767
+ isFlat ? "pt-0.5" : "space-y-2",
6768
+ !isFlat && isUser ? "text-right" : "text-left"
5847
6769
  ),
5848
6770
  children: [
5849
6771
  /* @__PURE__ */ jsxs(
5850
6772
  "div",
5851
6773
  {
5852
- className: cn8(
5853
- "flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400",
5854
- isUser ? "justify-end" : "justify-start"
6774
+ className: cn11(
6775
+ "flex items-center gap-2 text-xs",
6776
+ isFlat ? "mb-1.5" : "",
6777
+ !isFlat && isUser ? "justify-end" : "justify-start"
5855
6778
  ),
6779
+ style: { color: "var(--chat-meta-text, #6b7280)" },
5856
6780
  children: [
5857
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: isUser ? "You" : "Assistant" }),
6781
+ /* @__PURE__ */ jsx("span", { className: "font-medium", style: { color: "var(--chat-label-text, inherit)" }, children: isUser ? "You" : "Assistant" }),
5858
6782
  /* @__PURE__ */ jsx("span", { children: formattedTime }),
5859
6783
  message.isStreaming && /* @__PURE__ */ jsx(LoadingSpinner, { className: "h-3 w-3" })
5860
6784
  ]
5861
6785
  }
5862
6786
  ),
5863
- message.thinkingBlocks && message.thinkingBlocks.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: message.thinkingBlocks.map((block) => /* @__PURE__ */ jsxs(
5864
- "div",
6787
+ showThinking && message.thinkingBlocks && message.thinkingBlocks.length > 0 && /* @__PURE__ */ jsx(ThinkingBlockList, { blocks: message.thinkingBlocks }),
6788
+ showDelegation && message.delegationEvents && message.delegationEvents.length > 0 && /* @__PURE__ */ jsx(DelegationProgressList, { events: message.delegationEvents }),
6789
+ showToolCalls && toolCallVerbosity !== "hidden" && message.toolCalls && message.toolCalls.length > 0 && /* @__PURE__ */ jsx(
6790
+ ToolCallList,
5865
6791
  {
5866
- className: "bg-purple-50 dark:bg-purple-950/30 border border-purple-200 dark:border-purple-800 rounded-lg p-3 text-sm text-purple-800 dark:text-purple-200",
5867
- children: [
5868
- /* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-purple-600 dark:text-purple-400 mb-1", children: "Thinking..." }),
5869
- /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap", children: block.content })
5870
- ]
5871
- },
5872
- block.id
5873
- )) }),
5874
- showToolCalls && toolCallVerbosity !== "hidden" && message.toolCalls && message.toolCalls.length > 0 && (() => {
5875
- const verbosity = toolCallVerbosity ?? "verbose";
5876
- const filteredToolCalls = verbosity === "compact" ? message.toolCalls.filter((tc) => !isInternalTool(tc.name)) : message.toolCalls;
5877
- if (filteredToolCalls.length === 0) return null;
5878
- if (verbosity === "compact") {
5879
- const runningTools = filteredToolCalls.filter((tc) => tc.status === "pending" || tc.status === "running");
5880
- const doneTools = filteredToolCalls.filter((tc) => tc.status === "completed" || tc.status === "failed");
5881
- return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
5882
- doneTools.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-x-3 gap-y-1", children: doneTools.map((toolCall) => /* @__PURE__ */ jsx(
5883
- ToolCallEntry,
5884
- {
5885
- toolCall,
5886
- onImageClick,
5887
- compact: true
5888
- },
5889
- toolCall.id
5890
- )) }),
5891
- runningTools.map((toolCall) => /* @__PURE__ */ jsx(
5892
- ToolCallEntry,
5893
- {
5894
- toolCall,
5895
- onImageClick
5896
- },
5897
- toolCall.id
5898
- ))
5899
- ] });
6792
+ toolCalls: message.toolCalls,
6793
+ toolCallVerbosity,
6794
+ onImageClick,
6795
+ renderToolCall
5900
6796
  }
5901
- return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: filteredToolCalls.map((toolCall) => /* @__PURE__ */ jsx(
5902
- ToolCallEntry,
5903
- {
5904
- toolCall,
5905
- onImageClick
5906
- },
5907
- toolCall.id
5908
- )) });
5909
- })(),
5910
- message.content && /* @__PURE__ */ jsx(
5911
- "div",
6797
+ ),
6798
+ showImages && !showToolCalls && message.images && message.images.length > 0 && /* @__PURE__ */ jsx(
6799
+ ImageGallery,
5912
6800
  {
5913
- className: cn8(
5914
- "rounded-lg p-3",
5915
- isUser ? "bg-blue-500 text-white" : "bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100"
5916
- ),
5917
- children: isAssistant && enableMarkdown ? /* @__PURE__ */ jsx(
5918
- MarkdownContent,
5919
- {
5920
- content: message.content,
5921
- components: markdownComponents,
5922
- urlTransform: markdownUrlTransform,
5923
- contentTransform: markdownContentTransform
5924
- }
5925
- ) : /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap", children: message.content })
6801
+ images: message.images,
6802
+ onImageClick: onImageClick ? (img) => onImageClick({ url: img.url, alt: img.alt, filename: img.filename }) : void 0
5926
6803
  }
5927
6804
  ),
6805
+ message.content && (isFlat ? (
6806
+ // Flat variant: no bubble, just text with theme-aware color
6807
+ /* @__PURE__ */ jsx(
6808
+ "div",
6809
+ {
6810
+ className: cn11("text-sm break-words", !(isAssistant && enableMarkdown) && "whitespace-pre-wrap"),
6811
+ style: { color: "var(--chat-content-text, inherit)" },
6812
+ children: isAssistant && enableMarkdown ? /* @__PURE__ */ jsx(
6813
+ MarkdownContent,
6814
+ {
6815
+ content: message.content,
6816
+ components: markdownComponents,
6817
+ urlTransform: markdownUrlTransform,
6818
+ contentTransform: markdownContentTransform
6819
+ }
6820
+ ) : /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap", children: message.content })
6821
+ }
6822
+ )
6823
+ ) : (
6824
+ // Bubble variant: colored bubble backgrounds
6825
+ /* @__PURE__ */ jsx(
6826
+ "div",
6827
+ {
6828
+ className: "rounded-lg p-3",
6829
+ style: {
6830
+ backgroundColor: isUser ? "var(--chat-user-bg, #3b82f6)" : "var(--chat-assistant-bg, #f3f4f6)",
6831
+ color: isUser ? "var(--chat-user-text, #fff)" : "var(--chat-assistant-text, #111827)"
6832
+ },
6833
+ children: isAssistant && enableMarkdown ? /* @__PURE__ */ jsx(
6834
+ MarkdownContent,
6835
+ {
6836
+ content: message.content,
6837
+ components: markdownComponents,
6838
+ urlTransform: markdownUrlTransform,
6839
+ contentTransform: markdownContentTransform
6840
+ }
6841
+ ) : /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap", children: message.content })
6842
+ }
6843
+ )
6844
+ )),
5928
6845
  message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: message.attachments.map((attachment) => /* @__PURE__ */ jsx(
5929
6846
  "div",
5930
6847
  {
5931
- className: "flex items-center gap-2 bg-gray-100 dark:bg-gray-800 rounded-lg px-3 py-2 text-sm",
6848
+ className: "flex items-center gap-2 rounded-lg px-3 py-2 text-sm",
6849
+ style: { backgroundColor: "var(--chat-assistant-bg, #f3f4f6)" },
5932
6850
  children: /* @__PURE__ */ jsx("span", { className: "truncate max-w-[150px]", children: attachment.filename })
5933
6851
  },
5934
6852
  attachment.uuid
@@ -5940,7 +6858,7 @@ function ChatMessage({
5940
6858
  }
5941
6859
  );
5942
6860
  }
5943
- function cn9(...classes) {
6861
+ function cn12(...classes) {
5944
6862
  return classes.filter(Boolean).join(" ");
5945
6863
  }
5946
6864
  function MessageList({
@@ -5958,6 +6876,12 @@ function MessageList({
5958
6876
  markdownUrlTransform,
5959
6877
  markdownContentTransform,
5960
6878
  onImageClick,
6879
+ showThinking = true,
6880
+ showDelegation = true,
6881
+ showImages = true,
6882
+ renderMessage,
6883
+ renderToolCall,
6884
+ messageVariant = "bubble",
5961
6885
  sendMessage
5962
6886
  }) {
5963
6887
  const scrollRef = useRef(null);
@@ -5971,7 +6895,7 @@ function MessageList({
5971
6895
  "div",
5972
6896
  {
5973
6897
  ref: scrollRef,
5974
- className: cn9(
6898
+ className: cn12(
5975
6899
  "flex-1 overflow-y-auto",
5976
6900
  className
5977
6901
  ),
@@ -5982,20 +6906,31 @@ function MessageList({
5982
6906
  ] }) }),
5983
6907
  messages.length === 0 && !isLoading && !isLoadingHistory && (renderWelcome ? /* @__PURE__ */ jsx(Fragment, { children: typeof renderWelcome === "function" ? renderWelcome({ sendMessage: sendMessage || (() => {
5984
6908
  }) }) : renderWelcome }) : /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full p-8", children: /* @__PURE__ */ jsx("div", { className: "text-center text-gray-500 dark:text-gray-400", children: /* @__PURE__ */ jsx("p", { className: "text-lg", children: welcomeMessage }) }) })),
5985
- /* @__PURE__ */ jsx("div", { className: "divide-y divide-gray-100 dark:divide-gray-800", children: messages.map((message) => /* @__PURE__ */ jsx(
5986
- ChatMessage,
5987
- {
5988
- message,
5989
- enableMarkdown,
5990
- showToolCalls,
5991
- toolCallVerbosity,
5992
- markdownComponents,
5993
- markdownUrlTransform,
5994
- markdownContentTransform,
5995
- onImageClick
5996
- },
5997
- message.id
5998
- )) }),
6909
+ /* @__PURE__ */ jsx("div", { className: "divide-y divide-gray-100 dark:divide-gray-800", children: messages.map((message) => {
6910
+ const defaultRender = () => /* @__PURE__ */ jsx(
6911
+ ChatMessage,
6912
+ {
6913
+ message,
6914
+ enableMarkdown,
6915
+ showToolCalls,
6916
+ toolCallVerbosity,
6917
+ markdownComponents,
6918
+ markdownUrlTransform,
6919
+ markdownContentTransform,
6920
+ onImageClick,
6921
+ showThinking,
6922
+ showDelegation,
6923
+ showImages,
6924
+ renderToolCall,
6925
+ variant: messageVariant
6926
+ },
6927
+ message.id
6928
+ );
6929
+ if (renderMessage) {
6930
+ return /* @__PURE__ */ jsx("div", { children: renderMessage(message, defaultRender) }, message.id);
6931
+ }
6932
+ return defaultRender();
6933
+ }) }),
5999
6934
  isLoading && !isStreaming && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 p-4", children: [
6000
6935
  /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-8 h-8 rounded-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center", children: /* @__PURE__ */ jsx(LoadingSpinner, { className: "h-4 w-4 text-gray-600 dark:text-gray-300" }) }),
6001
6936
  /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Thinking..." })
@@ -6051,6 +6986,7 @@ function AgentChat({
6051
6986
  maxHeight = "600px",
6052
6987
  className,
6053
6988
  theme = "system",
6989
+ layout = "fixed",
6054
6990
  enableAttachments = false,
6055
6991
  enableMarkdown = true,
6056
6992
  showToolCalls = true,
@@ -6058,7 +6994,21 @@ function AgentChat({
6058
6994
  markdownComponents,
6059
6995
  markdownUrlTransform,
6060
6996
  markdownContentTransform,
6061
- onImageClick
6997
+ onImageClick,
6998
+ // Extension props
6999
+ hideHeader,
7000
+ renderAboveInput,
7001
+ renderBelowMessages,
7002
+ renderMessage,
7003
+ renderToolCall,
7004
+ messageVariant = "bubble",
7005
+ showThinking = true,
7006
+ showDelegation = true,
7007
+ showImages = true,
7008
+ pollingInterval,
7009
+ pollingEnabled,
7010
+ onDelegation,
7011
+ onAttachmentsReady
6062
7012
  }) {
6063
7013
  const {
6064
7014
  messages,
@@ -6085,7 +7035,10 @@ function AgentChat({
6085
7035
  onSessionStart,
6086
7036
  onToolCall,
6087
7037
  onToolResult,
6088
- onClarification
7038
+ onClarification,
7039
+ onDelegation,
7040
+ pollingInterval,
7041
+ pollingEnabled
6089
7042
  });
6090
7043
  const effectiveVerbosity = showToolCalls === false ? "hidden" : toolCallVerbosity ?? "compact";
6091
7044
  const dropZoneRef = useRef(null);
@@ -6102,6 +7055,11 @@ function AgentChat({
6102
7055
  console.error("[AgentChat] Attachment error:", msg);
6103
7056
  }
6104
7057
  });
7058
+ useEffect(() => {
7059
+ if (enableAttachments && onAttachmentsReady) {
7060
+ onAttachmentsReady({ addExternalFile: attachments.addExternalFile });
7061
+ }
7062
+ }, [enableAttachments, onAttachmentsReady, attachments.addExternalFile]);
6105
7063
  const handleSend = useCallback(
6106
7064
  async (content) => {
6107
7065
  if (enableAttachments && attachments.hasReadyFiles) {
@@ -6114,51 +7072,31 @@ function AgentChat({
6114
7072
  },
6115
7073
  [enableAttachments, attachments, sendMessage]
6116
7074
  );
6117
- return /* @__PURE__ */ jsxs(ChatContainer, { maxHeight, className, theme, children: [
6118
- enableAttachments ? /* @__PURE__ */ jsx(
6119
- FileDropZone,
6120
- {
6121
- ref: dropZoneRef,
6122
- ...attachments.dropZoneProps,
6123
- disabled: isLoading || !!clarification || isLoadingHistory,
6124
- children: /* @__PURE__ */ jsx(
6125
- MessageList,
6126
- {
6127
- messages,
6128
- welcomeMessage,
6129
- renderWelcome,
6130
- isLoading,
6131
- isStreaming,
6132
- isLoadingHistory,
6133
- enableMarkdown,
6134
- showToolCalls,
6135
- toolCallVerbosity: effectiveVerbosity,
6136
- markdownComponents,
6137
- markdownUrlTransform,
6138
- markdownContentTransform,
6139
- onImageClick,
6140
- sendMessage: handleSend
6141
- }
6142
- )
6143
- }
6144
- ) : /* @__PURE__ */ jsx(
6145
- MessageList,
6146
- {
6147
- messages,
6148
- welcomeMessage,
6149
- renderWelcome,
6150
- isLoading,
6151
- isStreaming,
6152
- isLoadingHistory,
6153
- enableMarkdown,
6154
- showToolCalls,
6155
- markdownComponents,
6156
- markdownUrlTransform,
6157
- markdownContentTransform,
6158
- onImageClick,
6159
- sendMessage: handleSend
6160
- }
6161
- ),
7075
+ const messageListProps = {
7076
+ messages,
7077
+ welcomeMessage: hideHeader ? void 0 : welcomeMessage,
7078
+ renderWelcome: hideHeader ? void 0 : renderWelcome,
7079
+ isLoading,
7080
+ isStreaming,
7081
+ isLoadingHistory,
7082
+ enableMarkdown,
7083
+ showToolCalls,
7084
+ toolCallVerbosity: effectiveVerbosity,
7085
+ markdownComponents,
7086
+ markdownUrlTransform,
7087
+ markdownContentTransform,
7088
+ onImageClick,
7089
+ showThinking,
7090
+ showDelegation,
7091
+ showImages,
7092
+ renderMessage,
7093
+ renderToolCall,
7094
+ messageVariant,
7095
+ sendMessage: handleSend
7096
+ };
7097
+ const chatContent = /* @__PURE__ */ jsxs(Fragment, { children: [
7098
+ /* @__PURE__ */ jsx(MessageList, { ...messageListProps }),
7099
+ renderBelowMessages?.(),
6162
7100
  clarification && /* @__PURE__ */ jsx("div", { className: "border-t border-gray-200 dark:border-gray-700 p-4", children: /* @__PURE__ */ jsx(
6163
7101
  AskUserPrompt,
6164
7102
  {
@@ -6168,6 +7106,7 @@ function AgentChat({
6168
7106
  }
6169
7107
  ) }),
6170
7108
  error && /* @__PURE__ */ jsx(ErrorBanner, { error, onRetry: retry, onDismiss: clearError }),
7109
+ renderAboveInput?.(),
6171
7110
  /* @__PURE__ */ jsx(
6172
7111
  ChatInput,
6173
7112
  {
@@ -6184,8 +7123,17 @@ function AgentChat({
6184
7123
  }
6185
7124
  )
6186
7125
  ] });
7126
+ return /* @__PURE__ */ jsx(ChatContainer, { maxHeight, className, theme, layout, children: enableAttachments ? /* @__PURE__ */ jsx(
7127
+ FileDropZone,
7128
+ {
7129
+ ref: dropZoneRef,
7130
+ ...attachments.dropZoneProps,
7131
+ disabled: isLoading || !!clarification || isLoadingHistory,
7132
+ children: chatContent
7133
+ }
7134
+ ) : chatContent });
6187
7135
  }
6188
- function cn10(...classes) {
7136
+ function cn13(...classes) {
6189
7137
  return classes.filter(Boolean).join(" ");
6190
7138
  }
6191
7139
  function TodoList({
@@ -6214,7 +7162,7 @@ function TodoList({
6214
7162
  return /* @__PURE__ */ jsxs(
6215
7163
  "div",
6216
7164
  {
6217
- className: cn10(
7165
+ className: cn13(
6218
7166
  "rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden",
6219
7167
  className
6220
7168
  ),
@@ -6222,7 +7170,7 @@ function TodoList({
6222
7170
  /* @__PURE__ */ jsxs(
6223
7171
  "div",
6224
7172
  {
6225
- className: cn10(
7173
+ className: cn13(
6226
7174
  "flex items-center gap-2 px-3 py-2 bg-gray-50 dark:bg-gray-800/50",
6227
7175
  collapsible && "cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800"
6228
7176
  ),
@@ -6253,7 +7201,7 @@ function TodoList({
6253
7201
  !isCollapsed && /* @__PURE__ */ jsx("ul", { className: "divide-y divide-gray-100 dark:divide-gray-700", children: todos.map((todo, idx) => /* @__PURE__ */ jsxs(
6254
7202
  "li",
6255
7203
  {
6256
- className: cn10(
7204
+ className: cn13(
6257
7205
  "px-3 py-2 flex items-start gap-2 text-sm",
6258
7206
  todo.status === "in_progress" && "bg-blue-50/50 dark:bg-blue-950/20",
6259
7207
  todo.status === "completed" && "opacity-60"
@@ -6263,7 +7211,7 @@ function TodoList({
6263
7211
  /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(
6264
7212
  "p",
6265
7213
  {
6266
- className: cn10(
7214
+ className: cn13(
6267
7215
  "text-gray-700 dark:text-gray-300",
6268
7216
  todo.status === "completed" && "line-through"
6269
7217
  ),
@@ -6280,39 +7228,6 @@ function TodoList({
6280
7228
  );
6281
7229
  }
6282
7230
 
6283
- // src/chat/index.ts
6284
- var DEPRECATION_WARNING = `
6285
- [@cadraos/sdk/chat] DEPRECATION WARNING
6286
-
6287
- This module is deprecated and will be removed in a future version.
6288
- Please migrate to @cadraos/react for:
6289
- - Simpler setup with CadraCopilot
6290
- - Better security (header-based SSE auth)
6291
- - Scoped CSS that won't conflict with your app
6292
-
6293
- Migration steps:
6294
- 1. npm install @cadraos/react
6295
- 2. import '@cadraos/react/styles.css'
6296
- 3. Replace <AgentChat> with <CadraCopilot> or <CadraChat>
6297
-
6298
- See: https://github.com/cadraos/cadra-sdk/blob/main/packages/react/MIGRATION.md
6299
- `;
6300
- var hasWarned = false;
6301
- function showDeprecationWarning() {
6302
- if (hasWarned) return;
6303
- hasWarned = true;
6304
- if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
6305
- return;
6306
- }
6307
- if (typeof window === "undefined") {
6308
- return;
6309
- }
6310
- console.warn(DEPRECATION_WARNING);
6311
- }
6312
- if (typeof window !== "undefined") {
6313
- setTimeout(showDeprecationWarning, 0);
6314
- }
6315
-
6316
- export { AgentChat, AlertCircleIcon, AskUserPrompt, BotIcon, ChatConfigProvider, ChatContainer, ChatInput, ChatMessage, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, CircleIcon, ClockIcon, CodeIcon, CopyIcon, DatabaseIcon, DownloadIcon, ExternalLinkIcon, FileDropZone, FileIcon, FileTextIcon, HelpCircleIcon, INTERNAL_TOOL_NAMES, ImageIcon, ImagesIcon, ListTodoIcon, LoadingSpinner, MarkdownContent, Maximize2Icon, MessageCircleIcon, MessageList, Minimize2Icon, PaperclipIcon, SendIcon, SparklesIcon, StopCircleIcon, TodoList, ToolCallEntry, UserIcon, XIcon, ZoomInIcon, ZoomOutIcon, compressImage, createDefaultAdapter, isInternalTool, useAgentChat, useChatConfig, useChatConfigOptional, useExecutionStream, useFileAttachments };
7231
+ export { AgentChat, AlertCircleIcon, AskUserPrompt, BotIcon, ChatConfigProvider, ChatContainer, ChatInput, ChatMessage, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, CircleIcon, ClockIcon, CodeIcon, CopyIcon, DatabaseIcon, DelegationProgress, DelegationProgressList, DownloadIcon, ExternalLinkIcon, FileDropZone, FileIcon, FileTextIcon, HelpCircleIcon, INTERNAL_TOOL_NAMES, ImageGallery, ImageIcon, ImageLightbox, ImagesIcon, ListTodoIcon, LoadingSpinner, MarkdownContent, Maximize2Icon, MessageCircleIcon, MessageList, Minimize2Icon, PaperclipIcon, SendIcon, SparklesIcon, StopCircleIcon, ThinkingBlock, ThinkingBlockList, TodoList, ToolCallEntry, UserIcon, XIcon, ZoomInIcon, ZoomOutIcon, compressImage, createDefaultAdapter, isInternalTool, useAgentChat, useChatConfig, useChatConfigOptional, useExecutionStream, useFileAttachments };
6317
7232
  //# sourceMappingURL=index.js.map
6318
7233
  //# sourceMappingURL=index.js.map