@opencxh/domain 1.153.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.
- package/dist/entities/activity/catalog.d.ts +23 -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 +142 -0
- package/dist/entities/assignment/types.test.d.ts +1 -0
- 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 +439 -31
- 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 +1150 -642
- package/dist/platform/ai-tools.d.ts +20 -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/provider.d.ts +14 -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
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ActingIdentity } from '../../platform/identity';
|
|
2
|
+
import { ResourceRef } from '../../platform/resource';
|
|
2
3
|
import { OwnerScope } from '../contact/types';
|
|
3
4
|
/**
|
|
4
|
-
* Playbooks — event-driven automation
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Playbooks — event-driven automation met AI-stappen. Zie docs/PLAYBOOKS.md.
|
|
6
|
+
*
|
|
7
|
+
* Twee uitvoeringsvormen, één contract: zie {@link Decider}. Alle staptypes in
|
|
8
|
+
* {@link Step} worden uitgevoerd; er is geen soort meer die de executor weigert.
|
|
7
9
|
*/
|
|
8
10
|
export type Autonomy = "suggest" | "auto";
|
|
9
11
|
export type PlaybookTrigger = {
|
|
@@ -29,11 +31,43 @@ export type PlaybookTrigger = {
|
|
|
29
31
|
debounceMs?: number;
|
|
30
32
|
} | {
|
|
31
33
|
kind: "manual";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Iemand wijst werk aan de agent van deze playbook toe — de wekker van een **opdracht**.
|
|
37
|
+
*
|
|
38
|
+
* Geen nieuw mechanisme: een toewijzing is al een activity, dus dezelfde poort levert hem af.
|
|
39
|
+
* Wat deze soort toevoegt is de vraag die de engine niet zelf kan beantwoorden — *is dit aan
|
|
40
|
+
* míjn agent?* — en het antwoord staat in `Playbook.agentId`, niet hier. Eén plek die de
|
|
41
|
+
* agent benoemt, want dat veld bepaalt óók namens wie de run handelt; zou het hier nóg een
|
|
42
|
+
* keer staan, dan kon een playbook op de toewijzing aan de één reageren namens de ander.
|
|
43
|
+
*
|
|
44
|
+
* Wélke soorten werk toegewezen kunnen worden is **gedeclareerd** door de app die ze bezit
|
|
45
|
+
* (`assignment-source`-federatie, zie `./assignment.ts`) en staat daarom als losse id in
|
|
46
|
+
* `targetKind` in plaats van als union hier.
|
|
47
|
+
*/
|
|
48
|
+
| {
|
|
49
|
+
kind: "assignment";
|
|
50
|
+
targetKind: string;
|
|
32
51
|
};
|
|
33
52
|
export interface Guardrails {
|
|
34
53
|
maxSteps?: number;
|
|
35
54
|
maxToolCalls?: number;
|
|
36
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Grenzen voor `maxTokens` op een AI-stap. De bovengrens is dezelfde als die van
|
|
58
|
+
* `/generate`: geen enkele prompt hier heeft meer output nodig, en een op hol
|
|
59
|
+
* geslagen run mag er niet voor betalen. De ondergrens houdt een typfout ("5")
|
|
60
|
+
* tegen die elk antwoord halverwege een woord afkapt.
|
|
61
|
+
*/
|
|
62
|
+
export declare const STEP_MAX_TOKENS_MIN = 64;
|
|
63
|
+
export declare const STEP_MAX_TOKENS_MAX = 8000;
|
|
64
|
+
/**
|
|
65
|
+
* `maxTokens` van een stap naar een bruikbare waarde, of `undefined` als er niets
|
|
66
|
+
* (bruikbaars) staat. Neemt ook strings aan, want de editor levert het veld als
|
|
67
|
+
* tekst op (`<input type="number">`) en een string in `max_tokens` is bij OpenAI
|
|
68
|
+
* en Anthropic een 400.
|
|
69
|
+
*/
|
|
70
|
+
export declare function clampStepMaxTokens(value: unknown): number | undefined;
|
|
37
71
|
export interface ConditionStep {
|
|
38
72
|
type: "condition";
|
|
39
73
|
/** JSONLogic expression evaluated against the run vars. */
|
|
@@ -41,11 +75,19 @@ export interface ConditionStep {
|
|
|
41
75
|
/** Gate: what to do when the condition is false. "then" = the steps that follow. */
|
|
42
76
|
onFalse: "stop" | "escalate" | "continue";
|
|
43
77
|
}
|
|
44
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Generiek over wat er in de body mag staan, zodat een beperkte staptaal een **echt subtype** kan
|
|
80
|
+
* zijn in plaats van een runtime-regel. Zie `ReadStep` in `../live-lens/types`: die laat hier
|
|
81
|
+
* alleen leesbare stappen in, en dan is "een leesbaan kan niet schrijven" een typefout in plaats
|
|
82
|
+
* van een controle die iemand kan vergeten aan te roepen.
|
|
83
|
+
*
|
|
84
|
+
* De default houdt elk bestaand gebruik (`ForEachStep` zonder parameter) ongewijzigd.
|
|
85
|
+
*/
|
|
86
|
+
export interface ForEachStep<S = Step> {
|
|
45
87
|
type: "for-each";
|
|
46
88
|
in: string;
|
|
47
89
|
as: string;
|
|
48
|
-
body:
|
|
90
|
+
body: S[];
|
|
49
91
|
}
|
|
50
92
|
export interface LookupStep {
|
|
51
93
|
type: "lookup";
|
|
@@ -60,13 +102,47 @@ export interface ActionStep {
|
|
|
60
102
|
action: string;
|
|
61
103
|
params: Record<string, unknown>;
|
|
62
104
|
autonomy?: Autonomy;
|
|
105
|
+
/**
|
|
106
|
+
* Var waarin het resultaat van de actie landt, als je het nodig hebt.
|
|
107
|
+
*
|
|
108
|
+
* Bestond niet, en daardoor was er geen manier om te wachten op iets dat je zelf net had
|
|
109
|
+
* aangemaakt: een `create_task` kon haar id nergens laten, dus `waitingOn: { on: "task" }` was
|
|
110
|
+
* niet in te gaan. Dezelfde vorm als `LookupStep.as`, en dezelfde parsing — twee antwoorden op
|
|
111
|
+
* "wat ís het resultaat van een tool" zou de volgende duplicatie zijn.
|
|
112
|
+
*
|
|
113
|
+
* Onder autonomie `suggest` wordt de actie vastgehouden en draait ze pas na goedkeuring; het
|
|
114
|
+
* resultaat landt dan bij het hervatten. Tot dat moment bestaat de var niet, en een stap die
|
|
115
|
+
* er dan al naar verwijst faalt luid (zie `engine/utils.ts`) in plaats van met leegte verder
|
|
116
|
+
* te gaan.
|
|
117
|
+
*/
|
|
118
|
+
as?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Wacht tot deze taak af is.
|
|
122
|
+
*
|
|
123
|
+
* De tegenhanger van `wait-for-reply`, voor het geval uit de support-procedure: "moet een
|
|
124
|
+
* collega iets doen, maak een taak en wacht tot die af is". `taskId` is een gewone verwijzing,
|
|
125
|
+
* dus `$newTask.id` na een `create_task` met een `as`.
|
|
126
|
+
*/
|
|
127
|
+
export interface WaitForTaskStep {
|
|
128
|
+
type: "wait-for-task";
|
|
129
|
+
/** `$ref` of letterlijk id van de taak om op te wachten. */
|
|
130
|
+
taskId: string;
|
|
63
131
|
}
|
|
64
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* Een enkele classificatie met gestructureerde uitvoer.
|
|
134
|
+
*
|
|
135
|
+
* **`profileId` en niet `accountId` + `model`.** Dit was de enige AI-stap die zijn eigen account
|
|
136
|
+
* en model droeg, terwijl de kernkeuze van dit systeem is dat een `AIProfile` het herbruikbare
|
|
137
|
+
* brein is en AI-stappen daarnaar verwijzen (`docs/PLAYBOOKS.md` §2). Wat die uitzondering kostte:
|
|
138
|
+
* sjablonen hadden `$default`/`$defaultModel`-placeholders nodig die de installer moest
|
|
139
|
+
* vervangen, en een modelwissel raakte elke classify-stap van elke playbook afzonderlijk.
|
|
140
|
+
*/
|
|
65
141
|
export interface ClassifyStep {
|
|
66
142
|
type: "classify";
|
|
67
143
|
as: string;
|
|
68
|
-
|
|
69
|
-
|
|
144
|
+
/** Het brein dat classificeert. Een goedkoop, snel profiel is hier de bedoeling. */
|
|
145
|
+
profileId: string;
|
|
70
146
|
mode: "topics" | "question" | "extract";
|
|
71
147
|
topicIds?: string[];
|
|
72
148
|
question?: string;
|
|
@@ -81,6 +157,16 @@ export interface ClassifyStep {
|
|
|
81
157
|
* eerdere `lookup` heeft opgehaald, zoals de berichten van het gesprek.
|
|
82
158
|
*/
|
|
83
159
|
input?: string;
|
|
160
|
+
/**
|
|
161
|
+
* Plafond op de output van deze stap, per model-call. Leeg = het
|
|
162
|
+
* `providerConfig` van het account/profiel, en anders de vendor-default.
|
|
163
|
+
*
|
|
164
|
+
* Bewust naast `guardrails` en niet erin: `maxSteps`/`maxToolCalls` begrenzen de
|
|
165
|
+
* hele run, dit geldt per call. In dezelfde bak zou het lezen als "totaalbudget
|
|
166
|
+
* voor deze stap", en dat is het niet — een agent-loop van vijf turns mag vijf
|
|
167
|
+
* keer tot dit plafond komen.
|
|
168
|
+
*/
|
|
169
|
+
maxTokens?: number;
|
|
84
170
|
}
|
|
85
171
|
export interface GenerateStep {
|
|
86
172
|
type: "generate";
|
|
@@ -88,13 +174,27 @@ export interface GenerateStep {
|
|
|
88
174
|
goal?: string;
|
|
89
175
|
kind: "reply" | "compose" | "note";
|
|
90
176
|
as?: string;
|
|
177
|
+
/** Plafond op de output van deze stap. Zie `ClassifyStep.maxTokens`. */
|
|
178
|
+
maxTokens?: number;
|
|
91
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Een agentische beurt **binnen een flow**.
|
|
182
|
+
*
|
|
183
|
+
* Draagt een {@link Procedure} in plaats van diens velden nóg een keer: dit had
|
|
184
|
+
* `goal`/`toolsOverride`/`guardrails`/`maxTokens` als eigen velden, wat exact dezelfde vijf
|
|
185
|
+
* dingen waren onder twee namen — en `runAgentStep` was een adapter die `goal` op `text` en
|
|
186
|
+
* `toolsOverride` op `tools` afbeeldde. Compositie in plaats van een tweede naamgeving.
|
|
187
|
+
*
|
|
188
|
+
* `profileId` staat hiér en niet in de procedure: een workflow heeft geen agent, dus het brein
|
|
189
|
+
* moet uit de stap komen. Bij een **opdracht** komt het brein van de agent
|
|
190
|
+
* (`User.profileId`) en draagt de procedure er dus geen.
|
|
191
|
+
*/
|
|
92
192
|
export interface AgentStep {
|
|
93
193
|
type: "agent";
|
|
194
|
+
/** Het brein voor deze stap. */
|
|
94
195
|
profileId: string;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
toolsOverride?: string[];
|
|
196
|
+
/** Wat er moet gebeuren, en waarbinnen. */
|
|
197
|
+
procedure: Procedure;
|
|
98
198
|
autonomy?: Autonomy;
|
|
99
199
|
as?: string;
|
|
100
200
|
}
|
|
@@ -102,7 +202,122 @@ export interface WaitForReplyStep {
|
|
|
102
202
|
type: "wait-for-reply";
|
|
103
203
|
deadline?: number;
|
|
104
204
|
}
|
|
105
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Meerdere takken tegelijk, en pas verder als ze allemaal klaar zijn.
|
|
207
|
+
*
|
|
208
|
+
* Bestaat voor één concreet probleem: stappen liepen strikt sequentieel, en drie lookups van
|
|
209
|
+
* elk ~1200 ms achter elkaar passen niet in een cadans van seconden (live assist). Sequentieel
|
|
210
|
+
* kost de som, parallel kost de langzaamste.
|
|
211
|
+
*
|
|
212
|
+
* **Alleen lezen.** Een tak mag niet pauzeren — geen goedkeuring, geen wachten op een antwoord.
|
|
213
|
+
* Dat is geen tijdelijke beperking maar een grens die het begrip eenvoudig houdt: een run die
|
|
214
|
+
* halverwege een fan-out pauzeert zou moeten onthouden welke takken al klaar waren en waar hij
|
|
215
|
+
* verder moet, en dat is een tweede toestandsmachine naast `waitingOn`. Wie iets wil schrijven
|
|
216
|
+
* doet dat in een stap ná de `parallel`.
|
|
217
|
+
*
|
|
218
|
+
* Elke tak schrijft naar zijn eigen `as`-namen; twee takken die dezelfde naam vullen is een
|
|
219
|
+
* fout, want wie er wint hangt dan van de timing af.
|
|
220
|
+
*/
|
|
221
|
+
export interface ParallelStep<S = Step> {
|
|
222
|
+
type: "parallel";
|
|
223
|
+
/** Elke tak is een eigen rijtje stappen. Zie {@link ForEachStep} over de parameter. */
|
|
224
|
+
branches: S[][];
|
|
225
|
+
/**
|
|
226
|
+
* Hoeveel takken er tegelijk mogen lopen. Leeg = alle.
|
|
227
|
+
*
|
|
228
|
+
* Een plafond bestaat omdat een tak een tool-call is: tien takken tegelijk zijn tien
|
|
229
|
+
* gelijktijdige aanroepen naar andere apps.
|
|
230
|
+
*/
|
|
231
|
+
maxConcurrent?: number;
|
|
232
|
+
/**
|
|
233
|
+
* Wat een falende tak betekent. Default `"fail"`: de stap faalt.
|
|
234
|
+
*
|
|
235
|
+
* `"continue"` laat de andere takken staan en gaat door — dat is wat een leesoppervlak wil
|
|
236
|
+
* (één kapotte baan mag de andere twee niet wissen), en precies waarom het een keuze is en
|
|
237
|
+
* geen aanname.
|
|
238
|
+
*/
|
|
239
|
+
onBranchError?: "fail" | "continue";
|
|
240
|
+
}
|
|
241
|
+
export type Step = ConditionStep | ForEachStep | ParallelStep | LookupStep | ActionStep | ClassifyStep | GenerateStep | AgentStep | WaitForReplyStep | WaitForTaskStep;
|
|
242
|
+
/**
|
|
243
|
+
* Een **procedure**: hoe een scenario aangepakt wordt, als prose met guardrails.
|
|
244
|
+
*
|
|
245
|
+
* Dit is de tweede uitvoeringsvorm naast `Step[]`, en {@link AgentStep} is er de
|
|
246
|
+
* variant-binnen-een-flow van (die *bevat* er een, en herhaalt zijn velden niet).
|
|
247
|
+
*
|
|
248
|
+
* **Geen `profileId`.** Dat stond hier, en het was de tweede brein-verwijzing in het systeem:
|
|
249
|
+
* `User.profileId` bestaat al — verplicht bij het aanmaken van een agent, met als doc "het brein
|
|
250
|
+
* van een agent" — en de engine las hem nooit. Twee velden voor één feit, zonder dat iets ze aan
|
|
251
|
+
* elkaar relateerde: `agentId: Alice` met het brein van Bob werd zonder klacht opgeslagen, en de
|
|
252
|
+
* tijdlijn zei dan Alice terwijl het model, de tools en de prompt van Bob waren.
|
|
253
|
+
*
|
|
254
|
+
* Nu is er één antwoord op "met welk brein": bij een opdracht dat van de agent, bij een
|
|
255
|
+
* agent-stap in een workflow dat van de stap. De procedure beschrijft het scenario, niet wie het
|
|
256
|
+
* uitvoert.
|
|
257
|
+
*
|
|
258
|
+
* `tools` is **narrowing-only**: het moet een deelverzameling zijn van `enabledTools` van het
|
|
259
|
+
* brein dat hem uitvoert. Het profiel is de identiteit (één per agent), de procedure het scenario
|
|
260
|
+
* (veel per agent), en een scenario mag nooit méér mogen dan de identiteit die het uitvoert.
|
|
261
|
+
*/
|
|
262
|
+
export interface Procedure {
|
|
263
|
+
/** De prose zelf — wat er moet gebeuren, in de woorden van wie het opschreef. */
|
|
264
|
+
text: string;
|
|
265
|
+
/** Toegestane tools. Narrowing-only t.o.v. `enabledTools` van het brein. */
|
|
266
|
+
tools?: string[];
|
|
267
|
+
guardrails?: Guardrails;
|
|
268
|
+
/** Plafond per beurt. Zie `ClassifyStep.maxTokens`. */
|
|
269
|
+
maxTokens?: number;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Wie kiest de volgende zet.
|
|
273
|
+
*
|
|
274
|
+
* Twee uitvoeringsvormen, één contract. Beide lopen door dezelfde toolruntime en dezelfde
|
|
275
|
+
* goedkeuringspoort; alleen de manier waarop de volgende zet gekozen wordt verschilt:
|
|
276
|
+
*
|
|
277
|
+
* - **workflow** — deterministisch, `Step[]`, gebouwd op de canvas. Routing, triage,
|
|
278
|
+
* achtergrondautomatisering. Een gratis, testbare poort in plaats van een prompt.
|
|
279
|
+
* - **procedure** — prose, een model kiest. Voor werk waarvan de stappen geen takken in een
|
|
280
|
+
* boom zijn (antwoorden *én* een taak maken, of eerst vragen en daarna alsnog antwoorden).
|
|
281
|
+
*
|
|
282
|
+
* Verkeerd om gebruikt faalt elke vorm op zijn eigen manier: een procedure als workflow
|
|
283
|
+
* verspreidt logica over blokken tot het onbeheersbaar is, een workflow als procedure ruilt een
|
|
284
|
+
* testbare conditie voor een onbetrouwbare prompt (en kost een modelaanroep per bericht).
|
|
285
|
+
*/
|
|
286
|
+
export type Decider = {
|
|
287
|
+
kind: "workflow";
|
|
288
|
+
steps: Step[];
|
|
289
|
+
} | {
|
|
290
|
+
kind: "procedure";
|
|
291
|
+
procedure: Procedure;
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* **Eén veld, met de soort erin.** Dit was een paar losse kolommen — `steps: Step[]` naast
|
|
295
|
+
* `procedure?: Procedure | null` — met een functie (`deciderOf`) die er een union van maakte
|
|
296
|
+
* volgens de regel "procedure aanwezig ⇒ procedure".
|
|
297
|
+
*
|
|
298
|
+
* Wat die vorm kostte:
|
|
299
|
+
*
|
|
300
|
+
* - een rij met **beide** gevuld was representeerbaar, en betekende stil "de steps zijn dood";
|
|
301
|
+
* - elk schrijfpad moest de onuitgesproken regel kennen: `crud/update.ts` moest expliciet `null`
|
|
302
|
+
* schrijven om "de procedure eruit halen" te laten werken, en `run-playbook.ts` had een
|
|
303
|
+
* conditionele spread om de kolom weg te laten;
|
|
304
|
+
* - de frontend had de regel nóg een keer (`!!pb.procedure` als soort-filter);
|
|
305
|
+
* - en het is al een keer stil fout gegaan: `fromView` droeg `procedure` niet mee, waardoor élke
|
|
306
|
+
* procedure die je opende en opsloeg zichzelf tot een lege workflow maakte.
|
|
307
|
+
*
|
|
308
|
+
* Met `kind` in de kolom is de soort een feit in plaats van een gevolgtrekking, en kan er geen
|
|
309
|
+
* derde toestand bestaan. De editor houdt zijn platte vorm — dat is wat `toView`/`fromView` doen.
|
|
310
|
+
*/
|
|
311
|
+
export declare const EMPTY_WORKFLOW: Decider;
|
|
312
|
+
/**
|
|
313
|
+
* De stappen van deze decider, of een lege lijst als het een procedure is.
|
|
314
|
+
*
|
|
315
|
+
* Twee lezers-helpers en géén `deciderOf` terug: het verschil is dat deze de soort *lezen* in
|
|
316
|
+
* plaats van hem te *raden* uit welke velden gevuld zijn.
|
|
317
|
+
*/
|
|
318
|
+
export declare function stepsOf(decider: Decider | undefined): Step[];
|
|
319
|
+
/** De procedure van deze decider, of `undefined` als het een workflow is. */
|
|
320
|
+
export declare function procedureOf(decider: Decider | undefined): Procedure | undefined;
|
|
106
321
|
export interface Playbook {
|
|
107
322
|
id: string;
|
|
108
323
|
organizationId: string;
|
|
@@ -112,7 +327,20 @@ export interface Playbook {
|
|
|
112
327
|
enabled: boolean;
|
|
113
328
|
autonomy: Autonomy;
|
|
114
329
|
trigger: PlaybookTrigger;
|
|
115
|
-
|
|
330
|
+
/** Wie de volgende zet kiest: stappen of prose. Zie {@link Decider}. */
|
|
331
|
+
decider: Decider;
|
|
332
|
+
/**
|
|
333
|
+
* De agent die dit uitvoert: het `userId` van een gebruiker met `type: "agent"`.
|
|
334
|
+
*
|
|
335
|
+
* Bepaalt **namens wie** de run handelt (`runActor`), en daarmee: wiens naam er in de tijdlijn
|
|
336
|
+
* staat, welke interacties hij mag raken, en van wiens budget het afgaat. Bewust náást
|
|
337
|
+
* `ownerScope` en niet erin — dat veld bepaalt wie de playbook mag *beheren*, en dat blijven
|
|
338
|
+
* mensen. Een agent logt nooit in, dus als beide op één veld leunden kon niemand hem meer
|
|
339
|
+
* aanpassen.
|
|
340
|
+
*
|
|
341
|
+
* Leeg = de actor volgt de scope, precies zoals voorheen.
|
|
342
|
+
*/
|
|
343
|
+
agentId?: string | null;
|
|
116
344
|
/** Bumped on every change; runs pin to the version they started on. */
|
|
117
345
|
version: number;
|
|
118
346
|
/** Actor of autonomous actions. */
|
|
@@ -129,19 +357,106 @@ export interface Playbook {
|
|
|
129
357
|
* de `PLAYBOOK_STARTED`-activity dekt "hij is begonnen" al. (Die status bestond,
|
|
130
358
|
* werd nooit geproduceerd, en had wél een label in de UI.)
|
|
131
359
|
*/
|
|
132
|
-
export type RunStatus = "running" | "
|
|
360
|
+
export type RunStatus = "running" | "waiting" | "done" | "escalated" | "failed" | "stopped";
|
|
361
|
+
/**
|
|
362
|
+
* Waaróp een wachtende run wacht.
|
|
363
|
+
*
|
|
364
|
+
* Dit was eerder statusinformatie: `awaiting_approval`, `awaiting_reply` en `timed_out` waren
|
|
365
|
+
* drie statussen die alle drie "wacht op X" betekenden, en de reden zat in de naam. Daardoor
|
|
366
|
+
* groeide de statusset met elke nieuwe reden mee — een run die op een taak wacht zou
|
|
367
|
+
* `awaiting_task` hebben gevraagd, een run die op een moment wacht `awaiting_time`, en dan
|
|
368
|
+
* moest elke lezer van `status` opnieuw worden bijgewerkt.
|
|
369
|
+
*
|
|
370
|
+
* De reden van het wachten is **data**, geen status. `status: "waiting"` zegt dát er gewacht
|
|
371
|
+
* wordt; dit veld zegt waarop, en wie het signaal levert leest alleen dit.
|
|
372
|
+
*
|
|
373
|
+
* `timed_out` staat er niet bij: een verstreken deadline is geen manier van wachten maar een
|
|
374
|
+
* uitkomst, en landt via `decideFinalState` op een eindstand (zie {@link TerminalLifecycle}).
|
|
375
|
+
*
|
|
376
|
+
* Er is ook geen `{ on: "time" }`. Die stond hier, zonder dat iets hem schreef of las: het
|
|
377
|
+
* wachten-op-een-moment dat wél bestaat is de timeout-job die bij `{ on: "reply" }` wordt
|
|
378
|
+
* ingeplanned, en die leest de deadline uit de job en niet uit dit veld. Een lid dat door niets
|
|
379
|
+
* geproduceerd wordt is een belofte aan elke lezer die hem moet afhandelen.
|
|
380
|
+
*/
|
|
381
|
+
export type WaitingOn = {
|
|
382
|
+
on: "approval";
|
|
383
|
+
}
|
|
384
|
+
/** De klant antwoordt, of een collega beantwoordt de interne vraag van de run. */
|
|
385
|
+
| {
|
|
386
|
+
on: "reply";
|
|
387
|
+
interactionId: string;
|
|
388
|
+
} | {
|
|
389
|
+
on: "task";
|
|
390
|
+
taskId: string;
|
|
391
|
+
};
|
|
133
392
|
/** Eindstanden: hier komt een run niet meer vanzelf uit. */
|
|
134
|
-
export declare const TERMINAL_RUN_STATUSES: readonly ["done", "escalated", "failed", "
|
|
135
|
-
/**
|
|
136
|
-
|
|
393
|
+
export declare const TERMINAL_RUN_STATUSES: readonly ["done", "escalated", "failed", "stopped"];
|
|
394
|
+
/**
|
|
395
|
+
* **Tweede vocabulaire, expliciet.** Waarom een run eindigde, zoals de tijdlijn het benoemt —
|
|
396
|
+
* niet hetzelfde als de status die op de run staat.
|
|
397
|
+
*
|
|
398
|
+
* Twee redenen zijn geen `RunStatus`, en dat is geen omissie:
|
|
399
|
+
*
|
|
400
|
+
* - **`rejected`** — een afgewezen voorstel landt als status `"stopped"`, maar de tijdlijn moet
|
|
401
|
+
* "afgewezen" kunnen zeggen.
|
|
402
|
+
* - **`timed_out`** — een run waarvan de deadline verstreek landt als `"escalated"` (er moet een
|
|
403
|
+
* mens iets mee), maar "geen antwoord binnen de deadline" is een andere mededeling dan
|
|
404
|
+
* "geëscaleerd". Dit was eerder een eigen status; hij is verhuisd naar dit vocabulaire, want
|
|
405
|
+
* het is een *reden* en geen toestand waar een run in kan verkeren.
|
|
406
|
+
*
|
|
407
|
+
* Dat dit vocabulaire rijker is dan de statusset is precies waarom het apart bestaat: de
|
|
408
|
+
* tijdlijn vertelt een mens wát er gebeurde, `status` vertelt de machine wat er nog te doen is.
|
|
409
|
+
*/
|
|
410
|
+
export type TerminalLifecycle = RunStatus | "rejected" | "timed_out";
|
|
411
|
+
/**
|
|
412
|
+
* Is deze run klaar — en daarmee ook: mag hij opnieuw gedraaid worden?
|
|
413
|
+
*
|
|
414
|
+
* Die tweede vraag had een eigen functie (`isRetryable`) die niets anders deed dan deze
|
|
415
|
+
* aanroepen. Twee namen voor één regel betekent dat een lezer moet uitzoeken of er een verschil
|
|
416
|
+
* is; dat er geen was, was niet te zien zonder de body te openen.
|
|
417
|
+
*
|
|
418
|
+
* De regel zelf staat hier dus één keer: een retry mag op precies de eindstanden. Een lopende of
|
|
419
|
+
* mens-gepauzeerde run blijft met rust, zodat een retry nooit over live uitvoering heen loopt of
|
|
420
|
+
* een openstaand voorstel overschrijft.
|
|
421
|
+
*/
|
|
137
422
|
export declare function isTerminal(status: RunStatus | string): boolean;
|
|
138
423
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
424
|
+
* Wacht deze run op iets externs?
|
|
425
|
+
*
|
|
426
|
+
* Eén statusvergelijking en niet meer een lijst: er was een `PAUSED_RUN_STATUSES` met twee
|
|
427
|
+
* leden omdat de reden van het wachten ín de status zat. Nu staat de reden in
|
|
428
|
+
* {@link WaitingOn} en is "wacht" één toestand — dus een nieuwe reden (een taak, een moment)
|
|
429
|
+
* verandert deze functie niet meer.
|
|
142
430
|
*/
|
|
143
|
-
export declare function isRetryable(status: RunStatus | string): boolean;
|
|
144
431
|
export declare function isPaused(status: RunStatus | string): boolean;
|
|
432
|
+
/**
|
|
433
|
+
* Loopt deze run nog — mag `finalizeRun` er een uitkomst over schrijven?
|
|
434
|
+
*
|
|
435
|
+
* "In de lucht" is precies "niet in een eindstand": `running` of `waiting`. De lock-retry in
|
|
436
|
+
* `jobs/context.ts` herschedulet tot vijf keer, dus zonder deze check kan een late job met een
|
|
437
|
+
* verouderde uitkomst over een al afgeronde run schrijven.
|
|
438
|
+
*/
|
|
439
|
+
export declare function isInFlight(status: RunStatus | string): boolean;
|
|
440
|
+
/**
|
|
441
|
+
* Het onderwerp van een run als één verwijzing, of `undefined` als hij er geen heeft.
|
|
442
|
+
*
|
|
443
|
+
* Zo'n run bestaat: een org-brede playbook die een rollup doet heeft geen resource om over te
|
|
444
|
+
* gaan. Dat is een geldige toestand en geen ontbrekend veld.
|
|
445
|
+
*/
|
|
446
|
+
export declare function subjectOf(run: {
|
|
447
|
+
subjectKind?: string;
|
|
448
|
+
subjectId?: string;
|
|
449
|
+
}): ResourceRef | undefined;
|
|
450
|
+
/** De scope-sleutel van het onderwerp, klaar voor `authorizeScope`. */
|
|
451
|
+
export declare function subjectKeyOf(run: {
|
|
452
|
+
subjectKind?: string;
|
|
453
|
+
subjectId?: string;
|
|
454
|
+
}): string | undefined;
|
|
455
|
+
/** Het interactie-id van deze run, als zijn onderwerp een gesprek is. */
|
|
456
|
+
export declare function runInteractionId(run: {
|
|
457
|
+
subjectKind?: string;
|
|
458
|
+
subjectId?: string;
|
|
459
|
+
}): string | undefined;
|
|
145
460
|
export interface RunStepTrace {
|
|
146
461
|
path: string;
|
|
147
462
|
type: string;
|
|
@@ -149,22 +464,83 @@ export interface RunStepTrace {
|
|
|
149
464
|
note?: string;
|
|
150
465
|
ms?: number;
|
|
151
466
|
}
|
|
467
|
+
/**
|
|
468
|
+
* Wat deze run in beweging zette.
|
|
469
|
+
*
|
|
470
|
+
* Was `createdBy: string`, en dat veld droeg de auteur van de **playbook** — niet wie de run
|
|
471
|
+
* startte. Dus "wie heeft dit gedaan" had geen antwoord, terwijl `run/start.ts` het userId van de
|
|
472
|
+
* mens die op start drukte al meestuurde in de job-data, waar niemand het las.
|
|
473
|
+
*/
|
|
474
|
+
export type StartedBy =
|
|
475
|
+
/** Een mens drukte op start (`POST /playbook-run/start`). */
|
|
476
|
+
{
|
|
477
|
+
kind: "user";
|
|
478
|
+
id: string;
|
|
479
|
+
}
|
|
480
|
+
/** De trigger vuurde: een activity, een toewijzing, een afgeronde taak. */
|
|
481
|
+
| {
|
|
482
|
+
kind: "trigger";
|
|
483
|
+
id?: string;
|
|
484
|
+
};
|
|
152
485
|
export interface PlaybookRun {
|
|
153
486
|
id: string;
|
|
154
487
|
organizationId: string;
|
|
155
488
|
playbookId: string;
|
|
156
489
|
playbookVersion: number;
|
|
157
|
-
|
|
490
|
+
/**
|
|
491
|
+
* De opdracht waarvan dit een **beurt** is, als er een is.
|
|
492
|
+
*
|
|
493
|
+
* Afwezig = een losstaande uitvoering (een automatisering die vuurt en klaar is). Aanwezig = één
|
|
494
|
+
* zet in werk dat langer leeft dan deze run, met een draad als geheugen.
|
|
495
|
+
*/
|
|
496
|
+
assignmentId?: string;
|
|
497
|
+
/**
|
|
498
|
+
* Waar deze run **over gaat**, in twee platte kolommen.
|
|
499
|
+
*
|
|
500
|
+
* Dit was `interactionId?: string`, en dat leek onschuldig — het veld was immers optioneel. Maar
|
|
501
|
+
* vier paden leunden er zwijgend op alsof het verplicht was: goedkeuren gooide `400` zonder
|
|
502
|
+
* interactie, de lijst filterde op `audience` (leeg voor een org-actor, dus onvindbaar), de
|
|
503
|
+
* tijdlijn deed niets, en de taak-wekker eiste een gesprek. Precies het geval waar de
|
|
504
|
+
* toewijs-federatie voor bestaat — werk dat géén gesprek is — viel dus in dat gat.
|
|
505
|
+
*
|
|
506
|
+
* **Twee kolommen en geen genest object**, om dezelfde reden als {@link WaitingOn} zijn
|
|
507
|
+
* `waitingOnKind` heeft: de store kan niet in een genest object zoeken, en hier moet op gezocht
|
|
508
|
+
* worden (de runs van dit gesprek, de runs van deze taak). `subjectOf` maakt er een
|
|
509
|
+
* {@link ResourceRef} van waar je hem als geheel nodig hebt.
|
|
510
|
+
*/
|
|
511
|
+
subjectKind?: string;
|
|
512
|
+
subjectId?: string;
|
|
158
513
|
status: RunStatus;
|
|
514
|
+
/**
|
|
515
|
+
* De aanleiding: wélk signaal deze run startte, plus de invoer zoals die er tóen uitzag.
|
|
516
|
+
*
|
|
517
|
+
* **`vars` hier is niet hetzelfde als `vars.trigger` hieronder, en dat is met opzet.** Dit veld
|
|
518
|
+
* is de *onveranderlijke invoer*; `vars` is de *werkkopie* die tijdens de run muteert — stappen
|
|
519
|
+
* schrijven erin, en resume-on-reply overschrijft `vars.trigger` met het nieuwe bericht. Een
|
|
520
|
+
* retry moet schoon herrekenen vanaf het oorspronkelijke signaal, en dat kan alleen als dat
|
|
521
|
+
* signaal ergens bewaard is gebleven.
|
|
522
|
+
*
|
|
523
|
+
* Het veld heette `event`, wat suggereerde dat het de rauwe activity was; het zijn de
|
|
524
|
+
* trigger-vars. Dezelfde vorm als `vars.trigger` betekent hier dus niet dezelfde betekenis.
|
|
525
|
+
*/
|
|
159
526
|
trigger: {
|
|
160
527
|
activityType?: string;
|
|
161
528
|
activityId?: string;
|
|
162
|
-
|
|
529
|
+
vars: Record<string, unknown>;
|
|
163
530
|
};
|
|
164
531
|
vars: Record<string, unknown>;
|
|
165
532
|
trace: RunStepTrace[];
|
|
166
|
-
/**
|
|
167
|
-
|
|
533
|
+
/**
|
|
534
|
+
* De uitvoeringsvorm, vastgepind bij de start: de playbook bijstellen mag een lopende of
|
|
535
|
+
* geparkeerde run niet halverwege van gedrag of opdracht laten wisselen (docs 11.4).
|
|
536
|
+
*/
|
|
537
|
+
decider: Decider;
|
|
538
|
+
/**
|
|
539
|
+
* De agent die deze run uitvoert, vastgepind — en daarmee ook **met welk brein**: dat is
|
|
540
|
+
* `User.profileId` van deze agent. Afwezig bij een workflow zonder agent; dan draagt een
|
|
541
|
+
* agent-stap zijn eigen `profileId`.
|
|
542
|
+
*/
|
|
543
|
+
agentId?: string | null;
|
|
168
544
|
/**
|
|
169
545
|
* Namens wie deze run handelt, vastgepind bij de start — net als `steps`. Anders
|
|
170
546
|
* wisselt een lopende of geparkeerde run stilletjes van identiteit zodra iemand de
|
|
@@ -180,19 +556,51 @@ export interface PlaybookRun {
|
|
|
180
556
|
pending?: {
|
|
181
557
|
action: string;
|
|
182
558
|
params: Record<string, unknown>;
|
|
559
|
+
as?: string;
|
|
183
560
|
}[] | null;
|
|
184
561
|
/** The AI_ACTION_PROPOSED activity created for the current pending batch (for resolve on approve/reject). */
|
|
185
562
|
proposalActivityId?: string | null;
|
|
186
563
|
/**
|
|
187
|
-
*
|
|
188
|
-
*
|
|
564
|
+
* Waarop deze run wacht, als `status === "waiting"`. `null` wanneer het veld gewist is (de
|
|
565
|
+
* store schrijft `null`), en afwezig bij een run die niet wacht.
|
|
566
|
+
*
|
|
567
|
+
* Vervangt de drie `awaiting_*`/`timed_out`-statussen: de reden van het wachten is data, dus
|
|
568
|
+
* een nieuwe reden kost een lid in {@link WaitingOn} en niet een status die elke lezer moet
|
|
569
|
+
* kennen.
|
|
570
|
+
*/
|
|
571
|
+
waitingOn?: WaitingOn | null;
|
|
572
|
+
/**
|
|
573
|
+
* De **soort** van {@link WaitingOn}, als platte kolom — puur om op te kunnen queryen.
|
|
574
|
+
*
|
|
575
|
+
* `waitingOn` is een genest object en de store kan daar niet in zoeken, dus elke wekker deed
|
|
576
|
+
* `status: "waiting"` en filterde daarna in het geheugen op `run.waitingOn?.on`
|
|
577
|
+
* (`jobs/run-playbook.ts`, `triggers/from_tasks.ts`). Dat is goedkoop bij tien wachtende runs
|
|
578
|
+
* en niet bij tienduizend. Afgeleid en op één plek geschreven (`finalizeRun`), zodat hij niet
|
|
579
|
+
* uit de pas kan lopen met het object ernaast.
|
|
580
|
+
*/
|
|
581
|
+
waitingOnKind?: WaitingOn["on"] | null;
|
|
582
|
+
/**
|
|
583
|
+
* Index van de stap waarop de flow pauzeerde — voor elke vorm van wachten.
|
|
584
|
+
* (Was `resumeIndex` naast `pending.stepIndex`: twee velden voor
|
|
189
585
|
* hetzelfde feit, in twee takken geschreven en in twee takken gelezen.)
|
|
586
|
+
*
|
|
587
|
+
* Heette `pausedAt`, wat een tijdstip suggereerde tussen velden die dat écht zijn
|
|
588
|
+
* (`lastStepAt`, `lastRunAt`, `deadline`, `until`). Het is een stap-index.
|
|
190
589
|
*/
|
|
191
|
-
|
|
590
|
+
resumeAtStep?: number | null;
|
|
192
591
|
rounds?: number;
|
|
193
|
-
/**
|
|
194
|
-
|
|
195
|
-
|
|
592
|
+
/**
|
|
593
|
+
* Wie deze run in zijn lijst ziet — een **index**, geen autorisatie.
|
|
594
|
+
*
|
|
595
|
+
* Heette `audience`, en dat woord suggereerde een rechtenlijst; hij werd ook zo gebruikt in de
|
|
596
|
+
* losse tak van `authorizeRunScope` terwijl de interactie-tak hem juist bewust negeerde (de
|
|
597
|
+
* denormalisatie verouderd zodra een gesprek van inbox wisselt). Autorisatie komt nu van het
|
|
598
|
+
* onderwerp of van de scope van de definitie; dit veld is er alleen om "mijn runs" te kunnen
|
|
599
|
+
* queryen.
|
|
600
|
+
*/
|
|
601
|
+
visibleTo?: string[];
|
|
602
|
+
/** Wie deze run in beweging zette. Zie {@link StartedBy}. */
|
|
603
|
+
startedBy: StartedBy;
|
|
196
604
|
approvedBy?: string | null;
|
|
197
605
|
result?: {
|
|
198
606
|
ok: boolean;
|
|
@@ -3,11 +3,7 @@
|
|
|
3
3
|
* so read-state (and, later, an audit log) can attach to any resource -
|
|
4
4
|
* interactions, activities, files, kb articles - without per-type schemas.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
export interface ResourceRef {
|
|
8
|
-
type: string;
|
|
9
|
-
id: string;
|
|
10
|
-
}
|
|
6
|
+
export type { ResourceRef } from '../../platform/resource';
|
|
11
7
|
/**
|
|
12
8
|
* A single user's high-water read mark on one resource. `lastReadAt` is the
|
|
13
9
|
* epoch (ms) up to which this user has read the resource; whether they have
|
|
@@ -1,8 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mens of agent.
|
|
3
|
+
*
|
|
4
|
+
* Een agent is **geen apart begrip naast de gebruiker** maar een gebruiker met een ander type.
|
|
5
|
+
* Dat is een keuze met een concreet doel: hij krijgt een echt `userId`, dus hij loopt door
|
|
6
|
+
* `authorizeIdentity` op het fail-closed pad, hij tekent zijn activities met zijn eigen naam in
|
|
7
|
+
* plaats van als "system", hij kan lid van een team zijn (`getReadableTeamIds` werkt), en hij
|
|
8
|
+
* verbruikt van zijn eigen per-user-budget. Elk van die dingen zou anders een uitzondering zijn
|
|
9
|
+
* geweest, en elke uitzondering is een plek waar een audit hem kwijtraakt.
|
|
10
|
+
*
|
|
11
|
+
* Afwezig betekent `"user"`: bestaande rijen zijn mensen, en de mirror wordt niet gebackfilld.
|
|
12
|
+
*/
|
|
13
|
+
export type UserType = "user" | "agent";
|
|
14
|
+
/**
|
|
15
|
+
* Wat een ander oppervlak van een gebruiker mag weten om hem te **tónen**.
|
|
16
|
+
*
|
|
17
|
+
* Los van {@link User}, en dat is het punt: een naam opzoeken is iets anders dan een gebruiker
|
|
18
|
+
* beheren. De beheerroute geeft het hele record plus zijn rollen (een extra RPC naar
|
|
19
|
+
* `system.rbac`) — dat is precies wat je niet wil als je alleen een auteursnaam in een tijdlijn
|
|
20
|
+
* zet: het kost een call die niemand nodig heeft en het deelt e-mail en rollen met een app die
|
|
21
|
+
* daar niets mee te maken heeft.
|
|
22
|
+
*
|
|
23
|
+
* `type` zit er wél in: een tijdlijn of een deelnemerslijst wil een agent kunnen markeren.
|
|
24
|
+
*/
|
|
25
|
+
export interface UserProfile {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
displayName?: string;
|
|
29
|
+
avatarUrl?: string;
|
|
30
|
+
type?: UserType;
|
|
31
|
+
/**
|
|
32
|
+
* Het brein van een agent, als dit een agent is — zie {@link User.profileId}.
|
|
33
|
+
*
|
|
34
|
+
* Hoort bij dit compacte record en niet alleen bij het volledige: "is dit een agent" staat er
|
|
35
|
+
* al (`type`), en "met welk brein" is de directe vervolgvraag van elke beller die er werk aan
|
|
36
|
+
* geeft. Zonder dit veld moest de ai-app de beheerroute gebruiken — het hele record plus een
|
|
37
|
+
* RPC naar `system.rbac` — om één id te weten.
|
|
38
|
+
*/
|
|
39
|
+
profileId?: string;
|
|
40
|
+
}
|
|
41
|
+
/** Is deze gebruiker een agent? Afwezig type = mens. */
|
|
42
|
+
export declare function isAgentUser(user: {
|
|
43
|
+
type?: UserType | string;
|
|
44
|
+
}): boolean;
|
|
1
45
|
export interface User {
|
|
2
46
|
id: string;
|
|
3
47
|
name: string;
|
|
4
48
|
email: string;
|
|
5
49
|
availableOrganizations: string[];
|
|
50
|
+
/**
|
|
51
|
+
* Mens of agent. Zie {@link UserType}.
|
|
52
|
+
*
|
|
53
|
+
* Staat op de **lokale mirror** en niet in `system.users`: dat is het platform-record en dat
|
|
54
|
+
* kennen we niet. Alles wat "is dit een mens" moet weten leest dit veld.
|
|
55
|
+
*/
|
|
56
|
+
type?: UserType;
|
|
57
|
+
/**
|
|
58
|
+
* Het brein van een agent: het `AIProfile` waarmee hij werkt. Alleen gezet als
|
|
59
|
+
* `type === "agent"`.
|
|
60
|
+
*/
|
|
61
|
+
profileId?: string;
|
|
6
62
|
/** Mirrored from system.users. */
|
|
7
63
|
firstName?: string;
|
|
8
64
|
lastName?: string;
|