@orbe-agro/client-core 5.6.243 → 5.6.245

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 (61) hide show
  1. package/dist/@ecme/components/template/Footer.js +1 -1
  2. package/dist/@ecme/services/AiService.js +2 -1
  3. package/dist/@ecme/services/AiService.js.map +1 -1
  4. package/dist/@ecme/views/concepts/ai/Chat/components/ChatView.js +14 -2
  5. package/dist/@ecme/views/concepts/ai/Chat/components/ChatView.js.map +1 -1
  6. package/dist/@ecme/views/concepts/ai/Chat/components/DataRequestCard.js +99 -0
  7. package/dist/@ecme/views/concepts/ai/Chat/components/DataRequestCard.js.map +1 -0
  8. package/dist/@ecme/views/concepts/ai/Chat/components/toolPresentation.js +15 -1
  9. package/dist/@ecme/views/concepts/ai/Chat/components/toolPresentation.js.map +1 -1
  10. package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatSend.js +21 -1
  11. package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatSend.js.map +1 -1
  12. package/dist/@types/@ecme/services/AiService.d.ts +13 -4
  13. package/dist/@types/@ecme/services/AiService.d.ts.map +1 -1
  14. package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatView.d.ts.map +1 -1
  15. package/dist/@types/@ecme/views/concepts/ai/Chat/components/DataRequestCard.d.ts +20 -0
  16. package/dist/@types/@ecme/views/concepts/ai/Chat/components/DataRequestCard.d.ts.map +1 -0
  17. package/dist/@types/@ecme/views/concepts/ai/Chat/components/toolPresentation.d.ts +12 -0
  18. package/dist/@types/@ecme/views/concepts/ai/Chat/components/toolPresentation.d.ts.map +1 -1
  19. package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatSend.d.ts +1 -0
  20. package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatSend.d.ts.map +1 -1
  21. package/dist/@types/@ecme/views/concepts/ai/Chat/types.d.ts +24 -0
  22. package/dist/@types/@ecme/views/concepts/ai/Chat/types.d.ts.map +1 -1
  23. package/dist/@types/base/@types/models/racao/carga.d.ts +1 -0
  24. package/dist/@types/base/@types/models/racao/carga.d.ts.map +1 -1
  25. package/dist/@types/base/configs/endpoints.config/agendamento/agendamento.d.ts +0 -1
  26. package/dist/@types/base/configs/endpoints.config/agendamento/agendamento.d.ts.map +1 -1
  27. package/dist/@types/base/configs/endpoints.config/agendamento/config/contratoVenda.d.ts +0 -1
  28. package/dist/@types/base/configs/endpoints.config/agendamento/config/contratoVenda.d.ts.map +1 -1
  29. package/dist/@types/base/configs/endpoints.config/dm/config/municipio.d.ts +4 -0
  30. package/dist/@types/base/configs/endpoints.config/dm/config/municipio.d.ts.map +1 -1
  31. package/dist/@types/base/configs/endpoints.config/dm/dm.d.ts +4 -0
  32. package/dist/@types/base/configs/endpoints.config/dm/dm.d.ts.map +1 -1
  33. package/dist/@types/base/configs/endpoints.config/endpoints.navigation.d.ts +4 -1
  34. package/dist/@types/base/configs/endpoints.config/endpoints.navigation.d.ts.map +1 -1
  35. package/dist/@types/base/services/modules/dm/municipio/MunicipioService.d.ts +1 -0
  36. package/dist/@types/base/services/modules/dm/municipio/MunicipioService.d.ts.map +1 -1
  37. package/dist/base/@types/models/racao/carga.js.map +1 -1
  38. package/dist/base/configs/endpoints.config/agendamento/config/contratoVenda.js +0 -1
  39. package/dist/base/configs/endpoints.config/agendamento/config/contratoVenda.js.map +1 -1
  40. package/dist/base/configs/endpoints.config/dm/config/municipio.js +2 -1
  41. package/dist/base/configs/endpoints.config/dm/config/municipio.js.map +1 -1
  42. package/dist/base/index.js +2 -1
  43. package/dist/base/services/index.js +2 -1
  44. package/dist/base/services/modules/agendamento/ContratoVendaService.js +2 -2
  45. package/dist/base/services/modules/agendamento/ContratoVendaService.js.map +1 -1
  46. package/dist/base/services/modules/dm/index.js +2 -1
  47. package/dist/base/services/modules/dm/municipio/MunicipioService.js +7 -0
  48. package/dist/base/services/modules/dm/municipio/MunicipioService.js.map +1 -1
  49. package/dist/base/services/modules/index.js +2 -1
  50. package/lib/@ecme/services/AiService.ts +14 -4
  51. package/lib/@ecme/views/concepts/ai/Chat/components/ChatView.tsx +17 -3
  52. package/lib/@ecme/views/concepts/ai/Chat/components/DataRequestCard.tsx +144 -0
  53. package/lib/@ecme/views/concepts/ai/Chat/components/toolPresentation.ts +29 -0
  54. package/lib/@ecme/views/concepts/ai/Chat/hooks/useChatSend.ts +43 -0
  55. package/lib/@ecme/views/concepts/ai/Chat/types.ts +23 -0
  56. package/lib/base/@types/models/racao/carga.ts +1 -0
  57. package/lib/base/configs/endpoints.config/agendamento/config/contratoVenda.ts +0 -1
  58. package/lib/base/configs/endpoints.config/dm/config/municipio.ts +2 -1
  59. package/lib/base/services/modules/agendamento/ContratoVendaService.ts +2 -2
  60. package/lib/base/services/modules/dm/municipio/MunicipioService.tsx +7 -0
  61. package/package.json +1 -1
