@optilogic/chat 1.3.2 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -197,6 +197,14 @@ interface AgentMessage {
197
197
  message?: string;
198
198
  /** Alternative content field */
199
199
  content?: string;
200
+ /**
201
+ * Optional event timestamp (epoch ms). When supplied, the reducer uses this
202
+ * for the item's `timestamp` and any state-level timing fields it sets
203
+ * (`firstMessageTime`, `thinkingStartTime`, `responseCompleteTime`) instead
204
+ * of `Date.now()`. Provide this when replaying historical events so durations
205
+ * reflect the original run rather than load time.
206
+ */
207
+ timestamp?: number;
200
208
  /** For status messages */
201
209
  status?: string;
202
210
  /** Agent name (multi-agent scenarios) */
@@ -318,6 +326,12 @@ declare const HITLInteractionRecord: React.ForwardRefExoticComponent<HITLInterac
318
326
  * Displays thinking, tool calls, knowledge retrieval, memory access, and final response.
319
327
  */
320
328
 
329
+ interface AgentResponseClassNames {
330
+ /** Classes for the inner container (border, rounded corners, overflow) */
331
+ container?: string;
332
+ /** Classes for the response content section (background, padding) */
333
+ response?: string;
334
+ }
321
335
  interface AgentResponseProps extends React.HTMLAttributes<HTMLDivElement> {
322
336
  /** The response state to render */
323
337
  state: AgentResponseState;
@@ -389,6 +403,21 @@ interface AgentResponseProps extends React.HTMLAttributes<HTMLDivElement> {
389
403
  * Defaults to "300px". Set to "none" to disable the constraint.
390
404
  */
391
405
  timelineMaxHeight?: string;
406
+ /**
407
+ * Class name overrides for internal elements.
408
+ * Use this to customize the container border/background or response section styling.
409
+ *
410
+ * @example
411
+ * // Transparent background and borders
412
+ * <AgentResponse
413
+ * state={state}
414
+ * classNames={{
415
+ * container: "border-transparent",
416
+ * response: "bg-transparent",
417
+ * }}
418
+ * />
419
+ */
420
+ classNames?: AgentResponseClassNames;
392
421
  }
393
422
  /**
394
423
  * AgentResponse Component
@@ -651,7 +680,10 @@ declare function useThinkingTimer({ startTime, endTime, status, }: UseThinkingTi
651
680
  /**
652
681
  * useAgentResponseAccumulator Hook
653
682
  *
654
- * Accumulates agent response messages into a unified state
683
+ * Accumulates agent response messages into a unified state.
684
+ *
685
+ * Thin wrapper around `reduceAgentMessage` — the pure reducer can be used
686
+ * directly outside React for replaying historical events.
655
687
  */
656
688
 
657
689
  interface UseAgentResponseAccumulatorOptions {
@@ -679,6 +711,36 @@ interface UseAgentResponseAccumulatorReturn {
679
711
  */
680
712
  declare function useAgentResponseAccumulator(options?: UseAgentResponseAccumulatorOptions): UseAgentResponseAccumulatorReturn;
681
713
 
714
+ /**
715
+ * Pure reducer for agent response messages.
716
+ *
717
+ * Used by `useAgentResponseAccumulator` for live streaming, and exported so
718
+ * non-React callers (e.g. server-side or store-based replay of historical
719
+ * conversations) can rebuild the same `AgentResponseState` from a sequence of
720
+ * `AgentMessage` events without rendering a component.
721
+ *
722
+ * Replay note on stable IDs: when a payload omits a per-item id
723
+ * (`tool.id`, `thinkingStep.id`, `knowledge.id`, `memory.id`,
724
+ * `statusUpdate.id`), the reducer falls back to `${type}-${Date.now()}`. That
725
+ * is fine for live streams but will produce different React keys on each
726
+ * replay. Callers reconstructing `AgentMessage` events from persisted rows
727
+ * should populate these ids from a stable source (e.g. the supplement-row
728
+ * primary key) so timeline keys remain consistent across reloads.
729
+ */
730
+
731
+ /**
732
+ * Pure reducer: apply a single `AgentMessage` to the accumulated state.
733
+ *
734
+ * `payload.timestamp` (epoch ms), if supplied, is used for the new item's
735
+ * `timestamp` and any state-level timing fields this call sets
736
+ * (`firstMessageTime`, `thinkingStartTime`, `responseCompleteTime`). When
737
+ * absent, `Date.now()` is used — matching the prior live-streaming behaviour.
738
+ *
739
+ * @example
740
+ * const state = events.reduce(reduceAgentMessage, initialAgentResponseState);
741
+ */
742
+ declare function reduceAgentMessage(prev: AgentResponseState, payload: AgentMessage): AgentResponseState;
743
+
682
744
  /**
683
745
  * Agent Response Utility Functions
684
746
  */
@@ -917,4 +979,4 @@ declare function parseResponseSegments(text: string): ResponseSegment[];
917
979
  */
918
980
  declare const INLINE_ACTION_PROMPT = "\n<inline_actions>\nWhen your response should include interactive components (like query viewers,\ndata tables, or executable actions), embed them as fenced code blocks using\nthe `json:action` language tag:\n\n```json:action\n{\n \"type\": \"action-type-here\",\n ...action-specific fields\n}\n```\n\nRules:\n- Each block must contain valid JSON with a \"type\" field.\n- The \"type\" must match a registered action component on the frontend.\n- Multiple action blocks per response are allowed.\n- Surround action blocks with normal markdown text for user context.\n- The action block is rendered as an interactive component in the chat UI.\n- SQL strings inside JSON must be properly escaped (newlines as \\n, quotes as \\\").\n\nAvailable action types:\n\n- \"optimap-query\": Displays SQL queries with a button to execute them and\n update the 3D globe map.\n Required fields:\n - type: \"optimap-query\"\n - locations_sql: string (the validated locations SQL query)\n - routes_sql: string (the validated routes SQL query)\n - database_name: string (the target database name)\n</inline_actions>\n";
919
981
 
920
- export { ActionBar, type ActionBarProps, type ActionComponentRegistry, ActionMarkdownRenderer, type ActionMarkdownRendererProps, type ActionSegment, ActivityIndicators, type ActivityIndicatorsProps, type AgentMessage, AgentResponse, type AgentResponseProps, type AgentResponseState, type AgentResponseStatus, type AgentRun, AgentTimeline, type DisplayEntry, type FeedbackValue, type GenericWebSocketMessage, type HITLInteraction, HITLInteractionRecord, type HITLInteractionRecordProps, type HITLQuestion, HITLQuestionPanel, type HITLQuestionPanelProps, type HITLResponseData, HITLSection, type HITLSectionProps, INLINE_ACTION_PROMPT, type InlineActionProps, type KnowledgeItem, type MarkdownSegment, type MemoryItem, MetadataRow, type MetadataRowProps, type PotentialResponse, type ResponseSegment, type StatusItem, type ThinkingContent, ThinkingSection, type ThinkingSectionProps, type ThinkingStep, type TimelineEntry, type TimelineEntryType, type TimelineUIState, type ToolCall, TruncatedMessage, type TruncatedMessageProps, type UseAgentResponseAccumulatorOptions, type UseAgentResponseAccumulatorReturn, type UseThinkingTimerOptions, UserPrompt, UserPromptInput, type UserPromptInputProps, type UserPromptInputRef, type UserPromptProps, buildResponseString, buildTimelineEntries, createTimelineUIState, deduplicateEntries, formatTime, formatTotalTime, groupIntoAgentRuns, initialAgentResponseState, parseResponseSegments, useAgentResponseAccumulator, useThinkingTimer };
982
+ export { ActionBar, type ActionBarProps, type ActionComponentRegistry, ActionMarkdownRenderer, type ActionMarkdownRendererProps, type ActionSegment, ActivityIndicators, type ActivityIndicatorsProps, type AgentMessage, AgentResponse, type AgentResponseProps, type AgentResponseState, type AgentResponseStatus, type AgentRun, AgentTimeline, type DisplayEntry, type FeedbackValue, type GenericWebSocketMessage, type HITLInteraction, HITLInteractionRecord, type HITLInteractionRecordProps, type HITLQuestion, HITLQuestionPanel, type HITLQuestionPanelProps, type HITLResponseData, HITLSection, type HITLSectionProps, INLINE_ACTION_PROMPT, type InlineActionProps, type KnowledgeItem, type MarkdownSegment, type MemoryItem, MetadataRow, type MetadataRowProps, type PotentialResponse, type ResponseSegment, type StatusItem, type ThinkingContent, ThinkingSection, type ThinkingSectionProps, type ThinkingStep, type TimelineEntry, type TimelineEntryType, type TimelineUIState, type ToolCall, TruncatedMessage, type TruncatedMessageProps, type UseAgentResponseAccumulatorOptions, type UseAgentResponseAccumulatorReturn, type UseThinkingTimerOptions, UserPrompt, UserPromptInput, type UserPromptInputProps, type UserPromptInputRef, type UserPromptProps, buildResponseString, buildTimelineEntries, createTimelineUIState, deduplicateEntries, formatTime, formatTotalTime, groupIntoAgentRuns, initialAgentResponseState, parseResponseSegments, reduceAgentMessage, useAgentResponseAccumulator, useThinkingTimer };
package/dist/index.d.ts CHANGED
@@ -197,6 +197,14 @@ interface AgentMessage {
197
197
  message?: string;
198
198
  /** Alternative content field */
199
199
  content?: string;
200
+ /**
201
+ * Optional event timestamp (epoch ms). When supplied, the reducer uses this
202
+ * for the item's `timestamp` and any state-level timing fields it sets
203
+ * (`firstMessageTime`, `thinkingStartTime`, `responseCompleteTime`) instead
204
+ * of `Date.now()`. Provide this when replaying historical events so durations
205
+ * reflect the original run rather than load time.
206
+ */
207
+ timestamp?: number;
200
208
  /** For status messages */
201
209
  status?: string;
202
210
  /** Agent name (multi-agent scenarios) */
@@ -318,6 +326,12 @@ declare const HITLInteractionRecord: React.ForwardRefExoticComponent<HITLInterac
318
326
  * Displays thinking, tool calls, knowledge retrieval, memory access, and final response.
319
327
  */
320
328
 
329
+ interface AgentResponseClassNames {
330
+ /** Classes for the inner container (border, rounded corners, overflow) */
331
+ container?: string;
332
+ /** Classes for the response content section (background, padding) */
333
+ response?: string;
334
+ }
321
335
  interface AgentResponseProps extends React.HTMLAttributes<HTMLDivElement> {
322
336
  /** The response state to render */
323
337
  state: AgentResponseState;
@@ -389,6 +403,21 @@ interface AgentResponseProps extends React.HTMLAttributes<HTMLDivElement> {
389
403
  * Defaults to "300px". Set to "none" to disable the constraint.
390
404
  */
391
405
  timelineMaxHeight?: string;
406
+ /**
407
+ * Class name overrides for internal elements.
408
+ * Use this to customize the container border/background or response section styling.
409
+ *
410
+ * @example
411
+ * // Transparent background and borders
412
+ * <AgentResponse
413
+ * state={state}
414
+ * classNames={{
415
+ * container: "border-transparent",
416
+ * response: "bg-transparent",
417
+ * }}
418
+ * />
419
+ */
420
+ classNames?: AgentResponseClassNames;
392
421
  }
393
422
  /**
394
423
  * AgentResponse Component
@@ -651,7 +680,10 @@ declare function useThinkingTimer({ startTime, endTime, status, }: UseThinkingTi
651
680
  /**
652
681
  * useAgentResponseAccumulator Hook
653
682
  *
654
- * Accumulates agent response messages into a unified state
683
+ * Accumulates agent response messages into a unified state.
684
+ *
685
+ * Thin wrapper around `reduceAgentMessage` — the pure reducer can be used
686
+ * directly outside React for replaying historical events.
655
687
  */
656
688
 
657
689
  interface UseAgentResponseAccumulatorOptions {
@@ -679,6 +711,36 @@ interface UseAgentResponseAccumulatorReturn {
679
711
  */
680
712
  declare function useAgentResponseAccumulator(options?: UseAgentResponseAccumulatorOptions): UseAgentResponseAccumulatorReturn;
681
713
 
714
+ /**
715
+ * Pure reducer for agent response messages.
716
+ *
717
+ * Used by `useAgentResponseAccumulator` for live streaming, and exported so
718
+ * non-React callers (e.g. server-side or store-based replay of historical
719
+ * conversations) can rebuild the same `AgentResponseState` from a sequence of
720
+ * `AgentMessage` events without rendering a component.
721
+ *
722
+ * Replay note on stable IDs: when a payload omits a per-item id
723
+ * (`tool.id`, `thinkingStep.id`, `knowledge.id`, `memory.id`,
724
+ * `statusUpdate.id`), the reducer falls back to `${type}-${Date.now()}`. That
725
+ * is fine for live streams but will produce different React keys on each
726
+ * replay. Callers reconstructing `AgentMessage` events from persisted rows
727
+ * should populate these ids from a stable source (e.g. the supplement-row
728
+ * primary key) so timeline keys remain consistent across reloads.
729
+ */
730
+
731
+ /**
732
+ * Pure reducer: apply a single `AgentMessage` to the accumulated state.
733
+ *
734
+ * `payload.timestamp` (epoch ms), if supplied, is used for the new item's
735
+ * `timestamp` and any state-level timing fields this call sets
736
+ * (`firstMessageTime`, `thinkingStartTime`, `responseCompleteTime`). When
737
+ * absent, `Date.now()` is used — matching the prior live-streaming behaviour.
738
+ *
739
+ * @example
740
+ * const state = events.reduce(reduceAgentMessage, initialAgentResponseState);
741
+ */
742
+ declare function reduceAgentMessage(prev: AgentResponseState, payload: AgentMessage): AgentResponseState;
743
+
682
744
  /**
683
745
  * Agent Response Utility Functions
684
746
  */
@@ -917,4 +979,4 @@ declare function parseResponseSegments(text: string): ResponseSegment[];
917
979
  */
918
980
  declare const INLINE_ACTION_PROMPT = "\n<inline_actions>\nWhen your response should include interactive components (like query viewers,\ndata tables, or executable actions), embed them as fenced code blocks using\nthe `json:action` language tag:\n\n```json:action\n{\n \"type\": \"action-type-here\",\n ...action-specific fields\n}\n```\n\nRules:\n- Each block must contain valid JSON with a \"type\" field.\n- The \"type\" must match a registered action component on the frontend.\n- Multiple action blocks per response are allowed.\n- Surround action blocks with normal markdown text for user context.\n- The action block is rendered as an interactive component in the chat UI.\n- SQL strings inside JSON must be properly escaped (newlines as \\n, quotes as \\\").\n\nAvailable action types:\n\n- \"optimap-query\": Displays SQL queries with a button to execute them and\n update the 3D globe map.\n Required fields:\n - type: \"optimap-query\"\n - locations_sql: string (the validated locations SQL query)\n - routes_sql: string (the validated routes SQL query)\n - database_name: string (the target database name)\n</inline_actions>\n";
919
981
 
920
- export { ActionBar, type ActionBarProps, type ActionComponentRegistry, ActionMarkdownRenderer, type ActionMarkdownRendererProps, type ActionSegment, ActivityIndicators, type ActivityIndicatorsProps, type AgentMessage, AgentResponse, type AgentResponseProps, type AgentResponseState, type AgentResponseStatus, type AgentRun, AgentTimeline, type DisplayEntry, type FeedbackValue, type GenericWebSocketMessage, type HITLInteraction, HITLInteractionRecord, type HITLInteractionRecordProps, type HITLQuestion, HITLQuestionPanel, type HITLQuestionPanelProps, type HITLResponseData, HITLSection, type HITLSectionProps, INLINE_ACTION_PROMPT, type InlineActionProps, type KnowledgeItem, type MarkdownSegment, type MemoryItem, MetadataRow, type MetadataRowProps, type PotentialResponse, type ResponseSegment, type StatusItem, type ThinkingContent, ThinkingSection, type ThinkingSectionProps, type ThinkingStep, type TimelineEntry, type TimelineEntryType, type TimelineUIState, type ToolCall, TruncatedMessage, type TruncatedMessageProps, type UseAgentResponseAccumulatorOptions, type UseAgentResponseAccumulatorReturn, type UseThinkingTimerOptions, UserPrompt, UserPromptInput, type UserPromptInputProps, type UserPromptInputRef, type UserPromptProps, buildResponseString, buildTimelineEntries, createTimelineUIState, deduplicateEntries, formatTime, formatTotalTime, groupIntoAgentRuns, initialAgentResponseState, parseResponseSegments, useAgentResponseAccumulator, useThinkingTimer };
982
+ export { ActionBar, type ActionBarProps, type ActionComponentRegistry, ActionMarkdownRenderer, type ActionMarkdownRendererProps, type ActionSegment, ActivityIndicators, type ActivityIndicatorsProps, type AgentMessage, AgentResponse, type AgentResponseProps, type AgentResponseState, type AgentResponseStatus, type AgentRun, AgentTimeline, type DisplayEntry, type FeedbackValue, type GenericWebSocketMessage, type HITLInteraction, HITLInteractionRecord, type HITLInteractionRecordProps, type HITLQuestion, HITLQuestionPanel, type HITLQuestionPanelProps, type HITLResponseData, HITLSection, type HITLSectionProps, INLINE_ACTION_PROMPT, type InlineActionProps, type KnowledgeItem, type MarkdownSegment, type MemoryItem, MetadataRow, type MetadataRowProps, type PotentialResponse, type ResponseSegment, type StatusItem, type ThinkingContent, ThinkingSection, type ThinkingSectionProps, type ThinkingStep, type TimelineEntry, type TimelineEntryType, type TimelineUIState, type ToolCall, TruncatedMessage, type TruncatedMessageProps, type UseAgentResponseAccumulatorOptions, type UseAgentResponseAccumulatorReturn, type UseThinkingTimerOptions, UserPrompt, UserPromptInput, type UserPromptInputProps, type UserPromptInputRef, type UserPromptProps, buildResponseString, buildTimelineEntries, createTimelineUIState, deduplicateEntries, formatTime, formatTotalTime, groupIntoAgentRuns, initialAgentResponseState, parseResponseSegments, reduceAgentMessage, useAgentResponseAccumulator, useThinkingTimer };
package/dist/index.js CHANGED
@@ -824,6 +824,188 @@ function deduplicateEntries(entries) {
824
824
  return result;
825
825
  }
826
826
 
827
+ // src/components/agent-response/reducer.ts
828
+ function reduceAgentMessage(prev, payload) {
829
+ const now = payload.timestamp ?? Date.now();
830
+ let newStatus = prev.status;
831
+ const isFirstMessage = prev.status === "idle" && payload.type !== "status";
832
+ if (isFirstMessage) {
833
+ newStatus = "processing";
834
+ }
835
+ const firstMessageTime = prev.firstMessageTime ?? (isFirstMessage ? now : null);
836
+ switch (payload.type) {
837
+ case "status":
838
+ if (payload.message === "Harness connected" || payload.status === "Harness connected") {
839
+ return { ...initialAgentResponseState };
840
+ }
841
+ return { ...prev, status: newStatus };
842
+ case "thinking": {
843
+ if (payload.thinkingStep) {
844
+ const newStep = {
845
+ id: payload.thinkingStep.id || `step-${now}`,
846
+ label: payload.thinkingStep.label,
847
+ content: payload.thinkingStep.content,
848
+ depth: payload.thinkingStep.depth ?? payload.depth ?? 0,
849
+ isCollapsed: payload.thinkingStep.isCollapsed,
850
+ timestamp: now,
851
+ agentName: payload.agentName,
852
+ parentAgent: payload.parentAgent
853
+ };
854
+ const thinkingStartTime2 = prev.thinkingStartTime ?? now;
855
+ const next2 = {
856
+ ...prev,
857
+ status: newStatus,
858
+ thinkingSteps: [...prev.thinkingSteps || [], newStep],
859
+ thinkingStartTime: thinkingStartTime2,
860
+ firstMessageTime
861
+ };
862
+ return { ...next2, timelineEntries: buildTimelineEntries(next2) };
863
+ }
864
+ const newThinking = payload.message || payload.content || "";
865
+ const separator = prev.thinking && newThinking ? "\n\n" : "";
866
+ const thinkingStartTime = prev.thinkingStartTime ?? (newThinking ? now : null);
867
+ const prevSteps = prev.thinkingSteps || [];
868
+ const plainStep = {
869
+ id: `step-${prevSteps.length}`,
870
+ label: newThinking,
871
+ content: newThinking,
872
+ depth: payload.depth ?? 0,
873
+ timestamp: now,
874
+ agentName: payload.agentName,
875
+ parentAgent: payload.parentAgent
876
+ };
877
+ const next = {
878
+ ...prev,
879
+ status: newStatus,
880
+ thinking: prev.thinking + separator + newThinking,
881
+ thinkingSteps: [...prevSteps, plainStep],
882
+ thinkingStartTime,
883
+ firstMessageTime
884
+ };
885
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
886
+ }
887
+ case "tool_call": {
888
+ const toolName = payload.message || payload.tool?.name;
889
+ if (toolName) {
890
+ const newToolCall = {
891
+ id: payload.tool?.id || `tool-${now}`,
892
+ name: toolName,
893
+ arguments: payload.tool?.arguments,
894
+ timestamp: now,
895
+ agentName: payload.agentName,
896
+ parentAgent: payload.parentAgent,
897
+ depth: payload.depth
898
+ };
899
+ const next = {
900
+ ...prev,
901
+ status: newStatus,
902
+ toolCalls: [...prev.toolCalls, newToolCall],
903
+ firstMessageTime
904
+ };
905
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
906
+ }
907
+ return { ...prev, status: newStatus, firstMessageTime };
908
+ }
909
+ case "knowledge": {
910
+ const knowledgeContent = payload.message || payload.knowledge?.content;
911
+ if (knowledgeContent) {
912
+ const newKnowledge = {
913
+ id: payload.knowledge?.id || `knowledge-${now}`,
914
+ source: payload.knowledge?.source || "unknown",
915
+ content: knowledgeContent,
916
+ timestamp: now,
917
+ agentName: payload.agentName,
918
+ parentAgent: payload.parentAgent,
919
+ depth: payload.depth
920
+ };
921
+ const next = {
922
+ ...prev,
923
+ status: newStatus,
924
+ knowledge: [...prev.knowledge, newKnowledge],
925
+ firstMessageTime
926
+ };
927
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
928
+ }
929
+ return { ...prev, status: newStatus, firstMessageTime };
930
+ }
931
+ case "memory": {
932
+ const memoryContent = payload.message || payload.memory?.content;
933
+ if (memoryContent) {
934
+ const newMemory = {
935
+ id: payload.memory?.id || `memory-${now}`,
936
+ type: payload.memory?.type || "unknown",
937
+ content: memoryContent,
938
+ timestamp: now,
939
+ agentName: payload.agentName,
940
+ parentAgent: payload.parentAgent,
941
+ depth: payload.depth
942
+ };
943
+ const next = {
944
+ ...prev,
945
+ status: newStatus,
946
+ memory: [...prev.memory, newMemory],
947
+ firstMessageTime
948
+ };
949
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
950
+ }
951
+ return { ...prev, status: newStatus, firstMessageTime };
952
+ }
953
+ case "response":
954
+ return {
955
+ ...prev,
956
+ status: "complete",
957
+ response: payload.message || payload.content || "",
958
+ responseCompleteTime: now,
959
+ firstMessageTime: prev.firstMessageTime ?? now
960
+ };
961
+ case "status_update": {
962
+ const statusMessage = payload.message || payload.statusUpdate?.message;
963
+ if (statusMessage) {
964
+ const newStatusItem = {
965
+ id: payload.statusUpdate?.id || `status-${now}`,
966
+ message: statusMessage,
967
+ agent: payload.statusUpdate?.agent,
968
+ timestamp: now,
969
+ agentName: payload.agentName,
970
+ parentAgent: payload.parentAgent,
971
+ depth: payload.depth
972
+ };
973
+ const next = {
974
+ ...prev,
975
+ status: newStatus,
976
+ statusUpdates: [...prev.statusUpdates, newStatusItem],
977
+ firstMessageTime
978
+ };
979
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
980
+ }
981
+ return { ...prev, status: newStatus, firstMessageTime };
982
+ }
983
+ case "potential_response": {
984
+ const respContent = payload.message || payload.content || "";
985
+ if (respContent) {
986
+ const newResp = {
987
+ id: `resp-${now}`,
988
+ content: respContent,
989
+ timestamp: now,
990
+ agentName: payload.agentName,
991
+ parentAgent: payload.parentAgent,
992
+ depth: payload.depth
993
+ };
994
+ const next = {
995
+ ...prev,
996
+ status: newStatus,
997
+ potentialResponses: [...prev.potentialResponses || [], newResp],
998
+ firstMessageTime
999
+ };
1000
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
1001
+ }
1002
+ return { ...prev, status: newStatus, firstMessageTime };
1003
+ }
1004
+ default:
1005
+ return { ...prev, status: newStatus, firstMessageTime };
1006
+ }
1007
+ }
1008
+
827
1009
  // src/components/agent-response/hooks/useAgentResponseAccumulator.ts
828
1010
  function useAgentResponseAccumulator(options) {
829
1011
  const [state, setState] = useState(initialAgentResponseState);
@@ -838,185 +1020,7 @@ function useAgentResponseAccumulator(options) {
838
1020
  } else {
839
1021
  payload = message;
840
1022
  }
841
- setState((prev) => {
842
- let newStatus = prev.status;
843
- const isFirstMessage = prev.status === "idle" && payload.type !== "status";
844
- if (isFirstMessage) {
845
- newStatus = "processing";
846
- }
847
- const firstMessageTime = prev.firstMessageTime ?? (isFirstMessage ? Date.now() : null);
848
- switch (payload.type) {
849
- case "status":
850
- if (payload.message === "Harness connected" || payload.status === "Harness connected") {
851
- return { ...initialAgentResponseState };
852
- }
853
- return { ...prev, status: newStatus };
854
- case "thinking": {
855
- if (payload.thinkingStep) {
856
- const newStep = {
857
- id: payload.thinkingStep.id || `step-${Date.now()}`,
858
- label: payload.thinkingStep.label,
859
- content: payload.thinkingStep.content,
860
- depth: payload.thinkingStep.depth ?? payload.depth ?? 0,
861
- isCollapsed: payload.thinkingStep.isCollapsed,
862
- timestamp: Date.now(),
863
- agentName: payload.agentName,
864
- parentAgent: payload.parentAgent
865
- };
866
- const thinkingStartTime2 = prev.thinkingStartTime ?? Date.now();
867
- const next2 = {
868
- ...prev,
869
- status: newStatus,
870
- thinkingSteps: [...prev.thinkingSteps || [], newStep],
871
- thinkingStartTime: thinkingStartTime2,
872
- firstMessageTime
873
- };
874
- return { ...next2, timelineEntries: buildTimelineEntries(next2) };
875
- }
876
- const newThinking = payload.message || payload.content || "";
877
- const separator = prev.thinking && newThinking ? "\n\n" : "";
878
- const thinkingStartTime = prev.thinkingStartTime ?? (newThinking ? Date.now() : null);
879
- const prevSteps = prev.thinkingSteps || [];
880
- const plainStep = {
881
- id: `step-${prevSteps.length}`,
882
- label: newThinking,
883
- content: newThinking,
884
- depth: payload.depth ?? 0,
885
- timestamp: Date.now(),
886
- agentName: payload.agentName,
887
- parentAgent: payload.parentAgent
888
- };
889
- const next = {
890
- ...prev,
891
- status: newStatus,
892
- thinking: prev.thinking + separator + newThinking,
893
- thinkingSteps: [...prevSteps, plainStep],
894
- thinkingStartTime,
895
- firstMessageTime
896
- };
897
- return { ...next, timelineEntries: buildTimelineEntries(next) };
898
- }
899
- case "tool_call": {
900
- const toolName = payload.message || payload.tool?.name;
901
- if (toolName) {
902
- const newToolCall = {
903
- id: payload.tool?.id || `tool-${Date.now()}`,
904
- name: toolName,
905
- arguments: payload.tool?.arguments,
906
- timestamp: Date.now(),
907
- agentName: payload.agentName,
908
- parentAgent: payload.parentAgent,
909
- depth: payload.depth
910
- };
911
- const next = {
912
- ...prev,
913
- status: newStatus,
914
- toolCalls: [...prev.toolCalls, newToolCall],
915
- firstMessageTime
916
- };
917
- return { ...next, timelineEntries: buildTimelineEntries(next) };
918
- }
919
- return { ...prev, status: newStatus, firstMessageTime };
920
- }
921
- case "knowledge": {
922
- const knowledgeContent = payload.message || payload.knowledge?.content;
923
- if (knowledgeContent) {
924
- const newKnowledge = {
925
- id: payload.knowledge?.id || `knowledge-${Date.now()}`,
926
- source: payload.knowledge?.source || "unknown",
927
- content: knowledgeContent,
928
- timestamp: Date.now(),
929
- agentName: payload.agentName,
930
- parentAgent: payload.parentAgent,
931
- depth: payload.depth
932
- };
933
- const next = {
934
- ...prev,
935
- status: newStatus,
936
- knowledge: [...prev.knowledge, newKnowledge],
937
- firstMessageTime
938
- };
939
- return { ...next, timelineEntries: buildTimelineEntries(next) };
940
- }
941
- return { ...prev, status: newStatus, firstMessageTime };
942
- }
943
- case "memory": {
944
- const memoryContent = payload.message || payload.memory?.content;
945
- if (memoryContent) {
946
- const newMemory = {
947
- id: payload.memory?.id || `memory-${Date.now()}`,
948
- type: payload.memory?.type || "unknown",
949
- content: memoryContent,
950
- timestamp: Date.now(),
951
- agentName: payload.agentName,
952
- parentAgent: payload.parentAgent,
953
- depth: payload.depth
954
- };
955
- const next = {
956
- ...prev,
957
- status: newStatus,
958
- memory: [...prev.memory, newMemory],
959
- firstMessageTime
960
- };
961
- return { ...next, timelineEntries: buildTimelineEntries(next) };
962
- }
963
- return { ...prev, status: newStatus, firstMessageTime };
964
- }
965
- case "response":
966
- return {
967
- ...prev,
968
- status: "complete",
969
- response: payload.message || payload.content || "",
970
- responseCompleteTime: Date.now(),
971
- firstMessageTime: prev.firstMessageTime ?? Date.now()
972
- };
973
- case "status_update": {
974
- const statusMessage = payload.message || payload.statusUpdate?.message;
975
- if (statusMessage) {
976
- const newStatusItem = {
977
- id: payload.statusUpdate?.id || `status-${Date.now()}`,
978
- message: statusMessage,
979
- agent: payload.statusUpdate?.agent,
980
- timestamp: Date.now(),
981
- agentName: payload.agentName,
982
- parentAgent: payload.parentAgent,
983
- depth: payload.depth
984
- };
985
- const next = {
986
- ...prev,
987
- status: newStatus,
988
- statusUpdates: [...prev.statusUpdates, newStatusItem],
989
- firstMessageTime
990
- };
991
- return { ...next, timelineEntries: buildTimelineEntries(next) };
992
- }
993
- return { ...prev, status: newStatus, firstMessageTime };
994
- }
995
- case "potential_response": {
996
- const respContent = payload.message || payload.content || "";
997
- if (respContent) {
998
- const newResp = {
999
- id: `resp-${Date.now()}`,
1000
- content: respContent,
1001
- timestamp: Date.now(),
1002
- agentName: payload.agentName,
1003
- parentAgent: payload.parentAgent,
1004
- depth: payload.depth
1005
- };
1006
- const next = {
1007
- ...prev,
1008
- status: newStatus,
1009
- potentialResponses: [...prev.potentialResponses || [], newResp],
1010
- firstMessageTime
1011
- };
1012
- return { ...next, timelineEntries: buildTimelineEntries(next) };
1013
- }
1014
- return { ...prev, status: newStatus, firstMessageTime };
1015
- }
1016
- default:
1017
- return { ...prev, status: newStatus, firstMessageTime };
1018
- }
1019
- });
1023
+ setState((prev) => reduceAgentMessage(prev, payload));
1020
1024
  },
1021
1025
  [topic]
1022
1026
  );
@@ -1324,6 +1328,7 @@ var AgentResponse = React11.forwardRef(
1324
1328
  renderMarkdown,
1325
1329
  renderThinkingMarkdown,
1326
1330
  timelineMaxHeight,
1331
+ classNames,
1327
1332
  className,
1328
1333
  ...props
1329
1334
  }, ref) => {
@@ -1368,7 +1373,7 @@ var AgentResponse = React11.forwardRef(
1368
1373
  onMouseLeave: () => setIsHovered(false),
1369
1374
  ...props,
1370
1375
  children: [
1371
- /* @__PURE__ */ jsxs("div", { className: "border border-border rounded-lg overflow-hidden", children: [
1376
+ /* @__PURE__ */ jsxs("div", { className: cn("border border-border rounded-lg overflow-hidden", classNames?.container), children: [
1372
1377
  showMetadataRow && /* @__PURE__ */ jsxs(Fragment, { children: [
1373
1378
  /* @__PURE__ */ jsx(
1374
1379
  MetadataRow,
@@ -1414,7 +1419,8 @@ var AgentResponse = React11.forwardRef(
1414
1419
  {
1415
1420
  className: cn(
1416
1421
  "bg-muted/50 p-4",
1417
- showMetadataRow && "border-t border-border"
1422
+ showMetadataRow && "border-t border-border",
1423
+ classNames?.response
1418
1424
  ),
1419
1425
  children: renderMarkdown ? renderMarkdown(state.response) : /* @__PURE__ */ jsx("span", { className: "whitespace-pre-wrap", children: state.response })
1420
1426
  }
@@ -1812,6 +1818,6 @@ Available action types:
1812
1818
  </inline_actions>
1813
1819
  `;
1814
1820
 
1815
- export { ActionBar, ActionMarkdownRenderer, ActivityIndicators, AgentResponse, AgentTimeline, HITLInteractionRecord, HITLQuestionPanel, HITLSection, INLINE_ACTION_PROMPT, MetadataRow, ThinkingSection, TruncatedMessage, UserPrompt, UserPromptInput, buildResponseString, buildTimelineEntries, createTimelineUIState, deduplicateEntries, formatTime, formatTotalTime, groupIntoAgentRuns, initialAgentResponseState, parseResponseSegments, useAgentResponseAccumulator, useThinkingTimer };
1821
+ export { ActionBar, ActionMarkdownRenderer, ActivityIndicators, AgentResponse, AgentTimeline, HITLInteractionRecord, HITLQuestionPanel, HITLSection, INLINE_ACTION_PROMPT, MetadataRow, ThinkingSection, TruncatedMessage, UserPrompt, UserPromptInput, buildResponseString, buildTimelineEntries, createTimelineUIState, deduplicateEntries, formatTime, formatTotalTime, groupIntoAgentRuns, initialAgentResponseState, parseResponseSegments, reduceAgentMessage, useAgentResponseAccumulator, useThinkingTimer };
1816
1822
  //# sourceMappingURL=index.js.map
1817
1823
  //# sourceMappingURL=index.js.map