@nyaruka/temba-components 0.129.10 → 0.129.11
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/CHANGELOG.md +13 -0
- package/demo/data/flows/sample-flow.json +96 -56
- package/dist/temba-components.js +278 -268
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +9 -6
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/config.js +2 -8
- package/out-tsc/src/flow/config.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm.js +101 -0
- package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +4 -89
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_subflow.js +123 -3
- package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_ticket.js +115 -13
- package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_webhook.js +160 -12
- package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +48 -66
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/utils.js +115 -0
- package/out-tsc/src/utils.js.map +1 -1
- package/out-tsc/test/nodes/split_by_llm.test.js +174 -0
- package/out-tsc/test/nodes/split_by_llm.test.js.map +1 -0
- package/package.json +1 -1
- package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
- package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
- package/screenshots/truth/checkbox/checkbox-label-background-hover.png +0 -0
- package/screenshots/truth/checkbox/checkbox-no-label-no-background-hover.png +0 -0
- package/screenshots/truth/checkbox/checkbox-whitespace-label-no-background-hover.png +0 -0
- package/screenshots/truth/checkbox/checkbox-with-help-text.png +0 -0
- package/screenshots/truth/checkbox/checked.png +0 -0
- package/screenshots/truth/checkbox/default.png +0 -0
- package/screenshots/truth/colorpicker/default.png +0 -0
- package/screenshots/truth/colorpicker/focused.png +0 -0
- package/screenshots/truth/colorpicker/initialized.png +0 -0
- package/screenshots/truth/colorpicker/selected.png +0 -0
- package/screenshots/truth/compose/attachments-tab.png +0 -0
- package/screenshots/truth/compose/attachments-with-files.png +0 -0
- package/screenshots/truth/compose/intial-text.png +0 -0
- package/screenshots/truth/compose/no-counter.png +0 -0
- package/screenshots/truth/compose/wraps-text-and-spaces.png +0 -0
- package/screenshots/truth/compose/wraps-text-and-url.png +0 -0
- package/screenshots/truth/compose/wraps-text-no-spaces.png +0 -0
- package/screenshots/truth/contacts/chat-failure.png +0 -0
- package/screenshots/truth/contacts/chat-for-active-contact.png +0 -0
- package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
- package/screenshots/truth/counter/summary.png +0 -0
- package/screenshots/truth/counter/text.png +0 -0
- package/screenshots/truth/counter/unicode-variables.png +0 -0
- package/screenshots/truth/counter/unicode.png +0 -0
- package/screenshots/truth/counter/variable.png +0 -0
- package/screenshots/truth/datepicker/date-truncated-time.png +0 -0
- package/screenshots/truth/datepicker/date.png +0 -0
- package/screenshots/truth/datepicker/initial-timezone.png +0 -0
- package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
- package/screenshots/truth/datepicker/updated-keyboard-date.png +0 -0
- package/screenshots/truth/dialog/focused.png +0 -0
- package/screenshots/truth/dropdown/right-edge-collision.png +0 -0
- package/screenshots/truth/editor/router.png +0 -0
- package/screenshots/truth/editor/send_msg.png +0 -0
- package/screenshots/truth/editor/set_contact_language.png +0 -0
- package/screenshots/truth/editor/set_contact_name.png +0 -0
- package/screenshots/truth/editor/set_run_result.png +0 -0
- package/screenshots/truth/editor/wait.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-checked.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-unchecked.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-with-errors.png +0 -0
- package/screenshots/truth/field-renderer/context-comparison.png +0 -0
- package/screenshots/truth/field-renderer/key-value-with-label.png +0 -0
- package/screenshots/truth/field-renderer/message-editor-with-label.png +0 -0
- package/screenshots/truth/field-renderer/select-multi.png +0 -0
- package/screenshots/truth/field-renderer/select-no-label.png +0 -0
- package/screenshots/truth/field-renderer/select-with-label.png +0 -0
- package/screenshots/truth/field-renderer/text-evaluated.png +0 -0
- package/screenshots/truth/field-renderer/text-no-label.png +0 -0
- package/screenshots/truth/field-renderer/text-with-errors.png +0 -0
- package/screenshots/truth/field-renderer/text-with-label.png +0 -0
- package/screenshots/truth/field-renderer/textarea-evaluated.png +0 -0
- package/screenshots/truth/field-renderer/textarea-with-label.png +0 -0
- package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
- package/screenshots/truth/list/fields-dragging.png +0 -0
- package/screenshots/truth/list/fields-filtered.png +0 -0
- package/screenshots/truth/list/fields-hovered.png +0 -0
- package/screenshots/truth/list/fields.png +0 -0
- package/screenshots/truth/list/items-selected.png +0 -0
- package/screenshots/truth/list/items-updated.png +0 -0
- package/screenshots/truth/list/items.png +0 -0
- package/screenshots/truth/menu/menu-focused-with items.png +0 -0
- package/screenshots/truth/menu/menu-refresh-1.png +0 -0
- package/screenshots/truth/menu/menu-refresh-2.png +0 -0
- package/screenshots/truth/menu/menu-submenu.png +0 -0
- package/screenshots/truth/menu/menu-tasks-nextup.png +0 -0
- package/screenshots/truth/menu/menu-tasks.png +0 -0
- package/screenshots/truth/message-editor/autogrow-initial-content.png +0 -0
- package/screenshots/truth/message-editor/default.png +0 -0
- package/screenshots/truth/message-editor/drag-highlight.png +0 -0
- package/screenshots/truth/message-editor/filtered-attachments.png +0 -0
- package/screenshots/truth/message-editor/with-completion.png +0 -0
- package/screenshots/truth/message-editor/with-properties.png +0 -0
- package/screenshots/truth/modax/form.png +0 -0
- package/screenshots/truth/modax/simple.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
- package/screenshots/truth/omnibox/selected.png +0 -0
- package/screenshots/truth/options/block.png +0 -0
- package/screenshots/truth/run-list/basic.png +0 -0
- package/screenshots/truth/select/disabled-multi-selection.png +0 -0
- package/screenshots/truth/select/disabled-selection.png +0 -0
- package/screenshots/truth/select/disabled.png +0 -0
- package/screenshots/truth/select/embedded.png +0 -0
- package/screenshots/truth/select/empty-options.png +0 -0
- package/screenshots/truth/select/expression-selected.png +0 -0
- package/screenshots/truth/select/expressions.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/screenshots/truth/select/local-options.png +0 -0
- package/screenshots/truth/select/multi-with-endpoint.png +0 -0
- package/screenshots/truth/select/multiple-initial-values.png +0 -0
- package/screenshots/truth/select/remote-options.png +0 -0
- package/screenshots/truth/select/search-enabled.png +0 -0
- package/screenshots/truth/select/search-multi-no-matches.png +0 -0
- package/screenshots/truth/select/search-selected-focus.png +0 -0
- package/screenshots/truth/select/search-selected.png +0 -0
- package/screenshots/truth/select/search-with-selected.png +0 -0
- package/screenshots/truth/select/searching.png +0 -0
- package/screenshots/truth/select/selected-multi-maxitems-reached.png +0 -0
- package/screenshots/truth/select/selected-multi.png +0 -0
- package/screenshots/truth/select/selected-single.png +0 -0
- package/screenshots/truth/select/selection-clearable.png +0 -0
- package/screenshots/truth/select/static-initial-value.png +0 -0
- package/screenshots/truth/select/static-initial-via-selected.png +0 -0
- package/screenshots/truth/select/truncated-selection.png +0 -0
- package/screenshots/truth/select/with-placeholder.png +0 -0
- package/screenshots/truth/select/without-placeholder.png +0 -0
- package/screenshots/truth/slider/update-slider-on-circle-dragged.png +0 -0
- package/screenshots/truth/templates/default.png +0 -0
- package/screenshots/truth/templates/unapproved.png +0 -0
- package/screenshots/truth/textinput/autogrow-initial.png +0 -0
- package/screenshots/truth/textinput/input-disabled.png +0 -0
- package/screenshots/truth/textinput/input-focused.png +0 -0
- package/screenshots/truth/textinput/input-form.png +0 -0
- package/screenshots/truth/textinput/input-inserted.png +0 -0
- package/screenshots/truth/textinput/input-placeholder.png +0 -0
- package/screenshots/truth/textinput/input-updated.png +0 -0
- package/screenshots/truth/textinput/input.png +0 -0
- package/screenshots/truth/textinput/textarea-focused.png +0 -0
- package/screenshots/truth/textinput/textarea.png +0 -0
- package/src/events.ts +4 -2
- package/src/flow/Editor.ts +6 -3
- package/src/flow/actions/set_contact_channel.ts +1 -1
- package/src/flow/actions/set_contact_field.ts +1 -1
- package/src/flow/actions/set_contact_language.ts +1 -1
- package/src/flow/actions/set_contact_status.ts +1 -1
- package/src/flow/config.ts +2 -8
- package/src/flow/nodes/split_by_llm.ts +119 -0
- package/src/flow/nodes/split_by_llm_categorize.ts +13 -116
- package/src/flow/nodes/split_by_subflow.ts +153 -3
- package/src/flow/nodes/split_by_ticket.ts +135 -12
- package/src/flow/nodes/split_by_webhook.ts +187 -12
- package/src/live/ContactChat.ts +56 -58
- package/src/store/flow-definition.d.ts +2 -1
- package/src/utils.ts +192 -0
- package/test/nodes/split_by_llm.test.ts +232 -0
- package/test-assets/style.css +36 -234
- package/web-dev-server.config.mjs +26 -0
- package/web-test-runner.config.mjs +1 -1
- package/out-tsc/src/flow/actions/call_llm.js +0 -64
- package/out-tsc/src/flow/actions/call_llm.js.map +0 -1
- package/out-tsc/src/flow/actions/call_webhook.js +0 -131
- package/out-tsc/src/flow/actions/call_webhook.js.map +0 -1
- package/out-tsc/src/flow/actions/enter_flow.js +0 -14
- package/out-tsc/src/flow/actions/enter_flow.js.map +0 -1
- package/out-tsc/src/flow/actions/open_ticket.js +0 -73
- package/out-tsc/src/flow/actions/open_ticket.js.map +0 -1
- package/out-tsc/test/actions/call_llm.test.js +0 -103
- package/out-tsc/test/actions/call_llm.test.js.map +0 -1
- package/src/flow/actions/call_llm.ts +0 -66
- package/src/flow/actions/call_webhook.ts +0 -143
- package/src/flow/actions/enter_flow.ts +0 -15
- package/src/flow/actions/open_ticket.ts +0 -83
- package/test/actions/call_llm.test.ts +0 -137
package/src/live/ContactChat.ts
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
ContactGroupsEvent,
|
|
28
28
|
ContactHistoryPage,
|
|
29
29
|
ContactLanguageChangedEvent,
|
|
30
|
+
ContactStatusChangedEvent,
|
|
30
31
|
MsgEvent,
|
|
31
32
|
NameChangedEvent,
|
|
32
33
|
OptInEvent,
|
|
@@ -61,6 +62,7 @@ export enum Events {
|
|
|
61
62
|
CONTACT_GROUPS_CHANGED = 'contact_groups_changed',
|
|
62
63
|
CONTACT_LANGUAGE_CHANGED = 'contact_language_changed',
|
|
63
64
|
CONTACT_NAME_CHANGED = 'contact_name_changed',
|
|
65
|
+
CONTACT_STATUS_CHANGED = 'contact_status_changed',
|
|
64
66
|
CONTACT_URNS_CHANGED = 'contact_urns_changed',
|
|
65
67
|
IVR_CREATED = 'ivr_created',
|
|
66
68
|
MSG_CREATED = 'msg_created',
|
|
@@ -97,28 +99,10 @@ const renderInfoList = (singular: string, plural: string, items: any[]) => {
|
|
|
97
99
|
};
|
|
98
100
|
|
|
99
101
|
const renderChannelEvent = (event: ChannelEvent): string => {
|
|
100
|
-
if (event.
|
|
101
|
-
return '
|
|
102
|
-
} else if (event.event.type === 'mo_miss') {
|
|
103
|
-
return 'Missed incoming call';
|
|
104
|
-
} else if (event.event.type === 'new_conversation') {
|
|
105
|
-
return 'Started conversation';
|
|
106
|
-
} else if (event.channel_event_type === 'welcome_message') {
|
|
107
|
-
return 'Welcome Message Sent';
|
|
108
|
-
} else if (event.event.type === 'referral') {
|
|
109
|
-
return 'Referred';
|
|
110
|
-
} else if (event.event.type === 'follow') {
|
|
111
|
-
return 'Followed';
|
|
102
|
+
if (event.channel_event_type === 'welcome_message') {
|
|
103
|
+
return 'Welcome message sent';
|
|
112
104
|
} else if (event.event.type === 'stop_contact') {
|
|
113
105
|
return 'Stopped';
|
|
114
|
-
} else if (event.event.type === 'mt_call') {
|
|
115
|
-
return 'Outgoing Phone Call'; // deprecated
|
|
116
|
-
} else if (event.event.type == 'mo_call') {
|
|
117
|
-
return 'Incoming Phone call'; // deprecated
|
|
118
|
-
} else if (event.event.type == 'optin') {
|
|
119
|
-
return `Opted in to **${event.event.optin?.name}**`; // deprecated
|
|
120
|
-
} else if (event.event.type == 'optout') {
|
|
121
|
-
return `Opted out of **${event.event.optin?.name}**`; // deprecated
|
|
122
106
|
}
|
|
123
107
|
};
|
|
124
108
|
|
|
@@ -220,6 +204,12 @@ export const renderContactLanguageChangedEvent = (
|
|
|
220
204
|
return `Language updated to **${event.language}**`;
|
|
221
205
|
};
|
|
222
206
|
|
|
207
|
+
export const renderContactStatusChangedEvent = (
|
|
208
|
+
event: ContactStatusChangedEvent
|
|
209
|
+
): string => {
|
|
210
|
+
return `Status updated to **${event.status}**`;
|
|
211
|
+
};
|
|
212
|
+
|
|
223
213
|
export const renderCallEvent = (event: CallEvent): string => {
|
|
224
214
|
if (event.type === Events.CALL_CREATED) {
|
|
225
215
|
return `Call started`;
|
|
@@ -232,7 +222,7 @@ export const renderCallEvent = (event: CallEvent): string => {
|
|
|
232
222
|
|
|
233
223
|
export const renderOptInEvent = (event: OptInEvent): string => {
|
|
234
224
|
if (event.type === Events.OPTIN_REQUESTED) {
|
|
235
|
-
return `Requested opt-in for
|
|
225
|
+
return `Requested opt-in for **${event.optin.name}**`;
|
|
236
226
|
} else if (event.type === Events.OPTIN_STARTED) {
|
|
237
227
|
return `Opted in to **${event.optin.name}**`;
|
|
238
228
|
} else if (event.type === Events.OPTIN_STOPPED) {
|
|
@@ -632,53 +622,58 @@ export class ContactChat extends ContactStoreElement {
|
|
|
632
622
|
public getEventMessage(event: ContactEvent): ChatEvent {
|
|
633
623
|
let message = null;
|
|
634
624
|
switch (event.type) {
|
|
635
|
-
case Events.
|
|
625
|
+
case Events.AIRTIME_TRANSFERRED:
|
|
636
626
|
message = {
|
|
637
627
|
type: MessageType.Inline,
|
|
638
|
-
text:
|
|
628
|
+
text: renderAirtimeTransferredEvent(event as AirtimeTransferredEvent)
|
|
639
629
|
};
|
|
640
630
|
break;
|
|
641
|
-
case Events.
|
|
631
|
+
case Events.CALL_CREATED:
|
|
632
|
+
case Events.CALL_MISSED:
|
|
633
|
+
case Events.CALL_RECEIVED:
|
|
642
634
|
message = {
|
|
643
635
|
type: MessageType.Inline,
|
|
644
|
-
text:
|
|
636
|
+
text: renderCallEvent(event as CallEvent)
|
|
645
637
|
};
|
|
646
638
|
break;
|
|
647
|
-
case Events.
|
|
639
|
+
case Events.CHAT_STARTED:
|
|
648
640
|
message = {
|
|
649
641
|
type: MessageType.Inline,
|
|
650
|
-
text:
|
|
642
|
+
text: renderChatStartedEvent(event as ChatStartedEvent)
|
|
651
643
|
};
|
|
652
644
|
break;
|
|
653
|
-
case Events.
|
|
645
|
+
case Events.CONTACT_FIELD_CHANGED:
|
|
654
646
|
message = {
|
|
655
647
|
type: MessageType.Inline,
|
|
656
|
-
text:
|
|
648
|
+
text: renderUpdateEvent(event as UpdateFieldEvent)
|
|
657
649
|
};
|
|
658
650
|
break;
|
|
659
|
-
case Events.
|
|
651
|
+
case Events.CONTACT_GROUPS_CHANGED:
|
|
660
652
|
message = {
|
|
661
653
|
type: MessageType.Inline,
|
|
662
|
-
text:
|
|
654
|
+
text: renderContactGroupsEvent(event as ContactGroupsEvent)
|
|
663
655
|
};
|
|
664
656
|
break;
|
|
665
|
-
case Events.
|
|
666
|
-
case Events.RUN_ENDED:
|
|
657
|
+
case Events.CONTACT_LANGUAGE_CHANGED:
|
|
667
658
|
message = {
|
|
668
659
|
type: MessageType.Inline,
|
|
669
|
-
text:
|
|
660
|
+
text: renderContactLanguageChangedEvent(
|
|
661
|
+
event as ContactLanguageChangedEvent
|
|
662
|
+
)
|
|
670
663
|
};
|
|
671
664
|
break;
|
|
672
|
-
case Events.
|
|
665
|
+
case Events.CONTACT_NAME_CHANGED:
|
|
673
666
|
message = {
|
|
674
667
|
type: MessageType.Inline,
|
|
675
|
-
text:
|
|
668
|
+
text: renderNameChanged(event as NameChangedEvent)
|
|
676
669
|
};
|
|
677
670
|
break;
|
|
678
|
-
case Events.
|
|
671
|
+
case Events.CONTACT_STATUS_CHANGED:
|
|
679
672
|
message = {
|
|
680
673
|
type: MessageType.Inline,
|
|
681
|
-
text:
|
|
674
|
+
text: renderContactStatusChangedEvent(
|
|
675
|
+
event as ContactStatusChangedEvent
|
|
676
|
+
)
|
|
682
677
|
};
|
|
683
678
|
break;
|
|
684
679
|
case Events.CONTACT_URNS_CHANGED:
|
|
@@ -687,52 +682,55 @@ export class ContactChat extends ContactStoreElement {
|
|
|
687
682
|
text: renderContactURNsChanged(event as URNsChangedEvent)
|
|
688
683
|
};
|
|
689
684
|
break;
|
|
690
|
-
case Events.
|
|
685
|
+
case Events.OPTIN_REQUESTED:
|
|
686
|
+
case Events.OPTIN_STARTED:
|
|
687
|
+
case Events.OPTIN_STOPPED:
|
|
691
688
|
message = {
|
|
692
689
|
type: MessageType.Inline,
|
|
693
|
-
text:
|
|
690
|
+
text: renderOptInEvent(event as OptInEvent)
|
|
694
691
|
};
|
|
695
692
|
break;
|
|
696
|
-
case Events.
|
|
693
|
+
case Events.RUN_STARTED:
|
|
694
|
+
case Events.RUN_ENDED:
|
|
697
695
|
message = {
|
|
698
696
|
type: MessageType.Inline,
|
|
699
|
-
text:
|
|
697
|
+
text: renderRunEvent(event as RunEvent)
|
|
700
698
|
};
|
|
701
699
|
break;
|
|
702
|
-
case Events.
|
|
703
|
-
case Events.CALL_MISSED:
|
|
704
|
-
case Events.CALL_RECEIVED:
|
|
700
|
+
case Events.TICKET_ASSIGNED:
|
|
705
701
|
message = {
|
|
706
702
|
type: MessageType.Inline,
|
|
707
|
-
text:
|
|
703
|
+
text: renderTicketAssigned(event as TicketEvent)
|
|
708
704
|
};
|
|
709
705
|
break;
|
|
710
|
-
case Events.
|
|
706
|
+
case Events.TICKET_CLOSED:
|
|
711
707
|
message = {
|
|
712
708
|
type: MessageType.Inline,
|
|
713
|
-
text:
|
|
709
|
+
text: renderTicketAction(event as TicketEvent, 'closed')
|
|
714
710
|
};
|
|
715
711
|
break;
|
|
716
|
-
case Events.
|
|
712
|
+
case Events.TICKET_OPENED:
|
|
717
713
|
message = {
|
|
718
714
|
type: MessageType.Inline,
|
|
719
|
-
text:
|
|
715
|
+
text: renderTicketAction(event as TicketEvent, 'opened')
|
|
720
716
|
};
|
|
721
717
|
break;
|
|
722
|
-
case Events.
|
|
718
|
+
case Events.TICKET_REOPENED:
|
|
723
719
|
message = {
|
|
724
720
|
type: MessageType.Inline,
|
|
725
|
-
text:
|
|
726
|
-
event as ContactLanguageChangedEvent
|
|
727
|
-
)
|
|
721
|
+
text: renderTicketAction(event as TicketEvent, 'reopened')
|
|
728
722
|
};
|
|
729
723
|
break;
|
|
730
|
-
case Events.
|
|
731
|
-
case Events.OPTIN_STARTED:
|
|
732
|
-
case Events.OPTIN_STOPPED:
|
|
724
|
+
case Events.TICKET_TOPIC_CHANGED:
|
|
733
725
|
message = {
|
|
734
726
|
type: MessageType.Inline,
|
|
735
|
-
text:
|
|
727
|
+
text: `Topic changed to **${(event as TicketEvent).topic.name}**`
|
|
728
|
+
};
|
|
729
|
+
break;
|
|
730
|
+
case Events.CHANNEL_EVENT: // deprecated
|
|
731
|
+
message = {
|
|
732
|
+
type: MessageType.Inline,
|
|
733
|
+
text: renderChannelEvent(event as ChannelEvent)
|
|
736
734
|
};
|
|
737
735
|
break;
|
|
738
736
|
}
|
package/src/utils.ts
CHANGED
|
@@ -932,3 +932,195 @@ export const getMiddle = (a: DOMRect, b: DOMRect) => {
|
|
|
932
932
|
|
|
933
933
|
// Export the UUID function from the uuid package
|
|
934
934
|
export { generateUUID };
|
|
935
|
+
|
|
936
|
+
// Helper types for router creation
|
|
937
|
+
export interface RouterCategory {
|
|
938
|
+
uuid: string;
|
|
939
|
+
name: string;
|
|
940
|
+
exit_uuid: string;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
export interface RouterExit {
|
|
944
|
+
uuid: string;
|
|
945
|
+
destination_uuid: string | null;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
export interface RouterCase {
|
|
949
|
+
uuid: string;
|
|
950
|
+
type: string;
|
|
951
|
+
arguments: string[];
|
|
952
|
+
category_uuid: string;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
export interface CreateCategoryParams {
|
|
956
|
+
name: string;
|
|
957
|
+
existingCategories: any[];
|
|
958
|
+
existingExits: any[];
|
|
959
|
+
existingCases?: any[];
|
|
960
|
+
caseConfig?: {
|
|
961
|
+
type: string;
|
|
962
|
+
arguments: string[];
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// Helper function to create or preserve a category with its exit and case
|
|
967
|
+
export const createOrPreserveCategory = (
|
|
968
|
+
params: CreateCategoryParams
|
|
969
|
+
): {
|
|
970
|
+
category: RouterCategory;
|
|
971
|
+
exit: RouterExit;
|
|
972
|
+
case?: RouterCase;
|
|
973
|
+
} => {
|
|
974
|
+
const { name, existingCategories, existingExits, existingCases, caseConfig } =
|
|
975
|
+
params;
|
|
976
|
+
|
|
977
|
+
// Find existing category
|
|
978
|
+
const existingCategory = existingCategories.find((cat) => cat.name === name);
|
|
979
|
+
const existingExit = existingCategory
|
|
980
|
+
? existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid)
|
|
981
|
+
: null;
|
|
982
|
+
const existingCase =
|
|
983
|
+
existingCategory && existingCases
|
|
984
|
+
? existingCases.find(
|
|
985
|
+
(case_) => case_.category_uuid === existingCategory.uuid
|
|
986
|
+
)
|
|
987
|
+
: null;
|
|
988
|
+
|
|
989
|
+
// Use existing UUIDs or generate new ones
|
|
990
|
+
const categoryUuid = existingCategory?.uuid || generateUUID();
|
|
991
|
+
const exitUuid = existingExit?.uuid || generateUUID();
|
|
992
|
+
const caseUuid = existingCase?.uuid || generateUUID();
|
|
993
|
+
|
|
994
|
+
const category: RouterCategory = {
|
|
995
|
+
uuid: categoryUuid,
|
|
996
|
+
name: name,
|
|
997
|
+
exit_uuid: exitUuid
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
const exit: RouterExit = {
|
|
1001
|
+
uuid: exitUuid,
|
|
1002
|
+
destination_uuid: existingExit?.destination_uuid || null
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
const result: {
|
|
1006
|
+
category: RouterCategory;
|
|
1007
|
+
exit: RouterExit;
|
|
1008
|
+
case?: RouterCase;
|
|
1009
|
+
} = { category, exit };
|
|
1010
|
+
|
|
1011
|
+
if (caseConfig) {
|
|
1012
|
+
result.case = {
|
|
1013
|
+
uuid: caseUuid,
|
|
1014
|
+
type: caseConfig.type,
|
|
1015
|
+
arguments: caseConfig.arguments,
|
|
1016
|
+
category_uuid: categoryUuid
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
return result;
|
|
1021
|
+
};
|
|
1022
|
+
|
|
1023
|
+
// Helper function to create a complete router with standard Success/Failure categories
|
|
1024
|
+
export const createSuccessFailureRouter = (
|
|
1025
|
+
operand: string,
|
|
1026
|
+
successCaseConfig: { type: string; arguments: string[] },
|
|
1027
|
+
existingCategories: any[] = [],
|
|
1028
|
+
existingExits: any[] = [],
|
|
1029
|
+
existingCases: any[] = []
|
|
1030
|
+
) => {
|
|
1031
|
+
const success = createOrPreserveCategory({
|
|
1032
|
+
name: 'Success',
|
|
1033
|
+
existingCategories,
|
|
1034
|
+
existingExits,
|
|
1035
|
+
existingCases,
|
|
1036
|
+
caseConfig: successCaseConfig
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
const failure = createOrPreserveCategory({
|
|
1040
|
+
name: 'Failure',
|
|
1041
|
+
existingCategories,
|
|
1042
|
+
existingExits
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
return {
|
|
1046
|
+
router: {
|
|
1047
|
+
type: 'switch' as const,
|
|
1048
|
+
categories: [success.category, failure.category],
|
|
1049
|
+
default_category_uuid: failure.category.uuid,
|
|
1050
|
+
operand: operand,
|
|
1051
|
+
cases: success.case ? [success.case] : []
|
|
1052
|
+
},
|
|
1053
|
+
exits: [success.exit, failure.exit]
|
|
1054
|
+
};
|
|
1055
|
+
};
|
|
1056
|
+
|
|
1057
|
+
// Helper function to create a multi-category router with Other/Failure defaults
|
|
1058
|
+
export const createMultiCategoryRouter = (
|
|
1059
|
+
operand: string,
|
|
1060
|
+
userCategories: string[],
|
|
1061
|
+
categoryToCaseMap: (categoryName: string) => {
|
|
1062
|
+
type: string;
|
|
1063
|
+
arguments: string[];
|
|
1064
|
+
},
|
|
1065
|
+
existingCategories: any[] = [],
|
|
1066
|
+
existingExits: any[] = [],
|
|
1067
|
+
existingCases: any[] = []
|
|
1068
|
+
) => {
|
|
1069
|
+
const categories: RouterCategory[] = [];
|
|
1070
|
+
const exits: RouterExit[] = [];
|
|
1071
|
+
const cases: RouterCase[] = [];
|
|
1072
|
+
|
|
1073
|
+
// Add user categories
|
|
1074
|
+
userCategories.forEach((categoryName) => {
|
|
1075
|
+
const result = createOrPreserveCategory({
|
|
1076
|
+
name: categoryName,
|
|
1077
|
+
existingCategories,
|
|
1078
|
+
existingExits,
|
|
1079
|
+
existingCases,
|
|
1080
|
+
caseConfig: categoryToCaseMap(categoryName)
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
categories.push(result.category);
|
|
1084
|
+
exits.push(result.exit);
|
|
1085
|
+
if (result.case) {
|
|
1086
|
+
cases.push(result.case);
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
// Add "Other" category (default)
|
|
1091
|
+
const other = createOrPreserveCategory({
|
|
1092
|
+
name: 'Other',
|
|
1093
|
+
existingCategories,
|
|
1094
|
+
existingExits
|
|
1095
|
+
});
|
|
1096
|
+
categories.push(other.category);
|
|
1097
|
+
exits.push(other.exit);
|
|
1098
|
+
|
|
1099
|
+
// Add "Failure" category
|
|
1100
|
+
const failure = createOrPreserveCategory({
|
|
1101
|
+
name: 'Failure',
|
|
1102
|
+
existingCategories,
|
|
1103
|
+
existingExits,
|
|
1104
|
+
existingCases,
|
|
1105
|
+
caseConfig: {
|
|
1106
|
+
type: 'has_only_text',
|
|
1107
|
+
arguments: ['<ERROR>']
|
|
1108
|
+
}
|
|
1109
|
+
});
|
|
1110
|
+
categories.push(failure.category);
|
|
1111
|
+
exits.push(failure.exit);
|
|
1112
|
+
if (failure.case) {
|
|
1113
|
+
cases.push(failure.case);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
return {
|
|
1117
|
+
router: {
|
|
1118
|
+
type: 'switch' as const,
|
|
1119
|
+
categories: categories,
|
|
1120
|
+
default_category_uuid: other.category.uuid,
|
|
1121
|
+
operand: operand,
|
|
1122
|
+
cases: cases
|
|
1123
|
+
},
|
|
1124
|
+
exits: exits
|
|
1125
|
+
};
|
|
1126
|
+
};
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { split_by_llm } from '../../src/flow/nodes/split_by_llm';
|
|
3
|
+
import { Node, CallLLM } from '../../src/store/flow-definition';
|
|
4
|
+
import { NodeTest } from '../NodeHelper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test suite for the split_by_llm node configuration.
|
|
8
|
+
*/
|
|
9
|
+
describe('split_by_llm node config', () => {
|
|
10
|
+
const helper = new NodeTest(split_by_llm, 'split_by_llm');
|
|
11
|
+
|
|
12
|
+
describe('basic properties', () => {
|
|
13
|
+
helper.testBasicProperties();
|
|
14
|
+
|
|
15
|
+
it('has correct name', () => {
|
|
16
|
+
expect(split_by_llm.name).to.equal('Call AI');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('has form configuration', () => {
|
|
20
|
+
expect(split_by_llm.form).to.exist;
|
|
21
|
+
expect(split_by_llm.form.llm).to.exist;
|
|
22
|
+
expect(split_by_llm.form.instructions).to.exist;
|
|
23
|
+
expect(split_by_llm.form.input).to.exist;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('has layout configuration', () => {
|
|
27
|
+
expect(split_by_llm.layout).to.exist;
|
|
28
|
+
expect(split_by_llm.layout).to.deep.equal([
|
|
29
|
+
'llm',
|
|
30
|
+
'input',
|
|
31
|
+
'instructions'
|
|
32
|
+
]);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('toFormData', () => {
|
|
37
|
+
it('extracts data from node with call_llm action', () => {
|
|
38
|
+
const node: Node = {
|
|
39
|
+
uuid: 'test-node',
|
|
40
|
+
actions: [
|
|
41
|
+
{
|
|
42
|
+
uuid: 'test-action',
|
|
43
|
+
type: 'call_llm',
|
|
44
|
+
llm: { uuid: 'gpt-4', name: 'GPT 4.1' },
|
|
45
|
+
instructions: 'Translate to French',
|
|
46
|
+
input: '@input',
|
|
47
|
+
output_local: '_llm_output'
|
|
48
|
+
} as CallLLM
|
|
49
|
+
],
|
|
50
|
+
exits: []
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const formData = split_by_llm.toFormData(node);
|
|
54
|
+
|
|
55
|
+
expect(formData.uuid).to.equal('test-node');
|
|
56
|
+
expect(formData.llm).to.deep.equal([{ value: 'gpt-4', name: 'GPT 4.1' }]);
|
|
57
|
+
expect(formData.input).to.equal('@input');
|
|
58
|
+
expect(formData.instructions).to.equal('Translate to French');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('handles empty node', () => {
|
|
62
|
+
const node: Node = {
|
|
63
|
+
uuid: 'test-node',
|
|
64
|
+
actions: [],
|
|
65
|
+
exits: []
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const formData = split_by_llm.toFormData(node);
|
|
69
|
+
|
|
70
|
+
expect(formData.uuid).to.equal('test-node');
|
|
71
|
+
expect(formData.llm).to.deep.equal([]);
|
|
72
|
+
expect(formData.input).to.equal('@input');
|
|
73
|
+
expect(formData.instructions).to.equal('');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('fromFormData', () => {
|
|
78
|
+
it('creates node with call_llm action and router', () => {
|
|
79
|
+
const formData = {
|
|
80
|
+
uuid: 'test-node',
|
|
81
|
+
llm: [{ value: 'gpt-4', name: 'GPT 4.1' }],
|
|
82
|
+
input: '@input',
|
|
83
|
+
instructions: 'Translate to French'
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const originalNode: Node = {
|
|
87
|
+
uuid: 'test-node',
|
|
88
|
+
actions: [],
|
|
89
|
+
exits: []
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const node = split_by_llm.fromFormData(formData, originalNode);
|
|
93
|
+
|
|
94
|
+
expect(node.uuid).to.equal('test-node');
|
|
95
|
+
expect(node.actions).to.have.length(1);
|
|
96
|
+
expect(node.actions[0].type).to.equal('call_llm');
|
|
97
|
+
expect((node.actions[0] as CallLLM).llm).to.deep.equal({
|
|
98
|
+
uuid: 'gpt-4',
|
|
99
|
+
name: 'GPT 4.1'
|
|
100
|
+
});
|
|
101
|
+
expect((node.actions[0] as CallLLM).instructions).to.equal(
|
|
102
|
+
'Translate to French'
|
|
103
|
+
);
|
|
104
|
+
expect((node.actions[0] as CallLLM).input).to.equal('@input');
|
|
105
|
+
expect((node.actions[0] as CallLLM).output_local).to.equal('_llm_output');
|
|
106
|
+
|
|
107
|
+
expect(node.router).to.exist;
|
|
108
|
+
expect(node.router.type).to.equal('switch');
|
|
109
|
+
expect(node.router.operand).to.equal('@locals._llm_output');
|
|
110
|
+
expect(node.router.categories).to.have.length(2);
|
|
111
|
+
expect(node.router.categories[0].name).to.equal('Success');
|
|
112
|
+
expect(node.router.categories[1].name).to.equal('Failure');
|
|
113
|
+
|
|
114
|
+
expect(node.exits).to.have.length(2);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('handles empty form data', () => {
|
|
118
|
+
const formData = {
|
|
119
|
+
uuid: 'test-node',
|
|
120
|
+
llm: [],
|
|
121
|
+
input: '',
|
|
122
|
+
instructions: ''
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const originalNode: Node = {
|
|
126
|
+
uuid: 'test-node',
|
|
127
|
+
actions: [],
|
|
128
|
+
exits: []
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const node = split_by_llm.fromFormData(formData, originalNode);
|
|
132
|
+
|
|
133
|
+
const action = node.actions[0] as CallLLM;
|
|
134
|
+
expect(action.llm).to.deep.equal({ uuid: '', name: '' });
|
|
135
|
+
expect(action.instructions).to.equal('');
|
|
136
|
+
expect(action.input).to.equal('@input');
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('node scenarios', () => {
|
|
141
|
+
const createTestNode = (
|
|
142
|
+
llm: any,
|
|
143
|
+
instructions: string,
|
|
144
|
+
input: string = '@input'
|
|
145
|
+
): Node => ({
|
|
146
|
+
uuid: 'test-node',
|
|
147
|
+
actions: [
|
|
148
|
+
{
|
|
149
|
+
uuid: 'test-action',
|
|
150
|
+
type: 'call_llm',
|
|
151
|
+
llm,
|
|
152
|
+
instructions,
|
|
153
|
+
input,
|
|
154
|
+
output_local: '_llm_output'
|
|
155
|
+
} as CallLLM
|
|
156
|
+
],
|
|
157
|
+
router: {
|
|
158
|
+
type: 'switch',
|
|
159
|
+
operand: '@locals._llm_output',
|
|
160
|
+
categories: [
|
|
161
|
+
{
|
|
162
|
+
uuid: 'success-category',
|
|
163
|
+
name: 'Success',
|
|
164
|
+
exit_uuid: 'success-exit'
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
uuid: 'failure-category',
|
|
168
|
+
name: 'Failure',
|
|
169
|
+
exit_uuid: 'failure-exit'
|
|
170
|
+
}
|
|
171
|
+
],
|
|
172
|
+
default_category_uuid: 'failure-category',
|
|
173
|
+
cases: [
|
|
174
|
+
{
|
|
175
|
+
uuid: 'success-case',
|
|
176
|
+
type: 'has_text',
|
|
177
|
+
arguments: [],
|
|
178
|
+
category_uuid: 'success-category'
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
exits: [
|
|
183
|
+
{
|
|
184
|
+
uuid: 'success-exit',
|
|
185
|
+
destination_uuid: null
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
uuid: 'failure-exit',
|
|
189
|
+
destination_uuid: null
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const nodeUI = {
|
|
195
|
+
type: 'split_by_llm',
|
|
196
|
+
position: { left: 50, top: 50 }
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
helper.testNode(
|
|
200
|
+
createTestNode({ uuid: 'gpt-4', name: 'GPT 4.1' }, 'Translate to French'),
|
|
201
|
+
nodeUI,
|
|
202
|
+
'translation-task'
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
helper.testNode(
|
|
206
|
+
createTestNode(
|
|
207
|
+
{ uuid: 'gpt-5', name: 'GPT 5' },
|
|
208
|
+
'Analyze the sentiment of the following message and classify it as positive, negative, or neutral. Provide a brief explanation for your classification.'
|
|
209
|
+
),
|
|
210
|
+
nodeUI,
|
|
211
|
+
'sentiment-analysis'
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
helper.testNode(
|
|
215
|
+
createTestNode(
|
|
216
|
+
{ uuid: 'gpt-4', name: 'GPT 4.1' },
|
|
217
|
+
'Summarize the key points from the conversation above in bullet format.'
|
|
218
|
+
),
|
|
219
|
+
nodeUI,
|
|
220
|
+
'summarization'
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
helper.testNode(
|
|
224
|
+
createTestNode(
|
|
225
|
+
{ uuid: 'gpt-5', name: 'GPT 5' },
|
|
226
|
+
'Extract any contact information (phone numbers, email addresses) from the text and format them as a JSON object.'
|
|
227
|
+
),
|
|
228
|
+
nodeUI,
|
|
229
|
+
'information-extraction'
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
});
|