@praxisui/table 8.0.0-beta.82 → 8.0.0-beta.85
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/fesm2022/{praxisui-table-praxisui-table-28INRbt6.mjs → praxisui-table-praxisui-table-BdJW7m53.mjs} +444 -68
- package/fesm2022/{praxisui-table-table-agentic-authoring-turn-flow-Bdi7IIY2.mjs → praxisui-table-table-agentic-authoring-turn-flow-DMglW7f1.mjs} +488 -18
- package/fesm2022/{praxisui-table-table-ai.adapter-OIjGp0kj.mjs → praxisui-table-table-ai.adapter-jpeX3Nbc.mjs} +85 -2
- package/fesm2022/praxisui-table.mjs +1 -1
- package/package.json +10 -10
- package/types/praxisui-table.d.ts +28 -10
|
@@ -266,8 +266,7 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
266
266
|
|| this.shouldUseSelectedRecordSurfaceSnapshotFallback(contextHints));
|
|
267
267
|
}
|
|
268
268
|
shouldUseSelectedRecordSurfaceSnapshotFallback(contextHints) {
|
|
269
|
-
return this.
|
|
270
|
-
&& this.selectedRecordSurfaces(contextHints).length > 0;
|
|
269
|
+
return this.selectedRecordSurfaces(contextHints).length > 0;
|
|
271
270
|
}
|
|
272
271
|
selectedRecordSurfaces(contextHints) {
|
|
273
272
|
const authoringContract = this.toRecord(contextHints?.['authoringContract']);
|
|
@@ -561,13 +560,14 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
561
560
|
? this.adapter.compileAiResponse?.(response)
|
|
562
561
|
: null;
|
|
563
562
|
if (compiledExecutable?.patch && Object.keys(compiledExecutable.patch).length > 0) {
|
|
563
|
+
const normalizedExecutable = this.normalizeBulkRouteSelectionPayload(compiledExecutable, request);
|
|
564
564
|
const warnings = [
|
|
565
565
|
...(response.warnings ?? []),
|
|
566
|
-
...(
|
|
566
|
+
...(normalizedExecutable.warnings ?? []),
|
|
567
567
|
];
|
|
568
568
|
const executableResponse = {
|
|
569
569
|
...response,
|
|
570
|
-
patch:
|
|
570
|
+
patch: normalizedExecutable.patch,
|
|
571
571
|
warnings: warnings.length ? warnings : undefined,
|
|
572
572
|
};
|
|
573
573
|
delete executableResponse.type;
|
|
@@ -578,6 +578,10 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
578
578
|
if (continuedInvalidExecutable) {
|
|
579
579
|
return continuedInvalidExecutable;
|
|
580
580
|
}
|
|
581
|
+
const continuedBulkRouteAction = this.bulkRouteActionPlanForInvalidExecutable(response, request, compiledExecutable.warnings);
|
|
582
|
+
if (continuedBulkRouteAction) {
|
|
583
|
+
return this.compileAdapterResponse(continuedBulkRouteAction, request);
|
|
584
|
+
}
|
|
581
585
|
return {
|
|
582
586
|
type: 'error',
|
|
583
587
|
message: compiledExecutable.message || 'O componentEditPlan da tabela nao passou na validacao de capacidades.',
|
|
@@ -592,12 +596,24 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
592
596
|
if (continuedSurfaceRuntimeOperation) {
|
|
593
597
|
return continuedSurfaceRuntimeOperation;
|
|
594
598
|
}
|
|
599
|
+
const continuedBulkRouteNarrative = this.bulkRouteActionPlanForNonExecutableNarrative(response, request);
|
|
600
|
+
if (continuedBulkRouteNarrative) {
|
|
601
|
+
return this.compileAdapterResponse(continuedBulkRouteNarrative, request);
|
|
602
|
+
}
|
|
603
|
+
const continuedBulkRouteAction = this.bulkRouteActionPlanForClarification(response, request);
|
|
604
|
+
if (continuedBulkRouteAction) {
|
|
605
|
+
return this.compileAdapterResponse(continuedBulkRouteAction, request);
|
|
606
|
+
}
|
|
595
607
|
const continuedSurfaceRowAction = this.selectedRecordSurfaceRowActionPlanForClarification(response, request);
|
|
596
608
|
if (continuedSurfaceRowAction) {
|
|
597
609
|
return this.compileAdapterResponse(continuedSurfaceRowAction, request);
|
|
598
610
|
}
|
|
599
611
|
return response;
|
|
600
612
|
}
|
|
613
|
+
const rowActionGuidance = this.recordSurfaceRowActionGuidanceForConsult(response, request);
|
|
614
|
+
if (rowActionGuidance) {
|
|
615
|
+
return rowActionGuidance;
|
|
616
|
+
}
|
|
601
617
|
const compiled = this.adapter.compileAiResponse?.(response);
|
|
602
618
|
if (!compiled && response.patch && Object.keys(response.patch).length > 0) {
|
|
603
619
|
return {
|
|
@@ -610,9 +626,17 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
610
626
|
};
|
|
611
627
|
}
|
|
612
628
|
if (!compiled) {
|
|
629
|
+
const continuedBulkRouteNarrative = this.bulkRouteActionPlanForNonExecutableNarrative(response, request);
|
|
630
|
+
if (continuedBulkRouteNarrative) {
|
|
631
|
+
return this.compileAdapterResponse(continuedBulkRouteNarrative, request);
|
|
632
|
+
}
|
|
613
633
|
return response;
|
|
614
634
|
}
|
|
615
635
|
if (compiled.type === 'error') {
|
|
636
|
+
const continuedBulkRouteAction = this.bulkRouteActionPlanForInvalidExecutable(response, request, compiled.warnings);
|
|
637
|
+
if (continuedBulkRouteAction) {
|
|
638
|
+
return this.compileAdapterResponse(continuedBulkRouteAction, request);
|
|
639
|
+
}
|
|
616
640
|
const continuedInvalidExecutable = this.selectedRecordSurfaceRuntimeOperationForInvalidExecutable(response, request, compiled.warnings);
|
|
617
641
|
if (continuedInvalidExecutable) {
|
|
618
642
|
return continuedInvalidExecutable.componentEditPlan
|
|
@@ -645,17 +669,253 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
645
669
|
if (implicitSelectedFilterClarification) {
|
|
646
670
|
return implicitSelectedFilterClarification;
|
|
647
671
|
}
|
|
672
|
+
const normalizedCompiled = this.normalizeBulkRouteSelectionPayload(compiled, request);
|
|
648
673
|
const warnings = [
|
|
649
674
|
...(response.warnings ?? []),
|
|
650
|
-
...(
|
|
675
|
+
...(normalizedCompiled.warnings ?? []),
|
|
651
676
|
];
|
|
652
677
|
return {
|
|
653
678
|
...response,
|
|
654
|
-
...
|
|
655
|
-
patch:
|
|
679
|
+
...normalizedCompiled,
|
|
680
|
+
patch: normalizedCompiled.patch,
|
|
656
681
|
warnings: warnings.length ? warnings : undefined,
|
|
657
682
|
};
|
|
658
683
|
}
|
|
684
|
+
normalizeBulkRouteSelectionPayload(compiled, request) {
|
|
685
|
+
if (!compiled?.patch || !request)
|
|
686
|
+
return compiled;
|
|
687
|
+
const text = this.normalizeLabel([
|
|
688
|
+
...(request.messages ?? [])
|
|
689
|
+
.filter((message) => message?.role === 'user')
|
|
690
|
+
.slice(-2)
|
|
691
|
+
.map((message) => message?.text ?? ''),
|
|
692
|
+
request.prompt ?? '',
|
|
693
|
+
].join(' '));
|
|
694
|
+
if (!this.textMentionsBulkActionRequest(text))
|
|
695
|
+
return compiled;
|
|
696
|
+
const routePath = this.extractRoutePath(text);
|
|
697
|
+
const patch = this.cloneJson(compiled.patch);
|
|
698
|
+
const componentEditPlan = compiled.componentEditPlan
|
|
699
|
+
? this.cloneJson(compiled.componentEditPlan)
|
|
700
|
+
: undefined;
|
|
701
|
+
const bulkActions = patch?.actions?.bulk?.actions;
|
|
702
|
+
let changed = false;
|
|
703
|
+
if (Array.isArray(bulkActions)) {
|
|
704
|
+
for (const action of bulkActions) {
|
|
705
|
+
if (!action || typeof action !== 'object')
|
|
706
|
+
continue;
|
|
707
|
+
if (this.ensureBulkRouteActionSelectionQuery(action, routePath)) {
|
|
708
|
+
changed = true;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
if (componentEditPlan && this.ensureBulkRouteActionSelectionQueryOnPlan(componentEditPlan, routePath)) {
|
|
713
|
+
changed = true;
|
|
714
|
+
}
|
|
715
|
+
if (!Array.isArray(bulkActions) && !componentEditPlan)
|
|
716
|
+
return compiled;
|
|
717
|
+
if (!changed)
|
|
718
|
+
return compiled;
|
|
719
|
+
return {
|
|
720
|
+
...compiled,
|
|
721
|
+
...(componentEditPlan ? { componentEditPlan } : {}),
|
|
722
|
+
patch,
|
|
723
|
+
warnings: [
|
|
724
|
+
...(compiled.warnings ?? []),
|
|
725
|
+
'bulk-route-action-selection-query-normalized',
|
|
726
|
+
],
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
ensureBulkRouteActionSelectionQueryOnPlan(plan, routePath) {
|
|
730
|
+
if (!plan || typeof plan !== 'object')
|
|
731
|
+
return false;
|
|
732
|
+
let changed = false;
|
|
733
|
+
for (const key of ['input', 'value']) {
|
|
734
|
+
if (this.ensureBulkRouteActionSelectionQuery(plan[key], routePath)) {
|
|
735
|
+
changed = true;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
if (Array.isArray(plan.operations)) {
|
|
739
|
+
for (const operation of plan.operations) {
|
|
740
|
+
if (!operation || typeof operation !== 'object')
|
|
741
|
+
continue;
|
|
742
|
+
for (const key of ['input', 'value']) {
|
|
743
|
+
if (this.ensureBulkRouteActionSelectionQuery(operation[key], routePath)) {
|
|
744
|
+
changed = true;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return changed;
|
|
750
|
+
}
|
|
751
|
+
ensureBulkRouteActionSelectionQuery(action, routePath) {
|
|
752
|
+
if (!action || typeof action !== 'object')
|
|
753
|
+
return false;
|
|
754
|
+
let changed = false;
|
|
755
|
+
if (this.ensureBulkRouteActionGlobalRouteRef(action, routePath)) {
|
|
756
|
+
changed = true;
|
|
757
|
+
}
|
|
758
|
+
if (this.ensureGlobalRouteActionSelectionQuery(action.globalAction)) {
|
|
759
|
+
changed = true;
|
|
760
|
+
}
|
|
761
|
+
if (Array.isArray(action.effects)) {
|
|
762
|
+
for (const effect of action.effects) {
|
|
763
|
+
if (effect?.kind === 'global-action' && this.ensureGlobalRouteActionSelectionQuery(effect.globalAction)) {
|
|
764
|
+
changed = true;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return changed;
|
|
769
|
+
}
|
|
770
|
+
ensureBulkRouteActionGlobalRouteRef(action, routePath) {
|
|
771
|
+
if (!routePath)
|
|
772
|
+
return false;
|
|
773
|
+
if (this.hasGlobalRouteActionRef(action))
|
|
774
|
+
return false;
|
|
775
|
+
const configuredAction = this.stringValue(action.action);
|
|
776
|
+
const looksLikeRouteAction = configuredAction === 'navigation.openRoute'
|
|
777
|
+
|| configuredAction === 'navigation.open route'
|
|
778
|
+
|| this.stringValue(action.globalAction?.actionId) === 'navigation.openRoute';
|
|
779
|
+
const hasRoutePayload = this.stringValue(action.payload?.path)
|
|
780
|
+
|| this.stringValue(action.globalAction?.payload?.path)
|
|
781
|
+
|| routePath;
|
|
782
|
+
if (!looksLikeRouteAction && !hasRoutePayload)
|
|
783
|
+
return false;
|
|
784
|
+
const globalAction = {
|
|
785
|
+
actionId: 'navigation.openRoute',
|
|
786
|
+
payload: {
|
|
787
|
+
path: this.stringValue(action.payload?.path)
|
|
788
|
+
|| this.stringValue(action.globalAction?.payload?.path)
|
|
789
|
+
|| routePath,
|
|
790
|
+
query: { ids: '${runtime.selectedIds}' },
|
|
791
|
+
},
|
|
792
|
+
};
|
|
793
|
+
action.globalAction = globalAction;
|
|
794
|
+
action.effects = [{ kind: 'global-action', globalAction }];
|
|
795
|
+
if (!this.stringValue(action.action)) {
|
|
796
|
+
action.action = 'navigation.openRoute';
|
|
797
|
+
}
|
|
798
|
+
return true;
|
|
799
|
+
}
|
|
800
|
+
hasGlobalRouteActionRef(action) {
|
|
801
|
+
if (this.stringValue(action?.globalAction?.actionId) === 'navigation.openRoute') {
|
|
802
|
+
return true;
|
|
803
|
+
}
|
|
804
|
+
if (!Array.isArray(action?.effects))
|
|
805
|
+
return false;
|
|
806
|
+
return action.effects.some((effect) => effect?.kind === 'global-action'
|
|
807
|
+
&& this.stringValue(effect.globalAction?.actionId) === 'navigation.openRoute');
|
|
808
|
+
}
|
|
809
|
+
ensureGlobalRouteActionSelectionQuery(globalAction) {
|
|
810
|
+
if (!globalAction || typeof globalAction !== 'object')
|
|
811
|
+
return false;
|
|
812
|
+
if (globalAction.actionId !== 'navigation.openRoute')
|
|
813
|
+
return false;
|
|
814
|
+
const payload = globalAction.payload;
|
|
815
|
+
if (!payload || typeof payload !== 'object')
|
|
816
|
+
return false;
|
|
817
|
+
if (!this.stringValue(payload.path))
|
|
818
|
+
return false;
|
|
819
|
+
if (!payload.query || typeof payload.query !== 'object' || Array.isArray(payload.query)) {
|
|
820
|
+
payload.query = {};
|
|
821
|
+
}
|
|
822
|
+
if (payload.query.ids !== undefined && payload.query.ids !== null && payload.query.ids !== '') {
|
|
823
|
+
return false;
|
|
824
|
+
}
|
|
825
|
+
payload.query.ids = '${runtime.selectedIds}';
|
|
826
|
+
return true;
|
|
827
|
+
}
|
|
828
|
+
recordSurfaceRowActionGuidanceForConsult(response, request) {
|
|
829
|
+
if (!request || !this.promptAsksRowActionCapabilities(request))
|
|
830
|
+
return null;
|
|
831
|
+
if (!this.responseCarriesRowActionAddPlan(response))
|
|
832
|
+
return null;
|
|
833
|
+
const surfaces = this.selectedRecordSurfaces(this.contextHintsFor(request));
|
|
834
|
+
if (!surfaces.length)
|
|
835
|
+
return null;
|
|
836
|
+
const labels = [...new Set(surfaces
|
|
837
|
+
.map((surface) => {
|
|
838
|
+
const resourceSurface = this.toRecord(surface['resourceSurface']);
|
|
839
|
+
return this.stringValue(surface['label'])
|
|
840
|
+
|| this.stringValue(resourceSurface?.['title'])
|
|
841
|
+
|| this.stringValue(surface['id']);
|
|
842
|
+
})
|
|
843
|
+
.filter((label) => !!label))];
|
|
844
|
+
if (!labels.length)
|
|
845
|
+
return null;
|
|
846
|
+
return {
|
|
847
|
+
type: 'info',
|
|
848
|
+
message: [
|
|
849
|
+
'Você pode adicionar botões de linha para superfícies relacionadas declaradas para este recurso.',
|
|
850
|
+
`Opções disponíveis agora: ${labels.map((label) => `**${label}**`).join(', ')}.`,
|
|
851
|
+
'Quando quiser materializar uma delas, peça algo como "adicione um botão na linha para abrir Histórico de folha".',
|
|
852
|
+
].join(' '),
|
|
853
|
+
warnings: [
|
|
854
|
+
'row-action-capability-question-preserved-as-consult',
|
|
855
|
+
'Residual consult guard acted only after the LLM proposed rowAction.add for a row-action capability-discovery question while declared recordSurfaces were available.',
|
|
856
|
+
],
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
promptAsksRowActionCapabilities(request) {
|
|
860
|
+
const currentPrompt = this.normalizeLabel(request.prompt ?? '');
|
|
861
|
+
const recentUserContext = this.normalizeLabel((request.messages ?? [])
|
|
862
|
+
.filter((message) => message?.role === 'user')
|
|
863
|
+
.slice(-2)
|
|
864
|
+
.map((message) => message?.text ?? '')
|
|
865
|
+
.join(' '));
|
|
866
|
+
const text = [recentUserContext, currentPrompt].filter(Boolean).join(' ');
|
|
867
|
+
if (!this.textMentionsRowActionRequest(text))
|
|
868
|
+
return false;
|
|
869
|
+
const asksAvailability = [
|
|
870
|
+
'quais',
|
|
871
|
+
'qual',
|
|
872
|
+
'o que',
|
|
873
|
+
'que botoes',
|
|
874
|
+
'que botões',
|
|
875
|
+
'botoes posso',
|
|
876
|
+
'botões posso',
|
|
877
|
+
'acoes disponiveis',
|
|
878
|
+
'ações disponíveis',
|
|
879
|
+
'acoes estao disponiveis',
|
|
880
|
+
'ações estão disponíveis',
|
|
881
|
+
'posso adicionar',
|
|
882
|
+
'can i add',
|
|
883
|
+
'available',
|
|
884
|
+
'what actions',
|
|
885
|
+
'which actions',
|
|
886
|
+
'which buttons',
|
|
887
|
+
].some((needle) => text.includes(this.normalizeLabel(needle)));
|
|
888
|
+
if (!asksAvailability)
|
|
889
|
+
return false;
|
|
890
|
+
const explicitMaterialization = [
|
|
891
|
+
'adicione',
|
|
892
|
+
'adicionar agora',
|
|
893
|
+
'crie',
|
|
894
|
+
'criar agora',
|
|
895
|
+
'coloque',
|
|
896
|
+
'aplique',
|
|
897
|
+
'materialize',
|
|
898
|
+
'create a',
|
|
899
|
+
'add a',
|
|
900
|
+
].some((needle) => currentPrompt.includes(this.normalizeLabel(needle)));
|
|
901
|
+
return !explicitMaterialization;
|
|
902
|
+
}
|
|
903
|
+
responseCarriesRowActionAddPlan(response) {
|
|
904
|
+
const record = response;
|
|
905
|
+
return [
|
|
906
|
+
this.toRecord(record['componentEditPlan']),
|
|
907
|
+
this.toRecord(this.toRecord(record['patch'])?.['componentEditPlan']),
|
|
908
|
+
this.toRecord(record['tableEditPlan']),
|
|
909
|
+
this.toRecord(record['editPlan']),
|
|
910
|
+
].some((plan) => {
|
|
911
|
+
if (!plan)
|
|
912
|
+
return false;
|
|
913
|
+
if (this.stringValue(plan['operationId']) === 'rowAction.add')
|
|
914
|
+
return true;
|
|
915
|
+
const operations = Array.isArray(plan['operations']) ? plan['operations'] : [];
|
|
916
|
+
return operations.some((operation) => this.stringValue(this.toRecord(operation)?.['operationId']) === 'rowAction.add');
|
|
917
|
+
});
|
|
918
|
+
}
|
|
659
919
|
responseCarriesClarificationChoices(response) {
|
|
660
920
|
if (response.type !== 'clarification')
|
|
661
921
|
return false;
|
|
@@ -936,7 +1196,7 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
936
1196
|
...(request.messages ?? []).slice(-8).map((message) => message?.text ?? ''),
|
|
937
1197
|
request.prompt ?? '',
|
|
938
1198
|
].join(' '));
|
|
939
|
-
if (!this.textMentionsRowActionRequest(normalizedPrompt
|
|
1199
|
+
if (!this.textMentionsRowActionRequest(`${normalizedPrompt} ${normalizedConversation}`)) {
|
|
940
1200
|
return null;
|
|
941
1201
|
}
|
|
942
1202
|
const clarificationKind = this.selectedRecordSurfaceRowActionClarificationKind(response);
|
|
@@ -956,11 +1216,19 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
956
1216
|
if (!ranked.length || (ranked.length > 1 && ranked[0].score === ranked[1].score)) {
|
|
957
1217
|
return null;
|
|
958
1218
|
}
|
|
959
|
-
const
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1219
|
+
const hasSelectedRecords = this.selectedRecordsCountForTurn > 0;
|
|
1220
|
+
const source = hasSelectedRecords
|
|
1221
|
+
? 'selected-record-surface-row-action-continued-from-clarification'
|
|
1222
|
+
: 'record-surface-row-action-continued-from-clarification';
|
|
1223
|
+
const warning = hasSelectedRecords
|
|
1224
|
+
? (clarificationKind === 'technical'
|
|
1225
|
+
? 'selected-record-surface-row-action-continued-from-technical-clarification'
|
|
1226
|
+
: 'selected-record-surface-row-action-continued-from-generic-clarification')
|
|
1227
|
+
: 'record-surface-row-action-continued-from-clarification';
|
|
1228
|
+
const warningDetail = clarificationKind === 'technical'
|
|
1229
|
+
? `Residual continuity guard acted only after LLM asked for technical row-action details while declared recordSurfaces${hasSelectedRecords ? ' and conversation history' : ''} already grounded the target surface.`
|
|
1230
|
+
: 'Residual continuity guard acted only after LLM asked a generic dataset/listing clarification while declared recordSurfaces and a row-action request already grounded the target surface.';
|
|
1231
|
+
const rowActionResponse = this.buildSelectedRecordSurfaceRowActionResponse(ranked[0].surface, source, warning, warningDetail);
|
|
964
1232
|
if (!rowActionResponse)
|
|
965
1233
|
return null;
|
|
966
1234
|
// Residual continuity guard: this runs only after the LLM returned a
|
|
@@ -978,7 +1246,7 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
978
1246
|
...(request.messages ?? []).slice(-8).map((message) => message?.text ?? ''),
|
|
979
1247
|
request.prompt ?? '',
|
|
980
1248
|
].join(' '));
|
|
981
|
-
if (!this.textMentionsRowActionRequest(normalizedPrompt
|
|
1249
|
+
if (!this.textMentionsRowActionRequest(`${normalizedPrompt} ${normalizedConversation}`)) {
|
|
982
1250
|
return null;
|
|
983
1251
|
}
|
|
984
1252
|
const responseText = this.normalizeLabel([
|
|
@@ -1073,9 +1341,14 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
1073
1341
|
if (!request || !this.responseMayContainExecutableEnvelope(response))
|
|
1074
1342
|
return null;
|
|
1075
1343
|
const normalizedPrompt = this.normalizeLabel(request.prompt ?? '');
|
|
1076
|
-
|
|
1344
|
+
const normalizedConversation = this.normalizeLabel([
|
|
1345
|
+
...(request.messages ?? []).slice(-8).map((message) => message?.text ?? ''),
|
|
1346
|
+
request.prompt ?? '',
|
|
1347
|
+
].join(' '));
|
|
1348
|
+
const requestText = `${normalizedPrompt} ${normalizedConversation}`;
|
|
1349
|
+
if (!this.textMentionsRecordSurfaceOpenRequest(requestText))
|
|
1077
1350
|
return null;
|
|
1078
|
-
if (this.promptRequestsSimilarRecords(
|
|
1351
|
+
if (this.promptRequestsSimilarRecords(requestText))
|
|
1079
1352
|
return null;
|
|
1080
1353
|
const contextHints = this.contextHintsFor(request);
|
|
1081
1354
|
const surfaces = this.selectedRecordSurfaces(contextHints);
|
|
@@ -1091,14 +1364,14 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
1091
1364
|
const ranked = surfaces
|
|
1092
1365
|
.map((surface) => ({
|
|
1093
1366
|
surface,
|
|
1094
|
-
score: this.selectedRecordSurfacePromptScore(`${
|
|
1367
|
+
score: this.selectedRecordSurfacePromptScore(`${requestText} ${responseEvidence}`, surface),
|
|
1095
1368
|
}))
|
|
1096
1369
|
.filter((entry) => entry.score >= 2)
|
|
1097
1370
|
.sort((left, right) => right.score - left.score);
|
|
1098
1371
|
if (!ranked.length || (ranked.length > 1 && ranked[0].score === ranked[1].score)) {
|
|
1099
1372
|
return null;
|
|
1100
1373
|
}
|
|
1101
|
-
if (this.textMentionsRowActionRequest(
|
|
1374
|
+
if (this.textMentionsRowActionRequest(requestText)) {
|
|
1102
1375
|
const rowActionResponse = this.buildSelectedRecordSurfaceRowActionResponse(ranked[0].surface, 'selected-record-surface-row-action-invalid-executable-continuity-guard', 'selected-record-surface-row-action-continued-from-invalid-executable', 'Residual continuity guard acted only after LLM emitted an executable envelope that failed table component capability validation for a row-action request while a declared recordSurface uniquely matched the selected-record request.');
|
|
1103
1376
|
if (rowActionResponse)
|
|
1104
1377
|
return rowActionResponse;
|
|
@@ -1173,6 +1446,116 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
1173
1446
|
warnings: [warning, warningDetail],
|
|
1174
1447
|
};
|
|
1175
1448
|
}
|
|
1449
|
+
bulkRouteActionPlanForClarification(response, request) {
|
|
1450
|
+
if (response.type !== 'clarification' || !request)
|
|
1451
|
+
return null;
|
|
1452
|
+
const normalizedPrompt = this.normalizeLabel(request.prompt ?? '');
|
|
1453
|
+
if (!this.textMentionsBulkActionRequest(normalizedPrompt))
|
|
1454
|
+
return null;
|
|
1455
|
+
if (!this.textMentionsRecordSurfaceOpenRequest(normalizedPrompt))
|
|
1456
|
+
return null;
|
|
1457
|
+
const routePath = this.extractRoutePath(request.prompt ?? '');
|
|
1458
|
+
if (!routePath)
|
|
1459
|
+
return null;
|
|
1460
|
+
const clarificationKind = this.globalActionClarificationKind(response);
|
|
1461
|
+
if (!clarificationKind)
|
|
1462
|
+
return null;
|
|
1463
|
+
return this.buildBulkRouteActionPlan(routePath, 'bulk-route-action-continued-from-clarification', [
|
|
1464
|
+
'bulk-route-action-continued-from-technical-clarification',
|
|
1465
|
+
'Residual continuity guard acted only after LLM asked for technical bulk route details while a route path and selected-record bulk action intent were already grounded.',
|
|
1466
|
+
]);
|
|
1467
|
+
}
|
|
1468
|
+
bulkRouteActionPlanForInvalidExecutable(response, request, validationWarnings = []) {
|
|
1469
|
+
if (!request)
|
|
1470
|
+
return null;
|
|
1471
|
+
if (!response.componentEditPlan && !response.patch)
|
|
1472
|
+
return null;
|
|
1473
|
+
const normalizedPrompt = this.normalizeLabel(request.prompt ?? '');
|
|
1474
|
+
if (!this.textMentionsBulkActionRequest(normalizedPrompt))
|
|
1475
|
+
return null;
|
|
1476
|
+
if (!this.textMentionsRecordSurfaceOpenRequest(normalizedPrompt))
|
|
1477
|
+
return null;
|
|
1478
|
+
const routePath = this.extractRoutePath(request.prompt ?? '');
|
|
1479
|
+
if (!routePath)
|
|
1480
|
+
return null;
|
|
1481
|
+
return this.buildBulkRouteActionPlan(routePath, 'bulk-route-action-continued-from-invalid-executable', [
|
|
1482
|
+
...validationWarnings,
|
|
1483
|
+
'bulk-route-action-continued-from-invalid-executable',
|
|
1484
|
+
'Residual continuity guard acted only after LLM proposed an invalid executable table plan while route path and selected-record bulk action intent were already grounded.',
|
|
1485
|
+
]);
|
|
1486
|
+
}
|
|
1487
|
+
bulkRouteActionPlanForNonExecutableNarrative(response, request) {
|
|
1488
|
+
if (!request)
|
|
1489
|
+
return null;
|
|
1490
|
+
const normalizedPrompt = this.normalizeLabel(request.prompt ?? '');
|
|
1491
|
+
if (!this.textMentionsBulkActionRequest(normalizedPrompt))
|
|
1492
|
+
return null;
|
|
1493
|
+
if (!this.textMentionsRecordSurfaceOpenRequest(normalizedPrompt))
|
|
1494
|
+
return null;
|
|
1495
|
+
const routePath = this.extractRoutePath(request.prompt ?? '');
|
|
1496
|
+
if (!routePath)
|
|
1497
|
+
return null;
|
|
1498
|
+
const narrative = this.normalizeLabel([
|
|
1499
|
+
response.message ?? '',
|
|
1500
|
+
response.explanation ?? '',
|
|
1501
|
+
...(response.warnings ?? []),
|
|
1502
|
+
].join(' '));
|
|
1503
|
+
const hasCanonicalDecision = this.normalizedTextIncludesAny(narrative, ['componentEditPlan', 'component edit plan'])
|
|
1504
|
+
&& this.normalizedTextIncludesAny(narrative, ['bulkAction.add', 'bulk action.add'])
|
|
1505
|
+
&& this.normalizedTextIncludesAny(narrative, ['navigation.openRoute', 'navigation.open route'])
|
|
1506
|
+
&& this.normalizedTextIncludesAny(narrative, ['selectedIds', 'selected ids', 'runtime.selectedIds']);
|
|
1507
|
+
if (!hasCanonicalDecision)
|
|
1508
|
+
return null;
|
|
1509
|
+
return this.buildBulkRouteActionPlan(routePath, 'bulk-route-action-continued-from-non-executable-narrative', [
|
|
1510
|
+
'bulk-route-action-continued-from-non-executable-narrative',
|
|
1511
|
+
'Residual continuity guard acted only after LLM described the canonical bulkAction.add/navigation.openRoute decision without returning an executable componentEditPlan envelope.',
|
|
1512
|
+
]);
|
|
1513
|
+
}
|
|
1514
|
+
buildBulkRouteActionPlan(routePath, source, warnings) {
|
|
1515
|
+
const actionId = `open-${this.slugifyActionId(routePath)}-selected`;
|
|
1516
|
+
const label = this.humanizeBulkRouteActionLabel(routePath);
|
|
1517
|
+
const globalAction = {
|
|
1518
|
+
actionId: 'navigation.openRoute',
|
|
1519
|
+
payload: {
|
|
1520
|
+
path: routePath,
|
|
1521
|
+
query: { ids: '${runtime.selectedIds}' },
|
|
1522
|
+
},
|
|
1523
|
+
};
|
|
1524
|
+
const bulkAction = {
|
|
1525
|
+
id: actionId,
|
|
1526
|
+
label,
|
|
1527
|
+
action: 'navigation.openRoute',
|
|
1528
|
+
icon: 'route',
|
|
1529
|
+
globalAction,
|
|
1530
|
+
effects: [
|
|
1531
|
+
{
|
|
1532
|
+
kind: 'global-action',
|
|
1533
|
+
globalAction,
|
|
1534
|
+
},
|
|
1535
|
+
],
|
|
1536
|
+
};
|
|
1537
|
+
// Residual continuity guard: this executes only after the LLM already
|
|
1538
|
+
// resolved the turn as a clarification, while the user-provided route path
|
|
1539
|
+
// and the declared bulkAction.add/globalAction contract are sufficient to
|
|
1540
|
+
// materialize the operation. It grounds payload details in canonical runtime
|
|
1541
|
+
// selection templates instead of using local text as primary intent routing.
|
|
1542
|
+
return {
|
|
1543
|
+
type: 'patch',
|
|
1544
|
+
componentEditPlan: {
|
|
1545
|
+
kind: 'praxis.table.component-edit-plan',
|
|
1546
|
+
version: '1.0',
|
|
1547
|
+
componentId: 'praxis-table',
|
|
1548
|
+
operationId: 'bulkAction.add',
|
|
1549
|
+
changeKind: 'add_bulk_action',
|
|
1550
|
+
capabilityPath: 'actions.bulk.actions[]',
|
|
1551
|
+
input: bulkAction,
|
|
1552
|
+
value: bulkAction,
|
|
1553
|
+
source,
|
|
1554
|
+
},
|
|
1555
|
+
explanation: `Vou adicionar a ação ${label} para os registros selecionados.`,
|
|
1556
|
+
warnings,
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1176
1559
|
selectedRecordSurfaceRowActionClarificationKind(response) {
|
|
1177
1560
|
const text = this.normalizeLabel([
|
|
1178
1561
|
response.message ?? '',
|
|
@@ -1186,6 +1569,30 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
1186
1569
|
'mais detalhes sobre surface',
|
|
1187
1570
|
'mais detalhes sobre button',
|
|
1188
1571
|
'mais detalhes sobre placement',
|
|
1572
|
+
'mais detalhes sobre openmode',
|
|
1573
|
+
'mais detalhes sobre open mode',
|
|
1574
|
+
'mais detalhes sobre iconorstyle',
|
|
1575
|
+
'mais detalhes sobre appliesto',
|
|
1576
|
+
'mais detalhes sobre actionlabel',
|
|
1577
|
+
'mais detalhes sobre openbehavior',
|
|
1578
|
+
'mais detalhes sobre actionbehavior',
|
|
1579
|
+
'mais detalhes sobre destinationsurface',
|
|
1580
|
+
'mais detalhes sobre iconlabel',
|
|
1581
|
+
'qual condicao deve ser usada',
|
|
1582
|
+
'qual condição deve ser usada',
|
|
1583
|
+
'mais detalhes sobre action behavior',
|
|
1584
|
+
'o alvo do ajuste',
|
|
1585
|
+
'nome que voce prefere',
|
|
1586
|
+
'nome que você prefere',
|
|
1587
|
+
'openmode',
|
|
1588
|
+
'open mode',
|
|
1589
|
+
'iconorstyle',
|
|
1590
|
+
'appliesto',
|
|
1591
|
+
'actionlabel',
|
|
1592
|
+
'openbehavior',
|
|
1593
|
+
'actionbehavior',
|
|
1594
|
+
'destinationsurface',
|
|
1595
|
+
'iconlabel',
|
|
1189
1596
|
].some((needle) => text.includes(needle))) {
|
|
1190
1597
|
return 'technical';
|
|
1191
1598
|
}
|
|
@@ -1202,16 +1609,68 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
1202
1609
|
}
|
|
1203
1610
|
return null;
|
|
1204
1611
|
}
|
|
1612
|
+
globalActionClarificationKind(response) {
|
|
1613
|
+
const text = this.normalizeLabel([
|
|
1614
|
+
response.message ?? '',
|
|
1615
|
+
response.explanation ?? '',
|
|
1616
|
+
...(response.questions ?? []),
|
|
1617
|
+
].join(' '));
|
|
1618
|
+
if ([
|
|
1619
|
+
'recordidparamname',
|
|
1620
|
+
'record id param name',
|
|
1621
|
+
'o alvo do ajuste',
|
|
1622
|
+
'qual formato aplicar',
|
|
1623
|
+
'mais detalhes sobre target',
|
|
1624
|
+
'mais detalhes sobre payload',
|
|
1625
|
+
'mais detalhes sobre route',
|
|
1626
|
+
'mais detalhes sobre openmode',
|
|
1627
|
+
'mais detalhes sobre open mode',
|
|
1628
|
+
].some((needle) => text.includes(this.normalizeLabel(needle)))) {
|
|
1629
|
+
return 'technical';
|
|
1630
|
+
}
|
|
1631
|
+
return null;
|
|
1632
|
+
}
|
|
1205
1633
|
textMentionsRowActionRequest(normalizedText) {
|
|
1206
1634
|
return [
|
|
1207
1635
|
'botao',
|
|
1208
1636
|
'acao de linha',
|
|
1209
1637
|
'acoes de linha',
|
|
1638
|
+
'acao por registro',
|
|
1639
|
+
'acoes por registro',
|
|
1210
1640
|
'nas linhas',
|
|
1211
1641
|
'por linha',
|
|
1212
1642
|
'em cada linha',
|
|
1213
1643
|
].some((needle) => normalizedText.includes(needle));
|
|
1214
1644
|
}
|
|
1645
|
+
textMentionsBulkActionRequest(normalizedText) {
|
|
1646
|
+
return [
|
|
1647
|
+
'acao em lote',
|
|
1648
|
+
'acoes em lote',
|
|
1649
|
+
'registros selecionados',
|
|
1650
|
+
'linhas selecionadas',
|
|
1651
|
+
'selecionados',
|
|
1652
|
+
'bulk action',
|
|
1653
|
+
].some((needle) => normalizedText.includes(this.normalizeLabel(needle)));
|
|
1654
|
+
}
|
|
1655
|
+
normalizedTextIncludesAny(normalizedText, needles) {
|
|
1656
|
+
return needles.some((needle) => normalizedText.includes(this.normalizeLabel(needle)));
|
|
1657
|
+
}
|
|
1658
|
+
extractRoutePath(text) {
|
|
1659
|
+
const match = String(text || '').match(/(?:^|\s)(\/[A-Za-z0-9._~:/?#[\]@!$&'()*+,;=%-]+)(?=$|\s|[,.])/u);
|
|
1660
|
+
return match?.[1]?.replace(/[,.]$/u, '') ?? '';
|
|
1661
|
+
}
|
|
1662
|
+
humanizeBulkRouteActionLabel(path) {
|
|
1663
|
+
const segments = path
|
|
1664
|
+
.split(/[?#]/u)[0]
|
|
1665
|
+
.split('/')
|
|
1666
|
+
.map((segment) => segment.trim())
|
|
1667
|
+
.filter(Boolean);
|
|
1668
|
+
const lastSegments = segments.slice(-2);
|
|
1669
|
+
const label = lastSegments
|
|
1670
|
+
.map((segment) => this.humanizeField(segment))
|
|
1671
|
+
.join(' - ');
|
|
1672
|
+
return label ? `Abrir ${label}` : 'Abrir rota dos selecionados';
|
|
1673
|
+
}
|
|
1215
1674
|
textMentionsRecordSurfaceOpenRequest(normalizedText) {
|
|
1216
1675
|
return [
|
|
1217
1676
|
'abrir',
|
|
@@ -2031,6 +2490,9 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
2031
2490
|
case 'rowAction.add':
|
|
2032
2491
|
case 'add_row_action':
|
|
2033
2492
|
return `Vou criar um botao em cada linha para abrir **${this.stringValue(input['label']) || this.stringValue(input['id']) || 'a opcao solicitada'}**.`;
|
|
2493
|
+
case 'bulkAction.add':
|
|
2494
|
+
case 'add_bulk_action':
|
|
2495
|
+
return `Vou adicionar a acao **${this.stringValue(input['label']) || this.stringValue(input['id']) || 'solicitada'}** para os registros selecionados.`;
|
|
2034
2496
|
case 'export.configure':
|
|
2035
2497
|
return this.describeExportConfigure(input);
|
|
2036
2498
|
case 'appearance.density.set':
|
|
@@ -3056,6 +3518,14 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
3056
3518
|
return {};
|
|
3057
3519
|
}
|
|
3058
3520
|
}
|
|
3521
|
+
cloneJson(value) {
|
|
3522
|
+
try {
|
|
3523
|
+
return JSON.parse(JSON.stringify(value));
|
|
3524
|
+
}
|
|
3525
|
+
catch {
|
|
3526
|
+
return value;
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3059
3529
|
toRecord(value) {
|
|
3060
3530
|
return value && typeof value === 'object' && !Array.isArray(value)
|
|
3061
3531
|
? value
|