@opencxh/domain 1.274.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.
Files changed (55) hide show
  1. package/dist/entities/activity/types.d.ts +5 -1
  2. package/dist/entities/ai-account/capabilities.d.ts +4 -0
  3. package/dist/entities/ai-account/index.d.ts +3 -0
  4. package/dist/entities/ai-account/modality.d.ts +24 -0
  5. package/dist/entities/ai-account/modality.test.d.ts +1 -0
  6. package/dist/entities/ai-account/routing.d.ts +71 -0
  7. package/dist/entities/ai-account/routing.test.d.ts +1 -0
  8. package/dist/entities/ai-account/system-one.d.ts +109 -0
  9. package/dist/entities/ai-account/system-one.test.d.ts +1 -0
  10. package/dist/entities/ai-account/types.d.ts +12 -5
  11. package/dist/entities/ai-account/vendors.d.ts +2 -7
  12. package/dist/entities/ai-message/types.d.ts +9 -0
  13. package/dist/entities/ai-settings/types.d.ts +9 -0
  14. package/dist/entities/approval/decide-each.d.ts +16 -0
  15. package/dist/entities/approval/decide-each.test.d.ts +1 -0
  16. package/dist/entities/approval/index.d.ts +1 -0
  17. package/dist/entities/eval/index.d.ts +2 -0
  18. package/dist/entities/eval/runner.d.ts +14 -0
  19. package/dist/entities/eval/runner.test.d.ts +1 -0
  20. package/dist/entities/eval/types.d.ts +46 -0
  21. package/dist/entities/inbox/types.d.ts +4 -4
  22. package/dist/entities/interaction/attention.d.ts +12 -13
  23. package/dist/entities/kb/index.d.ts +1 -0
  24. package/dist/entities/kb/keys.d.ts +2 -0
  25. package/dist/entities/playbook/actor.d.ts +1 -12
  26. package/dist/entities/playbook/approval.d.ts +14 -0
  27. package/dist/entities/playbook/approval.test.d.ts +1 -0
  28. package/dist/entities/playbook/autonomy.d.ts +25 -0
  29. package/dist/entities/playbook/autonomy.test.d.ts +1 -0
  30. package/dist/entities/playbook/index.d.ts +2 -0
  31. package/dist/entities/playbook/labels.d.ts +1 -3
  32. package/dist/entities/playbook/types.d.ts +30 -38
  33. package/dist/entities/reaction/types.d.ts +6 -1
  34. package/dist/entities/rule/bind.d.ts +23 -0
  35. package/dist/entities/rule/bind.test.d.ts +1 -0
  36. package/dist/entities/rule/cron.d.ts +40 -0
  37. package/dist/entities/rule/cron.test.d.ts +1 -0
  38. package/dist/entities/rule/eval.d.ts +31 -0
  39. package/dist/entities/rule/index.d.ts +4 -0
  40. package/dist/entities/rule/match.d.ts +8 -0
  41. package/dist/entities/rule/outcome.d.ts +44 -0
  42. package/dist/entities/rule/outcome.test.d.ts +1 -0
  43. package/dist/entities/rule/trigger-source.d.ts +4 -4
  44. package/dist/entities/rule/types.d.ts +91 -4
  45. package/dist/entities/scope/actor.d.ts +0 -5
  46. package/dist/entities/sla/types.d.ts +1 -1
  47. package/dist/entities/webhook/types.d.ts +7 -1
  48. package/dist/index.cjs +20 -20
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.js +2061 -1700
  51. package/dist/platform/ai-tools.d.ts +34 -15
  52. package/dist/platform/permission.d.ts +2 -2
  53. package/dist/platform/resource-source.d.ts +19 -0
  54. package/dist/platform/tool-verdict.d.ts +22 -9
  55. package/package.json +1 -1
@@ -6,6 +6,8 @@
6
6
  * from internal apps (via the "ai-tool" provider role) or external MCP servers —
7
7
  * both surface through the same {@link AiTool} shape.
8
8
  */
9
+ /** The provider role an app declares to offer AI tools (`/provider/ai-tools/*`). */
10
+ export declare const AI_TOOL_PROVIDER_GROUP = "ai-tool";
9
11
  /** JSON-Schema object describing a tool's arguments. */
