@orbe-agro/client-core 5.6.239 → 5.6.241

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.
Files changed (93) hide show
  1. package/dist/@ecme/assets/styles/app.css +116 -3
  2. package/dist/@ecme/assets/styles/tailwind/index.css +119 -3
  3. package/dist/@ecme/components/template/Footer.js +1 -1
  4. package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.js +0 -2
  5. package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.js.map +1 -1
  6. package/dist/@ecme/components/view/ChatBox/ChatBox.js +2 -0
  7. package/dist/@ecme/components/view/ChatBox/ChatBox.js.map +1 -1
  8. package/dist/@ecme/components/view/ChatBox/components/MessageList.js +2 -1
  9. package/dist/@ecme/components/view/ChatBox/components/MessageList.js.map +1 -1
  10. package/dist/@ecme/index.js +3 -4
  11. package/dist/@ecme/services/AiService.js +53 -24
  12. package/dist/@ecme/services/AiService.js.map +1 -1
  13. package/dist/@ecme/services/aiAuthHeaders.js +35 -0
  14. package/dist/@ecme/services/aiAuthHeaders.js.map +1 -0
  15. package/dist/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.js +4 -27
  16. package/dist/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.js.map +1 -1
  17. package/dist/@ecme/services/index.js +4 -5
  18. package/dist/@ecme/services/sseParser.js +42 -0
  19. package/dist/@ecme/services/sseParser.js.map +1 -0
  20. package/dist/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.js +15 -0
  21. package/dist/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.js.map +1 -0
  22. package/dist/@ecme/views/concepts/ai/Chat/components/ApprovalCard.js +73 -0
  23. package/dist/@ecme/views/concepts/ai/Chat/components/ApprovalCard.js.map +1 -0
  24. package/dist/@ecme/views/concepts/ai/Chat/components/ChatView.js +37 -10
  25. package/dist/@ecme/views/concepts/ai/Chat/components/ChatView.js.map +1 -1
  26. package/dist/@ecme/views/concepts/ai/Chat/components/ToolCallChip.js +153 -0
  27. package/dist/@ecme/views/concepts/ai/Chat/components/ToolCallChip.js.map +1 -0
  28. package/dist/@ecme/views/concepts/ai/Chat/components/toolPresentation.js +99 -0
  29. package/dist/@ecme/views/concepts/ai/Chat/components/toolPresentation.js.map +1 -0
  30. package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatSend.js +111 -17
  31. package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatSend.js.map +1 -1
  32. package/dist/@ecme/views/concepts/ai/Chat/store/generativeChatStore.js +29 -13
  33. package/dist/@ecme/views/concepts/ai/Chat/store/generativeChatStore.js.map +1 -1
  34. package/dist/@types/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.d.ts.map +1 -1
  35. package/dist/@types/@ecme/components/view/ChatBox/ChatBox.d.ts.map +1 -1
  36. package/dist/@types/@ecme/components/view/ChatBox/components/MessageList.d.ts +2 -0
  37. package/dist/@types/@ecme/components/view/ChatBox/components/MessageList.d.ts.map +1 -1
  38. package/dist/@types/@ecme/services/AiService.d.ts +28 -15
  39. package/dist/@types/@ecme/services/AiService.d.ts.map +1 -1
  40. package/dist/@types/@ecme/services/aiAuthHeaders.d.ts +12 -0
  41. package/dist/@types/@ecme/services/aiAuthHeaders.d.ts.map +1 -0
  42. package/dist/@types/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.d.ts +6 -0
  43. package/dist/@types/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.d.ts.map +1 -1
  44. package/dist/@types/@ecme/services/sseParser.d.ts +20 -0
  45. package/dist/@types/@ecme/services/sseParser.d.ts.map +1 -0
  46. package/dist/@types/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.d.ts +8 -0
  47. package/dist/@types/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.d.ts.map +1 -0
  48. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ApprovalCard.d.ts +15 -0
  49. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ApprovalCard.d.ts.map +1 -0
  50. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatView.d.ts.map +1 -1
  51. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ToolCallChip.d.ts +7 -0
  52. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ToolCallChip.d.ts.map +1 -0
  53. package/dist/@types/@ecme/views/concepts/ai/Chat/components/toolPresentation.d.ts +14 -0
  54. package/dist/@types/@ecme/views/concepts/ai/Chat/components/toolPresentation.d.ts.map +1 -0
  55. package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatSend.d.ts +2 -1
  56. package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatSend.d.ts.map +1 -1
  57. package/dist/@types/@ecme/views/concepts/ai/Chat/store/generativeChatStore.d.ts +1 -0
  58. package/dist/@types/@ecme/views/concepts/ai/Chat/store/generativeChatStore.d.ts.map +1 -1
  59. package/dist/@types/@ecme/views/concepts/ai/Chat/types.d.ts +96 -23
  60. package/dist/@types/@ecme/views/concepts/ai/Chat/types.d.ts.map +1 -1
  61. package/dist/@types/base/@types/models/transportadora/irpf.d.ts +1 -0
  62. package/dist/@types/base/@types/models/transportadora/irpf.d.ts.map +1 -1
  63. package/dist/@types/base/@types/models/transportadora/irpfFaixaDesconto.d.ts +0 -1
  64. package/dist/@types/base/@types/models/transportadora/irpfFaixaDesconto.d.ts.map +1 -1
  65. package/dist/base/assets/styles/init.css +128 -3
  66. package/lib/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.tsx +0 -2
  67. package/lib/@ecme/components/view/ChatBox/ChatBox.tsx +2 -0
  68. package/lib/@ecme/components/view/ChatBox/components/MessageList.tsx +8 -4
  69. package/lib/@ecme/services/AiService.ts +89 -44
  70. package/lib/@ecme/services/aiAuthHeaders.ts +58 -0
  71. package/lib/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.ts +10 -39
  72. package/lib/@ecme/services/sseParser.ts +75 -0
  73. package/lib/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.tsx +28 -0
  74. package/lib/@ecme/views/concepts/ai/Chat/components/ApprovalCard.tsx +103 -0
  75. package/lib/@ecme/views/concepts/ai/Chat/components/ChatView.tsx +74 -10
  76. package/lib/@ecme/views/concepts/ai/Chat/components/ToolCallChip.tsx +218 -0
  77. package/lib/@ecme/views/concepts/ai/Chat/components/toolPresentation.ts +137 -0
  78. package/lib/@ecme/views/concepts/ai/Chat/hooks/useChatSend.ts +175 -23
  79. package/lib/@ecme/views/concepts/ai/Chat/store/generativeChatStore.ts +41 -13
  80. package/lib/@ecme/views/concepts/ai/Chat/types.ts +82 -29
  81. package/lib/base/@types/models/transportadora/irpf.ts +1 -0
  82. package/lib/base/@types/models/transportadora/irpfFaixaDesconto.ts +0 -1
  83. package/package.json +1 -1
  84. package/dist/@ecme/views/concepts/ai/Chat/components/ModelSelect.js +0 -48
  85. package/dist/@ecme/views/concepts/ai/Chat/components/ModelSelect.js.map +0 -1
  86. package/dist/@ecme/views/concepts/ai/Chat/store/aiModelStore.js +0 -15
  87. package/dist/@ecme/views/concepts/ai/Chat/store/aiModelStore.js.map +0 -1
  88. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ModelSelect.d.ts +0 -8
  89. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ModelSelect.d.ts.map +0 -1
  90. package/dist/@types/@ecme/views/concepts/ai/Chat/store/aiModelStore.d.ts +0 -25
  91. package/dist/@types/@ecme/views/concepts/ai/Chat/store/aiModelStore.d.ts.map +0 -1
  92. package/lib/@ecme/views/concepts/ai/Chat/components/ModelSelect.tsx +0 -66
  93. package/lib/@ecme/views/concepts/ai/Chat/store/aiModelStore.ts +0 -23
