@opencxh/domain 1.154.0 → 1.158.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.
Files changed (35) hide show
  1. package/dist/entities/activity/catalog.d.ts +23 -0
  2. package/dist/entities/ai-profile/types.d.ts +19 -6
  3. package/dist/entities/ai-settings/types.d.ts +27 -0
  4. package/dist/entities/ai-settings/types.test.d.ts +1 -0
  5. package/dist/entities/assignment/index.d.ts +1 -0
  6. package/dist/entities/assignment/types.d.ts +142 -0
  7. package/dist/entities/assignment/types.test.d.ts +1 -0
  8. package/dist/entities/live-lens/index.d.ts +1 -0
  9. package/dist/entities/live-lens/types.d.ts +81 -0
  10. package/dist/entities/live-lens/types.test.d.ts +1 -0
  11. package/dist/entities/playbook/actor.d.ts +20 -0
  12. package/dist/entities/playbook/assignment.d.ts +123 -0
  13. package/dist/entities/playbook/assignment.test.d.ts +1 -0
  14. package/dist/entities/playbook/index.d.ts +1 -0
  15. package/dist/entities/playbook/status.test.d.ts +1 -0
  16. package/dist/entities/playbook/trigger-vars.d.ts +34 -3
  17. package/dist/entities/playbook/types.d.ts +412 -33
  18. package/dist/entities/read-state/types.d.ts +1 -5
  19. package/dist/entities/user/types.d.ts +56 -0
  20. package/dist/index.cjs +8 -8
  21. package/dist/index.d.ts +6 -0
  22. package/dist/index.js +1022 -523
  23. package/dist/platform/ai-tools.d.ts +20 -0
  24. package/dist/platform/audio-gate.test.d.ts +1 -0
  25. package/dist/platform/context.d.ts +16 -0
  26. package/dist/platform/presence.d.ts +59 -0
  27. package/dist/platform/resource.d.ts +39 -0
  28. package/dist/platform/sdk.d.ts +6 -0
  29. package/dist/platform/tool-sources.test.d.ts +1 -0
  30. package/dist/platform/transcript-cadence.d.ts +93 -0
  31. package/dist/platform/transcript-cadence.test.d.ts +1 -0
  32. package/dist/platform/transcript-sanitize.d.ts +1 -0
  33. package/dist/platform/transcript-sanitize.test.d.ts +1 -0
  34. package/dist/platform/work-mode.test.d.ts +1 -0
  35. package/package.json +1 -1
@@ -104,6 +104,26 @@ export interface AiToolResult {
104
104
  */
105
105
  sources?: ToolSource[];
106
106
  }
107
+ /**
108
+ * Stabiele sleutel voor "dit heb ik al laten zien".
109
+ *
110
+ * De volgorde `id` → `url` → `title` is aflopend in betrouwbaarheid: een id is stabiel, een
111
+ * url meestal, een titel alleen bij gebrek aan beide. Dat laatste is bewust geen fout — een
112
+ * geheugen-item heeft geen pagina en soms geen id, en dan is de titel de enige identiteit die
113
+ * het heeft. Een sleutel is nooit leeg, want dan zou hetzelfde item elke ronde terugkomen.
114
+ */
115
+ export declare function sourceKey(source: ToolSource): string;
116
+ /**
117
+ * Wat hiervan nieuw is, met de sleutels erbij.
118
+ *
119
+ * Voor een oppervlak dat zichzelf ongevraagd bijwerkt (live meelezen) is dit het verschil
120
+ * tussen "drie kaarten" en "dezelfde drie kaarten, elke acht seconden opnieuw". Ontdubbelt
121
+ * ook binnen de lading zelf: twee banen kunnen hetzelfde artikel aandragen.
122
+ */
123
+ export declare function freshSources(sources: readonly ToolSource[], alreadyShown?: readonly string[]): {
124
+ sources: ToolSource[];
125
+ keys: string[];
126
+ };
107
127
  /**
108
128
  * Returned by an app's `GET /provider/ai-tools/describe`.
109
129
  *
@@ -0,0 +1 @@
1
+ export {};
@@ -17,6 +17,22 @@ export interface HostContext {
17
17
  title?: string;
18
18
  /** Highest wins when multiple apps claim the same route. */
19
19
  priority?: number;