10
12
  export interface AiToolParameterSchema {
11
13
  type: "object";
@@ -19,6 +21,12 @@ export interface AiTool {
19
21
  description: string;
20
22
  parameters: AiToolParameterSchema;
21
23
  }
24
+ /** Does a tool change anything? Absent counts as write. */
25
+ export type ToolAccess = "read" | "write";
26
+ /** Does a write stay inside the organisation? Absent counts as outward. */
27
+ export type ToolEffect = "internal" | "outward";
28
+ /** Can a write be taken back? Absent counts as none. */
29
+ export type ToolReversible = "self" | "none" | "idempotent";
22
30
  /**
23
31
  * One entry in the tool catalog: what is available in this organisation right now.
24
32
  *
@@ -34,9 +42,9 @@ export interface ToolCatalogEntry {
34
42
  /** JSON-Schema of the tool's arguments — drives the playbook builder's param form. */
35
43
  parameters: AiToolParameterSchema;
36
44
  /** read | write as the tool declares it; absent = unknown. */
37
- access?: "read" | "write";
45
+ access?: ToolAccess;
38
46
  /** internal | outward as the tool declares it; absent = outward. */
39
- effect?: "internal" | "outward";
47
+ effect?: ToolEffect;
40
48
  /**
41
49
  * `"interactive"` = needs a watching user. Carried so a builder can say that up front:
42
50
  * a playbook runs unattended, and such a tool reports success for something that lands
@@ -46,7 +54,9 @@ export interface ToolCatalogEntry {
46
54
  /** What it leaves for a human to finish. See {@link AiToolDescriptor.produces}. */
47
55
  produces?: "draft";
48
56
  /** Whether it can be taken back. See {@link AiToolDescriptor.reversible}. */
49
- reversible?: "self" | "none" | "idempotent";
57
+ reversible?: ToolReversible;
58
+ /** The tool that takes it back. See {@link AiToolDescriptor.undoWith}. */
59
+ undoWith?: string;
50
60
  }
51
61
  /**
52
62
  * How an action can be taken back. Reads the fail-safe default in one place, so no caller has to
@@ -56,17 +66,17 @@ export interface ToolCatalogEntry {
56
66
  * reverse and running it again is free. Only writes have a real answer here.
57
67
  */
58
68
  export declare function toolReversible(tool: {
59
- access?: "read" | "write";
60
- reversible?: "self" | "none" | "idempotent";
61
- }): "self" | "none" | "idempotent";
69
+ access?: ToolAccess;
70
+ reversible?: ToolReversible;
71
+ }): ToolReversible;
62
72
  /**
63
73
  * Can this tool reach outside the building? A read never does; an `effect: "internal"` write says
64
74
  * so itself. Everything else — including a tool that declares neither — counts as outward, so a
65
75
  * forgotten declaration costs a tool for the turn rather than quietly sending a mail.
66
76
  */
67
77
  export declare function isOutwardTool(tool: {
68
- access?: "read" | "write";
69
- effect?: "internal" | "outward";
78
+ access?: ToolAccess;
79
+ effect?: ToolEffect;
70
80
  }): boolean;
71
81
  /** A model's request to call a tool. */
