@kuralle-agents/engagement 0.8.5 → 0.9.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.
|
@@ -1,19 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { InteractiveMessage, OutboundMiddleware } from '@kuralle-agents/messaging';
|
|
1
|
+
import type { OutboundMiddleware } from '@kuralle-agents/messaging';
|
|
3
2
|
import type { ChannelPolicy } from './policy.js';
|
|
4
|
-
|
|
5
|
-
export declare const BUTTON_TITLE_MAX = 20;
|
|
6
|
-
/** WhatsApp list row title limit (R-11). */
|
|
7
|
-
export declare const LIST_ROW_TITLE_MAX = 24;
|
|
8
|
-
/** WhatsApp reply buttons per message. */
|
|
9
|
-
export declare const BUTTON_COUNT_MAX = 3;
|
|
10
|
-
/** WhatsApp list rows per message. */
|
|
11
|
-
export declare const LIST_ROW_COUNT_MAX = 10;
|
|
12
|
-
/**
|
|
13
|
-
* Renders author choices to a channel-neutral `InteractiveMessage`, enforcing
|
|
14
|
-
* WhatsApp limits (R-11). URL options map to a single-button reply shape because
|
|
15
|
-
* `InteractiveMessage` has no dedicated CTA variant — the sink must interpret
|
|
16
|
-
* `ChoiceOption.url` when sending platform CTA messages.
|
|
17
|
-
*/
|
|
18
|
-
export declare function renderChoices(options: ChoiceOption[], prompt: string): InteractiveMessage;
|
|
3
|
+
export { renderChoices, BUTTON_TITLE_MAX, LIST_ROW_TITLE_MAX, BUTTON_COUNT_MAX, LIST_ROW_COUNT_MAX, } from '@kuralle-agents/messaging';
|
|
19
4
|
export declare function interactiveRenderer(policies?: ChannelPolicy[]): OutboundMiddleware;
|
|
@@ -1,105 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
export const BUTTON_COUNT_MAX = 3;
|
|
7
|
-
/** WhatsApp list rows per message. */
|
|
8
|
-
export const LIST_ROW_COUNT_MAX = 10;
|
|
9
|
-
function assertButtonTitle(label, optionId) {
|
|
10
|
-
if (label.length > BUTTON_TITLE_MAX) {
|
|
11
|
-
throw new Error(`interactive: button title for "${optionId}" exceeds ${BUTTON_TITLE_MAX} characters (got ${label.length})`);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
function assertListRowTitle(label, optionId) {
|
|
15
|
-
if (label.length > LIST_ROW_TITLE_MAX) {
|
|
16
|
-
throw new Error(`interactive: list row title for "${optionId}" exceeds ${LIST_ROW_TITLE_MAX} characters (got ${label.length})`);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Renders author choices to a channel-neutral `InteractiveMessage`, enforcing
|
|
21
|
-
* WhatsApp limits (R-11). URL options map to a single-button reply shape because
|
|
22
|
-
* `InteractiveMessage` has no dedicated CTA variant — the sink must interpret
|
|
23
|
-
* `ChoiceOption.url` when sending platform CTA messages.
|
|
24
|
-
*/
|
|
25
|
-
export function renderChoices(options, prompt) {
|
|
26
|
-
if (options.length === 0) {
|
|
27
|
-
throw new Error('interactive: at least one option is required');
|
|
28
|
-
}
|
|
29
|
-
const flowOption = options.find((o) => o.flow);
|
|
30
|
-
if (flowOption) {
|
|
31
|
-
if (options.length > 1) {
|
|
32
|
-
throw new Error('interactive: flow messages support exactly one option');
|
|
33
|
-
}
|
|
34
|
-
const { flowId } = flowOption.flow;
|
|
35
|
-
if (!flowOption.flow.cta) {
|
|
36
|
-
throw new Error('interactive: flow option requires flow.cta');
|
|
37
|
-
}
|
|
38
|
-
return {
|
|
39
|
-
type: 'flow',
|
|
40
|
-
body: prompt,
|
|
41
|
-
action: {
|
|
42
|
-
type: 'flow',
|
|
43
|
-
flowId,
|
|
44
|
-
flowToken: flowOption.id,
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
if (options.some((o) => o.url)) {
|
|
49
|
-
const urlOptions = options.filter((o) => o.url);
|
|
50
|
-
if (urlOptions.length > BUTTON_COUNT_MAX) {
|
|
51
|
-
throw new Error(`interactive: too many URL options (max ${BUTTON_COUNT_MAX} reply buttons)`);
|
|
52
|
-
}
|
|
53
|
-
for (const o of urlOptions) {
|
|
54
|
-
assertButtonTitle(o.label, o.id);
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
type: 'buttons',
|
|
58
|
-
body: prompt,
|
|
59
|
-
action: {
|
|
60
|
-
type: 'buttons',
|
|
61
|
-
buttons: urlOptions.map((o) => ({ id: o.id, title: o.label })),
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
if (options.length > LIST_ROW_COUNT_MAX) {
|
|
66
|
-
throw new Error(`interactive: too many options (max ${LIST_ROW_COUNT_MAX} list rows)`);
|
|
67
|
-
}
|
|
68
|
-
if (options.length <= BUTTON_COUNT_MAX) {
|
|
69
|
-
for (const o of options) {
|
|
70
|
-
assertButtonTitle(o.label, o.id);
|
|
71
|
-
}
|
|
72
|
-
return {
|
|
73
|
-
type: 'buttons',
|
|
74
|
-
body: prompt,
|
|
75
|
-
action: {
|
|
76
|
-
type: 'buttons',
|
|
77
|
-
buttons: options.map((o) => ({ id: o.id, title: o.label })),
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
for (const o of options) {
|
|
82
|
-
assertListRowTitle(o.label, o.id);
|
|
83
|
-
}
|
|
84
|
-
return {
|
|
85
|
-
type: 'list',
|
|
86
|
-
body: prompt,
|
|
87
|
-
action: {
|
|
88
|
-
type: 'list',
|
|
89
|
-
button: 'Choose',
|
|
90
|
-
sections: [
|
|
91
|
-
{
|
|
92
|
-
title: 'Options',
|
|
93
|
-
rows: options.map((o) => ({
|
|
94
|
-
id: o.id,
|
|
95
|
-
title: o.label,
|
|
96
|
-
description: o.description,
|
|
97
|
-
})),
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
}
|
|
1
|
+
// Canonical ChoiceOption -> InteractiveMessage rendering now lives in
|
|
2
|
+
// @kuralle-agents/messaging (the default stream mapper uses it too);
|
|
3
|
+
// re-exported here for existing engagement consumers.
|
|
4
|
+
export { renderChoices, BUTTON_TITLE_MAX, LIST_ROW_TITLE_MAX, BUTTON_COUNT_MAX, LIST_ROW_COUNT_MAX, } from '@kuralle-agents/messaging';
|
|
5
|
+
import { renderChoices } from '@kuralle-agents/messaging';
|
|
103
6
|
function policyFor(policies, platform) {
|
|
104
7
|
return policies.find((p) => p.channel === platform);
|
|
105
8
|
}
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"url": "git+https://github.com/kuralle/kuralle-agents.git",
|
|
7
7
|
"directory": "packages/kuralle-engagement"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.9.0",
|
|
10
10
|
"description": "Channel-agnostic engagement layer for Kuralle agents (window-safe outbound, smart-send, interactive fidelity, handoff, consent, proactive).",
|
|
11
11
|
"type": "module",
|
|
12
12
|
"main": "dist/index.js",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"ai": "^6.0.0",
|
|
29
29
|
"zod": "^4.0.0",
|
|
30
|
-
"@kuralle-agents/core": "0.
|
|
31
|
-
"@kuralle-agents/messaging
|
|
32
|
-
"@kuralle-agents/messaging": "0.
|
|
30
|
+
"@kuralle-agents/core": "0.9.0",
|
|
31
|
+
"@kuralle-agents/messaging": "0.9.0",
|
|
32
|
+
"@kuralle-agents/messaging-meta": "0.9.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"typescript": "^5.8.2",
|