20
+ /**
21
+ * De interactie waar dit oppervlak over gaat, als er één is.
22
+ *
23
+ * Als **veld** en niet als losse `slices`-sleutel: een paneel dat hierop leunt hoort te
24
+ * kunnen vertrouwen dat het er is. `CallTranscriptTab` hing zijn "Opslaan als notitie" hier
25
+ * al aan terwijl niemand het vulde, dus die knop was permanent uitgeschakeld — een
26
+ * toevallige sleutel geeft geen typefout, een ontbrekend veld wel.
27
+ */
28
+ interactionId?: string;
29
+ /**
30
+ * De **live** gesprekssessie, alleen gevuld zolang er een verbinding staat.
31
+ *
32
+ * Dit is de sleutel waarmee een paneel zich op `transcripts.deltas$(sessionId)` abonneert.
33
+ * Zonder dit veld toonde de transcript-tab altijd de lege staat, ongeacht wat er gezegd werd.
34
+ */
35
+ sessionId?: string;
20
36
  /** Extra data providers attach (e.g. interaction, activities, transcripts). */
21
37
  slices?: Record<string, unknown>;
22
38
  }
@@ -97,3 +97,62 @@ export interface AgeablePresence {
97
97
  * on a real transition.
98
98
  */
99
99
  export declare function agePresenceEntry<T extends AgeablePresence>(entry: T, now: number): T;
100
+ /**
101
+ * Voor welk **team** iemand nu werkt.
102
+ *
103
+ * De rol van een medewerker is een eigenschap van de persoon en niet van het gesprek: een
104
+ * support-medewerker doet meestal één ding, en op een persoonlijk kanaal is er niets aan het
105
+ * gesprek af te lezen. Deze instelling staat naast presence om dezelfde reden dat presence
106
+ * bestaat — het is "hoe ben ik nu", niet "wie ben ik".
107
+ *
108
+ * Waarde is een `teamId` en geen profielverwijzing: team is de scope waar profielen, onderwerpen,
109
+ * workflows en inboxen al op gescoped zijn, en het is ook wat een gerouteerd gesprek oplevert
110
+ * (`assignedInboxId` → `Inbox.teamId`). Eén keuze lost ze allemaal consistent op.
111
+ */
112
+ export interface WorkMode {
113
+ userId: string;
114
+ teamId: string;
115
+ /** `"manual"` of een bron die het namens de gebruiker zette (een rooster, later). */
116
+ source: string;
117
+ }
118
+ /**
119
+ * Voor welk team deze gebruiker nu werkt, en of hij daarvoor iets moet kiezen.
120
+ *
121
+ * Drie uitkomsten, en de derde is het hele punt:
122
+ *
123
+ * - **`teamId`** — óf expliciet gezet, óf impliciet omdat er maar één team is. Wie één ding doet
124
+ * hoeft nooit iets in te stellen.
125
+ * - **`undefined` met `mustChoose: false`** — geen enkel team; er is niets te kiezen en niets te
126
+ * doen.
127
+ * - **`undefined` met `mustChoose: true`** — meer dan één team en niets gekozen. Dan hoort een
128
+ * oppervlak dat op de rol leunt te **zwijgen** in plaats van er één te raden: fout gokken is
129
+ * erger dan niets tonen, en dat is dezelfde fail-closed regel als bij de account↔kanaal-binding.
130
+ *
131
+ * Pure functie, want dit is de enige echte beslissing in de werkmodus — de rest is opslag.
132
+ */
133
+ export declare function resolveWorkMode(stored: {
134
+ teamId?: string;
135
+ } | null | undefined, readableTeamIds: readonly string[]): {
136
+ teamId?: string;
137
+ mustChoose: boolean;
138
+ };
139
+ /**
140
+ * Mag de audio-pijplijn lopen — en dus: mag er meegelezen worden?
141
+ *
142
+ * Twee onafhankelijke voorwaarden, en dat is precies waarom dit een functie is en geen `&&` op
143
+ * de plek van gebruik:
144
+ *
145
+ * - **`providerAvailable`** — is er een STT-provider geregistreerd. Dat was tot nu toe de énige
146
+ * voorwaarde, en daarmee was "de AI-app is geïnstalleerd" hetzelfde als "we luisteren mee bij
147
+ * elk gesprek, org-breed". Een technische toevalligheid als beleid.
148
+ * - **`allowed`** — wil de organisatie dat. Een assistent die ongevraagd meeleest hoort niet te
149
+ * bestaan zonder dat je hem kunt stoppen.
150
+ *
151
+ * De gate wordt elke twee seconden opnieuw geasserteerd (federated remotes kunnen hun handler
152
+ * later registreren dan deze app boot), dus een schakelaar die niet in deze functie zit racet
153
+ * tegen die tik en gaat vanzelf weer aan.
154
+ */
155
+ export declare function shouldRunAudioPipeline(input: {
156
+ providerAvailable: boolean;
157
+ allowed: boolean;
158
+ }): boolean;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Waar iets **over gaat**: een verwijzing naar een resource, los van welke app hem bezit.
3
+ *
4
+ * Dit type stond in `entities/read-state`, met als doc "so read-state (and, later, an audit log)
5
+ * can attach to any resource". Dat "later" is nu: een run heeft precies dezelfde verwijzing nodig.
6
+ * Hij is daarom naar `platform/` gehesen in plaats van er een tweede naast te zetten — read-state
7
+ * exporteert hem door, zodat geen enkele bestaande importeur verandert.
8
+ *
9
+ * De platformbrede sleutelvorm is `"<soort>:<id>"`: dat is wat `authorizeScope` aanneemt, wat
10
+ * `ScopeAuthorizeRequest.scopeKey` draagt, en waar de dossiersleutels uit bestaan. {@link refKey}
11
+ * is de brug daarheen.
12
+ *
13
+ * Let op de veldnaam: `type`, terwijl de rest van de codebase `kind` gebruikt voor een
14
+ * discriminant (`OwnerScope.kind`, `ActingIdentity.kind`, `Decider.kind`, `splitScopeKey().kind`).
15
+ * Dat is een inconsistentie van vóór dit type, en hem hier omdopen zou read-state en de
16
+ * resource-reminders meesleuren — een eigen opruiming, niet deze.
17
+ */
18
+ export interface ResourceRef {
19
+ /** `"interaction"`, `"task"`, … — dezelfde soorten die een scope-provider declareert. */
20
+ type: string;
21
+ id: string;
22
+ }
23
+ /** De sleutelvorm die `authorizeScope` en de dossiersleutels gebruiken. */
24
+ export declare function refKey(ref: ResourceRef): string;
25
+ /**
26
+ * De soort die comms bezit, en de enige waar de engine iets extra's van weet: op een interactie
27
+ * kun je wachten op een antwoord en een regel in de tijdlijn zetten. Andere soorten kunnen dat
28
+ * niet, en dat is geen omissie maar het verschil tussen een gesprek en een taak.
29
+ */
30
+ export declare const INTERACTION_KIND = "interaction";
31
+ /**
32
+ * Het interactie-id, als dit onderwerp een gesprek is.
33
+ *
34
+ * Bestaat zodat de twee dingen die écht een gesprek nodig hebben (`wait-for-reply` en de
35
+ * lifecycle-marker) daarnaar kunnen vragen zonder overal `type === "interaction"` uit te
36
+ * schrijven — en zodat een run over een taak daar netjes `undefined` uit krijgt in plaats van
37
+ * stilzwijgend een id dat naar het verkeerde soort wijst.
38
+ */
39
+ export declare function interactionIdOf(subject: ResourceRef | undefined): string | undefined;
@@ -105,8 +105,14 @@ export interface InternalSDK<LocalServices extends ServiceMap = {}, TranslationK
105
105
  partials$(sessionId: string): Observable<TranscriptSegment>;
106
106
  persist(sessionId: string): Promise<void>;
107
107
  clear(sessionId: string): void;
108
+ /**
109
+ * `opts.from` is de index waar `segments` in het transcript begint: `0` is het hele
110
+ * transcript, hoger maakt het een delta op wat de ontvanger al heeft. Zonder dat stuurde
111
+ * elke flush (elke ~3s) de complete array opnieuw.
112
+ */
108
113
  setPersister(fn: (sessionId: string, segments: TranscriptSegment[], opts: {
109
114
  finalize: boolean;
115
+ from: number;
110
116
  }) => Promise<void>): void;
111
117
  };
