@opencxh/domain 1.275.0 → 1.276.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/types.d.ts +5 -1
- package/dist/entities/ai-account/modality.d.ts +0 -2
- package/dist/entities/ai-account/vendors.d.ts +2 -7
- package/dist/entities/ai-message/types.d.ts +2 -0
- package/dist/entities/approval/decide-each.d.ts +16 -0
- package/dist/entities/approval/decide-each.test.d.ts +1 -0
- package/dist/entities/approval/index.d.ts +1 -0
- package/dist/entities/playbook/actor.d.ts +1 -12
- package/dist/entities/playbook/approval.d.ts +14 -0
- package/dist/entities/playbook/approval.test.d.ts +1 -0
- package/dist/entities/playbook/autonomy.d.ts +25 -0
- package/dist/entities/playbook/autonomy.test.d.ts +1 -0
- package/dist/entities/playbook/index.d.ts +2 -0
- package/dist/entities/playbook/labels.d.ts +1 -3
- package/dist/entities/playbook/types.d.ts +30 -38
- package/dist/entities/reaction/types.d.ts +6 -1
- package/dist/entities/rule/bind.d.ts +20 -5
- package/dist/entities/rule/outcome.d.ts +2 -0
- package/dist/entities/rule/trigger-source.d.ts +4 -4
- package/dist/entities/rule/types.d.ts +47 -4
- package/dist/entities/scope/actor.d.ts +0 -5
- package/dist/entities/sla/types.d.ts +1 -1
- package/dist/entities/webhook/types.d.ts +7 -1
- package/dist/index.cjs +20 -20
- package/dist/index.js +1503 -1396
- package/dist/platform/ai-tools.d.ts +34 -15
- package/dist/platform/permission.d.ts +2 -2
- package/dist/platform/resource-source.d.ts +14 -0
- package/dist/platform/tool-verdict.d.ts +22 -9
- package/package.json +1 -1
|
@@ -281,7 +281,7 @@ export type AIActionProposedPayload = {
|
|
|
281
281
|
runId: string;
|
|
282
282
|
playbookId?: string;
|
|
283
283
|
playbookName?: string;
|
|
284
|
-
/** The held actions, e.g. { action: "
|
|
284
|
+
/** The held actions, e.g. { action: "mcp__jira__create_issue", params }. */
|
|
285
285
|
actions: {
|
|
286
286
|
action: string;
|
|
287
287
|
params?: Record<string, unknown>;
|
|
@@ -289,6 +289,10 @@ export type AIActionProposedPayload = {
|
|
|
289
289
|
status: "pending" | "approved" | "rejected";
|
|
290
290
|
/** Who the proposal was made on behalf of, so the card can show "on behalf of Finance". */
|
|
291
291
|
actor?: ActingIdentity;
|
|
292
|
+
/** The approval request that decides it — the card decides through that, not through ai. */
|
|
293
|
+
approvalRequestId?: string;
|
|
294
|
+
/** Every request this proposal waits on, one per guarded act; the first is `approvalRequestId`. */
|
|
295
|
+
approvalRequestIds?: string[];
|
|
292
296
|
};
|
|
293
297
|
/** Playbook lifecycle marker in the interaction timeline (system-authored). */
|
|
294
298
|
export type PlaybookLifecyclePayload = {
|
|
@@ -22,5 +22,3 @@ export interface ModelModality {
|
|
|
22
22
|
* declares, rather than silently refusing every attachment on a self-hosted or brand-new model.
|
|
23
23
|
*/
|
|
24
24
|
export declare function modelAcceptsAttachment(modality: ModelModality | undefined, kind: string): boolean | undefined;
|
|
25
|
-
/** Can this model speak? The honest question behind the `tts` flag. */
|
|
26
|
-
export declare function modelProduces(modality: ModelModality | undefined, out: string): boolean;
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { AiCapability } from './capabilities';
|
|
2
|
-
/**
|
|
3
|
-
* What a vendor can do. Was its own union of three; it is the same vocabulary the account
|
|
4
|
-
* defaults and the usage rows use, so it now names {@link AiCapability} instead of repeating it.
|
|
5
|
-
*/
|
|
6
|
-
export type AiVendorCapability = AiCapability;
|
|
7
2
|
export interface AiVendor {
|
|
8
3
|
id: string;
|
|
9
4
|
label: string;
|
|
10
5
|
/** What this vendor can do. Decides where it appears as an option in the UI. */
|
|
11
|
-
capabilities: readonly
|
|
6
|
+
capabilities: readonly AiCapability[];
|
|
12
7
|
/** Model a call runs on when it carries none itself. Absent for vendors without a chat adapter. */
|
|
13
8
|
defaultModel?: string;
|
|
14
9
|
/**
|
|
@@ -38,7 +33,7 @@ export declare function aiVendorLabel(vendorId: string): string;
|
|
|
38
33
|
*/
|
|
39
34
|
export declare function aiVendorDefaultModel(vendorId: string, fallback?: string): string;
|
|
40
35
|
/** Vendors offering this capability — for capability-filtered pickers. */
|
|
41
|
-
export declare function aiVendorsWith(capability:
|
|
36
|
+
export declare function aiVendorsWith(capability: AiCapability): AiVendor[];
|
|
42
37
|
/** True when the user has to fill in a host themselves (the vendor has no fixed one). */
|
|
43
38
|
export declare function aiVendorNeedsBaseUrl(vendorId: string): boolean;
|
|
44
39
|
/** Does this vendor accept this attachment kind? Text always works — that is prompt. */
|
|
@@ -39,6 +39,8 @@ export interface AIMessageOutput {
|
|
|
39
39
|
* question and then having the same thread draft a reply is the normal flow.
|
|
40
40
|
*/
|
|
41
41
|
export type AssistantMode = "ask" | "draft" | "agent";
|
|
42
|
+
/** Is this one of the three modes? For request bodies, which may carry anything. */
|
|
43
|
+
export declare function isAssistantMode(value: unknown): value is AssistantMode;
|
|
42
44
|
export interface AIMessage {
|
|
43
45
|
id: string;
|
|
44
46
|
organizationId: string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Give one verdict on every request of a proposal that this person may decide.
|
|
3
|
+
*
|
|
4
|
+
* A park asks one request per guarded act, each with its own approvers; the person pressing the
|
|
5
|
+
* button signs the ones that are theirs. A request that is not theirs (403) or already settled
|
|
6
|
+
* (400) is counted as `waiting` rather than failing the rest — anything else is a real error.
|
|
7
|
+
*/
|
|
8
|
+
export declare function decideEach(requestIds: readonly string[], decideOne: (requestId: string) => Promise<unknown>): Promise<{
|
|
9
|
+
decided: number;
|
|
10
|
+
waiting: number;
|
|
11
|
+
}>;
|
|
12
|
+
/** The requests a proposal waits on, from the list or the single id older rows carry. */
|
|
13
|
+
export declare function proposalRequestIds(source: {
|
|
14
|
+
approvalRequestIds?: readonly string[] | null;
|
|
15
|
+
approvalRequestId?: string | null;
|
|
16
|
+
}): string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
import { ActingIdentity } from '../../platform/identity';
|
|
2
|
-
import { toActingIdentity } from '../scope/actor';
|
|
3
2
|
import { OwnerScope } from '../scope/types';
|
|
4
|
-
/**
|
|
5
|
-
* `ownerScope` **is** a playbook's actor: there is no separate `runAs` field. Visibility, working
|
|
6
|
-
* area and attribution therefore all follow from the same field.
|
|
7
|
-
*
|
|
8
|
-
* On the storage side the personal variant is called `personal` (as with every other entity), on
|
|
9
|
-
* the execution side `user` (as with every other acting identity). This function is that
|
|
10
|
-
* translation, and the only place it belongs.
|
|
11
|
-
*/
|
|
12
|
-
export declare const playbookActor: typeof toActingIdentity;
|
|
13
3
|
/**
|
|
14
4
|
* Who this run acts for.
|
|
15
5
|
*
|
|
16
|
-
* **Two different questions
|
|
17
|
-
* {@link playbookActor}:**
|
|
6
|
+
* **Two different questions**, which is why this is not just `toActingIdentity(ownerScope)`:
|
|
18
7
|
*
|
|
19
8
|
* - *who acts* — the agent, when one is designated;
|
|
20
9
|
* - *who may manage this* — `ownerScope`, and that stays with humans.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A parked run's address in the approval layer: `playbook-run:<runId>~<step>`.
|
|
3
|
+
*
|
|
4
|
+
* The park is part of the key on purpose. The approval layer de-duplicates on `(scopeKey, act)`
|
|
5
|
+
* and keeps one approved row per key, so a flow that parks, resumes and parks again on a later
|
|
6
|
+
* step needs a key per park — while a retry of the *same* park must find its open request.
|
|
7
|
+
* `~` because the key travels in paths too, where `/` and `.` already mean something.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PLAYBOOK_RUN_SCOPE_KIND = "playbook-run";
|
|
10
|
+
/** The one act a parked run asks for: "carry out what was proposed". */
|
|
11
|
+
export declare const PLAYBOOK_RUN_APPROVAL_ACT = "run";
|
|
12
|
+
export declare function runApprovalKey(runId: string, step?: number): string;
|
|
13
|
+
/** The run behind an approval key's ref (`<runId>~<step>`), or the ref itself without a step. */
|
|
14
|
+
export declare function runIdOfApprovalRef(ref: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Autonomy } from './types';
|
|
2
|
+
/** Is this one of the three settings? For request bodies, which may carry anything. */
|
|
3
|
+
export declare function isAutonomy(value: unknown): value is Autonomy;
|
|
4
|
+
/**
|
|
5
|
+
* How much a run may do on its own, decided **once** at its start and frozen on the run. The
|
|
6
|
+
* playbook's setting wins where there is one (that is where the organisation configured it), then
|
|
7
|
+
* the agent's, then `suggest`.
|
|
8
|
+
*
|
|
9
|
+
* `demoted`: several autonomous playbooks would act outward on the same subject at once. They
|
|
10
|
+
* keep doing internal work themselves; a human decides which one goes out.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveAutonomy(input: {
|
|
13
|
+
playbook?: {
|
|
14
|
+
autonomy?: Autonomy;
|
|
15
|
+
} | null;
|
|
16
|
+
agent?: {
|
|
17
|
+
autonomy?: Autonomy;
|
|
18
|
+
} | null;
|
|
19
|
+
demoted?: boolean;
|
|
20
|
+
}): Autonomy;
|
|
21
|
+
/**
|
|
22
|
+
* A step's own setting may make it more careful than its run, never less: the run's value is
|
|
23
|
+
* where a demotion and the agent's mandate already landed.
|
|
24
|
+
*/
|
|
25
|
+
export declare function narrowAutonomy(run: Autonomy | undefined, step: Autonomy | undefined): Autonomy;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Readable name of an action/tool for a human: `
|
|
2
|
+
* Readable name of an action/tool for a human: `communication__update_interaction` becomes
|
|
3
3
|
* `communication · update interaction`.
|
|
4
4
|
*
|
|
5
5
|
* Shared, because the proposal card in comms already had this helper while the run timeline in the
|
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
* `voorstel: tool:mcp__jira__create_issue`.
|
|
8
8
|
*/
|
|
9
9
|
export declare function humanizeAction(action: string): string;
|
|
10
|
-
/** The namespaced tool id without the step's `tool:` prefix. */
|
|
11
|
-
export declare function toolName(action: string): string;
|
|
12
10
|
/**
|
|
13
11
|
* The tool's own name, without the namespace that says who owns it:
|
|
14
12
|
* `work__create_work_item` and `mcp__jira__create_issue` become `create_work_item` and
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ActingIdentity } from '../../platform/identity';
|
|
2
2
|
import { ResourceRef } from '../../platform/resource';
|
|
3
|
+
import { AssignmentControl } from '../assignment/types';
|
|
4
|
+
import { Trigger } from '../rule/types';
|
|
3
5
|
import { OwnerScope } from '../scope/types';
|
|
4
6
|
/**
|
|
5
7
|
* Playbooks — event-driven automation with AI steps. See docs/PLAYBOOKS.md.
|
|
@@ -7,41 +9,18 @@ import { OwnerScope } from '../scope/types';
|
|
|
7
9
|
* Two execution forms, one contract: see {@link Decider}. Every step type in
|
|
8
10
|
* {@link Step} is executed; there is no kind the executor refuses.
|
|
9
11
|
*/
|
|
10
|
-
export type Autonomy = "suggest" | "auto";
|
|
11
|
-
export type PlaybookTrigger = {
|
|
12
|
-
kind: "activity";
|
|
13
|
-
activityTypes: string[];
|
|
14
|
-
/** Channel kinds: "mail" | "chat" | "voice" (derived from the activity type). */
|
|
15
|
-
channels?: string[];
|
|
16
|
-
/** Specific channel ids (e.g. per mailbox). Matched against activity.channelId. */
|
|
17
|
-
channelIds?: string[];
|
|
18
|
-
filter?: unknown;
|
|
19
|
-
/**
|
|
20
|
-
* Wait this many milliseconds, then run **once** for the messages in that window
|
|
21
|
-
* instead of once per message. The run executes on the **newest** message; the ones
|
|
22
|
-
* in between are already covered by the conversation lookup step.
|
|
23
|
-
*
|
|
24
|
-
* Deliberately on the trigger, not in the memory layer: coalescing is a property of
|
|
25
|
-
* "how often do I want to react", not of what you remember.
|
|
26
|
-
*/
|
|
27
|
-
debounceMs?: number;
|
|
28
|
-
} | {
|
|
29
|
-
kind: "manual";
|
|
30
|
-
}
|
|
31
12
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* Not a new mechanism: an assignment is already an activity, so the same gate delivers it.
|
|
35
|
-
* The question the engine cannot answer itself — *is this for MY agent?* — is answered by
|
|
36
|
-
* `Playbook.agentId`, not here: one place names the agent, because that field also decides
|
|
37
|
-
* who the run acts as. Which kinds of work can be assigned is **declared** by the app that
|
|
38
|
-
* owns them (`assignment-source` federation, see `./assignment.ts`), hence a loose id in
|
|
39
|
-
* `targetKind` instead of a union here.
|
|
13
|
+
* How much a run may do on its own: ask before every write, ask only before a write that leaves
|
|
14
|
+
* the organisation, or ask nothing. Ordered from most to least careful.
|
|
40
15
|
*/
|
|
41
|
-
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
16
|
+
export type Autonomy = "suggest" | "outward" | "auto";
|
|
17
|
+
/**
|
|
18
|
+
* The arms of {@link Trigger} the playbook executor runs: an activity, a person, an assignment.
|
|
19
|
+
* One vocabulary; each executor names the part it runs (rules: `event` and `schedule`).
|
|
20
|
+
*/
|
|
21
|
+
export type PlaybookTrigger = Extract<Trigger, {
|
|
22
|
+
kind: "activity" | "manual" | "assignment";
|
|
23
|
+
}>;
|
|
45
24
|
export interface Guardrails {
|
|
46
25
|
maxSteps?: number;
|
|
47
26
|
maxToolCalls?: number;
|
|
@@ -96,14 +75,14 @@ export interface ForEachStep<S = Step> {
|
|
|
96
75
|
}
|
|
97
76
|
export interface LookupStep {
|
|
98
77
|
type: "lookup";
|
|
99
|
-
/**
|
|
78
|
+
/** The read tool, `<app>__<name>`. */
|
|
100
79
|
source: string;
|
|
101
80
|
filter?: unknown;
|
|
102
81
|
as: string;
|
|
103
82
|
}
|
|
104
83
|
export interface ActionStep {
|
|
105
84
|
type: "action";
|
|
106
|
-
/**
|
|
85
|
+
/** The write tool, `<app>__<name>`. */
|
|
107
86
|
action: string;
|
|
108
87
|
params: Record<string, unknown>;
|
|
109
88
|
autonomy?: Autonomy;
|
|
@@ -120,11 +99,11 @@ export interface ActionStep {
|
|
|
120
99
|
/**
|
|
121
100
|
* Wait until this task is done. Counterpart of `wait-for-reply`, for the support-procedure
|
|
122
101
|
* case "a colleague must do something: create a task and wait for it". `taskId` is an
|
|
123
|
-
* ordinary reference, e.g.
|
|
102
|
+
* ordinary reference, e.g. `{{newTask.id}}` after a `create_task` with an `as`.
|
|
124
103
|
*/
|
|
125
104
|
export interface WaitForTaskStep {
|
|
126
105
|
type: "wait-for-task";
|
|
127
|
-
/**
|
|
106
|
+
/** `{{ref}}` or literal id of the task to wait on. */
|
|
128
107
|
taskId: string;
|
|
129
108
|
}
|
|
130
109
|
/**
|
|
@@ -145,7 +124,7 @@ export interface ClassifyStep {
|
|
|
145
124
|
fields?: unknown;
|
|
146
125
|
instruction?: string;
|
|
147
126
|
/**
|
|
148
|
-
* Which text is classified, as a
|
|
127
|
+
* Which text is classified, as a `{{ref}}` into the run vars. Default `{{trigger.text}}`.
|
|
149
128
|
* Needed when the trigger carries no text: an `INTERACTION_STATUS_CHANGED` activity has
|
|
150
129
|
* only `{ fromStatus, toStatus }`, so `trigger.text` is empty. With `input: "$thread"` the
|
|
151
130
|
* step reads what an earlier `lookup` fetched.
|
|
@@ -217,6 +196,8 @@ export interface ParallelStep<S = Step> {
|
|
|
217
196
|
onBranchError?: "fail" | "continue";
|
|
218
197
|
}
|
|
219
198
|
export type Step = ConditionStep | ForEachStep | ParallelStep | LookupStep | ActionStep | ClassifyStep | GenerateStep | AgentStep | WaitForReplyStep | WaitForTaskStep;
|
|
199
|
+
/** Every step type, once. The `satisfies` pair fails to compile when a type is added or dropped. */
|
|
200
|
+
export declare const STEP_TYPES: readonly ["condition", "for-each", "parallel", "lookup", "action", "classify", "generate", "agent", "wait-for-reply", "wait-for-task"];
|
|
220
201
|
/**
|
|
221
202
|
* A **procedure**: how a scenario is handled, as prose with guardrails. The second execution
|
|
222
203
|
* form next to `Step[]`; {@link AgentStep} is its inside-a-flow variant (it *contains* one).
|
|
@@ -477,6 +458,11 @@ export interface PlaybookRun {
|
|
|
477
458
|
subjectKind?: string;
|
|
478
459
|
subjectId?: string;
|
|
479
460
|
status: RunStatus;
|
|
461
|
+
/**
|
|
462
|
+
* The autonomy this run started with ({@link resolveAutonomy}), frozen: a resume after an
|
|
463
|
+
* approval runs at the same setting it parked with. Absent on runs from before this field.
|
|
464
|
+
*/
|
|
465
|
+
autonomy?: Autonomy;
|
|
480
466
|
/**
|
|
481
467
|
* The cause: which signal started this run, plus the input as it looked **then**.
|
|
482
468
|
*
|
|
@@ -522,6 +508,12 @@ export interface PlaybookRun {
|
|
|
522
508
|
}[] | null;
|
|
523
509
|
/** The AI_ACTION_PROPOSED activity created for the current pending batch (for resolve on approve/reject). */
|
|
524
510
|
proposalActivityId?: string | null;
|
|
511
|
+
/** The approval request a parked run waits on (`runApprovalKey`). */
|
|
512
|
+
approvalRequestId?: string | null;
|
|
513
|
+
/** Every request this park waits on, one per distinct act; resumes when all are approved. */
|
|
514
|
+
approvalRequestIds?: string[];
|
|
515
|
+
/** The move an assignment turn chose before it parked; restored when the turn resumes. */
|
|
516
|
+
turnControl?: AssignmentControl | null;
|
|
525
517
|
/**
|
|
526
518
|
* What this run waits for, when `status === "waiting"`. `null` when cleared (the store
|
|
527
519
|
* writes `null`), absent on a run that is not waiting. A new wait reason costs a member in
|
|
@@ -67,9 +67,14 @@ export interface ReactionChange {
|
|
|
67
67
|
actor: ReactionActor;
|
|
68
68
|
/** `true` put it there, `false` took it away. */
|
|
69
69
|
on: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* The signed-in user who clicked. Absent when an app wrote it (a provider sync carrying a
|
|
72
|
+
* Teams emoji across), so a listener that syncs out never echoes a mirrored reaction back.
|
|
73
|
+
*/
|
|
74
|
+
byUser?: string;
|
|
70
75
|
}
|
|
71
76
|
/**
|
|
72
|
-
* The `reactions:changed` event, as apps receive it (`
|
|
77
|
+
* The `reactions:changed` event, as apps receive it (`context:reactions:changed`).
|
|
73
78
|
*
|
|
74
79
|
* Carries **both** the resulting chip set and the delta, because the two consumers need
|
|
75
80
|
* different things. A feed re-renders from `reactions` — a client that only got deltas and
|
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* One variable language for rules and playbooks: `{{path}}`.
|
|
3
3
|
*
|
|
4
|
-
* A
|
|
5
|
-
* id, a number stays a number); a reference inside longer text is stringified
|
|
6
|
-
*
|
|
4
|
+
* A value that is *only* a reference keeps the referenced value's type (`"{{subject.id}}"` → the
|
|
5
|
+
* id, a number stays a number); a reference inside longer text is stringified, objects as JSON.
|
|
6
|
+
* `{ "var": "path" }` in a condition is json-logic's own and not handled here.
|
|
7
|
+
*
|
|
8
|
+
* What an unknown reference becomes is the executor's call:
|
|
9
|
+
* - `"empty"` (rules): `""` — the same "empty is not an instruction" the tools already read;
|
|
10
|
+
* - `"throw"` (playbooks): an error when the path's **root** is not there (a typo, or a step that
|
|
11
|
+
* never ran). A known root with an empty leaf stays empty: a chat message has no `subject`, and
|
|
12
|
+
* that is not a mistake.
|
|
7
13
|
*/
|
|
8
|
-
export
|
|
14
|
+
export interface BindOptions {
|
|
15
|
+
onMissing?: "empty" | "throw";
|
|
16
|
+
/** Where the value sits, for the error message. */
|
|
17
|
+
where?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class UnresolvedRefError extends Error {
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
export declare function bindParams(params: Record<string, unknown>, context: Record<string, unknown>, options?: BindOptions): Record<string, unknown>;
|
|
23
|
+
export declare function bindValue(value: unknown, context: Record<string, unknown>, options?: BindOptions): unknown;
|
|
@@ -19,6 +19,8 @@ export interface OutcomePrior {
|
|
|
19
19
|
params: Record<string, unknown>;
|
|
20
20
|
/** Which params were content — a field the subject owns — rather than addressing. */
|
|
21
21
|
fields: string[];
|
|
22
|
+
/** Fields the tool reported writing with a value it chose itself (`AiToolResult.wrote`). */
|
|
23
|
+
wrote?: Record<string, unknown>;
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
26
|
* Which fields no longer hold what the action put there.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ToolCatalogEntry } from '../../platform/ai-tools';
|
|
2
|
+
import { RuleTemplate } from './types';
|
|
2
3
|
/**
|
|
3
4
|
* What kind of value sits at a field, so the builder knows which widget to draw and the
|
|
4
5
|
* comparison operators that make sense.
|
|
@@ -79,16 +80,15 @@ export interface EventDescriptor {
|
|
|
79
80
|
name: string;
|
|
80
81
|
/** What this event is, in the author's language: "Er komt een bericht binnen". */
|
|
81
82
|
label: string;
|
|
82
|
-
/**
|
|
83
|
-
* What the subject is. Also the key the undo reader uses to fetch current state, so a new
|
|
84
|
-
* subject kind needs a reader there before its runs can be undone.
|
|
85
|
-
*/
|
|
83
|
+
/** What the subject is, for the builder. The run itself records the subject's scope kind. */
|
|
86
84
|
subjectKind: string;
|
|
87
85
|
fields: EventField[];
|
|
88
86
|
}
|
|
89
87
|
/** What a `trigger-source` returns on `GET /provider/triggers/describe`. */
|
|
90
88
|
export interface TriggerSourceDescription {
|
|
91
89
|
events: EventDescriptor[];
|
|
90
|
+
/** Rules to start from, on this app's own events. */
|
|
91
|
+
templates?: RuleTemplate[];
|
|
92
92
|
}
|
|
93
93
|
/** An event plus the app that answered for it — the merged catalog a builder reads. */
|
|
94
94
|
export interface VocabularyEvent extends EventDescriptor {
|
|
@@ -5,8 +5,9 @@ import { OutcomePrior, RunOutcome } from './outcome';
|
|
|
5
5
|
*
|
|
6
6
|
* There were five of these, and they had to agree without anything saying so: `PlaybookTrigger`,
|
|
7
7
|
* `webhook.triggers[]` (four fixed strings), the sync tick, and twenty-one hand-rolled cron jobs.
|
|
8
|
+
* Playbooks now run a subset of this union (`PlaybookTrigger`); webhooks store `event` names.
|
|
8
9
|
*
|
|
9
|
-
* **
|
|
10
|
+
* **No `stream` arm.** `stream` is deliberately absent. It existed once, as a field-less
|
|
10
11
|
* `{ kind: "stream" }` on `PlaybookTrigger`, and was removed with a reason that generalises:
|
|
11
12
|
* *"Definitions belong separated by their runtime, not by their editor."* A live read lane has no
|
|
12
13
|
* run, no lock and no gate, so it is not an automation with a trigger — it is its own thing
|
|
@@ -27,18 +28,42 @@ export type Trigger =
|
|
|
27
28
|
| {
|
|
28
29
|
kind: "manual";
|
|
29
30
|
}
|
|
30
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Work was handed to an agent. `targetKind` is declared by the app that owns that work
|
|
33
|
+
* (`assignment-source` federation, see `playbook/assignment.ts`); which agent is answered by
|
|
34
|
+
* `Playbook.agentId`, not here.
|
|
35
|
+
*/
|
|
31
36
|
| {
|
|
32
37
|
kind: "assignment";
|
|
33
38
|
targetKind: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A message appears: these activity types, optionally on these channel kinds or ids, passing
|
|
42
|
+
* `filter` (JSONLogic). Its own arm rather than an `event` with a filter, so the editor keeps
|
|
43
|
+
* its pickers instead of an expression.
|
|
44
|
+
*/
|
|
45
|
+
| {
|
|
46
|
+
kind: "activity";
|
|
47
|
+
activityTypes: string[];
|
|
48
|
+
/** Channel kinds: "mail" | "chat" | "voice" (derived from the activity type). */
|
|
49
|
+
channels?: string[];
|
|
50
|
+
/** Specific channel ids (e.g. per mailbox). Matched against activity.channelId. */
|
|
51
|
+
channelIds?: string[];
|
|
52
|
+
filter?: unknown;
|
|
53
|
+
/**
|
|
54
|
+
* Wait this many milliseconds, then run **once** for the messages in that window instead
|
|
55
|
+
* of once per message, on the newest one. Deliberately on the trigger: coalescing is
|
|
56
|
+
* "how often do I react", not what you remember.
|
|
57
|
+
*/
|
|
58
|
+
debounceMs?: number;
|
|
34
59
|
};
|
|
35
60
|
/**
|
|
36
61
|
* One thing a rule does.
|
|
37
62
|
*
|
|
38
|
-
* **`action` is
|
|
63
|
+
* **`action` is `<app>__<tool>`** — the action library is the tool federation, the
|
|
39
64
|
* same 62 descriptors the assistant uses, with the model taken out from in front. A second
|
|
40
65
|
* library would duplicate what a descriptor already carries: a JSON-Schema, a scope gate, an
|
|
41
|
-
* `effect` classification and an approval hook.
|
|
66
|
+
* `effect` classification and an approval hook. Playbooks spell it the same.
|
|
42
67
|
*/
|
|
43
68
|
export interface RuleAction {
|
|
44
69
|
action: string;
|
|
@@ -145,3 +170,21 @@ export interface RuleRun extends RuleRunRecord {
|
|
|
145
170
|
outcomeAt?: number;
|
|
146
171
|
createdAt?: number;
|
|
147
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* A rule an organisation can start from, declared by the app whose event it listens to.
|
|
175
|
+
*
|
|
176
|
+
* Data, not rows seeded on install: an organisation that never opens the builder should not
|
|
177
|
+
* acquire automation it did not ask for. Installing one is a normal create, so it lands disabled
|
|
178
|
+
* and passes the same save-time gate as anything a person writes.
|
|
179
|
+
*/
|
|
180
|
+
export interface RuleTemplate {
|
|
181
|
+
id: string;
|
|
182
|
+
name: string;
|
|
183
|
+
description: string;
|
|
184
|
+
/** What the author still has to fill in. Named, so the form can ask instead of guessing. */
|
|
185
|
+
blanks: {
|
|
186
|
+
path: string;
|
|
187
|
+
label: string;
|
|
188
|
+
}[];
|
|
189
|
+
rule: Pick<Rule, "trigger" | "when" | "then">;
|
|
190
|
+
}
|
|
@@ -7,10 +7,5 @@ import { OwnerScope } from './types';
|
|
|
7
7
|
* carries an id on one side and not on the other. This is that translation, and it is
|
|
8
8
|
* meant to be the only one: a hand-rolled `kind === "personal" ? "user" : …` at a call
|
|
9
9
|
* site is how two vocabularies for the same three rungs drift apart.
|
|
10
|
-
*
|
|
11
|
-
* It arrived as `playbookActor` in `entities/playbook/`, whose own docstring already
|
|
12
|
-
* claimed to be "the only place this belongs" — correct, but it read as
|
|
13
|
-
* playbook-specific while every scoped entity needs the same conversion. `playbookActor`
|
|
14
|
-
* stays as a name so the playbook call sites and their tests keep working.
|
|
15
10
|
*/
|
|
16
11
|
export declare function toActingIdentity(scope: OwnerScope): ActingIdentity;
|
|
@@ -50,7 +50,7 @@ export interface SlaTarget {
|
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
52
|
* A named set of service targets. Assigned to a resource explicitly — from a workflow rule
|
|
53
|
-
* (`
|
|
53
|
+
* (`context__apply_sla`) or by hand — never matched automatically. That is why there is
|
|
54
54
|
* no `appliesTo` and no `order`: both only exist to drive a matcher nothing calls.
|
|
55
55
|
*/
|
|
56
56
|
export interface SlaProfile {
|
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export type WebhookMethod = "POST" | "PUT";
|
|
7
7
|
export type WebhookContentType = "json" | "multipart";
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* The bus events a webhook can listen to — full names, the same string as a rule's
|
|
10
|
+
* `Trigger.event.name`. Add one here and the automations app subscribes to it.
|
|
11
|
+
*/
|
|
12
|
+
export declare const WEBHOOK_EVENTS: readonly ["communication:interactions:created", "communication:interactions:updated", "communication:activities:created", "communication:activities:updated"];
|
|
13
|
+
export type WebhookTrigger = (typeof WEBHOOK_EVENTS)[number];
|
|
14
|
+
export declare function isWebhookEvent(value: unknown): value is WebhookTrigger;
|
|
9
15
|
export interface Webhook {
|
|
10
16
|
id: string;
|
|
11
17
|
organizationId: string;
|