@praxisui/table 8.0.0-beta.27 → 8.0.0-beta.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,4 @@
1
1
  import { firstValueFrom } from 'rxjs';
2
- import { shouldRoutePromptToGovernedDecision } from '@praxisui/ai';
3
2
 
4
3
  class TableAgenticAuthoringTurnFlow {
5
4
  adapter;
@@ -27,9 +26,6 @@ class TableAgenticAuthoringTurnFlow {
27
26
  ?.map((field) => this.toAiJsonObject(field))
28
27
  .filter((field) => Object.keys(field).length > 0);
29
28
  const contextHints = this.optionalJsonObject(this.adapter.getAuthoringContext?.());
30
- if (this.shouldRouteToGovernedDecision(prompt, contextHints)) {
31
- return this.toGovernedDecisionHandoff(prompt, request);
32
- }
33
29
  const response = await firstValueFrom(this.aiApi.getPatch({
34
30
  componentId,
35
31
  componentType,
@@ -134,6 +130,7 @@ class TableAgenticAuthoringTurnFlow {
134
130
  sessionId: response.sessionId ?? request.sessionId,
135
131
  assistantMessage: message,
136
132
  statusText: message,
133
+ quickReplies: this.toQuickReplies(response),
137
134
  canApply: false,
138
135
  };
139
136
  }
@@ -150,12 +147,11 @@ class TableAgenticAuthoringTurnFlow {
150
147
  }
151
148
  if (response.patch && Object.keys(response.patch).length > 0) {
152
149
  const warnings = response.warnings?.filter(Boolean) ?? [];
153
- const suffix = warnings.length ? ` Avisos: ${warnings.join('; ')}` : '';
154
150
  return {
155
151
  state: 'review',
156
152
  phase: 'review',
157
153
  sessionId: response.sessionId ?? request.sessionId,
158
- assistantMessage: `${response.explanation || 'Proposta de alteracao pronta para revisar.'}${suffix}`,
154
+ assistantMessage: response.explanation || 'Proposta de alteracao pronta para revisar.',
159
155
  statusText: 'Revise a proposta antes de aplicar.',
160
156
  canApply: true,
161
157
  pendingPatch: response.patch,
@@ -243,12 +239,17 @@ class TableAgenticAuthoringTurnFlow {
243
239
  return payloads
244
240
  .map((option, index) => {
245
241
  const label = option.label?.trim() || option.value?.trim() || `Opcao ${index + 1}`;
246
- const prompt = option.example?.trim() || option.value?.trim() || label;
242
+ const prompt = option.value?.trim() || option.example?.trim() || label;
247
243
  return {
248
244
  id: `option-${index + 1}`,
249
245
  label,
250
246
  prompt,
251
247
  kind: 'clarification-option',
248
+ description: this.optionDescription(option),
249
+ icon: this.optionIcon(option),
250
+ tone: this.optionTone(option),
251
+ presentation: this.optionPresentation(option),
252
+ contextHints: this.optionContextHints(option),
252
253
  };
253
254
  });
254
255
  }
@@ -261,6 +262,28 @@ class TableAgenticAuthoringTurnFlow {
261
262
  kind: 'clarification-option',
262
263
  }));
263
264
  }
265
+ optionContextHints(option) {
266
+ return this.toRecord(option.contextHints);
267
+ }
268
+ optionPresentation(option) {
269
+ const hints = this.optionContextHints(option);
270
+ return this.toRecord(hints?.['presentation']);
271
+ }
272
+ optionDescription(option) {
273
+ const presentation = this.optionPresentation(option);
274
+ const value = presentation?.['description'];
275
+ return typeof value === 'string' && value.trim() ? value.trim() : null;
276
+ }
277
+ optionIcon(option) {
278
+ const presentation = this.optionPresentation(option);
279
+ const value = presentation?.['icon'];
280
+ return typeof value === 'string' && value.trim() ? value.trim() : null;
281
+ }
282
+ optionTone(option) {
283
+ const presentation = this.optionPresentation(option);
284
+ const value = presentation?.['tone'];
285
+ return typeof value === 'string' && value.trim() ? value.trim() : null;
286
+ }
264
287
  buildCurrentStateDigest(currentState, dataProfile) {
265
288
  const columns = Array.isArray(currentState['columns'])
266
289
  ? currentState['columns']
@@ -273,64 +296,6 @@ class TableAgenticAuthoringTurnFlow {
273
296
  ...(rowCount !== undefined ? { rowCount } : {}),
274
297
  };
275
298
  }
276
- shouldRouteToGovernedDecision(prompt, contextHints) {
277
- return shouldRoutePromptToGovernedDecision(prompt, contextHints);
278
- }
279
- toGovernedDecisionHandoff(prompt, request) {
280
- const message = 'Esse pedido parece alterar uma decisao de negocio compartilhada. A tabela pode ajudar a descrever o alvo, mas a regra deve seguir pelo fluxo governado de domain-rules antes de qualquer materializacao runtime.';
281
- return {
282
- state: 'clarification',
283
- phase: 'clarify',
284
- sessionId: request.sessionId,
285
- assistantMessage: message,
286
- statusText: 'Handoff governado necessario.',
287
- canApply: false,
288
- quickReplies: [
289
- {
290
- id: 'shared-rule-handoff',
291
- label: 'Continuar como regra governada',
292
- prompt,
293
- kind: 'shared-rule-handoff',
294
- description: 'Criar intake de domain-rules em vez de aplicar patch local na tabela.',
295
- icon: 'rule',
296
- tone: 'warning',
297
- contextHints: {
298
- flowId: 'shared_rule_authoring',
299
- source: 'praxis-table',
300
- recommendedAction: 'domain-rules/intake',
301
- },
302
- },
303
- ],
304
- clarificationQuestions: [
305
- {
306
- id: 'table-governed-rule-confirmation',
307
- type: 'confirm',
308
- label: 'Deseja continuar pelo fluxo governado de regras compartilhadas?',
309
- description: 'Esse caminho permite intake, simulacao, aprovacao/publicacao, materializacao e validacao de enforcement.',
310
- required: true,
311
- options: [
312
- {
313
- id: 'shared-rule-handoff',
314
- label: 'Sim, continuar governado',
315
- value: prompt,
316
- description: 'Nao aplicar como patch local da tabela.',
317
- contextHints: {
318
- flowId: 'shared_rule_authoring',
319
- source: 'praxis-table',
320
- },
321
- },
322
- ],
323
- },
324
- ],
325
- diagnostics: {
326
- governedDecisionHandoff: {
327
- flowId: 'shared_rule_authoring',
328
- sourcePrompt: prompt,
329
- sourceComponent: 'praxis-table',
330
- },
331
- },
332
- };
333
- }
334
299
  optionalJsonObject(value) {
335
300
  if (value === undefined || value === null) {
336
301
  return undefined;
@@ -1,7 +1,7 @@
1
1
  import { firstValueFrom } from 'rxjs';
2
2
  import { BaseAiAdapter } from '@praxisui/ai';
3
3
  import { deepMerge } from '@praxisui/core';
4
- import { coerceTableComponentEditPlans, compileTableComponentEditPlans, TABLE_AI_CAPABILITIES, TASK_PRESETS, getTableComponentEditPlanCapabilities, TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS, TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS, TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA, TABLE_COMPONENT_EDIT_PLAN_VERSION, TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND, TABLE_COMPONENT_EDIT_PLAN_KIND } from './praxisui-table.mjs';
4
+ import { c as coerceTableComponentEditPlans, a as compileTableComponentEditPlans, T as TABLE_AI_CAPABILITIES, b as TASK_PRESETS, g as getTableComponentEditPlanCapabilities, d as TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS, e as TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS, f as TABLE_COMPONENT_EDIT_PLAN_OPERATION_IDS, h as TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA, i as TABLE_COMPONENT_EDIT_PLAN_VERSION, j as TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND, k as TABLE_COMPONENT_EDIT_PLAN_KIND } from './praxisui-table-praxisui-table-CKnX_qQK.mjs';
5
5
 
6
6
  /**
7
7
  * Analisa uma amostra de dados da tabela para gerar estatísticas
@@ -179,14 +179,16 @@ class TableAiAdapter extends BaseAiAdapter {
179
179
  batchKind: TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND,
180
180
  version: TABLE_COMPONENT_EDIT_PLAN_VERSION,
181
181
  schemaId: TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA.$id,
182
+ allowedOperationIds: [...TABLE_COMPONENT_EDIT_PLAN_OPERATION_IDS],
182
183
  allowedChangeKinds: [...TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS],
183
184
  expectedPaths: { ...TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS },
184
185
  capabilities: getTableComponentEditPlanCapabilities(),
185
186
  rules: [
186
- 'Use componentEditPlan instead of free patch when the request fits an allowed table edit changeKind.',
187
+ 'Use componentEditPlan instead of free patch when the request fits an allowed table operationId or changeKind.',
188
+ 'Prefer manifest operationId for governed agentic authoring responses.',
187
189
  'Use batch kind with operations for multiple table edits in one request.',
188
190
  'Use Json Logic objects for computed expressions and conditional rules.',
189
- 'Do not invent fields, changeKinds, capabilityPaths, formats, badge variants, or colors outside the provided contract.',
191
+ 'Do not invent fields, operationIds, changeKinds, capabilityPaths, formats, badge variants, or colors outside the provided contract.',
190
192
  ],
191
193
  },
192
194
  },
@@ -773,8 +775,8 @@ Columns Analysis:
773
775
  });
774
776
  }
775
777
  /**
776
- * If a patch adds only a currency format, ensure the column type is set to 'currency'
777
- * so the formatter runs. Avoid overriding an explicit non-currency type.
778
+ * If a patch adds a typed format, ensure the column type is set so the
779
+ * formatter runs. Avoid overriding an explicit type.
778
780
  */
779
781
  normalizePatch(patch) {
780
782
  if (!patch.columns || !Array.isArray(patch.columns))
@@ -792,9 +794,29 @@ Columns Analysis:
792
794
  if (!format)
793
795
  return false;
794
796
  const fmt = format.trim();
797
+ if (this.looksLikeMaskFormat(fmt))
798
+ return false;
795
799
  // Heuristics: contains date tokens like d/M/y or common date separators
796
800
  return /(d|M|y){2,}/i.test(fmt) || fmt.includes('/') || fmt.includes('-');
797
801
  }
802
+ looksLikeBooleanFormat(format) {
803
+ if (!format)
804
+ return false;
805
+ const fmt = format.trim();
806
+ return [
807
+ 'true-false',
808
+ 'yes-no',
809
+ 'active-inactive',
810
+ 'on-off',
811
+ 'enabled-disabled',
812
+ ].includes(fmt) || fmt.startsWith('custom|');
813
+ }
814
+ looksLikeMaskFormat(format) {
815
+ if (!format)
816
+ return false;
817
+ const fmt = format.trim();
818
+ return /[0#9X]/i.test(fmt) && /^[0#9X.\-/()\s]+$/i.test(fmt);
819
+ }
798
820
  isIconRendererHint(renderer) {
799
821
  if (!renderer)
800
822
  return false;
@@ -812,6 +834,9 @@ Columns Analysis:
812
834
  if (this.looksLikeCurrencyFormat(next.format)) {
813
835
  next.type = 'currency';
814
836
  }
837
+ else if (this.looksLikeBooleanFormat(next.format)) {
838
+ next.type = 'boolean';
839
+ }
815
840
  else if (this.looksLikeDateFormat(next.format)) {
816
841
  next.type = 'date';
817
842
  }