112
118
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,93 @@
1
+ import { TranscriptSegment } from './media';
2
+ /**
3
+ * Wanneer is er genoeg nieuw gezegd om opnieuw te gaan kijken?
4
+ *
5
+ * Dit is de héle beslissing achter een live-meelezende assistent, en met opzet puur: geen
6
+ * model, geen klok, geen store. Comms bepaalt *wanneer* (hier), de ai-app bepaalt *wat*.
7
+ *
8
+ * De twee valkuilen die de drempels hieronder afdekken:
9
+ *
10
+ * - **Te vaak.** De transcribe-route wordt elke ~3 seconden per actief gesprek geraakt. Zonder
11
+ * vloer is dat 20 zoekrondes per minuut per gesprek, waarvan de meeste hetzelfde antwoord
12
+ * opleveren omdat er één woord bij is gekomen.
13
+ * - **Te gretig.** "Ja." en "Klopt." zijn nieuwe uitingen maar geen nieuw onderwerp. Daarom
14
+ * telt niet alleen tijd, maar ook of de zoekvraag wérkelijk verschoven is.
15
+ *
16
+ * De vergelijking gebeurt tegen de vorige **uitgevoerde** zoekvraag, niet tegen het vorige
17
+ * venster: anders schuift het onderwerp mee met het venster en vuurt hij eeuwig door.
18
+ */
19
+ /** Hoeveel gesprek er in de zoekvraag gaat. Ouder dan dit is niet meer waar het over gaat. */
20
+ export declare const CADENCE_WINDOW_MS = 60000;
21
+ /** Ondergrens tussen twee rondes, ongeacht hoeveel er gezegd is. */
22
+ export declare const CADENCE_FLOOR_MS = 8000;
23
+ /** Minder dan dit aantal nieuwe definitieve uitingen is nog geen nieuw onderwerp. */
24
+ export declare const CADENCE_MIN_NEW_SEGMENTS = 2;
25
+ /** Onder dit aandeel nieuwe woorden gaat het nog over hetzelfde. */
26
+ export declare const CADENCE_MIN_NOVELTY = 0.4;
27
+ /** De losse woorden waar een zoekvraag op rust: kleine letters, zonder ruis, zonder dubbelen. */
28
+ export declare function extractTerms(text: string): string[];
29
+ /**
30
+ * Welk deel van waar het nú over gaat, is nog niet opgezocht? 1 is volledig nieuw, 0 is
31
+ * precies dezelfde vraag.
32
+ *
33
+ * Bewust asymmetrisch, en niet Jaccard. Het venster groeit terwijl de vorige zoekvraag
34
+ * blijft staan, en Jaccard straft die groei af: hoe langer het gesprek over één onderwerp
35
+ * doorgaat, hoe lager de symmetrische overlap wordt, tot hij alsnog vuurt. Dat is exact de
36
+ * "vuurt eeuwig door"-fout die de vergelijking moest voorkomen. De vraag die telt is
37
+ * eenzijdig: staat er iets nieuws op tafel?
38
+ */
39
+ export declare function novelty(current: readonly string[], previous: readonly string[]): number;
40
+ /**
41
+ * De laatste ~60 seconden gesproken tekst, schoongemaakt.
42
+ *
43
+ * Het venster wordt gemeten vanaf de **laatste uiting**, niet vanaf de serverklok:
44
+ * `startedAt`/`endedAt` van een segment komen van de transcriptieprovider en hoeven niet
45
+ * dezelfde oorsprong te hebben als `Date.now()` hier. Onderling verschil is wél
46
+ * betrouwbaar, en dat is alles wat een venster nodig heeft.
47
+ *
48
+ * Partiële segmenten blijven eruit: die veranderen nog terwijl je ze leest.
49
+ */
50
+ export declare function buildWindow(segments: readonly TranscriptSegment[], windowMs?: number): {
51
+ text: string;
52
+ segmentCount: number;
53
+ };
54
+ /**
55
+ * Hoeveel getoonde sleutels we bijhouden. Een gesprek van een half uur kan er honderden
56
+ * opleveren en de rij wordt bij elke flush in zijn geheel herschreven, dus dit is geen
57
+ * geheugen maar een venster: wat eruit valt mag opnieuw verschijnen.
58
+ */
59
+ export declare const MAX_SHOWN_KEYS = 60;
60
+ /**
61
+ * Wat dit gesprek al te zien heeft gekregen, plus wat er net bij kwam — zonder dubbelen en
62
+ * begrensd. De oudste sleutels vallen eruit, want de nieuwste zijn de kaarten die nu op het
63
+ * scherm staan.
64
+ */
65
+ export declare function mergeShownKeys(existing: readonly string[], shown: readonly string[], max?: number): string[];
66
+ /** Wat er van de vorige ronde bewaard is. Leeg betekent "nog nooit gekeken". */
67
+ export interface CadenceState {
68
+ /** Serverklok van de vorige ronde — alleen voor de vloer. */
69
+ lastTriggerAt?: number;
70
+ /** Aantal definitieve uitingen op dat moment — alleen voor "hoeveel is er bij gekomen". */
71
+ lastSegmentCount?: number;
72
+ /** De vorige uitgevoerde zoekvraag, waar de onderwerpwissel tegen gemeten wordt. */
73
+ lastQueryTerms?: string[];
74
+ }
75
+ export type CadenceDecision = {
76
+ trigger: false;
77
+ reason: "no_speech" | "too_soon" | "too_few_new" | "same_topic";
78
+ } | {
79
+ trigger: true;
80
+ text: string;
81
+ terms: string[];
82
+ segmentCount: number;
83
+ };
84
+ /**
85
+ * Vier poorten, van goedkoop naar duur — de eerste die dichtblijft, is het antwoord.
86
+ * `reason` is er zodat een gesprek dat níets oplevert te verklaren is zonder een debugger.
87
+ */
88
+ export declare function decideCadence(input: {
89
+ segments: readonly TranscriptSegment[];
90
+ now: number;
91
+ state: CadenceState;
92
+ windowMs?: number;
93
+ }): CadenceDecision;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export declare const sanitizeTranscript: (transcript: string) => string;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencxh/domain",
3
- "version": "1.154.0",
3
+ "version": "1.158.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",