@opencxh/domain 1.154.0 → 1.159.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/activity/catalog.d.ts +33 -2
- package/dist/entities/activity/resolve.d.ts +24 -0
- package/dist/entities/activity/types.d.ts +45 -2
- package/dist/entities/ai-conversation/types.d.ts +26 -0
- package/dist/entities/ai-profile/types.d.ts +19 -6
- package/dist/entities/ai-settings/types.d.ts +27 -0
- package/dist/entities/ai-settings/types.test.d.ts +1 -0
- package/dist/entities/assignment/index.d.ts +1 -0
- package/dist/entities/assignment/types.d.ts +170 -0
- package/dist/entities/assignment/types.test.d.ts +1 -0
- package/dist/entities/interaction/types.d.ts +4 -2
- package/dist/entities/live-lens/index.d.ts +1 -0
- package/dist/entities/live-lens/types.d.ts +81 -0
- package/dist/entities/live-lens/types.test.d.ts +1 -0
- package/dist/entities/playbook/actor.d.ts +20 -0
- package/dist/entities/playbook/assignment.d.ts +123 -0
- package/dist/entities/playbook/assignment.test.d.ts +1 -0
- package/dist/entities/playbook/index.d.ts +1 -0
- package/dist/entities/playbook/status.test.d.ts +1 -0
- package/dist/entities/playbook/trigger-vars.d.ts +34 -3
- package/dist/entities/playbook/types.d.ts +412 -33
- package/dist/entities/read-state/types.d.ts +1 -5
- package/dist/entities/user/types.d.ts +56 -0
- package/dist/index.cjs +8 -8
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1099 -545
- package/dist/platform/ai-tools.d.ts +20 -0
- package/dist/platform/api.d.ts +13 -0
- package/dist/platform/audio-gate.test.d.ts +1 -0
- package/dist/platform/context.d.ts +16 -0
- package/dist/platform/presence.d.ts +59 -0
- package/dist/platform/resource.d.ts +39 -0
- package/dist/platform/sdk.d.ts +6 -0
- package/dist/platform/tool-sources.test.d.ts +1 -0
- package/dist/platform/transcript-cadence.d.ts +93 -0
- package/dist/platform/transcript-cadence.test.d.ts +1 -0
- package/dist/platform/transcript-sanitize.d.ts +1 -0
- package/dist/platform/transcript-sanitize.test.d.ts +1 -0
- package/dist/platform/work-mode.test.d.ts +1 -0
- package/package.json +1 -1
|
@@ -51,6 +51,18 @@ interface ActivityTypeInfo<T extends ActivityType = ActivityType> {
|
|
|
51
51
|
carriesText?: boolean;
|
|
52
52
|
/** Door de engine zelf geschreven; mag geen nieuwe playbook-run openen. */
|
|
53
53
|
playbookAuthored?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Betekent dit type dat er daadwerkelijk contact tot stand kwam — dat er gesproken is?
|
|
56
|
+
*
|
|
57
|
+
* Nodig omdat "is hier echt iets uitgewisseld" niet uit berichten alleen te bepalen valt: een
|
|
58
|
+
* aangenomen telefoongesprek is een volwaardige casus met nul berichten, en een gemiste oproep
|
|
59
|
+
* is het tegenovergestelde. Een eigen vlag en niet afgeleid van `shape`, want beide zijn
|
|
60
|
+
* `event` — het verschil zit in de betekenis, niet in de vorm.
|
|
61
|
+
*
|
|
62
|
+
* Bewust hier en niet als lijstje in de app die de vraag stelt: dat is precies hoe "is dit een
|
|
63
|
+
* bericht?" zes keer los kwam te staan.
|
|
64
|
+
*/
|
|
65
|
+
connected?: boolean;
|
|
54
66
|
/**
|
|
55
67
|
* Verschijnt in de trigger-keuzelijst van playbooks en webhooks.
|
|
56
68
|
*
|
|
@@ -96,9 +108,17 @@ export declare function activityIconOf(type: string): string;
|
|
|
96
108
|
/** `mail` | `chat` | `voice` | `video`, of `undefined` voor een levenscyclus-event. */
|
|
97
109
|
export declare function channelKindOf(type: string): ActivityChannelKind | undefined;
|
|
98
110
|
/**
|
|
99
|
-
* Draagt
|
|
100
|
-
*
|
|
111
|
+
* Draagt deze vorm een bericht of een interne notitie — iets wat een mens schreef en wat als
|
|
112
|
+
* "het gesprek" telt? Sluit transcripten uit; die zijn wel tekst, maar geen bericht.
|
|
113
|
+
*
|
|
114
|
+
* Op de **shape** en niet op het type, zodat er precies één definitie van "is dit een
|
|
115
|
+
* bericht" bestaat. {@link isMessageType} beantwoordt hem voor de ingebouwde types;
|
|
116
|
+
* `ActivityTypeRegistry.isMessage` doet hetzelfde voor een type dat een app declareerde.
|
|
117
|
+
* Zonder die splitsing had elk van beide zijn eigen kopie van de regel gekregen — en dat is
|
|
118
|
+
* precies hoe er twaalf hardgecodeerde typelijstjes door de codebase zijn ontstaan.
|
|
101
119
|
*/
|
|
120
|
+
export declare function isMessageShape(shape: ActivityShape | undefined): boolean;
|
|
121
|
+
/** Zie {@link isMessageShape}. Voor de ingebouwde types. */
|
|
102
122
|
export declare function isMessageType(type: string): boolean;
|
|
103
123
|
/** Kan een mens hierop antwoorden? Notities niet — die gaan nergens heen. */
|
|
104
124
|
export declare function isReplyableType(type: string): boolean;
|
|
@@ -111,6 +131,17 @@ export declare function carriesText(type: string): boolean;
|
|
|
111
131
|
export declare function messageCountsAs(type: string): "inbound_message" | "outbound_message" | undefined;
|
|
112
132
|
/** Door de playbook-engine zelf geschreven; mag geen nieuwe run openen. */
|
|
113
133
|
export declare function isPlaybookAuthoredType(type: string): boolean;
|
|
134
|
+
/** Kwam er met dit type daadwerkelijk contact tot stand? Zie {@link ActivityTypeInfo.connected}. */
|
|
135
|
+
export declare function isConnectedType(type: string): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Is dit een transcript-achtig artefact — meegeleverde inhoud die leesbare tekst draagt?
|
|
138
|
+
*
|
|
139
|
+
* Het onderscheid met een bestand zit al in de catalogus (`FILE_UPLOADED` draagt geen tekst), dus
|
|
140
|
+
* dit is geen nieuwe lijst maar een combinatie van twee bestaande antwoorden. Zo telt het
|
|
141
|
+
* transcript van een externe provider mee zodra die app zijn type declareert, zonder dat hier een
|
|
142
|
+
* naam bij hoeft.
|
|
143
|
+
*/
|
|
144
|
+
export declare function isTranscriptType(type: string): boolean;
|
|
114
145
|
/** De inboxlijst-regel, of `""` wanneer het type er geen heeft. */
|
|
115
146
|
export declare function activitySnippet(activity: Activity): string;
|
|
116
147
|
/**
|
|
@@ -57,6 +57,30 @@ export declare class ActivityTypeRegistry {
|
|
|
57
57
|
descriptor(type: string): ActivityTypeDescriptor | undefined;
|
|
58
58
|
/** De declaratieve blokken van een type, als het er heeft. */
|
|
59
59
|
blocks(type: string): ActivityBlock[] | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Dezelfde semantische vragen als de losse accessors in `catalog.ts`, maar dan óók voor
|
|
62
|
+
* types die een app declareerde.
|
|
63
|
+
*
|
|
64
|
+
* Dat verschil is de reden dat deze methodes bestaan. `isMessageType(type)` leest alleen
|
|
65
|
+
* `ACTIVITY_CATALOG`, dus een gedeclareerd type met `shape: "message"` gaf daar `false` —
|
|
66
|
+
* een helpdesk-app kon een berichtsoort meebrengen die vervolgens niet meetelde als
|
|
67
|
+
* gesprek, niet antwoordbaar was en niet in de analytics landde. Wie een registry bij de
|
|
68
|
+
* hand heeft, hoort deze te gebruiken; wie er geen heeft valt terug op de ingebouwde.
|
|
69
|
+
*
|
|
70
|
+
* De regel zelf staat maar op één plek: {@link isMessageShape} en de velden van
|
|
71
|
+
* {@link ResolvedActivityType}.
|
|
72
|
+
*/
|
|
73
|
+
isMessage(type: string): boolean;
|
|
74
|
+
/** Kan een mens hierop antwoorden? Notities niet — die gaan nergens heen. */
|
|
75
|
+
isReplyable(type: string): boolean;
|
|
76
|
+
/** Leesbare inhoud voor een model: berichten, notities én transcripten. */
|
|
77
|
+
carriesText(type: string): boolean;
|
|
78
|
+
/** Telt mee als in- of uitgaand bericht in de analytics-rollup. */
|
|
79
|
+
countsAs(type: string): "inbound_message" | "outbound_message" | undefined;
|
|
80
|
+
/** `mail` | `chat` | `voice` | `video`, of `undefined` voor een levenscyclus-event. */
|
|
81
|
+
channelKind(type: string): ActivityChannelKind | undefined;
|
|
82
|
+
/** Transcript-achtig artefact: meegeleverde inhoud die leesbare tekst draagt. */
|
|
83
|
+
isTranscript(type: string): boolean;
|
|
60
84
|
/** De vertaler die bij deze registry hoort, voor het oplossen van blokteksten. */
|
|
61
85
|
get translator(): Translate;
|
|
62
86
|
}
|
|
@@ -165,9 +165,16 @@ export type FileUploadedPayload = {
|
|
|
165
165
|
/** Storage FilePointer id, when the file lives in the storage app (download via storage.file.{id}.download). */
|
|
166
166
|
fileId?: string;
|
|
167
167
|
};
|
|
168
|
+
/**
|
|
169
|
+
* Elke status die `Interaction.status` kan aannemen, `snoozed` inbegrepen. Die ontbrak,
|
|
170
|
+
* en daardoor had de tijdlijn een gat precies waar hij het meest verrast: parkeren en
|
|
171
|
+
* wakker worden waren de enige twee statuswissels die geen spoor achterlieten, dus een
|
|
172
|
+
* gesprek sprong uit en weer in de lijst zonder dat iets vertelde waarom.
|
|
173
|
+
*/
|
|
174
|
+
export type InteractionStatus = "open" | "pending" | "closed" | "snoozed";
|
|
168
175
|
export type InteractionStatusChangedPayload = {
|
|
169
|
-
fromStatus:
|
|
170
|
-
toStatus:
|
|
176
|
+
fromStatus: InteractionStatus;
|
|
177
|
+
toStatus: InteractionStatus;
|
|
171
178
|
};
|
|
172
179
|
export type InteractionAssignedPayload = {
|
|
173
180
|
userId: string;
|
|
@@ -335,3 +342,39 @@ export type Activity = (BaseActivity & {
|
|
|
335
342
|
type: "INTERACTION_ASSIGNED";
|
|
336
343
|
payload: InteractionAssignedPayload;
|
|
337
344
|
});
|
|
345
|
+
/**
|
|
346
|
+
* Een activity van **welk type dan ook**, inclusief een type dat een app declareerde.
|
|
347
|
+
*
|
|
348
|
+
* `Activity` is een gesloten unie over de 41 ingebouwde types, en dat is met opzet: alleen zo
|
|
349
|
+
* weet TypeScript na `activity.type === "EMAIL_RECEIVED"` dat `payload.from` bestaat. Maar
|
|
350
|
+
* `ACTIVITY_TYPE_AUTHORING.md` nodigt apps uit hun eigen type mee te brengen, en zo'n rij
|
|
351
|
+
* pást niet in die unie — vandaar de ~40 `as Activity`-casts die door de repo staan.
|
|
352
|
+
*
|
|
353
|
+
* Een open tak ín `Activity` lost dat niet op: dan wordt `payload` overal een unie met
|
|
354
|
+
* `Record<string, unknown>` en verdwijnt precies de versmalling waar de unie voor bestaat.
|
|
355
|
+
* Daarom een eigen naam. Code die ook gedeclareerde types verwerkt — de feed, de
|
|
356
|
+
* inboxregel, de analytics-rollup — typeert op `AnyActivity` en vraagt de catalogus wat het
|
|
357
|
+
* ding is; code die in een payload leest blijft op `Activity` en versmalt.
|
|
358
|
+
*/
|
|
359
|
+
export type AnyActivity = Activity | (BaseActivity & {
|
|
360
|
+
type: string;
|
|
361
|
+
payload: Record<string, unknown>;
|
|
362
|
+
});
|
|
363
|
+
/**
|
|
364
|
+
* Type-guards voor de twee payload-vormen waar de UI rechtstreeks in leest.
|
|
365
|
+
*
|
|
366
|
+
* Dit zijn bewust wél typenamen en geen catalogus-vraag. De catalogus beantwoordt *semantiek*
|
|
367
|
+
* ("is dit een bericht", "welk kanaal") en dat hoort nooit als typelijstje in een component.
|
|
368
|
+
* Deze twee doen iets anders: ze **versmallen het type**, zodat `activity.payload.from` en
|
|
369
|
+
* `activity.payload.text` erna bestaan. Een `channelKindOf(...) === "mail"` kan dat niet — die
|
|
370
|
+
* geeft een boolean terug en TypeScript weet daarna nog steeds niet welke payload er ligt.
|
|
371
|
+
*
|
|
372
|
+
* Ze staan hier, naast de union, zodat er één plek is die de namen kent in plaats van een
|
|
373
|
+
* herhaling per component.
|
|
374
|
+
*/
|
|
375
|
+
export declare function isEmailActivity(activity: Activity): activity is Extract<Activity, {
|
|
376
|
+
type: "EMAIL_RECEIVED" | "EMAIL_SENT";
|
|
377
|
+
}>;
|
|
378
|
+
export declare function isChatMessageActivity(activity: Activity): activity is Extract<Activity, {
|
|
379
|
+
type: "CHAT_MESSAGE_SENT" | "CHAT_MESSAGE_RECEIVED";
|
|
380
|
+
}>;
|
|
@@ -1,4 +1,25 @@
|
|
|
1
|
+
import { AssignmentStatus } from '../assignment/types';
|
|
1
2
|
export type AIConversationVisibility = "shared" | "personal";
|
|
3
|
+
/**
|
|
4
|
+
* Dat deze draad die van een **agent-opdracht** is, en waar hij bij hoort te verschijnen.
|
|
5
|
+
*
|
|
6
|
+
* De draad van een opdracht leeft op `assignment:<id>` en niet op het onderwerp — dat is precies
|
|
7
|
+
* waarom een opdracht meerdere beurten kan overleven terwijl de mensvragen over hetzelfde gesprek
|
|
8
|
+
* hun eigen draad houden. Het nadeel was dat er geen enkele ingang naar toe was, behalve de
|
|
9
|
+
* agentpagina: het werk was er wel, maar niet te zien op de plek waar het over ging.
|
|
10
|
+
*
|
|
11
|
+
* Daarom levert `conversation/resolve` de draad van een opdracht ook uit bij de scope van zijn
|
|
12
|
+
* **onderwerp**, met dit stempel erop. Niet opgeslagen — het is de stand van nu, gelezen bij het
|
|
13
|
+
* ophalen, precies zoals de status van de opdracht zelf.
|
|
14
|
+
*/
|
|
15
|
+
export interface AIConversationAgentThread {
|
|
16
|
+
assignmentId: string;
|
|
17
|
+
/** Het `userId` van de agent die deze opdracht doet. */
|
|
18
|
+
agentId: string;
|
|
19
|
+
status: AssignmentStatus;
|
|
20
|
+
/** De scope waaronder deze draad wordt meegeleverd: het onderwerp van de opdracht. */
|
|
21
|
+
subjectScopeKey: string;
|
|
22
|
+
}
|
|
2
23
|
/**
|
|
3
24
|
* A single assistant conversation (thread). Grouped into the tools-panel tabs by
|
|
4
25
|
* `scopeKey`; messages, runs and thread-continuity key on the conversation id.
|
|
@@ -22,4 +43,9 @@ export interface AIConversation {
|
|
|
22
43
|
origin: "auto" | "user";
|
|
23
44
|
createdAt: number;
|
|
24
45
|
updatedAt: number;
|
|
46
|
+
/**
|
|
47
|
+
* Gezet bij het ophalen, nooit opgeslagen: deze draad hangt aan een agent-opdracht over de
|
|
48
|
+
* gevraagde scope. Aanwezig = meelezen, niet meepraten (zie {@link AIConversationAgentThread}).
|
|
49
|
+
*/
|
|
50
|
+
agent?: AIConversationAgentThread;
|
|
25
51
|
}
|
|
@@ -8,16 +8,21 @@ export interface AIProfile<T extends Record<string, any> = Record<string, any>>
|
|
|
8
8
|
organizationId: string;
|
|
9
9
|
/**
|
|
10
10
|
* Who may use this profile. Company-wide (`org`) or bound to a `team`; profiles
|
|
11
|
-
* are never personal.
|
|
12
|
-
*
|
|
11
|
+
* are never personal. The server resolves one on create (`normalizeProfileScope`),
|
|
12
|
+
* so it is always present.
|
|
13
13
|
*/
|
|
14
|
-
ownerScope
|
|
14
|
+
ownerScope: OwnerScope;
|
|
15
15
|
name: string;
|
|
16
16
|
description?: string;
|
|
17
17
|
accountId: string;
|
|
18
18
|
model: string;
|
|
19
19
|
providerConfig?: T;
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* De basisinstructie van dit brein. Optioneel: een profiel dat alleen tools ontsluit heeft
|
|
22
|
+
* er geen nodig. Stond hier als verplicht terwijl het schema hem optioneel maakte, waardoor
|
|
23
|
+
* elke lezer `?? ""` moest schrijven zonder dat het type dat verklaarde.
|
|
24
|
+
*/
|
|
25
|
+
systemPrompt?: string;
|
|
21
26
|
contextIds?: string[];
|
|
22
27
|
predefinedPrompts?: PredefinedPrompt[];
|
|
23
28
|
/** Namespaced tool names this profile may use (default: none enabled). */
|
|
@@ -31,8 +36,16 @@ export interface AIProfile<T extends Record<string, any> = Record<string, any>>
|
|
|
31
36
|
* which the transform leaves untouched.
|
|
32
37
|
*
|
|
33
38
|
* Under autonomy "suggest", write tools are held for approval; reads run freely.
|
|
34
|
-
* A tool absent from this list defaults to "write" (safe).
|
|
35
|
-
*
|
|
39
|
+
* A tool absent from this list defaults to "write" (safe).
|
|
40
|
+
*
|
|
41
|
+
* **Waar dit wél en níet geldt.** Afgedwongen in `playbook/ai/gate.ts`, en daarmee op elke
|
|
42
|
+
* autonome run (workflow of procedure). De interactieve assistent doet er **niets** mee: daar
|
|
43
|
+
* bestaat geen bevestigingsstap, en er is ook geen `requiresConfirmation` om aan te haken —
|
|
44
|
+
* die stond hier als belofte terwijl er nergens een implementatie was. Een `write`-markering
|
|
45
|
+
* die je met een gesprek in de chat verwacht af te dwingen, doet dus niets.
|
|
46
|
+
*
|
|
47
|
+
* Dat is een openstaand gat en geen ontwerpkeuze: een bevestigingsstap in de chat is UI plus
|
|
48
|
+
* een extra ronde, en hoort een besluit te zijn in plaats van een veld dat stil niets doet.
|
|
36
49
|
*/
|
|
37
50
|
toolPolicy?: {
|
|
38
51
|
name: string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wat een organisatie voor de AI-app als geheel instelt — niet per profiel, niet per gebruiker.
|
|
3
|
+
*
|
|
4
|
+
* Eén veld tot nu toe, en dat is met opzet geen `Record<string, unknown>`: een instelling die
|
|
5
|
+
* niemand kan opnoemen is een instelling die niemand kan vinden.
|
|
6
|
+
*/
|
|
7
|
+
export interface AiOrgSettings {
|
|
8
|
+
/**
|
|
9
|
+
* Mag de AI-app meeluisteren met gesprekken (spraak naar tekst)?
|
|
10
|
+
*
|
|
11
|
+
* Dit is de knop die er niet was: de AI-app installeren zette transcriptie aan voor élk
|
|
12
|
+
* gesprek in de organisatie, wat een technische toevalligheid was die als beleid gold.
|
|
13
|
+
*/
|
|
14
|
+
listeningEnabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Mag er meegeluisterd worden?
|
|
18
|
+
*
|
|
19
|
+
* **Afwezig = ja**, en dat is hier de juiste kant: de knop is nieuw, en een organisatie die
|
|
20
|
+
* hem nooit heeft aangeraakt hoort niet plotseling zonder transcriptie te zitten. Uit is dus
|
|
21
|
+
* een expliciete keuze en niet een lege rij.
|
|
22
|
+
*
|
|
23
|
+
* Eén plek, zodat de client (die de upload overslaat) en de server (die hem weigert) niet
|
|
24
|
+
* ieder hun eigen default kunnen hebben — dan zou de een luisteren terwijl de ander denkt van
|
|
25
|
+
* niet.
|
|
26
|
+
*/
|
|
27
|
+
export declare function listeningAllowed(settings: AiOrgSettings | null | undefined): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './types';
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { ResourceRef } from '../../platform/resource';
|
|
2
|
+
import { Activity } from '../activity/types';
|
|
3
|
+
import { WaitingOn } from '../playbook/types';
|
|
4
|
+
/**
|
|
5
|
+
* Een **opdracht**: werk dat aan een agent is toegewezen en zo lang leeft als het werk.
|
|
6
|
+
*
|
|
7
|
+
* **Waarom dit een entity is.** Het was er geen: `plans/unify-ai.md` besliste "een opdracht *is*
|
|
8
|
+
* een run met een procedure, een agent als actor en een lange levensduur". Dat is verdedigbaar
|
|
9
|
+
* gedacht, en de code liet zien wat het kostte:
|
|
10
|
+
*
|
|
11
|
+
* - `resume-playbook.ts` kortte elke procedure-run af op `{ status: "done" }`, dus een opdracht was
|
|
12
|
+
* structureel **één modelbeurt**;
|
|
13
|
+
* - de draad (een `AIConversation` op `playbook-run:<id>`) deelde géén geheugen met de agent:
|
|
14
|
+
* `runProcedure` gaf bewust geen `conversationId` mee, dus wat een mens in de draad zei bereikte
|
|
15
|
+
* de agent nooit en omgekeerd;
|
|
16
|
+
* - `retry` betekende "doe de hele opdracht opnieuw vanaf de originele trigger" — zinnig voor een
|
|
17
|
+
* workflow van seconden, onzin voor werk dat dagen liep;
|
|
18
|
+
* - en "wat voor ding is dit" moest uit de *uitvoeringsvorm* worden afgeleid
|
|
19
|
+
* (`decider.kind === "procedure"`), dus de vorm deed dienst als producttype.
|
|
20
|
+
*
|
|
21
|
+
* Nu is een opdracht wat hij is, en een run wat die is: **één beurt**. De opdracht leeft, de runs
|
|
22
|
+
* zijn wat hij deed.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Waar een opdracht in verkeert.
|
|
26
|
+
*
|
|
27
|
+
* Bewust dezelfde woorden als de eindstanden van een run, en bewust minder: een opdracht kan niet
|
|
28
|
+
* `failed` zijn. Een gefaalde beurt is een gefaalde run — de opdracht staat dan nog open, want er
|
|
29
|
+
* is niets afgehandeld. Dat verschil is precies waarom dit een eigen vocabulaire is.
|
|
30
|
+
*/
|
|
31
|
+
export type AssignmentStatus = "open" | "waiting" | "done" | "escalated";
|
|
32
|
+
export declare const TERMINAL_ASSIGNMENT_STATUSES: readonly ["done", "escalated"];
|
|
33
|
+
export declare function isAssignmentTerminal(status: AssignmentStatus | string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* De scope-soort waaronder de draad van een opdracht leeft.
|
|
36
|
+
*
|
|
37
|
+
* Was `playbook-run:<id>`, want de draad hing aan een run. Hij hangt nu aan de opdracht, en dat is
|
|
38
|
+
* het hele punt: een draad die stopt zodra één beurt klaar is, is geen draad.
|
|
39
|
+
*
|
|
40
|
+
* Staat in domain omdat het een **contract tussen client en server** is: de client bouwt de
|
|
41
|
+
* sleutel om de draad te openen, de server autoriseert hem. Twee plekken die het voorvoegsel los
|
|
42
|
+
* uitschrijven lopen bij de eerste typefout stil uiteen — en het gevolg daarvan is "geen toegang
|
|
43
|
+
* tot deze scope", niet een foutmelding die het zegt.
|
|
44
|
+
*/
|
|
45
|
+
export declare const ASSIGNMENT_SCOPE_KIND = "assignment";
|
|
46
|
+
export declare function assignmentScopeKey(assignmentId: string): string;
|
|
47
|
+
export interface Assignment {
|
|
48
|
+
id: string;
|
|
49
|
+
organizationId: string;
|
|
50
|
+
/** De agent die dit doet: het `userId` van een gebruiker met `type: "agent"`. */
|
|
51
|
+
agentId: string;
|
|
52
|
+
/** De definitie waar deze opdracht uit voortkomt (een playbook met een procedure). */
|
|
53
|
+
jobId: string;
|
|
54
|
+
/**
|
|
55
|
+
* De versie waarmee hij begon — puur voor de audit.
|
|
56
|
+
*
|
|
57
|
+
* Elke **beurt** pint zijn eigen procedure (`run.decider`), dus een verbeterde prose komt bij de
|
|
58
|
+
* volgende beurt aan zonder een lopende beurt van opdracht te laten wisselen. Eeuwig pinnen zou
|
|
59
|
+
* betekenen dat een correctie nooit aankomt; niet pinnen dat een beurt halverwege verandert.
|
|
60
|
+
*/
|
|
61
|
+
jobVersion: number;
|
|
62
|
+
/** Waar deze opdracht over gaat. Afwezig = werk zonder resource (een rollup, een klus). */
|
|
63
|
+
subjectKind?: string;
|
|
64
|
+
subjectId?: string;
|
|
65
|
+
status: AssignmentStatus;
|
|
66
|
+
/**
|
|
67
|
+
* Waarop de **opdracht** wacht tussen twee beurten.
|
|
68
|
+
*
|
|
69
|
+
* Bewust hier en niet op de run, want het zijn twee verschillende soorten pauze:
|
|
70
|
+
*
|
|
71
|
+
* - een **workflow** pauzeert *midden in een flow* en hervat op stap N+1 met dezelfde vars — de
|
|
72
|
+
* cursor (`run.resumeAtStep`) is essentieel;
|
|
73
|
+
* - een **opdracht** heeft geen cursor. "Hervatten" is *nog een beurt nemen*, met de draad als
|
|
74
|
+
* geheugen.
|
|
75
|
+
*
|
|
76
|
+
* Dat die twee in één veld geperst zaten is waarom elke procedure-run `resumeAtStep: 0` opsloeg.
|
|
77
|
+
*/
|
|
78
|
+
waitingOn?: WaitingOn | null;
|
|
79
|
+
/** De soort van `waitingOn` als platte kolom — de store kan niet in een genest object zoeken. */
|
|
80
|
+
waitingOnKind?: WaitingOn["on"] | null;
|
|
81
|
+
/**
|
|
82
|
+
* Hoeveel beurten deze opdracht al heeft gehad.
|
|
83
|
+
*
|
|
84
|
+
* Was `run.rounds`, wat het aantal keer parkeren *binnen één run* telde. Op dit niveau is het de
|
|
85
|
+
* teller die telt: een agent die met een mens heen en weer blijft pingpongen moet een plafond
|
|
86
|
+
* hebben.
|
|
87
|
+
*/
|
|
88
|
+
turns: number;
|
|
89
|
+
/** De draad: agent én mens schrijven hierin. Dit is de toestand van de opdracht. */
|
|
90
|
+
conversationId: string;
|
|
91
|
+
/** Lijst-index, geen autorisatie — zie `PlaybookRun.visibleTo`. */
|
|
92
|
+
visibleTo?: string[];
|
|
93
|
+
/** Waar deze opdracht over gaat, in mensentaal. Voor de lijst. */
|
|
94
|
+
title?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Waaróm de opdracht in deze stand staat, als er iets uit te leggen is.
|
|
97
|
+
*
|
|
98
|
+
* `decideAssignmentState` rekende dit al uit en niets bewaarde het, dus je zag `escalated` zonder
|
|
99
|
+
* uitleg — precies de vraag ("waarom heeft hij dit overgedragen?") die dit ontwerp zou moeten
|
|
100
|
+
* kunnen beantwoorden. De reden van de agent zelf staat hier, en zijn woorden in de draad.
|
|
101
|
+
*/
|
|
102
|
+
statusReason?: string;
|
|
103
|
+
createdBy: string;
|
|
104
|
+
lastActivityAt?: number;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Wekt deze activity een opdracht die op een antwoord wacht?
|
|
108
|
+
*
|
|
109
|
+
* **Twee bronnen, twee regels, en dat verschil is het hele punt.**
|
|
110
|
+
*
|
|
111
|
+
* - **De klant antwoordt** (`inbound`): dat wekt altijd. Een klant kan niemand @-noemen, en zijn
|
|
112
|
+
* antwoord is per definitie het antwoord waar de opdracht op wachtte.
|
|
113
|
+
* - **Een collega schrijft een interne notitie**: die wekt **alleen als de agent genoemd is**.
|
|
114
|
+
*
|
|
115
|
+
* Die tweede regel is er omdat "elke interne notitie wekt" te grof is: twee collega's die in het
|
|
116
|
+
* dossier overleggen zouden dan elk een modelbeurt kosten, over iets waar de agent niet bij
|
|
117
|
+
* gevraagd was — en dat vreet het beurtplafond op aan gesprek dat niet voor hem bedoeld was.
|
|
118
|
+
*
|
|
119
|
+
* Een vermelding is precies de vraag die de engine zelf niet kan beantwoorden: *is dit aan míjn
|
|
120
|
+
* agent gericht?* Dezelfde vorm als {@link assignmentMismatch} bij het toewijzen — expliciet, want
|
|
121
|
+
* geraden zou stil het verkeerde doen. En het maakt zelf-wekken onmogelijk: een agent noemt
|
|
122
|
+
* zichzelf niet.
|
|
123
|
+
*/
|
|
124
|
+
export declare function wakesAssignment(activity: Activity, agentId: string): boolean;
|
|
125
|
+
/** Het onderwerp van een opdracht als één verwijzing, of `undefined`. */
|
|
126
|
+
export declare function assignmentSubject(assignment: {
|
|
127
|
+
subjectKind?: string;
|
|
128
|
+
subjectId?: string;
|
|
129
|
+
}): ResourceRef | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* Hoeveel beurten een opdracht mag nemen voordat een mens het overneemt.
|
|
132
|
+
*
|
|
133
|
+
* Niet oneindig, want elke beurt is een modelaanroep en een agent kan met de beste bedoelingen
|
|
134
|
+
* blijven vragen. Bij het plafond escaleert hij, en dat is te zien in de draad — een opdracht die
|
|
135
|
+
* stil ophoudt zou de vraag "waarom doet hij niets meer" onbeantwoordbaar maken.
|
|
136
|
+
*/
|
|
137
|
+
export declare const MAX_ASSIGNMENT_TURNS = 12;
|
|
138
|
+
/**
|
|
139
|
+
* Wat een beurt als volgende zet koos. Dit is wat de control-tools vastleggen.
|
|
140
|
+
*
|
|
141
|
+
* Eén union, want de vier uitkomsten sluiten elkaar uit: je wacht op iets, je bent klaar, of je
|
|
142
|
+
* geeft het over aan een mens.
|
|
143
|
+
*/
|
|
144
|
+
export type AssignmentControl = {
|
|
145
|
+
kind: "wait";
|
|
146
|
+
on: WaitingOn;
|
|
147
|
+
} | {
|
|
148
|
+
kind: "done";
|
|
149
|
+
note?: string;
|
|
150
|
+
} | {
|
|
151
|
+
kind: "escalate";
|
|
152
|
+
reason: string;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Waar de opdracht na deze beurt in verkeert.
|
|
156
|
+
*
|
|
157
|
+
* Puur, zodat de regel op één plek staat en zonder Bridge te testen is — dezelfde vorm als
|
|
158
|
+
* `decideFinalState` voor een run.
|
|
159
|
+
*
|
|
160
|
+
* **Geen control-call betekent escaleren**, niet stil openblijven. Dat is de regel die
|
|
161
|
+
* `decideFinalState` al toepast op een run die wacht zonder geldige reden ("liever luid falen dan
|
|
162
|
+
* stil parkeren"): een agent die zijn beurt afmaakt zonder te zeggen wat hij wil, laat een mens
|
|
163
|
+
* met een opdracht zitten waarvan niemand weet of er nog iets gebeurt.
|
|
164
|
+
*/
|
|
165
|
+
export declare function decideAssignmentState(control: AssignmentControl | undefined, turnsSoFar: number, maxTurns?: number): {
|
|
166
|
+
status: AssignmentStatus;
|
|
167
|
+
waitingOn: WaitingOn | null;
|
|
168
|
+
turns: number;
|
|
169
|
+
reason?: string;
|
|
170
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { InteractionParticipant } from '../../platform/communication';
|
|
2
|
-
import { ActivityType } from '../activity/types';
|
|
2
|
+
import { ActivityType, InteractionStatus } from '../activity/types';
|
|
3
3
|
export interface ActivityPreview {
|
|
4
4
|
activityId: string;
|
|
5
5
|
/** Ook een door een app gedeclareerd type; de union houdt alleen de autocomplete. */
|
|
@@ -77,7 +77,9 @@ export interface Interaction {
|
|
|
77
77
|
*/
|
|
78
78
|
channelUriKey?: string;
|
|
79
79
|
title: string;
|
|
80
|
-
|
|
80
|
+
/** Eén definitie, gedeeld met `INTERACTION_STATUS_CHANGED`, zodat de tijdlijn elke
|
|
81
|
+
* overgang kan vastleggen die dit veld kan maken. */
|
|
82
|
+
status: InteractionStatus;
|
|
81
83
|
/**
|
|
82
84
|
* UX-shape van de interactie. "thread" = email-stijl met aparte replyable
|
|
83
85
|
* berichten (inline reply per activity). "conversation" = chat-stijl met
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './types';
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { OwnerScope } from '../contact/types';
|
|
2
|
+
import { ConditionStep, ForEachStep, LookupStep, ParallelStep, Step } from '../playbook/types';
|
|
3
|
+
/**
|
|
4
|
+
* Een **leesbaan**: wat er meeleest tijdens een levend gesprek, en aan wie het iets toont.
|
|
5
|
+
*
|
|
6
|
+
* **Waarom dit een eigen entity is en geen playbook met een `stream`-trigger.** Dat was het:
|
|
7
|
+
* `PlaybookTrigger` had een arm `{ kind: "stream" }` met opzet zonder velden, en zo'n rij deed
|
|
8
|
+
* daarna niets van wat een playbook doet — geen run, geen job, geen lock, geen goedkeuringspoort,
|
|
9
|
+
* geen `finalizeRun`. `live-assist` bouwde met de hand een `RunContext` en riep `executeFlow`
|
|
10
|
+
* direct aan.
|
|
11
|
+
*
|
|
12
|
+
* De prijs stond in de velden: `autonomy`, `agentId`, `procedure`, `stats`, `lastRunAt` en
|
|
13
|
+
* `debounceMs` waren voor zo'n rij allemaal betekenisloos, en `steps` mocht maar vier van de tien
|
|
14
|
+
* staptypes bevatten. Iedere lezer van `Playbook` moest dus impliciet weten of hij naar een
|
|
15
|
+
* automatisering of naar een leesbaan keek, met twee functies in domain als vangnet en een
|
|
16
|
+
* tabel-scan-plus-cache als selectie.
|
|
17
|
+
*
|
|
18
|
+
* Definities horen gescheiden te zijn naar hun **runtime**, niet naar hun editor. Een leesbaan
|
|
19
|
+
* heeft geen run, dus is het geen playbook.
|
|
20
|
+
*
|
|
21
|
+
* Wat hij deelt met een playbook is de **staptaal** en de executor — niet de tabel.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Wat een leesbaan mag doen: opzoeken, kiezen, en dat desnoods parallel of per item.
|
|
25
|
+
*
|
|
26
|
+
* Dit is een **echt subtype** van {@link Step} en geen lijst met toegestane namen. Alles wat
|
|
27
|
+
* schrijft (`action`), een model kost (`classify`, `generate`, `agent`) of kan pauzeren
|
|
28
|
+
* (`wait-for-*`) valt erbuiten — en pauzeren kán hier ook niet, want er is geen rij om op te
|
|
29
|
+
* hervatten.
|
|
30
|
+
*
|
|
31
|
+
* Dat het een type is en geen controle is de winst: een leesbaan die zou schrijven is nu een
|
|
32
|
+
* typefout bij het bouwen, in plaats van een validatie die pas bij het opslaan (of erger: bij de
|
|
33
|
+
* eerste ronde, tijdens een telefoongesprek) iets zegt.
|
|
34
|
+
*
|
|
35
|
+
* Wie tijdens een gesprek iets wíl laten schrijven, doet dat met een playbook op een
|
|
36
|
+
* `activity`-trigger. Die heeft een run, een eigenaar en een goedkeuringspoort.
|
|
37
|
+
*/
|
|
38
|
+
export type ReadStep = LookupStep | ConditionStep | ForEachStep<ReadStep> | ParallelStep<ReadStep>;
|
|
39
|
+
/** De staptypes die een leesbaan mag bevatten — de runtime-tegenhanger van {@link ReadStep}. */
|
|
40
|
+
export declare const READ_STEP_TYPES: readonly string[];
|
|
41
|
+
export interface LiveLens {
|
|
42
|
+
id: string;
|
|
43
|
+
organizationId: string;
|
|
44
|
+
/** Voor wie deze baan loopt. De werkmodus selecteert de team-banen; zie {@link selectLenses}. */
|
|
45
|
+
ownerScope: OwnerScope;
|
|
46
|
+
name: string;
|
|
47
|
+
description?: string;
|
|
48
|
+
enabled: boolean;
|
|
49
|
+
/** Wat er opgezocht wordt. Alleen lezen — zie {@link ReadStep}. */
|
|
50
|
+
steps: ReadStep[];
|
|
51
|
+
createdBy: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Waarom deze stappenlijst geen leesbaan mag zijn, of `null` als hij het mag.
|
|
55
|
+
*
|
|
56
|
+
* Nodig ondanks {@link ReadStep}, want een `POST` levert JSON en daar helpt een type niet: dit is
|
|
57
|
+
* de poort bij het **opslaan**. Hij draaide voorheen bij élke ronde, elke acht seconden per lopend
|
|
58
|
+
* gesprek, om een eigenschap te controleren die bij het opslaan al vaststond.
|
|
59
|
+
*
|
|
60
|
+
* Een reden en geen boolean, omdat een geweigerde baan anders stil niets doet — precies de klasse
|
|
61
|
+
* fout die "ik heb hem aangezet en er komt niets" onbeantwoordbaar maakt.
|
|
62
|
+
*/
|
|
63
|
+
export declare function readStepError(steps: readonly Step[]): string | null;
|
|
64
|
+
/**
|
|
65
|
+
* De leesbanen die bij déze medewerker op dít moment horen.
|
|
66
|
+
*
|
|
67
|
+
* De werkmodus is wat een team-baan selecteert: zonder die keuze zouden bij iemand die in Sales
|
|
68
|
+
* én Support zit beide baansets tegelijk meelezen — het probleem waarvoor de werkmodus bestaat.
|
|
69
|
+
* Persoonlijke en org-brede banen staan er los van.
|
|
70
|
+
*
|
|
71
|
+
* Merk op dat de *acting identity* van een ronde altijd de medewerker zelf is, ook bij een team-
|
|
72
|
+
* of org-brede baan: hij ziet tijdens zijn eigen gesprek nooit meer dan hij mag zien. De eigenaar
|
|
73
|
+
* bepaalt hier alleen wélke banen er lopen.
|
|
74
|
+
*
|
|
75
|
+
* Geen `skipped`-uitkomst meer: die bestond om een baan te melden die niet mocht meelezen, en dat
|
|
76
|
+
* kan niet meer bestaan — `readStepError` weigert hem bij het opslaan.
|
|
77
|
+
*/
|
|
78
|
+
export declare function selectLenses<T extends Pick<LiveLens, "enabled" | "ownerScope">>(lenses: readonly T[], lens: {
|
|
79
|
+
userId: string;
|
|
80
|
+
teamId?: string;
|
|
81
|
+
}): T[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -9,6 +9,26 @@ import { OwnerScope } from '../contact/types';
|
|
|
9
9
|
* functie is die vertaling, en de enige plek waar hij hoort.
|
|
10
10
|
*/
|
|
11
11
|
export declare function playbookActor(scope: OwnerScope): ActingIdentity;
|
|
12
|
+
/**
|
|
13
|
+
* Namens wie deze run handelt.
|
|
14
|
+
*
|
|
15
|
+
* **Twee verschillende vragen, en dat is de hele reden dat deze functie naast
|
|
16
|
+
* {@link playbookActor} bestaat:**
|
|
17
|
+
*
|
|
18
|
+
* - *wie handelt* — de agent, als er één is aangewezen;
|
|
19
|
+
* - *wie mag dit beheren* — `ownerScope`, en dat blijft van mensen.
|
|
20
|
+
*
|
|
21
|
+
* Die twee op één veld laten leunen leek aantrekkelijk, want een agent is een gebruiker en
|
|
22
|
+
* `ownerScope: { kind: "personal", userId }` levert precies de juiste actor op. Maar
|
|
23
|
+
* `ownerScope` bepaalt óók wie mag bewerken, en dan kon geen enkel mens de playbook van een
|
|
24
|
+
* agent nog aanpassen — de agent zelf logt immers nooit in.
|
|
25
|
+
*
|
|
26
|
+
* Zonder `agentId` verandert er niets: dan is de actor die van de scope, precies zoals eerst.
|
|
27
|
+
*/
|
|
28
|
+
export declare function runActor(playbook: {
|
|
29
|
+
agentId?: string | null;
|
|
30
|
+
ownerScope: OwnerScope;
|
|
31
|
+
}): ActingIdentity;
|
|
12
32
|
/**
|
|
13
33
|
* Stabiele sleutel om actors te groeperen. Tien playbooks van hetzelfde team horen
|
|
14
34
|
* één autorisatie-call te kosten, niet tien.
|