@praxisui/dynamic-form 10.0.0-rc.41 → 10.0.0-rc.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/dynamic-form",
3
- "version": "10.0.0-rc.41",
3
+ "version": "10.0.0-rc.42",
4
4
  "description": "Angular dynamic form engine for Praxis UI: metadata-driven forms, hooks, and services integrating @praxisui/* packages.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
@@ -9,13 +9,13 @@
9
9
  "@angular/forms": "^21.0.0",
10
10
  "@angular/material": "^21.0.0",
11
11
  "@angular/router": "^21.0.0",
12
- "@praxisui/ai": "^10.0.0-rc.41",
13
- "@praxisui/dynamic-fields": "^10.0.0-rc.41",
14
- "@praxisui/metadata-editor": "^10.0.0-rc.41",
15
- "@praxisui/rich-content": "^10.0.0-rc.41",
16
- "@praxisui/settings-panel": "^10.0.0-rc.41",
17
- "@praxisui/visual-builder": "^10.0.0-rc.41",
18
- "@praxisui/core": "^10.0.0-rc.41",
12
+ "@praxisui/ai": "^10.0.0-rc.42",
13
+ "@praxisui/dynamic-fields": "^10.0.0-rc.42",
14
+ "@praxisui/metadata-editor": "^10.0.0-rc.42",
15
+ "@praxisui/rich-content": "^10.0.0-rc.42",
16
+ "@praxisui/settings-panel": "^10.0.0-rc.42",
17
+ "@praxisui/visual-builder": "^10.0.0-rc.42",
18
+ "@praxisui/core": "^10.0.0-rc.42",
19
19
  "rxjs": "^7.8.0"
20
20
  },