@@ -1 +1 @@
1
- {"version":3,"file":"ChatBox.js","sources":["../../../../../lib/@ecme/components/view/ChatBox/ChatBox.tsx"],"sourcesContent":["import ChatContainer from './components/ChatContainer'\nimport MessageList from './components/MessageList'\nimport ChatInput from './components/ChatInput'\nimport type { MessageListProps } from './components/MessageList'\nimport type { ChatContainerProps } from './components/ChatContainer'\nimport type { ChatInputProps } from './components/ChatInput'\nimport type { ReactNode } from 'react'\nimport { forwardRef } from 'react'\nimport type { ScrollBarRef } from '@/components/ui/ScrollBar'\n\nexport type MessageList = MessageListProps['list']\n\nexport type ChatBoxProps = {\n messageList: MessageList\n header?: ChatContainerProps['header']\n showMessageList?: boolean\n children?: ReactNode\n containerClass?: string\n} & Omit<MessageListProps, 'list'> &\n ChatInputProps\n\nconst ChatBox = forwardRef<ScrollBarRef, ChatBoxProps>((props, ref) => {\n const {\n messageList,\n showMessageList = true,\n children,\n header,\n placeholder,\n onInputChange,\n showAvatar,\n avatarGap,\n customRenderer,\n customAction,\n bubbleClass,\n myBubbleClass,\n botBubbleClass,\n renderTyping,\n typing,\n messageListClass,\n containerClass,\n } = props\n\n return (\n <ChatContainer\n className={containerClass}\n header={header}\n input={\n <ChatInput\n placeholder={placeholder}\n onInputChange={onInputChange}\n />\n }\n >\n {showMessageList && (\n <MessageList\n ref={ref}\n list={messageList}\n showAvatar={showAvatar}\n avatarGap={avatarGap}\n customRenderer={customRenderer}\n customAction={customAction}\n typing={typing}\n messageListClass={messageListClass}\n bubbleClass={bubbleClass}\n myBubbleClass={myBubbleClass}\n botBubbleClass={botBubbleClass}\n renderTyping={renderTyping}\n /> )}\n {children}\n </ChatContainer>\n )\n})\n\nChatBox.displayName = 'ChatBox'\n\nexport default ChatBox\n"],"names":[],"mappings":";;;;;AAqBA,MAAM,UAAU,WAAuC,CAAC,OAAO,QAAQ;AACnE,QAAM;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA;AAEJ,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,WAAW;AAAA,MACX;AAAA,MACA,OACI;AAAA,QAAC;AAAA,QAAA;AAAA,UACG;AAAA,UACA;AAAA,QAAA;AAAA,MAAA;AAAA,MAIP,UAAA;AAAA,QAAA,mBACG;AAAA,UAAC;AAAA,UAAA;AAAA,YACG;AAAA,YACA,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,QAAA;AAAA,QAEP;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGb,CAAC;AAED,QAAQ,cAAc;"}
1
+ {"version":3,"file":"ChatBox.js","sources":["../../../../../lib/@ecme/components/view/ChatBox/ChatBox.tsx"],"sourcesContent":["import ChatContainer from './components/ChatContainer'\nimport MessageList from './components/MessageList'\nimport ChatInput from './components/ChatInput'\nimport type { MessageListProps } from './components/MessageList'\nimport type { ChatContainerProps } from './components/ChatContainer'\nimport type { ChatInputProps } from './components/ChatInput'\nimport type { ReactNode } from 'react'\nimport { forwardRef } from 'react'\nimport type { ScrollBarRef } from '@/components/ui/ScrollBar'\n\nexport type MessageList = MessageListProps['list']\n\nexport type ChatBoxProps = {\n messageList: MessageList\n header?: ChatContainerProps['header']\n showMessageList?: boolean\n children?: ReactNode\n containerClass?: string\n} & Omit<MessageListProps, 'list'> &\n ChatInputProps\n\nconst ChatBox = forwardRef<ScrollBarRef, ChatBoxProps>((props, ref) => {\n const {\n messageList,\n showMessageList = true,\n children,\n header,\n placeholder,\n onInputChange,\n showAvatar,\n avatarGap,\n customRenderer,\n customAction,\n bubbleClass,\n myBubbleClass,\n botBubbleClass,\n errorBubbleClass,\n renderTyping,\n typing,\n messageListClass,\n containerClass,\n } = props\n\n return (\n <ChatContainer\n className={containerClass}\n header={header}\n input={\n <ChatInput\n placeholder={placeholder}\n onInputChange={onInputChange}\n />\n }\n >\n {showMessageList && (\n <MessageList\n ref={ref}\n list={messageList}\n showAvatar={showAvatar}\n avatarGap={avatarGap}\n customRenderer={customRenderer}\n customAction={customAction}\n typing={typing}\n messageListClass={messageListClass}\n bubbleClass={bubbleClass}\n myBubbleClass={myBubbleClass}\n botBubbleClass={botBubbleClass}\n errorBubbleClass={errorBubbleClass}\n renderTyping={renderTyping}\n /> )}\n {children}\n </ChatContainer>\n )\n})\n\nChatBox.displayName = 'ChatBox'\n\nexport default ChatBox\n"],"names":[],"mappings":";;;;;AAqBA,MAAM,UAAU,WAAuC,CAAC,OAAO,QAAQ;AACnE,QAAM;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA;AAEJ,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,WAAW;AAAA,MACX;AAAA,MACA,OACI;AAAA,QAAC;AAAA,QAAA;AAAA,UACG;AAAA,UACA;AAAA,QAAA;AAAA,MAAA;AAAA,MAIP,UAAA;AAAA,QAAA,mBACG;AAAA,UAAC;AAAA,UAAA;AAAA,YACG;AAAA,YACA,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,QAAA;AAAA,QAEP;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGb,CAAC;AAED,QAAQ,cAAc;"}
@@ -16,6 +16,7 @@ const MessageList = forwardRef((props, ref) => {
16
16
  bubbleClass,
17
17
  myBubbleClass,
18
18
  botBubbleClass,
19
+ errorBubbleClass,
19
20
  renderTyping
20
21
  } = props;
21
22
  return /* @__PURE__ */ jsx("div", { className: classNames("relative", messageListClass), children: /* @__PURE__ */ jsxs("div", { className: "absolute top-0 left-0 h-full w-full py-4", children: [
@@ -33,7 +34,7 @@ const MessageList = forwardRef((props, ref) => {
33
34
  {
34
35
  showAvatar,
35
36
  avatarGap,
36
- bubbleClass: message.isMyMessage ? myBubbleClass ?? bubbleClass : botBubbleClass ?? bubbleClass,
37
+ bubbleClass: message.isError ? errorBubbleClass ?? bubbleClass : message.isMyMessage ? myBubbleClass ?? bubbleClass : botBubbleClass ?? bubbleClass,
37
38
  ...message,
38
39
  ...customRenderer ? {
39
40
  customRenderer: () => customRenderer(message, index)
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.js","sources":["../../../../../../lib/@ecme/components/view/ChatBox/components/MessageList.tsx"],"sourcesContent":["import ScrollBar from '@/components/ui/ScrollBar'\nimport Message from './Message'\nimport classNames from '@/utils/classNames'\nimport type { ReactNode } from 'react'\nimport { forwardRef } from 'react'\nimport type { ScrollBarRef } from '@/components/ui/ScrollBar'\nimport type { MessageProps } from './Message'\n\ntype List = MessageProps & { fresh?: boolean }\n\nexport type MessageListProps = {\n list: List[]\n showAvatar?: boolean\n avatarGap?: boolean\n typing?:\n | {\n id: string\n name: string\n avatarImageUrl?: string\n }\n | false\n customRenderer?: (message: List, index: number) => string | ReactNode\n customAction?: (message: List, index: number) => string | ReactNode\n bubbleClass?: string\n myBubbleClass?: string\n botBubbleClass?: string\n renderTyping?: () => ReactNode\n messageListClass?: string\n}\n\nconst MessageList = forwardRef<ScrollBarRef, MessageListProps>((props, ref) => { const {\n list = [],\n showAvatar = true,\n typing = false,\n avatarGap,\n customRenderer,\n customAction,\n messageListClass,\n bubbleClass,\n myBubbleClass,\n botBubbleClass,\n renderTyping,\n } = props\n\n return (\n <div className={classNames('relative', messageListClass)}>\n <div className=\"absolute top-0 left-0 h-full w-full py-4\"> <ScrollBar\n ref={ref}\n autoHide\n className=\"overflow-y-auto h-full max-w-full\"\n >\n <div className=\"flex flex-col gap-4 px-4\">\n {list.map((message, index) => (\n <Message\n key={message.id}\n showAvatar={showAvatar}\n avatarGap={avatarGap}\n bubbleClass={\n message.isMyMessage\n ? myBubbleClass ?? bubbleClass\n : botBubbleClass ?? bubbleClass\n }\n {...message}\n {...(customRenderer\n ? {\n customRenderer: () =>\n customRenderer(message, index),\n }\n : {})}\n {...(customAction\n ? {\n customAction: () =>\n customAction(message, index),\n }\n : {})}\n />\n ))}\n {typing && (\n <Message\n id={typing.name + 'typing'}\n sender={typing}\n type=\"regular\"\n showAvatar={showAvatar}\n bubbleClass={botBubbleClass ?? bubbleClass}\n avatarGap={avatarGap}\n content={\n renderTyping ? (\n renderTyping()\n ) : (\n <span className=\"flex items-center gap-2\">\n <span className=\"size-1.5 rounded-full bg-gray-700 motion-safe:animate-[bounce_1s_ease-in-out_infinite] dark:bg-gray-300\"></span>\n <span className=\"size-1.5 rounded-full bg-gray-700 motion-safe:animate-[bounce_0.5s_ease-in-out_infinite] dark:bg-gray-300\"></span>\n <span className=\"size-1.5 rounded-full bg-gray-700 motion-safe:animate-[bounce_1s_ease-in-out_infinite] dark:bg-gray-300\"></span>\n </span>\n )\n }\n />\n )}\n </div> </ScrollBar>\n </div>\n </div>\n )\n})\n\nMessageList.displayName = 'MessageList'\n\nexport default MessageList\n"],"names":[],"mappings":";;;;;;AA8BA,MAAM,cAAc,WAA2C,CAAC,OAAO,QAAQ;AAAK,QAAM;AAAA,IAClF,OAAO,CAAA;AAAA,IACP,aAAa;AAAA,IACb,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA;AAEJ,SACI,oBAAC,OAAA,EAAI,WAAW,WAAW,YAAY,gBAAgB,GACnD,UAAA,qBAAC,OAAA,EAAI,WAAU,4CAA2C,UAAA;AAAA,IAAA;AAAA,IAAgB;AAAA,MAAC;AAAA,MAAA;AAAA,QACnE;AAAA,QACA,UAAQ;AAAA,QACR,WAAU;AAAA,QAEV,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,4BACV,UAAA;AAAA,YAAA,KAAK,IAAI,CAAC,SAAS,UAChB;AAAA,cAAC;AAAA,cAAA;AAAA,gBAEG;AAAA,gBACA;AAAA,gBACA,aACI,QAAQ,cACF,iBAAiB,cACjB,kBAAkB;AAAA,gBAE3B,GAAG;AAAA,gBACH,GAAI,iBACC;AAAA,kBACI,gBAAgB,MACZ,eAAe,SAAS,KAAK;AAAA,gBAAA,IAErC,CAAA;AAAA,gBACL,GAAI,eACC;AAAA,kBACI,cAAc,MACV,aAAa,SAAS,KAAK;AAAA,gBAAA,IAEnC,CAAA;AAAA,cAAC;AAAA,cApBF,QAAQ;AAAA,YAAA,CAsBpB;AAAA,YACA,UACG;AAAA,cAAC;AAAA,cAAA;AAAA,gBACG,IAAI,OAAO,OAAO;AAAA,gBAClB,QAAQ;AAAA,gBACR,MAAK;AAAA,gBACL;AAAA,gBACA,aAAa,kBAAkB;AAAA,gBAC/B;AAAA,gBACA,SACI,eACI,iBAEA,qBAAC,QAAA,EAAK,WAAU,2BACZ,UAAA;AAAA,kBAAA,oBAAC,QAAA,EAAK,WAAU,0GAAA,CAA0G;AAAA,kBAC1H,oBAAC,QAAA,EAAK,WAAU,4GAAA,CAA4G;AAAA,kBAC5H,oBAAC,QAAA,EAAK,WAAU,0GAAA,CAA0G;AAAA,gBAAA,EAAA,CAC9H;AAAA,cAAA;AAAA,YAAA;AAAA,UAGZ,GAER;AAAA,UAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAAgB,EAAA,CAC9B,EAAA,CACJ;AAER,CAAC;AAED,YAAY,cAAc;"}
1
+ {"version":3,"file":"MessageList.js","sources":["../../../../../../lib/@ecme/components/view/ChatBox/components/MessageList.tsx"],"sourcesContent":["import ScrollBar from '@/components/ui/ScrollBar'\nimport Message from './Message'\nimport classNames from '@/utils/classNames'\nimport type { ReactNode } from 'react'\nimport { forwardRef } from 'react'\nimport type { ScrollBarRef } from '@/components/ui/ScrollBar'\nimport type { MessageProps } from './Message'\n\ntype List = MessageProps & { fresh?: boolean; isError?: boolean }\n\nexport type MessageListProps = {\n list: List[]\n showAvatar?: boolean\n avatarGap?: boolean\n typing?:\n | {\n id: string\n name: string\n avatarImageUrl?: string\n }\n | false\n customRenderer?: (message: List, index: number) => string | ReactNode\n customAction?: (message: List, index: number) => string | ReactNode\n bubbleClass?: string\n myBubbleClass?: string\n botBubbleClass?: string\n errorBubbleClass?: string\n renderTyping?: () => ReactNode\n messageListClass?: string\n}\n\nconst MessageList = forwardRef<ScrollBarRef, MessageListProps>((props, ref) => { const {\n list = [],\n showAvatar = true,\n typing = false,\n avatarGap,\n customRenderer,\n customAction,\n messageListClass,\n bubbleClass,\n myBubbleClass,\n botBubbleClass,\n errorBubbleClass,\n renderTyping,\n } = props\n\n return (\n <div className={classNames('relative', messageListClass)}>\n <div className=\"absolute top-0 left-0 h-full w-full py-4\"> <ScrollBar\n ref={ref}\n autoHide\n className=\"overflow-y-auto h-full max-w-full\"\n >\n <div className=\"flex flex-col gap-4 px-4\">\n {list.map((message, index) => (\n <Message\n key={message.id}\n showAvatar={showAvatar}\n avatarGap={avatarGap}\n bubbleClass={\n message.isError\n ? errorBubbleClass ?? bubbleClass\n : message.isMyMessage\n ? myBubbleClass ?? bubbleClass\n : botBubbleClass ?? bubbleClass\n }\n {...message}\n {...(customRenderer\n ? {\n customRenderer: () =>\n customRenderer(message, index),\n }\n : {})}\n {...(customAction\n ? {\n customAction: () =>\n customAction(message, index),\n }\n : {})}\n />\n ))}\n {typing && (\n <Message\n id={typing.name + 'typing'}\n sender={typing}\n type=\"regular\"\n showAvatar={showAvatar}\n bubbleClass={botBubbleClass ?? bubbleClass}\n avatarGap={avatarGap}\n content={\n renderTyping ? (\n renderTyping()\n ) : (\n <span className=\"flex items-center gap-2\">\n <span className=\"size-1.5 rounded-full bg-gray-700 motion-safe:animate-[bounce_1s_ease-in-out_infinite] dark:bg-gray-300\"></span>\n <span className=\"size-1.5 rounded-full bg-gray-700 motion-safe:animate-[bounce_0.5s_ease-in-out_infinite] dark:bg-gray-300\"></span>\n <span className=\"size-1.5 rounded-full bg-gray-700 motion-safe:animate-[bounce_1s_ease-in-out_infinite] dark:bg-gray-300\"></span>\n </span>\n )\n }\n />\n )}\n </div> </ScrollBar>\n </div>\n </div>\n )\n})\n\nMessageList.displayName = 'MessageList'\n\nexport default MessageList\n"],"names":[],"mappings":";;;;;;AA+BA,MAAM,cAAc,WAA2C,CAAC,OAAO,QAAQ;AAAK,QAAM;AAAA,IAClF,OAAO,CAAA;AAAA,IACP,aAAa;AAAA,IACb,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA;AAEJ,SACI,oBAAC,OAAA,EAAI,WAAW,WAAW,YAAY,gBAAgB,GACnD,UAAA,qBAAC,OAAA,EAAI,WAAU,4CAA2C,UAAA;AAAA,IAAA;AAAA,IAAgB;AAAA,MAAC;AAAA,MAAA;AAAA,QACnE;AAAA,QACA,UAAQ;AAAA,QACR,WAAU;AAAA,QAEV,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,4BACV,UAAA;AAAA,YAAA,KAAK,IAAI,CAAC,SAAS,UAChB;AAAA,cAAC;AAAA,cAAA;AAAA,gBAEG;AAAA,gBACA;AAAA,gBACA,aACI,QAAQ,UACF,oBAAoB,cACpB,QAAQ,cACN,iBAAiB,cACjB,kBAAkB;AAAA,gBAE7B,GAAG;AAAA,gBACH,GAAI,iBACC;AAAA,kBACI,gBAAgB,MACZ,eAAe,SAAS,KAAK;AAAA,gBAAA,IAErC,CAAA;AAAA,gBACL,GAAI,eACC;AAAA,kBACI,cAAc,MACV,aAAa,SAAS,KAAK;AAAA,gBAAA,IAEnC,CAAA;AAAA,cAAC;AAAA,cAtBF,QAAQ;AAAA,YAAA,CAwBpB;AAAA,YACA,UACG;AAAA,cAAC;AAAA,cAAA;AAAA,gBACG,IAAI,OAAO,OAAO;AAAA,gBAClB,QAAQ;AAAA,gBACR,MAAK;AAAA,gBACL;AAAA,gBACA,aAAa,kBAAkB;AAAA,gBAC/B;AAAA,gBACA,SACI,eACI,iBAEA,qBAAC,QAAA,EAAK,WAAU,2BACZ,UAAA;AAAA,kBAAA,oBAAC,QAAA,EAAK,WAAU,0GAAA,CAA0G;AAAA,kBAC1H,oBAAC,QAAA,EAAK,WAAU,4GAAA,CAA4G;AAAA,kBAC5H,oBAAC,QAAA,EAAK,WAAU,0GAAA,CAA0G;AAAA,gBAAA,EAAA,CAC9H;AAAA,cAAA;AAAA,YAAA;AAAA,UAGZ,GAER;AAAA,UAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAAgB,EAAA,CAC9B,EAAA,CACJ;AAER,CAAC;AAED,YAAY,cAAc;"}
@@ -10,7 +10,7 @@ import "./auth/index.js";
10
10
  import "./assets/index.js";
11
11
  import "./locales/index.js";
12
12
  import { ADMIN, USER } from "./constants/roles.constant.js";
13
- import { AI_API_URL, AI_MODEL_HEADER, apiGetAiModels, apiGetChatHistory, apiGetImages, apiPostChat, apiPostImages } from "./services/AiService.js";
13
+ import { AI_API_URL, apiGetChatHistory, apiGetImages, apiPostImages, resumeChat, streamChat } from "./services/AiService.js";
14
14
  import { APP_NAME, REDIRECT_URL_KEY } from "./constants/app.constant.js";
15
15
  import { AUTH_PREFIX_PATH, CONCEPTS_PREFIX_PATH, DASHBOARDS_PREFIX_PATH, GUIDE_PREFIX_PATH, PAGES_PREFIX_PATH, ROOT, UI_COMPONENTS_PREFIX_PATH } from "./constants/route.constant.js";
16
16
  import { default as default2 } from "./components/shared/AbbreviateNumber.js";
@@ -207,7 +207,6 @@ import { default as default137 } from "./utils/hoc/withHeaderItem.js";
207
207
  export {
208
208
  ADMIN,
209
209
  AI_API_URL,
210
- AI_MODEL_HEADER,
211
210
  APP_NAME,
212
211
  AUTH_PREFIX_PATH,
213
212
  default2 as AbbreviateNumber,
@@ -376,7 +375,6 @@ export {
376
375
  default103 as Views,
377
376
  default104 as acronym,
378
377
  apiForgotPassword,
379
- apiGetAiModels,
380
378
  apiGetAnalyticDashboard,
381
379
  apiGetArticleList,
382
380
  apiGetCalendar,
@@ -421,7 +419,6 @@ export {
421
419
  apiGetSupportHubCategories,
422
420
  apiGithubOauthSignIn,
423
421
  apiGoogleOauthSignIn,
424
- apiPostChat,
425
422
  apiPostImages,
426
423
  apiPostProject,
427
424
  apiResetPassword,
@@ -449,7 +446,9 @@ export {
449
446
  othersPlaceholder,
450
447
  protectedRoutes,
451
448
  publicRoutes,
449
+ resumeChat,
452
450
  default114 as sharedDocs,
451
+ streamChat,
453
452
  tailwindStyles,
454
453
  templateStyles,
455
454
  default115 as themeConfig,
@@ -1,6 +1,6 @@
1
+ import { authHeaders } from "./aiAuthHeaders.js";
1
2
  import ApiService from "./ApiService.js";
2
- import { useAiModelStore } from "../views/concepts/ai/Chat/store/aiModelStore.js";
3
- const AI_MODEL_HEADER = "X-Ai-Model";
3
+ import { readSse } from "./sseParser.js";
4
4
  const AI_DEV_URL = "http://localhost:8000";
5
5
  const AI_BUILD_URL = "https://orbe-ai-homolog.apps.qas.orbeagro.com.br";
6
6
  function getAiApiUrl() {
@@ -11,33 +11,63 @@ function getAiApiUrl() {
11
11
  return AI_BUILD_URL;
12
12
  }
13
13
  const AI_API_URL = getAiApiUrl();
14
- const aiModelHeader = () => {
15
- const selectedModel = useAiModelStore.getState().selectedModel;
16
- return selectedModel ? { [AI_MODEL_HEADER]: selectedModel } : void 0;
17
- };
18
14
  const aiRequest = (config) => ApiService.fetchDataWithAxios({
19
15
  ...config,
20
16
  baseURL: AI_API_URL,
21
17
  skipGlobalLoading: true
22
18
  });
23
- async function apiPostChat(data) {
24
- return aiRequest({
25
- url: "/ai/chat",
26
- method: "post",
27
- data,
28
- headers: aiModelHeader()
29
- });
30
- }
31
- async function apiGetChatHistory() {
19
+ async function apiGetChatHistory(conversationId) {
32
20
  return aiRequest({
33
21
  url: "/ai/chat/history",
34
- method: "get"
22
+ method: "get",
23
+ params: conversationId ? { conversation_id: conversationId } : void 0
35
24
  });
36
25
  }
37
- async function apiGetAiModels() {
38
- return aiRequest({
39
- url: "/ai/models",
40
- method: "get"
26
+ async function streamChat({
27
+ prompt,
28
+ conversationId,
29
+ signal,
30
+ onEvent
31
+ }) {
32
+ await postarEConsumir(
33
+ "/ai/chat/stream",
34
+ { prompt, conversation_id: conversationId },
35
+ onEvent,
36
+ signal
37
+ );
38
+ }
39
+ async function resumeChat({
40
+ approved,
41
+ conversationId,
42
+ signal,
43
+ onEvent
44
+ }) {
45
+ await postarEConsumir(
46
+ "/ai/chat/resume",
47
+ { approved, conversation_id: conversationId },
48
+ onEvent,
49
+ signal
50
+ );
51
+ }
52
+ async function postarEConsumir(caminho, corpo, onEvent, signal) {
53
+ const resposta = await fetch(`${AI_API_URL}${caminho}`, {
54
+ method: "POST",
55
+ headers: {
56
+ ...authHeaders(),
57
+ "Content-Type": "application/json"
58
+ },
59
+ body: JSON.stringify(corpo),
60
+ signal
61
+ });
62
+ if (!resposta.ok || !resposta.body) {
63
+ throw new Error(`Falha ao falar com a IA (HTTP ${resposta.status})`);
64
+ }
65
+ await readSse(resposta.body, ({ event, data }) => {
66
+ try {
67
+ onEvent({ type: event, data: JSON.parse(data) });
68
+ } catch (error) {
69
+ console.debug("Evento SSE ignorado:", event, error);
70
+ }
41
71
  });
42
72
  }
43
73
  async function apiGetImages(params) {
@@ -56,11 +86,10 @@ async function apiPostImages(data) {
56
86
  }
57
87
  export {
58
88
  AI_API_URL,
59
- AI_MODEL_HEADER,
60
- apiGetAiModels,
61
89
  apiGetChatHistory,
62
90
  apiGetImages,
63
- apiPostChat,
64
- apiPostImages
91
+ apiPostImages,
92
+ resumeChat,
93
+ streamChat
65
94
  };
66
95
  //# sourceMappingURL=AiService.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AiService.js","sources":["../../../lib/@ecme/services/AiService.ts"],"sourcesContent":["import ApiService from './ApiService'\nimport { useAiModelStore } from '@/views/concepts/ai/Chat/store/aiModelStore'\nimport type { AxiosRequestConfig } from 'axios'\n\n/** Informa ao backend qual modelo usar. Sem o header, ele aplica o default. */\nexport const AI_MODEL_HEADER = 'X-Ai-Model'\n\nconst AI_DEV_URL = 'http://localhost:8000'\nconst AI_BUILD_URL = 'https://orbe-ai-homolog.apps.qas.orbeagro.com.br'\n\n/**\n * Host da API de IA.\n *\n * O /ai/* nao vive no gateway do resto da aplicacao, entao nao pode usar o\n * baseURL do AxiosBase (API_URL). A resolucao e por origin em runtime, e nao\n * por import.meta.env.MODE, porque o MODE e congelado na build da lib como\n * \"production\" e nao reflete o dev do MFE consumidor.\n */\nfunction getAiApiUrl() {\n const origin = globalThis?.location?.origin ?? ''\n\n if (origin.includes('localhost') || origin.includes('127.0.0.1')) {\n return AI_DEV_URL\n }\n\n // QAS e PRD compartilham a mesma URL por enquanto. Quando houver uma URL\n // de PRD, o split entra aqui: if (origin.includes('.prd.')) return AI_PRD_URL\n return AI_BUILD_URL\n}\n\nexport const AI_API_URL = getAiApiUrl()\n\nexport type AiModel = {\n id: string\n label: string\n default: boolean\n cloud: boolean\n}\n\nexport type GetAiModelsResponse = {\n models: AiModel[]\n}\n\n/**\n * Header do modelo escolhido, montado por chamada.\n *\n * Deliberadamente NAO e um interceptor global do AxiosBase: o chat vive no\n * layout de todos os MFEs, e um interceptor faria toda requisicao de todo\n * modulo passar por essa checagem so para servir ao /ai/*.\n */\nconst aiModelHeader = () => {\n const selectedModel = useAiModelStore.getState().selectedModel\n return selectedModel ? { [AI_MODEL_HEADER]: selectedModel } : undefined\n}\n\n/**\n * Toda chamada de IA sai pelo AI_API_URL (o baseURL por requisicao vence o da\n * instancia do AxiosBase) e fica fora do loading global o chat mostra o\n * proprio balaozinho de \"digitando\".\n */\nconst aiRequest = <T>(config: AxiosRequestConfig) =>\n ApiService.fetchDataWithAxios<T>({\n ...config,\n baseURL: AI_API_URL,\n skipGlobalLoading: true,\n })\n\nexport async function apiPostChat<T>(data: {\n prompt: string\n attachments?: File[]\n}) {\n return aiRequest<T>({\n url: '/ai/chat',\n method: 'post',\n data,\n headers: aiModelHeader(),\n })\n}\n\nexport async function apiGetChatHistory<T>() {\n return aiRequest<T>({\n url: '/ai/chat/history',\n method: 'get',\n })\n}\n\nexport async function apiGetAiModels<T>() {\n return aiRequest<T>({\n url: '/ai/models',\n method: 'get',\n })\n}\n\nexport async function apiGetImages<T, U extends Record<string, unknown>>(\n params: U,\n) {\n return aiRequest<T>({\n url: '/ai/images',\n method: 'get',\n params,\n })\n}\n\nexport async function apiPostImages<T, U extends Record<string, unknown>>(\n data: U,\n) {\n return aiRequest<T>({\n url: '/ai/images',\n method: 'post',\n data,\n })\n}\n"],"names":[],"mappings":";;AAKO,MAAM,kBAAkB;AAE/B,MAAM,aAAa;AACnB,MAAM,eAAe;AAUrB,SAAS,cAAc;AACnB,QAAM,SAAS,YAAY,UAAU,UAAU;AAE/C,MAAI,OAAO,SAAS,WAAW,KAAK,OAAO,SAAS,WAAW,GAAG;AAC9D,WAAO;AAAA,EACX;AAIA,SAAO;AACX;AAEO,MAAM,aAAa,YAAA;AAoB1B,MAAM,gBAAgB,MAAM;AACxB,QAAM,gBAAgB,gBAAgB,SAAA,EAAW;AACjD,SAAO,gBAAgB,EAAE,CAAC,eAAe,GAAG,kBAAkB;AAClE;AAOA,MAAM,YAAY,CAAI,WAClB,WAAW,mBAAsB;AAAA,EAC7B,GAAG;AAAA,EACH,SAAS;AAAA,EACT,mBAAmB;AACvB,CAAC;AAEL,eAAsB,YAAe,MAGlC;AACC,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,IACA,SAAS,cAAA;AAAA,EAAc,CAC1B;AACL;AAEA,eAAsB,oBAAuB;AACzC,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,EAAA,CACX;AACL;AAEA,eAAsB,iBAAoB;AACtC,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,EAAA,CACX;AACL;AAEA,eAAsB,aAClB,QACF;AACE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EAAA,CACH;AACL;AAEA,eAAsB,cAClB,MACF;AACE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EAAA,CACH;AACL;"}
1
+ {"version":3,"file":"AiService.js","sources":["../../../lib/@ecme/services/AiService.ts"],"sourcesContent":["import { authHeaders } from './aiAuthHeaders'\nimport ApiService from './ApiService'\nimport { readSse } from './sseParser'\nimport type { ChatEvent } from '@/views/concepts/ai/Chat/types'\nimport type { AxiosRequestConfig } from 'axios'\n\nconst AI_DEV_URL = 'http://localhost:8000'\nconst AI_BUILD_URL = 'https://orbe-ai-homolog.apps.qas.orbeagro.com.br'\n\n/**\n * Host da API de IA.\n *\n * O /ai/* nao vive no gateway do resto da aplicacao, entao nao pode usar o\n * baseURL do AxiosBase (API_URL). A resolucao e por origin em runtime, e nao\n * por import.meta.env.MODE, porque o MODE e congelado na build da lib como\n * \"production\" e nao reflete o dev do MFE consumidor.\n */\nfunction getAiApiUrl() {\n const origin = globalThis?.location?.origin ?? ''\n\n if (origin.includes('localhost') || origin.includes('127.0.0.1')) {\n return AI_DEV_URL\n }\n\n // QAS e PRD compartilham a mesma URL por enquanto. Quando houver uma URL\n // de PRD, o split entra aqui: if (origin.includes('.prd.')) return AI_PRD_URL\n return AI_BUILD_URL\n}\n\nexport const AI_API_URL = getAiApiUrl()\n\n/**\n * Toda chamada de IA sai pelo AI_API_URL (o baseURL por requisicao vence o da\n * instancia do AxiosBase) e fica fora do loading global — o chat mostra o\n * proprio balaozinho de \"digitando\".\n */\nconst aiRequest = <T>(config: AxiosRequestConfig) =>\n ApiService.fetchDataWithAxios<T>({\n ...config,\n baseURL: AI_API_URL,\n skipGlobalLoading: true,\n })\n\nexport async function apiGetChatHistory<T>(conversationId?: string) {\n return aiRequest<T>({\n url: '/ai/chat/history',\n method: 'get',\n params: conversationId ? { conversation_id: conversationId } : undefined,\n })\n}\n\nexport type StreamChatParams = {\n prompt: string\n /** Identifica a conversa; o backend usa como thread da memoria. */\n conversationId?: string\n signal?: AbortSignal\n onEvent: (evento: ChatEvent) => void\n}\n\nexport type ResumeChatParams = {\n /** true = aprovar a operacao pendente, false = negar. */\n approved: boolean\n conversationId?: string\n signal?: AbortSignal\n onEvent: (evento: ChatEvent) => void\n}\n\n/**\n * Envia a mensagem e consome a resposta em streaming (SSE).\n *\n * Usa `fetch`, e nao o Axios, porque o Axios no browser so resolve a Promise\n * com a resposta inteira nao ha como ler o corpo enquanto ele chega.\n */\nexport async function streamChat({\n prompt,\n conversationId,\n signal,\n onEvent,\n}: StreamChatParams): Promise<void> {\n await postarEConsumir(\n '/ai/chat/stream',\n { prompt, conversation_id: conversationId },\n onEvent,\n signal,\n )\n}\n\n/**\n * Retoma uma conversa parada num pedido de aprovacao.\n *\n * Devolve o mesmo tipo de stream do `streamChat`, e a resposta continua na\n * MESMA mensagem do chat o backend so volta do ponto onde parou.\n */\nexport async function resumeChat({\n approved,\n conversationId,\n signal,\n onEvent,\n}: ResumeChatParams): Promise<void> {\n await postarEConsumir(\n '/ai/chat/resume',\n { approved, conversation_id: conversationId },\n onEvent,\n signal,\n )\n}\n\n/** POST + leitura do SSE, comum ao envio e a retomada. */\nasync function postarEConsumir(\n caminho: string,\n corpo: Record<string, unknown>,\n onEvent: (evento: ChatEvent) => void,\n signal?: AbortSignal,\n): Promise<void> {\n const resposta = await fetch(`${AI_API_URL}${caminho}`, {\n method: 'POST',\n headers: {\n ...authHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(corpo),\n signal,\n })\n\n if (!resposta.ok || !resposta.body) {\n throw new Error(`Falha ao falar com a IA (HTTP ${resposta.status})`)\n }\n\n await readSse(resposta.body, ({ event, data }) => {\n try {\n onEvent({ type: event, data: JSON.parse(data) } as ChatEvent)\n } catch (error) {\n // Evento malformado nao pode derrubar o stream inteiro.\n console.debug('Evento SSE ignorado:', event, error)\n }\n })\n}\n\nexport async function apiGetImages<T, U extends Record<string, unknown>>(\n params: U,\n) {\n return aiRequest<T>({\n url: '/ai/images',\n method: 'get',\n params,\n })\n}\n\nexport async function apiPostImages<T, U extends Record<string, unknown>>(\n data: U,\n) {\n return aiRequest<T>({\n url: '/ai/images',\n method: 'post',\n data,\n })\n}\n"],"names":[],"mappings":";;;AAMA,MAAM,aAAa;AACnB,MAAM,eAAe;AAUrB,SAAS,cAAc;AACnB,QAAM,SAAS,YAAY,UAAU,UAAU;AAE/C,MAAI,OAAO,SAAS,WAAW,KAAK,OAAO,SAAS,WAAW,GAAG;AAC9D,WAAO;AAAA,EACX;AAIA,SAAO;AACX;AAEO,MAAM,aAAa,YAAA;AAO1B,MAAM,YAAY,CAAI,WAClB,WAAW,mBAAsB;AAAA,EAC7B,GAAG;AAAA,EACH,SAAS;AAAA,EACT,mBAAmB;AACvB,CAAC;AAEL,eAAsB,kBAAqB,gBAAyB;AAChE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ,iBAAiB,EAAE,iBAAiB,mBAAmB;AAAA,EAAA,CAClE;AACL;AAwBA,eAAsB,WAAW;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,GAAoC;AAChC,QAAM;AAAA,IACF;AAAA,IACA,EAAE,QAAQ,iBAAiB,eAAA;AAAA,IAC3B;AAAA,IACA;AAAA,EAAA;AAER;AAQA,eAAsB,WAAW;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,GAAoC;AAChC,QAAM;AAAA,IACF;AAAA,IACA,EAAE,UAAU,iBAAiB,eAAA;AAAA,IAC7B;AAAA,IACA;AAAA,EAAA;AAER;AAGA,eAAe,gBACX,SACA,OACA,SACA,QACa;AACb,QAAM,WAAW,MAAM,MAAM,GAAG,UAAU,GAAG,OAAO,IAAI;AAAA,IACpD,QAAQ;AAAA,IACR,SAAS;AAAA,MACL,GAAG,YAAA;AAAA,MACH,gBAAgB;AAAA,IAAA;AAAA,IAEpB,MAAM,KAAK,UAAU,KAAK;AAAA,IAC1B;AAAA,EAAA,CACH;AAED,MAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAChC,UAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,GAAG;AAAA,EACvE;AAEA,QAAM,QAAQ,SAAS,MAAM,CAAC,EAAE,OAAO,WAAW;AAC9C,QAAI;AACA,cAAQ,EAAE,MAAM,OAAO,MAAM,KAAK,MAAM,IAAI,GAAgB;AAAA,IAChE,SAAS,OAAO;AAEZ,cAAQ,MAAM,wBAAwB,OAAO,KAAK;AAAA,IACtD;AAAA,EACJ,CAAC;AACL;AAEA,eAAsB,aAClB,QACF;AACE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EAAA,CACH;AACL;AAEA,eAAsB,cAClB,MACF;AACE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EAAA,CACH;AACL;"}
@@ -0,0 +1,35 @@
1
+ import appConfig from "../configs/app.config.js";
2
+ import { TOKEN_NAME_IN_STORAGE, TOKEN_TYPE, REQUEST_HEADER_AUTH_KEY } from "../constants/api.constant.js";
3
+ const authHeaders = () => {
4
+ const storage = appConfig.accessTokenPersistStrategy;
5
+ const headers = {};
6
+ if (storage !== "localStorage" && storage !== "sessionStorage") {
7
+ return headers;
8
+ }
9
+ const source = storage === "localStorage" ? localStorage : sessionStorage;
10
+ const accessToken = source.getItem(TOKEN_NAME_IN_STORAGE) || "";
11
+ if (accessToken) {
12
+ headers[REQUEST_HEADER_AUTH_KEY] = `${TOKEN_TYPE}${accessToken}`;
13
+ }
14
+ const userId = readUserId();
15
+ if (userId) {
16
+ headers["X-User-Id"] = userId;
17
+ }
18
+ return headers;
19
+ };
20
+ const readUserId = () => {
21
+ try {
22
+ const raw = localStorage.getItem("SessionUserPageStore");
23
+ if (!raw) {
24
+ return void 0;
25
+ }
26
+ return JSON.parse(raw)?.state?.user?.userId;
27
+ } catch (error) {
28
+ console.debug("Could not read userId from session store:", error);
29
+ return void 0;
30
+ }
31
+ };
32
+ export {
33
+ authHeaders
34
+ };
35
+ //# sourceMappingURL=aiAuthHeaders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiAuthHeaders.js","sources":["../../../lib/@ecme/services/aiAuthHeaders.ts"],"sourcesContent":["import appConfig from '@/configs/app.config'\nimport {\n REQUEST_HEADER_AUTH_KEY,\n TOKEN_NAME_IN_STORAGE,\n TOKEN_TYPE,\n} from '@/constants/api.constant'\n\n/**\n * Headers de autenticacao lidos do storage.\n *\n * Existe porque o chat de IA usa `fetch` (o Axios nao faz streaming no\n * browser) e portanto nao passa pelo interceptor. Em vez de duplicar as regras\n * de onde mora o token, o interceptor e o fetch chamam esta funcao — uma\n * verdade so.\n *\n * Ver AxiosRequestIntrceptorConfigCallback, que a consome.\n */\nexport const authHeaders = (): Record<string, string> => {\n const storage = appConfig.accessTokenPersistStrategy\n const headers: Record<string, string> = {}\n\n if (storage !== 'localStorage' && storage !== 'sessionStorage') {\n return headers\n }\n\n const source = storage === 'localStorage' ? localStorage : sessionStorage\n const accessToken = source.getItem(TOKEN_NAME_IN_STORAGE) || ''\n\n if (accessToken) {\n headers[REQUEST_HEADER_AUTH_KEY] = `${TOKEN_TYPE}${accessToken}`\n }\n\n const userId = readUserId()\n if (userId) {\n headers['X-User-Id'] = userId\n }\n\n return headers\n}\n\n/**\n * userId da sessao persistida pelo zustand.\n *\n * Silencioso em caso de erro: um storage corrompido nao pode derrubar a\n * requisicao — sem o header, o backend apenas trata o usuario como desconhecido.\n */\nconst readUserId = (): string | undefined => {\n try {\n const raw = localStorage.getItem('SessionUserPageStore')\n if (!raw) {\n return undefined\n }\n return JSON.parse(raw)?.state?.user?.userId\n } catch (error) {\n console.debug('Could not read userId from session store:', error)\n return undefined\n }\n}\n"],"names":[],"mappings":";;AAiBO,MAAM,cAAc,MAA8B;AACrD,QAAM,UAAU,UAAU;AAC1B,QAAM,UAAkC,CAAA;AAExC,MAAI,YAAY,kBAAkB,YAAY,kBAAkB;AAC5D,WAAO;AAAA,EACX;AAEA,QAAM,SAAS,YAAY,iBAAiB,eAAe;AAC3D,QAAM,cAAc,OAAO,QAAQ,qBAAqB,KAAK;AAE7D,MAAI,aAAa;AACb,YAAQ,uBAAuB,IAAI,GAAG,UAAU,GAAG,WAAW;AAAA,EAClE;AAEA,QAAM,SAAS,WAAA;AACf,MAAI,QAAQ;AACR,YAAQ,WAAW,IAAI;AAAA,EAC3B;AAEA,SAAO;AACX;AAQA,MAAM,aAAa,MAA0B;AACzC,MAAI;AACA,UAAM,MAAM,aAAa,QAAQ,sBAAsB;AACvD,QAAI,CAAC,KAAK;AACN,aAAO;AAAA,IACX;AACA,WAAO,KAAK,MAAM,GAAG,GAAG,OAAO,MAAM;AAAA,EACzC,SAAS,OAAO;AACZ,YAAQ,MAAM,6CAA6C,KAAK;AAChE,WAAO;AAAA,EACX;AACJ;"}
@@ -1,31 +1,8 @@
1
- import appConfig from "../../configs/app.config.js";
2
- import { TOKEN_NAME_IN_STORAGE, TOKEN_TYPE, REQUEST_HEADER_AUTH_KEY } from "../../constants/api.constant.js";
1
+ import { authHeaders } from "../aiAuthHeaders.js";
3
2
  const AxiosRequestIntrceptorConfigCallback = (config) => {
4
- const storage = appConfig.accessTokenPersistStrategy;
5
- if (storage === "localStorage" || storage === "sessionStorage") {
6
- let accessToken = "";
7
- if (storage === "localStorage") {
8
- accessToken = localStorage.getItem(TOKEN_NAME_IN_STORAGE) || "";
9
- }
10
- if (storage === "sessionStorage") {
11
- accessToken = sessionStorage.getItem(TOKEN_NAME_IN_STORAGE) || "";
12
- }
13
- if (accessToken) {
14
- config.headers[REQUEST_HEADER_AUTH_KEY] = `${TOKEN_TYPE}${accessToken}`;
15
- }
16
- try {
17
- const sessionUserStore = localStorage.getItem("SessionUserPageStore");
18
- if (sessionUserStore) {
19
- const parsedStore = JSON.parse(sessionUserStore);
20
- const userId = parsedStore?.state?.user?.userId;
21
- if (userId) {
22
- config.headers["X-User-Id"] = userId;
23
- }
24
- }
25
- } catch (error) {
26
- console.debug("Could not read userId from session store:", error);
27
- }
28
- }
3
+ Object.entries(authHeaders()).forEach(([chave, valor]) => {
4
+ config.headers[chave] = valor;
5
+ });
29
6
  return config;
30
7
  };
31
8
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"AxiosRequestIntrceptorConfigCallback.js","sources":["../../../../lib/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.ts"],"sourcesContent":["import appConfig from '@/configs/app.config'\nimport {\n TOKEN_TYPE,\n REQUEST_HEADER_AUTH_KEY,\n TOKEN_NAME_IN_STORAGE,\n} from '@/constants/api.constant'\nimport type { InternalAxiosRequestConfig } from 'axios'\n\nconst AxiosRequestIntrceptorConfigCallback = (\n config: InternalAxiosRequestConfig,\n) => {\n const storage = appConfig.accessTokenPersistStrategy\n\n if (storage === 'localStorage' || storage === 'sessionStorage') {\n let accessToken = ''\n\n if (storage === 'localStorage') {\n accessToken = localStorage.getItem(TOKEN_NAME_IN_STORAGE) || ''\n }\n\n if (storage === 'sessionStorage') {\n accessToken = sessionStorage.getItem(TOKEN_NAME_IN_STORAGE) || ''\n }\n\n if (accessToken) {\n config.headers[REQUEST_HEADER_AUTH_KEY] =\n `${TOKEN_TYPE}${accessToken}`\n }\n\n // Adicionar X-User-Id header se o usuário estiver autenticado\n try {\n const sessionUserStore = localStorage.getItem('SessionUserPageStore')\n if (sessionUserStore) {\n const parsedStore = JSON.parse(sessionUserStore)\n const userId = parsedStore?.state?.user?.userId\n if (userId) {\n config.headers['X-User-Id'] = userId\n }\n }\n } catch (error) {\n // Silently ignore errors reading user session\n console.debug('Could not read userId from session store:', error)\n }\n }\n\n return config\n}\n\nexport default AxiosRequestIntrceptorConfigCallback\n"],"names":[],"mappings":";;AAQA,MAAM,uCAAuC,CACzC,WACC;AACD,QAAM,UAAU,UAAU;AAE1B,MAAI,YAAY,kBAAkB,YAAY,kBAAkB;AAC5D,QAAI,cAAc;AAElB,QAAI,YAAY,gBAAgB;AAC5B,oBAAc,aAAa,QAAQ,qBAAqB,KAAK;AAAA,IACjE;AAEA,QAAI,YAAY,kBAAkB;AAC9B,oBAAc,eAAe,QAAQ,qBAAqB,KAAK;AAAA,IACnE;AAEA,QAAI,aAAa;AACb,aAAO,QAAQ,uBAAuB,IAClC,GAAG,UAAU,GAAG,WAAW;AAAA,IACnC;AAGA,QAAI;AACA,YAAM,mBAAmB,aAAa,QAAQ,sBAAsB;AACpE,UAAI,kBAAkB;AAClB,cAAM,cAAc,KAAK,MAAM,gBAAgB;AAC/C,cAAM,SAAS,aAAa,OAAO,MAAM;AACzC,YAAI,QAAQ;AACR,iBAAO,QAAQ,WAAW,IAAI;AAAA,QAClC;AAAA,MACJ;AAAA,IACJ,SAAS,OAAO;AAEZ,cAAQ,MAAM,6CAA6C,KAAK;AAAA,IACpE;AAAA,EACJ;AAEA,SAAO;AACX;"}
1
+ {"version":3,"file":"AxiosRequestIntrceptorConfigCallback.js","sources":["../../../../lib/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.ts"],"sourcesContent":["import { authHeaders } from '../aiAuthHeaders'\nimport type { InternalAxiosRequestConfig } from 'axios'\n\n/**\n * Injeta Authorization e X-User-Id em toda requisicao do Axios.\n *\n * As regras de onde o token mora vivem em `authHeaders` compartilhadas com o\n * chat de IA, que usa `fetch` e nao passa por aqui.\n */\nconst AxiosRequestIntrceptorConfigCallback = (\n config: InternalAxiosRequestConfig,\n) => {\n Object.entries(authHeaders()).forEach(([chave, valor]) => {\n config.headers[chave] = valor\n })\n\n return config\n}\n\nexport default AxiosRequestIntrceptorConfigCallback\n"],"names":[],"mappings":";AASA,MAAM,uCAAuC,CACzC,WACC;AACD,SAAO,QAAQ,aAAa,EAAE,QAAQ,CAAC,CAAC,OAAO,KAAK,MAAM;AACtD,WAAO,QAAQ,KAAK,IAAI;AAAA,EAC5B,CAAC;AAED,SAAO;AACX;"}
@@ -1,6 +1,6 @@
1
1
  import { default as default2 } from "./ApiService.js";
2
2
  import { apiGetPricingPlans, apiGetRolesPermissionsRoles, apiGetRolesPermissionsUsers, apiGetSettingsBilling, apiGetSettingsIntergration, apiGetSettingsNotification, apiGetSettingsProfile } from "./AccontsService.js";
3
- import { AI_API_URL, AI_MODEL_HEADER, apiGetAiModels, apiGetChatHistory, apiGetImages, apiPostChat, apiPostImages } from "./AiService.js";
3
+ import { AI_API_URL, apiGetChatHistory, apiGetImages, apiPostImages, resumeChat, streamChat } from "./AiService.js";
4
4
  import { apiForgotPassword, apiResetPassword, apiSignIn, apiSignOut, apiSignUp } from "./AuthService.js";
5
5
  import { apiGetCalendar } from "./CalendarService.js";
6
6
  import { apiGetChats, apiGetContactDetails, apiGetContacts, apiGetConversation } from "./ChatService.js";
@@ -17,10 +17,8 @@ import { apiGetProduct, apiGetProductList } from "./ProductService.js";
17
17
  import { apiGetProject, apiGetProjectMembers, apiGetProjectTask, apiGetProjectTasks, apiGetProjects, apiGetScrumBoards, apiPostProject } from "./ProjectService.js";
18
18
  export {
19
19
  AI_API_URL,
20
- AI_MODEL_HEADER,
21
20
  default2 as ApiService,
22
21
  apiForgotPassword,
23
- apiGetAiModels,
24
22
  apiGetAnalyticDashboard,
25
23
  apiGetArticleList,
26
24
  apiGetCalendar,
@@ -65,12 +63,13 @@ export {
65
63
  apiGetSupportHubCategories,
66
64
  apiGithubOauthSignIn,
67
65
  apiGoogleOauthSignIn,
68
- apiPostChat,
69
66
  apiPostImages,
70
67
  apiPostProject,
71
68
  apiResetPassword,
72
69
  apiSignIn,
73
70
  apiSignOut,
74
- apiSignUp
71
+ apiSignUp,
72
+ resumeChat,
73
+ streamChat
75
74
  };
76
75
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,42 @@
1
+ const SEPARADOR = /\r?\n\r?\n/;
2
+ async function readSse(body, onEvent) {
3
+ const reader = body.getReader();
4
+ const decoder = new TextDecoder();
5
+ let buffer = "";
6
+ try {
7
+ for (; ; ) {
8
+ const { done, value } = await reader.read();
9
+ if (done) {
10
+ emitir(buffer, onEvent);
11
+ return;
12
+ }
13
+ buffer += decoder.decode(value, { stream: true });
14
+ const blocos = buffer.split(SEPARADOR);
15
+ buffer = blocos.pop() ?? "";
16
+ blocos.forEach((bloco) => emitir(bloco, onEvent));
17
+ }
18
+ } finally {
19
+ reader.releaseLock();
20
+ }
21
+ }
22
+ function emitir(bloco, onEvent) {
23
+ if (!bloco.trim()) {
24
+ return;
25
+ }
26
+ let event = "message";
27
+ const dados = [];
28
+ bloco.split(/\r?\n/).forEach((linha) => {
29
+ if (linha.startsWith("event:")) {
30
+ event = linha.slice(6).trim();
31
+ } else if (linha.startsWith("data:")) {
32
+ dados.push(linha.slice(5).replace(/^ /, ""));
33
+ }
34
+ });
35
+ if (dados.length) {
36
+ onEvent({ event, data: dados.join("\n") });
37
+ }
38
+ }
39
+ export {
40
+ readSse
41
+ };
42
+ //# sourceMappingURL=sseParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sseParser.js","sources":["../../../lib/@ecme/services/sseParser.ts"],"sourcesContent":["/**\n * Parser de Server-Sent Events sobre um ReadableStream.\n *\n * O EventSource nativo do browser nao serve aqui: ele so faz GET e nao aceita\n * headers, e o chat e um POST autenticado. Entao lemos o corpo do `fetch` na\n * mao.\n *\n * Duas bordas do protocolo que uma implementacao ingenua erra:\n *\n * 1. um chunk da rede pode cortar um evento no meio — por isso o resto fica no\n * buffer ate chegar o proximo `\\n\\n`;\n * 2. um chunk pode trazer varios eventos de uma vez.\n */\n\nexport type SseEvent = {\n event: string\n data: string\n}\n\nconst SEPARADOR = /\\r?\\n\\r?\\n/\n\n/** Le o stream ate o fim, chamando `onEvent` a cada evento completo. */\nexport async function readSse(\n body: ReadableStream<Uint8Array>,\n onEvent: (evento: SseEvent) => void,\n): Promise<void> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n try {\n for (;;) {\n const { done, value } = await reader.read()\n\n if (done) {\n // O ultimo evento pode nao vir seguido de linha em branco.\n emitir(buffer, onEvent)\n return\n }\n\n buffer += decoder.decode(value, { stream: true })\n\n const blocos = buffer.split(SEPARADOR)\n // O ultimo pedaco pode estar incompleto: volta para o buffer.\n buffer = blocos.pop() ?? ''\n blocos.forEach((bloco) => emitir(bloco, onEvent))\n }\n } finally {\n reader.releaseLock()\n }\n}\n\n/** Converte um bloco \"event: x\\ndata: y\" em SseEvent. */\nfunction emitir(bloco: string, onEvent: (evento: SseEvent) => void) {\n if (!bloco.trim()) {\n return\n }\n\n let event = 'message'\n const dados: string[] = []\n\n bloco.split(/\\r?\\n/).forEach((linha) => {\n if (linha.startsWith('event:')) {\n event = linha.slice(6).trim()\n } else if (linha.startsWith('data:')) {\n // O espaco depois de \"data:\" e opcional no protocolo.\n dados.push(linha.slice(5).replace(/^ /, ''))\n }\n // Linhas iniciadas por \":\" sao comentarios (keep-alive) e sao ignoradas.\n })\n\n if (dados.length) {\n onEvent({ event, data: dados.join('\\n') })\n }\n}\n"],"names":[],"mappings":"AAmBA,MAAM,YAAY;AAGlB,eAAsB,QAClB,MACA,SACa;AACb,QAAM,SAAS,KAAK,UAAA;AACpB,QAAM,UAAU,IAAI,YAAA;AACpB,MAAI,SAAS;AAEb,MAAI;AACA,eAAS;AACL,YAAM,EAAE,MAAM,MAAA,IAAU,MAAM,OAAO,KAAA;AAErC,UAAI,MAAM;AAEN,eAAO,QAAQ,OAAO;AACtB;AAAA,MACJ;AAEA,gBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,MAAM;AAEhD,YAAM,SAAS,OAAO,MAAM,SAAS;AAErC,eAAS,OAAO,SAAS;AACzB,aAAO,QAAQ,CAAC,UAAU,OAAO,OAAO,OAAO,CAAC;AAAA,IACpD;AAAA,EACJ,UAAA;AACI,WAAO,YAAA;AAAA,EACX;AACJ;AAGA,SAAS,OAAO,OAAe,SAAqC;AAChE,MAAI,CAAC,MAAM,QAAQ;AACf;AAAA,EACJ;AAEA,MAAI,QAAQ;AACZ,QAAM,QAAkB,CAAA;AAExB,QAAM,MAAM,OAAO,EAAE,QAAQ,CAAC,UAAU;AACpC,QAAI,MAAM,WAAW,QAAQ,GAAG;AAC5B,cAAQ,MAAM,MAAM,CAAC,EAAE,KAAA;AAAA,IAC3B,WAAW,MAAM,WAAW,OAAO,GAAG;AAElC,YAAM,KAAK,MAAM,MAAM,CAAC,EAAE,QAAQ,MAAM,EAAE,CAAC;AAAA,IAC/C;AAAA,EAEJ,CAAC;AAED,MAAI,MAAM,QAAQ;AACd,YAAQ,EAAE,OAAO,MAAM,MAAM,KAAK,IAAI,GAAG;AAAA,EAC7C;AACJ;"}
@@ -0,0 +1,15 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { TbPlugConnectedX } from "react-icons/tb";
3
+ const AiErrorMessage = () => {
4
+ return /* @__PURE__ */ jsxs("span", { className: "flex items-start gap-3", children: [
5
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full bg-red-100 text-red-500 dark:bg-red-500/15 dark:text-red-400", children: /* @__PURE__ */ jsx(TbPlugConnectedX, { size: 18 }) }),
6
+ /* @__PURE__ */ jsxs("span", { className: "flex flex-col gap-0.5", children: [
7
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-red-600 dark:text-red-400", children: "Falha na comunicação" }),
8
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-red-500/90 dark:text-red-300/90", children: "Desculpe, estou com um pequeno problema de comunicação e não consigo te atender no momento. Tente novamente em instantes." })
9
+ ] })
10
+ ] });
11
+ };
12
+ export {
13
+ AiErrorMessage as default
14
+ };
15
+ //# sourceMappingURL=AiErrorMessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiErrorMessage.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.tsx"],"sourcesContent":["import { TbPlugConnectedX } from 'react-icons/tb'\n\n/**\n * Mensagem de erro do agente Orbe AI — exibida no lugar da resposta quando a\n * comunicação com o serviço de IA falha, com acento vermelho para sinalizar\n * o erro sem quebrar o tom visual do chat.\n */\nconst AiErrorMessage = () => {\n return (\n <span className=\"flex items-start gap-3\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full bg-red-100 text-red-500 dark:bg-red-500/15 dark:text-red-400\">\n <TbPlugConnectedX size={18} />\n </span>\n <span className=\"flex flex-col gap-0.5\">\n <span className=\"text-sm font-semibold text-red-600 dark:text-red-400\">\n Falha na comunicação\n </span>\n <span className=\"text-sm text-red-500/90 dark:text-red-300/90\">\n Desculpe, estou com um pequeno problema de comunicação e\n não consigo te atender no momento. Tente novamente em\n instantes.\n </span>\n </span>\n </span>\n )\n}\n\nexport default AiErrorMessage\n"],"names":[],"mappings":";;AAOA,MAAM,iBAAiB,MAAM;AACzB,SACI,qBAAC,QAAA,EAAK,WAAU,0BACZ,UAAA;AAAA,IAAA,oBAAC,UAAK,WAAU,qIACZ,8BAAC,kBAAA,EAAiB,MAAM,IAAI,EAAA,CAChC;AAAA,IACA,qBAAC,QAAA,EAAK,WAAU,yBACZ,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,WAAU,wDAAuD,UAAA,wBAEvE;AAAA,MACA,oBAAC,QAAA,EAAK,WAAU,gDAA+C,UAAA,4HAAA,CAI/D;AAAA,IAAA,EAAA,CACJ;AAAA,EAAA,GACJ;AAER;"}
@@ -0,0 +1,73 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { TbLock } from "react-icons/tb";
4
+ import "../../../../../components/ui/Button/index.js";
5
+ import { iconeFerramenta, camposVisiveis, rotularFerramenta } from "./toolPresentation.js";
6
+ import Button from "../../../../../components/ui/Button/Button.js";
7
+ const ApprovalCard = ({ approval, onDecide }) => {
8
+ const [decisao, setDecisao] = useState(null);
9
+ const decidir = (aprovado) => {
10
+ setDecisao(aprovado ? "aprovar" : "negar");
11
+ onDecide(aprovado);
12
+ };
13
+ return /* @__PURE__ */ jsxs("div", { className: "not-prose mt-1 overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800", children: [
14
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-gray-200 px-4 py-2.5 dark:border-gray-700", children: [
15
+ /* @__PURE__ */ jsx(TbLock, { size: 16, className: "text-gray-400 dark:text-gray-500" }),
16
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400", children: "Confirmação necessária" })
17
+ ] }),
18
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-3.5", children: [
19
+ approval.calls.map((call) => {
20
+ const Icone = iconeFerramenta(call.name);
21
+ const campos = camposVisiveis(call.args);
22
+ return /* @__PURE__ */ jsxs("div", { className: "mb-4 last:mb-0", children: [
23
+ /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-start gap-2.5", children: [
24
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary-subtle text-primary", children: /* @__PURE__ */ jsx(Icone, { size: 17 }) }),
25
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
26
+ /* @__PURE__ */ jsx("div", { className: "font-semibold text-gray-900 dark:text-gray-100", children: rotularFerramenta(call.name) }),
27
+ /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Revise os dados antes de confirmar." })
28
+ ] })
29
+ ] }),
30
+ /* @__PURE__ */ jsx("dl", { className: "divide-y divide-gray-100 rounded-lg border border-gray-100 dark:divide-gray-700 dark:border-gray-700", children: campos.map((campo) => /* @__PURE__ */ jsxs(
31
+ "div",
32
+ {
33
+ className: "flex items-baseline justify-between gap-4 px-3 py-2",
34
+ children: [
35
+ /* @__PURE__ */ jsx("dt", { className: "shrink-0 text-sm text-gray-500 dark:text-gray-400", children: campo.rotulo }),
36
+ /* @__PURE__ */ jsx("dd", { className: "truncate text-sm font-medium text-gray-900 dark:text-gray-100", children: campo.valor })
37
+ ]
38
+ },
39
+ campo.chave
40
+ )) })
41
+ ] }, call.id);
42
+ }),
43
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2", children: [
44
+ /* @__PURE__ */ jsx(
45
+ Button,
46
+ {
47
+ variant: "solid",
48
+ size: "sm",
49
+ loading: decisao === "aprovar",
50
+ disabled: decisao !== null,
51
+ onClick: () => decidir(true),
52
+ children: "Confirmar"
53
+ }
54
+ ),
55
+ /* @__PURE__ */ jsx(
56
+ Button,
57
+ {
58
+ size: "sm",
59
+ loading: decisao === "negar",
60
+ disabled: decisao !== null,
61
+ onClick: () => decidir(false),
62
+ children: "Cancelar"
63
+ }
64
+ ),
65
+ /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-gray-400 dark:text-gray-500", children: "Nada é gravado até você confirmar" })
66
+ ] })
67
+ ] })
68
+ ] });
69
+ };
70
+ export {
71
+ ApprovalCard as default
72
+ };
73
+ //# sourceMappingURL=ApprovalCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApprovalCard.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ApprovalCard.tsx"],"sourcesContent":["import { useState } from 'react'\nimport { TbLock } from 'react-icons/tb'\nimport Button from '@/components/ui/Button'\nimport { camposVisiveis, iconeFerramenta, rotularFerramenta } from './toolPresentation'\nimport type { PendingApproval } from '../types'\n\ntype ApprovalCardProps = {\n approval: PendingApproval\n onDecide: (approved: boolean) => void\n}\n\n/**\n * Confirmacao de uma operacao que grava no ERP.\n *\n * O agente fica PARADO enquanto este card estiver na tela — so volta a\n * responder depois do clique. Por isso ele nao usa a paleta de alerta: nao e um\n * aviso de erro, e uma decisao de negocio que o usuario precisa tomar.\n */\nconst ApprovalCard = ({ approval, onDecide }: ApprovalCardProps) => {\n const [decisao, setDecisao] = useState<'aprovar' | 'negar' | null>(null)\n\n const decidir = (aprovado: boolean) => {\n setDecisao(aprovado ? 'aprovar' : 'negar')\n onDecide(aprovado)\n }\n\n return (\n <div className=\"not-prose mt-1 overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800\">\n <div className=\"flex items-center gap-2 border-b border-gray-200 px-4 py-2.5 dark:border-gray-700\">\n <TbLock size={16} className=\"text-gray-400 dark:text-gray-500\" />\n <span className=\"text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400\">\n Confirmação necessária\n </span>\n </div>\n\n <div className=\"px-4 py-3.5\">\n {approval.calls.map((call) => {\n const Icone = iconeFerramenta(call.name)\n const campos = camposVisiveis(call.args)\n\n return (\n <div key={call.id} className=\"mb-4 last:mb-0\">\n <div className=\"mb-3 flex items-start gap-2.5\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary-subtle text-primary\">\n <Icone size={17} />\n </span>\n <div className=\"min-w-0\">\n <div className=\"font-semibold text-gray-900 dark:text-gray-100\">\n {rotularFerramenta(call.name)}\n </div>\n <div className=\"text-sm text-gray-500 dark:text-gray-400\">\n Revise os dados antes de confirmar.\n </div>\n </div>\n </div>\n\n <dl className=\"divide-y divide-gray-100 rounded-lg border border-gray-100 dark:divide-gray-700 dark:border-gray-700\">\n {campos.map((campo) => (\n <div\n key={campo.chave}\n className=\"flex items-baseline justify-between gap-4 px-3 py-2\"\n >\n <dt className=\"shrink-0 text-sm text-gray-500 dark:text-gray-400\">\n {campo.rotulo}\n </dt>\n <dd className=\"truncate text-sm font-medium text-gray-900 dark:text-gray-100\">\n {campo.valor}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n )\n })}\n\n <div className=\"mt-4 flex items-center gap-2\">\n <Button\n variant=\"solid\"\n size=\"sm\"\n loading={decisao === 'aprovar'}\n disabled={decisao !== null}\n onClick={() => decidir(true)}\n >\n Confirmar\n </Button>\n <Button\n size=\"sm\"\n loading={decisao === 'negar'}\n disabled={decisao !== null}\n onClick={() => decidir(false)}\n >\n Cancelar\n </Button>\n <span className=\"ml-auto text-xs text-gray-400 dark:text-gray-500\">\n Nada é gravado até você confirmar\n </span>\n </div>\n </div>\n </div>\n )\n}\n\nexport default ApprovalCard\n"],"names":[],"mappings":";;;;;;AAkBA,MAAM,eAAe,CAAC,EAAE,UAAU,eAAkC;AAChE,QAAM,CAAC,SAAS,UAAU,IAAI,SAAqC,IAAI;AAEvE,QAAM,UAAU,CAAC,aAAsB;AACnC,eAAW,WAAW,YAAY,OAAO;AACzC,aAAS,QAAQ;AAAA,EACrB;AAEA,SACI,qBAAC,OAAA,EAAI,WAAU,6HACX,UAAA;AAAA,IAAA,qBAAC,OAAA,EAAI,WAAU,qFACX,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAO,MAAM,IAAI,WAAU,oCAAmC;AAAA,MAC/D,oBAAC,QAAA,EAAK,WAAU,kFAAiF,UAAA,yBAAA,CAEjG;AAAA,IAAA,GACJ;AAAA,IAEA,qBAAC,OAAA,EAAI,WAAU,eACV,UAAA;AAAA,MAAA,SAAS,MAAM,IAAI,CAAC,SAAS;AAC1B,cAAM,QAAQ,gBAAgB,KAAK,IAAI;AACvC,cAAM,SAAS,eAAe,KAAK,IAAI;AAEvC,eACI,qBAAC,OAAA,EAAkB,WAAU,kBACzB,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,iCACX,UAAA;AAAA,YAAA,oBAAC,UAAK,WAAU,qGACZ,8BAAC,OAAA,EAAM,MAAM,IAAI,EAAA,CACrB;AAAA,YACA,qBAAC,OAAA,EAAI,WAAU,WACX,UAAA;AAAA,cAAA,oBAAC,SAAI,WAAU,kDACV,UAAA,kBAAkB,KAAK,IAAI,GAChC;AAAA,cACA,oBAAC,OAAA,EAAI,WAAU,4CAA2C,UAAA,sCAAA,CAE1D;AAAA,YAAA,EAAA,CACJ;AAAA,UAAA,GACJ;AAAA,8BAEC,MAAA,EAAG,WAAU,wGACT,UAAA,OAAO,IAAI,CAAC,UACT;AAAA,YAAC;AAAA,YAAA;AAAA,cAEG,WAAU;AAAA,cAEV,UAAA;AAAA,gBAAA,oBAAC,MAAA,EAAG,WAAU,qDACT,UAAA,MAAM,QACX;AAAA,gBACA,oBAAC,MAAA,EAAG,WAAU,iEACT,gBAAM,MAAA,CACX;AAAA,cAAA;AAAA,YAAA;AAAA,YARK,MAAM;AAAA,UAAA,CAUlB,EAAA,CACL;AAAA,QAAA,EAAA,GA7BM,KAAK,EA8Bf;AAAA,MAER,CAAC;AAAA,MAED,qBAAC,OAAA,EAAI,WAAU,gCACX,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACG,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,YAAY;AAAA,YACrB,UAAU,YAAY;AAAA,YACtB,SAAS,MAAM,QAAQ,IAAI;AAAA,YAC9B,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAGD;AAAA,UAAC;AAAA,UAAA;AAAA,YACG,MAAK;AAAA,YACL,SAAS,YAAY;AAAA,YACrB,UAAU,YAAY;AAAA,YACtB,SAAS,MAAM,QAAQ,KAAK;AAAA,YAC/B,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAGD,oBAAC,QAAA,EAAK,WAAU,oDAAmD,UAAA,oCAAA,CAEnE;AAAA,MAAA,EAAA,CACJ;AAAA,IAAA,EAAA,CACJ;AAAA,EAAA,GACJ;AAER;"}