72
82
  export interface AiToolCall {
@@ -137,6 +147,12 @@ export interface AiToolResult {
137
147
  * stored `AIMessage`, so the thread keeps its provenance without a new entity.
138
148
  */
139
149
  sources?: ToolSource[];
150
+ /**
151
+ * Subject fields this call set whose value the params do not say — a value the tool chose
152
+ * itself (`assign_least_loaded` picks the assignee). Without it a rule run cannot tell what it
153
+ * wrote, so neither the undo nor the outcome check could judge it.
154
+ */
155
+ wrote?: Record<string, unknown>;
140
156
  }
141
157
  /**
142
158
  * Stable key for "I have already shown this".
@@ -168,7 +184,7 @@ export declare function freshSources(sources: readonly ToolSource[], alreadyShow
168
184
  */
169
185
  export interface AiToolDescriptor extends AiTool {
170
186
  /** Does this tool mutate anything? Drives the suggest gate. Absent = unknown. */
171
- access?: "read" | "write";
187
+ access?: ToolAccess;
172
188
  /**
173
189
  * The resource this tool works on, so a generic gate can authorize it:
174
190
  * `{ param: "interactionId", kind: "interaction" }` means "authorize
@@ -200,7 +216,7 @@ export interface AiToolDescriptor extends AiTool {
200
216
  * should not silently count as harmless. See `shouldDemoteAuto` in the playbook engine, which
201
217
  * decides the suggest downgrade on this.
202
218
  */
203
- effect?: "internal" | "outward";
219
+ effect?: ToolEffect;
204
220
  /**
205
221
  * What this tool leaves behind for a human to finish. `"draft"` = it prepares something the
206
222
  * user reviews and sends (a reply draft), which is exactly the deliverable of an
@@ -224,10 +240,7 @@ export interface AiToolDescriptor extends AiTool {
224
240
  * attribute, an SLA profile). The executor records what was there before; undo replays that
225
241
  * through this same tool, and nothing else has to know anything.
226
242
  *
227
- * Deliberately narrow. `add_tag` is reversible too, but by a *different* tool
228
- * (`remove_tag`), and expressing that needs a second field naming the counter-action. That
229
- * field can arrive the day an undo actually wants it; until then such a tool stays on the
230
- * default and simply is not offered as undoable. Under-promising is the safe direction.
243
+ * A tool undone by a *different* tool names it in {@link AiToolDescriptor.undoWith}.
231
244
  * - `"none"` — irreversible. A sent mail, a webhook, a row at a third party. The gate belongs
232
245
  * *before* it; afterwards there is nothing to do but send a second message, and that is a
233
246
  * human's decision, not an undo.
@@ -246,7 +259,13 @@ export interface AiToolDescriptor extends AiTool {
246
259
  * becomes `"self"` when its clear-semantics are fixed, not when someone decides it feels
247
260
  * reversible — which is exactly why the default is the careful one.
248
261
  */
249
- reversible?: "self" | "none" | "idempotent";
262
+ reversible?: ToolReversible;
263
+ /**
264
+ * The bare name of the tool in this same app that puts back the previous values, when that is
265
+ * not this tool itself. `assign_least_loaded` chooses an assignee and cannot be told one, so its
266
+ * inverse is `update_interaction` with the assignee it replaced. Only read with `"self"`.
267
+ */
268
+ undoWith?: string;
250
269
  }
251
270
  /**
252
271
  * Body of `POST /provider/ai-tools/invoke`. Replaces five inline structural types (the caller in
@@ -18,8 +18,8 @@ export declare const APP_PERMISSIONS: {
18
18
  readonly "app-store": readonly ["app.publish", "app.read", "app.write", "setting.read", "setting.write"];
19
19
  readonly assist: readonly ["board.read"];
20
20
  readonly automations: readonly ["sync.read", "sync.write", "webhook.read", "webhook.write"];
21
- readonly communication: readonly ["account.read", "account.write", "activity-type.read", "activity.read", "activity.write", "attachment.read", "attribute.read", "attribute.write", "calendar.read", "calendar.write", "channel.read", "channel.write", "custom-field.read", "custom-field.write", "folder.read", "folder.write", "inbox.read", "inbox.write", "interaction.read", "interaction.write", "reaction.read", "reaction.write", "reminder.read", "template.read", "template.write", "topic.read", "topic.write"];
22
- readonly context: readonly ["kind.read", "kind.write", "memory.read", "memory.write"];
21
+ readonly communication: readonly ["account.read", "account.write", "activity-type.read", "activity.read", "activity.write", "attachment.read", "calendar.read", "calendar.write", "channel.read", "channel.write", "folder.read", "folder.write", "inbox.read", "inbox.write", "interaction.read", "interaction.write", "reminder.read", "template.read", "template.write"];
22
+ readonly context: readonly ["attribute.read", "attribute.write", "custom-field.read", "custom-field.write", "kind.read", "kind.write", "memory.read", "memory.write", "reaction.read", "reaction.write", "topic.read", "topic.write"];
23
23
  readonly crm: readonly ["company.read", "company.write", "contact.read", "contact.write"];
24
24
  readonly "eylo-voip": readonly ["account.read", "account.write", "callflow.read", "callflow.write", "channel.read", "channel.write", "contact.read", "contact.write", "device.read", "device.write", "group.read", "group.write", "interaction.read", "interaction.write", "media.read", "media.write", "menu.read", "menu.write", "phone-number.read", "phone-number.write", "recording.read", "recording.write", "sip.read", "temporal-rule.read", "temporal-rule.write", "user.read", "user.write", "vmbox.read", "vmbox.write", "webhook.read", "webhook.write"];
25
25
  readonly google: readonly ["account.read", "account.write", "contact.read"];
@@ -80,9 +80,23 @@ export interface ResourceSummary {
80
80
  */
81
81
  related?: string[];
82
82
  }