21
21
  "dependencies": {
@@ -7,7 +7,7 @@ import { MatDialog } from '@angular/material/dialog';
7
7
  import { MatSnackBar } from '@angular/material/snack-bar';
8
8
  import { CdkDragStart, CdkDragMove, CdkDragEnd, CdkDragDrop } from '@angular/cdk/drag-drop';
9
9
  import * as _praxisui_core from '@praxisui/core';
10
- import { AsyncConfigStorage, FormLayout, FieldMetadata, FormLayoutRule, FormRuleTargetType as FormRuleTargetType$1, PraxisJsonLogicService, FormSection, FormRow, FormColumn, FormConfig, FormConfigWithSections, FormLayoutItem, ReactiveDeterminationDefinition, ReactiveDeterminationExecutionEvent, FormActionButton, DynamicFormMode, AiCapability, DynamicFormLayoutScope, BackConfig, FormPresentationConfig, EmptyStateTone, EmptyStateVariant, EmptyStateAlignment, EmptyStateDensity, EmptyStateIconContainer, FormPresentationPreset, RichBlockHostCapabilities, ApiEndpoint, ApiUrlEntry, FormLayoutMode, FormLayoutOptions, DynamicFormLayoutPolicy, FormHooksLayout, EndpointConfig, FormSubmitEvent, FormReadyEvent, FormValueChangeEvent, FormPayloadPreviewEvent, SyncResult, FormInitializationError, LoadingState, FormCustomActionEvent, FormActionConfirmationEvent, FormLayoutTabItem, RichContentDocument, JsonLogicRecord, GenericCrudService, ConnectionStorage, DynamicFormService, ErrorMessageService, SchemaNormalizerService, ComponentMetadataRegistry, GlobalConfigService, ComponentKeyService, LoadingOrchestrator, ApiUrlConfig, PraxisLoadingRenderer, FormHooksRegistry, FormHookPreset, LoggerService, EnterpriseRuntimeContextService, FormLayoutTabsAppearance, FormSectionHeaderAction, FormSectionHeaderConfig, FormConfigState, JsonLogicExpression, FormHelpPresentationConfig, GlobalActionCatalogEntry, PraxisRuntimeConditionalEffectRule, PraxisRuntimeGlobalActionEffect, SurfaceOpenPayload, GlobalActionField, PraxisEffectPolicy, FieldDefinition, ComponentDocMeta, DiscoveredResourceOption, Breakpoint, DomainRuleRequestOptions, DomainRuleService, DomainRuleMaterialization, SchemaIdParams, CompiledDynamicFormSchema, TableConfig, SurfaceOpenActionEditorComponent, IconPickerService, GlobalActionRef, AiCapabilityCategory, AiCapabilityCatalog, AiValueKind, ComponentAuthoringManifest, GovernedPagePreviewWidgetAdapter, WidgetInstance } from '@praxisui/core';
10
+ import { AsyncConfigStorage, FormLayout, FieldMetadata, FormLayoutRule, FormRuleTargetType as FormRuleTargetType$1, PraxisJsonLogicService, FormSection, FormRow, FormColumn, FormConfig, FormConfigWithSections, FormLayoutItem, ReactiveDeterminationDefinition, ReactiveDeterminationExecutionEvent, FormActionButton, DynamicFormMode, PraxisRuntimeFormValueTargetIdentity, PraxisRuntimeFormValueEligibility, PraxisRuntimeFormValueProposal, PraxisRuntimeFormValueApplyMode, PraxisRuntimeFormValuePreviewResult, PraxisRuntimeFormValueApplyRequest, PraxisRuntimeFormValueApplyReceipt, PraxisRuntimeFormValueUndoReceipt, AiCapability, DynamicFormLayoutScope, BackConfig, FormPresentationConfig, EmptyStateTone, EmptyStateVariant, EmptyStateAlignment, EmptyStateDensity, EmptyStateIconContainer, FormPresentationPreset, PraxisRuntimeFormValueTargetPort, RichBlockHostCapabilities, ApiEndpoint, ApiUrlEntry, FormLayoutMode, FormLayoutOptions, DynamicFormLayoutPolicy, FormHooksLayout, EndpointConfig, FormSubmitEvent, FormReadyEvent, FormValueChangeEvent, FormPayloadPreviewEvent, SyncResult, FormInitializationError, LoadingState, FormCustomActionEvent, FormActionConfirmationEvent, FormLayoutTabItem, RichContentDocument, JsonLogicRecord, GenericCrudService, ConnectionStorage, DynamicFormService, ErrorMessageService, SchemaNormalizerService, ComponentMetadataRegistry, GlobalConfigService, ComponentKeyService, LoadingOrchestrator, ApiUrlConfig, PraxisLoadingRenderer, FormHooksRegistry, FormHookPreset, LoggerService, EnterpriseRuntimeContextService, FormLayoutTabsAppearance, FormSectionHeaderAction, FormSectionHeaderConfig, FormConfigState, JsonLogicExpression, FormHelpPresentationConfig, GlobalActionCatalogEntry, PraxisRuntimeConditionalEffectRule, PraxisRuntimeGlobalActionEffect, SurfaceOpenPayload, GlobalActionField, PraxisEffectPolicy, FieldDefinition, ComponentDocMeta, DiscoveredResourceOption, Breakpoint, DomainRuleRequestOptions, DomainRuleService, DomainRuleMaterialization, SchemaIdParams, CompiledDynamicFormSchema, TableConfig, SurfaceOpenActionEditorComponent, IconPickerService, GlobalActionRef, AiCapabilityCategory, AiCapabilityCatalog, AiValueKind, ComponentAuthoringManifest, GovernedPagePreviewWidgetAdapter, WidgetInstance } from '@praxisui/core';
11
11
  export { CompiledDynamicFormSchema, DynamicFormLayoutScope, DynamicFormMode } from '@praxisui/core';
12
12
  import * as rxjs from 'rxjs';
13
13
  import { Observable, Subscription, BehaviorSubject } from 'rxjs';
@@ -514,6 +514,14 @@ interface FormAiHost {
514
514
  readonlyModeGlobal?: boolean | null;
515
515
  effectiveReadonly?: boolean;
516
516
  applyConfigFromAdapter(config: FormConfig): void;
517
+ getRuntimeValueTargetIdentity?(): PraxisRuntimeFormValueTargetIdentity;
518
+ getRuntimeValueEligibility?(): PraxisRuntimeFormValueEligibility;
519
+ previewRuntimeValues?(proposal: PraxisRuntimeFormValueProposal, options?: {
520
+ readonly selectedFieldPaths?: readonly string[];
521
+ readonly applyMode?: PraxisRuntimeFormValueApplyMode;
522
+ }): PraxisRuntimeFormValuePreviewResult;
523
+ applyRuntimeValues?(request: PraxisRuntimeFormValueApplyRequest): Promise<PraxisRuntimeFormValueApplyReceipt> | PraxisRuntimeFormValueApplyReceipt;
524
+ undoRuntimeValues?(receiptId?: string): Promise<PraxisRuntimeFormValueUndoReceipt> | PraxisRuntimeFormValueUndoReceipt;
517
525
  }
518
526
 
519
527
  declare class FormAiAdapter extends BaseAiAdapter<FormConfig> {
@@ -529,6 +537,14 @@ declare class FormAiAdapter extends BaseAiAdapter<FormConfig> {
529
537
  getDataProfile(): Record<string, any>;
530
538
  getSchemaFields(): Record<string, any>[];
531
539
  getAuthoringContext(): Record<string, any>;
540
+ getRuntimeValueTargetIdentity(): PraxisRuntimeFormValueTargetIdentity | null;
541
+ getRuntimeValueEligibility(): PraxisRuntimeFormValueEligibility | null;
542
+ previewRuntimeValues(proposal: PraxisRuntimeFormValueProposal, options?: {
543
+ readonly selectedFieldPaths?: readonly string[];
544
+ readonly applyMode?: PraxisRuntimeFormValueApplyMode;
545
+ }): PraxisRuntimeFormValuePreviewResult | null;
546
+ applyRuntimeValues(request: PraxisRuntimeFormValueApplyRequest): Promise<PraxisRuntimeFormValueApplyReceipt | null>;
547
+ undoRuntimeValues(receiptId?: string): Promise<PraxisRuntimeFormValueUndoReceipt | null>;
532
548
  compileAiResponse(response: Record<string, unknown>): AiResponseCompileResult | null;
533
549
  createSnapshot(): FormConfig;
534
550
  restoreSnapshot(snapshot: FormConfig): Promise<void>;
@@ -733,7 +749,7 @@ interface FormColumnRichContentRenderItem {
733
749
  style?: Record<string, any> | null;
734
750
  }
735
751
  type FormColumnRenderItem = FormColumnFieldsRenderItem | FormColumnRichContentRenderItem;
736
- declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy {
752
+ declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy, PraxisRuntimeFormValueTargetPort {
737
753
  private crud;
738
754
  private http;
739
755
  private fb;
@@ -1073,6 +1089,14 @@ declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy {
1073
1089
  private readonly entityReadCancel$;
1074
1090
  private isDestroyed;
1075
1091
  private formValueChangesSubscription;
1092
+ private formStatusChangesSubscription;
1093
+ private readonly runtimeValueJournal;
1094
+ private runtimeValueRevision;
1095
+ private runtimeValueTrackedForm;
1096
+ private readonly runtimeValueTrackedControls;
1097
+ private suppressCommandRuleSideEffectsDepth;
1098
+ private pendingSuppressedCommandEvaluation;
1099
+ private consumingSuppressedCommandEvaluation;
1076
1100
  private readonly submitFieldErrorSubscriptions;
1077
1101
  private activeSubmitErrorDetails;
1078
1102
  private reactiveDeterminationSubscription;
@@ -1458,7 +1482,7 @@ declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy {
1458
1482
  closeAiAssistant(): void;
1459
1483
  onAiAssistantPromptChange(prompt: string): void;
1460
1484
  onAiAssistantSubmit(prompt: string): void;
1461
- onAiAssistantApply(): void;
1485
+ onAiAssistantApply(contextHints?: Record<string, unknown> | void): void;
1462
1486
  onAiAssistantRetry(): void;
1463
1487
  onAiAssistantCancel(): void;
1464
1488
  onAiAssistantQuickReply(reply: PraxisAssistantShellQuickReply): void;
@@ -1655,6 +1679,21 @@ declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy {
1655
1679
  private logRowGapsSnapshot;
1656
1680
  private applyPresentationVars;
1657
1681
  private applyPresentationConfig;
1682
+ getRuntimeValueTargetIdentity(): PraxisRuntimeFormValueTargetIdentity;
1683
+ getRuntimeValueEligibility(): PraxisRuntimeFormValueEligibility;
1684
+ previewRuntimeValues(proposal: PraxisRuntimeFormValueProposal, options?: {
1685
+ readonly selectedFieldPaths?: readonly string[];
1686
+ readonly applyMode?: PraxisRuntimeFormValueApplyMode;
1687
+ }): PraxisRuntimeFormValuePreviewResult;
1688
+ applyRuntimeValues(request: PraxisRuntimeFormValueApplyRequest): PraxisRuntimeFormValueApplyReceipt;
1689
+ undoRuntimeValues(receiptId?: string): PraxisRuntimeFormValueUndoReceipt;
1690
+ private clearRuntimeValueControlSubscriptions;
1691
+ private collectLeafFormControls;
1692
+ private ensureRuntimeValueTracking;
1693
+ private withSuppressedCommandSideEffects;
1694
+ private createRuntimeFormHostCallbacks;
1695
+ private isConfiguredReactiveDeterminationOutputField;
1696
+ private collectRuntimeValueFieldClassification;
1658
1697
  static ɵfac: i0.ɵɵFactoryDeclaration<PraxisDynamicForm, [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }]>;
1659
1698
  static ɵcmp: i0.ɵɵComponentDeclaration<PraxisDynamicForm, "praxis-dynamic-form", never, { "resourcePath": { "alias": "resourcePath"; "required": false; }; "resourceId": { "alias": "resourceId"; "required": false; }; "initialValue": { "alias": "initialValue"; "required": false; }; "emptyState": { "alias": "emptyState"; "required": false; }; "editorialContext": { "alias": "editorialContext"; "required": false; }; "mode": { "alias": "mode"; "required": false; }; "config": { "alias": "config"; "required": false; }; "actions": { "alias": "actions"; "required": false; }; "schemaSource": { "alias": "schemaSource"; "required": false; }; "actionId": { "alias": "actionId"; "required": false; }; "operationId": { "alias": "operationId"; "required": false; }; "schemaUrl": { "alias": "schemaUrl"; "required": false; }; "readUrl": { "alias": "readUrl"; "required": false; }; "submitUrl": { "alias": "submitUrl"; "required": false; }; "submitMethod": { "alias": "submitMethod"; "required": false; }; "submitIdempotencyKey": { "alias": "submitIdempotencyKey"; "required": false; }; "submitCorrelationId": { "alias": "submitCorrelationId"; "required": false; }; "submitResourceVersion": { "alias": "submitResourceVersion"; "required": false; }; "submitResourceVersionTargetResourceKey": { "alias": "submitResourceVersionTargetResourceKey"; "required": false; }; "submitResourceVersionTargetIdField": { "alias": "submitResourceVersionTargetIdField"; "required": false; }; "responseSchemaUrl": { "alias": "responseSchemaUrl"; "required": false; }; "apiEndpointKey": { "alias": "apiEndpointKey"; "required": false; }; "apiUrlEntry": { "alias": "apiUrlEntry"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "showAiAssistant": { "alias": "showAiAssistant"; "required": false; }; "formId": { "alias": "formId"; "required": false; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "configPersistenceStrategy": { "alias": "configPersistenceStrategy"; "required": false; }; "layout": { "alias": "layout"; "required": false; }; "layoutMode": { "alias": "layoutMode"; "required": false; }; "formLayout": { "alias": "formLayout"; "required": false; }; "generatedLayoutPreset": { "alias": "generatedLayoutPreset"; "required": false; }; "layoutPolicy": { "alias": "layoutPolicy"; "required": false; }; "backConfig": { "alias": "backConfig"; "required": false; }; "hooks": { "alias": "hooks"; "required": false; }; "removeEmptyContainersOnSave": { "alias": "removeEmptyContainersOnSave"; "required": false; }; "reactiveValidation": { "alias": "reactiveValidation"; "required": false; }; "reactiveValidationDebounceMs": { "alias": "reactiveValidationDebounceMs"; "required": false; }; "notifyIfOutdated": { "alias": "notifyIfOutdated"; "required": false; }; "snoozeMs": { "alias": "snoozeMs"; "required": false; }; "autoOpenSettingsOnOutdated": { "alias": "autoOpenSettingsOnOutdated"; "required": false; }; "readonlyModeGlobal": { "alias": "readonlyModeGlobal"; "required": false; }; "disabledModeGlobal": { "alias": "disabledModeGlobal"; "required": false; }; "presentationModeGlobal": { "alias": "presentationModeGlobal"; "required": false; }; "presentation": { "alias": "presentation"; "required": false; }; "presentationPreset": { "alias": "presentationPreset"; "required": false; }; "sectionDefaultAppearance": { "alias": "sectionDefaultAppearance"; "required": false; }; "sectionDivider": { "alias": "sectionDivider"; "required": false; }; "visibleGlobal": { "alias": "visibleGlobal"; "required": false; }; "fieldIconPolicy": { "alias": "fieldIconPolicy"; "required": false; }; "domainRules": { "alias": "domainRules"; "required": false; }; "customEndpoints": { "alias": "customEndpoints"; "required": false; }; }, { "formSubmit": "formSubmit"; "formCancel": "formCancel"; "formReset": "formReset"; "configChange": "configChange"; "configPatchChange": "configPatchChange"; "formReady": "formReady"; "valueChange": "valueChange"; "payloadPreviewChange": "payloadPreviewChange"; "syncCompleted": "syncCompleted"; "initializationError": "initializationError"; "loadingStateChange": "loadingStateChange"; "enableCustomizationChange": "enableCustomizationChange"; "customAction": "customAction"; "actionConfirmation": "actionConfirmation"; "schemaStatusChange": "schemaStatusChange"; "fieldRenderError": "fieldRenderError"; "ruleDiagnosticsChange": "ruleDiagnosticsChange"; "reactiveDeterminationExecuted": "reactiveDeterminationExecuted"; "reactiveDeterminationPendingChange": "reactiveDeterminationPendingChange"; "tabChange": "tabChange"; "tabSelected": "tabSelected"; }, never, never, true, never>;
1660
1699
  }
@@ -1,539 +0,0 @@
1
- import { Observable } from 'rxjs';
2
- import { withAuthoringScopePolicy } from '@praxisui/ai';
3
-
4
- class DynamicFormAgenticAuthoringTurnFlow {
5
- adapter;
6
- turnClient;
7
- mode = 'agentic-authoring';
8
- constructor(adapter, turnClient) {
9
- this.adapter = adapter;
10
- this.turnClient = turnClient;
11
- }
12
- submit(request) {
13
- const prompt = (request.prompt ?? '').trim();
14
- if (!prompt) {
15
- return Promise.resolve({
16
- state: 'listening',
17
- phase: 'capture',
18
- statusText: '',
19
- });
20
- }
21
- const componentId = this.adapter.componentId || request.componentId || 'praxis-dynamic-form';
22
- const componentType = this.adapter.componentType || request.componentType || 'form';
23
- const currentState = this.toAiJsonObject(this.adapter.getCurrentConfig());
24
- const runtimeState = this.optionalJsonObject(this.adapter.getRuntimeState?.());
25
- const contextHints = this.mergeJsonObjects(this.optionalJsonObject(this.adapter.getAuthoringContext?.()), this.optionalJsonObject(request.action?.contextHints));
26
- if (this.shouldRestrictToInlineHelp(contextHints)) {
27
- return Promise.resolve(this.toInlineHelpOnlyResult(prompt, request, contextHints));
28
- }
29
- const buildRequest = async () => {
30
- await this.adapter.prepareAuthoringContext?.();
31
- const preparedRuntimeState = this.optionalJsonObject(this.adapter.getRuntimeState?.()) ?? runtimeState;
32
- const preparedContextHints = this.mergeJsonObjects(this.optionalJsonObject(this.adapter.getAuthoringContext?.()), this.optionalJsonObject(request.action?.contextHints));
33
- const dataProfile = this.optionalJsonObject(this.adapter.getDataProfile?.());
34
- const schemaFields = this.adapter.getSchemaFields?.()
35
- ?.map((field) => this.toAiJsonObject(field))
36
- .filter((field) => Object.keys(field).length > 0);
37
- const patchRequest = withAuthoringScopePolicy({
38
- componentId,
39
- componentType,
40
- userPrompt: prompt,
41
- sessionId: request.sessionId,
42
- clientTurnId: request.clientTurnId,
43
- messages: this.toChatMessages(request.messages, prompt),
44
- currentState,
45
- currentStateDigest: this.buildCurrentStateDigest(currentState, preparedRuntimeState),
46
- uiContextRef: {
47
- componentId,
48
- componentType,
49
- },
50
- ...(dataProfile ? { dataProfile } : {}),
51
- ...(preparedRuntimeState ? { runtimeState: preparedRuntimeState } : {}),
52
- ...(schemaFields?.length ? { schemaFields } : {}),
53
- ...(preparedContextHints ? { contextHints: preparedContextHints } : {}),
54
- }, {
55
- componentId,
56
- componentType,
57
- componentLabel: this.adapter.componentName || 'formulário',
58
- });
59
- return {
60
- ...patchRequest,
61
- targetApp: 'praxis-ui-angular',
62
- targetComponentId: componentId,
63
- currentPage: currentState,
64
- conversationMessages: this.toConversationMessages(request.messages),
65
- pendingClarification: this.toPendingClarification(request),
66
- attachmentSummaries: this.toAttachmentSummaries(request),
67
- activeSemanticDecision: this.optionalJsonObject(request.activeSemanticDecision ?? request.action?.activeSemanticDecision),
68
- contextHints: patchRequest.contextHints ?? null,
69
- };
70
- };
71
- return this.submitViaAgenticStream(request, buildRequest);
72
- }
73
- submitViaAgenticStream(request, buildRequest) {
74
- return new Observable((subscriber) => {
75
- let closed = false;
76
- let subscription = null;
77
- const close = () => {
78
- closed = true;
79
- subscription?.unsubscribe();
80
- subscription = null;
81
- };
82
- void buildRequest()
83
- .then((turnRequest) => {
84
- if (closed)
85
- return;
86
- subscription = this.turnClient.streamEvents(turnRequest, {
87
- initialStatusText: 'Preparando o contexto seguro do formulário.',
88
- resultTimeoutMs: 90_000,
89
- streamTimeoutMs: 90_000,
90
- }).subscribe({
91
- next: (event) => {
92
- if (closed)
93
- return;
94
- const result = this.toAgenticStreamTurnResult(event, request);
95
- subscriber.next(result);
96
- if (result.state !== 'processing') {
97
- subscriber.complete();
98
- close();
99
- }
100
- },
101
- error: (error) => {
102
- if (closed)
103
- return;
104
- subscriber.next(this.toAssistantErrorResult(error));
105
- subscriber.complete();
106
- close();
107
- },
108
- });
109
- })
110
- .catch((error) => {
111
- if (closed)
112
- return;
113
- subscriber.next(this.toAssistantErrorResult(error));
114
- subscriber.complete();
115
- close();
116
- });
117
- return () => close();
118
- });
119
- }
120
- toAgenticStreamTurnResult(event, request) {
121
- if (event.kind === 'stream-started') {
122
- return {
123
- state: 'processing',
124
- phase: 'contextualize',
125
- statusText: 'Analisando o formulário e suas capacidades.',
126
- sessionId: event.start.threadId,
127
- clientTurnId: request.clientTurnId ?? event.start.turnId,
128
- observationId: event.start.observationId ?? null,
129
- canApply: false,
130
- };
131
- }
132
- if (event.kind === 'stream-lifecycle') {
133
- return {
134
- state: 'processing',
135
- phase: 'contextualize',
136
- statusText: event.statusText,
137
- sessionId: event.start.threadId,
138
- clientTurnId: request.clientTurnId ?? event.start.turnId,
139
- observationId: event.start.observationId ?? null,
140
- canApply: false,
141
- diagnostics: event.diagnostics
142
- ? { streamLifecycle: { phase: event.phase, ...event.diagnostics } }
143
- : undefined,
144
- };
145
- }
146
- if (event.event.type === 'result') {
147
- const payload = this.toRecord(event.event.payload) ?? {};
148
- const rawResponse = this.toRecord(payload['response']) ?? payload;
149
- const response = this.normalizeAgenticResponse(rawResponse);
150
- return {
151
- ...this.toTurnResult(this.compileAdapterResponse(response), request),
152
- sessionId: event.event.threadId || request.sessionId,
153
- clientTurnId: request.clientTurnId ?? event.event.turnId,
154
- };
155
- }
156
- return this.turnClient.toTurnResult(event.event, request.clientTurnId);
157
- }
158
- normalizeAgenticResponse(response) {
159
- const type = response['type'];
160
- const normalizedType = type === 'patch'
161
- || type === 'clarification'
162
- || type === 'error'
163
- || type === 'info'
164
- ? type
165
- : this.toRecord(response['patch']) || this.toRecord(response['compiledPatch'])
166
- ? 'patch'
167
- : 'info';
168
- const patch = this.toRecord(response['patch']) ?? this.toRecord(response['compiledPatch']) ?? undefined;
169
- const message = typeof response['message'] === 'string'
170
- ? response['message']
171
- : typeof response['assistantMessage'] === 'string'
172
- ? response['assistantMessage']
173
- : undefined;
174
- return {
175
- ...response,
176
- type: normalizedType,
177
- ...(patch ? { patch } : {}),
178
- ...(message ? { message } : {}),
179
- };
180
- }
181
- toConversationMessages(messages) {
182
- return (messages ?? [])
183
- .filter((message) => message.role === 'user' || message.role === 'assistant' || message.role === 'system')
184
- .map((message) => ({
185
- id: message.id,
186
- role: message.role,
187
- text: message.text,
188
- }))
189
- .filter((message) => message.text.trim().length > 0);
190
- }
191
- toPendingClarification(request) {
192
- const pending = request.pendingClarification;
193
- if (!pending?.sourcePrompt?.trim())
194
- return null;
195
- return {
196
- sourcePrompt: pending.sourcePrompt,
197
- questions: pending.questions.map((question) => question.label).filter(Boolean),
198
- assistantMessage: pending.assistantMessage ?? null,
199
- clientTurnId: pending.clientTurnId ?? null,
200
- diagnostics: this.optionalJsonObject(pending.diagnostics) ?? null,
201
- };
202
- }
203
- toAttachmentSummaries(request) {
204
- return (request.attachments ?? []).map((attachment) => ({
205
- id: attachment.id,
206
- name: attachment.name,
207
- kind: attachment.kind,
208
- mimeType: attachment.mimeType ?? null,
209
- sizeBytes: attachment.sizeBytes ?? null,
210
- source: attachment.source ?? null,
211
- hasPreview: !!attachment.previewUrl,
212
- }));
213
- }
214
- toAssistantErrorResult(error) {
215
- const message = error instanceof Error
216
- ? error.message
217
- : typeof error === 'string' && error.trim()
218
- ? error
219
- : 'Não foi possível concluir o pedido do formulário.';
220
- return {
221
- state: 'error',
222
- phase: 'capture',
223
- assistantMessage: `Não consegui concluir este pedido. ${message}`,
224
- errorText: message,
225
- canApply: false,
226
- pendingPatch: null,
227
- };
228
- }
229
- async apply(request) {
230
- const contextHints = this.optionalJsonObject(this.adapter.getAuthoringContext?.());
231
- if (this.shouldRestrictToInlineHelp(contextHints)) {
232
- return {
233
- state: 'error',
234
- phase: 'apply',
235
- assistantMessage: 'Este formulario esta em modo de leitura. Posso explicar ou diagnosticar, mas nao aplicar mudancas locais.',
236
- errorText: 'Aplicacao bloqueada em view/readonly sem customizacao.',
237
- canApply: false,
238
- pendingPatch: null,
239
- };
240
- }
241
- const patch = this.toRecord(request.pendingPatch);
242
- if (!patch) {
243
- return {
244
- state: 'error',
245
- phase: 'apply',
246
- assistantMessage: 'Nao ha alteracao de formulario pronta para aplicar.',
247
- errorText: 'Nao ha alteracao de formulario pronta para aplicar.',
248
- canApply: false,
249
- };
250
- }
251
- const result = await this.adapter.applyPatch(patch, request.prompt);
252
- if (!result.success) {
253
- return {
254
- state: 'error',
255
- phase: 'apply',
256
- assistantMessage: result.error || 'Nao foi possivel aplicar as alteracoes no formulario.',
257
- errorText: result.error || 'Nao foi possivel aplicar as alteracoes no formulario.',
258
- canApply: true,
259
- pendingPatch: patch,
260
- };
261
- }
262
- return {
263
- state: 'success',
264
- phase: 'summarize',
265
- assistantMessage: 'Alteracoes aplicadas no formulario.',
266
- statusText: 'Alteracoes aplicadas no formulario.',
267
- canApply: false,
268
- pendingPatch: null,
269
- diagnostics: result.warnings?.length ? { warnings: result.warnings } : undefined,
270
- };
271
- }
272
- cancel() {
273
- return Promise.resolve({
274
- state: 'listening',
275
- phase: 'capture',
276
- assistantMessage: 'Solicitacao cancelada.',
277
- statusText: '',
278
- canApply: false,
279
- pendingPatch: null,
280
- pendingClarification: null,
281
- });
282
- }
283
- retry(request) {
284
- const lastPrompt = [...(request.messages ?? [])].reverse()
285
- .find((message) => message.role === 'user')?.text;
286
- return this.submit({
287
- ...request,
288
- prompt: lastPrompt ?? request.prompt,
289
- action: { kind: 'retry' },
290
- });
291
- }
292
- toTurnResult(response, request) {
293
- if (!response) {
294
- return {
295
- state: 'error',
296
- phase: 'capture',
297
- assistantMessage: 'Resposta vazia da IA.',
298
- errorText: 'Resposta vazia da IA.',
299
- };
300
- }
301
- if (response.type === 'clarification') {
302
- const questions = this.toClarificationQuestions(response);
303
- return {
304
- state: 'clarification',
305
- phase: 'clarify',
306
- sessionId: response.sessionId ?? request.sessionId,
307
- observationId: response.observationId ?? request.observationId ?? null,
308
- assistantMessage: response.message || 'Preciso de mais detalhes para continuar.',
309
- clarificationQuestions: questions,
310
- quickReplies: this.toQuickReplies(response),
311
- canApply: false,
312
- };
313
- }
314
- if (response.type === 'info') {
315
- const message = response.message || response.explanation || 'Informacao gerada.';
316
- return {
317
- state: 'success',
318
- phase: 'summarize',
319
- sessionId: response.sessionId ?? request.sessionId,
320
- observationId: response.observationId ?? request.observationId ?? null,
321
- assistantMessage: message,
322
- statusText: message,
323
- canApply: false,
324
- };
325
- }
326
- if (response.type === 'error') {
327
- const message = response.message || 'Falha ao gerar alteracao de formulario.';
328
- return {
329
- state: 'error',
330
- phase: 'capture',
331
- sessionId: response.sessionId ?? request.sessionId,
332
- observationId: response.observationId ?? request.observationId ?? null,
333
- assistantMessage: message,
334
- errorText: message,
335
- diagnostics: response.warnings?.length ? { warnings: response.warnings } : undefined,
336
- };
337
- }
338
- if (response.patch && Object.keys(response.patch).length > 0) {
339
- const warnings = response.warnings?.filter(Boolean) ?? [];
340
- const suffix = warnings.length ? ` Avisos: ${warnings.join('; ')}` : '';
341
- return {
342
- state: 'review',
343
- phase: 'review',
344
- sessionId: response.sessionId ?? request.sessionId,
345
- observationId: response.observationId ?? request.observationId ?? null,
346
- assistantMessage: `${response.explanation || 'Proposta de alteracao pronta para revisar.'}${suffix}`,
347
- statusText: 'Revise a proposta antes de aplicar.',
348
- canApply: true,
349
- pendingPatch: response.patch,
350
- preview: {
351
- kind: 'dynamic-form-config-patch',
352
- diff: response.diff ?? [],
353
- },
354
- diagnostics: warnings.length ? { warnings } : undefined,
355
- };
356
- }
357
- return {
358
- state: 'success',
359
- phase: 'summarize',
360
- sessionId: response.sessionId ?? request.sessionId,
361
- observationId: response.observationId ?? request.observationId ?? null,
362
- assistantMessage: response.message || response.explanation || 'Nenhuma alteracao necessaria.',
363
- statusText: response.message || response.explanation || 'Nenhuma alteracao necessaria.',
364
- canApply: false,
365
- };
366
- }
367
- compileAdapterResponse(response) {
368
- const compiled = this.adapter.compileAiResponse?.(response);
369
- if (!compiled && response.patch && Object.keys(response.patch).length > 0) {
370
- return {
371
- type: 'error',
372
- message: 'O formulario exige componentEditPlan validado pelo manifesto antes de gerar patch local.',
373
- warnings: [
374
- 'free-dynamic-form-patch-rejected',
375
- 'Use componentEditPlan validado contra PRAXIS_DYNAMIC_FORM_AUTHORING_MANIFEST.',
376
- ],
377
- };
378
- }
379
- if (!compiled) {
380
- return response;
381
- }
382
- if (compiled.type === 'error') {
383
- return {
384
- type: 'error',
385
- message: compiled.message || 'O componentEditPlan do formulario nao passou na validacao de capacidades.',
386
- warnings: compiled.warnings,
387
- };
388
- }
389
- const warnings = [
390
- ...(response.warnings ?? []),
391
- ...(compiled.warnings ?? []),
392
- ];
393
- return {
394
- ...response,
395
- ...compiled,
396
- patch: compiled.patch,
397
- warnings: warnings.length ? warnings : undefined,
398
- };
399
- }
400
- toChatMessages(messages, prompt) {
401
- const supported = (messages ?? [])
402
- .filter((message) => message.role === 'user' || message.role === 'assistant' || message.role === 'system')
403
- .map((message) => ({
404
- role: message.role,
405
- content: message.text,
406
- }))
407
- .filter((message) => message.content.trim().length > 0);
408
- return supported.length ? supported : [{ role: 'user', content: prompt }];
409
- }
410
- toClarificationQuestions(response) {
411
- const labels = response.questions?.length
412
- ? response.questions
413
- : response.message
414
- ? [response.message]
415
- : ['Qual ajuste voce quer aplicar no formulario?'];
416
- const options = this.toQuickReplies(response).map((reply) => ({
417
- id: reply.id,
418
- label: reply.label,
419
- value: reply.prompt,
420
- description: reply.description ?? undefined,
421
- contextHints: reply.contextHints ? { ...reply.contextHints } : undefined,
422
- }));
423
- return labels.map((label, index) => ({
424
- id: `dynamic-form-clarification-${index + 1}`,
425
- type: options.length ? 'single-choice' : 'text',
426
- label,
427
- allowCustom: true,
428
- options,
429
- }));
430
- }
431
- toQuickReplies(response) {
432
- const payloads = response.optionPayloads ?? [];
433
- if (payloads.length) {
434
- return payloads
435
- .map((option, index) => {
436
- const label = option.label?.trim() || option.value?.trim() || `Opcao ${index + 1}`;
437
- const prompt = option.value?.trim() || option.example?.trim() || label;
438
- return {
439
- id: `option-${index + 1}`,
440
- label,
441
- prompt,
442
- kind: 'clarification-option',
443
- description: option.example?.trim() || undefined,
444
- contextHints: this.optionalJsonObject(option.contextHints),
445
- };
446
- });
447
- }
448
- return (response.options ?? [])
449
- .filter((option) => !!option?.trim())
450
- .map((option, index) => ({
451
- id: `option-${index + 1}`,
452
- label: option.trim(),
453
- prompt: option.trim(),
454
- kind: 'clarification-option',
455
- description: undefined,
456
- contextHints: undefined,
457
- }));
458
- }
459
- buildCurrentStateDigest(currentState, runtimeState) {
460
- const fields = Array.isArray(currentState['fieldMetadata'])
461
- ? currentState['fieldMetadata']
462
- .map((field) => this.toRecord(field)?.['name'])
463
- .filter((field) => typeof field === 'string' && field.length > 0)
464
- : undefined;
465
- const sections = Array.isArray(currentState['sections']) ? currentState['sections'].length : undefined;
466
- return {
467
- ...(fields?.length ? { columns: fields } : {}),
468
- ...(typeof runtimeState?.['totalFields'] === 'number'
469
- ? { rowCount: runtimeState['totalFields'] }
470
- : sections !== undefined
471
- ? { rowCount: sections }
472
- : {}),
473
- };
474
- }
475
- shouldRestrictToInlineHelp(contextHints) {
476
- const policy = this.toRecord(contextHints?.['runtimeAuthoringPolicy']);
477
- return policy?.['canApplyLocalPatch'] === false;
478
- }
479
- toInlineHelpOnlyResult(prompt, request, contextHints) {
480
- const policy = this.toRecord(contextHints?.['runtimeAuthoringPolicy']);
481
- const reason = typeof policy?.['reason'] === 'string'
482
- ? policy['reason']
483
- : 'Formulario em modo de leitura ou readonly.';
484
- return {
485
- state: 'success',
486
- phase: 'summarize',
487
- sessionId: request.sessionId,
488
- assistantMessage: `Posso ajudar explicando este formulario ou diagnosticando o estado atual, mas nao vou aplicar alteracoes locais aqui. Motivo: ${reason}`,
489
- statusText: 'Modo somente assistencia.',
490
- canApply: false,
491
- pendingPatch: null,
492
- quickReplies: [
493
- {
494
- id: 'explain-current-form',
495
- label: 'Explicar formulario atual',
496
- prompt: `Explique este formulario considerando: ${prompt}`,
497
- kind: 'inline-help',
498
- icon: 'help',
499
- },
500
- ],
501
- };
502
- }
503
- optionalJsonObject(value) {
504
- if (value === undefined || value === null) {
505
- return undefined;
506
- }
507
- const object = this.toAiJsonObject(value);
508
- return Object.keys(object).length ? object : undefined;
509
- }
510
- mergeJsonObjects(base, overlay) {
511
- if (!base)
512
- return overlay;
513
- if (!overlay)
514
- return base;
515
- return {
516
- ...base,
517
- ...overlay,
518
- };
519
- }
520
- toAiJsonObject(value) {
521
- const record = this.toRecord(value);
522
- if (!record) {
523
- return {};
524
- }
525
- try {
526
- return JSON.parse(JSON.stringify(record));
527
- }
528
- catch {
529
- return {};
530
- }
531
- }
532
- toRecord(value) {
533
- return value && typeof value === 'object' && !Array.isArray(value)
534
- ? value
535
- : null;
536
- }
537
- }
538
-
539
- export { DynamicFormAgenticAuthoringTurnFlow };