@praxisui/page-builder 8.0.0-beta.27 → 8.0.0-beta.29

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.
@@ -25,7 +25,7 @@ import * as i6$1 from '@angular/material/divider';
25
25
  import { MatDividerModule } from '@angular/material/divider';
26
26
  import * as i6$2 from '@angular/material/select';
27
27
  import { MatSelectModule } from '@angular/material/select';
28
- import { BehaviorSubject, merge, timeout, map, switchMap, Observable, firstValueFrom, from, concatMap, catchError, of, lastValueFrom } from 'rxjs';
28
+ import { BehaviorSubject, merge, timeout, map, switchMap, Observable, from, firstValueFrom, concatMap, catchError, of, filter, take } from 'rxjs';
29
29
  import { SETTINGS_PANEL_DATA } from '@praxisui/settings-panel';
30
30
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
31
31
  import * as i7 from '@angular/material/tabs';
@@ -2401,13 +2401,14 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2401
2401
  'praxis.pageBuilder.agentic.panelAria': 'AI page authoring',
2402
2402
  'praxis.pageBuilder.agentic.title': 'Praxis semantic copilot',
2403
2403
  'praxis.pageBuilder.agentic.subtitle': 'Author governed decisions with previews, confirmation, and runtime materialization.',
2404
- 'praxis.pageBuilder.agentic.header.title.page': 'Praxis page copilot',
2404
+ 'praxis.pageBuilder.agentic.header.title.page': 'Praxis page decision copilot',
2405
2405
  'praxis.pageBuilder.agentic.header.title.widget': 'Praxis widget copilot',
2406
2406
  'praxis.pageBuilder.agentic.header.title.review': 'Praxis review copilot',
2407
2407
  'praxis.pageBuilder.agentic.header.title.governed': 'Praxis governed copilot',
2408
- 'praxis.pageBuilder.agentic.header.subtitle.page': 'Author page-level layout, widgets and governed materialization.',
2408
+ 'praxis.pageBuilder.agentic.header.subtitle.page': 'Turn intent into layout, widgets, and governed materializations.',
2409
2409
  'praxis.pageBuilder.agentic.header.subtitle.route': 'Authoring page route {route}.',
2410
2410
  'praxis.pageBuilder.agentic.header.subtitle.widget': 'Focused on {target}.',
2411
+ 'praxis.pageBuilder.agentic.header.subtitle.reviewBlocked': 'Preview ready for governed review.',
2411
2412
  'praxis.pageBuilder.agentic.header.subtitle.review': 'Preview ready for review and persistence.',
2412
2413
  'praxis.pageBuilder.agentic.header.subtitle.governed': 'Continue the governed semantic-decision flow.',
2413
2414
  'praxis.pageBuilder.agentic.header.mode.page': 'Page',
@@ -2429,7 +2430,9 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2429
2430
  'praxis.pageBuilder.agentic.dock.summaryIdle': 'Conversation preserved. Continue where you stopped.',
2430
2431
  'praxis.pageBuilder.agentic.promptLabel': 'Message',
2431
2432
  'praxis.pageBuilder.agentic.promptPlaceholder': 'Describe the page, dashboard, form, or change you need.',
2432
- 'praxis.pageBuilder.agentic.emptyConversation': 'Tell me what you want to create or change. I will ask follow-up questions before applying the preview.',
2433
+ 'praxis.pageBuilder.agentic.emptyConversation': 'Describe the outcome you want. I will ground the context, prepare a governed preview, and wait for review before applying anything.',
2434
+ 'praxis.pageBuilder.agentic.emptyConversation.blankGeneric': 'This host page is still blank. Tell me what decision or activity this app needs to support. I can suggest a dashboard, table, form, or review flow, then turn it into a governed preview for you to review before anything changes.',
2435
+ 'praxis.pageBuilder.agentic.emptyConversation.existingPage': 'Tell me what you want to improve here. I can read the current layout, widgets, route, and governed context, then prepare a preview for you to review before anything changes.',
2433
2436
  'praxis.pageBuilder.agentic.conversationAria': 'AI conversation',
2434
2437
  'praxis.pageBuilder.agentic.quickRepliesAria': 'Quick replies',
2435
2438
  'praxis.pageBuilder.agentic.contextAria': 'Active context',
@@ -2445,6 +2448,23 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2445
2448
  'praxis.pageBuilder.agentic.context.governedDomainContextRequest': 'Requested context',
2446
2449
  'praxis.pageBuilder.agentic.context.governedDomainContextSize': 'Grounding size',
2447
2450
  'praxis.pageBuilder.agentic.context.sharedRuleTargetLayer': 'Target materialization',
2451
+ 'praxis.pageBuilder.agentic.context.semanticDecisionResource': 'Source',
2452
+ 'praxis.pageBuilder.agentic.context.semanticDecisionKind': 'Goal',
2453
+ 'praxis.pageBuilder.agentic.context.semanticDecisionEvidence': 'Review',
2454
+ 'praxis.pageBuilder.agentic.context.operationCreate': 'Create',
2455
+ 'praxis.pageBuilder.agentic.context.operationUpdate': 'Adjust',
2456
+ 'praxis.pageBuilder.agentic.context.operationRead': 'Explore',
2457
+ 'praxis.pageBuilder.agentic.context.artifactDashboard': 'dashboard',
2458
+ 'praxis.pageBuilder.agentic.context.artifactTable': 'table',
2459
+ 'praxis.pageBuilder.agentic.context.artifactForm': 'form',
2460
+ 'praxis.pageBuilder.agentic.context.artifactPage': 'screen',
2461
+ 'praxis.pageBuilder.agentic.context.changeAnalytics': 'with analysis',
2462
+ 'praxis.pageBuilder.agentic.context.changeDashboard': 'with dashboard view',
2463
+ 'praxis.pageBuilder.agentic.context.changeTable': 'with details',
2464
+ 'praxis.pageBuilder.agentic.context.changeForm': 'with editing',
2465
+ 'praxis.pageBuilder.agentic.context.evidenceReviewRequired': 'Needs field review',
2466
+ 'praxis.pageBuilder.agentic.context.evidenceLowConfidence': 'Needs source confirmation',
2467
+ 'praxis.pageBuilder.agentic.context.evidenceGrounded': 'Source confirmed',
2448
2468
  'praxis.pageBuilder.agentic.editMessage': 'Edit',
2449
2469
  'praxis.pageBuilder.agentic.resendMessage': 'Resend',
2450
2470
  'praxis.pageBuilder.agentic.removeAttachment': 'Remove attachment',
@@ -2454,7 +2474,7 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2454
2474
  'praxis.pageBuilder.agentic.mode.diagnostic': 'Diagnostic',
2455
2475
  'praxis.pageBuilder.agentic.mode.review': 'Review',
2456
2476
  'praxis.pageBuilder.agentic.mode.inlineHelp': 'Help',
2457
- 'praxis.pageBuilder.agentic.state.idle': 'Idle',
2477
+ 'praxis.pageBuilder.agentic.state.idle': 'Ready',
2458
2478
  'praxis.pageBuilder.agentic.state.listening': 'Ready',
2459
2479
  'praxis.pageBuilder.agentic.state.processing': 'Processing',
2460
2480
  'praxis.pageBuilder.agentic.state.clarification': 'Waiting for input',
@@ -2486,9 +2506,16 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2486
2506
  'praxis.pageBuilder.agentic.exploratory.capability.table': 'tables',
2487
2507
  'praxis.pageBuilder.agentic.exploratory.capability.form': 'forms',
2488
2508
  'praxis.pageBuilder.agentic.exploratory.capability.masterDetail': 'master-detail pages',
2489
- 'praxis.pageBuilder.agentic.resourceDiscovery.found': 'I found APIs that can feed this screen. Choose one before generating the preview.',
2509
+ 'praxis.pageBuilder.agentic.resourceDiscovery.found': 'I found {sourceCount} for this screen. I recommend starting with {first} because it is the best fit for charts, KPIs, and drill-down. Review the cards below to see what each source is good for, what it returns, and what I will create after you select it.',
2510
+ 'praxis.pageBuilder.agentic.resourceDiscovery.sourceCountSingular': '1 candidate source',
2511
+ 'praxis.pageBuilder.agentic.resourceDiscovery.sourceCountPlural': '{count} candidate sources',
2490
2512
  'praxis.pageBuilder.agentic.resourceDiscovery.empty': 'I did not find a matching API yet. Describe the business data this screen should use.',
2491
2513
  'praxis.pageBuilder.agentic.resourceDiscovery.useResource': 'Use {resourcePath}',
2514
+ 'praxis.pageBuilder.agentic.resourceDiscovery.defaultRecommendedLabel': 'the first option',
2515
+ 'praxis.pageBuilder.agentic.resourceDiscovery.cardDescription': 'Recommended source for turning {label} into a dashboard: helps choose charts, lists, filters, and formats before materializing the screen.',
2516
+ 'praxis.pageBuilder.agentic.resourceDiscovery.cardBestFor': 'Use when you want to understand whether {label} answers the business goal before creating widgets.',
2517
+ 'praxis.pageBuilder.agentic.resourceDiscovery.cardReturns': 'Suggests metrics, dimensions, filters, value formats, charts, and detail lists compatible with the source.',
2518
+ 'praxis.pageBuilder.agentic.resourceDiscovery.cardNextStep': 'Select it so I can propose a governed preview with rich cards, drill-down, and sensible default formats.',
2492
2519
  'praxis.pageBuilder.agentic.diagnostics.title': 'LLM diagnostics',
2493
2520
  'praxis.pageBuilder.agentic.diagnostics.badge': 'Debug',
2494
2521
  'praxis.pageBuilder.agentic.diagnostics.description': 'Prompt, context bundle, and tool catalog returned by the backend for this turn.',
@@ -2510,10 +2537,12 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2510
2537
  'praxis.pageBuilder.agentic.status.refinedCandidates': 'Reviewing the retrieved resources with the AI...',
2511
2538
  'praxis.pageBuilder.agentic.status.projectKnowledgeRetrieved': 'Retrieved governed project knowledge for this authoring turn.',
2512
2539
  'praxis.pageBuilder.agentic.status.projectKnowledgeRetrievedCount': 'Retrieved {count} governed project knowledge signals for this authoring turn.',
2513
- 'praxis.pageBuilder.agentic.status.projectKnowledgeAuditCited': '{cited} of {count} governed project knowledge signals were cited in sourceRefs.',
2540
+ 'praxis.pageBuilder.agentic.status.projectKnowledgeAuditCited': 'Governed knowledge cited: {cited} of {count}.',
2514
2541
  'praxis.pageBuilder.agentic.status.previewing': 'Generating preview...',
2515
2542
  'praxis.pageBuilder.agentic.status.previewCompile': 'Compiling preview...',
2516
2543
  'praxis.pageBuilder.agentic.status.previewReady': 'Preview applied to the page.',
2544
+ 'praxis.pageBuilder.agentic.status.reviewReady': 'Ready for review.',
2545
+ 'praxis.pageBuilder.agentic.status.reviewNeedsAttention': 'Review the pending points before saving.',
2517
2546
  'praxis.pageBuilder.agentic.status.acceptedAddLocalField': 'Local field added to the form.',
2518
2547
  'praxis.pageBuilder.agentic.status.acceptedRemoveLocalField': 'Local field removed from the form.',
2519
2548
  'praxis.pageBuilder.agentic.status.acceptedRelabelField': 'Field label updated.',
@@ -2820,9 +2849,10 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
2820
2849
  'praxis.pageBuilder.agentic.header.title.widget': 'Copiloto de componente Praxis',
2821
2850
  'praxis.pageBuilder.agentic.header.title.review': 'Copiloto de revisão Praxis',
2822
2851
  'praxis.pageBuilder.agentic.header.title.governed': 'Copiloto governado Praxis',
2823
- 'praxis.pageBuilder.agentic.header.subtitle.page': 'Autore layout, widgets e materialização governada no nível da página.',
2852
+ 'praxis.pageBuilder.agentic.header.subtitle.page': 'Transforme intenção em layout, widgets e materializações governadas.',
2824
2853
  'praxis.pageBuilder.agentic.header.subtitle.route': 'Autoria da rota {route}.',
2825
2854
  'praxis.pageBuilder.agentic.header.subtitle.widget': 'Foco em {target}.',
2855
+ 'praxis.pageBuilder.agentic.header.subtitle.reviewBlocked': 'Prévia pronta para revisão governada.',
2826
2856
  'praxis.pageBuilder.agentic.header.subtitle.review': 'Prévia pronta para revisão e persistência.',
2827
2857
  'praxis.pageBuilder.agentic.header.subtitle.governed': 'Continue o fluxo governado de decisão semântica.',
2828
2858
  'praxis.pageBuilder.agentic.header.mode.page': 'Página',
@@ -2844,7 +2874,9 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
2844
2874
  'praxis.pageBuilder.agentic.dock.summaryIdle': 'Conversa preservada. Continue de onde parou.',
2845
2875
  'praxis.pageBuilder.agentic.promptLabel': 'Mensagem',
2846
2876
  'praxis.pageBuilder.agentic.promptPlaceholder': 'Descreva a página, dashboard, formulário ou alteração que você precisa.',
2847
- 'praxis.pageBuilder.agentic.emptyConversation': 'Diga o que você quer criar ou alterar. Vou fazer perguntas antes de aplicar a pré-visualização.',
2877
+ 'praxis.pageBuilder.agentic.emptyConversation': 'Descreva o resultado que você quer. Vou fundamentar o contexto, preparar uma prévia governada e aguardar revisão antes de aplicar qualquer mudança.',
2878
+ 'praxis.pageBuilder.agentic.emptyConversation.blankGeneric': 'Esta página do host ainda está em branco. Conte qual decisão ou atividade este app precisa apoiar. Posso sugerir um dashboard, tabela, formulário ou fluxo de revisão e transformar isso em uma prévia governada para você revisar antes de qualquer mudança.',
2879
+ 'praxis.pageBuilder.agentic.emptyConversation.existingPage': 'Conte o que você quer melhorar aqui. Posso ler o layout atual, widgets, rota e contexto governado, depois preparar uma prévia para você revisar antes de qualquer mudança.',
2848
2880
  'praxis.pageBuilder.agentic.conversationAria': 'Conversa com IA',
2849
2881
  'praxis.pageBuilder.agentic.quickRepliesAria': 'Respostas rápidas',
2850
2882
  'praxis.pageBuilder.agentic.contextAria': 'Contexto ativo',
@@ -2860,6 +2892,23 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
2860
2892
  'praxis.pageBuilder.agentic.context.governedDomainContextRequest': 'Contexto solicitado',
2861
2893
  'praxis.pageBuilder.agentic.context.governedDomainContextSize': 'Tamanho do grounding',
