@cadraos/sdk 0.1.11-test → 0.1.12

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.
@@ -581,9 +581,11 @@ var DEFAULT_STREAMING_CONFIG = {
581
581
  activityTimeoutMs: 3e4,
582
582
  pollingIntervalMs: 2e3
583
583
  };
584
+ var DEFAULT_POLLING_ENABLED = true;
584
585
  var ExecutionStreamControllerImpl = class {
585
586
  options;
586
587
  config;
588
+ pollingEnabled;
587
589
  sseClient = null;
588
590
  status = "connecting";
589
591
  reconnectAttempts = 0;
@@ -617,6 +619,7 @@ var ExecutionStreamControllerImpl = class {
617
619
  constructor(options) {
618
620
  this.options = options;
619
621
  this.config = { ...DEFAULT_STREAMING_CONFIG, ...options.config };
622
+ this.pollingEnabled = options.pollingEnabled ?? DEFAULT_POLLING_ENABLED;
620
623
  }
621
624
  /**
622
625
  * Get the last event ID (for resume support)
@@ -957,15 +960,61 @@ var ExecutionStreamControllerImpl = class {
957
960
  if (this.status === "closed") {
958
961
  return;
959
962
  }
963
+ await this.recoverState();
964
+ if (this.status === "closed") {
965
+ return;
966
+ }
960
967
  try {
961
968
  await this.connectSSE();
962
969
  } catch {
963
970
  await this.handleConnectionError(error);
964
971
  }
965
972
  } else {
966
- this.status = "fallback_polling";
967
- this.emit("connectionChange", { connected: false, usingFallback: true });
968
- this.startPolling();
973
+ if (this.pollingEnabled) {
974
+ this.status = "fallback_polling";
975
+ this.emit("connectionChange", { connected: false, usingFallback: true });
976
+ this.startPolling();
977
+ } else {
978
+ this.handleError({
979
+ error: "SSE connection failed and polling is disabled",
980
+ errorCode: "connection_failed"
981
+ });
982
+ }
983
+ }
984
+ }
985
+ /**
986
+ * Recover state by checking execution status.
987
+ *
988
+ * Called during reconnection to catch any events missed while SSE was down.
989
+ * If the execution completed while disconnected, emits completion immediately.
990
+ * Otherwise, emits any new logs that weren't seen via SSE.
991
+ */
992
+ async recoverState() {
993
+ try {
994
+ const execution = await this.options.getExecution(this.options.executionId);
995
+ if (execution.logs) {
996
+ for (const log of execution.logs) {
997
+ if (!this.seenEventIds.has(log.uuid)) {
998
+ this.seenEventIds.add(log.uuid);
999
+ this.emit("log", log);
1000
+ }
1001
+ }
1002
+ }
1003
+ if (execution.status === "completed") {
1004
+ this.stopPolling();
1005
+ this.handleComplete(execution);
1006
+ return;
1007
+ }
1008
+ if (execution.status === "failed" || execution.status === "cancelled") {
1009
+ this.stopPolling();
1010
+ this.handleError({
1011
+ error: execution.error ?? `Execution ${execution.status}`,
1012
+ errorCode: execution.status
1013
+ });
1014
+ return;
1015
+ }
1016
+ } catch (err) {
1017
+ console.warn("[SDK:StreamController] State recovery failed (non-fatal):", err);
969
1018
  }
970
1019
  }
971
1020
  /**
@@ -2817,12 +2866,54 @@ function useExecutionStream(options) {
2817
2866
  }
2818
2867
 
2819
2868
  // src/chat/hooks/useAgentChat.ts
2869
+ var __DEV__ = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
2820
2870
  var SILENT_TOOL_NAMES = /* @__PURE__ */ new Set([
2821
2871
  "check_delegations"
2822
2872
  ]);
2823
2873
  function generateId() {
2824
2874
  return `msg-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
2825
2875
  }
2876
+ function extractImagesFromResult(result, sourceToolCallId) {
2877
+ if (!result) return [];
2878
+ let data = result;
2879
+ if (typeof result === "string") {
2880
+ try {
2881
+ data = JSON.parse(result);
2882
+ } catch {
2883
+ if (/\.(png|jpg|jpeg|gif|webp|svg|bmp)(\?.*)?$/i.test(result) || result.startsWith("data:image/")) {
2884
+ return [{ url: result, sourceToolCallId }];
2885
+ }
2886
+ return [];
2887
+ }
2888
+ }
2889
+ if (typeof data !== "object" || data === null) return [];
2890
+ const obj = data;
2891
+ if (Array.isArray(obj.images)) {
2892
+ return obj.images.filter((img) => typeof img.url === "string").map((img) => ({
2893
+ url: img.url,
2894
+ alt: img.alt || img.prompt || void 0,
2895
+ filename: img.filename,
2896
+ sourceToolCallId
2897
+ }));
2898
+ }
2899
+ if (typeof obj.url === "string" && /\.(png|jpg|jpeg|gif|webp|svg|bmp)(\?.*)?$/i.test(obj.url)) {
2900
+ return [{ url: obj.url, alt: obj.alt, sourceToolCallId }];
2901
+ }
2902
+ if (typeof obj.imageUrl === "string") {
2903
+ return [{ url: obj.imageUrl, alt: obj.alt, sourceToolCallId }];
2904
+ }
2905
+ return [];
2906
+ }
2907
+ function deriveImagesFromToolCalls(toolCalls) {
2908
+ if (!toolCalls) return [];
2909
+ const images = [];
2910
+ for (const tc of toolCalls) {
2911
+ if (tc.status === "completed" && tc.result) {
2912
+ images.push(...extractImagesFromResult(tc.result, tc.id));
2913
+ }
2914
+ }
2915
+ return images;
2916
+ }
2826
2917
  function historyToMessage(historyMsg) {
2827
2918
  return {
2828
2919
  id: historyMsg.uuid,
@@ -2863,7 +2954,9 @@ function useAgentChat(options) {
2863
2954
  // Deprecated, but still supported
2864
2955
  onToolCall,
2865
2956
  onToolResult,
2866
- onClarification
2957
+ onClarification,
2958
+ pollingInterval,
2959
+ pollingEnabled
2867
2960
  } = options;
2868
2961
  const contextConfig = useChatConfigOptional();
2869
2962
  const adapter = propsAdapter ?? contextConfig?.adapter;
@@ -2895,8 +2988,14 @@ function useAgentChat(options) {
2895
2988
  const streamingMessageIdRef = useRef(null);
2896
2989
  const pendingToolCallsRef = useRef(/* @__PURE__ */ new Map());
2897
2990
  const lastMessageContentRef = useRef("");
2991
+ const finalizedRef = useRef(false);
2898
2992
  const firedToolResultsRef = useRef(/* @__PURE__ */ new Set());
2899
2993
  const streamControllerRef = useRef(null);
2994
+ const pendingDelegationsRef = useRef(/* @__PURE__ */ new Map());
2995
+ const onDelegationRef = useRef(options.onDelegation);
2996
+ useEffect(() => {
2997
+ onDelegationRef.current = options.onDelegation;
2998
+ }, [options.onDelegation]);
2900
2999
  const updateStreamingMessage = useCallback((content) => {
2901
3000
  if (!streamingMessageIdRef.current) return;
2902
3001
  setMessages(
@@ -2925,25 +3024,72 @@ function useAgentChat(options) {
2925
3024
  });
2926
3025
  });
2927
3026
  }, []);
2928
- const finalizeStreamingMessage = useCallback((terminalStatus = "completed") => {
3027
+ const addDelegationEvent = useCallback((delegation) => {
3028
+ setMessages((prev) => {
3029
+ const targetId = streamingMessageIdRef.current ?? [...prev].reverse().find((m) => m.role === "assistant")?.id;
3030
+ if (!targetId) return prev;
3031
+ return prev.map((msg) => {
3032
+ if (msg.id !== targetId) return msg;
3033
+ const existing = msg.delegationEvents ?? [];
3034
+ if (delegation.type === "delegation_completed" && delegation.handoffId) {
3035
+ const updatedEvents = existing.map(
3036
+ (de) => de.handoffId === delegation.handoffId ? { ...de, ...delegation, status: delegation.status ?? "completed" } : de
3037
+ );
3038
+ const hasMatch = existing.some((de) => de.handoffId === delegation.handoffId);
3039
+ return {
3040
+ ...msg,
3041
+ delegationEvents: hasMatch ? updatedEvents : [...existing, delegation]
3042
+ };
3043
+ }
3044
+ return { ...msg, delegationEvents: [...existing, delegation] };
3045
+ });
3046
+ });
3047
+ }, []);
3048
+ const updateMessageImages = useCallback(() => {
3049
+ setMessages((prev) => {
3050
+ const targetId = streamingMessageIdRef.current ?? [...prev].reverse().find((m) => m.role === "assistant")?.id;
3051
+ if (!targetId) return prev;
3052
+ return prev.map((msg) => {
3053
+ if (msg.id !== targetId) return msg;
3054
+ const images = deriveImagesFromToolCalls(msg.toolCalls);
3055
+ return images.length > 0 ? { ...msg, images } : msg;
3056
+ });
3057
+ });
3058
+ }, []);
3059
+ const finalizeStreamingMessage = useCallback((finalOutput) => {
2929
3060
  if (!streamingMessageIdRef.current) return;
2930
- setMessages(
2931
- (prev) => prev.map((msg) => {
2932
- if (msg.id !== streamingMessageIdRef.current) return msg;
3061
+ finalizedRef.current = true;
3062
+ const streamMsgId = streamingMessageIdRef.current;
3063
+ setMessages((prev) => {
3064
+ const resolvedContent = finalOutput || streamingContentRef.current || "";
3065
+ const duplicateExists = resolvedContent && prev.some(
3066
+ (msg) => msg.id !== streamMsgId && msg.role === "assistant" && !msg.isStreaming && msg.content === resolvedContent
3067
+ );
3068
+ if (duplicateExists) {
3069
+ return prev.filter((msg) => msg.id !== streamMsgId);
3070
+ }
3071
+ return prev.map((msg) => {
3072
+ if (msg.id !== streamMsgId) return msg;
2933
3073
  const updatedToolCalls = msg.toolCalls?.map(
2934
- (tc) => tc.status === "running" || tc.status === "pending" ? { ...tc, status: terminalStatus } : tc
3074
+ (tc) => tc.status === "running" || tc.status === "pending" ? { ...tc, status: "completed" } : tc
2935
3075
  );
2936
- return { ...msg, isStreaming: false, toolCalls: updatedToolCalls };
2937
- })
2938
- );
3076
+ return {
3077
+ ...msg,
3078
+ content: resolvedContent || msg.content,
3079
+ isStreaming: false,
3080
+ toolCalls: updatedToolCalls
3081
+ };
3082
+ });
3083
+ });
2939
3084
  streamingMessageIdRef.current = null;
2940
3085
  streamingContentRef.current = "";
2941
3086
  pendingToolCallsRef.current.clear();
2942
3087
  firedToolResultsRef.current.clear();
3088
+ pendingDelegationsRef.current.clear();
2943
3089
  }, []);
2944
3090
  const handleExecutionLog = useCallback(
2945
3091
  (log) => {
2946
- console.log("[useAgentChat] handleExecutionLog:", log.type, log.metadata);
3092
+ if (__DEV__) console.log("[useAgentChat] handleExecutionLog:", log.type, log.metadata);
2947
3093
  switch (log.type) {
2948
3094
  // Primary handlers for ai-saas-api worker log types
2949
3095
  case "llm_response": {
@@ -2963,11 +3109,46 @@ function useAgentChat(options) {
2963
3109
  }
2964
3110
  break;
2965
3111
  }
3112
+ case "delegation": {
3113
+ const delegationType = log.metadata?.delegationType;
3114
+ if (delegationType === "started" || delegationType === "delegation_started") {
3115
+ const delegation = {
3116
+ type: "delegation_started",
3117
+ handoffId: log.metadata?.handoffId,
3118
+ toAgent: log.metadata?.targetAgentName || log.metadata?.targetAgentUuid,
3119
+ targetAgentUuid: log.metadata?.targetAgentUuid,
3120
+ taskPreview: log.metadata?.taskPreview,
3121
+ timestamp: new Date(log.timestamp || Date.now()),
3122
+ status: "active"
3123
+ };
3124
+ if (delegation.handoffId) {
3125
+ pendingDelegationsRef.current.set(delegation.handoffId, delegation);
3126
+ }
3127
+ addDelegationEvent(delegation);
3128
+ onDelegationRef.current?.(delegation);
3129
+ } else if (delegationType === "completed" || delegationType === "delegation_completed") {
3130
+ const delegation = {
3131
+ type: "delegation_completed",
3132
+ handoffId: log.metadata?.handoffId,
3133
+ resultPreview: log.metadata?.resultPreview,
3134
+ timestamp: new Date(log.timestamp || Date.now()),
3135
+ status: log.metadata?.status === "failed" ? "failed" : "completed",
3136
+ durationMs: log.durationMs
3137
+ };
3138
+ if (delegation.handoffId) {
3139
+ pendingDelegationsRef.current.delete(delegation.handoffId);
3140
+ }
3141
+ addDelegationEvent(delegation);
3142
+ onDelegationRef.current?.(delegation);
3143
+ }
3144
+ break;
3145
+ }
2966
3146
  case "info":
2967
3147
  case "system":
2968
- console.log("[useAgentChat] Status:", log.type, log.title);
3148
+ if (__DEV__) console.log("[useAgentChat] Status:", log.type, log.title);
2969
3149
  break;
2970
3150
  case "tool_call": {
3151
+ if (finalizedRef.current) break;
2971
3152
  const toolName = log.metadata?.toolName;
2972
3153
  if (SILENT_TOOL_NAMES.has(toolName)) break;
2973
3154
  const toolCallId = log.metadata?.toolCallId || `tool-${Date.now()}`;
@@ -3022,17 +3203,18 @@ function useAgentChat(options) {
3022
3203
  firedToolResultsRef.current.add(resultToolCallId);
3023
3204
  }
3024
3205
  onToolResultRef.current?.(resultToolName, result, durationMs);
3206
+ updateMessageImages();
3025
3207
  break;
3026
3208
  }
3027
3209
  default:
3028
- console.log("[useAgentChat] Unhandled log type:", log.type, log);
3210
+ if (__DEV__) console.log("[useAgentChat] Unhandled log type:", log.type, log);
3029
3211
  }
3030
3212
  },
3031
- [updateStreamingMessage, updateToolCall]
3213
+ [updateStreamingMessage, updateToolCall, updateMessageImages, addDelegationEvent]
3032
3214
  );
3033
3215
  const handleStreamLog = useCallback(
3034
3216
  (log) => {
3035
- console.log("[useAgentChat] handleStreamLog:", log.logType, log.metadata);
3217
+ if (__DEV__) console.log("[useAgentChat] handleStreamLog:", log.logType, log.metadata);
3036
3218
  switch (log.logType) {
3037
3219
  case "llm_response": {
3038
3220
  const llmText = log.metadata?.text || "";
@@ -3051,9 +3233,42 @@ function useAgentChat(options) {
3051
3233
  }
3052
3234
  break;
3053
3235
  }
3236
+ case "delegation_started": {
3237
+ const delegation = {
3238
+ type: "delegation_started",
3239
+ handoffId: log.metadata?.handoffId,
3240
+ toAgent: log.metadata?.targetAgentName || log.metadata?.targetAgentUuid,
3241
+ targetAgentUuid: log.metadata?.targetAgentUuid,
3242
+ taskPreview: log.metadata?.taskPreview,
3243
+ timestamp: new Date(log.timestamp || Date.now()),
3244
+ status: "active"
3245
+ };
3246
+ if (delegation.handoffId) {
3247
+ pendingDelegationsRef.current.set(delegation.handoffId, delegation);
3248
+ }
3249
+ addDelegationEvent(delegation);
3250
+ onDelegationRef.current?.(delegation);
3251
+ break;
3252
+ }
3253
+ case "delegation_completed": {
3254
+ const delegation = {
3255
+ type: "delegation_completed",
3256
+ handoffId: log.metadata?.handoffId,
3257
+ resultPreview: log.metadata?.resultPreview,
3258
+ timestamp: new Date(log.timestamp || Date.now()),
3259
+ status: log.metadata?.status === "failed" ? "failed" : "completed",
3260
+ durationMs: log.durationMs
3261
+ };
3262
+ if (delegation.handoffId) {
3263
+ pendingDelegationsRef.current.delete(delegation.handoffId);
3264
+ }
3265
+ addDelegationEvent(delegation);
3266
+ onDelegationRef.current?.(delegation);
3267
+ break;
3268
+ }
3054
3269
  case "info":
3055
3270
  case "system":
3056
- console.log("[useAgentChat] Status:", log.logType, log.message);
3271
+ if (__DEV__) console.log("[useAgentChat] Status:", log.logType, log.message);
3057
3272
  break;
3058
3273
  case "response_text":
3059
3274
  case "text_chunk": {
@@ -3063,6 +3278,7 @@ function useAgentChat(options) {
3063
3278
  break;
3064
3279
  }
3065
3280
  case "tool_call": {
3281
+ if (finalizedRef.current) break;
3066
3282
  const toolName = log.metadata?.toolName;
3067
3283
  if (SILENT_TOOL_NAMES.has(toolName)) break;
3068
3284
  const toolCallId = log.metadata?.toolCallId || `tool-${Date.now()}`;
@@ -3117,6 +3333,7 @@ function useAgentChat(options) {
3117
3333
  firedToolResultsRef.current.add(resultToolCallId);
3118
3334
  }
3119
3335
  onToolResultRef.current?.(resultToolName, result, durationMs);
3336
+ updateMessageImages();
3120
3337
  break;
3121
3338
  }
3122
3339
  case "final_response": {
@@ -3128,10 +3345,10 @@ function useAgentChat(options) {
3128
3345
  break;
3129
3346
  }
3130
3347
  default:
3131
- console.log("[useAgentChat] Unknown log type:", log.logType, log);
3348
+ if (__DEV__) console.log("[useAgentChat] Unknown log type:", log.logType, log);
3132
3349
  }
3133
3350
  },
3134
- [updateStreamingMessage, updateToolCall]
3351
+ [updateStreamingMessage, updateToolCall, updateMessageImages, addDelegationEvent]
3135
3352
  );
3136
3353
  const handleClarification = useCallback(
3137
3354
  (data) => {
@@ -3140,17 +3357,23 @@ function useAgentChat(options) {
3140
3357
  },
3141
3358
  [onClarification]
3142
3359
  );
3143
- const handleComplete = useCallback(() => {
3144
- console.log("[useAgentChat] handleComplete called");
3360
+ const completedRef = useRef(false);
3361
+ const handleComplete = useCallback((finalOutput) => {
3362
+ if (completedRef.current) {
3363
+ if (__DEV__) console.log("[useAgentChat] handleComplete: skipping duplicate complete");
3364
+ return;
3365
+ }
3366
+ completedRef.current = true;
3367
+ if (__DEV__) console.log("[useAgentChat] handleComplete called");
3145
3368
  setIsLoading(false);
3146
3369
  setIsStreamControllerConnected(false);
3147
- finalizeStreamingMessage();
3370
+ finalizeStreamingMessage(finalOutput);
3148
3371
  setCurrentExecutionId(null);
3149
3372
  streamControllerRef.current = null;
3150
3373
  }, [finalizeStreamingMessage]);
3151
3374
  const handleError = useCallback(
3152
3375
  (errorMsg) => {
3153
- console.log("[useAgentChat] handleError called:", errorMsg);
3376
+ if (__DEV__) console.log("[useAgentChat] handleError called:", errorMsg);
3154
3377
  const chatError = {
3155
3378
  code: "EXECUTION_ERROR",
3156
3379
  message: errorMsg,
@@ -3159,7 +3382,7 @@ function useAgentChat(options) {
3159
3382
  setError(chatError);
3160
3383
  setIsLoading(false);
3161
3384
  setIsStreamControllerConnected(false);
3162
- finalizeStreamingMessage("failed");
3385
+ finalizeStreamingMessage();
3163
3386
  setCurrentExecutionId(null);
3164
3387
  streamControllerRef.current = null;
3165
3388
  onError?.(chatError);
@@ -3189,43 +3412,39 @@ function useAgentChat(options) {
3189
3412
  if (pollingExecutionIdRef.current === executionId) return;
3190
3413
  stopPolling();
3191
3414
  pollingExecutionIdRef.current = executionId;
3192
- console.log("[useAgentChat] Starting polling fallback for:", executionId);
3415
+ if (__DEV__) console.log("[useAgentChat] Starting polling fallback for:", executionId);
3193
3416
  const poll = async () => {
3194
3417
  if (pollingExecutionIdRef.current !== executionId) return;
3195
3418
  try {
3196
3419
  const execution = await adapter.getExecution(executionId);
3197
3420
  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
- }
3421
+ if (__DEV__) console.log("[useAgentChat] Polling: execution completed");
3203
3422
  stopPolling();
3204
- handleComplete();
3423
+ handleComplete(execution.result || void 0);
3205
3424
  } else if (execution.status === "failed") {
3206
- console.log("[useAgentChat] Polling: execution failed");
3425
+ if (__DEV__) console.log("[useAgentChat] Polling: execution failed");
3207
3426
  stopPolling();
3208
3427
  handleError(execution.error || "Execution failed");
3209
3428
  }
3210
3429
  } catch (err) {
3211
- console.warn("[useAgentChat] Polling error (will retry):", err);
3430
+ if (__DEV__) console.warn("[useAgentChat] Polling error (will retry):", err);
3212
3431
  }
3213
3432
  };
3214
3433
  poll();
3215
- pollingIntervalRef.current = setInterval(poll, 2e3);
3216
- }, [adapter, stopPolling, updateStreamingMessage, handleComplete, handleError]);
3434
+ pollingIntervalRef.current = setInterval(poll, pollingInterval ?? 2e3);
3435
+ }, [adapter, stopPolling, handleComplete, handleError, pollingInterval]);
3217
3436
  useEffect(() => {
3218
- if (!useStreamController && isUsingFallback && currentExecutionId && isLoading) {
3219
- console.log("[useAgentChat] SSE fallback detected, activating polling");
3437
+ if (!useStreamController && isUsingFallback && currentExecutionId && isLoading && pollingEnabled !== false) {
3438
+ if (__DEV__) console.log("[useAgentChat] SSE fallback detected, activating polling");
3220
3439
  startPolling(currentExecutionId);
3221
3440
  }
3222
- }, [useStreamController, isUsingFallback, currentExecutionId, isLoading, startPolling]);
3441
+ }, [useStreamController, isUsingFallback, currentExecutionId, isLoading, startPolling, pollingEnabled]);
3223
3442
  const sseTimeoutRef = useRef(null);
3224
3443
  useEffect(() => {
3225
- if (!useStreamController && currentExecutionId && isLoading && !legacyIsConnected && !isUsingFallback) {
3444
+ if (!useStreamController && currentExecutionId && isLoading && !legacyIsConnected && !isUsingFallback && pollingEnabled !== false) {
3226
3445
  sseTimeoutRef.current = setTimeout(() => {
3227
3446
  if (!legacyIsConnected && currentExecutionId && isLoading) {
3228
- console.log("[useAgentChat] SSE connection timeout, activating polling fallback");
3447
+ if (__DEV__) console.log("[useAgentChat] SSE connection timeout, activating polling fallback");
3229
3448
  startPolling(currentExecutionId);
3230
3449
  }
3231
3450
  }, 1e4);
@@ -3236,7 +3455,7 @@ function useAgentChat(options) {
3236
3455
  sseTimeoutRef.current = null;
3237
3456
  }
3238
3457
  };
3239
- }, [useStreamController, currentExecutionId, isLoading, legacyIsConnected, isUsingFallback, startPolling]);
3458
+ }, [useStreamController, currentExecutionId, isLoading, legacyIsConnected, isUsingFallback, startPolling, pollingEnabled]);
3240
3459
  useEffect(() => {
3241
3460
  if (!currentExecutionId) {
3242
3461
  stopPolling();
@@ -3252,7 +3471,7 @@ function useAgentChat(options) {
3252
3471
  streamControllerRef.current.cancel();
3253
3472
  streamControllerRef.current = null;
3254
3473
  }
3255
- console.log("[useAgentChat] Creating stream controller for:", executionId);
3474
+ if (__DEV__) console.log("[useAgentChat] Creating stream controller for:", executionId);
3256
3475
  const controller = adapter.createStream(executionId, sessionId);
3257
3476
  streamControllerRef.current = controller;
3258
3477
  controller.on("log", (log) => {
@@ -3303,6 +3522,34 @@ function useAgentChat(options) {
3303
3522
  }
3304
3523
  firedToolResultsRef.current.add(toolCallId);
3305
3524
  onToolResultRef.current?.(toolName, data.result, data.durationMs);
3525
+ updateMessageImages();
3526
+ });
3527
+ controller.on("delegationStarted", (data) => {
3528
+ const delegation = {
3529
+ type: "delegation_started",
3530
+ handoffId: data.handoffId,
3531
+ toAgent: data.targetAgentName || data.targetAgentUuid,
3532
+ targetAgentUuid: data.targetAgentUuid,
3533
+ taskPreview: data.taskPreview,
3534
+ timestamp: new Date(data.timestamp),
3535
+ status: "active"
3536
+ };
3537
+ pendingDelegationsRef.current.set(data.handoffId, delegation);
3538
+ addDelegationEvent(delegation);
3539
+ onDelegationRef.current?.(delegation);
3540
+ });
3541
+ controller.on("delegationCompleted", (data) => {
3542
+ const delegation = {
3543
+ type: "delegation_completed",
3544
+ handoffId: data.handoffId,
3545
+ resultPreview: data.resultPreview,
3546
+ timestamp: new Date(data.timestamp),
3547
+ status: data.status === "failed" ? "failed" : "completed",
3548
+ durationMs: data.durationMs
3549
+ };
3550
+ pendingDelegationsRef.current.delete(data.handoffId);
3551
+ addDelegationEvent(delegation);
3552
+ onDelegationRef.current?.(delegation);
3306
3553
  });
3307
3554
  controller.on("textDelta", (data) => {
3308
3555
  streamingContentRef.current += data.delta;
@@ -3316,11 +3563,8 @@ function useAgentChat(options) {
3316
3563
  });
3317
3564
  });
3318
3565
  controller.on("complete", ({ execution }) => {
3319
- if (execution?.output && !streamingContentRef.current) {
3320
- streamingContentRef.current = execution.output;
3321
- updateStreamingMessage(execution.output);
3322
- }
3323
- handleComplete();
3566
+ const output = execution?.output || void 0;
3567
+ handleComplete(output);
3324
3568
  });
3325
3569
  controller.on("error", (errorEvent) => {
3326
3570
  handleError(errorEvent.error);
@@ -3334,7 +3578,7 @@ function useAgentChat(options) {
3334
3578
  });
3335
3579
  setIsStreamControllerConnected(true);
3336
3580
  },
3337
- [adapter, handleExecutionLog, updateStreamingMessage, updateToolCall, handleClarification, handleComplete, handleError]
3581
+ [adapter, handleExecutionLog, updateStreamingMessage, updateToolCall, updateMessageImages, addDelegationEvent, handleClarification, handleComplete, handleError]
3338
3582
  );
3339
3583
  const sendMessage = useCallback(
3340
3584
  async (content, options2) => {
@@ -3364,8 +3608,10 @@ function useAgentChat(options) {
3364
3608
  setMessages((prev) => [...prev, assistantMessage]);
3365
3609
  streamingMessageIdRef.current = assistantMessageId;
3366
3610
  streamingContentRef.current = "";
3611
+ completedRef.current = false;
3612
+ finalizedRef.current = false;
3367
3613
  try {
3368
- console.log("[useAgentChat] Starting execution...", { agentId, sessionId: currentSessionId });
3614
+ if (__DEV__) console.log("[useAgentChat] Starting execution...", { agentId, sessionId: currentSessionId });
3369
3615
  const result = await adapter.startExecution({
3370
3616
  agentId,
3371
3617
  teamId,
@@ -3373,7 +3619,7 @@ function useAgentChat(options) {
3373
3619
  content: content.trim(),
3374
3620
  attachmentUuids
3375
3621
  });
3376
- console.log("[useAgentChat] Execution started:", result);
3622
+ if (__DEV__) console.log("[useAgentChat] Execution started:", result);
3377
3623
  if (!currentSessionId && result.sessionId) {
3378
3624
  internallyCreatedSessionRef.current = result.sessionId;
3379
3625
  setCurrentSessionId(result.sessionId);
@@ -3384,7 +3630,7 @@ function useAgentChat(options) {
3384
3630
  connectStreamController(result.executionId, result.sessionId || currentSessionId || void 0);
3385
3631
  setCurrentExecutionId(result.executionId);
3386
3632
  } else {
3387
- console.log("[useAgentChat] Setting executionId:", result.executionId);
3633
+ if (__DEV__) console.log("[useAgentChat] Setting executionId:", result.executionId);
3388
3634
  setCurrentExecutionId(result.executionId);
3389
3635
  }
3390
3636
  } catch (err) {
@@ -3444,6 +3690,7 @@ function useAgentChat(options) {
3444
3690
  setMessages([]);
3445
3691
  setCurrentSessionId(null);
3446
3692
  hasLoadedInitialSession.current = false;
3693
+ lastLoadedSessionRef.current = null;
3447
3694
  internallyCreatedSessionRef.current = null;
3448
3695
  }, []);
3449
3696
  const loadSession = useCallback(
@@ -3539,15 +3786,20 @@ function useAgentChat(options) {
3539
3786
  },
3540
3787
  [adapter, onError]
3541
3788
  );
3789
+ const lastLoadedSessionRef = useRef(null);
3542
3790
  useEffect(() => {
3543
- if (initialSessionId && !hasLoadedInitialSession.current) {
3544
- if (internallyCreatedSessionRef.current === initialSessionId) {
3545
- hasLoadedInitialSession.current = true;
3546
- return;
3547
- }
3791
+ if (!initialSessionId) return;
3792
+ if (internallyCreatedSessionRef.current === initialSessionId) {
3793
+ lastLoadedSessionRef.current = initialSessionId;
3548
3794
  hasLoadedInitialSession.current = true;
3549
- loadSession(initialSessionId);
3795
+ return;
3796
+ }
3797
+ if (lastLoadedSessionRef.current === initialSessionId && hasLoadedInitialSession.current) {
3798
+ return;
3550
3799
  }
3800
+ lastLoadedSessionRef.current = initialSessionId;
3801
+ hasLoadedInitialSession.current = true;
3802
+ loadSession(initialSessionId);
3551
3803
  }, [initialSessionId, loadSession]);
3552
3804
  useEffect(() => {
3553
3805
  return () => {
@@ -3563,6 +3815,16 @@ function useAgentChat(options) {
3563
3815
  }
3564
3816
  return !!currentExecutionId && legacyIsConnected;
3565
3817
  }, [useStreamController, currentExecutionId, isStreamControllerConnected, legacyIsConnected]);
3818
+ const activeDelegation = useMemo(() => {
3819
+ for (let i = messages.length - 1; i >= 0; i--) {
3820
+ const msg = messages[i];
3821
+ if (msg.delegationEvents) {
3822
+ const active = msg.delegationEvents.find((de) => de.status === "active");
3823
+ if (active) return active;
3824
+ }
3825
+ }
3826
+ return null;
3827
+ }, [messages]);
3566
3828
  return {
3567
3829
  messages,
3568
3830
  isLoading,
@@ -3571,6 +3833,7 @@ function useAgentChat(options) {
3571
3833
  error,
3572
3834
  sessionId: currentSessionId,
3573
3835
  clarification,
3836
+ activeDelegation,
3574
3837
  sendMessage,
3575
3838
  respondToClarification,
3576
3839
  cancel,
@@ -4426,18 +4689,30 @@ function ChatContainer({
4426
4689
  children,
4427
4690
  maxHeight = "600px",
4428
4691
  className,
4429
- theme = "system"
4692
+ theme = "system",
4693
+ layout = "fixed"
4430
4694
  }) {
4431
4695
  const maxHeightValue = typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight;
4696
+ const isFill = layout === "fill";
4432
4697
  return /* @__PURE__ */ jsx(
4433
4698
  "div",
4434
4699
  {
4435
4700
  className: cn2(
4436
- "flex flex-col bg-white dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden",
4701
+ "cadra-chat-container flex flex-col overflow-hidden",
4702
+ // Default colors use CSS custom properties with Tailwind fallbacks.
4703
+ // Consumers can override via CSS: --chat-bg, --chat-border, --chat-border-radius
4704
+ !isFill && "rounded-lg border",
4705
+ isFill && "flex-1 min-h-0",
4437
4706
  className
4438
4707
  ),
4439
- style: { maxHeight: maxHeightValue },
4708
+ style: {
4709
+ ...!isFill ? { maxHeight: maxHeightValue } : void 0,
4710
+ // CSS custom properties for theming — consumers set these to override
4711
+ backgroundColor: "var(--chat-bg, var(--background, #fff))",
4712
+ borderColor: !isFill ? "var(--chat-border, var(--border, #e5e7eb))" : void 0
4713
+ },
4440
4714
  "data-theme": theme,
4715
+ "data-layout": layout,
4441
4716
  children
4442
4717
  }
4443
4718
  );
@@ -5124,7 +5399,7 @@ var FileDropZone = forwardRef(
5124
5399
  {
5125
5400
  ref: dropZoneRef,
5126
5401
  "data-dropzone": "wrapper",
5127
- className: cn4("relative w-full h-full", className),
5402
+ className: cn4("relative flex flex-col flex-1 min-h-0", className),
5128
5403
  style: { minHeight: "inherit" },
5129
5404
  children: [
5130
5405
  /* @__PURE__ */ jsx(
@@ -5409,6 +5684,312 @@ function AskUserPrompt({
5409
5684
  function cn6(...classes) {
5410
5685
  return classes.filter(Boolean).join(" ");
5411
5686
  }
5687
+ function formatDuration(ms) {
5688
+ if (ms < 1e3) return `${ms}ms`;
5689
+ return `${(ms / 1e3).toFixed(1)}s`;
5690
+ }
5691
+ function DelegationProgress({
5692
+ event,
5693
+ className
5694
+ }) {
5695
+ const statusIcon = useMemo(() => {
5696
+ switch (event.status) {
5697
+ case "active":
5698
+ return /* @__PURE__ */ jsx(LoadingSpinner, { className: "h-4 w-4 text-blue-500" });
5699
+ case "completed":
5700
+ return /* @__PURE__ */ jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-500" });
5701
+ case "failed":
5702
+ return /* @__PURE__ */ jsx(AlertCircleIcon, { className: "h-4 w-4 text-red-500" });
5703
+ default:
5704
+ return /* @__PURE__ */ jsx(LoadingSpinner, { className: "h-4 w-4 text-gray-400" });
5705
+ }
5706
+ }, [event.status]);
5707
+ const statusColor = useMemo(() => {
5708
+ switch (event.status) {
5709
+ case "active":
5710
+ return "border-blue-200 dark:border-blue-800 bg-blue-50/50 dark:bg-blue-950/20";
5711
+ case "completed":
5712
+ return "border-green-200 dark:border-green-800 bg-green-50/50 dark:bg-green-950/20";
5713
+ case "failed":
5714
+ return "border-red-200 dark:border-red-800 bg-red-50/50 dark:bg-red-950/20";
5715
+ default:
5716
+ return "border-gray-200 dark:border-gray-700";
5717
+ }
5718
+ }, [event.status]);
5719
+ return /* @__PURE__ */ jsx(
5720
+ "div",
5721
+ {
5722
+ className: cn6(
5723
+ "rounded-lg border text-sm px-3 py-2",
5724
+ statusColor,
5725
+ className
5726
+ ),
5727
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
5728
+ statusIcon,
5729
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
5730
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
5731
+ event.fromAgent && /* @__PURE__ */ jsxs(Fragment, { children: [
5732
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700 dark:text-gray-300 truncate", children: event.fromAgent }),
5733
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400 dark:text-gray-500 flex-shrink-0", children: "\u2192" })
5734
+ ] }),
5735
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-900 dark:text-gray-100 truncate", children: event.toAgent || event.targetAgentUuid || "Specialist" })
5736
+ ] }),
5737
+ 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 }),
5738
+ 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 })
5739
+ ] }),
5740
+ 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) })
5741
+ ] })
5742
+ }
5743
+ );
5744
+ }
5745
+ function DelegationProgressList({
5746
+ events,
5747
+ className
5748
+ }) {
5749
+ if (!events || events.length === 0) return null;
5750
+ return /* @__PURE__ */ jsx("div", { className: cn6("space-y-2", className), children: events.map((event, index) => /* @__PURE__ */ jsx(
5751
+ DelegationProgress,
5752
+ {
5753
+ event
5754
+ },
5755
+ event.handoffId || `delegation-${index}`
5756
+ )) });
5757
+ }
5758
+ function ImageLightbox({
5759
+ images,
5760
+ currentIndex,
5761
+ onClose,
5762
+ onPrev,
5763
+ onNext,
5764
+ className
5765
+ }) {
5766
+ const currentImage = images[currentIndex];
5767
+ const hasMultiple = images.length > 1;
5768
+ useEffect(() => {
5769
+ function handleKeyDown(e) {
5770
+ switch (e.key) {
5771
+ case "Escape":
5772
+ onClose();
5773
+ break;
5774
+ case "ArrowLeft":
5775
+ if (hasMultiple) onPrev();
5776
+ break;
5777
+ case "ArrowRight":
5778
+ if (hasMultiple) onNext();
5779
+ break;
5780
+ }
5781
+ }
5782
+ document.addEventListener("keydown", handleKeyDown);
5783
+ return () => document.removeEventListener("keydown", handleKeyDown);
5784
+ }, [onClose, onPrev, onNext, hasMultiple]);
5785
+ useEffect(() => {
5786
+ const originalOverflow = document.body.style.overflow;
5787
+ document.body.style.overflow = "hidden";
5788
+ return () => {
5789
+ document.body.style.overflow = originalOverflow;
5790
+ };
5791
+ }, []);
5792
+ const handleDownload = useCallback(() => {
5793
+ if (!currentImage) return;
5794
+ const link = document.createElement("a");
5795
+ link.href = currentImage.url;
5796
+ link.download = currentImage.filename || `image-${currentIndex + 1}`;
5797
+ link.target = "_blank";
5798
+ link.rel = "noopener noreferrer";
5799
+ document.body.appendChild(link);
5800
+ link.click();
5801
+ document.body.removeChild(link);
5802
+ }, [currentImage, currentIndex]);
5803
+ if (!currentImage) return null;
5804
+ return /* @__PURE__ */ jsxs(
5805
+ "div",
5806
+ {
5807
+ className: `fixed inset-0 z-50 flex items-center justify-center bg-black/80 ${className || ""}`,
5808
+ onClick: onClose,
5809
+ children: [
5810
+ /* @__PURE__ */ jsxs("div", { className: "absolute top-0 left-0 right-0 flex items-center justify-between p-4 z-10", children: [
5811
+ /* @__PURE__ */ jsx("div", { className: "text-white text-sm", children: hasMultiple && /* @__PURE__ */ jsxs("span", { children: [
5812
+ currentIndex + 1,
5813
+ " / ",
5814
+ images.length
5815
+ ] }) }),
5816
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
5817
+ /* @__PURE__ */ jsx(
5818
+ "button",
5819
+ {
5820
+ type: "button",
5821
+ onClick: (e) => {
5822
+ e.stopPropagation();
5823
+ handleDownload();
5824
+ },
5825
+ className: "p-2 rounded-full bg-black/50 hover:bg-black/70 text-white transition-colors",
5826
+ "aria-label": "Download image",
5827
+ children: /* @__PURE__ */ jsx(DownloadIcon, { className: "h-5 w-5" })
5828
+ }
5829
+ ),
5830
+ /* @__PURE__ */ jsx(
5831
+ "button",
5832
+ {
5833
+ type: "button",
5834
+ onClick: (e) => {
5835
+ e.stopPropagation();
5836
+ onClose();
5837
+ },
5838
+ className: "p-2 rounded-full bg-black/50 hover:bg-black/70 text-white transition-colors",
5839
+ "aria-label": "Close lightbox",
5840
+ children: /* @__PURE__ */ jsx(XIcon, { className: "h-5 w-5" })
5841
+ }
5842
+ )
5843
+ ] })
5844
+ ] }),
5845
+ hasMultiple && /* @__PURE__ */ jsx(
5846
+ "button",
5847
+ {
5848
+ type: "button",
5849
+ onClick: (e) => {
5850
+ e.stopPropagation();
5851
+ onPrev();
5852
+ },
5853
+ className: "absolute left-4 top-1/2 -translate-y-1/2 p-2 rounded-full bg-black/50 hover:bg-black/70 text-white transition-colors z-10",
5854
+ "aria-label": "Previous image",
5855
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "h-6 w-6" })
5856
+ }
5857
+ ),
5858
+ /* @__PURE__ */ jsx(
5859
+ "img",
5860
+ {
5861
+ src: currentImage.url,
5862
+ alt: currentImage.alt || `Image ${currentIndex + 1}`,
5863
+ className: "max-w-[90vw] max-h-[85vh] object-contain",
5864
+ onClick: (e) => e.stopPropagation()
5865
+ }
5866
+ ),
5867
+ hasMultiple && /* @__PURE__ */ jsx(
5868
+ "button",
5869
+ {
5870
+ type: "button",
5871
+ onClick: (e) => {
5872
+ e.stopPropagation();
5873
+ onNext();
5874
+ },
5875
+ className: "absolute right-4 top-1/2 -translate-y-1/2 p-2 rounded-full bg-black/50 hover:bg-black/70 text-white transition-colors z-10",
5876
+ "aria-label": "Next image",
5877
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-6 w-6" })
5878
+ }
5879
+ ),
5880
+ currentImage.alt && /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 p-4 text-center z-10", children: /* @__PURE__ */ jsx("p", { className: "text-white text-sm bg-black/50 inline-block px-3 py-1 rounded-full", children: currentImage.alt }) })
5881
+ ]
5882
+ }
5883
+ );
5884
+ }
5885
+ function cn7(...classes) {
5886
+ return classes.filter(Boolean).join(" ");
5887
+ }
5888
+ function ImageWithLoading({ src, alt, className, onClick }) {
5889
+ const [isLoaded, setIsLoaded] = useState(false);
5890
+ const [hasError, setHasError] = useState(false);
5891
+ return /* @__PURE__ */ jsxs(
5892
+ "div",
5893
+ {
5894
+ className: cn7(
5895
+ "relative overflow-hidden bg-gray-100 dark:bg-gray-800",
5896
+ className
5897
+ ),
5898
+ children: [
5899
+ !isLoaded && !hasError && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 animate-pulse bg-gray-200 dark:bg-gray-700" }),
5900
+ hasError && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-gray-400 dark:text-gray-500 text-sm", children: "Failed to load" }),
5901
+ /* @__PURE__ */ jsx(
5902
+ "img",
5903
+ {
5904
+ src,
5905
+ alt,
5906
+ loading: "lazy",
5907
+ className: cn7(
5908
+ "w-full h-auto max-h-[300px] object-contain transition-opacity duration-200",
5909
+ isLoaded ? "opacity-100" : "opacity-0"
5910
+ ),
5911
+ onLoad: () => setIsLoaded(true),
5912
+ onError: () => setHasError(true),
5913
+ onClick,
5914
+ style: onClick ? { cursor: "pointer" } : void 0
5915
+ }
5916
+ )
5917
+ ]
5918
+ }
5919
+ );
5920
+ }
5921
+ function ImageGallery({
5922
+ images,
5923
+ onImageClick,
5924
+ className
5925
+ }) {
5926
+ const [lightboxIndex, setLightboxIndex] = useState(null);
5927
+ const handleImageClick = useCallback(
5928
+ (image, index) => {
5929
+ if (onImageClick) {
5930
+ onImageClick(image);
5931
+ } else {
5932
+ setLightboxIndex(index);
5933
+ }
5934
+ },
5935
+ [onImageClick]
5936
+ );
5937
+ const handleLightboxClose = useCallback(() => {
5938
+ setLightboxIndex(null);
5939
+ }, []);
5940
+ const handleLightboxPrev = useCallback(() => {
5941
+ setLightboxIndex(
5942
+ (prev) => prev !== null ? (prev - 1 + images.length) % images.length : null
5943
+ );
5944
+ }, [images.length]);
5945
+ const handleLightboxNext = useCallback(() => {
5946
+ setLightboxIndex(
5947
+ (prev) => prev !== null ? (prev + 1) % images.length : null
5948
+ );
5949
+ }, [images.length]);
5950
+ if (!images || images.length === 0) return null;
5951
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
5952
+ /* @__PURE__ */ jsx(
5953
+ "div",
5954
+ {
5955
+ className: cn7(
5956
+ "grid gap-2",
5957
+ images.length === 1 ? "grid-cols-1" : images.length === 2 ? "grid-cols-2" : "grid-cols-2 sm:grid-cols-3",
5958
+ className
5959
+ ),
5960
+ children: images.map((image, index) => /* @__PURE__ */ jsx(
5961
+ "button",
5962
+ {
5963
+ type: "button",
5964
+ onClick: () => handleImageClick(image, index),
5965
+ 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 text-left",
5966
+ children: /* @__PURE__ */ jsx(
5967
+ ImageWithLoading,
5968
+ {
5969
+ src: image.url,
5970
+ alt: image.alt || `Image ${index + 1}`
5971
+ }
5972
+ )
5973
+ },
5974
+ `${image.url}-${index}`
5975
+ ))
5976
+ }
5977
+ ),
5978
+ lightboxIndex !== null && !onImageClick && /* @__PURE__ */ jsx(
5979
+ ImageLightbox,
5980
+ {
5981
+ images,
5982
+ currentIndex: lightboxIndex,
5983
+ onClose: handleLightboxClose,
5984
+ onPrev: handleLightboxPrev,
5985
+ onNext: handleLightboxNext
5986
+ }
5987
+ )
5988
+ ] });
5989
+ }
5990
+ function cn8(...classes) {
5991
+ return classes.filter(Boolean).join(" ");
5992
+ }
5412
5993
  function MarkdownContent({
5413
5994
  content,
5414
5995
  className,
@@ -5428,11 +6009,11 @@ function MarkdownContent({
5428
6009
  h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mt-3 mb-1 first:mt-0", children }),
5429
6010
  h4: ({ children }) => /* @__PURE__ */ jsx("h4", { className: "text-base font-semibold mt-2 mb-1 first:mt-0", children }),
5430
6011
  // Paragraphs
5431
- p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "mb-2 last:mb-0 leading-relaxed", children }),
6012
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "mb-1.5 last:mb-0", children }),
5432
6013
  // 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 }),
6014
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside mb-1.5 last:mb-0", children }),
6015
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "list-decimal list-inside mb-1.5 last:mb-0", children }),
6016
+ li: ({ children }) => /* @__PURE__ */ jsx("li", { className: "", children }),
5436
6017
  // Links
5437
6018
  a: ({ href, children }) => /* @__PURE__ */ jsx(
5438
6019
  "a",
@@ -5467,7 +6048,7 @@ function MarkdownContent({
5467
6048
  if (isCodeBlock) {
5468
6049
  return /* @__PURE__ */ jsxs("div", { className: "relative my-2", children: [
5469
6050
  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 }) })
6051
+ /* @__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
6052
  ] });
5472
6053
  }
5473
6054
  return /* @__PURE__ */ jsx(
@@ -5514,7 +6095,7 @@ function MarkdownContent({
5514
6095
  () => customComponents ? { ...defaultComponents, ...customComponents } : defaultComponents,
5515
6096
  [defaultComponents, customComponents]
5516
6097
  );
5517
- return /* @__PURE__ */ jsx("div", { className: cn6("prose prose-sm dark:prose-invert max-w-none", className), children: /* @__PURE__ */ jsx(
6098
+ return /* @__PURE__ */ jsx("div", { className: cn8("max-w-none text-sm leading-relaxed", className), children: /* @__PURE__ */ jsx(
5518
6099
  ReactMarkdown,
5519
6100
  {
5520
6101
  remarkPlugins: [remarkGfm],
@@ -5524,6 +6105,58 @@ function MarkdownContent({
5524
6105
  }
5525
6106
  ) });
5526
6107
  }
6108
+ function cn9(...classes) {
6109
+ return classes.filter(Boolean).join(" ");
6110
+ }
6111
+ function ThinkingBlock({
6112
+ block,
6113
+ defaultExpanded = false,
6114
+ className
6115
+ }) {
6116
+ const [isExpanded, setIsExpanded] = useState(defaultExpanded);
6117
+ return /* @__PURE__ */ jsxs(
6118
+ "div",
6119
+ {
6120
+ className: cn9(
6121
+ "rounded-lg border",
6122
+ "border-purple-200 dark:border-purple-800",
6123
+ "bg-purple-50/50 dark:bg-purple-950/20",
6124
+ className
6125
+ ),
6126
+ children: [
6127
+ /* @__PURE__ */ jsxs(
6128
+ "button",
6129
+ {
6130
+ type: "button",
6131
+ onClick: () => setIsExpanded(!isExpanded),
6132
+ 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",
6133
+ children: [
6134
+ 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" }),
6135
+ /* @__PURE__ */ jsx(SparklesIcon, { className: "h-4 w-4 text-purple-500 flex-shrink-0" }),
6136
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-purple-700 dark:text-purple-300", children: "Thinking" })
6137
+ ]
6138
+ }
6139
+ ),
6140
+ 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 }) })
6141
+ ]
6142
+ }
6143
+ );
6144
+ }
6145
+ function ThinkingBlockList({
6146
+ blocks,
6147
+ defaultExpanded = false,
6148
+ className
6149
+ }) {
6150
+ if (!blocks || blocks.length === 0) return null;
6151
+ return /* @__PURE__ */ jsx("div", { className: cn9("space-y-2", className), children: blocks.map((block) => /* @__PURE__ */ jsx(
6152
+ ThinkingBlock,
6153
+ {
6154
+ block,
6155
+ defaultExpanded
6156
+ },
6157
+ block.id
6158
+ )) });
6159
+ }
5527
6160
  var INTERNAL_TOOL_NAMES = /* @__PURE__ */ new Set([
5528
6161
  "update_task_list",
5529
6162
  "create_task",
@@ -5554,7 +6187,7 @@ function isInternalTool(toolName) {
5554
6187
  }
5555
6188
  return false;
5556
6189
  }
5557
- function cn7(...classes) {
6190
+ function cn10(...classes) {
5558
6191
  return classes.filter(Boolean).join(" ");
5559
6192
  }
5560
6193
  function formatToolName(toolName) {
@@ -5603,7 +6236,7 @@ function formatToolName(toolName) {
5603
6236
  }
5604
6237
  return uniqueWords.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
5605
6238
  }
5606
- function formatDuration(ms) {
6239
+ function formatDuration2(ms) {
5607
6240
  if (ms < 1e3) {
5608
6241
  return `${ms}ms`;
5609
6242
  }
@@ -5624,7 +6257,7 @@ function formatJsonPreview(data, maxLength = 100) {
5624
6257
  return String(data);
5625
6258
  }
5626
6259
  }
5627
- function extractImagesFromResult(result) {
6260
+ function extractImagesFromResult2(result) {
5628
6261
  if (!result) return [];
5629
6262
  let data = result;
5630
6263
  if (typeof result === "string") {
@@ -5668,7 +6301,7 @@ function ToolCallEntry({
5668
6301
  [toolCall.name]
5669
6302
  );
5670
6303
  const resultImages = useMemo(
5671
- () => toolCall.status === "completed" && toolCall.result ? extractImagesFromResult(toolCall.result) : [],
6304
+ () => toolCall.status === "completed" && toolCall.result ? extractImagesFromResult2(toolCall.result) : [],
5672
6305
  [toolCall.status, toolCall.result]
5673
6306
  );
5674
6307
  const hasImages = resultImages.length > 0;
@@ -5704,14 +6337,14 @@ function ToolCallEntry({
5704
6337
  return /* @__PURE__ */ jsxs(
5705
6338
  "div",
5706
6339
  {
5707
- className: cn7(
6340
+ className: cn10(
5708
6341
  "inline-flex items-center gap-1.5 text-xs text-gray-500 dark:text-gray-400",
5709
6342
  className
5710
6343
  ),
5711
6344
  children: [
5712
6345
  /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: statusIcon }),
5713
6346
  /* @__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) })
6347
+ toolCall.durationMs !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-gray-400 dark:text-gray-500", children: formatDuration2(toolCall.durationMs) })
5715
6348
  ]
5716
6349
  }
5717
6350
  );
@@ -5719,7 +6352,7 @@ function ToolCallEntry({
5719
6352
  return /* @__PURE__ */ jsxs(
5720
6353
  "div",
5721
6354
  {
5722
- className: cn7(
6355
+ className: cn10(
5723
6356
  "rounded-lg border text-sm",
5724
6357
  statusColor,
5725
6358
  className
@@ -5735,12 +6368,12 @@ function ToolCallEntry({
5735
6368
  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
6369
  /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: statusIcon }),
5737
6370
  /* @__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) }),
6371
+ 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
6372
  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
6373
  ]
5741
6374
  }
5742
6375
  ),
5743
- hasImages && /* @__PURE__ */ jsx("div", { className: "px-3 pb-2", children: /* @__PURE__ */ jsx("div", { className: cn7(
6376
+ hasImages && /* @__PURE__ */ jsx("div", { className: "px-3 pb-2", children: /* @__PURE__ */ jsx("div", { className: cn10(
5744
6377
  "grid gap-2",
5745
6378
  resultImages.length === 1 ? "grid-cols-1" : "grid-cols-2"
5746
6379
  ), children: resultImages.map((img, idx) => {
@@ -5799,22 +6432,28 @@ function ToolCallEntry({
5799
6432
  }
5800
6433
  );
5801
6434
  }
5802
- function cn8(...classes) {
6435
+ function cn11(...classes) {
5803
6436
  return classes.filter(Boolean).join(" ");
5804
6437
  }
5805
6438
  function ChatMessage({
5806
6439
  message,
5807
6440
  enableMarkdown = true,
5808
6441
  showToolCalls = true,
5809
- toolCallVerbosity,
6442
+ toolCallVerbosity: _toolCallVerbosity,
5810
6443
  className,
5811
6444
  markdownComponents,
5812
6445
  markdownUrlTransform,
5813
6446
  markdownContentTransform,
5814
- onImageClick
6447
+ onImageClick,
6448
+ showThinking = true,
6449
+ showDelegation = true,
6450
+ showImages = true,
6451
+ renderToolCall,
6452
+ variant = "bubble"
5815
6453
  }) {
5816
6454
  const isUser = message.role === "user";
5817
6455
  const isAssistant = message.role === "assistant";
6456
+ const isFlat = variant === "flat";
5818
6457
  const formattedTime = useMemo(() => {
5819
6458
  const date = message.timestamp instanceof Date ? message.timestamp : new Date(message.timestamp);
5820
6459
  return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
@@ -5822,113 +6461,124 @@ function ChatMessage({
5822
6461
  return /* @__PURE__ */ jsxs(
5823
6462
  "div",
5824
6463
  {
5825
- className: cn8(
5826
- "flex gap-3 p-4",
5827
- isUser ? "flex-row-reverse" : "flex-row",
6464
+ className: cn11(
6465
+ "cadra-chat-message flex gap-3",
6466
+ isFlat ? "py-5 px-4" : "p-4",
6467
+ // Bubble: user messages right-aligned. Flat: always left-aligned.
6468
+ !isFlat && isUser ? "flex-row-reverse" : "flex-row",
6469
+ // Flat variant: subtle row background for user messages
6470
+ isFlat && isUser && "chat-message-user-row",
5828
6471
  className
5829
6472
  ),
6473
+ style: isFlat && isUser ? {
6474
+ backgroundColor: "var(--chat-user-row-bg, rgba(128, 128, 128, 0.08))"
6475
+ } : void 0,
6476
+ "data-role": message.role,
5830
6477
  children: [
5831
6478
  /* @__PURE__ */ jsx(
5832
6479
  "div",
5833
6480
  {
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
- ),
6481
+ className: "flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center shadow-sm",
6482
+ style: {
6483
+ backgroundColor: isUser ? "var(--chat-user-avatar-bg, #3b82f6)" : "var(--chat-assistant-avatar-bg, #e5e7eb)",
6484
+ color: isUser ? "var(--chat-user-avatar-text, #fff)" : "var(--chat-assistant-avatar-text, #4b5563)"
6485
+ },
5838
6486
  children: isUser ? /* @__PURE__ */ jsx(UserIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(BotIcon, { className: "h-4 w-4" })
5839
6487
  }
5840
6488
  ),
5841
6489
  /* @__PURE__ */ jsxs(
5842
6490
  "div",
5843
6491
  {
5844
- className: cn8(
5845
- "flex-1 min-w-0 space-y-2",
5846
- isUser ? "text-right" : "text-left"
6492
+ className: cn11(
6493
+ "flex-1 min-w-0",
6494
+ isFlat ? "pt-0.5" : "space-y-2",
6495
+ !isFlat && isUser ? "text-right" : "text-left"
5847
6496
  ),
5848
6497
  children: [
5849
6498
  /* @__PURE__ */ jsxs(
5850
6499
  "div",
5851
6500
  {
5852
- className: cn8(
5853
- "flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400",
5854
- isUser ? "justify-end" : "justify-start"
6501
+ className: cn11(
6502
+ "flex items-center gap-2 text-xs",
6503
+ isFlat ? "mb-1.5" : "",
6504
+ !isFlat && isUser ? "justify-end" : "justify-start"
5855
6505
  ),
6506
+ style: { color: "var(--chat-meta-text, #6b7280)" },
5856
6507
  children: [
5857
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: isUser ? "You" : "Assistant" }),
6508
+ /* @__PURE__ */ jsx("span", { className: "font-medium", style: { color: "var(--chat-label-text, inherit)" }, children: isUser ? "You" : "Assistant" }),
5858
6509
  /* @__PURE__ */ jsx("span", { children: formattedTime }),
5859
6510
  message.isStreaming && /* @__PURE__ */ jsx(LoadingSpinner, { className: "h-3 w-3" })
5860
6511
  ]
5861
6512
  }
5862
6513
  ),
5863
- message.thinkingBlocks && message.thinkingBlocks.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: message.thinkingBlocks.map((block) => /* @__PURE__ */ jsxs(
5864
- "div",
5865
- {
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
- ] });
5900
- }
5901
- return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: filteredToolCalls.map((toolCall) => /* @__PURE__ */ jsx(
6514
+ showThinking && message.thinkingBlocks && message.thinkingBlocks.length > 0 && /* @__PURE__ */ jsx(ThinkingBlockList, { blocks: message.thinkingBlocks }),
6515
+ showDelegation && message.delegationEvents && message.delegationEvents.length > 0 && /* @__PURE__ */ jsx(DelegationProgressList, { events: message.delegationEvents }),
6516
+ showToolCalls && message.toolCalls && message.toolCalls.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: message.toolCalls.map((toolCall) => {
6517
+ const defaultRender = () => /* @__PURE__ */ jsx(
5902
6518
  ToolCallEntry,
5903
6519
  {
5904
6520
  toolCall,
5905
6521
  onImageClick
5906
6522
  },
5907
6523
  toolCall.id
5908
- )) });
5909
- })(),
5910
- message.content && /* @__PURE__ */ jsx(
5911
- "div",
6524
+ );
6525
+ if (renderToolCall) {
6526
+ return /* @__PURE__ */ jsx("div", { children: renderToolCall(toolCall, defaultRender) }, toolCall.id);
6527
+ }
6528
+ return defaultRender();
6529
+ }) }),
6530
+ showImages && message.images && message.images.length > 0 && /* @__PURE__ */ jsx(
6531
+ ImageGallery,
5912
6532
  {
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 })
6533
+ images: message.images,
6534
+ onImageClick: onImageClick ? (img) => onImageClick({ url: img.url, alt: img.alt, filename: img.filename }) : void 0
5926
6535
  }
5927
6536
  ),
6537
+ message.content && (isFlat ? (
6538
+ // Flat variant: no bubble, just text with theme-aware color
6539
+ /* @__PURE__ */ jsx(
6540
+ "div",
6541
+ {
6542
+ className: cn11("text-sm break-words", !(isAssistant && enableMarkdown) && "whitespace-pre-wrap"),
6543
+ style: { color: "var(--chat-content-text, inherit)" },
6544
+ children: isAssistant && enableMarkdown ? /* @__PURE__ */ jsx(
6545
+ MarkdownContent,
6546
+ {
6547
+ content: message.content,
6548
+ components: markdownComponents,
6549
+ urlTransform: markdownUrlTransform,
6550
+ contentTransform: markdownContentTransform
6551
+ }
6552
+ ) : /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap", children: message.content })
6553
+ }
6554
+ )
6555
+ ) : (
6556
+ // Bubble variant: colored bubble backgrounds
6557
+ /* @__PURE__ */ jsx(
6558
+ "div",
6559
+ {
6560
+ className: "rounded-lg p-3",
6561
+ style: {
6562
+ backgroundColor: isUser ? "var(--chat-user-bg, #3b82f6)" : "var(--chat-assistant-bg, #f3f4f6)",
6563
+ color: isUser ? "var(--chat-user-text, #fff)" : "var(--chat-assistant-text, #111827)"
6564
+ },
6565
+ children: isAssistant && enableMarkdown ? /* @__PURE__ */ jsx(
6566
+ MarkdownContent,
6567
+ {
6568
+ content: message.content,
6569
+ components: markdownComponents,
6570
+ urlTransform: markdownUrlTransform,
6571
+ contentTransform: markdownContentTransform
6572
+ }
6573
+ ) : /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap", children: message.content })
6574
+ }
6575
+ )
6576
+ )),
5928
6577
  message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: message.attachments.map((attachment) => /* @__PURE__ */ jsx(
5929
6578
  "div",
5930
6579
  {
5931
- className: "flex items-center gap-2 bg-gray-100 dark:bg-gray-800 rounded-lg px-3 py-2 text-sm",
6580
+ className: "flex items-center gap-2 rounded-lg px-3 py-2 text-sm",
6581
+ style: { backgroundColor: "var(--chat-assistant-bg, #f3f4f6)" },
5932
6582
  children: /* @__PURE__ */ jsx("span", { className: "truncate max-w-[150px]", children: attachment.filename })
5933
6583
  },
5934
6584
  attachment.uuid
@@ -5940,7 +6590,7 @@ function ChatMessage({
5940
6590
  }
5941
6591
  );
5942
6592
  }
5943
- function cn9(...classes) {
6593
+ function cn12(...classes) {
5944
6594
  return classes.filter(Boolean).join(" ");
5945
6595
  }
5946
6596
  function MessageList({
@@ -5958,6 +6608,12 @@ function MessageList({
5958
6608
  markdownUrlTransform,
5959
6609
  markdownContentTransform,
5960
6610
  onImageClick,
6611
+ showThinking = true,
6612
+ showDelegation = true,
6613
+ showImages = true,
6614
+ renderMessage,
6615
+ renderToolCall,
6616
+ messageVariant = "bubble",
5961
6617
  sendMessage
5962
6618
  }) {
5963
6619
  const scrollRef = useRef(null);
@@ -5971,7 +6627,7 @@ function MessageList({
5971
6627
  "div",
5972
6628
  {
5973
6629
  ref: scrollRef,
5974
- className: cn9(
6630
+ className: cn12(
5975
6631
  "flex-1 overflow-y-auto",
5976
6632
  className
5977
6633
  ),
@@ -5982,20 +6638,31 @@ function MessageList({
5982
6638
  ] }) }),
5983
6639
  messages.length === 0 && !isLoading && !isLoadingHistory && (renderWelcome ? /* @__PURE__ */ jsx(Fragment, { children: typeof renderWelcome === "function" ? renderWelcome({ sendMessage: sendMessage || (() => {
5984
6640
  }) }) : 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
- )) }),
6641
+ /* @__PURE__ */ jsx("div", { className: "divide-y divide-gray-100 dark:divide-gray-800", children: messages.map((message) => {
6642
+ const defaultRender = () => /* @__PURE__ */ jsx(
6643
+ ChatMessage,
6644
+ {
6645
+ message,
6646
+ enableMarkdown,
6647
+ showToolCalls,
6648
+ toolCallVerbosity,
6649
+ markdownComponents,
6650
+ markdownUrlTransform,
6651
+ markdownContentTransform,
6652
+ onImageClick,
6653
+ showThinking,
6654
+ showDelegation,
6655
+ showImages,
6656
+ renderToolCall,
6657
+ variant: messageVariant
6658
+ },
6659
+ message.id
6660
+ );
6661
+ if (renderMessage) {
6662
+ return /* @__PURE__ */ jsx("div", { children: renderMessage(message, defaultRender) }, message.id);
6663
+ }
6664
+ return defaultRender();
6665
+ }) }),
5999
6666
  isLoading && !isStreaming && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 p-4", children: [
6000
6667
  /* @__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
6668
  /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Thinking..." })
@@ -6051,6 +6718,7 @@ function AgentChat({
6051
6718
  maxHeight = "600px",
6052
6719
  className,
6053
6720
  theme = "system",
6721
+ layout = "fixed",
6054
6722
  enableAttachments = false,
6055
6723
  enableMarkdown = true,
6056
6724
  showToolCalls = true,
@@ -6058,7 +6726,20 @@ function AgentChat({
6058
6726
  markdownComponents,
6059
6727
  markdownUrlTransform,
6060
6728
  markdownContentTransform,
6061
- onImageClick
6729
+ onImageClick,
6730
+ // Extension props
6731
+ hideHeader,
6732
+ renderAboveInput,
6733
+ renderBelowMessages,
6734
+ renderMessage,
6735
+ renderToolCall,
6736
+ messageVariant = "bubble",
6737
+ showThinking = true,
6738
+ showDelegation = true,
6739
+ showImages = true,
6740
+ pollingInterval,
6741
+ pollingEnabled,
6742
+ onDelegation
6062
6743
  }) {
6063
6744
  const {
6064
6745
  messages,
@@ -6085,7 +6766,10 @@ function AgentChat({
6085
6766
  onSessionStart,
6086
6767
  onToolCall,
6087
6768
  onToolResult,
6088
- onClarification
6769
+ onClarification,
6770
+ onDelegation,
6771
+ pollingInterval,
6772
+ pollingEnabled
6089
6773
  });
6090
6774
  const effectiveVerbosity = showToolCalls === false ? "hidden" : toolCallVerbosity ?? "compact";
6091
6775
  const dropZoneRef = useRef(null);
@@ -6114,51 +6798,31 @@ function AgentChat({
6114
6798
  },
6115
6799
  [enableAttachments, attachments, sendMessage]
6116
6800
  );
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
- ),
6801
+ const messageListProps = {
6802
+ messages,
6803
+ welcomeMessage: hideHeader ? void 0 : welcomeMessage,
6804
+ renderWelcome: hideHeader ? void 0 : renderWelcome,
6805
+ isLoading,
6806
+ isStreaming,
6807
+ isLoadingHistory,
6808
+ enableMarkdown,
6809
+ showToolCalls,
6810
+ toolCallVerbosity: effectiveVerbosity,
6811
+ markdownComponents,
6812
+ markdownUrlTransform,
6813
+ markdownContentTransform,
6814
+ onImageClick,
6815
+ showThinking,
6816
+ showDelegation,
6817
+ showImages,
6818
+ renderMessage,
6819
+ renderToolCall,
6820
+ messageVariant,
6821
+ sendMessage: handleSend
6822
+ };
6823
+ const chatContent = /* @__PURE__ */ jsxs(Fragment, { children: [
6824
+ /* @__PURE__ */ jsx(MessageList, { ...messageListProps }),
6825
+ renderBelowMessages?.(),
6162
6826
  clarification && /* @__PURE__ */ jsx("div", { className: "border-t border-gray-200 dark:border-gray-700 p-4", children: /* @__PURE__ */ jsx(
6163
6827
  AskUserPrompt,
6164
6828
  {
@@ -6168,6 +6832,7 @@ function AgentChat({
6168
6832
  }
6169
6833
  ) }),
6170
6834
  error && /* @__PURE__ */ jsx(ErrorBanner, { error, onRetry: retry, onDismiss: clearError }),
6835
+ renderAboveInput?.(),
6171
6836
  /* @__PURE__ */ jsx(
6172
6837
  ChatInput,
6173
6838
  {
@@ -6184,8 +6849,17 @@ function AgentChat({
6184
6849
  }
6185
6850
  )
6186
6851
  ] });
6852
+ return /* @__PURE__ */ jsx(ChatContainer, { maxHeight, className, theme, layout, children: enableAttachments ? /* @__PURE__ */ jsx(
6853
+ FileDropZone,
6854
+ {
6855
+ ref: dropZoneRef,
6856
+ ...attachments.dropZoneProps,
6857
+ disabled: isLoading || !!clarification || isLoadingHistory,
6858
+ children: chatContent
6859
+ }
6860
+ ) : chatContent });
6187
6861
  }
6188
- function cn10(...classes) {
6862
+ function cn13(...classes) {
6189
6863
  return classes.filter(Boolean).join(" ");
6190
6864
  }
6191
6865
  function TodoList({
@@ -6214,7 +6888,7 @@ function TodoList({
6214
6888
  return /* @__PURE__ */ jsxs(
6215
6889
  "div",
6216
6890
  {
6217
- className: cn10(
6891
+ className: cn13(
6218
6892
  "rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden",
6219
6893
  className
6220
6894
  ),
@@ -6222,7 +6896,7 @@ function TodoList({
6222
6896
  /* @__PURE__ */ jsxs(
6223
6897
  "div",
6224
6898
  {
6225
- className: cn10(
6899
+ className: cn13(
6226
6900
  "flex items-center gap-2 px-3 py-2 bg-gray-50 dark:bg-gray-800/50",
6227
6901
  collapsible && "cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800"
6228
6902
  ),
@@ -6253,7 +6927,7 @@ function TodoList({
6253
6927
  !isCollapsed && /* @__PURE__ */ jsx("ul", { className: "divide-y divide-gray-100 dark:divide-gray-700", children: todos.map((todo, idx) => /* @__PURE__ */ jsxs(
6254
6928
  "li",
6255
6929
  {
6256
- className: cn10(
6930
+ className: cn13(
6257
6931
  "px-3 py-2 flex items-start gap-2 text-sm",
6258
6932
  todo.status === "in_progress" && "bg-blue-50/50 dark:bg-blue-950/20",
6259
6933
  todo.status === "completed" && "opacity-60"
@@ -6263,7 +6937,7 @@ function TodoList({
6263
6937
  /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(
6264
6938
  "p",
6265
6939
  {
6266
- className: cn10(
6940
+ className: cn13(
6267
6941
  "text-gray-700 dark:text-gray-300",
6268
6942
  todo.status === "completed" && "line-through"
6269
6943
  ),
@@ -6280,39 +6954,6 @@ function TodoList({
6280
6954
  );
6281
6955
  }
6282
6956
 
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 };
6957
+ 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
6958
  //# sourceMappingURL=index.js.map
6318
6959
  //# sourceMappingURL=index.js.map