@@ -0,0 +1,144 @@
1
+ import { useState } from 'react'
2
+ import { TbForms } from 'react-icons/tb'
3
+ import Button from '@/components/ui/Button'
4
+ import Input from '@/components/ui/Input'
5
+ import Select from '@/components/ui/Select'
6
+ import { opcoesDoCampo, rotularCampo, tipoDoCampo } from './toolPresentation'
7
+ import type { PendingInput } from '../types'
8
+
9
+ type DataRequestCardProps = {
10
+ input: PendingInput
11
+ /** `null` = o usuario fechou sem preencher. */
12
+ onSubmit: (dados: Record<string, unknown> | null) => void
13
+ }
14
+
15
+ /**
16
+ * Formulario dos campos que faltam para criar um registro no ERP.
17
+ *
18
+ * O agente fica PARADO enquanto este card estiver na tela — ele so volta a
19
+ * responder depois do envio. Por isso divide o visual do ApprovalCard: sao as
20
+ * duas paradas do fluxo, e o usuario deve reconhece-las como a mesma coisa.
21
+ *
22
+ * Os valores vao para o modelo, que monta a chamada final. Por isso o envio nao
23
+ * valida tipo: o `type=number` e o select sao conveniencia de digitacao, nao
24
+ * regra de negocio — quem valida de verdade e o backend do ERP.
25
+ */
26
+ const DataRequestCard = ({ input, onSubmit }: DataRequestCardProps) => {
27
+ const [valores, setValores] = useState<Record<string, string>>({})
28
+ const [enviando, setEnviando] = useState<'enviar' | 'cancelar' | null>(null)
29
+
30
+ const preencher = (campo: string, valor: string) =>
31
+ setValores((atual) => ({ ...atual, [campo]: valor }))
32
+
33
+ // Exigir todos evita uma ida e volta: faltando um, o agente pediria de novo.
34
+ const completo = input.campos.every((campo) => valores[campo]?.trim())
35
+
36
+ const enviar = () => {
37
+ setEnviando('enviar')
38
+ // Numeros vao como number; o resto como texto. O modelo aceita os dois,
39
+ // mas o tipo certo evita que ele precise adivinhar.
40
+ const dados = Object.fromEntries(
41
+ input.campos.map((campo) => {
42
+ const bruto = valores[campo].trim()
43
+ const numero =
44
+ tipoDoCampo(campo) === 'numero' ? Number(bruto) : NaN
45
+ return [campo, Number.isNaN(numero) ? bruto : numero]
46
+ }),
47
+ )
48
+ onSubmit(dados)
49
+ }
50
+
51
+ const cancelar = () => {
52
+ setEnviando('cancelar')
53
+ onSubmit(null)
54
+ }
55
+
56
+ return (
57
+ <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">
58
+ <div className="flex items-center gap-2 border-b border-gray-200 px-4 py-2.5 dark:border-gray-700">
59
+ <TbForms size={16} className="text-gray-400 dark:text-gray-500" />
60
+ <span className="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
61
+ Dados necessários
62
+ </span>
63
+ </div>
64
+
65
+ <div className="px-4 py-3.5">
66
+ <div className="mb-3 text-sm text-gray-500 dark:text-gray-400">
67
+ Preencha os campos abaixo para eu continuar.
68
+ </div>
69
+
70
+ <div className="flex flex-col gap-3">
71
+ {input.campos.map((campo) => {
72
+ const rotulo = rotularCampo(campo)
73
+ const opcoes = opcoesDoCampo(campo)
74
+
75
+ return (
76
+ <label key={campo} className="flex flex-col gap-1">
77
+ <span className="text-sm text-gray-600 dark:text-gray-300">
78
+ {rotulo}
79
+ </span>
80
+ {opcoes.length ? (
81
+ <Select
82
+ options={opcoes}
83
+ value={opcoes.filter(
84
+ (opcao) =>
85
+ opcao.value === valores[campo],
86
+ )}
87
+ placeholder={`Selecione ${rotulo.toLowerCase()}`}
88
+ isDisabled={enviando !== null}
89
+ onChange={(opcao) =>
90
+ preencher(
91
+ campo,
92
+ (opcao as { value: string } | null)
93
+ ?.value ?? '',
94
+ )
95
+ }
96
+ />
97
+ ) : (
98
+ <Input
99
+ type={
100
+ tipoDoCampo(campo) === 'numero'
101
+ ? 'number'
102
+ : 'text'
103
+ }
104
+ value={valores[campo] ?? ''}
105
+ disabled={enviando !== null}
106
+ placeholder={`Informe ${rotulo.toLowerCase()}`}
107
+ onChange={(evento) =>
108
+ preencher(campo, evento.target.value)
109
+ }
110
+ />
111
+ )}
112
+ </label>
113
+ )
114
+ })}
115
+ </div>
116
+
117
+ <div className="mt-4 flex items-center gap-2">
118
+ <Button
119
+ variant="solid"
120
+ size="sm"
121
+ loading={enviando === 'enviar'}
122
+ disabled={!completo || enviando !== null}
123
+ onClick={enviar}
124
+ >
125
+ Enviar
126
+ </Button>
127
+ <Button
128
+ size="sm"
129
+ loading={enviando === 'cancelar'}
130
+ disabled={enviando !== null}
131
+ onClick={cancelar}
132
+ >
133
+ Cancelar
134
+ </Button>
135
+ <span className="ml-auto text-xs text-gray-400 dark:text-gray-500">
136
+ Você ainda confirma antes de gravar
137
+ </span>
138
+ </div>
139
+ </div>
140
+ </div>
141
+ )
142
+ }
143
+
144
+ export default DataRequestCard
@@ -84,6 +84,35 @@ const REFERENCIAS = new Set([
84
84
 
85
85
  const ORDENACAO: Record<string, string> = { ASC: 'Crescente', DESC: 'Decrescente' }
86
86
 
87
+ /**
88
+ * Opcoes dos campos que sao enum no backend.
89
+ *
90
+ * O rotulo sai do mesmo `humanizar` usado na exibicao, entao o formulario e o
91
+ * card de confirmacao mostram exatamente o mesmo texto.
92
+ */
93
+ const OPCOES: Record<string, string[]> = {
94
+ tipo_contrato: ['MERCADO_INTERNO', 'MERCADO_EXTERNO'],
95
+ }
96
+
97
+ export const opcoesDoCampo = (chave: string) =>
98
+ (OPCOES[chave] ?? []).map((valor) => ({
99
+ value: valor,
100
+ label: humanizar(valor),
101
+ }))
102
+
103
+ /**
104
+ * Que tipo de controle o campo pede no formulario de coleta.
105
+ *
106
+ * E so UX (teclado numerico, lista em vez de texto livre): os valores voltam
107
+ * para o modelo, e e ele quem monta a chamada final — um tipo errado nao
108
+ * quebra, so piora o preenchimento.
109
+ */
110
+ export const tipoDoCampo = (chave: string): 'numero' | 'enum' | 'texto' => {
111
+ if (OPCOES[chave]) return 'enum'
112
+ if (REFERENCIAS.has(chave) || chave === 'saldo_negociado') return 'numero'
113
+ return 'texto'
114
+ }
115
+
87
116
  /** Converte o valor tecnico no que o usuario espera ler. */
88
117
  export const formatarValor = (chave: string, valor: unknown): string => {
89
118
  if (valor === null || valor === undefined || valor === '') {
@@ -137,6 +137,15 @@ const useChatSend = () => {
137
137
  break
138
138
  }
139
139
 
140
+ case 'input_required':
141
+ // Diferente da aprovação, aqui nenhuma ferramenta foi
142
+ // pedida ao ERP: o agente só percebeu que faltam campos.
143
+ // Por isso não há chip de ferramenta para ajustar.
144
+ updateConversation(chatId, messageId, {
145
+ pendingInput: evento.data,
146
+ })
147
+ break
148
+
140
149
  case 'done':
141
150
  // O done traz a resposta final completa e é a fonte
142
151
  // autoritativa — se algum token se perdeu, ele corrige.
@@ -235,9 +244,43 @@ const useChatSend = () => {
235
244
  )
236
245
  }
237
246
 
247
+ /**
248
+ * Envia os dados que faltavam (ou o cancelamento) e retoma a conversa.
249
+ *
250
+ * Mesma mecânica do `handleApproval`: continua na MESMA mensagem, então o
251
+ * acumulador parte do que já está lá.
252
+ */
253
+ const handleDataSubmit = async (
254
+ chatId: string,
255
+ messageId: string,
256
+ dados: Record<string, unknown> | null,
257
+ ) => {
258
+ const mensagem = usGenerativeChatStore
259
+ .getState()
260
+ .chatHistory.find((chat) => chat.id === chatId)
261
+ ?.conversation?.find((item) => item.id === messageId)
262
+
263
+ if (!mensagem?.pendingInput) {
264
+ return
265
+ }
266
+
267
+ setIsTyping(true)
268
+ // Some com o formulário antes da chamada: dois envios mandariam duas
269
+ // retomadas, e a segunda falha (o interrupt já foi consumido).
270
+ updateConversation(chatId, messageId, { pendingInput: undefined })
271
+
272
+ await consumirStream(
273
+ chatId,
274
+ messageId,
275
+ (onEvent) => resumeChat({ dados, conversationId: chatId, onEvent }),
276
+ { texto: mensagem.content ?? '', tools: mensagem.tools ?? [] },
277
+ )
278
+ }
279
+
238
280
  return {
239
281
  handleSend,
240
282
  handleApproval,
283
+ handleDataSubmit,
241
284
  }
242
285
  }
243
286
 
@@ -24,6 +24,17 @@ export type PendingApproval = {
24
24
  calls: { id: string; name: string; args: Record<string, unknown> }[]
25
25
  }
26
26
 
27
+ /**
28
+ * Criacao parada por falta de dados, esperando o usuario preencher.
29
+ *
30
+ * `campos` traz os nomes TECNICOS dos parametros que faltam (ex.:
31
+ * `produto_id`); quem exibe traduz com `rotularCampo`.
32
+ */
33
+ export type PendingInput = {
34
+ id: string
35
+ campos: string[]
36
+ }
37
+
27
38
  export type Conversation = {
28
39
  id: string
29
40
  sender: {
@@ -53,6 +64,8 @@ export type Conversation = {
53
64
  tools?: ToolCall[]
54
65
  /** Preenchido quando o agente pausou esperando aprovacao humana. */
55
66
  pendingApproval?: PendingApproval
67
+ /** Preenchido quando o agente pausou pedindo os dados que faltam. */
68
+ pendingInput?: PendingInput
56
69
  }
57
70
 
58
71
  /**
@@ -97,6 +110,16 @@ export type ChatEvent =
97
110
  }[]
98
111
  }
99
112
  }
113
+ | {
114
+ /**
115
+ * Faltam campos para criar: o agente parou esperando o formulario.
116
+ *
117
+ * Como no `approval_required`, o `done` NAO vem — o turno esta
118
+ * pausado. Retomar e chamar `resumeChat({ dados })`.
119
+ */
120
+ type: 'input_required'
121
+ data: { id: string; campos: string[] }
122
+ }
100
123
  | { type: 'done'; data: { content: string } }
101
124
  | { type: 'error'; data: { message: string } }
102
125
 
@@ -63,6 +63,7 @@ export type TOrdensCarga = {
63
63
  }
64
64
 
65
65
  export type TProdutosOrdemCarga = {
66
+ id?: number
66
67
  produtoId: number
67
68
  codigo: string
68
69
  descricao: string
@@ -1,7 +1,6 @@
1
1
  const contratoVenda = {
2
2
  findAll: '/agendamento/api/contrato-venda',
3
3
  findOne: '/agendamento/api/contrato-venda',
4
- findContratos: '/agendamento/api/vendas/contrato/find',
5
4
  comSaldoByCliente: '/agendamento/api/contrato-venda/com-saldo/cliente',
6
5
  relatorioCotas: '/agendamento/api/contrato-venda/find-relatorio-cotas',
7
6
  periodo: '/agendamento/api/contrato-venda/periodo',
@@ -5,7 +5,8 @@ const municipio = {
5
5
  findMunicipioByCodigo: { endpoint: `${MUNICIPIO_BASE_URL}/find/`, method: 'post' },
6
6
  findMonitor: { endpoint: `${MUNICIPIO_BASE_URL}/find-monitor`, httpMethod: 'post' },
7
7
  findAllUfs: { endpoint: `${MUNICIPIO_BASE_URL}/find-all-ufs`, httpMethod: 'get' },
8
- findMunicipioByUf: { endpoint: `${MUNICIPIO_BASE_URL}/find-municipio-by-uf/`, httpMethod: 'get' }
8
+ findMunicipioByUf: { endpoint: `${MUNICIPIO_BASE_URL}/find-municipio-by-uf/`, httpMethod: 'get' },
9
+ findById : { endpoint: `${MUNICIPIO_BASE_URL}`, httpMethod: 'get' }
9
10
  }
10
11
 
11
12
  export default municipio
@@ -36,7 +36,7 @@ export async function apiFindContratosComSaldoPorCliente(clienteId: string | num
36
36
 
37
37
  export async function apiFindAllContratos(params: Record<string, unknown>) {
38
38
  return ApiService.fetchDataWithAxios<TQueryResponse<TContratoVenda>>({
39
- url: endpointsConfig.agendamento.contratoVenda.findContratos,
39
+ url: endpointsConfig.agendamento.contratoVenda.findAll,
40
40
  method: 'post',
41
41
  data: params,
42
42
  })
@@ -44,7 +44,7 @@ export async function apiFindAllContratos(params: Record<string, unknown>) {
44
44
 
45
45
  export async function apiFindACDVendasContrato(contratoNumero: string) {
46
46
  return ApiService.fetchDataWithAxios<TQueryResponse<TContratoVenda>>({
47
- url: endpointsConfig.agendamento.contratoVenda.findContratos,
47
+ url: endpointsConfig.agendamento.contratoVenda.findAll,
48
48
  method: 'post',
49
49
  data: {
50
50
  pageNumber: 1,
@@ -41,3 +41,10 @@ export async function apiFindMunicipioByUf(uf: string) {
41
41
  method: MUNICIPIO_ENDPOINT.findMunicipioByUf.httpMethod,
42
42
  })
43
43
  }
44
+
45
+ export async function apiFindMunicipioById(id: string) {
46
+ return ApiService.fetchDataWithAxios<TMunicipio>({
47
+ url: MUNICIPIO_ENDPOINT.findById.endpoint + `/${id}`,
48
+ method: MUNICIPIO_ENDPOINT.findById.httpMethod,
49
+ })
50
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbe-agro/client-core",
3
- "version": "5.6.243",
3
+ "version": "5.6.245",
4
4
  "description": "Biblioteca principal de componentes e utilidades para os microfrontends do Orbe Agro.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",