@opencxh/domain 1.126.0 → 1.128.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.
- package/dist/entities/ai-account/index.d.ts +1 -0
- package/dist/entities/ai-account/types.d.ts +6 -0
- package/dist/entities/ai-account/vendors.d.ts +47 -0
- package/dist/entities/analytics/index.d.ts +1 -0
- package/dist/entities/analytics/usage.d.ts +56 -0
- package/dist/entities/memory/alias.d.ts +19 -0
- package/dist/entities/memory/index.d.ts +5 -0
- package/dist/entities/memory/ingest.d.ts +61 -0
- package/dist/entities/memory/item.d.ts +77 -0
- package/dist/entities/memory/kind.d.ts +66 -0
- package/dist/entities/memory/query.d.ts +71 -0
- package/dist/entities/playbook/trigger-vars.d.ts +6 -0
- package/dist/entities/playbook/types.d.ts +22 -0
- package/dist/index.cjs +5 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +295 -147
- package/dist/platform/ai-tools.d.ts +17 -0
- package/dist/platform/scope.d.ts +17 -0
- package/package.json +1 -1
|
@@ -3,6 +3,12 @@ export interface AiAccount {
|
|
|
3
3
|
organizationId: string;
|
|
4
4
|
vendor: string;
|
|
5
5
|
apiKey: string;
|
|
6
|
+
/**
|
|
7
|
+
* API-host voor dit account. Alleen in te vullen bij vendors zonder vaste
|
|
8
|
+
* host (self-hosted: Ollama, vLLM, een eigen gateway) — bij de rest komt de
|
|
9
|
+
* host uit `AI_VENDORS` en wordt dit veld genegeerd.
|
|
10
|
+
*/
|
|
11
|
+
baseUrl?: string;
|
|
6
12
|
isDefaultLlm?: boolean;
|
|
7
13
|
isDefaultStt?: boolean;
|
|
8
14
|
isDefaultTts?: boolean;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* De AI-vendors waar de ai-app een adapter voor heeft.
|
|
3
|
+
*
|
|
4
|
+
* Eén bron voor zowel de UI (accountformulier, tabellabels) als de server
|
|
5
|
+
* (default-model, API-host). Eerder stonden die lijsten los van elkaar en
|
|
6
|
+
* liepen ze uiteen — de UI noemde vendors waarvoor geen adapter bestond.
|
|
7
|
+
*
|
|
8
|
+
* Deze catalogus beschrijft *wat* een vendor is. *Hoe* je ertegen praat (welke
|
|
9
|
+
* adapterklasse, welk model-filter) staat server-side in `providers/registry`,
|
|
10
|
+
* die zich tegen deze lijst verantwoordt: een vendor die hier `"chat"` claimt
|
|
11
|
+
* en daar geen chat-adapter heeft, is een testfout.
|
|
12
|
+
*
|
|
13
|
+
* `id` is wat er in `AiAccount.vendor` belandt; die string is dus onderdeel van
|
|
14
|
+
* het opslagformaat en mag niet zomaar hernoemd worden.
|
|
15
|
+
*/
|
|
16
|
+
export type AiVendorCapability = "chat" | "transcription" | "embedding";
|
|
17
|
+
export interface AiVendor {
|
|
18
|
+
id: string;
|
|
19
|
+
label: string;
|
|
20
|
+
/** Wat deze vendor kan. Bepaalt waar hij in de UI als optie verschijnt. */
|
|
21
|
+
capabilities: readonly AiVendorCapability[];
|
|
22
|
+
/**
|
|
23
|
+
* Model waarmee een aanroep draait die zelf geen model meekrijgt. Afwezig
|
|
24
|
+
* voor vendors zonder chat-adapter.
|
|
25
|
+
*/
|
|
26
|
+
defaultModel?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Vaste API-host. Afwezig betekent dat de user er zelf een moet invullen
|
|
29
|
+
* op het account (`AiAccount.baseUrl`) — dat is het geval bij self-hosted
|
|
30
|
+
* runtimes en eigen gateways.
|
|
31
|
+
*/
|
|
32
|
+
baseUrl?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare const AI_VENDORS: readonly AiVendor[];
|
|
35
|
+
export declare function findAiVendor(vendorId: string): AiVendor | undefined;
|
|
36
|
+
/** Leesbare naam voor een opgeslagen vendor-id; valt terug op de id zelf. */
|
|
37
|
+
export declare function aiVendorLabel(vendorId: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Default-model voor een vendor. De fallback is bewust een bestaand model en
|
|
40
|
+
* geen lege string: callers gebruiken dit juist omdat ze zelf geen keuze
|
|
41
|
+
* hebben.
|
|
42
|
+
*/
|
|
43
|
+
export declare function aiVendorDefaultModel(vendorId: string, fallback?: string): string;
|
|
44
|
+
/** Vendors die deze capability aanbieden — voor capability-gefilterde keuzelijsten. */
|
|
45
|
+
export declare function aiVendorsWith(capability: AiVendorCapability): AiVendor[];
|
|
46
|
+
/** True wanneer de user zelf een host moet invullen (vendor heeft er geen vaste). */
|
|
47
|
+
export declare function aiVendorNeedsBaseUrl(vendorId: string): boolean;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { MetricDefinition } from './metric';
|
|
2
|
+
/**
|
|
3
|
+
* Gedeeld vocabulaire voor verbruik — wat een app aan externe middelen opmaakt.
|
|
4
|
+
*
|
|
5
|
+
* Bewust géén centrale usage-tabel. Apps bezitten hun eigen ruwe rijen (dat is
|
|
6
|
+
* hoe de rest van de analytics-keten al werkt) en rollen die zelf op. Een
|
|
7
|
+
* centrale tabel zou apps die de data al hebben — een voip-app heeft z'n
|
|
8
|
+
* gesprekken al staan — dwingen alles dubbel weg te schrijven.
|
|
9
|
+
*
|
|
10
|
+
* Wat hier wél gedeeld wordt is de *taal*: dezelfde assen en dezelfde
|
|
11
|
+
* metric-naamgeving, zodat AI-tokens en belminuten naast elkaar in één
|
|
12
|
+
* dashboard passen en je ze op `provider` tegen elkaar kunt afzetten.
|
|
13
|
+
*
|
|
14
|
+
* Een app die verbruik wil rapporteren:
|
|
15
|
+
* 1. rolt z'n eigen rijen op met `FactAccumulator` (platform-api)
|
|
16
|
+
* 2. emit op de assen hieronder + de core-dimensie `provider`
|
|
17
|
+
* 3. declareert `usageMetrics("voip", [{ unit: "call_minutes", ... }])`
|
|
18
|
+
* in z'n `/analytics/describe`
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Waar het verbruik in wordt uitgedrukt. Open string — een app mag een eigen
|
|
22
|
+
* eenheid declareren; deze staan hier omdat ze naar verwachting terugkomen.
|
|
23
|
+
*/
|
|
24
|
+
export type UsageUnit = "input_tokens" | "output_tokens" | "cached_input_tokens" | "requests" | "seconds" | "bytes" | (string & {});
|
|
25
|
+
/**
|
|
26
|
+
* Verbruiksdimensies die meerdere apps delen. Aanvullend op de core-dimensie
|
|
27
|
+
* `provider` (welke leverancier), die hiervoor al bestond.
|
|
28
|
+
*
|
|
29
|
+
* `resource` — het specifieke ding dat verbruikt is: een model-id bij AI, een
|
|
30
|
+
* lijn of nummer bij voip, een bucket bij opslag.
|
|
31
|
+
* `origin` — de functie die het verbruik veroorzaakte: een gesprek, een
|
|
32
|
+
* playbook, een samenvatting. Beantwoordt "waar gaat het geld heen", wat een
|
|
33
|
+
* andere vraag is dan "bij wie".
|
|
34
|
+
*/
|
|
35
|
+
export declare const USAGE_DIMENSIONS: {
|
|
36
|
+
id: string;
|
|
37
|
+
label: string;
|
|
38
|
+
labelSource: "raw";
|
|
39
|
+
}[];
|
|
40
|
+
export declare const USAGE_DIMENSION_IDS: string[];
|
|
41
|
+
/** Metric-id volgens de gedeelde conventie: `<app>.usage.<unit>`. */
|
|
42
|
+
export declare function usageMetricId(app: string, unit: UsageUnit): string;
|
|
43
|
+
export interface UsageMetricSpec {
|
|
44
|
+
unit: UsageUnit;
|
|
45
|
+
label: string;
|
|
46
|
+
/** Default `count` — tokens, requests en bytes zijn allemaal tellingen. */
|
|
47
|
+
valueType?: MetricDefinition["valueType"];
|
|
48
|
+
/** Extra assen bovenop provider/resource/origin/time. */
|
|
49
|
+
extraDimensions?: string[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Bouwt de `MetricDefinition`s voor een app z'n verbruiksmetrics, met overal
|
|
53
|
+
* dezelfde assen. Scheelt elke app dezelfde zes regels boilerplate en zorgt dat
|
|
54
|
+
* de definities niet per app uiteenlopen.
|
|
55
|
+
*/
|
|
56
|
+
export declare function usageMetrics(app: string, specs: UsageMetricSpec[]): MetricDefinition[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { MemorySubjectKey } from './item';
|
|
2
|
+
/**
|
|
3
|
+
* Twee subjects die hetzelfde blijken te zijn (een merge van interacties, later een echte
|
|
4
|
+
* identiteitslaag). Het geheugen verhuist niet: de alias wordt bij het lezen opgelost.
|
|
5
|
+
*
|
|
6
|
+
* **Eén niveau diep by construction**: een alias wiens `canonical` zelf een alias is wordt
|
|
7
|
+
* geweigerd bij het schrijven. Resolutie is daarmee twee queries en nooit recursief — geen
|
|
8
|
+
* cyclus-detectie, geen diepte-limiet, geen verrassing op het hete pad.
|
|
9
|
+
*/
|
|
10
|
+
export interface MemorySubjectAlias {
|
|
11
|
+
id: string;
|
|
12
|
+
organizationId: string;
|
|
13
|
+
/** Het subject dat is opgegaan in `canonical`. Unique per org. */
|
|
14
|
+
subject: MemorySubjectKey;
|
|
15
|
+
canonical: MemorySubjectKey;
|
|
16
|
+
/** De app die de samenvoeging meldde. */
|
|
17
|
+
source: string;
|
|
18
|
+
createdAt?: number;
|
|
19
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { MemoryKindId, MemoryLink, MemorySubjectKey } from './item';
|
|
2
|
+
/**
|
|
3
|
+
* Schrijven is een **CAS-upsert**, geen snapshot-replace zoals analytics.
|
|
4
|
+
*
|
|
5
|
+
* Analytics mag een hele periode weggooien en opnieuw wegschrijven omdat een fact
|
|
6
|
+
* herberekenbaar is uit de bronstore. Een delta-gevouwen verhaal is de opgetelde uitkomst
|
|
7
|
+
* van N modelcalls en is dat niet. Bovendien is remove+insert niet atomair: een lezer kan
|
|
8
|
+
* "geen item" observeren op een subject dat wél een verhaal heeft.
|
|
9
|
+
*/
|
|
10
|
+
export interface MemoryUpsertRequest {
|
|
11
|
+
organizationId: string;
|
|
12
|
+
/** De schrijvende app; de hub vult dit uit `req.source.app` en vertrouwt de body hier niet. */
|
|
13
|
+
source: string;
|
|
14
|
+
subject: MemorySubjectKey;
|
|
15
|
+
kind: MemoryKindId;
|
|
16
|
+
/** Default bij `cardinality: "single"`: `"<kind>:<subject>"`. */
|
|
17
|
+
sourceRef?: string;
|
|
18
|
+
title: string;
|
|
19
|
+
body: string;
|
|
20
|
+
occurredAt?: number;
|
|
21
|
+
/** Watermerk van het bron-event dat deze schrijfactie veroorzaakte. */
|
|
22
|
+
throughRef?: string;
|
|
23
|
+
throughAt?: number;
|
|
24
|
+
/** Mismatch => `accepted: false` met `reason: "stale-version"`; de caller herplant. */
|
|
25
|
+
expectedVersion?: number;
|
|
26
|
+
audienceRef?: string;
|
|
27
|
+
locale?: string;
|
|
28
|
+
/** Weglaten: de hub extraheert keywords zelf uit titel + body (één tokenizer, schrijf én lees). */
|
|
29
|
+
keywords?: string[];
|
|
30
|
+
tags?: string[];
|
|
31
|
+
links?: MemoryLink[];
|
|
32
|
+
}
|
|
33
|
+
export type MemoryUpsertRejection = "stale-version" | "stale-watermark" | "unknown-kind" | "kind-disabled" | "subject-kind-mismatch" | "not-owner";
|
|
34
|
+
export interface MemoryUpsertResult {
|
|
35
|
+
accepted: boolean;
|
|
36
|
+
/** De versie zoals die nu in de store staat — ook bij een afwijzing, zodat de caller kan herplannen. */
|
|
37
|
+
version: number;
|
|
38
|
+
itemId?: string;
|
|
39
|
+
reason?: MemoryUpsertRejection;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Expliciet destructief: gooit alle items van (subject, kind) van deze bron weg en zet
|
|
43
|
+
* `items` ervoor terug. Alleen voor **herberekenbare** kinds, bv. een nachtelijke re-fold.
|
|
44
|
+
*/
|
|
45
|
+
export interface MemoryReplaceRequest {
|
|
46
|
+
organizationId: string;
|
|
47
|
+
source: string;
|
|
48
|
+
subject: MemorySubjectKey;
|
|
49
|
+
kind: MemoryKindId;
|
|
50
|
+
items: MemoryUpsertRequest[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Bron-gestuurd wissen. De **bron** pusht dit; de hub interpreteert geen deletes: de
|
|
54
|
+
* mapping van een verwijderd contact naar zijn interacties leeft in comms, en
|
|
55
|
+
* `contacts:deleted` publiceert alleen `{ id }` — zonder `organizationId`.
|
|
56
|
+
*/
|
|
57
|
+
export interface MemoryPurgeRequest {
|
|
58
|
+
organizationId: string;
|
|
59
|
+
source: string;
|
|
60
|
+
subjects: MemorySubjectKey[];
|
|
61
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* De geheugenlaag (`apps/context`): één durende laag per **subject**, waarbij de
|
|
3
|
+
* organisatie zelf per event bepaalt wat er onthouden wordt.
|
|
4
|
+
*
|
|
5
|
+
* `Memory*` en niet `Context*`: `platform/context.ts` exporteert al `HostContext` en
|
|
6
|
+
* `context.collect` (vluchtige route-context) uit dezelfde platte barrel.
|
|
7
|
+
*/
|
|
8
|
+
/** Een bestaande scopeKey: `interaction:i_1`, `contact:c_9`. Een latere identiteitslaag is gewoon een ander prefix. */
|
|
9
|
+
export type MemorySubjectKey = string;
|
|
10
|
+
/** `comms.resolution` (app-gedeclareerd) of `sales_besluitvormer` (org-eigen). */
|
|
11
|
+
export type MemoryKindId = string;
|
|
12
|
+
/**
|
|
13
|
+
* Een verwijzing naar iets anders — intern (`interaction:i_2`) of extern
|
|
14
|
+
* (`hubspot:5591`, `clickup:86ab2`).
|
|
15
|
+
*
|
|
16
|
+
* Een **lijst**, nooit een object met de relatie als key: de app-sdk http-client
|
|
17
|
+
* mangelt elke object-key camel<->snake, dus `{ "crm.company": "..." }` komt verminkt
|
|
18
|
+
* aan de andere kant aan.
|
|
19
|
+
*/
|
|
20
|
+
export interface MemoryLink {
|
|
21
|
+
rel: string;
|
|
22
|
+
target: string;
|
|
23
|
+
}
|
|
24
|
+
/** Harde grens op de body. Geheugen is een samenvatting; een mailbox-schaduwkopie is het niet. */
|
|
25
|
+
export declare const MAX_MEMORY_CHARS = 2000;
|
|
26
|
+
export interface MemoryItem {
|
|
27
|
+
id: string;
|
|
28
|
+
organizationId: string;
|
|
29
|
+
subject: MemorySubjectKey;
|
|
30
|
+
kind: MemoryKindId;
|
|
31
|
+
title: string;
|
|
32
|
+
/** DE inhoud: markdown, begrensd op {@link MAX_MEMORY_CHARS}. Nooit een genest object. */
|
|
33
|
+
body: string;
|
|
34
|
+
/** Schrijvende app (== `req.source.app`); playbook-schrijfacties komen binnen als "ai". */
|
|
35
|
+
source: string;
|
|
36
|
+
/** Identiteit binnen (subject, kind) voor de bron. Bij `cardinality: "single"` de vouw-sleutel. */
|
|
37
|
+
sourceRef: string;
|
|
38
|
+
occurredAt: number;
|
|
39
|
+
/**
|
|
40
|
+
* Watermerk: tot en met welk bron-event dit item gevouwen is. Maakt dubbele events en
|
|
41
|
+
* retries gratis — een oudere `throughAt` wordt afgewezen in plaats van overschreven.
|
|
42
|
+
*/
|
|
43
|
+
throughRef?: string;
|
|
44
|
+
throughAt?: number;
|
|
45
|
+
/** Optimistic concurrency; de hub doet compare-and-swap op dit veld. */
|
|
46
|
+
version: number;
|
|
47
|
+
/** Overgenomen uit de kind-definitie, niet uit de call — zie `MemoryKindDefinition.visibility`. */
|
|
48
|
+
visibility: MemoryVisibility;
|
|
49
|
+
/**
|
|
50
|
+
* Zichtbaarheids-ANKER (inbox-id / OwnerScope-sleutel), **geen ledenlijst**: een
|
|
51
|
+
* gesnapshotte ledenlijst veroudert bij elke inbox-join en reassignment, en
|
|
52
|
+
* stale-permissive is een lek.
|
|
53
|
+
*/
|
|
54
|
+
audienceRef?: string;
|
|
55
|
+
/** Cosine over taalgrenzen wordt geweigerd; de skip wordt geteld, niet verzwegen. */
|
|
56
|
+
locale: string;
|
|
57
|
+
/** Gedenormaliseerde termen: het enige selectieve structurele filter (er is geen substring-operator). */
|
|
58
|
+
keywords?: string[];
|
|
59
|
+
/** Snelle alternatieve sleutels, bv. `tel:+31612345678` voor het rinkelmoment. */
|
|
60
|
+
tags?: string[];
|
|
61
|
+
links?: MemoryLink[];
|
|
62
|
+
/** Model waarmee de vector is gemaakt; retrieval vergelijkt alleen binnen hetzelfde model. */
|
|
63
|
+
embeddingModel?: string;
|
|
64
|
+
/** Uit een live pull (fase 3); nooit gepersisteerd. */
|
|
65
|
+
live?: boolean;
|
|
66
|
+
createdAt?: number;
|
|
67
|
+
updatedAt?: number;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* `"audience"` = alleen voor wie het subject mag zien. `"org"` = org-breed leesbaar en
|
|
71
|
+
* daarmee vindbaar in het cross-subject-pad ("is dit eerder bij een andere klant
|
|
72
|
+
* voorgekomen?").
|
|
73
|
+
*
|
|
74
|
+
* Per **kind** gedeclareerd en niet per item: het cross-subject-pad kan zich geen
|
|
75
|
+
* autorisatie-round-trip per hit veroorloven, dus het filtert structureel op deze kolom.
|
|
76
|
+
*/
|
|
77
|
+
export type MemoryVisibility = "audience" | "org";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { LocaleBundle } from '../analytics/dashboard';
|
|
2
|
+
import { OwnerScope } from '../contact/types';
|
|
3
|
+
import { MemoryKindId, MemoryVisibility } from './item';
|
|
4
|
+
/**
|
|
5
|
+
* Wat er onthouden mág worden, en met welke regels.
|
|
6
|
+
*
|
|
7
|
+
* Twee bronnen, één type:
|
|
8
|
+
* - **app-gedeclareerd** via `GET /provider/memory/describe` (de ingebouwde defaults);
|
|
9
|
+
* - **org-eigen** als rij in `memory_kind`. Mal: `CustomFieldDef` — de organisatie
|
|
10
|
+
* definieert de sleutel, een generieke store bewaart de waarde.
|
|
11
|
+
*
|
|
12
|
+
* `ownerScope` is wat "iedereen wil zijn eigen relevante data" mogelijk maakt: sales legt
|
|
13
|
+
* andere dingen vast dan support, en een persoonlijk kind is alleen van die gebruiker.
|
|
14
|
+
*/
|
|
15
|
+
export interface MemoryKindDefinition {
|
|
16
|
+
/** Org-eigen: `[a-z0-9_]+` (geen punt — die leest als een genest form-pad). App-eigen: `<app>.<naam>`. */
|
|
17
|
+
id: MemoryKindId;
|
|
18
|
+
label: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
/** Subject-soorten waarop dit kind mag landen, bv. `["interaction"]` of `["contact"]`. */
|
|
21
|
+
subjectKinds: string[];
|
|
22
|
+
visibility: MemoryVisibility;
|
|
23
|
+
/** `"single"` = één item per (subject, kind), doorvouwen. `"many"` = losse items. */
|
|
24
|
+
cardinality: "single" | "many";
|
|
25
|
+
/** Ordening onder het tekenbudget van de bundel. */
|
|
26
|
+
priority: number;
|
|
27
|
+
/** Mag dit kind in het cross-subject-pad meedoen? Alleen zinvol bij `visibility: "org"`. */
|
|
28
|
+
crossSubjectSearchable: boolean;
|
|
29
|
+
/** Embedden kost geld; per kind aan/uit. */
|
|
30
|
+
embed: boolean;
|
|
31
|
+
retentionDays?: number;
|
|
32
|
+
/** Rang-multiplier: een opgeloste casus verslaat een losse notitie. Default 1. */
|
|
33
|
+
weight?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Wie dit kind bezit. Bepaalt zowel wie mag schrijven als de **ordening** voor een
|
|
36
|
+
* lezer (eigen team eerst). Afwezig = de hele organisatie.
|
|
37
|
+
*/
|
|
38
|
+
ownerScope?: OwnerScope;
|
|
39
|
+
/** Wie hem declareerde. De org kan een app-kind niet oprekken, alleen uitzetten. */
|
|
40
|
+
origin: "app" | "org";
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Bare payload van `GET /provider/memory/describe` — **niet** in `ResponseFactory`
|
|
45
|
+
* verpakt (mal: `AnalyticsSourceDescription`).
|
|
46
|
+
*/
|
|
47
|
+
export interface MemorySourceDescription {
|
|
48
|
+
/** De declarerende app (== `manifest.name` == `req.source.app`). */
|
|
49
|
+
source: string;
|
|
50
|
+
kinds: MemoryKindDefinition[];
|
|
51
|
+
/** Vlakke LIJST: keys met een punt worden gemangeld. */
|
|
52
|
+
locales?: LocaleBundle;
|
|
53
|
+
/** Fase 3: welke subjects/kinds deze bron live kan leveren. */
|
|
54
|
+
live?: {
|
|
55
|
+
subjectKinds: string[];
|
|
56
|
+
kinds: MemoryKindId[];
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** De samengestelde catalogus die de hub aan de frontend levert (`GET /kinds`). */
|
|
60
|
+
export interface MemoryKindCatalog {
|
|
61
|
+
/** App-gedeclareerd + org-eigen, gemengd. */
|
|
62
|
+
kinds: MemoryKindDefinition[];
|
|
63
|
+
/** Bronnen die meededen aan de fan-out (voor "wie levert dit?"). */
|
|
64
|
+
sources: string[];
|
|
65
|
+
locales: LocaleBundle;
|
|
66
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { MemoryItem, MemoryKindId, MemorySubjectKey } from './item';
|
|
2
|
+
/** Grenzen van het tekenbudget van een bundel. Buiten bereik wordt geklemd, niet geweigerd. */
|
|
3
|
+
export declare const MIN_MEMORY_BUDGET = 500;
|
|
4
|
+
export declare const MAX_MEMORY_BUDGET = 12000;
|
|
5
|
+
export declare const DEFAULT_MEMORY_BUDGET = 4000;
|
|
6
|
+
/**
|
|
7
|
+
* Één query-contract voor het dossier-paneel, de brief tijdens het rinkelen en elke
|
|
8
|
+
* AI-tool. Geen tweede codepad: het verschil tussen die drie is `budget`, niet code.
|
|
9
|
+
*/
|
|
10
|
+
export interface MemoryQuery {
|
|
11
|
+
/** Weglaten = cross-subject zoeken ("vergelijkbare cases"). */
|
|
12
|
+
subject?: MemorySubjectKey;
|
|
13
|
+
/** Extra subjects die bij hetzelfde beeld horen, bv. het contact naast de interactie. */
|
|
14
|
+
alsoSubjects?: MemorySubjectKey[];
|
|
15
|
+
/** Default true. */
|
|
16
|
+
resolveAliases?: boolean;
|
|
17
|
+
kinds?: MemoryKindId[];
|
|
18
|
+
tags?: string[];
|
|
19
|
+
/** Vrije tekst. Afwezig = puur structurele ordening (priority x recency x weight) en dus geen embedding-call. */
|
|
20
|
+
text?: string;
|
|
21
|
+
since?: number;
|
|
22
|
+
limit?: number;
|
|
23
|
+
/** Zo bedoel je "bij ANDERE klanten". */
|
|
24
|
+
excludeSubjects?: MemorySubjectKey[];
|
|
25
|
+
format?: "items" | "bundle" | "both";
|
|
26
|
+
/** Geklemd op [{@link MIN_MEMORY_BUDGET}, {@link MAX_MEMORY_BUDGET}]. */
|
|
27
|
+
budget?: number;
|
|
28
|
+
/** Fase 3: ook live bronnen bevragen, met harde timeout en eigen sub-budget. */
|
|
29
|
+
live?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface MemoryHit {
|
|
32
|
+
item: MemoryItem;
|
|
33
|
+
score: number;
|
|
34
|
+
snippet: string;
|
|
35
|
+
/** Ruw materiaal voor een confidence-gate (fase 4): waar kwam de score vandaan? */
|
|
36
|
+
matched: {
|
|
37
|
+
keyword: number;
|
|
38
|
+
semantic: number;
|
|
39
|
+
recency: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export interface MemoryQueryResult {
|
|
43
|
+
hits: MemoryHit[];
|
|
44
|
+
bundle?: string;
|
|
45
|
+
/** Hoeveel rijen het structurele voorfilter opleverde. */
|
|
46
|
+
scanned: number;
|
|
47
|
+
/** Scan-cap geraakt OF hits uit de bundel gevallen — nooit stil afkappen. */
|
|
48
|
+
truncated?: boolean;
|
|
49
|
+
/** `false` = keyword-only (geen embedding-account, of geen enkele vergelijkbare vector). */
|
|
50
|
+
semantic: boolean;
|
|
51
|
+
/** Hits die de her-autorisatie van de top-K niet overleefden. */
|
|
52
|
+
withheld?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Kandidaten overgeslagen door model- of taal-mismatch. Zonder deze teller degradeert
|
|
55
|
+
* een modelwissel volkomen stil: `cosineSimilarity` geeft bij dimensie-mismatch 0, dus
|
|
56
|
+
* na het omzetten van `isDefaultEmbedding` scoort élk bestaand item 0 en valt retrieval
|
|
57
|
+
* geruisloos terug op keyword.
|
|
58
|
+
*/
|
|
59
|
+
vectorSkipped?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Waarom er niets terugkwam, als dat een structurele reden heeft in plaats van "niets
|
|
62
|
+
* gevonden".
|
|
63
|
+
*
|
|
64
|
+
* `"no-cross-subject-kinds"` is de belangrijkste: zoeken bij ándere klanten leest alleen
|
|
65
|
+
* geheugensoorten die als `visibility: "org"` én `crossSubjectSearchable` zijn
|
|
66
|
+
* gedeclareerd. Is er geen enkele, dan is een leeg resultaat geen zoekuitkomst maar een
|
|
67
|
+
* configuratiefeit — en dat hoort de caller te weten in plaats van te concluderen dat er
|
|
68
|
+
* niets vergelijkbaars bestaat.
|
|
69
|
+
*/
|
|
70
|
+
reason?: "no-cross-subject-kinds" | "no-subject-access";
|
|
71
|
+
}
|
|
@@ -40,6 +40,12 @@ export declare const TRIGGER_VARS: readonly [{
|
|
|
40
40
|
}, {
|
|
41
41
|
readonly name: "textRaw";
|
|
42
42
|
readonly type: "string";
|
|
43
|
+
}, {
|
|
44
|
+
readonly name: "fromStatus";
|
|
45
|
+
readonly type: "string";
|
|
46
|
+
}, {
|
|
47
|
+
readonly name: "toStatus";
|
|
48
|
+
readonly type: "string";
|
|
43
49
|
}];
|
|
44
50
|
/** De variabelen die een classify-stap oplevert, per mode. */
|
|
45
51
|
export declare const CLASSIFY_VARS: {
|
|
@@ -14,6 +14,19 @@ export type PlaybookTrigger = {
|
|
|
14
14
|
/** Specific channel ids (e.g. per mailbox). Matched against activity.channelId. */
|
|
15
15
|
channelIds?: string[];
|
|
16
16
|
filter?: unknown;
|
|
17
|
+
/**
|
|
18
|
+
* Wacht dit aantal milliseconden en draai dan **één** run voor de berichten in dat
|
|
19
|
+
* venster, in plaats van een run per bericht.
|
|
20
|
+
*
|
|
21
|
+
* Voor een playbook dat bij elk bericht een modelcall doet is dit het verschil tussen
|
|
22
|
+
* vier calls en één bij een mailwisseling van vier berichten in tien minuten. De run
|
|
23
|
+
* draait op het **nieuwste** bericht uit het venster; wat ertussen zat is in de
|
|
24
|
+
* samenvatting van dat gesprek al meegenomen via de lookup-stap.
|
|
25
|
+
*
|
|
26
|
+
* Bewust op de trigger en niet in de geheugenlaag: coalesceren is een eigenschap van
|
|
27
|
+
* "hoe vaak wil ik hierop reageren", niet van wat je onthoudt.
|
|
28
|
+
*/
|
|
29
|
+
debounceMs?: number;
|
|
17
30
|
} | {
|
|
18
31
|
kind: "manual";
|
|
19
32
|
};
|
|
@@ -59,6 +72,15 @@ export interface ClassifyStep {
|
|
|
59
72
|
question?: string;
|
|
60
73
|
fields?: unknown;
|
|
61
74
|
instruction?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Wélke tekst geclassificeerd wordt, als `$ref` in de run-vars. Default `$trigger.text`.
|
|
77
|
+
*
|
|
78
|
+
* Nodig zodra de trigger zelf geen tekst draagt. Een `INTERACTION_STATUS_CHANGED`-activity
|
|
79
|
+
* heeft alleen `{ fromStatus, toStatus }` in zijn payload, dus `trigger.text` is leeg — en
|
|
80
|
+
* dan krijgt het model een lege invoer. Met `input: "$thread"` leest de stap wat een
|
|
81
|
+
* eerdere `lookup` heeft opgehaald, zoals de berichten van het gesprek.
|
|
82
|
+
*/
|
|
83
|
+
input?: string;
|
|
62
84
|
}
|
|
63
85
|
export interface GenerateStep {
|
|
64
86
|
type: "generate";
|
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=140;function f(e){return e.replace(/<style[\s\S]*?<\/style>/gi," ").replace(/<script[\s\S]*?<\/script>/gi," ").replace(/<[^>]+>/g," ").replace(/ /g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/\s+/g," ").trim()}function G(e){const t=e.trim();return t.length<=d?t:t.slice(0,d-1).trimEnd()+"…"}function l(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 k(e){switch(e.type){case"EMAIL_RECEIVED":case"EMAIL_SENT":{const t=e.payload,n=t.bodySnippet?.trim()||f(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?` (${l(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?` (${l(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?` (${l(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 V(e){return{activityId:e.id,type:e.type,snippet:G(k(e)),authorName:e.author?.name??"",direction:e.direction,createdAt:e.createdAt??Date.now()}}function $(e,t,n=[]){const r=e.createdAt;if(!r)return[];const a=new Set(n);return e.author.type==="user"&&e.author.id&&a.add(e.author.id),Object.entries(t).filter(([s,i])=>i>=r&&!a.has(s)).map(([s])=>s)}const H=[{id:"agent",label:"Agent",labelSource:"user"},{id:"team",label:"Team",labelSource:"team"},{id:"inbox",label:"Inbox",labelSource:"inbox"},{id:"channel",label:"Kanaal",labelSource:"channel"},{id:"provider",label:"Provider",labelSource:"raw"},{id:"status",label:"Status",labelSource:"raw"},{id:"handledBy",label:"Afhandelaar",labelSource:"raw"},{id:"time",label:"Tijd",labelSource:"raw"}];function w(e){const t=[];for(const n of Object.keys(e))for(const r of Object.keys(e[n]))t.push({lang:n,key:r,value:e[n][r]});return t}function c(e){return e<10?`0${e}`:`${e}`}function _(e,t){const n=new Date(e),r=`${n.getUTCFullYear()}-${c(n.getUTCMonth()+1)}-${c(n.getUTCDate())}`;return t==="day"?r:`${r}T${c(n.getUTCHours())}`}function I(e,t){const n=new Date(e);return n.setUTCMinutes(0,0,0),t==="day"&&n.setUTCHours(0),n.getTime()}const B=36e5,F=864e5;function x(e,t,n){const r=n==="hour"?B:F,a=[];for(let s=I(e,n);s<=t;s+=r)a.push(_(s,n));return a}const S=[{id:"resource",label:"Resource",labelSource:"raw"},{id:"origin",label:"Herkomst",labelSource:"raw"}],b=S.map(e=>e.id);function T(e,t){return`${e}.usage.${t}`}function v(e,t){return t.map(n=>({id:T(e,n.unit),label:n.label,category:"Verbruik",valueType:n.valueType??"count",aggregation:"sum",supportedDimensions:["provider",...b,...n.extraDimensions??[],"time"]}))}function Y(e){return(e.startsWith("tool:")?e.slice(5):e).replace(/__/g," · ").replace(/\./g," · ").replace(/_/g," ")}const W=[{name:"text",type:"string"},{name:"subject",type:"string"},{name:"from",type:"string"},{name:"type",type:"string"},{name:"direction",type:"string"},{name:"channelId",type:"string"},{name:"interactionId",type:"string"},{name:"activityId",type:"string"},{name:"authorType",type:"string"},{name:"authorName",type:"string"},{name:"textRaw",type:"string"},{name:"fromStatus",type:"string"},{name:"toStatus",type:"string"}],j={topics:[{name:"topic",type:"string"},{name:"confidence",type:"number"}],question:[{name:"answer",type:"boolean"},{name:"confidence",type:"number"}],extract:[]};function m(e){switch(e.kind){case"user":return`user:${e.userId}`;case"team":return`team:${e.teamId}`;case"org":return"org"}}function K(e){if(typeof e!="string")return;const t=e.trim();if(t==="org")return{kind:"org"};const n=t.indexOf(":");if(n<=0)return;const r=t.slice(0,n),a=t.slice(n+1).trim();if(a){if(r==="user")return{kind:"user",userId:a};if(r==="team")return{kind:"team",teamId:a}}}function M(e){return m(e)}function q(e){switch(e.kind){case"personal":return{kind:"user",userId:e.userId};case"team":return{kind:"team",teamId:e.teamId};case"org":return{kind:"org"}}}function X(e){return M(e)}const R=["done","escalated","failed","timed_out","stopped"],N=["awaiting_approval","awaiting_reply"];function D(e){return R.includes(e)}function z(e){return D(e)}function J(e){return N.includes(e)}const u=[{id:"openai",label:"OpenAI",capabilities:["chat","transcription","embedding"],defaultModel:"gpt-5-mini",baseUrl:"https://api.openai.com/v1"},{id:"gemini",label:"Google Gemini",capabilities:["chat","transcription","embedding"],defaultModel:"gemini-3.5-flash",baseUrl:"https://generativelanguage.googleapis.com/v1beta"},{id:"anthropic",label:"Anthropic",capabilities:["chat"],defaultModel:"claude-haiku-4-5",baseUrl:"https://api.anthropic.com/v1"},{id:"elevenlabs",label:"ElevenLabs",capabilities:["transcription"],baseUrl:"https://api.elevenlabs.io/v1"},{id:"moonshot",label:"Moonshot (Kimi)",capabilities:["chat"],defaultModel:"kimi-k3",baseUrl:"https://api.moonshot.ai/v1"},{id:"deepseek",label:"DeepSeek",capabilities:["chat"],defaultModel:"deepseek-v4-flash",baseUrl:"https://api.deepseek.com/v1"},{id:"groq",label:"Groq",capabilities:["chat"],defaultModel:"openai/gpt-oss-120b",baseUrl:"https://api.groq.com/openai/v1"},{id:"mistral",label:"Mistral",capabilities:["chat"],defaultModel:"mistral-large-latest",baseUrl:"https://api.mistral.ai/v1"},{id:"openrouter",label:"OpenRouter",capabilities:["chat"],defaultModel:"openrouter/auto",baseUrl:"https://openrouter.ai/api/v1"},{id:"ollama",label:"Ollama (self-hosted)",capabilities:["chat"],defaultModel:"llama3.3"},{id:"openai-compatible",label:"OpenAI-compatible (eigen endpoint)",capabilities:["chat"],defaultModel:"default"}];function o(e){return u.find(t=>t.id===e)}function Q(e){return o(e)?.label??e}function Z(e,t="gpt-5-mini"){return o(e)?.defaultModel??t}function ee(e){return u.filter(t=>t.capabilities.includes(e))}function te(e){const t=o(e);return!!t&&!t.baseUrl}const ne=new Set(["mail","message"]);function O(e,t){const n=e.settings?.signatures?.[t];return!n||!n.enabled||!n.body||n.body.trim()===""?null:n}function re(e,t,n,r="html"){if(!e)return n;const a=O(e,t);return a?`${n}${r==="text"?`
|
|
2
2
|
|
|
3
|
-
`:t==="mail"?"<br><br>-- <br>":"<br><br>"}${
|
|
4
|
-
`);for(let n=0;n<t.length;n++)if(
|
|
3
|
+
`:t==="mail"?"<br><br>-- <br>":"<br><br>"}${a.body}`:n}function ae(e){return e.endpoints??[]}const se=e=>!!e.assignedUserId||!!e.assignedInboxId,ie=e=>e.status==="closed",oe=e=>({urgent:10,high:5,normal:2,low:1})[e.priority]||0,le=(e,t=30)=>e.title?.length<=t?e.title:`${e.title.substring(0,t)}...`;function ce(e,t){return e.lastActivityAt?!(e.seenBy??[]).includes(t):!1}const ue=2e3,de=500,pe=12e3,Ee=4e3,ge=[/<blockquote/i,/class="?gmail_quote/i,/id="?[^"]*divRplyFwdMsg/i,/id="?[^"]*mail-editor-reference-message-container/i,/-{3,}\s*Original Message\s*-{3,}/i,/\n_{5,}\s*\n/,/\bOn\b[\s\S]{0,200}?\bwrote:/i],p=/^\s*(?:>+\s*)?(?:from|van|sent|verzonden|to|aan|cc|subject|onderwerp|date|datum)\s*:/i,Ae=/^\s*(?:on|op)\b.{0,200}?\b(?:wrote|schreef|geschreven)\s*:?\s*$/i;function fe(e){const t=e.split(`
|
|
4
|
+
`);for(let n=0;n<t.length;n++)if(Ae.test(t[n])||p.test(t[n])&&t.slice(n+1,n+4).some(r=>p.test(r)))return t.slice(0,n).join(`
|
|
5
5
|
`).trim();return e}function E(e){let t=e;return t=t.replace(/<(script|style)[\s\S]*?<\/\1>/gi,""),t=t.replace(/<br\s*\/?>/gi,`
|
|
6
6
|
`),t=t.replace(/<\/(p|div|li|tr|h[1-6]|ul|ol|table)>/gi,`
|
|
7
|
-
`),t=t.replace(/<[^>]+>/g,""),t=t.replace(/<[^>]*$/,""),t}function
|
|
7
|
+
`),t=t.replace(/<[^>]+>/g,""),t=t.replace(/<[^>]*$/,""),t}function g(e){return e.replace(/ /gi," ").replace(/</gi,"<").replace(/>/gi,">").replace(/"/gi,'"').replace(/'/gi,"'").replace(/&#(\d+);/g,(t,n)=>String.fromCharCode(Number(n))).replace(/&/gi,"&")}function A(e){return e.replace(/\r/g,"").replace(/[ \t]+/g," ").replace(/ *\n */g,`
|
|
8
8
|
`).replace(/\n{3,}/g,`
|
|
9
9
|
|
|
10
|
-
`).trim()}function
|
|
10
|
+
`).trim()}function _e(e){if(typeof e!="string"||!e)return"";let t=e.length;for(const s of ge){const i=e.search(s);i>=0&&i<t&&(t=i)}const n=e.slice(0,t);let r=A(g(E(n)));return r||(r=A(g(E(e)))),fe(r)||r}const Ie=/(^|[._+-])(no-?reply|noreply|donotreply|do-not-reply|newsletter|nieuwsbrief|mailer|mailing|notifications?|bounce|postmaster|marketing)@/i,Se=/\b(unsubscribe|afmelden|uitschrijven|opt[\s-]?out|manage (your )?preferences|geen (e-?mails?|nieuwsbrief|berichten) meer)\b/i;function be(e,t){return!!(e&&Ie.test(e)||t&&Se.test(t))}const h=3,y=600;function Te(e,t){return e>=h||t>=y}function L(e,t){const n=new Set(e.disabledIntents??[]),r=e.intentOverrides??{},a=t.intents.filter(i=>!n.has(i.intent)).map(i=>Me(i,r[i.intent]));if(!e.extraIntents||e.extraIntents.length===0)return a;const s=new Set(a.map(i=>i.intent));for(const i of e.extraIntents)s.has(i.intent)||(a.push(i),s.add(i.intent));return a}function U(e,t){const n={};for(const r of e.intents){if(!r.togglable)continue;const a=t?.[r.intent];n[r.intent]=a??r.defaultEnabled??!0}return n}function me(e,t){const n=U(e,t);return Object.entries(n).filter(([,r])=>!r).map(([r])=>r)}function Me(e,t){return t?{intent:t.intent??e.intent,targetSchemes:t.targetSchemes??e.targetSchemes,transport:t.transport??e.transport}:e}function Re(e,t){const n=[];for(const r of e){if(!r.enabled)continue;const a=t[r.providerId];if(a)for(const s of L(r,a))n.push({channel:r,description:a,capability:s})}return n}function Ne(e,t){return t.filter(n=>n.capability.intent===e)}function C(e,t){return t.filter(n=>n.capability.targetSchemes.includes(e))}function De(e,t){return C(e.scheme,t)}function Oe(e,t,n){const r=[];for(const a of e)for(const s of n)s.capability.intent===t&&s.capability.targetSchemes.includes(a.scheme)&&r.push({channelIntent:s,endpoint:a});return r}var P=(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))(P||{});const he="message_window",ye="message_templates",Le={FROM:"from",TO:"to",CC:"cc",BCC:"bcc",ORGANIZER:"organizer",PRESENTER:"presenter",ATTENDEE:"attendee",OWNER:"owner",MEMBER:"member",GUEST:"guest",HOST:"host",PARTICIPANT:"participant"},Ue=(e,t)=>({intent:e,...t}),Ce="folder_management",Pe="remote_search",Ge={ok:!1,code:"UNSUPPORTED",message:"Provider does not support this op"},ke=9e4,Ve="installation-id";exports.AI_VENDORS=u;exports.CLASSIFY_VARS=j;exports.CORE_DIMENSIONS=H;exports.CommunicationScheme=P;exports.DEFAULT_MEMORY_BUDGET=Ee;exports.FEATURE_FOLDER_MANAGEMENT=Ce;exports.FEATURE_REMOTE_SEARCH=Pe;exports.INSTALLATION_HEADER=Ve;exports.InteractionParticipantRole=Le;exports.MAX_MEMORY_BUDGET=pe;exports.MAX_MEMORY_CHARS=ue;exports.MIN_MEMORY_BUDGET=de;exports.PAUSED_RUN_STATUSES=N;exports.PRESENCE_ONLINE_WINDOW_MS=ke;exports.PROVIDER_FEATURE_MESSAGE_TEMPLATES=ye;exports.PROVIDER_FEATURE_MESSAGE_WINDOW=he;exports.SIGNATURE_INTENTS=ne;exports.SUMMARY_MIN_LAST_CHARS=y;exports.SUMMARY_MIN_MESSAGES=h;exports.TERMINAL_RUN_STATUSES=R;exports.TRIGGER_VARS=W;exports.UNSUPPORTED=Ge;exports.USAGE_DIMENSIONS=S;exports.USAGE_DIMENSION_IDS=b;exports.actingIdentityKey=M;exports.actorKey=X;exports.aiVendorDefaultModel=Z;exports.aiVendorLabel=Q;exports.aiVendorNeedsBaseUrl=te;exports.aiVendorsWith=ee;exports.applySignature=re;exports.buildActivityPreview=V;exports.buildChannelIntents=Re;exports.cleanMessageText=_e;exports.defineIntent=Ue;exports.disabledIntentsFromCapabilities=me;exports.filterByEndpoint=De;exports.filterByIntent=Ne;exports.filterByTargetScheme=C;exports.findAiVendor=o;exports.flattenLocales=w;exports.floorToPeriod=I;exports.formatActingIdentity=m;exports.formatPeriod=_;exports.getActivitySeenUserIds=$;exports.getContactEndpoints=ae;exports.getShortTitle=le;exports.getUrgencyScore=oe;exports.humanizeAction=Y;exports.isAssigned=se;exports.isClosed=ie;exports.isInteractionUnseen=ce;exports.isLikelyBulk=be;exports.isPaused=J;exports.isRetryable=z;exports.isTerminal=D;exports.isThreadLongEnough=Te;exports.matchContactToIntents=Oe;exports.parseActingIdentity=K;exports.periodsInRange=x;exports.playbookActor=q;exports.resolveAccountCapabilities=U;exports.resolveChannelIntents=L;exports.resolveSignature=O;exports.stripHtml=f;exports.usageMetricId=T;exports.usageMetrics=v;
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export * from './entities/calendar-event';
|
|
|
18
18
|
export * from './entities/draft';
|
|
19
19
|
export * from './entities/inbox';
|
|
20
20
|
export * from './entities/interaction';
|
|
21
|
+
export * from './entities/memory';
|
|
21
22
|
export * from './entities/task';
|
|
22
23
|
export * from './entities/note';
|
|
23
24
|
export * from './entities/read-state';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
function
|
|
1
|
+
function f(e) {
|
|
2
2
|
return e.replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<[^>]+>/g, " ").replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/\s+/g, " ").trim();
|
|
3
3
|
}
|
|
4
|
-
function
|
|
4
|
+
function b(e) {
|
|
5
5
|
const t = e.trim();
|
|
6
6
|
return t.length <= 140 ? t : t.slice(0, 139).trimEnd() + "…";
|
|
7
7
|
}
|
|
@@ -10,11 +10,11 @@ function i(e) {
|
|
|
10
10
|
const t = Math.floor(e / 60), n = Math.floor(e % 60);
|
|
11
11
|
return `${t}:${n.toString().padStart(2, "0")}`;
|
|
12
12
|
}
|
|
13
|
-
function
|
|
13
|
+
function A(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() ||
|
|
17
|
+
const t = e.payload, n = t.bodySnippet?.trim() || f(t.body ?? "");
|
|
18
18
|
return t.subject ? `${t.subject} — ${n}` : n;
|
|
19
19
|
}
|
|
20
20
|
case "CHAT_MESSAGE_SENT":
|
|
@@ -91,23 +91,23 @@ function f(e) {
|
|
|
91
91
|
return "";
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
function
|
|
94
|
+
function j(e) {
|
|
95
95
|
return {
|
|
96
96
|
activityId: e.id,
|
|
97
97
|
type: e.type,
|
|
98
|
-
snippet:
|
|
98
|
+
snippet: b(A(e)),
|
|
99
99
|
authorName: e.author?.name ?? "",
|
|
100
100
|
direction: e.direction,
|
|
101
101
|
createdAt: e.createdAt ?? Date.now()
|
|
102
102
|
};
|
|
103
103
|
}
|
|
104
|
-
function
|
|
104
|
+
function v(e, t, n = []) {
|
|
105
105
|
const r = e.createdAt;
|
|
106
106
|
if (!r) return [];
|
|
107
|
-
const
|
|
108
|
-
return e.author.type === "user" && e.author.id &&
|
|
107
|
+
const a = new Set(n);
|
|
108
|
+
return e.author.type === "user" && e.author.id && a.add(e.author.id), Object.entries(t).filter(([s, o]) => o >= r && !a.has(s)).map(([s]) => s);
|
|
109
109
|
}
|
|
110
|
-
const
|
|
110
|
+
const W = [
|
|
111
111
|
{ id: "agent", label: "Agent", labelSource: "user" },
|
|
112
112
|
{ id: "team", label: "Team", labelSource: "team" },
|
|
113
113
|
{ id: "inbox", label: "Inbox", labelSource: "inbox" },
|
|
@@ -117,7 +117,7 @@ const x = [
|
|
|
117
117
|
{ id: "handledBy", label: "Afhandelaar", labelSource: "raw" },
|
|
118
118
|
{ id: "time", label: "Tijd", labelSource: "raw" }
|
|
119
119
|
];
|
|
120
|
-
function
|
|
120
|
+
function Y(e) {
|
|
121
121
|
const t = [];
|
|
122
122
|
for (const n of Object.keys(e))
|
|
123
123
|
for (const r of Object.keys(e[n]))
|
|
@@ -127,7 +127,7 @@ function B(e) {
|
|
|
127
127
|
function l(e) {
|
|
128
128
|
return e < 10 ? `0${e}` : `${e}`;
|
|
129
129
|
}
|
|
130
|
-
function
|
|
130
|
+
function m(e, t) {
|
|
131
131
|
const n = new Date(e), r = `${n.getUTCFullYear()}-${l(n.getUTCMonth() + 1)}-${l(n.getUTCDate())}`;
|
|
132
132
|
return t === "day" ? r : `${r}T${l(n.getUTCHours())}`;
|
|
133
133
|
}
|
|
@@ -136,16 +136,38 @@ function _(e, t) {
|
|
|
136
136
|
return n.setUTCMinutes(0, 0, 0), t === "day" && n.setUTCHours(0), n.getTime();
|
|
137
137
|
}
|
|
138
138
|
const I = 36e5, T = 864e5;
|
|
139
|
-
function
|
|
140
|
-
const r = n === "hour" ? I : T,
|
|
141
|
-
for (let
|
|
142
|
-
|
|
143
|
-
return
|
|
139
|
+
function K(e, t, n) {
|
|
140
|
+
const r = n === "hour" ? I : T, a = [];
|
|
141
|
+
for (let s = _(e, n); s <= t; s += r)
|
|
142
|
+
a.push(m(s, n));
|
|
143
|
+
return a;
|
|
144
|
+
}
|
|
145
|
+
const S = [
|
|
146
|
+
{ id: "resource", label: "Resource", labelSource: "raw" },
|
|
147
|
+
{ id: "origin", label: "Herkomst", labelSource: "raw" }
|
|
148
|
+
], M = S.map((e) => e.id);
|
|
149
|
+
function D(e, t) {
|
|
150
|
+
return `${e}.usage.${t}`;
|
|
151
|
+
}
|
|
152
|
+
function q(e, t) {
|
|
153
|
+
return t.map((n) => ({
|
|
154
|
+
id: D(e, n.unit),
|
|
155
|
+
label: n.label,
|
|
156
|
+
category: "Verbruik",
|
|
157
|
+
valueType: n.valueType ?? "count",
|
|
158
|
+
aggregation: "sum",
|
|
159
|
+
supportedDimensions: [
|
|
160
|
+
"provider",
|
|
161
|
+
...M,
|
|
162
|
+
...n.extraDimensions ?? [],
|
|
163
|
+
"time"
|
|
164
|
+
]
|
|
165
|
+
}));
|
|
144
166
|
}
|
|
145
|
-
function
|
|
167
|
+
function X(e) {
|
|
146
168
|
return (e.startsWith("tool:") ? e.slice(5) : e).replace(/__/g, " · ").replace(/\./g, " · ").replace(/_/g, " ");
|
|
147
169
|
}
|
|
148
|
-
const
|
|
170
|
+
const z = [
|
|
149
171
|
{ name: "text", type: "string" },
|
|
150
172
|
{ name: "subject", type: "string" },
|
|
151
173
|
{ name: "from", type: "string" },
|
|
@@ -156,8 +178,16 @@ const W = [
|
|
|
156
178
|
{ name: "activityId", type: "string" },
|
|
157
179
|
{ name: "authorType", type: "string" },
|
|
158
180
|
{ name: "authorName", type: "string" },
|
|
159
|
-
{ name: "textRaw", type: "string" }
|
|
160
|
-
|
|
181
|
+
{ name: "textRaw", type: "string" },
|
|
182
|
+
// Alleen gevuld bij INTERACTION_STATUS_CHANGED; een filter als
|
|
183
|
+
// `trigger.toStatus == "closed"` is de trigger voor "onthoud dit bij afsluiten".
|
|
184
|
+
{ name: "fromStatus", type: "string" },
|
|
185
|
+
{ name: "toStatus", type: "string" }
|
|
186
|
+
// Bewust GEEN `contactId`. Een interactie draagt geen contact-id; dat zou per run een
|
|
187
|
+
// lookup via `remoteParty` naar de contactenlijst kosten, en dan hangt geheugen op
|
|
188
|
+
// klantniveau aan een gok in plaats van aan een vastgelegde identiteit. Zodra partijen
|
|
189
|
+
// wél in de database staan (party/CRM) komt dit terug als een echt veld.
|
|
190
|
+
], J = {
|
|
161
191
|
topics: [
|
|
162
192
|
{ name: "topic", type: "string" },
|
|
163
193
|
{ name: "confidence", type: "number" }
|
|
@@ -168,7 +198,7 @@ const W = [
|
|
|
168
198
|
],
|
|
169
199
|
extract: []
|
|
170
200
|
};
|
|
171
|
-
function
|
|
201
|
+
function N(e) {
|
|
172
202
|
switch (e.kind) {
|
|
173
203
|
case "user":
|
|
174
204
|
return `user:${e.userId}`;
|
|
@@ -178,22 +208,22 @@ function S(e) {
|
|
|
178
208
|
return "org";
|
|
179
209
|
}
|
|
180
210
|
}
|
|
181
|
-
function
|
|
211
|
+
function Q(e) {
|
|
182
212
|
if (typeof e != "string") return;
|
|
183
213
|
const t = e.trim();
|
|
184
214
|
if (t === "org") return { kind: "org" };
|
|
185
215
|
const n = t.indexOf(":");
|
|
186
216
|
if (n <= 0) return;
|
|
187
|
-
const r = t.slice(0, n),
|
|
188
|
-
if (
|
|
189
|
-
if (r === "user") return { kind: "user", userId:
|
|
190
|
-
if (r === "team") return { kind: "team", teamId:
|
|
217
|
+
const r = t.slice(0, n), a = t.slice(n + 1).trim();
|
|
218
|
+
if (a) {
|
|
219
|
+
if (r === "user") return { kind: "user", userId: a };
|
|
220
|
+
if (r === "team") return { kind: "team", teamId: a };
|
|
191
221
|
}
|
|
192
222
|
}
|
|
193
|
-
function
|
|
194
|
-
return
|
|
223
|
+
function R(e) {
|
|
224
|
+
return N(e);
|
|
195
225
|
}
|
|
196
|
-
function
|
|
226
|
+
function Z(e) {
|
|
197
227
|
switch (e.kind) {
|
|
198
228
|
case "personal":
|
|
199
229
|
return { kind: "user", userId: e.userId };
|
|
@@ -203,44 +233,148 @@ function q(e) {
|
|
|
203
233
|
return { kind: "org" };
|
|
204
234
|
}
|
|
205
235
|
}
|
|
206
|
-
function
|
|
207
|
-
return
|
|
236
|
+
function ee(e) {
|
|
237
|
+
return R(e);
|
|
238
|
+
}
|
|
239
|
+
const O = ["done", "escalated", "failed", "timed_out", "stopped"], h = ["awaiting_approval", "awaiting_reply"];
|
|
240
|
+
function L(e) {
|
|
241
|
+
return O.includes(e);
|
|
242
|
+
}
|
|
243
|
+
function te(e) {
|
|
244
|
+
return L(e);
|
|
245
|
+
}
|
|
246
|
+
function ne(e) {
|
|
247
|
+
return h.includes(e);
|
|
248
|
+
}
|
|
249
|
+
const g = [
|
|
250
|
+
{
|
|
251
|
+
id: "openai",
|
|
252
|
+
label: "OpenAI",
|
|
253
|
+
capabilities: ["chat", "transcription", "embedding"],
|
|
254
|
+
defaultModel: "gpt-5-mini",
|
|
255
|
+
baseUrl: "https://api.openai.com/v1"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
id: "gemini",
|
|
259
|
+
label: "Google Gemini",
|
|
260
|
+
capabilities: ["chat", "transcription", "embedding"],
|
|
261
|
+
defaultModel: "gemini-3.5-flash",
|
|
262
|
+
baseUrl: "https://generativelanguage.googleapis.com/v1beta"
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
id: "anthropic",
|
|
266
|
+
label: "Anthropic",
|
|
267
|
+
capabilities: ["chat"],
|
|
268
|
+
defaultModel: "claude-haiku-4-5",
|
|
269
|
+
baseUrl: "https://api.anthropic.com/v1"
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
id: "elevenlabs",
|
|
273
|
+
label: "ElevenLabs",
|
|
274
|
+
capabilities: ["transcription"],
|
|
275
|
+
baseUrl: "https://api.elevenlabs.io/v1"
|
|
276
|
+
},
|
|
277
|
+
// --- Chat Completions-vendors ------------------------------------------
|
|
278
|
+
// Alles hieronder draait op één adapter (`OpenAiCompatibleProvider`). Een
|
|
279
|
+
// nieuwe toevoegen is een rij hier + een regel in `providers/registry`.
|
|
280
|
+
//
|
|
281
|
+
// `defaultModel` is bewust een alias waar de vendor er een aanbiedt
|
|
282
|
+
// (`mistral-large-latest`, `openrouter/auto`): losse model-ids verlopen,
|
|
283
|
+
// aliassen niet. Waar dat niet kan, staat het nieuwste vlaggenschip.
|
|
284
|
+
{
|
|
285
|
+
id: "moonshot",
|
|
286
|
+
label: "Moonshot (Kimi)",
|
|
287
|
+
capabilities: ["chat"],
|
|
288
|
+
defaultModel: "kimi-k3",
|
|
289
|
+
baseUrl: "https://api.moonshot.ai/v1"
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
id: "deepseek",
|
|
293
|
+
label: "DeepSeek",
|
|
294
|
+
capabilities: ["chat"],
|
|
295
|
+
defaultModel: "deepseek-v4-flash",
|
|
296
|
+
baseUrl: "https://api.deepseek.com/v1"
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
id: "groq",
|
|
300
|
+
label: "Groq",
|
|
301
|
+
capabilities: ["chat"],
|
|
302
|
+
defaultModel: "openai/gpt-oss-120b",
|
|
303
|
+
baseUrl: "https://api.groq.com/openai/v1"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
id: "mistral",
|
|
307
|
+
label: "Mistral",
|
|
308
|
+
capabilities: ["chat"],
|
|
309
|
+
defaultModel: "mistral-large-latest",
|
|
310
|
+
baseUrl: "https://api.mistral.ai/v1"
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
id: "openrouter",
|
|
314
|
+
label: "OpenRouter",
|
|
315
|
+
capabilities: ["chat"],
|
|
316
|
+
// De Auto Router kiest zelf een model per prompt, dus dit verloopt niet
|
|
317
|
+
// mee met de wekelijks wisselende slugs in de catalogus.
|
|
318
|
+
defaultModel: "openrouter/auto",
|
|
319
|
+
baseUrl: "https://openrouter.ai/api/v1"
|
|
320
|
+
},
|
|
321
|
+
// Self-hosted: geen vaste host, de user vult er zelf een in op het account.
|
|
322
|
+
// Praten allemaal Chat Completions, dus dezelfde adapter.
|
|
323
|
+
{
|
|
324
|
+
id: "ollama",
|
|
325
|
+
label: "Ollama (self-hosted)",
|
|
326
|
+
capabilities: ["chat"],
|
|
327
|
+
defaultModel: "llama3.3"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
id: "openai-compatible",
|
|
331
|
+
label: "OpenAI-compatible (eigen endpoint)",
|
|
332
|
+
capabilities: ["chat"],
|
|
333
|
+
// vLLM, LM Studio, een eigen gateway — model en host komen van de user.
|
|
334
|
+
defaultModel: "default"
|
|
335
|
+
}
|
|
336
|
+
];
|
|
337
|
+
function c(e) {
|
|
338
|
+
return g.find((t) => t.id === e);
|
|
208
339
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
return b.includes(e);
|
|
340
|
+
function re(e) {
|
|
341
|
+
return c(e)?.label ?? e;
|
|
212
342
|
}
|
|
213
|
-
function
|
|
214
|
-
return
|
|
343
|
+
function ae(e, t = "gpt-5-mini") {
|
|
344
|
+
return c(e)?.defaultModel ?? t;
|
|
345
|
+
}
|
|
346
|
+
function se(e) {
|
|
347
|
+
return g.filter((t) => t.capabilities.includes(e));
|
|
215
348
|
}
|
|
216
|
-
function
|
|
217
|
-
|
|
349
|
+
function oe(e) {
|
|
350
|
+
const t = c(e);
|
|
351
|
+
return !!t && !t.baseUrl;
|
|
218
352
|
}
|
|
219
|
-
const
|
|
220
|
-
function
|
|
353
|
+
const ie = /* @__PURE__ */ new Set(["mail", "message"]);
|
|
354
|
+
function y(e, t) {
|
|
221
355
|
const n = e.settings?.signatures?.[t];
|
|
222
356
|
return !n || !n.enabled || !n.body || n.body.trim() === "" ? null : n;
|
|
223
357
|
}
|
|
224
|
-
function
|
|
358
|
+
function le(e, t, n, r = "html") {
|
|
225
359
|
if (!e) return n;
|
|
226
|
-
const
|
|
227
|
-
return
|
|
360
|
+
const a = y(e, t);
|
|
361
|
+
return a ? `${n}${r === "text" ? `
|
|
228
362
|
|
|
229
|
-
` : t === "mail" ? "<br><br>-- <br>" : "<br><br>"}${
|
|
363
|
+
` : t === "mail" ? "<br><br>-- <br>" : "<br><br>"}${a.body}` : n;
|
|
230
364
|
}
|
|
231
|
-
function
|
|
365
|
+
function ce(e) {
|
|
232
366
|
return e.endpoints ?? [];
|
|
233
367
|
}
|
|
234
|
-
const
|
|
368
|
+
const ue = (e) => !!e.assignedUserId || !!e.assignedInboxId, de = (e) => e.status === "closed", pe = (e) => ({
|
|
235
369
|
urgent: 10,
|
|
236
370
|
high: 5,
|
|
237
371
|
normal: 2,
|
|
238
372
|
low: 1
|
|
239
|
-
})[e.priority] || 0,
|
|
240
|
-
function
|
|
373
|
+
})[e.priority] || 0, Ee = (e, t = 30) => e.title?.length <= t ? e.title : `${e.title.substring(0, t)}...`;
|
|
374
|
+
function ge(e, t) {
|
|
241
375
|
return e.lastActivityAt ? !(e.seenBy ?? []).includes(t) : !1;
|
|
242
376
|
}
|
|
243
|
-
const
|
|
377
|
+
const fe = 2e3, be = 500, Ae = 12e3, me = 4e3, C = [
|
|
244
378
|
/<blockquote/i,
|
|
245
379
|
/class="?gmail_quote/i,
|
|
246
380
|
// Gmail quote container
|
|
@@ -253,107 +387,107 @@ const L = [
|
|
|
253
387
|
// Outlook underscore separator before "From:"
|
|
254
388
|
/\bOn\b[\s\S]{0,200}?\bwrote:/i
|
|
255
389
|
// Gmail "On <date> <name> wrote:"
|
|
256
|
-
], u = /^\s*(?:>+\s*)?(?:from|van|sent|verzonden|to|aan|cc|subject|onderwerp|date|datum)\s*:/i,
|
|
257
|
-
function
|
|
390
|
+
], u = /^\s*(?:>+\s*)?(?:from|van|sent|verzonden|to|aan|cc|subject|onderwerp|date|datum)\s*:/i, U = /^\s*(?:on|op)\b.{0,200}?\b(?:wrote|schreef|geschreven)\s*:?\s*$/i;
|
|
391
|
+
function k(e) {
|
|
258
392
|
const t = e.split(`
|
|
259
393
|
`);
|
|
260
394
|
for (let n = 0; n < t.length; n++)
|
|
261
|
-
if (
|
|
395
|
+
if (U.test(t[n]) || u.test(t[n]) && t.slice(n + 1, n + 4).some((r) => u.test(r)))
|
|
262
396
|
return t.slice(0, n).join(`
|
|
263
397
|
`).trim();
|
|
264
398
|
return e;
|
|
265
399
|
}
|
|
266
|
-
function
|
|
400
|
+
function d(e) {
|
|
267
401
|
let t = e;
|
|
268
402
|
return t = t.replace(/<(script|style)[\s\S]*?<\/\1>/gi, ""), t = t.replace(/<br\s*\/?>/gi, `
|
|
269
403
|
`), t = t.replace(/<\/(p|div|li|tr|h[1-6]|ul|ol|table)>/gi, `
|
|
270
404
|
`), t = t.replace(/<[^>]+>/g, ""), t = t.replace(/<[^>]*$/, ""), t;
|
|
271
405
|
}
|
|
272
|
-
function
|
|
406
|
+
function p(e) {
|
|
273
407
|
return e.replace(/ /gi, " ").replace(/</gi, "<").replace(/>/gi, ">").replace(/"/gi, '"').replace(/'/gi, "'").replace(/&#(\d+);/g, (t, n) => String.fromCharCode(Number(n))).replace(/&/gi, "&");
|
|
274
408
|
}
|
|
275
|
-
function
|
|
409
|
+
function E(e) {
|
|
276
410
|
return e.replace(/\r/g, "").replace(/[ \t]+/g, " ").replace(/ *\n */g, `
|
|
277
411
|
`).replace(/\n{3,}/g, `
|
|
278
412
|
|
|
279
413
|
`).trim();
|
|
280
414
|
}
|
|
281
|
-
function
|
|
415
|
+
function _e(e) {
|
|
282
416
|
if (typeof e != "string" || !e) return "";
|
|
283
417
|
let t = e.length;
|
|
284
|
-
for (const
|
|
285
|
-
const o = e.search(
|
|
418
|
+
for (const s of C) {
|
|
419
|
+
const o = e.search(s);
|
|
286
420
|
o >= 0 && o < t && (t = o);
|
|
287
421
|
}
|
|
288
422
|
const n = e.slice(0, t);
|
|
289
|
-
let r = p(d(
|
|
290
|
-
return r || (r = p(d(
|
|
423
|
+
let r = E(p(d(n)));
|
|
424
|
+
return r || (r = E(p(d(e)))), k(r) || r;
|
|
291
425
|
}
|
|
292
|
-
const
|
|
293
|
-
function
|
|
294
|
-
return !!(e &&
|
|
426
|
+
const P = /(^|[._+-])(no-?reply|noreply|donotreply|do-not-reply|newsletter|nieuwsbrief|mailer|mailing|notifications?|bounce|postmaster|marketing)@/i, $ = /\b(unsubscribe|afmelden|uitschrijven|opt[\s-]?out|manage (your )?preferences|geen (e-?mails?|nieuwsbrief|berichten) meer)\b/i;
|
|
427
|
+
function Ie(e, t) {
|
|
428
|
+
return !!(e && P.test(e) || t && $.test(t));
|
|
295
429
|
}
|
|
296
|
-
const
|
|
297
|
-
function
|
|
298
|
-
return e >=
|
|
430
|
+
const G = 3, V = 600;
|
|
431
|
+
function Te(e, t) {
|
|
432
|
+
return e >= G || t >= V;
|
|
299
433
|
}
|
|
300
|
-
function
|
|
301
|
-
const n = new Set(e.disabledIntents ?? []), r = e.intentOverrides ?? {},
|
|
302
|
-
if (!e.extraIntents || e.extraIntents.length === 0) return
|
|
303
|
-
const
|
|
434
|
+
function w(e, t) {
|
|
435
|
+
const n = new Set(e.disabledIntents ?? []), r = e.intentOverrides ?? {}, a = t.intents.filter((o) => !n.has(o.intent)).map((o) => x(o, r[o.intent]));
|
|
436
|
+
if (!e.extraIntents || e.extraIntents.length === 0) return a;
|
|
437
|
+
const s = new Set(a.map((o) => o.intent));
|
|
304
438
|
for (const o of e.extraIntents)
|
|
305
|
-
|
|
306
|
-
return
|
|
439
|
+
s.has(o.intent) || (a.push(o), s.add(o.intent));
|
|
440
|
+
return a;
|
|
307
441
|
}
|
|
308
|
-
function
|
|
442
|
+
function H(e, t) {
|
|
309
443
|
const n = {};
|
|
310
444
|
for (const r of e.intents) {
|
|
311
445
|
if (!r.togglable) continue;
|
|
312
|
-
const
|
|
313
|
-
n[r.intent] =
|
|
446
|
+
const a = t?.[r.intent];
|
|
447
|
+
n[r.intent] = a ?? r.defaultEnabled ?? !0;
|
|
314
448
|
}
|
|
315
449
|
return n;
|
|
316
450
|
}
|
|
317
|
-
function
|
|
318
|
-
const n =
|
|
451
|
+
function Se(e, t) {
|
|
452
|
+
const n = H(e, t);
|
|
319
453
|
return Object.entries(n).filter(([, r]) => !r).map(([r]) => r);
|
|
320
454
|
}
|
|
321
|
-
function
|
|
455
|
+
function x(e, t) {
|
|
322
456
|
return t ? {
|
|
323
457
|
intent: t.intent ?? e.intent,
|
|
324
458
|
targetSchemes: t.targetSchemes ?? e.targetSchemes,
|
|
325
459
|
transport: t.transport ?? e.transport
|
|
326
460
|
} : e;
|
|
327
461
|
}
|
|
328
|
-
function
|
|
462
|
+
function Me(e, t) {
|
|
329
463
|
const n = [];
|
|
330
464
|
for (const r of e) {
|
|
331
465
|
if (!r.enabled) continue;
|
|
332
|
-
const
|
|
333
|
-
if (
|
|
334
|
-
for (const
|
|
335
|
-
n.push({ channel: r, description:
|
|
466
|
+
const a = t[r.providerId];
|
|
467
|
+
if (a)
|
|
468
|
+
for (const s of w(r, a))
|
|
469
|
+
n.push({ channel: r, description: a, capability: s });
|
|
336
470
|
}
|
|
337
471
|
return n;
|
|
338
472
|
}
|
|
339
|
-
function
|
|
473
|
+
function De(e, t) {
|
|
340
474
|
return t.filter((n) => n.capability.intent === e);
|
|
341
475
|
}
|
|
342
|
-
function
|
|
476
|
+
function B(e, t) {
|
|
343
477
|
return t.filter((n) => n.capability.targetSchemes.includes(e));
|
|
344
478
|
}
|
|
345
|
-
function
|
|
346
|
-
return
|
|
479
|
+
function Ne(e, t) {
|
|
480
|
+
return B(e.scheme, t);
|
|
347
481
|
}
|
|
348
|
-
function
|
|
482
|
+
function Re(e, t, n) {
|
|
349
483
|
const r = [];
|
|
350
|
-
for (const
|
|
351
|
-
for (const
|
|
352
|
-
|
|
484
|
+
for (const a of e)
|
|
485
|
+
for (const s of n)
|
|
486
|
+
s.capability.intent === t && s.capability.targetSchemes.includes(a.scheme) && r.push({ channelIntent: s, endpoint: a });
|
|
353
487
|
return r;
|
|
354
488
|
}
|
|
355
|
-
var
|
|
356
|
-
const
|
|
489
|
+
var F = /* @__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))(F || {});
|
|
490
|
+
const Oe = "message_window", he = "message_templates", Le = {
|
|
357
491
|
// E-mail
|
|
358
492
|
FROM: "from",
|
|
359
493
|
TO: "to",
|
|
@@ -370,59 +504,73 @@ const Ee = "message_window", ge = "message_templates", fe = {
|
|
|
370
504
|
// Voice/conference
|
|
371
505
|
HOST: "host",
|
|
372
506
|
PARTICIPANT: "participant"
|
|
373
|
-
},
|
|
507
|
+
}, ye = (e, t) => ({ intent: e, ...t }), Ce = "folder_management", Ue = "remote_search", ke = { ok: !1, code: "UNSUPPORTED", message: "Provider does not support this op" }, Pe = 9e4, $e = "installation-id";
|
|
374
508
|
export {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
509
|
+
g as AI_VENDORS,
|
|
510
|
+
J as CLASSIFY_VARS,
|
|
511
|
+
W as CORE_DIMENSIONS,
|
|
512
|
+
F as CommunicationScheme,
|
|
513
|
+
me as DEFAULT_MEMORY_BUDGET,
|
|
514
|
+
Ce as FEATURE_FOLDER_MANAGEMENT,
|
|
515
|
+
Ue as FEATURE_REMOTE_SEARCH,
|
|
516
|
+
$e as INSTALLATION_HEADER,
|
|
517
|
+
Le as InteractionParticipantRole,
|
|
518
|
+
Ae as MAX_MEMORY_BUDGET,
|
|
519
|
+
fe as MAX_MEMORY_CHARS,
|
|
520
|
+
be as MIN_MEMORY_BUDGET,
|
|
521
|
+
h as PAUSED_RUN_STATUSES,
|
|
522
|
+
Pe as PRESENCE_ONLINE_WINDOW_MS,
|
|
523
|
+
he as PROVIDER_FEATURE_MESSAGE_TEMPLATES,
|
|
524
|
+
Oe as PROVIDER_FEATURE_MESSAGE_WINDOW,
|
|
525
|
+
ie as SIGNATURE_INTENTS,
|
|
526
|
+
V as SUMMARY_MIN_LAST_CHARS,
|
|
527
|
+
G as SUMMARY_MIN_MESSAGES,
|
|
528
|
+
O as TERMINAL_RUN_STATUSES,
|
|
529
|
+
z as TRIGGER_VARS,
|
|
530
|
+
ke as UNSUPPORTED,
|
|
531
|
+
S as USAGE_DIMENSIONS,
|
|
532
|
+
M as USAGE_DIMENSION_IDS,
|
|
533
|
+
R as actingIdentityKey,
|
|
534
|
+
ee as actorKey,
|
|
535
|
+
ae as aiVendorDefaultModel,
|
|
536
|
+
re as aiVendorLabel,
|
|
537
|
+
oe as aiVendorNeedsBaseUrl,
|
|
538
|
+
se as aiVendorsWith,
|
|
539
|
+
le as applySignature,
|
|
540
|
+
j as buildActivityPreview,
|
|
541
|
+
Me as buildChannelIntents,
|
|
542
|
+
_e as cleanMessageText,
|
|
543
|
+
ye as defineIntent,
|
|
544
|
+
Se as disabledIntentsFromCapabilities,
|
|
545
|
+
Ne as filterByEndpoint,
|
|
546
|
+
De as filterByIntent,
|
|
547
|
+
B as filterByTargetScheme,
|
|
548
|
+
c as findAiVendor,
|
|
549
|
+
Y as flattenLocales,
|
|
404
550
|
_ as floorToPeriod,
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
551
|
+
N as formatActingIdentity,
|
|
552
|
+
m as formatPeriod,
|
|
553
|
+
v as getActivitySeenUserIds,
|
|
554
|
+
ce as getContactEndpoints,
|
|
555
|
+
Ee as getShortTitle,
|
|
556
|
+
pe as getUrgencyScore,
|
|
557
|
+
X as humanizeAction,
|
|
558
|
+
ue as isAssigned,
|
|
559
|
+
de as isClosed,
|
|
560
|
+
ge as isInteractionUnseen,
|
|
561
|
+
Ie as isLikelyBulk,
|
|
562
|
+
ne as isPaused,
|
|
563
|
+
te as isRetryable,
|
|
564
|
+
L as isTerminal,
|
|
565
|
+
Te as isThreadLongEnough,
|
|
566
|
+
Re as matchContactToIntents,
|
|
567
|
+
Q as parseActingIdentity,
|
|
568
|
+
K as periodsInRange,
|
|
569
|
+
Z as playbookActor,
|
|
570
|
+
H as resolveAccountCapabilities,
|
|
571
|
+
w as resolveChannelIntents,
|
|
572
|
+
y as resolveSignature,
|
|
573
|
+
f as stripHtml,
|
|
574
|
+
D as usageMetricId,
|
|
575
|
+
q as usageMetrics
|
|
428
576
|
};
|
|
@@ -59,6 +59,23 @@ export interface AiToolDescriptor extends AiTool {
|
|
|
59
59
|
* overal.
|
|
60
60
|
*/
|
|
61
61
|
surface?: "interactive";
|
|
62
|
+
/**
|
|
63
|
+
* Reikt deze tool naar **buiten** de organisatie, of blijft het intern?
|
|
64
|
+
*
|
|
65
|
+
* `"outward"` = er gaat iets de deur uit of er verschijnt iets bij een derde: een mail
|
|
66
|
+
* versturen, een ticket aanmaken, in Slack posten. Twee autonome playbooks die dat
|
|
67
|
+
* tegelijk op hetzelfde gesprek doen leveren dubbele berichten aan een klant, en dáár
|
|
68
|
+
* hoort een mens tussen te staan.
|
|
69
|
+
*
|
|
70
|
+
* `"internal"` = het resultaat blijft binnen het platform: een attribuut, een
|
|
71
|
+
* geheugen-item, een notitie. Twee playbooks die dat tegelijk doen zitten elkaar niet in
|
|
72
|
+
* de weg — verschillende rijen, en de concurrency wordt al door de store afgehandeld.
|
|
73
|
+
*
|
|
74
|
+
* **Afwezig betekent `"outward"`.** Bewust de voorzichtige kant: een tool die niets
|
|
75
|
+
* declareert hoort niet stilzwijgend als onschuldig te gelden. Zie
|
|
76
|
+
* `shouldDemoteAuto` in de playbook-engine, dat hierop de suggest-degradatie bepaalt.
|
|
77
|
+
*/
|
|
78
|
+
effect?: "internal" | "outward";
|
|
62
79
|
}
|
|
63
80
|
/**
|
|
64
81
|
* Body van `POST /provider/ai-tools/invoke`. Vervangt vijf inline structurele
|
package/dist/platform/scope.d.ts
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
|
+
import { OwnerScope } from '../entities/contact/types';
|
|
1
2
|
import { ActingIdentity } from './identity';
|
|
2
3
|
/** Access decision + whether the scope anchor is team-shared + the SSE audience. */
|
|
3
4
|
export interface ScopeAuth {
|
|
4
5
|
allowed: boolean;
|
|
5
6
|
shared?: boolean;
|
|
6
7
|
audience?: string[];
|
|
8
|
+
/**
|
|
9
|
+
* Van wie deze resource is, zoals de eigenaar-app het ziet: een persoonlijke mailbox, een
|
|
10
|
+
* teaminbox, of de organisatie.
|
|
11
|
+
*
|
|
12
|
+
* Los van `shared` en `audience`, die iets anders zeggen. `shared` gaat over of een
|
|
13
|
+
* AI-gesprek op deze scope met het team gedeeld wordt (voor een interactie altijd waar), en
|
|
14
|
+
* `audience` is de momentane ledenlijst voor SSE. Dit veld gaat over **eigenaarschap**, en
|
|
15
|
+
* dat is wat een consument nodig heeft om te beslissen of afgeleide kennis breder mag dan
|
|
16
|
+
* de resource zelf.
|
|
17
|
+
*
|
|
18
|
+
* Eerste consument is de geheugenlaag: een org-brede geheugensoort wordt bij het schrijven
|
|
19
|
+
* versmald naar `audience` als het bronsubject persoonlijk is, zodat een gesprek uit iemands
|
|
20
|
+
* eigen mailbox niet in de cross-klant-zoekresultaten van een collega opduikt. Afwezig =
|
|
21
|
+
* onbekend, en dat wordt daar als "versmallen" gelezen: de veilige kant.
|
|
22
|
+
*/
|
|
23
|
+
ownerScope?: OwnerScope;
|
|
7
24
|
}
|
|
8
25
|
/** GET /provider/scope/describe response: the scopeKey prefixes an app owns. */
|
|
9
26
|
export interface ScopeDescribe {
|