@opencxh/domain 1.91.0 → 1.92.0

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.
@@ -3,7 +3,7 @@ import { TranscriptSegment } from '../../platform/media';
3
3
  export type CallStatus = "new" | "connecting" | "ringing" | "connected" | "held" | "ended" | "failed";
4
4
  export type CallDirection = "inbound" | "outbound";
5
5
  export type CallType = "audio" | "video" | "data" | "screen-share";
6
- export type ActivityType = "VOICE_CALL_STARTED" | "VOICE_CALL_ANSWERED" | "VOICE_CALL_HOLD" | "VOICE_CALL_UNHOLD" | "VOICE_CALL_ENDED" | "VOICE_CALL_MISSED" | "VOICE_CALL_VOICEMAIL" | "VIDEO_CALL_STARTED" | "VIDEO_CALL_ANSWERED" | "VIDEO_CALL_HOLD" | "VIDEO_CALL_UNHOLD" | "VIDEO_CALL_ENDED" | "VIDEO_CALL_MISSED" | "EMAIL_RECEIVED" | "EMAIL_SENT" | "CHAT_MESSAGE_SENT" | "CHAT_MESSAGE_RECEIVED" | "CHAT_MEMBER_JOINED" | "CHAT_MEMBER_LEFT" | "CHAT_RENAMED" | "CHAT_CALL_STARTED" | "CHAT_CALL_ENDED" | "CHAT_EVENT" | "AI_MESSAGE_ADDED" | "MEETING_SCHEDULED" | "MEETING_STARTED" | "MEETING_ENDED" | "MEETING_PARTICIPANT_JOINED" | "MEETING_PARTICIPANT_LEFT" | "COMMENT_ADDED" | "FILE_UPLOADED" | "INTERACTION_CREATED" | "INTERACTION_STATUS_CHANGED" | "INTERACTION_ASSIGNED" | "VOICE_CALL_FAILED" | "VIDEO_CALL_FAILED" | "TRANSCRIPT_ADDED";
6
+ export type ActivityType = "VOICE_CALL_STARTED" | "VOICE_CALL_ANSWERED" | "VOICE_CALL_HOLD" | "VOICE_CALL_UNHOLD" | "VOICE_CALL_ENDED" | "VOICE_CALL_MISSED" | "VOICE_CALL_VOICEMAIL" | "VIDEO_CALL_STARTED" | "VIDEO_CALL_ANSWERED" | "VIDEO_CALL_HOLD" | "VIDEO_CALL_UNHOLD" | "VIDEO_CALL_ENDED" | "VIDEO_CALL_MISSED" | "EMAIL_RECEIVED" | "EMAIL_SENT" | "CHAT_MESSAGE_SENT" | "CHAT_MESSAGE_RECEIVED" | "CHAT_MEMBER_JOINED" | "CHAT_MEMBER_LEFT" | "CHAT_RENAMED" | "CHAT_CALL_STARTED" | "CHAT_CALL_ENDED" | "CHAT_EVENT" | "AI_MESSAGE_ADDED" | "AI_ACTION_PROPOSED" | "PLAYBOOK_STARTED" | "PLAYBOOK_COMPLETED" | "PLAYBOOK_ESCALATED" | "MEETING_SCHEDULED" | "MEETING_STARTED" | "MEETING_ENDED" | "MEETING_PARTICIPANT_JOINED" | "MEETING_PARTICIPANT_LEFT" | "COMMENT_ADDED" | "FILE_UPLOADED" | "INTERACTION_CREATED" | "INTERACTION_STATUS_CHANGED" | "INTERACTION_ASSIGNED" | "VOICE_CALL_FAILED" | "VIDEO_CALL_FAILED" | "TRANSCRIPT_ADDED";
7
7
  export interface Attachment {
8
8
  id: string;
9
9
  filename: string;
@@ -183,6 +183,29 @@ export type AIMessageAddedPayload = {
183
183
  accountId?: string;
184
184
  model?: string;
185
185
  };
186
+ /**
187
+ * A playbook proposes one or more actions for a human to approve/reject (autonomy:
188
+ * suggest). Rendered inline in the interaction timeline; approve/reject call the ai
189
+ * app's `playbook-run` endpoints. System-authored, so it does not re-trigger playbooks.
190
+ */
191
+ export type AIActionProposedPayload = {
192
+ runId: string;
193
+ playbookId?: string;
194
+ playbookName?: string;
195
+ /** The held actions, e.g. { action: "tool:mcp__jira__create_issue", params }. */
196
+ actions: {
197
+ action: string;
198
+ params?: Record<string, unknown>;
199
+ }[];
200
+ status: "pending" | "approved" | "rejected";
201
+ };
202
+ /** Playbook lifecycle marker in the interaction timeline (system-authored). */
203
+ export type PlaybookLifecyclePayload = {
204
+ runId: string;
205
+ playbookId?: string;
206
+ playbookName?: string;
207
+ status?: string;
208
+ };
186
209
  export type Activity = (BaseActivity & {
187
210
  type: "VOICE_CALL_STARTED";
188
211
  payload: VoiceCallPayload;
@@ -264,6 +287,18 @@ export type Activity = (BaseActivity & {
264
287
  }) | (BaseActivity & {
265
288
  type: "AI_MESSAGE_ADDED";
266
289
  payload: AIMessageAddedPayload;
290
+ }) | (BaseActivity & {
291
+ type: "AI_ACTION_PROPOSED";
292
+ payload: AIActionProposedPayload;
293
+ }) | (BaseActivity & {
294
+ type: "PLAYBOOK_STARTED";
295
+ payload: PlaybookLifecyclePayload;
296
+ }) | (BaseActivity & {
297
+ type: "PLAYBOOK_COMPLETED";
298
+ payload: PlaybookLifecyclePayload;
299
+ }) | (BaseActivity & {
300
+ type: "PLAYBOOK_ESCALATED";
301
+ payload: PlaybookLifecyclePayload;
267
302
  }) | (BaseActivity & {
268
303
  type: "MEETING_SCHEDULED";
269
304
  payload: MeetingPayload;
@@ -22,6 +22,22 @@ export interface AIProfile<T extends Record<string, any> = Record<string, any>>
22
22
  predefinedPrompts?: PredefinedPrompt[];
23
23
  /** Namespaced tool names this profile may use (default: none enabled). */
24
24
  enabledTools?: string[];
25
+ /**
26
+ * Per-tool confirmation policy. Stored as a LIST (not a keyed map) on purpose:
27
+ * namespaced tool names contain "__", and the SDK client transforms every
28
+ * object KEY between camelCase/snake_case — which mangles map keys (e.g.
29
+ * `communication__compose_email` -> `communication_ComposeEmail`) so they no
30
+ * longer match `enabledTools`. As a list the tool name lives in a string VALUE,
31
+ * which the transform leaves untouched.
32
+ *
33
+ * Under autonomy "suggest", write tools are held for approval; reads run freely.
34
+ * A tool absent from this list defaults to "write" (safe). Also usable by the
35
+ * interactive assistant's requiresConfirmation flow.
36
+ */
37
+ toolPolicy?: {
38
+ name: string;
39
+ policy: "read" | "write";
40
+ }[];
25
41
  /**
26
42
  * Whether the acting user's PERSONAL MCP tools (their own per-user connections)
27
43
  * are available on this profile, on top of the admin-curated `enabledTools`.
@@ -0,0 +1 @@
1
+ export * from './types';
@@ -0,0 +1,154 @@
1
+ import { OwnerScope } from '../contact/types';
2
+ /**
3
+ * Playbooks — event-driven automation with AI steps. See docs/PLAYBOOKS.md.
4
+ * Fase 0 covers the deterministic subset; AI steps are typed here but the
5
+ * executor rejects them until Fase 2.
6
+ */
7
+ export type Autonomy = "suggest" | "auto";
8
+ export type PlaybookTrigger = {
9
+ kind: "activity";
10
+ activityTypes: string[];
11
+ /** Channel kinds: "mail" | "chat" | "voice" (derived from the activity type). */
12
+ channels?: string[];
13
+ /** Specific channel ids (e.g. per mailbox). Matched against activity.channelId. */
14
+ channelIds?: string[];
15
+ filter?: unknown;
16
+ } | {
17
+ kind: "manual";
18
+ };
19
+ export interface Guardrails {
20
+ maxSteps?: number;
21
+ maxToolCalls?: number;
22
+ policyCaps?: Record<string, unknown>;
23
+ }
24
+ export interface ConditionStep {
25
+ type: "condition";
26
+ /** JSONLogic expression evaluated against the run vars. */
27
+ if: unknown;
28
+ /** Gate: what to do when the condition is false. "then" = the steps that follow. */
29
+ onFalse: "stop" | "escalate" | "continue";
30
+ }
31
+ export interface ForEachStep {
32
+ type: "for-each";
33
+ in: string;
34
+ as: string;
35
+ body: Step[];
36
+ }
37
+ export interface LookupStep {
38
+ type: "lookup";
39
+ /** "tool:<namespaced>" (Fase 1) or a local source ("interactions"/"tasks"). */
40
+ source: string;
41
+ filter?: unknown;
42
+ as: string;
43
+ }
44
+ export interface ActionStep {
45
+ type: "action";
46
+ /** Local action ("task.create"/"interaction.set"/"notify.user") or "tool:<namespaced>" (Fase 1). */
47
+ action: string;
48
+ params: Record<string, unknown>;
49
+ autonomy?: Autonomy;
50
+ }
51
+ /** AI steps — typed in Fase 0, executed from Fase 2. */
52
+ export interface ClassifyStep {
53
+ type: "classify";
54
+ as: string;
55
+ accountId: string;
56
+ model: string;
57
+ mode: "topics" | "question" | "extract";
58
+ topicIds?: string[];
59
+ question?: string;
60
+ fields?: unknown;
61
+ instruction?: string;
62
+ }
63
+ export interface GenerateStep {
64
+ type: "generate";
65
+ profileId: string;
66
+ goal?: string;
67
+ kind: "reply" | "compose" | "note";
68
+ as?: string;
69
+ }
70
+ export interface AgentStep {
71
+ type: "agent";
72
+ profileId: string;
73
+ goal: string;
74
+ guardrails: Guardrails;
75
+ toolsOverride?: string[];
76
+ autonomy?: Autonomy;
77
+ as?: string;
78
+ }
79
+ export interface WaitForReplyStep {
80
+ type: "wait-for-reply";
81
+ deadline?: number;
82
+ }
83
+ export type Step = ConditionStep | ForEachStep | LookupStep | ActionStep | ClassifyStep | GenerateStep | AgentStep | WaitForReplyStep;
84
+ export interface Playbook {
85
+ id: string;
86
+ organizationId: string;
87
+ ownerScope: OwnerScope;
88
+ name: string;
89
+ description?: string;
90
+ enabled: boolean;
91
+ autonomy: Autonomy;
92
+ trigger: PlaybookTrigger;
93
+ steps: Step[];
94
+ /** Bumped on every change; runs pin to the version they started on. */
95
+ version: number;
96
+ /** Actor of autonomous actions. */
97
+ createdBy: string;
98
+ lastRunAt?: number;
99
+ stats?: {
100
+ runs: number;
101
+ proposals: number;
102
+ autoActions: number;
103
+ };
104
+ }
105
+ export type RunStatus = "pending" | "running" | "awaiting_approval" | "awaiting_reply" | "done" | "escalated" | "failed" | "timed_out" | "stopped";
106
+ export interface RunStepTrace {
107
+ path: string;
108
+ type: string;
109
+ ok: boolean;
110
+ note?: string;
111
+ ms?: number;
112
+ }
113
+ export interface PlaybookRun {
114
+ id: string;
115
+ organizationId: string;
116
+ playbookId: string;
117
+ playbookVersion: number;
118
+ interactionId?: string;
119
+ status: RunStatus;
120
+ trigger: {
121
+ activityType?: string;
122
+ activityId?: string;
123
+ event: Record<string, unknown>;
124
+ };
125
+ vars: Record<string, unknown>;
126
+ trace: RunStepTrace[];
127
+ /** Snapshot of the playbook steps at run start — version-pinned resume (docs 11.4). */
128
+ steps?: Step[];
129
+ /** Held action(s) awaiting human approval (autonomy: suggest) — a batch per paused step. */
130
+ pending?: {
131
+ stepIndex: number;
132
+ actions: {
133
+ action: string;
134
+ params: Record<string, unknown>;
135
+ }[];
136
+ };
137
+ /** The AI_ACTION_PROPOSED activity created for the current pending batch (for resolve on approve/reject). */
138
+ proposalActivityId?: string;
139
+ /** Parked run (awaiting_reply): where to continue + correlation + round counter. */
140
+ awaitFor?: {
141
+ interactionId?: string;
142
+ };
143
+ resumeIndex?: number;
144
+ rounds?: number;
145
+ /** Denormalized interaction audience for efficient list-filtering. */
146
+ audience?: string[];
147
+ createdBy: string;
148
+ approvedBy?: string;
149
+ result?: {
150
+ ok: boolean;
151
+ error?: string;
152
+ };
153
+ lastStepAt?: number;
154
+ }
package/dist/index.cjs CHANGED
@@ -1,3 +1,8 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=140;function i(e){return e.replace(/<style[\s\S]*?<\/style>/gi," ").replace(/<script[\s\S]*?<\/script>/gi," ").replace(/<[^>]+>/g," ").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/\s+/g," ").trim()}function I(e){const t=e.trim();return t.length<=l?t:t.slice(0,l-1).trimEnd()+"…"}function E(e){if(!e||e<0)return"";const t=Math.floor(e/60),n=Math.floor(e%60);return`${t}:${n.toString().padStart(2,"0")}`}function _(e){switch(e.type){case"EMAIL_RECEIVED":case"EMAIL_SENT":{const t=e.payload,n=t.bodySnippet?.trim()||i(t.body??"");return t.subject?`${t.subject} — ${n}`:n}case"CHAT_MESSAGE_SENT":case"CHAT_MESSAGE_RECEIVED":return e.payload.text??"";case"CHAT_RENAMED":return`Hernoemd naar "${e.payload.newName}"`;case"CHAT_MEMBER_JOINED":return`${e.payload.members.map(t=>t.name).join(", ")} toegevoegd`;case"CHAT_MEMBER_LEFT":return`${e.payload.members.map(t=>t.name).join(", ")} verlaten`;case"CHAT_CALL_STARTED":return"Gesprek gestart";case"CHAT_CALL_ENDED":return`Gesprek beëindigd${e.payload.duration?` (${E(e.payload.duration)})`:""}`;case"CHAT_EVENT":return e.payload.text??e.payload.eventType;case"VOICE_CALL_STARTED":case"VIDEO_CALL_STARTED":return"Gesprek gestart";case"VOICE_CALL_ANSWERED":case"VIDEO_CALL_ANSWERED":return"Gesprek aangenomen";case"VOICE_CALL_HOLD":case"VIDEO_CALL_HOLD":return"In de wacht";case"VOICE_CALL_UNHOLD":case"VIDEO_CALL_UNHOLD":return"Hervat";case"VOICE_CALL_ENDED":case"VIDEO_CALL_ENDED":return`Gesprek beëindigd${e.payload.duration?` (${E(e.payload.duration)})`:""}`;case"VOICE_CALL_MISSED":case"VIDEO_CALL_MISSED":return"Gemiste oproep";case"VOICE_CALL_FAILED":case"VIDEO_CALL_FAILED":return"Gesprek mislukt";case"VOICE_CALL_VOICEMAIL":return e.payload.transcription?.trim()?e.payload.transcription:"Voicemail ontvangen";case"TRANSCRIPT_ADDED":return(e.payload.segments??[]).map(t=>t.text).join(" ");case"AI_MESSAGE_ADDED":return e.payload.output?.text??e.payload.input?.text??"";case"MEETING_SCHEDULED":return`Vergadering gepland: ${e.payload.title}`;case"MEETING_STARTED":return`Vergadering gestart: ${e.payload.title}`;case"MEETING_ENDED":return`Vergadering beëindigd${e.payload.duration?` (${E(e.payload.duration)})`:""}`;case"MEETING_PARTICIPANT_JOINED":return`${e.payload.name} deelgenomen`;case"MEETING_PARTICIPANT_LEFT":return`${e.payload.name} verlaten`;case"COMMENT_ADDED":return e.payload.text??"";case"FILE_UPLOADED":return`Bestand: ${e.payload.fileName}`;case"INTERACTION_CREATED":return"Interactie aangemaakt";case"INTERACTION_STATUS_CHANGED":return`Status: ${e.payload.fromStatus} → ${e.payload.toStatus}`;case"INTERACTION_ASSIGNED":return"Interactie toegewezen";default:return""}}function T(e){return{activityId:e.id,type:e.type,snippet:I(_(e)),authorName:e.author?.name??"",direction:e.direction,createdAt:e.createdAt??Date.now()}}function g(e,t,n=[]){const r=e.createdAt;if(!r)return[];const s=new Set(n);return e.author.type==="user"&&e.author.id&&s.add(e.author.id),Object.entries(t).filter(([a,o])=>o>=r&&!s.has(a)).map(([a])=>a)}const S=new Set(["mail","message"]);function u(e,t){const n=e.settings?.signatures?.[t];return!n||!n.enabled||!n.body||n.body.trim()===""?null:n}function f(e,t,n,r="html"){if(!e)return n;const s=u(e,t);return s?`${n}${r==="text"?`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=140;function p(e){return e.replace(/<style[\s\S]*?<\/style>/gi," ").replace(/<script[\s\S]*?<\/script>/gi," ").replace(/<[^>]+>/g," ").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/\s+/g," ").trim()}function T(e){const t=e.trim();return t.length<=l?t:t.slice(0,l-1).trimEnd()+"…"}function E(e){if(!e||e<0)return"";const t=Math.floor(e/60),n=Math.floor(e%60);return`${t}:${n.toString().padStart(2,"0")}`}function f(e){switch(e.type){case"EMAIL_RECEIVED":case"EMAIL_SENT":{const t=e.payload,n=t.bodySnippet?.trim()||p(t.body??"");return t.subject?`${t.subject} — ${n}`:n}case"CHAT_MESSAGE_SENT":case"CHAT_MESSAGE_RECEIVED":return e.payload.text??"";case"CHAT_RENAMED":return`Hernoemd naar "${e.payload.newName}"`;case"CHAT_MEMBER_JOINED":return`${e.payload.members.map(t=>t.name).join(", ")} toegevoegd`;case"CHAT_MEMBER_LEFT":return`${e.payload.members.map(t=>t.name).join(", ")} verlaten`;case"CHAT_CALL_STARTED":return"Gesprek gestart";case"CHAT_CALL_ENDED":return`Gesprek beëindigd${e.payload.duration?` (${E(e.payload.duration)})`:""}`;case"CHAT_EVENT":return e.payload.text??e.payload.eventType;case"VOICE_CALL_STARTED":case"VIDEO_CALL_STARTED":return"Gesprek gestart";case"VOICE_CALL_ANSWERED":case"VIDEO_CALL_ANSWERED":return"Gesprek aangenomen";case"VOICE_CALL_HOLD":case"VIDEO_CALL_HOLD":return"In de wacht";case"VOICE_CALL_UNHOLD":case"VIDEO_CALL_UNHOLD":return"Hervat";case"VOICE_CALL_ENDED":case"VIDEO_CALL_ENDED":return`Gesprek beëindigd${e.payload.duration?` (${E(e.payload.duration)})`:""}`;case"VOICE_CALL_MISSED":case"VIDEO_CALL_MISSED":return"Gemiste oproep";case"VOICE_CALL_FAILED":case"VIDEO_CALL_FAILED":return"Gesprek mislukt";case"VOICE_CALL_VOICEMAIL":return e.payload.transcription?.trim()?e.payload.transcription:"Voicemail ontvangen";case"TRANSCRIPT_ADDED":return(e.payload.segments??[]).map(t=>t.text).join(" ");case"AI_MESSAGE_ADDED":return e.payload.output?.text??e.payload.input?.text??"";case"AI_ACTION_PROPOSED":return`Voorstel wacht op goedkeuring (${e.payload.actions?.length??0} actie(s))`;case"PLAYBOOK_STARTED":return`Playbook gestart${e.payload.playbookName?`: ${e.payload.playbookName}`:""}`;case"PLAYBOOK_COMPLETED":return"Playbook afgerond";case"PLAYBOOK_ESCALATED":return"Playbook geëscaleerd naar een mens";case"MEETING_SCHEDULED":return`Vergadering gepland: ${e.payload.title}`;case"MEETING_STARTED":return`Vergadering gestart: ${e.payload.title}`;case"MEETING_ENDED":return`Vergadering beëindigd${e.payload.duration?` (${E(e.payload.duration)})`:""}`;case"MEETING_PARTICIPANT_JOINED":return`${e.payload.name} deelgenomen`;case"MEETING_PARTICIPANT_LEFT":return`${e.payload.name} verlaten`;case"COMMENT_ADDED":return e.payload.text??"";case"FILE_UPLOADED":return`Bestand: ${e.payload.fileName}`;case"INTERACTION_CREATED":return"Interactie aangemaakt";case"INTERACTION_STATUS_CHANGED":return`Status: ${e.payload.fromStatus} → ${e.payload.toStatus}`;case"INTERACTION_ASSIGNED":return"Interactie toegewezen";default:return""}}function S(e){return{activityId:e.id,type:e.type,snippet:T(f(e)),authorName:e.author?.name??"",direction:e.direction,createdAt:e.createdAt??Date.now()}}function N(e,t,n=[]){const r=e.createdAt;if(!r)return[];const s=new Set(n);return e.author.type==="user"&&e.author.id&&s.add(e.author.id),Object.entries(t).filter(([a,o])=>o>=r&&!s.has(a)).map(([a])=>a)}const D=new Set(["mail","message"]);function d(e,t){const n=e.settings?.signatures?.[t];return!n||!n.enabled||!n.body||n.body.trim()===""?null:n}function O(e,t,n,r="html"){if(!e)return n;const s=d(e,t);return s?`${n}${r==="text"?`
2
2
 
3
- `:t==="mail"?"<br><br>-- <br>":"<br><br>"}${s.body}`:n}function N(e){return e.endpoints??[]}const D=e=>!!e.assignedUserId||!!e.assignedInboxId,R=e=>e.status==="closed",L=e=>({urgent:10,high:5,normal:2,low:1})[e.priority]||0,O=(e,t=30)=>e.title?.length<=t?e.title:`${e.title.substring(0,t)}...`;function C(e,t){return e.lastActivityAt?!(e.seenBy??[]).includes(t):!1}function c(e,t){const n=new Set(e.disabledIntents??[]),r=e.intentOverrides??{},s=t.intents.filter(o=>!n.has(o.intent)).map(o=>b(o,r[o.intent]));if(!e.extraIntents||e.extraIntents.length===0)return s;const a=new Set(s.map(o=>o.intent));for(const o of e.extraIntents)a.has(o.intent)||(s.push(o),a.add(o.intent));return s}function d(e,t){const n={};for(const r of e.intents){if(!r.togglable)continue;const s=t?.[r.intent];n[r.intent]=s??r.defaultEnabled??!0}return n}function M(e,t){const n=d(e,t);return Object.entries(n).filter(([,r])=>!r).map(([r])=>r)}function b(e,t){return t?{intent:t.intent??e.intent,targetSchemes:t.targetSchemes??e.targetSchemes,transport:t.transport??e.transport}:e}function m(e,t){const n=[];for(const r of e){if(!r.enabled)continue;const s=t[r.providerId];if(s)for(const a of c(r,s))n.push({channel:r,description:s,capability:a})}return n}function P(e,t){return t.filter(n=>n.capability.intent===e)}function p(e,t){return t.filter(n=>n.capability.targetSchemes.includes(e))}function U(e,t){return p(e.scheme,t)}function G(e,t,n){const r=[];for(const s of e)for(const a of n)a.capability.intent===t&&a.capability.targetSchemes.includes(s.scheme)&&r.push({channelIntent:a,endpoint:s});return r}var A=(e=>(e.MAILTO="mailto",e.SIP="sip",e.TEL="tel",e.WEBHOOK="webhook",e.USERNAME="username",e.ID="id",e.CUSTOM="custom",e.URL="url",e.TELEGRAM="telegram",e.WHATSAPP="whatsapp",e.MESSENGER="messenger",e.INSTAGRAM="instagram",e.VIBER="viber",e.SMS="sms",e.FAX="fax",e.TEAMS="teams",e.CALENDAR="calendar",e))(A||{});const y="message_window",V="message_templates",h={FROM:"from",TO:"to",CC:"cc",BCC:"bcc",ORGANIZER:"organizer",PRESENTER:"presenter",ATTENDEE:"attendee",OWNER:"owner",MEMBER:"member",GUEST:"guest",HOST:"host",PARTICIPANT:"participant"},H=(e,t)=>({intent:e,...t}),$="folder_management",F="remote_search",w={ok:!1,code:"UNSUPPORTED",message:"Provider does not support this op"},B=9e4,x="installation-id";exports.CommunicationScheme=A;exports.FEATURE_FOLDER_MANAGEMENT=$;exports.FEATURE_REMOTE_SEARCH=F;exports.INSTALLATION_HEADER=x;exports.InteractionParticipantRole=h;exports.PRESENCE_ONLINE_WINDOW_MS=B;exports.PROVIDER_FEATURE_MESSAGE_TEMPLATES=V;exports.PROVIDER_FEATURE_MESSAGE_WINDOW=y;exports.SIGNATURE_INTENTS=S;exports.UNSUPPORTED=w;exports.applySignature=f;exports.buildActivityPreview=T;exports.buildChannelIntents=m;exports.defineIntent=H;exports.disabledIntentsFromCapabilities=M;exports.filterByEndpoint=U;exports.filterByIntent=P;exports.filterByTargetScheme=p;exports.getActivitySeenUserIds=g;exports.getContactEndpoints=N;exports.getShortTitle=O;exports.getUrgencyScore=L;exports.isAssigned=D;exports.isClosed=R;exports.isInteractionUnseen=C;exports.matchContactToIntents=G;exports.resolveAccountCapabilities=d;exports.resolveChannelIntents=c;exports.resolveSignature=u;exports.stripHtml=i;
3
+ `:t==="mail"?"<br><br>-- <br>":"<br><br>"}${s.body}`:n}function R(e){return e.endpoints??[]}const L=e=>!!e.assignedUserId||!!e.assignedInboxId,C=e=>e.status==="closed",b=e=>({urgent:10,high:5,normal:2,low:1})[e.priority]||0,M=(e,t=30)=>e.title?.length<=t?e.title:`${e.title.substring(0,t)}...`;function m(e,t){return e.lastActivityAt?!(e.seenBy??[]).includes(t):!1}const P=[/<blockquote/i,/class="?gmail_quote/i,/id="?[^"]*divRplyFwdMsg/i,/-{3,}\s*Original Message\s*-{3,}/i,/\n_{5,}\s*\n/,/\bOn\b[\s\S]{0,200}?\bwrote:/i];function i(e){let t=e;return t=t.replace(/<(script|style)[\s\S]*?<\/\1>/gi,""),t=t.replace(/<br\s*\/?>/gi,`
4
+ `),t=t.replace(/<\/(p|div|li|tr|h[1-6]|ul|ol|table)>/gi,`
5
+ `),t=t.replace(/<[^>]+>/g,""),t=t.replace(/<[^>]*$/,""),t}function c(e){return e.replace(/&nbsp;/gi," ").replace(/&lt;/gi,"<").replace(/&gt;/gi,">").replace(/&quot;/gi,'"').replace(/&#39;/gi,"'").replace(/&#(\d+);/g,(t,n)=>String.fromCharCode(Number(n))).replace(/&amp;/gi,"&")}function u(e){return e.replace(/\r/g,"").replace(/[ \t]+/g," ").replace(/ *\n */g,`
6
+ `).replace(/\n{3,}/g,`
7
+
8
+ `).trim()}function y(e){if(typeof e!="string"||!e)return"";let t=e.length;for(const s of P){const a=e.search(s);a>=0&&a<t&&(t=a)}const n=e.slice(0,t);let r=u(c(i(n)));return r||(r=u(c(i(e)))),r}function A(e,t){const n=new Set(e.disabledIntents??[]),r=e.intentOverrides??{},s=t.intents.filter(o=>!n.has(o.intent)).map(o=>U(o,r[o.intent]));if(!e.extraIntents||e.extraIntents.length===0)return s;const a=new Set(s.map(o=>o.intent));for(const o of e.extraIntents)a.has(o.intent)||(s.push(o),a.add(o.intent));return s}function g(e,t){const n={};for(const r of e.intents){if(!r.togglable)continue;const s=t?.[r.intent];n[r.intent]=s??r.defaultEnabled??!0}return n}function h(e,t){const n=g(e,t);return Object.entries(n).filter(([,r])=>!r).map(([r])=>r)}function U(e,t){return t?{intent:t.intent??e.intent,targetSchemes:t.targetSchemes??e.targetSchemes,transport:t.transport??e.transport}:e}function G(e,t){const n=[];for(const r of e){if(!r.enabled)continue;const s=t[r.providerId];if(s)for(const a of A(r,s))n.push({channel:r,description:s,capability:a})}return n}function V(e,t){return t.filter(n=>n.capability.intent===e)}function I(e,t){return t.filter(n=>n.capability.targetSchemes.includes(e))}function $(e,t){return I(e.scheme,t)}function H(e,t,n){const r=[];for(const s of e)for(const a of n)a.capability.intent===t&&a.capability.targetSchemes.includes(s.scheme)&&r.push({channelIntent:a,endpoint:s});return r}var _=(e=>(e.MAILTO="mailto",e.SIP="sip",e.TEL="tel",e.WEBHOOK="webhook",e.USERNAME="username",e.ID="id",e.CUSTOM="custom",e.URL="url",e.TELEGRAM="telegram",e.WHATSAPP="whatsapp",e.MESSENGER="messenger",e.INSTAGRAM="instagram",e.VIBER="viber",e.SMS="sms",e.FAX="fax",e.TEAMS="teams",e.CALENDAR="calendar",e))(_||{});const F="message_window",k="message_templates",B={FROM:"from",TO:"to",CC:"cc",BCC:"bcc",ORGANIZER:"organizer",PRESENTER:"presenter",ATTENDEE:"attendee",OWNER:"owner",MEMBER:"member",GUEST:"guest",HOST:"host",PARTICIPANT:"participant"},x=(e,t)=>({intent:e,...t}),w="folder_management",W="remote_search",j={ok:!1,code:"UNSUPPORTED",message:"Provider does not support this op"},K=9e4,q="installation-id";exports.CommunicationScheme=_;exports.FEATURE_FOLDER_MANAGEMENT=w;exports.FEATURE_REMOTE_SEARCH=W;exports.INSTALLATION_HEADER=q;exports.InteractionParticipantRole=B;exports.PRESENCE_ONLINE_WINDOW_MS=K;exports.PROVIDER_FEATURE_MESSAGE_TEMPLATES=k;exports.PROVIDER_FEATURE_MESSAGE_WINDOW=F;exports.SIGNATURE_INTENTS=D;exports.UNSUPPORTED=j;exports.applySignature=O;exports.buildActivityPreview=S;exports.buildChannelIntents=G;exports.cleanMessageText=y;exports.defineIntent=x;exports.disabledIntentsFromCapabilities=h;exports.filterByEndpoint=$;exports.filterByIntent=V;exports.filterByTargetScheme=I;exports.getActivitySeenUserIds=N;exports.getContactEndpoints=R;exports.getShortTitle=M;exports.getUrgencyScore=b;exports.isAssigned=L;exports.isClosed=C;exports.isInteractionUnseen=m;exports.matchContactToIntents=H;exports.resolveAccountCapabilities=g;exports.resolveChannelIntents=A;exports.resolveSignature=d;exports.stripHtml=p;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './entities/activity';
2
+ export * from './entities/playbook';
2
3
  export * from './entities/kb';
3
4
  export * from './entities/topic';
4
5
  export * from './entities/ai-account';
@@ -22,6 +23,7 @@ export * from './entities/organization';
22
23
  export * from './entities/shopify';
23
24
  export * from './entities/transcript';
24
25
  export * from './entities/user';
26
+ export * from './text/message';
25
27
  export * from './platform/ai-tools';
26
28
  export * from './platform/api';
27
29
  export * from './platform/common';
package/dist/index.js CHANGED
@@ -1,21 +1,21 @@
1
- function u(e) {
1
+ function p(e) {
2
2
  return e.replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/\s+/g, " ").trim();
3
3
  }
4
- function l(e) {
4
+ function i(e) {
5
5
  const t = e.trim();
6
6
  return t.length <= 140 ? t : t.slice(0, 139).trimEnd() + "…";
7
7
  }
8
- function E(e) {
8
+ function l(e) {
9
9
  if (!e || e < 0) return "";
10
- const t = Math.floor(e / 60), n = Math.floor(e % 60);
11
- return `${t}:${n.toString().padStart(2, "0")}`;
10
+ const t = Math.floor(e / 60), r = Math.floor(e % 60);
11
+ return `${t}:${r.toString().padStart(2, "0")}`;
12
12
  }
13
- function p(e) {
13
+ function d(e) {
14
14
  switch (e.type) {
15
15
  case "EMAIL_RECEIVED":
16
16
  case "EMAIL_SENT": {
17
- const t = e.payload, n = t.bodySnippet?.trim() || u(t.body ?? "");
18
- return t.subject ? `${t.subject} — ${n}` : n;
17
+ const t = e.payload, r = t.bodySnippet?.trim() || p(t.body ?? "");
18
+ return t.subject ? `${t.subject} — ${r}` : r;
19
19
  }
20
20
  case "CHAT_MESSAGE_SENT":
21
21
  case "CHAT_MESSAGE_RECEIVED":
@@ -29,7 +29,7 @@ function p(e) {
29
29
  case "CHAT_CALL_STARTED":
30
30
  return "Gesprek gestart";
31
31
  case "CHAT_CALL_ENDED":
32
- return `Gesprek beëindigd${e.payload.duration ? ` (${E(e.payload.duration)})` : ""}`;
32
+ return `Gesprek beëindigd${e.payload.duration ? ` (${l(e.payload.duration)})` : ""}`;
33
33
  case "CHAT_EVENT":
34
34
  return e.payload.text ?? e.payload.eventType;
35
35
  case "VOICE_CALL_STARTED":
@@ -46,7 +46,7 @@ function p(e) {
46
46
  return "Hervat";
47
47
  case "VOICE_CALL_ENDED":
48
48
  case "VIDEO_CALL_ENDED":
49
- return `Gesprek beëindigd${e.payload.duration ? ` (${E(e.payload.duration)})` : ""}`;
49
+ return `Gesprek beëindigd${e.payload.duration ? ` (${l(e.payload.duration)})` : ""}`;
50
50
  case "VOICE_CALL_MISSED":
51
51
  case "VIDEO_CALL_MISSED":
52
52
  return "Gemiste oproep";
@@ -59,12 +59,20 @@ function p(e) {
59
59
  return (e.payload.segments ?? []).map((t) => t.text).join(" ");
60
60
  case "AI_MESSAGE_ADDED":
61
61
  return e.payload.output?.text ?? e.payload.input?.text ?? "";
62
+ case "AI_ACTION_PROPOSED":
63
+ return `Voorstel wacht op goedkeuring (${e.payload.actions?.length ?? 0} actie(s))`;
64
+ case "PLAYBOOK_STARTED":
65
+ return `Playbook gestart${e.payload.playbookName ? `: ${e.payload.playbookName}` : ""}`;
66
+ case "PLAYBOOK_COMPLETED":
67
+ return "Playbook afgerond";
68
+ case "PLAYBOOK_ESCALATED":
69
+ return "Playbook geëscaleerd naar een mens";
62
70
  case "MEETING_SCHEDULED":
63
71
  return `Vergadering gepland: ${e.payload.title}`;
64
72
  case "MEETING_STARTED":
65
73
  return `Vergadering gestart: ${e.payload.title}`;
66
74
  case "MEETING_ENDED":
67
- return `Vergadering beëindigd${e.payload.duration ? ` (${E(e.payload.duration)})` : ""}`;
75
+ return `Vergadering beëindigd${e.payload.duration ? ` (${l(e.payload.duration)})` : ""}`;
68
76
  case "MEETING_PARTICIPANT_JOINED":
69
77
  return `${e.payload.name} deelgenomen`;
70
78
  case "MEETING_PARTICIPANT_LEFT":
@@ -83,103 +91,141 @@ function p(e) {
83
91
  return "";
84
92
  }
85
93
  }
86
- function T(e) {
94
+ function S(e) {
87
95
  return {
88
96
  activityId: e.id,
89
97
  type: e.type,
90
- snippet: l(p(e)),
98
+ snippet: i(d(e)),
91
99
  authorName: e.author?.name ?? "",
92
100
  direction: e.direction,
93
101
  createdAt: e.createdAt ?? Date.now()
94
102
  };
95
103
  }
96
- function g(e, t, n = []) {
97
- const r = e.createdAt;
98
- if (!r) return [];
99
- const s = new Set(n);
100
- return e.author.type === "user" && e.author.id && s.add(e.author.id), Object.entries(t).filter(([a, o]) => o >= r && !s.has(a)).map(([a]) => a);
101
- }
102
- const f = /* @__PURE__ */ new Set(["mail", "message"]);
103
- function d(e, t) {
104
- const n = e.settings?.signatures?.[t];
105
- return !n || !n.enabled || !n.body || n.body.trim() === "" ? null : n;
106
- }
107
- function D(e, t, n, r = "html") {
108
- if (!e) return n;
109
- const s = d(e, t);
110
- return s ? `${n}${r === "text" ? `
104
+ function N(e, t, r = []) {
105
+ const n = e.createdAt;
106
+ if (!n) return [];
107
+ const s = new Set(r);
108
+ return e.author.type === "user" && e.author.id && s.add(e.author.id), Object.entries(t).filter(([a, o]) => o >= n && !s.has(a)).map(([a]) => a);
109
+ }
110
+ const L = /* @__PURE__ */ new Set(["mail", "message"]);
111
+ function A(e, t) {
112
+ const r = e.settings?.signatures?.[t];
113
+ return !r || !r.enabled || !r.body || r.body.trim() === "" ? null : r;
114
+ }
115
+ function O(e, t, r, n = "html") {
116
+ if (!e) return r;
117
+ const s = A(e, t);
118
+ return s ? `${r}${n === "text" ? `
111
119
 
112
- ` : t === "mail" ? "<br><br>-- <br>" : "<br><br>"}${s.body}` : n;
120
+ ` : t === "mail" ? "<br><br>-- <br>" : "<br><br>"}${s.body}` : r;
113
121
  }
114
- function N(e) {
122
+ function R(e) {
115
123
  return e.endpoints ?? [];
116
124
  }
117
- const S = (e) => !!e.assignedUserId || !!e.assignedInboxId, L = (e) => e.status === "closed", R = (e) => ({
125
+ const b = (e) => !!e.assignedUserId || !!e.assignedInboxId, C = (e) => e.status === "closed", M = (e) => ({
118
126
  urgent: 10,
119
127
  high: 5,
120
128
  normal: 2,
121
129
  low: 1
122
- })[e.priority] || 0, O = (e, t = 30) => e.title?.length <= t ? e.title : `${e.title.substring(0, t)}...`;
123
- function C(e, t) {
130
+ })[e.priority] || 0, m = (e, t = 30) => e.title?.length <= t ? e.title : `${e.title.substring(0, t)}...`;
131
+ function P(e, t) {
124
132
  return e.lastActivityAt ? !(e.seenBy ?? []).includes(t) : !1;
125
133
  }
126
- function c(e, t) {
127
- const n = new Set(e.disabledIntents ?? []), r = e.intentOverrides ?? {}, s = t.intents.filter((o) => !n.has(o.intent)).map((o) => A(o, r[o.intent]));
134
+ const g = [
135
+ /<blockquote/i,
136
+ /class="?gmail_quote/i,
137
+ // Gmail quote container
138
+ /id="?[^"]*divRplyFwdMsg/i,
139
+ // Outlook web reply/forward header
140
+ /-{3,}\s*Original Message\s*-{3,}/i,
141
+ /\n_{5,}\s*\n/,
142
+ // Outlook underscore separator before "From:"
143
+ /\bOn\b[\s\S]{0,200}?\bwrote:/i
144
+ // Gmail "On <date> <name> wrote:"
145
+ ];
146
+ function E(e) {
147
+ let t = e;
148
+ return t = t.replace(/<(script|style)[\s\S]*?<\/\1>/gi, ""), t = t.replace(/<br\s*\/?>/gi, `
149
+ `), t = t.replace(/<\/(p|div|li|tr|h[1-6]|ul|ol|table)>/gi, `
150
+ `), t = t.replace(/<[^>]+>/g, ""), t = t.replace(/<[^>]*$/, ""), t;
151
+ }
152
+ function u(e) {
153
+ return e.replace(/&nbsp;/gi, " ").replace(/&lt;/gi, "<").replace(/&gt;/gi, ">").replace(/&quot;/gi, '"').replace(/&#39;/gi, "'").replace(/&#(\d+);/g, (t, r) => String.fromCharCode(Number(r))).replace(/&amp;/gi, "&");
154
+ }
155
+ function c(e) {
156
+ return e.replace(/\r/g, "").replace(/[ \t]+/g, " ").replace(/ *\n */g, `
157
+ `).replace(/\n{3,}/g, `
158
+
159
+ `).trim();
160
+ }
161
+ function $(e) {
162
+ if (typeof e != "string" || !e) return "";
163
+ let t = e.length;
164
+ for (const s of g) {
165
+ const a = e.search(s);
166
+ a >= 0 && a < t && (t = a);
167
+ }
168
+ const r = e.slice(0, t);
169
+ let n = c(u(E(r)));
170
+ return n || (n = c(u(E(e)))), n;
171
+ }
172
+ function _(e, t) {
173
+ const r = new Set(e.disabledIntents ?? []), n = e.intentOverrides ?? {}, s = t.intents.filter((o) => !r.has(o.intent)).map((o) => T(o, n[o.intent]));
128
174
  if (!e.extraIntents || e.extraIntents.length === 0) return s;
129
175
  const a = new Set(s.map((o) => o.intent));
130
176
  for (const o of e.extraIntents)
131
177
  a.has(o.intent) || (s.push(o), a.add(o.intent));
132
178
  return s;
133
179
  }
134
- function i(e, t) {
135
- const n = {};
136
- for (const r of e.intents) {
137
- if (!r.togglable) continue;
138
- const s = t?.[r.intent];
139
- n[r.intent] = s ?? r.defaultEnabled ?? !0;
180
+ function I(e, t) {
181
+ const r = {};
182
+ for (const n of e.intents) {
183
+ if (!n.togglable) continue;
184
+ const s = t?.[n.intent];
185
+ r[n.intent] = s ?? n.defaultEnabled ?? !0;
140
186
  }
141
- return n;
187
+ return r;
142
188
  }
143
- function M(e, t) {
144
- const n = i(e, t);
145
- return Object.entries(n).filter(([, r]) => !r).map(([r]) => r);
189
+ function h(e, t) {
190
+ const r = I(e, t);
191
+ return Object.entries(r).filter(([, n]) => !n).map(([n]) => n);
146
192
  }
147
- function A(e, t) {
193
+ function T(e, t) {
148
194
  return t ? {
149
195
  intent: t.intent ?? e.intent,
150
196
  targetSchemes: t.targetSchemes ?? e.targetSchemes,
151
197
  transport: t.transport ?? e.transport
152
198
  } : e;
153
199
  }
154
- function b(e, t) {
155
- const n = [];
156
- for (const r of e) {
157
- if (!r.enabled) continue;
158
- const s = t[r.providerId];
200
+ function y(e, t) {
201
+ const r = [];
202
+ for (const n of e) {
203
+ if (!n.enabled) continue;
204
+ const s = t[n.providerId];
159
205
  if (s)
160
- for (const a of c(r, s))
161
- n.push({ channel: r, description: s, capability: a });
206
+ for (const a of _(n, s))
207
+ r.push({ channel: n, description: s, capability: a });
162
208
  }
163
- return n;
209
+ return r;
164
210
  }
165
- function P(e, t) {
166
- return t.filter((n) => n.capability.intent === e);
211
+ function V(e, t) {
212
+ return t.filter((r) => r.capability.intent === e);
167
213
  }
168
- function I(e, t) {
169
- return t.filter((n) => n.capability.targetSchemes.includes(e));
214
+ function f(e, t) {
215
+ return t.filter((r) => r.capability.targetSchemes.includes(e));
170
216
  }
171
- function m(e, t) {
172
- return I(e.scheme, t);
217
+ function G(e, t) {
218
+ return f(e.scheme, t);
173
219
  }
174
- function G(e, t, n) {
175
- const r = [];
220
+ function H(e, t, r) {
221
+ const n = [];
176
222
  for (const s of e)
177
- for (const a of n)
178
- a.capability.intent === t && a.capability.targetSchemes.includes(s.scheme) && r.push({ channelIntent: a, endpoint: s });
179
- return r;
223
+ for (const a of r)
224
+ a.capability.intent === t && a.capability.targetSchemes.includes(s.scheme) && n.push({ channelIntent: a, endpoint: s });
225
+ return n;
180
226
  }
181
- var _ = /* @__PURE__ */ ((e) => (e.MAILTO = "mailto", e.SIP = "sip", e.TEL = "tel", e.WEBHOOK = "webhook", e.USERNAME = "username", e.ID = "id", e.CUSTOM = "custom", e.URL = "url", e.TELEGRAM = "telegram", e.WHATSAPP = "whatsapp", e.MESSENGER = "messenger", e.INSTAGRAM = "instagram", e.VIBER = "viber", e.SMS = "sms", e.FAX = "fax", e.TEAMS = "teams", e.CALENDAR = "calendar", e))(_ || {});
182
- const V = "message_window", $ = "message_templates", H = {
227
+ var D = /* @__PURE__ */ ((e) => (e.MAILTO = "mailto", e.SIP = "sip", e.TEL = "tel", e.WEBHOOK = "webhook", e.USERNAME = "username", e.ID = "id", e.CUSTOM = "custom", e.URL = "url", e.TELEGRAM = "telegram", e.WHATSAPP = "whatsapp", e.MESSENGER = "messenger", e.INSTAGRAM = "instagram", e.VIBER = "viber", e.SMS = "sms", e.FAX = "fax", e.TEAMS = "teams", e.CALENDAR = "calendar", e))(D || {});
228
+ const U = "message_window", k = "message_templates", x = {
183
229
  // E-mail
184
230
  FROM: "from",
185
231
  TO: "to",
@@ -196,36 +242,37 @@ const V = "message_window", $ = "message_templates", H = {
196
242
  // Voice/conference
197
243
  HOST: "host",
198
244
  PARTICIPANT: "participant"
199
- }, U = (e, t) => ({ intent: e, ...t }), h = "folder_management", y = "remote_search", w = { ok: !1, code: "UNSUPPORTED", message: "Provider does not support this op" }, x = 9e4, F = "installation-id";
245
+ }, F = (e, t) => ({ intent: e, ...t }), w = "folder_management", B = "remote_search", W = { ok: !1, code: "UNSUPPORTED", message: "Provider does not support this op" }, j = 9e4, K = "installation-id";
200
246
  export {
201
- _ as CommunicationScheme,
202
- h as FEATURE_FOLDER_MANAGEMENT,
203
- y as FEATURE_REMOTE_SEARCH,
204
- F as INSTALLATION_HEADER,
205
- H as InteractionParticipantRole,
206
- x as PRESENCE_ONLINE_WINDOW_MS,
207
- $ as PROVIDER_FEATURE_MESSAGE_TEMPLATES,
208
- V as PROVIDER_FEATURE_MESSAGE_WINDOW,
209
- f as SIGNATURE_INTENTS,
210
- w as UNSUPPORTED,
211
- D as applySignature,
212
- T as buildActivityPreview,
213
- b as buildChannelIntents,
214
- U as defineIntent,
215
- M as disabledIntentsFromCapabilities,
216
- m as filterByEndpoint,
217
- P as filterByIntent,
218
- I as filterByTargetScheme,
219
- g as getActivitySeenUserIds,
220
- N as getContactEndpoints,
221
- O as getShortTitle,
222
- R as getUrgencyScore,
223
- S as isAssigned,
224
- L as isClosed,
225
- C as isInteractionUnseen,
226
- G as matchContactToIntents,
227
- i as resolveAccountCapabilities,
228
- c as resolveChannelIntents,
229
- d as resolveSignature,
230
- u as stripHtml
247
+ D as CommunicationScheme,
248
+ w as FEATURE_FOLDER_MANAGEMENT,
249
+ B as FEATURE_REMOTE_SEARCH,
250
+ K as INSTALLATION_HEADER,
251
+ x as InteractionParticipantRole,
252
+ j as PRESENCE_ONLINE_WINDOW_MS,
253
+ k as PROVIDER_FEATURE_MESSAGE_TEMPLATES,
254
+ U as PROVIDER_FEATURE_MESSAGE_WINDOW,
255
+ L as SIGNATURE_INTENTS,
256
+ W as UNSUPPORTED,
257
+ O as applySignature,
258
+ S as buildActivityPreview,
259
+ y as buildChannelIntents,
260
+ $ as cleanMessageText,
261
+ F as defineIntent,
262
+ h as disabledIntentsFromCapabilities,
263
+ G as filterByEndpoint,
264
+ V as filterByIntent,
265
+ f as filterByTargetScheme,
266
+ N as getActivitySeenUserIds,
267
+ R as getContactEndpoints,
268
+ m as getShortTitle,
269
+ M as getUrgencyScore,
270
+ b as isAssigned,
271
+ C as isClosed,
272
+ P as isInteractionUnseen,
273
+ H as matchContactToIntents,
274
+ I as resolveAccountCapabilities,
275
+ _ as resolveChannelIntents,
276
+ A as resolveSignature,
277
+ p as stripHtml
231
278
  };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Clean an inbound message body for display/LLM use: cut the quoted reply /
3
+ * forwarded thread, strip HTML, decode common entities, collapse whitespace.
4
+ * Without this the raw HTML + full Gmail/Outlook quote leaks the OLD message into
5
+ * classify/extract/agent (or history views) instead of the sender's new content.
6
+ * Pure, dependency-free (lives in domain so both server apps can share it).
7
+ */
8
+ export declare function cleanMessageText(raw: unknown): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencxh/domain",
3
- "version": "1.91.0",
3
+ "version": "1.92.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",