2862
2894
  'praxis.pageBuilder.agentic.context.sharedRuleTargetLayer': 'Materialização alvo',
2895
+ 'praxis.pageBuilder.agentic.context.semanticDecisionResource': 'Fonte',
2896
+ 'praxis.pageBuilder.agentic.context.semanticDecisionKind': 'Objetivo',
2897
+ 'praxis.pageBuilder.agentic.context.semanticDecisionEvidence': 'Revisão',
2898
+ 'praxis.pageBuilder.agentic.context.operationCreate': 'Criar',
2899
+ 'praxis.pageBuilder.agentic.context.operationUpdate': 'Ajustar',
2900
+ 'praxis.pageBuilder.agentic.context.operationRead': 'Consultar',
2901
+ 'praxis.pageBuilder.agentic.context.artifactDashboard': 'dashboard',
2902
+ 'praxis.pageBuilder.agentic.context.artifactTable': 'tabela',
2903
+ 'praxis.pageBuilder.agentic.context.artifactForm': 'formulário',
2904
+ 'praxis.pageBuilder.agentic.context.artifactPage': 'tela',
2905
+ 'praxis.pageBuilder.agentic.context.changeAnalytics': 'com análise',
2906
+ 'praxis.pageBuilder.agentic.context.changeDashboard': 'com visão gerencial',
2907
+ 'praxis.pageBuilder.agentic.context.changeTable': 'com detalhes',
2908
+ 'praxis.pageBuilder.agentic.context.changeForm': 'com edição',
2909
+ 'praxis.pageBuilder.agentic.context.evidenceReviewRequired': 'Precisa revisar campos',
2910
+ 'praxis.pageBuilder.agentic.context.evidenceLowConfidence': 'Precisa confirmar fonte',
2911
+ 'praxis.pageBuilder.agentic.context.evidenceGrounded': 'Fonte confirmada',
2863
2912
  'praxis.pageBuilder.agentic.editMessage': 'Editar',
2864
2913
  'praxis.pageBuilder.agentic.resendMessage': 'Reenviar',
2865
2914
  'praxis.pageBuilder.agentic.removeAttachment': 'Remover anexo',
@@ -2869,7 +2918,7 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
2869
2918
  'praxis.pageBuilder.agentic.mode.diagnostic': 'Diagnóstico',
2870
2919
  'praxis.pageBuilder.agentic.mode.review': 'Revisão',
2871
2920
  'praxis.pageBuilder.agentic.mode.inlineHelp': 'Ajuda',
2872
- 'praxis.pageBuilder.agentic.state.idle': 'Ocioso',
2921
+ 'praxis.pageBuilder.agentic.state.idle': 'Pronto',
2873
2922
  'praxis.pageBuilder.agentic.state.listening': 'Pronto',
2874
2923
  'praxis.pageBuilder.agentic.state.processing': 'Processando',
2875
2924
  'praxis.pageBuilder.agentic.state.clarification': 'Aguardando resposta',
@@ -2901,9 +2950,16 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
2901
2950
  'praxis.pageBuilder.agentic.exploratory.capability.table': 'tabelas',
2902
2951
  'praxis.pageBuilder.agentic.exploratory.capability.form': 'formulários',
2903
2952
  'praxis.pageBuilder.agentic.exploratory.capability.masterDetail': 'páginas master-detail',
2904
- 'praxis.pageBuilder.agentic.resourceDiscovery.found': 'Encontrei APIs que podem alimentar esta tela. Escolha uma antes de gerar a pré-visualização.',
2953
+ 'praxis.pageBuilder.agentic.resourceDiscovery.found': 'Encontrei {sourceCount} para esta tela. Minha recomendação é começar por {first}, porque parece a melhor opção para gráficos, KPIs e drill-down. Revise os cards abaixo para entender quando usar cada fonte, o que ela retorna e o que eu vou criar depois da seleção.',
2954
+ 'praxis.pageBuilder.agentic.resourceDiscovery.sourceCountSingular': '1 fonte candidata',
2955
+ 'praxis.pageBuilder.agentic.resourceDiscovery.sourceCountPlural': '{count} fontes candidatas',
2905
2956
  'praxis.pageBuilder.agentic.resourceDiscovery.empty': 'Ainda não encontrei uma API correspondente. Descreva quais dados de negócio esta tela deve usar.',
2906
2957
  'praxis.pageBuilder.agentic.resourceDiscovery.useResource': 'Usar {resourcePath}',
2958
+ 'praxis.pageBuilder.agentic.resourceDiscovery.defaultRecommendedLabel': 'a primeira opção',
2959
+ 'praxis.pageBuilder.agentic.resourceDiscovery.cardDescription': 'Fonte recomendada para transformar {label} em painel: ajuda a escolher gráficos, listas, filtros e formatos antes de materializar a tela.',
2960
+ 'praxis.pageBuilder.agentic.resourceDiscovery.cardBestFor': 'Quando você quer entender se {label} responde ao objetivo de negócio antes de criar widgets.',
2961
+ 'praxis.pageBuilder.agentic.resourceDiscovery.cardReturns': 'Sugere métricas, dimensões, filtros, formatos de valor, gráficos e listas de detalhe compatíveis com a fonte.',
2962
+ 'praxis.pageBuilder.agentic.resourceDiscovery.cardNextStep': 'Selecione para eu propor uma pré-visualização governada com cards ricos, drill-down e formatos adequados por padrão.',
2907
2963
  'praxis.pageBuilder.agentic.diagnostics.title': 'Diagnóstico do LLM',
2908
2964
  'praxis.pageBuilder.agentic.diagnostics.badge': 'Debug',
2909
2965
  'praxis.pageBuilder.agentic.diagnostics.description': 'Prompt, pacote de contexto e catálogo de ferramentas retornados pelo backend para este turno.',
@@ -2925,10 +2981,12 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
2925
2981
  'praxis.pageBuilder.agentic.status.refinedCandidates': 'Estou revisando os recursos encontrados com a IA...',
2926
2982
  'praxis.pageBuilder.agentic.status.projectKnowledgeRetrieved': 'Recuperei conhecimento governado do projeto para este turno de autoria.',
2927
2983
  'praxis.pageBuilder.agentic.status.projectKnowledgeRetrievedCount': 'Recuperei {count} sinais de conhecimento governado do projeto para este turno.',
2928
- 'praxis.pageBuilder.agentic.status.projectKnowledgeAuditCited': '{cited} de {count} sinais de conhecimento governado foram citados em sourceRefs.',
2984
+ 'praxis.pageBuilder.agentic.status.projectKnowledgeAuditCited': 'Conhecimento governado citado: {cited} de {count}.',
2929
2985
  'praxis.pageBuilder.agentic.status.previewing': 'Gerando pré-visualização...',
2930
2986
  'praxis.pageBuilder.agentic.status.previewCompile': 'Compilando pré-visualização...',
2931
2987
  'praxis.pageBuilder.agentic.status.previewReady': 'Pré-visualização aplicada à página.',
2988
+ 'praxis.pageBuilder.agentic.status.reviewReady': 'Pronto para revisar.',
2989
+ 'praxis.pageBuilder.agentic.status.reviewNeedsAttention': 'Revise os pontos pendentes antes de salvar.',
2932
2990
  'praxis.pageBuilder.agentic.status.acceptedAddLocalField': 'Campo local adicionado ao formulário.',
2933
2991
  'praxis.pageBuilder.agentic.status.acceptedRemoveLocalField': 'Campo local removido do formulário.',
2934
2992
  'praxis.pageBuilder.agentic.status.acceptedRelabelField': 'Rótulo do campo atualizado.',