83
+ /** How one kind reads wherever it is listed: a picker tab, a link row, a related group. */
84
+ export interface ResourceKindInfo {
85
+ /** Already in the viewer's language: the owning app has the words, a consumer never does. */
86
+ label: string;
87
+ /** Lucide icon name (kebab-case), like `ResourceSummary.icon`. */
88
+ icon?: string;
89
+ /** Semantic tint for the icon, so one kind has one colour on every surface. */
90
+ tone?: "info" | "success" | "warning" | "danger" | "muted";
91
+ }
83
92
  /** Answer to `resources.describe`: which kinds this app can search and resolve. */
84
93
  export interface ResourceSourceDescribe {
85
94
  kinds: string[];
95
+ /**
96
+ * Per kind this app **owns**: those in `kinds`, and any it owns without offering search (a
97
+ * dossier row can still carry them). Absent = consumers show the raw kind, the honest fallback.
98
+ */
99
+ info?: Record<string, ResourceKindInfo>;
86
100
  }
87
101
  /** Params for `resources.search`. */
88
102
  export interface ResourceSearchParams {
@@ -266,4 +280,9 @@ export interface ResourceReadRequest {
266
280
  export interface ResourceReadResponse {
267
281
  text: string;
268
282
  title?: string;
283
+ /**
284
+ * The row itself, for a caller that compares values rather than reads prose — the undo and
285
+ * the outcome check. Same authorization as the text, so one read serves both.
286
+ */
287
+ fields?: Record<string, unknown>;
269
288
  }
@@ -1,5 +1,7 @@
1
1
  import { Agent } from '../entities/agent/types';
2
2
  import { AssistantMode } from '../entities/ai-message/types';
3
+ import { Autonomy } from '../entities/playbook/types';
4
+ import { ToolCatalogEntry } from './ai-tools';
3
5
  /**
4
6
  * May this tool be offered to the model this turn — and if it writes, may it run?
5
7
  *
@@ -26,15 +28,10 @@ export type ToolVerdict =
26
28
  /** Offered, but a call is captured for approval instead of executed. */
27
29
  | "held";
28
30
  /** What a verdict is made of. The declared half of a tool plus where it came from. */
29
- export interface ToolFacts {
30
- name: string;
31
- access?: "read" | "write";
32
- effect?: "internal" | "outward";
33
- surface?: "interactive";
34
- produces?: "draft";
31
+ export type ToolFacts = Pick<ToolCatalogEntry, "name" | "access" | "effect" | "surface" | "produces"> & {
35
32
  /** Runs on the acting user's own connection (a personal MCP server). */
36
33
  personal?: boolean;
37
- }
34
+ };
38
35
  export interface ToolVerdictContext {
39
36
  /**
40
37
  * Tool names the profile switched on. **`undefined` means no filter** — the catalog asks that
@@ -58,8 +55,8 @@ export interface ToolVerdictContext {
58
55
  mode?: AssistantMode;
59
56
  /** A read lane: nothing that writes, whatever else it declares. */
60
57
  readOnly?: boolean;
61
- /** Is the approval gate on for this turn? Then writes are held instead of run. */
62
- gate?: boolean;
58
+ /** The approval gate for this turn; absent means nothing is held (the interactive assistant). */
59
+ gate?: ToolGate;
63
60
  /**
64
61
  * The agent's mandate, when an agent runs this turn. It may call a tool a read that declares
65
62
  * itself a write, and vice versa — an admin's explicit choice about this colleague.
@@ -77,4 +74,20 @@ export interface ToolVerdictContext {
77
74
  * approval — which is why every descriptor should declare it.
78
75
  */
79
76
  export declare function isWriteTool(tool: ToolFacts, policy?: Agent["toolPolicy"]): boolean;
77
+ /** What decides whether a write waits for a human. */
78
+ export interface ToolGate {
79
+ /** The run's autonomy, after any step narrowed it. */
80
+ autonomy: Autonomy;
81
+ /**
82
+ * Tools an approval policy guards: these always ask, whatever the autonomy says. `"all"` when
83
+ * the policies could not be read — then every write asks, because nobody can say which not to.
84
+ */
85
+ guarded?: ReadonlySet<string> | "all";
86
+ }
87
+ /**
88
+ * Must a human sign this call before it runs? The one answer for a workflow's action step and an
89
+ * agent's tool call. Reads never ask; a guarded tool always does; then the autonomy decides, where
90
+ * `outward` asks only for what leaves the organisation.
91
+ */
92
+ export declare function mustAsk(tool: ToolFacts, gate: ToolGate, policy?: Agent["toolPolicy"]): boolean;
80
93
  export declare function toolVerdict(tool: ToolFacts, ctx: ToolVerdictContext): ToolVerdict;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencxh/domain",
3
- "version": "1.274.0",
3
+ "version": "1.276.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",