@@ -11134,7 +11192,7 @@ function providePageBuilderWidgetAiCatalogs() {
11134
11192
 
11135
11193
  const DEFAULT_AGENTIC_AUTHORING_REQUEST_TIMEOUT_MS = 15000;
11136
11194
  const DEFAULT_TURN_STREAM_START_TIMEOUT_MS = 10000;
11137
- const DEFAULT_TURN_STREAM_TIMEOUT_MS = 60000;
11195
+ const DEFAULT_TURN_STREAM_TIMEOUT_MS = 240000;
11138
11196
  const PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS = new InjectionToken('PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS');
11139
11197
  class PageBuilderAgenticAuthoringService {
11140
11198
  http = inject(HttpClient);
@@ -11166,6 +11224,7 @@ class PageBuilderAgenticAuthoringService {
11166
11224
  scope: body.scope,
11167
11225
  tags: body.tags,
11168
11226
  compiledFormPatch: body.compiledFormPatch,
11227
+ semanticDecision: body.semanticDecision ?? null,
11169
11228
  }, {
11170
11229
  headers: this.buildHeaders(ifMatch ? { 'If-Match': this.formatEtag(ifMatch) } : undefined),
11171
11230
  });
@@ -11544,7 +11603,7 @@ const PRAXIS_PAGE_BUILDER_AUTHORING_MANIFEST = {
11544
11603
  { name: 'pageChange', type: 'WidgetPageDefinition', description: 'Emitted after local apply/preview produces a renderable page.' },
11545
11604
  { name: 'agenticAuthoringEnableStreaming', type: 'boolean', description: 'Opt-in flag for the canonical streaming turn endpoints.' },
11546
11605
  { name: 'agenticAuthoringIncludeLlmDiagnostics', type: 'boolean', description: 'Opt-in flag that exposes governed diagnostics as cockpit evidence for validation and debugging.' },
11547
- { name: 'agenticAuthoringContextHints', type: 'Record<string, unknown>', description: 'Host-provided semantic hints, including governed domain-catalog references used to ground AI-authored decisions.' },
11606
+ { name: 'agenticAuthoringContextHints', type: 'Record<string, unknown>', description: 'Host-provided semantic hints, including governed domain-catalog references and optional RAG-authored openingMessage used to ground AI-authored decisions.' },
11548
11607
  ],
11549
11608
  editableTargets: [
11550
11609
  { kind: 'page', resolver: 'widget-page-definition-root', description: 'Root WidgetPageDefinition document: title, metadata, context and renderable page envelope.' },
@@ -12328,6 +12387,84 @@ function clone(value) {
12328
12387
  }
12329
12388
  }
12330
12389
 
12390
+ const RUNTIME_AUTHORING_METADATA_INPUTS = [
12391
+ 'schemaVerification',
12392
+ 'schemaEvidenceSource',
12393
+ 'schemaEvidenceUrl',
12394
+ ];
12395
+ function normalizePageBuilderRuntimePage(page) {
12396
+ if (!page?.widgets?.length) {
12397
+ return page;
12398
+ }
12399
+ return {
12400
+ ...page,
12401
+ widgets: page.widgets.map((widget) => normalizePageBuilderRuntimeWidget(widget)),
12402
+ };
12403
+ }
12404
+ function normalizePageBuilderRuntimeWidget(widget) {
12405
+ const definition = widget.definition;
12406
+ if (!definition?.inputs) {
12407
+ return widget;
12408
+ }
12409
+ const inputs = { ...definition.inputs };
12410
+ for (const key of RUNTIME_AUTHORING_METADATA_INPUTS) {
12411
+ delete inputs[key];
12412
+ }
12413
+ if (definition.id === 'praxis-rich-content') {
12414
+ if (inputs['kpis'] !== undefined) {
12415
+ const document = isRecord(inputs['document']) ? inputs['document'] : {};
12416
+ inputs['document'] = {
12417
+ ...document,
12418
+ kpis: document['kpis'] ?? inputs['kpis'],
12419
+ };
12420
+ }
12421
+ delete inputs['kpis'];
12422
+ delete inputs['resourcePath'];
12423
+ delete inputs['schemaUrl'];
12424
+ }
12425
+ if (definition.id === 'praxis-filter') {
12426
+ if (!String(inputs['resourcePath'] || '').trim()) {
12427
+ const inferredResourcePath = inferResourcePathFromSchemaUrl(inputs['schemaUrl']);
12428
+ if (inferredResourcePath) {
12429
+ inputs['resourcePath'] = inferredResourcePath;
12430
+ }
12431
+ }
12432
+ delete inputs['schemaUrl'];
12433
+ }
12434
+ if (definition.id === 'praxis-table') {
12435
+ delete inputs['title'];
12436
+ delete inputs['schemaUrl'];
12437
+ delete inputs['submitUrl'];
12438
+ delete inputs['submitMethod'];
12439
+ }
12440
+ return {
12441
+ ...widget,
12442
+ definition: {
12443
+ ...definition,
12444
+ inputs,
12445
+ },
12446
+ };
12447
+ }
12448
+ function inferResourcePathFromSchemaUrl(schemaUrl) {
12449
+ const raw = String(schemaUrl || '').trim();
12450
+ if (!raw)
12451
+ return undefined;
12452
+ try {
12453
+ const url = new URL(raw, 'http://praxis.local');
12454
+ const path = url.searchParams.get('path') || url.searchParams.get('resourcePath');
12455
+ if (path)
12456
+ return path;
12457
+ }
12458
+ catch {
12459
+ // Keep the fallback below for partial schema URLs.
12460
+ }
12461
+ const match = raw.match(/[?&](?:path|resourcePath)=([^&]+)/);
12462
+ return match?.[1] ? decodeURIComponent(match[1]) : undefined;
12463
+ }
12464
+ function isRecord(value) {
12465
+ return !!value && typeof value === 'object' && !Array.isArray(value);
12466
+ }
12467
+
12331
12468
  const LEGACY_OPTIONS_KEY = 'options';
12332
12469
  const LEGACY_LAYOUT_KEY = 'layout';
12333
12470
  class PageBuilderAiAdapter {
@@ -12452,7 +12589,8 @@ class PageBuilderAiAdapter {
12452
12589
  return page;
12453
12590
  const cloned = this.clone(page);
12454
12591
  const { [LEGACY_OPTIONS_KEY]: _legacyOptions, ...rest } = cloned;
12455
- const widgets = (cloned.widgets || []).map((w) => this.stripLegacyLayoutFields(w));
12592
+ const widgets = (cloned.widgets || [])
12593
+ .map((w) => normalizePageBuilderRuntimeWidget(this.stripLegacyLayoutFields(w)));
12456
12594
  return {
12457
12595
  ...rest,
12458
12596
  widgets,
@@ -12472,7 +12610,8 @@ class PageBuilderAiAdapter {
12472
12610
  return page;
12473
12611
  const cloned = this.clone(page);
12474
12612
  const { [LEGACY_OPTIONS_KEY]: _legacyOptions, ...rest } = cloned;
12475
- const widgets = (cloned.widgets || []).map((w) => this.stripLegacyLayoutFields(w));
12613
+ const widgets = (cloned.widgets || [])
12614
+ .map((w) => normalizePageBuilderRuntimeWidget(this.stripLegacyLayoutFields(w)));
12476
12615
  return {
12477
12616
  ...rest,
12478
12617
  widgets,
@@ -12846,6 +12985,10 @@ class PageBuilderAgenticAuthoringTurnFlow {
12846
12985
  phase: 'capture',
12847
12986
  });
12848
12987
  }
12988
+ const contextualActionContext = this.contextualPreviewActionContextFromRequest(request);
12989
+ if (contextualActionContext) {
12990
+ return from(this.submitContextualPreviewAction(request, prompt, contextualActionContext));
12991
+ }
12849
12992
  if (this.context.enableTurnStream?.() === true && this.service.streamTurn) {
12850
12993
  return this.submitWithTurnStream(request, prompt);
12851
12994
  }
@@ -12863,9 +13006,10 @@ class PageBuilderAgenticAuthoringTurnFlow {
12863
13006
  const componentCapabilities = await this.context.loadComponentCapabilities();
12864
13007
  const selectedWidgetKey = this.context.selectedWidgetKey();
12865
13008
  const intentResolution = await firstValueFrom(this.service.resolveIntent(this.buildIntentResolutionRequest(prompt, selectedWidgetKey, componentCapabilities, authoringContext)));
12866
- const intentAssistantMessage = this.resolveIntentAssistantMessage(intentResolution);
13009
+ const intentQuickReplies = this.resolveShellQuickReplies(intentResolution);
13010
+ const intentAssistantMessage = this.normalizeAssistantMessageForQuickReplies(this.resolveIntentAssistantMessage(intentResolution), intentQuickReplies);
12867
13011
  if (intentAssistantMessage) {
12868
- const quickReplies = this.toShellQuickReplies(intentResolution.quickReplies ?? []);
13012
+ const quickReplies = intentQuickReplies;
12869
13013
  const explicitPendingClarification = this.toShellPendingClarification(intentResolution.pendingClarification);
12870
13014
  const intentClarification = this.resolveIntentClarification(intentResolution);
12871
13015
  const routeRequiredClarification = this.resolveSharedRuleRouteClarification(intentResolution, this.resolveEffectivePrompt(intentResolution, prompt), request.clientTurnId);
@@ -12873,10 +13017,13 @@ class PageBuilderAgenticAuthoringTurnFlow {
12873
13017
  ?? (intentClarification
12874
13018
  ? this.buildPendingClarificationForNextTurn(request, this.resolveEffectivePrompt(intentResolution, prompt), intentClarification)
12875
13019
  : routeRequiredClarification);
13020
+ const consultativeCatalogIntent = this.isConsultativeCatalogIntent(intentResolution);
12876
13021
  const shouldAutoGenerateGuidedPreview = this.shouldAutoGenerateGuidedPreview(intentResolution, quickReplies, prompt) && !this.hasPendingClarificationQuestion(pendingClarification);
12877
- const mustPauseForClarification = (!this.isExecutableIntent(intentResolution) && !shouldAutoGenerateGuidedPreview)
13022
+ const mustPauseForClarification = (!this.isExecutableIntent(intentResolution, request) && !shouldAutoGenerateGuidedPreview)
12878
13023
  || this.hasPendingClarificationQuestion(pendingClarification);
12879
- if (mustPauseForClarification && !this.hasPendingClarificationQuestion(pendingClarification) && quickReplies.length === 0) {
13024
+ if (mustPauseForClarification
13025
+ && !this.hasPendingClarificationQuestion(pendingClarification)
13026
+ && (quickReplies.length === 0 || consultativeCatalogIntent)) {
12880
13027
  return {
12881
13028
  state: 'success',
12882
13029
  phase: 'summarize',
@@ -12925,7 +13072,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
12925
13072
  state: 'clarification',
12926
13073
  phase: 'clarify',
12927
13074
  assistantMessage: clarification,
12928
- quickReplies: this.toShellQuickReplies(intentResolution.quickReplies ?? []),
13075
+ quickReplies: this.resolveShellQuickReplies(intentResolution),
12929
13076
  canApply: false,
12930
13077
  statusText: '',
12931
13078
  errorText: '',
@@ -12953,7 +13100,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
12953
13100
  model: this.context.model(),
12954
13101
  apiKey: this.context.apiKey(),
12955
13102
  currentPage: this.context.currentPage(),
12956
- selectedWidgetKey,
13103
+ selectedWidgetKey: this.resolveSelectedWidgetKey(selectedWidgetKey, authoringContext.contextHints),
12957
13104
  intentResolution,
12958
13105
  componentCapabilities,
12959
13106
  ...authoringContext,
@@ -12986,14 +13133,13 @@ class PageBuilderAgenticAuthoringTurnFlow {
12986
13133
  };
12987
13134
  }
12988
13135
  const status = this.context.describePreviewStatus(preview);
12989
- const statusText = this.withProjectKnowledgeAuditStatus(status, preview);
12990
13136
  return {
12991
13137
  state: 'review',
12992
13138
  phase: 'review',
12993
13139
  assistantMessage: status,
12994
13140
  quickReplies: [],
12995
13141
  canApply: true,
12996
- statusText,
13142
+ statusText: this.reviewStatusText(status, true),
12997
13143
  errorText: '',
12998
13144
  preview,
12999
13145
  diagnostics: { intentResolution },
@@ -13035,21 +13181,68 @@ class PageBuilderAgenticAuthoringTurnFlow {
13035
13181
  pendingPatch: null,
13036
13182
  };
13037
13183
  }
13184
+ async submitContextualPreviewAction(request, prompt, contextHints) {
13185
+ const componentId = this.readString(contextHints, 'targetComponentId')
13186
+ || this.readString(contextHints, 'selectedComponentId');
13187
+ const artifactKind = this.readString(contextHints, 'artifactKind')
13188
+ || (componentId === 'praxis-table' ? 'table' : componentId === 'praxis-dynamic-form' ? 'form' : 'chart');
13189
+ const changeKind = this.readString(contextHints, 'changeKind') || 'contextual_component_action';
13190
+ const intentResolution = {
13191
+ valid: true,
13192
+ operationKind: 'modify',
13193
+ artifactKind,
13194
+ changeKind,
13195
+ authoringProfile: 'component-capability-catalog',
13196
+ targetApp: this.context.targetApp,
13197
+ targetComponentId: this.context.targetComponentId,
13198
+ target: componentId
13199
+ ? {
13200
+ componentId,
13201
+ widgetKey: this.readString(contextHints, 'targetWidgetKey')
13202
+ || this.readString(contextHints, 'selectedWidgetKey')
13203
+ || this.context.selectedWidgetKey()
13204
+ || '',
13205
+ resourcePath: this.readString(contextHints, 'resourcePath'),
13206
+ schemaUrl: this.readString(contextHints, 'schemaUrl'),
13207
+ submitUrl: this.readString(contextHints, 'submitUrl'),
13208
+ submitMethod: this.readString(contextHints, 'submitMethod'),
13209
+ }
13210
+ : null,
13211
+ selectedCandidate: this.contextualActionCandidate(contextHints),
13212
+ candidates: [],
13213
+ gate: {
13214
+ gateId: 'component-capability-catalog',
13215
+ status: 'eligible',
13216
+ messages: [],
13217
+ },
13218
+ effectivePrompt: prompt,
13219
+ assistantMessage: null,
13220
+ quickReplies: [],
13221
+ pendingClarification: null,
13222
+ clarificationQuestions: [],
13223
+ warnings: [],
13224
+ failureCodes: [],
13225
+ currentPageSummary: {},
13226
+ contextHints,
13227
+ };
13228
+ return this.completeExecutableStreamPreview(request, prompt, intentResolution, undefined);
13229
+ }
13038
13230
  async buildTurnStreamRequest(request, prompt) {
13039
13231
  const componentCapabilities = await this.context.loadComponentCapabilities();
13040
13232
  const selectedWidgetKey = this.context.selectedWidgetKey();
13233
+ const authoringContext = this.buildAuthoringContext(request);
13041
13234
  return {
13042
13235
  userPrompt: prompt,
13043
13236
  targetApp: this.context.targetApp,
13044
13237
  targetComponentId: this.context.targetComponentId,
13045
13238
  currentRoute: null,
13046
13239
  currentPage: this.context.currentPage(),
13047
- selectedWidgetKey,
13240
+ selectedWidgetKey: this.resolveSelectedWidgetKey(selectedWidgetKey, authoringContext.contextHints),
13048
13241
  provider: this.context.provider(),
13049
13242
  model: this.context.model(),
13050
13243
  apiKey: this.context.apiKey(),
13051
13244
  componentCapabilities,
13052
- ...this.buildAuthoringContext(request),
13245
+ ...authoringContext,
13053
13246
  };
13054
13247
  }
13055
13248
  async toTurnResultFromStreamEvent(event, request, prompt) {
@@ -13108,14 +13301,21 @@ class PageBuilderAgenticAuthoringTurnFlow {
13108
13301
  preview: null,
13109
13302
  };
13110
13303
  }
13111
- const assistantMessage = this.readString(payload, 'assistantMessage')
13304
+ const rawAssistantMessage = this.readString(payload, 'assistantMessage')
13112
13305
  || this.resolveIntentAssistantMessage(intentResolution)
13113
13306
  || (preview ? this.context.describePreviewStatus(preview) : '');
13114
13307
  const rawQuickReplies = Array.isArray(payload['quickReplies'])
13115
13308
  ? payload['quickReplies']
13116
13309
  : intentResolution.quickReplies ?? [];
13117
- const quickReplies = this.toShellQuickReplies(rawQuickReplies);
13310
+ const quickReplies = this.resolveShellQuickReplies(intentResolution, rawQuickReplies);
13311
+ const assistantMessage = this.normalizeAssistantMessageForQuickReplies(rawAssistantMessage, quickReplies);
13118
13312
  const canApply = payload['canApply'] === true && !!preview?.valid;
13313
+ const contextualExecutableIntent = request
13314
+ ? this.toExecutableContextualComponentIntent(intentResolution, request)
13315
+ : null;
13316
+ if (!canApply && contextualExecutableIntent && request && prompt) {
13317
+ return this.completeExecutableStreamPreview(request, prompt, contextualExecutableIntent, preview);
13318
+ }
13119
13319
  if (canApply
13120
13320
  && request
13121
13321
  && prompt
@@ -13123,17 +13323,54 @@ class PageBuilderAgenticAuthoringTurnFlow {
13123
13323
  return this.completeExecutableStreamPreview(request, prompt, intentResolution, undefined);
13124
13324
  }
13125
13325
  if (!canApply) {
13326
+ if (preview && this.hasMaterializablePreview(preview) && this.isGovernedBlockedStreamPreview(payload, preview)) {
13327
+ const applied = await this.context.applyLocalPreview(preview);
13328
+ if (!applied.success) {
13329
+ const message = applied.error || this.context.tx('agentic.errors.applyLocal', 'Preview could not be applied.');
13330
+ return {
13331
+ state: 'error',
13332
+ phase: 'preview',
13333
+ assistantMessage: message,
13334
+ canApply: false,
13335
+ statusText: '',
13336
+ errorText: message,
13337
+ preview: null,
13338
+ diagnostics: {
13339
+ intentResolution,
13340
+ preview,
13341
+ decisionDiagnostics: this.toJsonObject(payload['decisionDiagnostics']),
13342
+ toolLoopTrace: Array.isArray(payload['toolLoopTrace']) ? payload['toolLoopTrace'] : undefined,
13343
+ },
13344
+ };
13345
+ }
13346
+ return {
13347
+ state: 'review',
13348
+ phase: 'review',
13349
+ assistantMessage,
13350
+ quickReplies,
13351
+ canApply: false,
13352
+ statusText: this.reviewStatusText(assistantMessage, false),
13353
+ errorText: '',
13354
+ preview,
13355
+ diagnostics: {
13356
+ intentResolution,
13357
+ preview,
13358
+ decisionDiagnostics: this.toJsonObject(payload['decisionDiagnostics']),
13359
+ toolLoopTrace: Array.isArray(payload['toolLoopTrace']) ? payload['toolLoopTrace'] : undefined,
13360
+ },
13361
+ };
13362
+ }
13126
13363
  const pendingClarification = this.toShellPendingClarification(intentResolution?.pendingClarification)
13127
13364
  ?? this.resolveSharedRuleRouteClarification(intentResolution, this.resolveEffectivePrompt(intentResolution, assistantMessage));
13128
13365
  if (!pendingClarification
13129
- && (this.isExecutableIntent(intentResolution)
13366
+ && (this.isExecutableIntent(intentResolution, request)
13130
13367
  || (!!prompt && this.shouldAutoGenerateGuidedPreview(intentResolution, quickReplies, prompt)))
13131
13368
  && !this.hasBlockingResourceQuickReply(quickReplies)
13132
13369
  && request
13133
13370
  && prompt) {
13134
13371
  return this.completeExecutableStreamPreview(request, prompt, intentResolution, preview);
13135
13372
  }
13136
- const requiresChoice = quickReplies.length > 0;
13373
+ const requiresChoice = quickReplies.length > 0 && !this.isConsultativeCatalogIntent(intentResolution);
13137
13374
  return {
13138
13375
  state: pendingClarification || requiresChoice ? 'clarification' : 'success',
13139
13376
  phase: pendingClarification || requiresChoice ? 'clarify' : 'summarize',
@@ -13162,14 +13399,13 @@ class PageBuilderAgenticAuthoringTurnFlow {
13162
13399
  };
13163
13400
  }
13164
13401
  const status = assistantMessage || this.context.describePreviewStatus(preview);
13165
- const statusText = this.withProjectKnowledgeAuditStatus(status, preview);
13166
13402
  return {
13167
13403
  state: 'review',
13168
13404
  phase: 'review',
13169
13405
  assistantMessage: status,
13170
- quickReplies: [],
13406
+ quickReplies,
13171
13407
  canApply: true,
13172
- statusText,
13408
+ statusText: this.reviewStatusText(status, true),
13173
13409
  errorText: '',
13174
13410
  preview,
13175
13411
  diagnostics: { intentResolution, preview },
@@ -13182,7 +13418,10 @@ class PageBuilderAgenticAuthoringTurnFlow {
13182
13418
  return false;
13183
13419
  }
13184
13420
  const contextHints = this.toJsonObject(reply.contextHints);
13185
- return !!this.readString(contextHints, 'resourcePath');
13421
+ if (this.isContextualPreviewActionReply(reply, contextHints)) {
13422
+ return false;
13423
+ }
13424
+ return !!this.readString(contextHints, 'resourcePath') || this.isResourceQuickReply(reply);
13186
13425
  });
13187
13426
  }
13188
13427
  async completeExecutableStreamPreview(request, prompt, intentResolution, streamPreview) {
@@ -13190,6 +13429,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
13190
13429
  const authoringContext = this.buildAuthoringContext(request);
13191
13430
  const componentCapabilities = await this.context.loadComponentCapabilities();
13192
13431
  const selectedWidgetKey = this.context.selectedWidgetKey();
13432
+ const effectiveSelectedWidgetKey = this.resolveSelectedWidgetKey(selectedWidgetKey, authoringContext.contextHints);
13193
13433
  const reusableStreamPreview = streamPreview?.valid
13194
13434
  && !this.shouldRegenerateStreamPreview(intentResolution, streamPreview);
13195
13435
  const preview = reusableStreamPreview
@@ -13200,7 +13440,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
13200
13440
  model: this.context.model(),
13201
13441
  apiKey: this.context.apiKey(),
13202
13442
  currentPage: this.context.currentPage(),
13203
- selectedWidgetKey,
13443
+ selectedWidgetKey: effectiveSelectedWidgetKey,
13204
13444
  intentResolution,
13205
13445
  componentCapabilities,
13206
13446
  ...authoringContext,
@@ -13233,14 +13473,13 @@ class PageBuilderAgenticAuthoringTurnFlow {
13233
13473
  };
13234
13474
  }
13235
13475
  const status = this.context.describePreviewStatus(preview);
13236
- const statusText = this.withProjectKnowledgeAuditStatus(status, preview);
13237
13476
  return {
13238
13477
  state: 'review',
13239
13478
  phase: 'review',
13240
13479
  assistantMessage: status,
13241
13480
  quickReplies: [],
13242
13481
  canApply: true,
13243
- statusText,
13482
+ statusText: this.reviewStatusText(status, true),
13244
13483
  errorText: '',
13245
13484
  preview,
13246
13485
  diagnostics: { intentResolution, preview },
@@ -13272,6 +13511,43 @@ class PageBuilderAgenticAuthoringTurnFlow {
13272
13511
  }
13273
13512
  return true;
13274
13513
  }
13514
+ isGovernedBlockedStreamPreview(payload, preview) {
13515
+ const previewDiagnostics = this.toJsonObject(preview.diagnostics);
13516
+ const decisionDiagnostics = this.toJsonObject(payload['decisionDiagnostics'])
13517
+ ?? this.toJsonObject(previewDiagnostics?.['decisionDiagnostics']);
13518
+ if (decisionDiagnostics) {
13519
+ if (decisionDiagnostics['requiresReview'] === true) {
13520
+ return true;
13521
+ }
13522
+ if (decisionDiagnostics['decisionValid'] === false) {
13523
+ return true;
13524
+ }
13525
+ if (this.readString(decisionDiagnostics, 'reviewReason')) {
13526
+ return true;
13527
+ }
13528
+ }
13529
+ const warnings = Array.isArray(preview.warnings)
13530
+ ? preview.warnings.map((warning) => `${warning}`)
13531
+ : [];
13532
+ const failureCodes = Array.isArray(preview.failureCodes)
13533
+ ? preview.failureCodes.map((code) => `${code}`)
13534
+ : [];
13535
+ return warnings.some((warning) => warning === 'semantic-preview-materialization-mismatch'
13536
+ || warning === 'semantic-axis-schema-verification-pending')
13537
+ || failureCodes.some((code) => code === 'semantic-decision-required'
13538
+ || code.startsWith('semantic-preview-'));
13539
+ }
13540
+ hasMaterializablePreview(preview) {
13541
+ if (!preview) {
13542
+ return false;
13543
+ }
13544
+ if (preview.uiCompositionPlan) {
13545
+ return true;
13546
+ }
13547
+ const patch = this.toJsonObject(preview.compiledFormPatch)?.['patch'];
13548
+ const page = this.toJsonObject(patch)?.['page'];
13549
+ return !!this.toJsonObject(page);
13550
+ }
13275
13551
  phaseForStreamPayload(payload) {
13276
13552
  const phase = this.readString(payload, 'phase');
13277
13553
  if (phase === 'intent.resolve')
@@ -13322,21 +13598,22 @@ class PageBuilderAgenticAuthoringTurnFlow {
13322
13598
  }
13323
13599
  return base;
13324
13600
  }
13325
- withProjectKnowledgeAuditStatus(status, preview) {
13326
- const audit = this.toJsonObject(preview?.diagnostics?.projectKnowledgeAudit);
13327
- if (!audit) {
13328
- return status;
13329
- }
13330
- const influenceCount = this.readNumber(audit, 'influenceCount');
13331
- const citedCount = this.readNumber(audit, 'citedCount');
13332
- if (!influenceCount || influenceCount <= 0 || citedCount === null || citedCount < 0) {
13333
- return status;
13601
+ reviewStatusText(status, canApply) {
13602
+ const normalized = status.trim();
13603
+ if (normalized && !this.shouldReplaceReviewStatus(normalized)) {
13604
+ return normalized;
13334
13605
  }
13335
- const auditStatus = this.context
13336
- .tx('agentic.status.projectKnowledgeAuditCited', '{cited} of {count} governed project knowledge signals were cited in sourceRefs.')
13337
- .replace('{cited}', String(citedCount))
13338
- .replace('{count}', String(influenceCount));
13339
- return [status, auditStatus].filter((part) => !!part.trim()).join(' ');
13606
+ return canApply
13607
+ ? this.context.tx('agentic.status.reviewReady', 'Ready for review.')
13608
+ : this.context.tx('agentic.status.reviewNeedsAttention', 'Review the pending points before saving.');
13609
+ }
13610
+ shouldReplaceReviewStatus(status) {
13611
+ const normalized = status.toLocaleLowerCase();
13612
+ return status.length > 80
13613
+ || normalized.includes('preview applied')
13614
+ || normalized.includes('pré-visualização')
13615
+ || normalized.includes('pre-visualizacao')
13616
+ || normalized.includes('sourcerefs');
13340
13617
  }
13341
13618
  isBackendResourceDiscoveryPayload(payload) {
13342
13619
  const diagnostics = this.toJsonObject(payload['diagnostics']);
@@ -13519,10 +13796,9 @@ class PageBuilderAgenticAuthoringTurnFlow {
13519
13796
  const quickReplies = result.quickReplies?.length
13520
13797
  ? this.toShellQuickReplies(result.quickReplies)
13521
13798
  : this.toResourceCandidateQuickReplies(result.candidates, result.artifactKind);
13522
- const assistantMessage = result.assistantMessage?.trim()
13523
- || (quickReplies.length
13524
- ? this.context.tx('agentic.resourceDiscovery.found', 'I found APIs that can feed this screen. Choose one before generating the preview.')
13525
- : this.context.tx('agentic.resourceDiscovery.empty', 'I did not find a matching API yet. Describe the business data this screen should use.'));
13799
+ const assistantMessage = quickReplies.length
13800
+ ? this.resourceDiscoveryAssistantMessage(result.assistantMessage, quickReplies)
13801
+ : this.context.tx('agentic.resourceDiscovery.empty', 'I did not find a matching API yet. Describe the business data this screen should use.');
13526
13802
  const intentResult = await this.resolveIntentAfterResourceDiscovery(request, request.pendingClarification?.sourcePrompt || prompt, contextHints, result, assistantMessage, quickReplies);
13527
13803
  if (intentResult) {
13528
13804
  return intentResult;
@@ -13569,12 +13845,16 @@ class PageBuilderAgenticAuthoringTurnFlow {
13569
13845
  ...authoringContext,
13570
13846
  contextHints: this.resourceDiscoveryContextHints(contextHints, result),
13571
13847
  })));
13572
- const assistantMessage = this.resolveIntentAssistantMessage(intentResolution)
13848
+ const resolvedAssistantMessage = this.resolveIntentAssistantMessage(intentResolution)
13573
13849
  || this.resolveIntentClarification(intentResolution)
13574
13850
  || fallbackAssistantMessage;
13575
13851
  const quickReplies = intentResolution.quickReplies?.length
13576
13852
  ? this.toShellQuickReplies(intentResolution.quickReplies)
13577
13853
  : fallbackQuickReplies;
13854
+ const assistantMessage = quickReplies.some((reply) => this.isResourceQuickReply(reply))
13855
+ && this.isGenericResourceDiscoveryMessage(resolvedAssistantMessage)
13856
+ ? fallbackAssistantMessage
13857
+ : resolvedAssistantMessage;
13578
13858
  const explicitPendingClarification = this.toShellPendingClarification(intentResolution.pendingClarification);
13579
13859
  const routeRequiredClarification = this.resolveSharedRuleRouteClarification(intentResolution, this.resolveEffectivePrompt(intentResolution, prompt), request.clientTurnId);
13580
13860
  const pendingClarification = explicitPendingClarification
@@ -13637,6 +13917,37 @@ class PageBuilderAgenticAuthoringTurnFlow {
13637
13917
  const contextHints = this.toJsonObject(request.action?.contextHints);
13638
13918
  return this.readString(contextHints, 'tool') === 'searchApiResources';
13639
13919
  }
13920
+ resourceDiscoveryAssistantMessage(backendMessage, quickReplies) {
13921
+ const backendText = backendMessage?.trim() ?? '';
13922
+ if (backendText && !this.isGenericResourceDiscoveryMessage(backendText)) {
13923
+ return backendText;
13924
+ }
13925
+ const firstLabel = quickReplies[0]?.label?.trim()
13926
+ || this.context.tx('agentic.resourceDiscovery.defaultRecommendedLabel', 'the first option');
13927
+ const sourceCount = this.resourceDiscoverySourceCountLabel(quickReplies.length);
13928
+ return this.context.tx('agentic.resourceDiscovery.found', 'I found {sourceCount} for this screen. I recommend starting with {first} because it is the best fit for charts, KPIs, and drill-down. Review the cards below to see what each source is good for, what it returns, and what I will create after you select it.')
13929
+ .replace('{sourceCount}', sourceCount)
13930
+ .replace('{first}', firstLabel);
13931
+ }
13932
+ resourceDiscoverySourceCountLabel(count) {
13933
+ const key = count === 1
13934
+ ? 'agentic.resourceDiscovery.sourceCountSingular'
13935
+ : 'agentic.resourceDiscovery.sourceCountPlural';
13936
+ const fallback = count === 1 ? '1 candidate source' : '{count} candidate sources';
13937
+ return this.context.tx(key, fallback).replace('{count}', String(count));
13938
+ }
13939
+ normalizeAssistantMessageForQuickReplies(assistantMessage, quickReplies) {
13940
+ const message = assistantMessage?.trim() ?? '';
13941
+ return quickReplies.some((reply) => this.isResourceQuickReply(reply))
13942
+ ? this.resourceDiscoveryAssistantMessage(message, quickReplies)
13943
+ : message;
13944
+ }
13945
+ isGenericResourceDiscoveryMessage(message) {
13946
+ return /(?:encontrei|found).*(?:apis?|fontes?|sources?).*(?:escolha|choose)/iu.test(message)
13947
+ || /(?:encontrei|found).*(?:fontes?|sources?).*(?:candidatas?|candidate)/iu.test(message)
13948
+ || /(?:fonte|source).*(?:encontrada|found).*(?:escolha|choose)/iu.test(message)
13949
+ || /(?:fonte|source).*(?:encontrada|found).*(?:catalogo|catalog)/iu.test(message);
13950
+ }
13640
13951
  toResourceCandidateQuickReplies(candidates, artifactKind) {
13641
13952
  return candidates
13642
13953
  .filter((candidate) => !!candidate.resourcePath?.trim())
@@ -13696,20 +14007,184 @@ class PageBuilderAgenticAuthoringTurnFlow {
13696
14007
  const message = intentResolution.assistantMessage?.trim();
13697
14008
  return message || null;
13698
14009
  }
13699
- isExecutableIntent(intentResolution) {
14010
+ isExecutableIntent(intentResolution, request) {
13700
14011
  const operationKind = intentResolution.operationKind;
13701
14012
  const artifactKind = intentResolution.artifactKind;
13702
14013
  const allowsMaterializedArtifactOperation = operationKind === 'create'
13703
14014
  || operationKind === 'modify'
13704
14015
  || operationKind === 'remove';
13705
14016
  return !!intentResolution.valid
13706
- && intentResolution.gate?.status === 'eligible'
13707
- && ((allowsMaterializedArtifactOperation
13708
- && !!intentResolution.selectedCandidate
13709
- && (artifactKind === 'form'
13710
- || artifactKind === 'dashboard'
13711
- || artifactKind === 'table'))
13712
- || this.isExecutablePageCompositionIntent(intentResolution));
14017
+ && (this.isExecutableContextualComponentIntent(intentResolution, request)
14018
+ || (intentResolution.gate?.status === 'eligible'
14019
+ && ((allowsMaterializedArtifactOperation
14020
+ && !!intentResolution.selectedCandidate
14021
+ && (artifactKind === 'form'
14022
+ || artifactKind === 'dashboard'
14023
+ || artifactKind === 'table'
14024
+ || artifactKind === 'chart'))
14025
+ || this.isExecutablePageCompositionIntent(intentResolution))));
14026
+ }
14027
+ isExecutableContextualComponentIntent(intentResolution, request) {
14028
+ const operationKind = intentResolution.operationKind;
14029
+ const requestContextHints = this.contextualPreviewActionContextFromRequest(request)
14030
+ ?? this.toJsonObject(request?.action?.contextHints)
14031
+ ?? this.toJsonObject(request?.contextHints);
14032
+ const requestIsContextualPreviewAction = this.isContextualPreviewActionContext(requestContextHints);
14033
+ if (!requestIsContextualPreviewAction
14034
+ && operationKind !== 'create'
14035
+ && operationKind !== 'modify'
14036
+ && operationKind !== 'remove') {
14037
+ return false;
14038
+ }
14039
+ const contextHints = this.toJsonObject(intentResolution.contextHints)
14040
+ ?? requestContextHints;
14041
+ if (!this.isContextualPreviewActionContext(contextHints) && !requestIsContextualPreviewAction) {
14042
+ return false;
14043
+ }
14044
+ const componentId = this.readString(contextHints, 'targetComponentId')
14045
+ || this.readString(contextHints, 'selectedComponentId')
14046
+ || this.readString(requestContextHints, 'targetComponentId')
14047
+ || this.readString(requestContextHints, 'selectedComponentId')
14048
+ || intentResolution.target?.componentId
14049
+ || '';
14050
+ return componentId === 'praxis-chart'
14051
+ || componentId === 'praxis-table'
14052
+ || componentId === 'praxis-dynamic-form';
14053
+ }
14054
+ toExecutableContextualComponentIntent(intentResolution, request) {
14055
+ const requestContextHints = this.contextualPreviewActionContextFromRequest(request)
14056
+ ?? this.toJsonObject(request.action?.contextHints)
14057
+ ?? this.toJsonObject(request.contextHints);
14058
+ if (!this.isContextualPreviewActionContext(requestContextHints)) {
14059
+ return null;
14060
+ }
14061
+ const intentContextHints = this.toJsonObject(intentResolution.contextHints);
14062
+ const contextHints = {
14063
+ ...(requestContextHints ?? {}),
14064
+ ...(intentContextHints ?? {}),
14065
+ };
14066
+ const componentId = this.readString(contextHints, 'targetComponentId')
14067
+ || this.readString(contextHints, 'selectedComponentId')
14068
+ || intentResolution.target?.componentId
14069
+ || '';
14070
+ if (componentId !== 'praxis-chart'
14071
+ && componentId !== 'praxis-table'
14072
+ && componentId !== 'praxis-dynamic-form') {
14073
+ return null;
14074
+ }
14075
+ const currentOperation = intentResolution.operationKind;
14076
+ const operationKind = currentOperation === 'create'
14077
+ || currentOperation === 'modify'
14078
+ || currentOperation === 'remove'
14079
+ ? currentOperation
14080
+ : 'modify';
14081
+ const artifactKind = intentResolution.artifactKind
14082
+ || this.readString(contextHints, 'artifactKind')
14083
+ || (componentId === 'praxis-chart'
14084
+ ? 'chart'
14085
+ : componentId === 'praxis-table'
14086
+ ? 'table'
14087
+ : 'form');
14088
+ const changeKind = this.readString(contextHints, 'changeKind')
14089
+ || intentResolution.changeKind
14090
+ || 'contextual_component_action';
14091
+ return {
14092
+ ...intentResolution,
14093
+ valid: true,
14094
+ operationKind,
14095
+ artifactKind,
14096
+ changeKind,
14097
+ gate: {
14098
+ ...(intentResolution.gate ?? { gateId: '', status: '', messages: [] }),
14099
+ status: 'eligible',
14100
+ messages: [],
14101
+ },
14102
+ pendingClarification: null,
14103
+ clarificationQuestions: [],
14104
+ failureCodes: [],
14105
+ contextHints,
14106
+ };
14107
+ }
14108
+ isContextualPreviewActionContext(contextHints) {
14109
+ const hints = contextHints ?? null;
14110
+ const hintSource = this.readString(hints, 'source');
14111
+ const hintKind = this.readString(hints, 'kind');
14112
+ return hintSource === 'component-capability-catalog'
14113
+ || hintKind === 'contextual-preview-action';
14114
+ }
14115
+ contextualPreviewActionContextFromRequest(request) {
14116
+ const explicit = this.toJsonObject(request?.action?.contextHints);
14117
+ if (this.isContextualPreviewActionContext(explicit)) {
14118
+ return explicit;
14119
+ }
14120
+ const actionId = request?.action?.id?.trim();
14121
+ if (!actionId) {
14122
+ return null;
14123
+ }
14124
+ const base = {
14125
+ source: 'component-capability-catalog',
14126
+ kind: 'contextual-preview-action',
14127
+ operationKind: 'modify',
14128
+ };
14129
+ if (actionId === 'chart-change-line' || actionId === 'chart-change-donut') {
14130
+ return {
14131
+ ...base,
14132
+ artifactKind: 'chart',
14133
+ changeKind: 'set_chart_type',
14134
+ chartType: actionId === 'chart-change-donut' ? 'donut' : 'line',
14135
+ capabilityId: 'praxis-chart.type.set@0.1.0',
14136
+ targetComponentId: 'praxis-chart',
14137
+ selectedComponentId: 'praxis-chart',
14138
+ };
14139
+ }
14140
+ if (actionId === 'chart-add-detail-table' || actionId === 'chart-add-detail-modal') {
14141
+ return {
14142
+ ...base,
14143
+ artifactKind: 'chart',
14144
+ changeKind: 'enable_chart_drilldown',
14145
+ capabilityId: 'praxis-chart.drilldown.enable@0.1.0',
14146
+ targetComponentId: 'praxis-chart',
14147
+ selectedComponentId: 'praxis-chart',
14148
+ ...(actionId === 'chart-add-detail-modal'
14149
+ ? {
14150
+ surfacePresentation: 'modal',
14151
+ surfaceActionId: 'surface.open',
14152
+ surfaceWidgetId: 'praxis-table',
14153
+ }
14154
+ : {}),
14155
+ };
14156
+ }
14157
+ if (actionId === 'table-export-selected-rows') {
14158
+ return {
14159
+ ...base,
14160
+ artifactKind: 'table',
14161
+ changeKind: 'configure_export',
14162
+ capabilityId: 'praxis-table.export.selected-rows@0.1.0',
14163
+ targetComponentId: 'praxis-table',
14164
+ selectedComponentId: 'praxis-table',
14165
+ };
14166
+ }
14167
+ return null;
14168
+ }
14169
+ contextualActionCandidate(contextHints) {
14170
+ const resourcePath = this.readString(contextHints, 'resourcePath');
14171
+ if (!resourcePath) {
14172
+ return null;
14173
+ }
14174
+ const submitUrl = this.readString(contextHints, 'submitUrl') || resourcePath;
14175
+ const submitMethod = this.readString(contextHints, 'submitMethod')
14176
+ || this.readString(contextHints, 'operation')
14177
+ || 'get';
14178
+ return {
14179
+ resourcePath,
14180
+ operation: submitMethod,
14181
+ schemaUrl: this.readString(contextHints, 'schemaUrl'),
14182
+ submitUrl,
14183
+ submitMethod,
14184
+ score: 1,
14185
+ reason: 'component capability context',
14186
+ evidence: ['component-capability-catalog'],
14187
+ };
13713
14188
  }
13714
14189
  shouldAutoGenerateGuidedPreview(intentResolution, quickReplies, prompt) {
13715
14190
  if (!this.isGuidedPreviewIntent(intentResolution)) {
@@ -13734,6 +14209,61 @@ class PageBuilderAgenticAuthoringTurnFlow {
13734
14209
  return (artifactKind === 'dashboard' || artifactKind === 'page' || artifactKind === 'table' || artifactKind === 'form')
13735
14210
  && (intentResolution.operationKind === 'compose' || intentResolution.operationKind === 'explore');
13736
14211
  }
14212
+ isConsultativeCatalogIntent(intentResolution) {
14213
+ if (!intentResolution) {
14214
+ return false;
14215
+ }
14216
+ const operationKind = intentResolution.operationKind;
14217
+ const changeKind = intentResolution.changeKind;
14218
+ return (operationKind === 'explore' || operationKind === 'explain')
14219
+ && intentResolution.artifactKind === 'api_catalog'
14220
+ && (changeKind === 'answer_api_catalog_question'
14221
+ || changeKind === 'answer_catalog_question'
14222
+ || changeKind === 'api_catalog_followup'
14223
+ || intentResolution.authoringProfile === 'api-catalog-qa');
14224
+ }
14225
+ resolveShellQuickReplies(intentResolution, quickReplies = intentResolution.quickReplies ?? []) {
14226
+ const effectiveQuickReplies = this.isConsultativeCatalogIntent(intentResolution)
14227
+ ? quickReplies.filter((reply) => !this.isResourceCandidateQuickReply(reply))
14228
+ : this.shouldSuppressWorkflowQuickReplies(intentResolution)
14229
+ ? quickReplies.filter((reply) => !this.isWorkflowQuickReply(reply))
14230
+ : quickReplies;
14231
+ const shellQuickReplies = this.toShellQuickReplies(effectiveQuickReplies);
14232
+ if (shellQuickReplies.length) {
14233
+ return shellQuickReplies;
14234
+ }
14235
+ return this.contextualCapabilityFallbackQuickReplies(intentResolution);
14236
+ }
14237
+ shouldSuppressWorkflowQuickReplies(intentResolution) {
14238
+ if (intentResolution.selectedCandidate || this.isConsultativeCatalogIntent(intentResolution)) {
14239
+ return false;
14240
+ }
14241
+ const operationKind = (intentResolution.operationKind ?? '').trim().toLowerCase();
14242
+ const artifactKind = (intentResolution.artifactKind ?? '').trim().toLowerCase();
14243
+ const changeKind = (intentResolution.changeKind ?? '').trim().toLowerCase();
14244
+ return artifactKind === 'unknown'
14245
+ || operationKind === 'unknown'
14246
+ || changeKind === 'unknown';
14247
+ }
14248
+ isWorkflowQuickReply(reply) {
14249
+ const kind = (reply.kind ?? '').trim().toLowerCase();
14250
+ return kind === 'revise' || kind === 'cancel' || kind === 'confirm';
14251
+ }
14252
+ isResourceCandidateQuickReply(reply) {
14253
+ const kind = (reply.kind ?? '').trim().toLowerCase();
14254
+ if (kind !== 'suggestion') {
14255
+ return false;
14256
+ }
14257
+ const contextHints = this.toJsonObject(reply.contextHints);
14258
+ if (this.isContextualPreviewActionReply(reply, contextHints)) {
14259
+ return false;
14260
+ }
14261
+ return !!contextHints
14262
+ && (!!contextHints['resourcePath']
14263
+ || !!contextHints['resourceKey']
14264
+ || !!contextHints['submitUrl']
14265
+ || !!contextHints['schemaUrl']);
14266
+ }
13737
14267
  isExplicitPreviewCreationPrompt(prompt) {
13738
14268
  const normalized = prompt
13739
14269
  .normalize('NFD')
@@ -13838,7 +14368,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
13838
14368
  toShellQuickReplies(quickReplies) {
13839
14369
  return quickReplies
13840
14370
  .filter((reply) => !!reply.id && !!reply.label && (!!reply.prompt || reply.kind === 'cancel'))
13841
- .map((reply) => ({
14371
+ .map((reply) => this.enrichShellQuickReply({
13842
14372
  id: reply.id,
13843
14373
  kind: reply.kind,
13844
14374
  label: reply.label,
@@ -13846,9 +14376,334 @@ class PageBuilderAgenticAuthoringTurnFlow {
13846
14376
  description: reply.description,
13847
14377
  icon: reply.icon,
13848
14378
  tone: reply.tone,
14379
+ presentation: null,
13849
14380
  contextHints: this.toJsonObject(reply.contextHints),
13850
14381
  }));
13851
14382
  }
14383
+ contextualCapabilityFallbackQuickReplies(intentResolution) {
14384
+ if (!this.shouldOfferContextualCapabilityActions(intentResolution)) {
14385
+ return [];
14386
+ }
14387
+ const componentContext = this.resolveCurrentComponentContext(intentResolution);
14388
+ if (componentContext?.componentId !== 'praxis-chart') {
14389
+ return [];
14390
+ }
14391
+ return [
14392
+ this.contextualCapabilityQuickReply({
14393
+ id: 'chart-change-line',
14394
+ label: this.context.tx('agentic.quickReplies.chartChangeLine.label', 'Trocar para linhas'),
14395
+ prompt: this.context.tx('agentic.quickReplies.chartChangeLine.prompt', 'Altere o gráfico selecionado para linhas.'),
14396
+ icon: 'show_chart',
14397
+ changeKind: 'set_chart_type',
14398
+ chartType: 'line',
14399
+ capabilityId: 'praxis-chart.type.set@0.1.0',
14400
+ widgetKey: componentContext.widgetKey,
14401
+ }),
14402
+ this.contextualCapabilityQuickReply({
14403
+ id: 'chart-change-donut',
14404
+ label: this.context.tx('agentic.quickReplies.chartChangeDonut.label', 'Ver como donut'),
14405
+ prompt: this.context.tx('agentic.quickReplies.chartChangeDonut.prompt', 'Altere o gráfico selecionado para donut.'),
14406
+ icon: 'donut_large',
14407
+ changeKind: 'set_chart_type',
14408
+ chartType: 'donut',
14409
+ capabilityId: 'praxis-chart.type.set@0.1.0',
14410
+ widgetKey: componentContext.widgetKey,
14411
+ }),
14412
+ this.contextualCapabilityQuickReply({
14413
+ id: 'chart-add-detail-table',
14414
+ label: this.context.tx('agentic.quickReplies.chartAddDetailTable.label', 'Detalhes em tabela'),
14415
+ prompt: this.context.tx('agentic.quickReplies.chartAddDetailTable.prompt', 'Adicione uma tabela de detalhes para a seleção do gráfico.'),
14416
+ icon: 'table_view',
14417
+ changeKind: 'enable_chart_drilldown',
14418
+ capabilityId: 'praxis-chart.drilldown.enable@0.1.0',
14419
+ widgetKey: componentContext.widgetKey,
14420
+ }),
14421
+ ];
14422
+ }
14423
+ contextualCapabilityQuickReply(options) {
14424
+ return this.enrichContextualActionQuickReply({
14425
+ id: options.id,
14426
+ kind: 'suggestion',
14427
+ label: options.label,
14428
+ prompt: options.prompt,
14429
+ icon: options.icon,
14430
+ tone: 'analytics',
14431
+ contextHints: {
14432
+ source: 'component-capability-catalog',
14433
+ kind: 'contextual-preview-action',
14434
+ operationKind: 'modify',
14435
+ artifactKind: 'chart',
14436
+ changeKind: options.changeKind,
14437
+ ...(options.chartType ? { chartType: options.chartType } : {}),
14438
+ capabilityId: options.capabilityId,
14439
+ targetComponentId: 'praxis-chart',
14440
+ selectedComponentId: 'praxis-chart',
14441
+ ...(options.widgetKey ? { selectedWidgetKey: options.widgetKey } : {}),
14442
+ },
14443
+ });
14444
+ }
14445
+ shouldOfferContextualCapabilityActions(intentResolution) {
14446
+ if (this.isConsultativeCatalogIntent(intentResolution)) {
14447
+ return false;
14448
+ }
14449
+ const operationKind = (intentResolution.operationKind ?? '').trim().toLowerCase();
14450
+ const artifactKind = (intentResolution.artifactKind ?? '').trim().toLowerCase();
14451
+ const changeKind = (intentResolution.changeKind ?? '').trim().toLowerCase();
14452
+ if (operationKind !== 'explore' && operationKind !== 'explain') {
14453
+ return false;
14454
+ }
14455
+ if (artifactKind === 'chart') {
14456
+ return true;
14457
+ }
14458
+ return changeKind.includes('chart')
14459
+ || changeKind.includes('component')
14460
+ || !!this.resolveCurrentComponentContext(intentResolution);
14461
+ }
14462
+ resolveCurrentComponentContext(intentResolution) {
14463
+ const contextHints = this.toJsonObject(intentResolution.contextHints);
14464
+ const targetComponentId = this.readString(contextHints, 'targetComponentId')
14465
+ || this.readString(contextHints, 'selectedComponentId')
14466
+ || intentResolution.target?.componentId
14467
+ || '';
14468
+ const targetWidgetKey = this.readString(contextHints, 'selectedWidgetKey')
14469
+ || intentResolution.target?.widgetKey
14470
+ || this.context.selectedWidgetKey()
14471
+ || '';
14472
+ if (targetComponentId) {
14473
+ return { componentId: targetComponentId, widgetKey: targetWidgetKey || null };
14474
+ }
14475
+ const page = this.currentPageRecord();
14476
+ const widgets = Array.isArray(page?.['widgets']) ? page['widgets'] : [];
14477
+ const selectedWidget = targetWidgetKey
14478
+ ? widgets.find((widget) => this.readWidgetKey(widget) === targetWidgetKey)
14479
+ : null;
14480
+ const selectedComponentId = selectedWidget ? this.readWidgetComponentId(selectedWidget) : '';
14481
+ if (selectedComponentId) {
14482
+ return { componentId: selectedComponentId, widgetKey: targetWidgetKey || null };
14483
+ }
14484
+ const chartWidget = widgets.find((widget) => this.readWidgetComponentId(widget) === 'praxis-chart');
14485
+ if (chartWidget) {
14486
+ return {
14487
+ componentId: 'praxis-chart',
14488
+ widgetKey: this.readWidgetKey(chartWidget) || null,
14489
+ };
14490
+ }
14491
+ return null;
14492
+ }
14493
+ currentPageRecord() {
14494
+ const page = this.context.currentPage();
14495
+ return page && typeof page === 'object' && !Array.isArray(page)
14496
+ ? page
14497
+ : null;
14498
+ }
14499
+ readWidgetKey(widget) {
14500
+ const record = widget && typeof widget === 'object' && !Array.isArray(widget)
14501
+ ? widget
14502
+ : null;
14503
+ const key = record?.['key'];
14504
+ return typeof key === 'string' ? key.trim() : '';
14505
+ }
14506
+ readWidgetComponentId(widget) {
14507
+ const record = widget && typeof widget === 'object' && !Array.isArray(widget)
14508
+ ? widget
14509
+ : null;
14510
+ const definition = record?.['definition'];
14511
+ const definitionRecord = definition && typeof definition === 'object' && !Array.isArray(definition)
14512
+ ? definition
14513
+ : null;
14514
+ const id = definitionRecord?.['id'];
14515
+ return typeof id === 'string' ? id.trim() : '';
14516
+ }
14517
+ enrichShellQuickReply(reply) {
14518
+ if (this.isContextualPreviewActionReply(reply, this.toJsonObject(reply.contextHints))) {
14519
+ return this.enrichContextualActionQuickReply(reply);
14520
+ }
14521
+ if (!this.isResourceQuickReply(reply)) {
14522
+ return reply;
14523
+ }
14524
+ const contextHints = { ...(reply.contextHints ?? {}) };
14525
+ if (!this.hasQuickReplyPresentation(contextHints)) {
14526
+ contextHints['presentation'] = this.resourceQuickReplyPresentation(reply);
14527
+ }
14528
+ return {
14529
+ ...reply,
14530
+ description: this.resourceQuickReplyDescription(reply),
14531
+ icon: reply.icon || 'dataset',
14532
+ tone: reply.tone || 'resource',
14533
+ contextHints,
14534
+ };
14535
+ }
14536
+ enrichContextualActionQuickReply(reply) {
14537
+ const contextHints = this.toJsonObject(reply.contextHints) ?? {};
14538
+ const presentation = {
14539
+ kind: 'contextual-action',
14540
+ categoryLabel: this.context.tx('agentic.quickReplies.contextualAction.category', 'Ação sugerida'),
14541
+ description: this.contextualActionDescription(reply, contextHints),
14542
+ ctaLabel: this.context.tx('agentic.quickReplies.contextualAction.cta', 'Pré-visualizar ajuste'),
14543
+ icon: reply.icon || this.contextualActionIcon(reply, contextHints),
14544
+ tone: reply.tone || 'analytics',
14545
+ evidence: this.contextualActionEvidence(contextHints),
14546
+ };
14547
+ return {
14548
+ ...reply,
14549
+ description: presentation.description,
14550
+ icon: presentation.icon,
14551
+ tone: presentation.tone,
14552
+ presentation,
14553
+ };
14554
+ }
14555
+ contextualActionDescription(reply, contextHints) {
14556
+ const existing = reply.description?.trim() ?? '';
14557
+ if (existing && !this.isGenericContextualActionDescription(existing)) {
14558
+ return existing;
14559
+ }
14560
+ const changeKind = this.readString(contextHints, 'changeKind');
14561
+ switch (changeKind) {
14562
+ case 'set_chart_type':
14563
+ return this.context.tx('agentic.quickReplies.contextualAction.chartType.description', 'Altera apenas a apresentação do gráfico selecionado e mantém a fonte de dados atual.');
14564
+ case 'enable_chart_drilldown':
14565
+ return this.context.tx('agentic.quickReplies.contextualAction.chartDrilldown.description', 'Adiciona uma superfície de detalhe a partir da seleção do gráfico, preservando o contexto do dado.');
14566
+ case 'configure_export':
14567
+ return this.context.tx('agentic.quickReplies.contextualAction.export.description', 'Configura uma ação operacional para exportar a seleção atual sem mudar a consulta base.');
14568
+ default:
14569
+ return this.context.tx('agentic.quickReplies.contextualAction.default.description', 'Prepara um ajuste compatível com as capacidades confirmadas do componente selecionado.');
14570
+ }
14571
+ }
14572
+ contextualActionIcon(reply, contextHints) {
14573
+ const changeKind = this.readString(contextHints, 'changeKind');
14574
+ const chartType = this.readString(contextHints, 'chartType')
14575
+ || this.readString(contextHints, 'targetChartType');
14576
+ const actionId = reply.id?.trim() ?? '';
14577
+ if (changeKind === 'set_chart_type') {
14578
+ return chartType === 'donut' || actionId === 'chart-change-donut'
14579
+ ? 'donut_large'
14580
+ : 'show_chart';
14581
+ }
14582
+ if (changeKind === 'enable_chart_drilldown')
14583
+ return 'table_view';
14584
+ if (changeKind === 'configure_export')
14585
+ return 'ios_share';
14586
+ return 'auto_fix_high';
14587
+ }
14588
+ contextualActionEvidence(contextHints) {
14589
+ const evidence = [];
14590
+ const targetComponentId = this.readString(contextHints, 'targetComponentId')
14591
+ || this.readString(contextHints, 'selectedComponentId');
14592
+ const changeKind = this.readString(contextHints, 'changeKind');
14593
+ const capabilityId = this.readString(contextHints, 'capabilityId');
14594
+ const selectedWidgetKey = this.readString(contextHints, 'selectedWidgetKey');
14595
+ if (targetComponentId) {
14596
+ evidence.push({
14597
+ icon: 'widgets',
14598
+ value: this.shortTechnicalLabel(targetComponentId),
14599
+ ariaLabel: this.context.tx('agentic.quickReplies.contextualAction.componentEvidence', 'Componente {value}').replace('{value}', targetComponentId),
14600
+ });
14601
+ }
14602
+ if (changeKind) {
14603
+ evidence.push({
14604
+ icon: 'rule',
14605
+ value: this.shortTechnicalLabel(changeKind),
14606
+ ariaLabel: this.context.tx('agentic.quickReplies.contextualAction.changeEvidence', 'Mudança {value}').replace('{value}', changeKind),
14607
+ });
14608
+ }
14609
+ if (capabilityId) {
14610
+ evidence.push({
14611
+ icon: 'verified',
14612
+ value: this.context.tx('agentic.quickReplies.contextualAction.capabilityEvidence', 'capability'),
14613
+ ariaLabel: capabilityId,
14614
+ });
14615
+ }
14616
+ if (!capabilityId && selectedWidgetKey) {
14617
+ evidence.push({
14618
+ icon: 'ads_click',
14619
+ value: this.context.tx('agentic.quickReplies.contextualAction.selectionEvidence', 'seleção atual'),
14620
+ ariaLabel: selectedWidgetKey,
14621
+ });
14622
+ }
14623
+ return evidence.slice(0, 4);
14624
+ }
14625
+ isResourceQuickReply(reply) {
14626
+ const kind = (reply.kind || '').trim().toLowerCase();
14627
+ const id = (reply.id || '').trim().toLowerCase();
14628
+ const contextHints = this.toJsonObject(reply.contextHints);
14629
+ if (this.isContextualPreviewActionReply(reply, contextHints)) {
14630
+ return false;
14631
+ }
14632
+ return kind === 'resource'
14633
+ || id.startsWith('resource-')
14634
+ || !!this.readString(contextHints, 'resourcePath');
14635
+ }
14636
+ isContextualPreviewActionReply(reply, contextHints) {
14637
+ const hintSource = typeof contextHints?.['source'] === 'string'
14638
+ ? contextHints['source'].trim()
14639
+ : '';
14640
+ const hintKind = typeof contextHints?.['kind'] === 'string'
14641
+ ? contextHints['kind'].trim()
14642
+ : '';
14643
+ return hintSource === 'component-capability-catalog'
14644
+ || hintKind === 'contextual-preview-action'
14645
+ || (reply.id ?? '').startsWith('chart-')
14646
+ || (reply.id ?? '').startsWith('table-export-');
14647
+ }
14648
+ hasQuickReplyPresentation(contextHints) {
14649
+ const presentation = contextHints['presentation'];
14650
+ if (!presentation || Array.isArray(presentation) || typeof presentation !== 'object') {
14651
+ return false;
14652
+ }
14653
+ return ['bestFor', 'returns', 'nextStep']
14654
+ .some((key) => typeof presentation[key] === 'string'
14655
+ && !!String(presentation[key]).trim());
14656
+ }
14657
+ resourceQuickReplyDescription(reply) {
14658
+ const description = reply.description?.trim() ?? '';
14659
+ if (description
14660
+ && !this.isTechnicalResourceDescription(description)
14661
+ && !this.isGenericResourceDescription(description)) {
14662
+ return description;
14663
+ }
14664
+ return this.context.tx('agentic.resourceDiscovery.cardDescription', 'Fonte recomendada para transformar {label} em painel: ajuda a escolher graficos, listas, filtros e formatos antes de materializar a tela.').replace('{label}', reply.label);
14665
+ }
14666
+ resourceQuickReplyPresentation(reply) {
14667
+ const contextHints = this.toJsonObject(reply.contextHints);
14668
+ const artifactKind = this.readString(contextHints, 'artifactKind');
14669
+ if (artifactKind === 'table') {
14670
+ return {
14671
+ bestFor: `Boa quando voce quer transformar ${reply.label} em uma tabela navegavel.`,
14672
+ returns: 'Retorna uma pre-visualizacao com colunas, filtros e fonte semantica preservada.',
14673
+ nextStep: 'Clique para criar a tabela e revisar antes de salvar.',
14674
+ };
14675
+ }
14676
+ return {
14677
+ bestFor: this.context.tx('agentic.resourceDiscovery.cardBestFor', 'Quando voce quer entender se {label} responde ao objetivo de negocio antes de criar widgets.').replace('{label}', reply.label),
14678
+ returns: this.context.tx('agentic.resourceDiscovery.cardReturns', 'Sugere metricas, dimensoes, filtros, formatos de valor, graficos e listas de detalhe compativeis com a fonte.'),
14679
+ nextStep: this.context.tx('agentic.resourceDiscovery.cardNextStep', 'Selecione para eu propor uma pre-visualizacao governada com cards ricos, drill-down e formatos adequados por padrao.'),
14680
+ };
14681
+ }
14682
+ isTechnicalResourceDescription(description) {
14683
+ return /(?:^|\s)(?:GET|POST|PUT|PATCH|DELETE)\s+\//iu.test(description)
14684
+ || /\/api\//iu.test(description)
14685
+ || /\/schemas\//iu.test(description);
14686
+ }
14687
+ isGenericResourceDescription(description) {
14688
+ return /op(?:c|ç)ao encontrada no cat(?:a|á)logo sem(?:a|â)ntico/iu.test(description)
14689
+ || /fonte candidata encontrada no cat(?:a|á)logo/iu.test(description);
14690
+ }
14691
+ isGenericContextualActionDescription(description) {
14692
+ const normalized = description
14693
+ .normalize('NFD')
14694
+ .replace(/[\u0300-\u036f]/g, '')
14695
+ .toLocaleLowerCase('pt-BR');
14696
+ return normalized.includes('acao sugerida')
14697
+ && normalized.includes('capacidades confirmadas');
14698
+ }
14699
+ shortTechnicalLabel(value) {
14700
+ return value
14701
+ .trim()
14702
+ .replace(/^praxis-/u, '')
14703
+ .replace(/@.*$/u, '')
14704
+ .replace(/[_-]+/gu, ' ')
14705
+ .trim();
14706
+ }
13852
14707
  buildPendingClarificationForNextTurn(request, sourcePrompt, clarification) {
13853
14708
  return this.buildPendingClarification(sourcePrompt, clarification, request.clientTurnId);
13854
14709
  }
@@ -13923,7 +14778,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
13923
14778
  targetApp: this.context.targetApp,
13924
14779
  targetComponentId: this.context.targetComponentId,
13925
14780
  currentPage: this.context.currentPage(),
13926
- selectedWidgetKey,
14781
+ selectedWidgetKey: this.resolveSelectedWidgetKey(selectedWidgetKey, authoringContext.contextHints),
13927
14782
  provider: this.context.provider(),
13928
14783
  model: this.context.model(),
13929
14784
  apiKey: this.context.apiKey(),
@@ -13931,6 +14786,12 @@ class PageBuilderAgenticAuthoringTurnFlow {
13931
14786
  ...authoringContext,
13932
14787
  };
13933
14788
  }
14789
+ resolveSelectedWidgetKey(selectedWidgetKey, contextHints) {
14790
+ const hints = this.toJsonObject(contextHints) ?? null;
14791
+ return this.readString(hints, 'selectedWidgetKey')
14792
+ || this.readString(hints, 'targetWidgetKey')
14793
+ || selectedWidgetKey;
14794
+ }
13934
14795
  buildContextHints(request) {
13935
14796
  const base = this.toJsonObject(request.action?.contextHints)
13936
14797
  ?? this.toJsonObject(request.contextHints);
@@ -14173,6 +15034,8 @@ class DynamicPageBuilderComponent {
14173
15034
  agenticAuthoringStatus = signal('', ...(ngDevMode ? [{ debugName: "agenticAuthoringStatus" }] : []));
14174
15035
  agenticAuthoringError = signal('', ...(ngDevMode ? [{ debugName: "agenticAuthoringError" }] : []));
14175
15036
  agenticAuthoringPreviewResult = signal(null, ...(ngDevMode ? [{ debugName: "agenticAuthoringPreviewResult" }] : []));
15037
+ agenticAuthoringSemanticDecision = signal(null, ...(ngDevMode ? [{ debugName: "agenticAuthoringSemanticDecision" }] : []));
15038
+ agenticAuthoringCanApply = signal(false, ...(ngDevMode ? [{ debugName: "agenticAuthoringCanApply" }] : []));
14176
15039
  agenticAuthoringLastEtag = signal(null, ...(ngDevMode ? [{ debugName: "agenticAuthoringLastEtag" }] : []));
14177
15040
  agenticAuthoringConversation = signal([], ...(ngDevMode ? [{ debugName: "agenticAuthoringConversation" }] : []));
14178
15041
  agenticAuthoringQuickReplies = signal([], ...(ngDevMode ? [{ debugName: "agenticAuthoringQuickReplies" }] : []));
@@ -14198,12 +15061,12 @@ class DynamicPageBuilderComponent {
14198
15061
  agenticAuthoringEditingMessageId = signal(null, ...(ngDevMode ? [{ debugName: "agenticAuthoringEditingMessageId" }] : []));
14199
15062
  selectedWidgetKey = signal(null, ...(ngDevMode ? [{ debugName: "selectedWidgetKey" }] : []));
14200
15063
  agenticAuthoringWidgetContextKey = signal(null, ...(ngDevMode ? [{ debugName: "agenticAuthoringWidgetContextKey" }] : []));
14201
- agenticAuthoringPanelLayout = signal({
14202
- left: 16,
14203
- top: 16,
15064
+ agenticAuthoringPanelLayout = signal(createPraxisAssistantViewportLayout({
14204
15065
  width: 440,
14205
- height: 560,
14206
- }, ...(ngDevMode ? [{ debugName: "agenticAuthoringPanelLayout" }] : []));
15066
+ height: 620,
15067
+ top: 96,
15068
+ margin: 24,
15069
+ }), ...(ngDevMode ? [{ debugName: "agenticAuthoringPanelLayout" }] : []));
14207
15070
  previewMode = false;
14208
15071
  agenticComponentCapabilities;
14209
15072
  agenticComponentCapabilitiesPromise;
@@ -14429,7 +15292,7 @@ class DynamicPageBuilderComponent {
14429
15292
  if (this.resolveSelectedWidgetKey()) {
14430
15293
  return this.tx('agentic.header.title.widget', 'Praxis widget copilot');
14431
15294
  }
14432
- return this.tx('agentic.header.title.page', 'Praxis page copilot');
15295
+ return this.tx('agentic.header.title.page', 'Praxis page decision copilot');
14433
15296
  }
14434
15297
  agenticAuthoringHeaderSubtitle() {
14435
15298
  const selectedWidgetLabel = this.resolveSelectedWidgetLabel();
@@ -14437,6 +15300,9 @@ class DynamicPageBuilderComponent {
14437
15300
  return this.tx('agentic.header.subtitle.governed', 'Continue the governed semantic-decision flow.');
14438
15301
  }
14439
15302
  if (this.agenticAuthoringPreviewResult()?.valid) {
15303
+ if (!this.agenticAuthoringCanApply()) {
15304
+ return this.tx('agentic.header.subtitle.reviewBlocked', 'Preview ready for governed review.');
15305
+ }
14440
15306
  return this.tx('agentic.header.subtitle.review', 'Preview ready for review and persistence.');
14441
15307
  }
14442
15308
  if (selectedWidgetLabel) {
@@ -14448,7 +15314,7 @@ class DynamicPageBuilderComponent {
14448
15314
  return this.tx('agentic.header.subtitle.route', 'Authoring page route {route}.')
14449
15315
  .replace('{route}', routePath);
14450
15316
  }
14451
- return this.tx('agentic.header.subtitle.page', 'Author page-level layout, widgets and governed materialization.');
15317
+ return this.tx('agentic.header.subtitle.page', 'Turn intent into layout, widgets, and governed materializations.');
14452
15318
  }
14453
15319
  agenticAuthoringHeaderModeLabel() {
14454
15320
  if (this.agenticAuthoringSharedRuleHandoffState()) {
@@ -14466,7 +15332,7 @@ class DynamicPageBuilderComponent {
14466
15332
  close: this.tx('agentic.minimize', 'Minimize'),
14467
15333
  prompt: this.tx('agentic.promptLabel', 'Message'),
14468
15334
  promptPlaceholder: this.tx('agentic.promptPlaceholder', 'Describe the page, dashboard, form or change you need.'),
14469
- emptyConversation: this.tx('agentic.emptyConversation', 'Tell me what you want to create or change. I will ask follow-up questions before applying the preview.'),
15335
+ emptyConversation: this.agenticAuthoringEmptyConversationMessage(),
14470
15336
  submit: this.tx('agentic.preview', 'Generate preview'),
14471
15337
  apply: this.tx('agentic.persist', 'Save'),
14472
15338
  conversationAria: this.tx('agentic.conversationAria', 'AI conversation'),
@@ -14485,7 +15351,7 @@ class DynamicPageBuilderComponent {
14485
15351
  modeDiagnostic: this.tx('agentic.mode.diagnostic', 'Diagnostic'),
14486
15352
  modeReview: this.tx('agentic.mode.review', 'Review'),
14487
15353
  modeInlineHelp: this.tx('agentic.mode.inlineHelp', 'Help'),
14488
- stateIdle: this.tx('agentic.state.idle', 'Idle'),
15354
+ stateIdle: this.tx('agentic.state.idle', 'Ready'),
14489
15355
  stateListening: this.tx('agentic.state.listening', 'Ready'),
14490
15356
  stateProcessing: this.tx('agentic.state.processing', 'Processing'),
14491
15357
  stateClarification: this.tx('agentic.state.clarification', 'Waiting for input'),
@@ -14495,6 +15361,39 @@ class DynamicPageBuilderComponent {
14495
15361
  stateError: this.tx('agentic.state.error', 'Error'),
14496
15362
  };
14497
15363
  }
15364
+ agenticAuthoringEmptyConversationMessage() {
15365
+ const authoredOpening = this.resolveAgenticAuthoredOpeningMessage();
15366
+ if (authoredOpening) {
15367
+ return authoredOpening;
15368
+ }
15369
+ if (this.isAgenticAuthoringPageBlank()) {
15370
+ return this.tx('agentic.emptyConversation.blankGeneric', 'This host page is still blank. Tell me what decision or activity this app needs to support. I can suggest a dashboard, table, form, or review flow, then turn it into a governed preview for you to review before anything changes.');
15371
+ }
15372
+ return this.tx('agentic.emptyConversation.existingPage', 'Tell me what you want to improve here. I can read the current layout, widgets, route, and governed context, then prepare a preview for you to review before anything changes.');
15373
+ }
15374
+ resolveAgenticAuthoredOpeningMessage() {
15375
+ const hints = this.toRecord(this.agenticAuthoringContextHints);
15376
+ if (!hints)
15377
+ return null;
15378
+ const candidateRecords = [
15379
+ hints,
15380
+ this.toRecord(hints['domainOpening']),
15381
+ this.toRecord(hints['ragOpening']),
15382
+ this.toRecord(hints['opening']),
15383
+ this.toRecord(hints['domainSummary']),
15384
+ ];
15385
+ for (const record of candidateRecords) {
15386
+ const message = this.trimmedString(record?.['openingMessage'])
15387
+ || this.trimmedString(record?.['message']);
15388
+ if (message)
15389
+ return message;
15390
+ }
15391
+ return null;
15392
+ }
15393
+ isAgenticAuthoringPageBlank() {
15394
+ const widgets = this.currentPage().widgets;
15395
+ return !Array.isArray(widgets) || widgets.length === 0;
15396
+ }
14498
15397
  agenticAuthoringSubmitAction() {
14499
15398
  const label = this.tx('agentic.preview', 'Generate preview');
14500
15399
  return {
@@ -14585,6 +15484,8 @@ class DynamicPageBuilderComponent {
14585
15484
  this.agenticAuthoringStatus.set('');
14586
15485
  this.agenticAuthoringError.set('');
14587
15486
  this.agenticAuthoringPreviewResult.set(null);
15487
+ this.agenticAuthoringSemanticDecision.set(null);
15488
+ this.agenticAuthoringCanApply.set(false);
14588
15489
  this.agenticAuthoringConversation.set([]);
14589
15490
  this.agenticAuthoringQuickReplies.set([]);
14590
15491
  this.agenticAuthoringAttachments.set([]);
@@ -14830,6 +15731,7 @@ class DynamicPageBuilderComponent {
14830
15731
  });
14831
15732
  }
14832
15733
  }
15734
+ items.push(...this.agenticAuthoringSemanticDecisionContextItems());
14833
15735
  const handoff = this.agenticAuthoringSharedRuleHandoffState();
14834
15736
  if (handoff) {
14835
15737
  items.push({
@@ -14921,6 +15823,138 @@ class DynamicPageBuilderComponent {
14921
15823
  }
14922
15824
  return items;
14923
15825
  }
15826
+ agenticAuthoringSemanticDecisionContextItems() {
15827
+ const semanticDecision = this.toRecord(this.agenticAuthoringSemanticDecision());
15828
+ if (!semanticDecision) {
15829
+ return [];
15830
+ }
15831
+ const items = [];
15832
+ const selectedResource = this.toRecord(semanticDecision['selectedResource']);
15833
+ const resourcePath = this.trimmedString(selectedResource?.['resourcePath']);
15834
+ const operationKind = this.trimmedString(semanticDecision['operationKind']);
15835
+ const artifactKind = this.trimmedString(semanticDecision['artifactKind']);
15836
+ const changeKind = this.trimmedString(semanticDecision['changeKind']);
15837
+ if (this.shouldHideSemanticDecisionContextItems(operationKind, artifactKind, changeKind, resourcePath)) {
15838
+ return items;
15839
+ }
15840
+ if (resourcePath) {
15841
+ items.push({
15842
+ id: 'semantic-decision-resource',
15843
+ kind: 'custom',
15844
+ label: this.tx('agentic.context.semanticDecisionResource', 'Fonte'),
15845
+ value: this.humanizeAgenticResourcePath(resourcePath),
15846
+ icon: 'dataset',
15847
+ });
15848
+ }
15849
+ const decisionSummary = [operationKind, artifactKind, changeKind]
15850
+ .filter((value) => !!value)
15851
+ .join(' · ');
15852
+ if (decisionSummary) {
15853
+ items.push({
15854
+ id: 'semantic-decision-kind',
15855
+ kind: 'custom',
15856
+ label: this.tx('agentic.context.semanticDecisionKind', 'Objetivo'),
15857
+ value: this.humanizeAgenticDecisionSummary(operationKind ?? '', artifactKind ?? '', changeKind ?? ''),
15858
+ icon: 'account_tree',
15859
+ });
15860
+ }
15861
+ const retrievedEvidence = this.toRecord(semanticDecision['retrievedEvidence']);
15862
+ const retrievalEvidence = this.toRecord(semanticDecision['retrievalEvidence']);
15863
+ const retrievalSource = this.trimmedString(retrievedEvidence?.['retrievalSource'])
15864
+ || this.trimmedString(retrievalEvidence?.['retrievalSource']);
15865
+ const reviewReason = this.trimmedString(semanticDecision['reviewReason']);
15866
+ const confidence = typeof semanticDecision['confidence'] === 'number'
15867
+ ? semanticDecision['confidence']
15868
+ : null;
15869
+ const evidenceSummary = this.humanizeAgenticDecisionEvidence(retrievalSource ?? '', reviewReason ?? '', confidence);
15870
+ if (evidenceSummary) {
15871
+ items.push({
15872
+ id: 'semantic-decision-evidence',
15873
+ kind: 'custom',
15874
+ label: this.tx('agentic.context.semanticDecisionEvidence', 'Revisão'),
15875
+ value: evidenceSummary,
15876
+ icon: reviewReason ? 'policy' : 'verified',
15877
+ });
15878
+ }
15879
+ return items;
15880
+ }
15881
+ shouldHideSemanticDecisionContextItems(operationKind, artifactKind, changeKind, resourcePath) {
15882
+ const operation = (operationKind ?? '').trim().toLowerCase();
15883
+ const artifact = (artifactKind ?? '').trim().toLowerCase();
15884
+ const change = (changeKind ?? '').trim().toLowerCase();
15885
+ return artifact === 'unknown'
15886
+ || artifact === 'api_catalog'
15887
+ || operation === 'explore'
15888
+ || operation === 'explain'
15889
+ || change === 'answer_api_catalog_question'
15890
+ || change === 'answer_catalog_question'
15891
+ || change === 'api_catalog_followup';
15892
+ }
15893
+ humanizeAgenticResourcePath(resourcePath) {
15894
+ const lastSegment = resourcePath.split('?')[0].split('/').filter(Boolean).pop() || resourcePath;
15895
+ return lastSegment
15896
+ .replace(/^vw[-_]/i, '')
15897
+ .replace(/[-_]+/g, ' ')
15898
+ .replace(/\b\w/g, (char) => char.toUpperCase());
15899
+ }
15900
+ humanizeAgenticDecisionSummary(operationKind, artifactKind, changeKind) {
15901
+ const operation = this.humanizeAgenticOperationKind(operationKind);
15902
+ const artifact = this.humanizeAgenticArtifactKind(artifactKind);
15903
+ const change = this.humanizeAgenticChangeKind(changeKind);
15904
+ return [operation, artifact, change].filter((value) => !!value).join(' · ');
15905
+ }
15906
+ humanizeAgenticOperationKind(value) {
15907
+ const normalized = value.trim().toLowerCase();
15908
+ if (normalized === 'create')
15909
+ return this.tx('agentic.context.operationCreate', 'Criar');
15910
+ if (normalized === 'update')
15911
+ return this.tx('agentic.context.operationUpdate', 'Ajustar');
15912
+ if (normalized === 'read')
15913
+ return this.tx('agentic.context.operationRead', 'Consultar');
15914
+ return this.humanizeAgenticToken(value);
15915
+ }
15916
+ humanizeAgenticArtifactKind(value) {
15917
+ const normalized = value.trim().toLowerCase();
15918
+ if (normalized === 'dashboard')
15919
+ return this.tx('agentic.context.artifactDashboard', 'dashboard');
15920
+ if (normalized === 'table')
15921
+ return this.tx('agentic.context.artifactTable', 'tabela');
15922
+ if (normalized === 'form')
15923
+ return this.tx('agentic.context.artifactForm', 'formulário');
15924
+ if (normalized === 'page')
15925
+ return this.tx('agentic.context.artifactPage', 'tela');
15926
+ return this.humanizeAgenticToken(value).toLowerCase();
15927
+ }
15928
+ humanizeAgenticChangeKind(value) {
15929
+ const normalized = value.trim().toLowerCase();
15930
+ if (normalized.includes('analytics'))
15931
+ return this.tx('agentic.context.changeAnalytics', 'com análise');
15932
+ if (normalized.includes('dashboard'))
15933
+ return this.tx('agentic.context.changeDashboard', 'com visão gerencial');
15934
+ if (normalized.includes('table'))
15935
+ return this.tx('agentic.context.changeTable', 'com detalhes');
15936
+ if (normalized.includes('form'))
15937
+ return this.tx('agentic.context.changeForm', 'com edição');
15938
+ return this.humanizeAgenticToken(value).toLowerCase();
15939
+ }
15940
+ humanizeAgenticDecisionEvidence(retrievalSource, reviewReason, confidence) {
15941
+ if (reviewReason) {
15942
+ return this.tx('agentic.context.evidenceReviewRequired', 'Precisa revisar campos');
15943
+ }
15944
+ if (confidence !== null && confidence < 0.7) {
15945
+ return this.tx('agentic.context.evidenceLowConfidence', 'Precisa confirmar fonte');
15946
+ }
15947
+ if (retrievalSource) {
15948
+ return this.tx('agentic.context.evidenceGrounded', 'Fonte confirmada');
15949
+ }
15950
+ return '';
15951
+ }
15952
+ humanizeAgenticToken(value) {
15953
+ return value
15954
+ .trim()
15955
+ .replace(/[-_]+/g, ' ')
15956
+ .replace(/\b\w/g, (char) => char.toUpperCase());
15957
+ }
14924
15958
  async previewAgenticAuthoring() {
14925
15959
  const prompt = this.agenticAuthoringPrompt().trim();
14926
15960
  if (!prompt || this.agenticAuthoringBusy())
@@ -14928,6 +15962,7 @@ class DynamicPageBuilderComponent {
14928
15962
  this.agenticAuthoringBusy.set(true);
14929
15963
  this.agenticAuthoringError.set('');
14930
15964
  this.agenticAuthoringPreviewResult.set(null);
15965
+ this.agenticAuthoringCanApply.set(false);
14931
15966
  this.agenticAuthoringSharedRuleHandoffState.set(null);
14932
15967
  this.clearSharedRuleCockpitState();
14933
15968
  this.clearProjectKnowledgeCockpitState();
@@ -14939,6 +15974,7 @@ class DynamicPageBuilderComponent {
14939
15974
  ? controller.submitEditedMessage(editingMessageId, prompt)
14940
15975
  : controller.submitPrompt(prompt));
14941
15976
  this.agenticAuthoringEditingMessageId.set(null);
15977
+ this.agenticAuthoringPrompt.set('');
14942
15978
  }
14943
15979
  catch (error) {
14944
15980
  this.agenticAuthoringStatus.set('');
@@ -14975,6 +16011,7 @@ class DynamicPageBuilderComponent {
14975
16011
  this.agenticAuthoringBusy.set(true);
14976
16012
  this.agenticAuthoringError.set('');
14977
16013
  this.agenticAuthoringPreviewResult.set(null);
16014
+ this.agenticAuthoringCanApply.set(false);
14978
16015
  this.agenticAuthoringSharedRuleHandoffState.set(null);
14979
16016
  this.clearSharedRuleCockpitState();
14980
16017
  this.clearProjectKnowledgeCockpitState();
@@ -14992,6 +16029,7 @@ class DynamicPageBuilderComponent {
14992
16029
  displayPrompt: visiblePrompt,
14993
16030
  contextHints,
14994
16031
  }));
16032
+ this.agenticAuthoringPrompt.set('');
14995
16033
  }
14996
16034
  catch (error) {
14997
16035
  this.agenticAuthoringStatus.set('');
@@ -15095,9 +16133,25 @@ class DynamicPageBuilderComponent {
15095
16133
  return visiblePrompt;
15096
16134
  }
15097
16135
  isResourceQuickReply(reply, contextHints) {
16136
+ if (this.isContextualPreviewActionQuickReply(reply, contextHints)) {
16137
+ return false;
16138
+ }
15098
16139
  return this.hasResourceContextHint(contextHints)
15099
16140
  && !['cancel', 'revise'].includes((reply.kind || '').trim().toLowerCase());
15100
16141
  }
16142
+ isContextualPreviewActionQuickReply(reply, contextHints) {
16143
+ const source = typeof contextHints?.['source'] === 'string'
16144
+ ? contextHints['source'].trim()
16145
+ : '';
16146
+ const kind = typeof contextHints?.['kind'] === 'string'
16147
+ ? contextHints['kind'].trim()
16148
+ : '';
16149
+ const id = (reply.id || '').trim();
16150
+ return source === 'component-capability-catalog'
16151
+ || kind === 'contextual-preview-action'
16152
+ || id.startsWith('chart-')
16153
+ || id.startsWith('table-export-');
16154
+ }
15101
16155
  isGovernedConfirmationQuickReply(reply, contextHints) {
15102
16156
  return this.isConfirmationQuickReply(reply)
15103
16157
  && this.hasResourceContextHint(contextHints);
@@ -15165,6 +16219,7 @@ class DynamicPageBuilderComponent {
15165
16219
  this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Resolving intent...'));
15166
16220
  this.agenticAuthoringError.set('');
15167
16221
  this.agenticAuthoringPreviewResult.set(null);
16222
+ this.agenticAuthoringCanApply.set(false);
15168
16223
  this.clearProjectKnowledgeCockpitState();
15169
16224
  try {
15170
16225
  await this.consumeAgenticTurn(this.ensureAgenticTurnController().resendMessage(message.id));
@@ -15205,6 +16260,8 @@ class DynamicPageBuilderComponent {
15205
16260
  this.agenticAuthoringEditingMessageId.set(null);
15206
16261
  this.agenticAuthoringPrompt.set('');
15207
16262
  this.agenticAuthoringPreviewResult.set(null);
16263
+ this.agenticAuthoringSemanticDecision.set(null);
16264
+ this.agenticAuthoringCanApply.set(false);
15208
16265
  this.agenticAuthoringSharedRuleHandoffState.set(null);
15209
16266
  this.clearSharedRuleCockpitState();
15210
16267
  this.clearProjectKnowledgeCockpitState();
@@ -15212,7 +16269,7 @@ class DynamicPageBuilderComponent {
15212
16269
  }
15213
16270
  async persistAgenticAuthoring() {
15214
16271
  const preview = this.agenticAuthoringPreviewResult();
15215
- if (!preview || this.agenticAuthoringBusy())
16272
+ if (!preview || !this.agenticAuthoringCanApply() || this.agenticAuthoringBusy())
15216
16273
  return;
15217
16274
  const componentId = this.resolveAgenticComponentId();
15218
16275
  if (!componentId) {
@@ -15232,10 +16289,17 @@ class DynamicPageBuilderComponent {
15232
16289
  tags: {
15233
16290
  source: 'page-builder-agentic-authoring',
15234
16291
  },
16292
+ semanticDecision: this.agenticAuthoringSemanticDecision(),
15235
16293
  }));
15236
16294
  this.agenticAuthoringLastEtag.set(result.etag ?? null);
15237
16295
  this.agenticAuthoringApplied.emit(result);
16296
+ this.agenticAuthoringPreviewResult.set(null);
16297
+ this.agenticAuthoringSemanticDecision.set(null);
16298
+ this.agenticAuthoringCanApply.set(false);
16299
+ this.agenticAuthoringQuickReplies.set([]);
16300
+ this.agenticAuthoringPrompt.set('');
15238
16301
  this.agenticAuthoringStatus.set(this.tx('agentic.status.saved', 'Page saved.'));
16302
+ this.syncAgenticAuthoringSession();
15239
16303
  }
15240
16304
  catch (error) {
15241
16305
  this.agenticAuthoringStatus.set('');
@@ -15797,6 +16861,7 @@ class DynamicPageBuilderComponent {
15797
16861
  this.agenticAuthoringStatus.set(this.tx('agentic.status.sharedRuleTargetSelected', 'Shared-rule target selected. Continue by creating the governed definition.'));
15798
16862
  this.agenticAuthoringError.set('');
15799
16863
  this.agenticAuthoringPreviewResult.set(null);
16864
+ this.agenticAuthoringCanApply.set(false);
15800
16865
  this.agenticAuthoringSharedRuleHandoffState.set(next);
15801
16866
  this.agenticAuthoringSharedRuleHandoff.emit(next);
15802
16867
  this.appendAgenticMessage('user', visiblePrompt);
@@ -16063,12 +17128,14 @@ class DynamicPageBuilderComponent {
16063
17128
  const handoff = this.resolveAgenticSharedRuleHandoff(state);
16064
17129
  const previousHandoff = this.agenticAuthoringSharedRuleHandoffState();
16065
17130
  this.agenticAuthoringConversation.set(state.messages);
16066
- this.agenticAuthoringQuickReplies.set(preview?.valid ? [] : state.quickReplies);
17131
+ this.agenticAuthoringQuickReplies.set(state.quickReplies);
16067
17132
  this.agenticAuthoringStatus.set(handoff && !preview?.valid
16068
17133
  ? this.tx('agentic.status.sharedRuleHandoff', 'Continue this request in the shared-rules flow.')
16069
17134
  : state.statusText);
16070
17135
  this.agenticAuthoringError.set(state.errorText);
16071
17136
  this.agenticAuthoringPreviewResult.set(preview);
17137
+ this.agenticAuthoringSemanticDecision.set(this.resolveAgenticSemanticDecision(state.diagnostics));
17138
+ this.agenticAuthoringCanApply.set(!!preview?.valid && !!state.canApply);
16072
17139
  this.moveAgenticAuthoringPanelToReviewSidecar(preview);
16073
17140
  this.agenticAuthoringAttachments.set(state.attachments);
16074
17141
  if (!this.sameSharedRuleHandoffIdentity(previousHandoff, handoff)) {
@@ -16124,7 +17191,7 @@ class DynamicPageBuilderComponent {
16124
17191
  }
16125
17192
  this.agenticAuthoringPanelLayout.set(createPraxisAssistantViewportLayout({
16126
17193
  width: 440,
16127
- height: 560,
17194
+ height: 620,
16128
17195
  top: 96,
16129
17196
  margin: 24,
16130
17197
  }));
@@ -16266,7 +17333,14 @@ class DynamicPageBuilderComponent {
16266
17333
  return Object.keys(merged).length ? merged : undefined;
16267
17334
  }
16268
17335
  consumeAgenticTurn(states$) {
16269
- return lastValueFrom(states$.pipe(concatMap((state) => from(this.applyAgenticTurnState(state)).pipe(map(() => state)))));
17336
+ return firstValueFrom(states$.pipe(concatMap((state) => from(this.applyAgenticTurnState(state)).pipe(map(() => state))), filter((state) => this.isAgenticTurnTerminalState(state)), take(1)));
17337
+ }
17338
+ isAgenticTurnTerminalState(state) {
17339
+ return state.state === 'review'
17340
+ || state.state === 'clarification'
17341
+ || state.state === 'error'
17342
+ || state.state === 'success'
17343
+ || state.state === 'listening';
16270
17344
  }
16271
17345
  agenticAuthoringDiagnosticsTop() {
16272
17346
  return Math.max(16, this.agenticAuthoringPanelLayout().top);
@@ -16285,6 +17359,11 @@ class DynamicPageBuilderComponent {
16285
17359
  const intentResolution = this.toRecord(diagnostics?.['intentResolution']);
16286
17360
  return this.toRecord(intentResolution?.['llmDiagnostics']);
16287
17361
  }
17362
+ resolveAgenticSemanticDecision(diagnostics) {
17363
+ const intentResolution = this.toRecord(diagnostics?.['intentResolution']);
17364
+ const semanticDecision = this.toRecord(intentResolution?.['semanticDecision']);
17365
+ return semanticDecision ? semanticDecision : null;
17366
+ }
16288
17367
  cloneAgenticContextHints(contextHints) {
16289
17368
  if (!contextHints || typeof contextHints !== 'object' || Array.isArray(contextHints)) {
16290
17369
  return undefined;
@@ -16330,8 +17409,10 @@ class DynamicPageBuilderComponent {
16330
17409
  }
16331
17410
  resolvePreviewCompiledFormPatch(preview) {
16332
17411
  if (preview.uiCompositionPlan || preview.compiledFormPatch?.patch?.page) {
17412
+ const planDiagnostics = this.toRecord(this.toRecord(preview.uiCompositionPlan)?.['diagnostics']);
16333
17413
  return {
16334
17414
  ...preview.compiledFormPatch,
17415
+ diagnostics: planDiagnostics ?? preview.compiledFormPatch?.['diagnostics'],
16335
17416
  patch: {
16336
17417
  ...(preview.compiledFormPatch?.patch ?? {}),
16337
17418
  page: this.clonePage(this.currentPage()),
@@ -16359,7 +17440,7 @@ class DynamicPageBuilderComponent {
16359
17440
  return this.clonePage(input);
16360
17441
  }
16361
17442
  clonePage(page) {
16362
- return JSON.parse(JSON.stringify(page));
17443
+ return normalizePageBuilderRuntimePage(JSON.parse(JSON.stringify(page)));
16363
17444
  }
16364
17445
  clearSelectedWidgetIfMissing(page) {
16365
17446
  const selected = this.selectedWidgetKey();
@@ -16580,7 +17661,7 @@ class DynamicPageBuilderComponent {
16580
17661
  [statusText]="agenticAuthoringStatus()"
16581
17662
  [errorText]="agenticAuthoringError()"
16582
17663
  [busy]="agenticAuthoringBusy()"
16583
- [canApply]="!!agenticAuthoringPreviewResult()?.valid"
17664
+ [canApply]="agenticAuthoringCanApply()"
16584
17665
  [primaryAction]="agenticAuthoringSubmitAction()"
16585
17666
  [showAttachAction]="false"
16586
17667
  [enablePastedAttachments]="false"
@@ -17004,7 +18085,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
17004
18085
  [statusText]="agenticAuthoringStatus()"
17005
18086
  [errorText]="agenticAuthoringError()"
17006
18087
  [busy]="agenticAuthoringBusy()"
17007
- [canApply]="!!agenticAuthoringPreviewResult()?.valid"
18088
+ [canApply]="agenticAuthoringCanApply()"
17008
18089
  [primaryAction]="agenticAuthoringSubmitAction()"
17009
18090
  [showAttachAction]="false"
17010
18091
  [enablePastedAttachments]="false"