@burdenoff/microfe-botmanor 2026.1110.2 → 2026.1110.3

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.
@@ -0,0 +1,286 @@
1
+ import { useTr as e } from "../../shared/hooks/useTr.js";
2
+ import { Card as t, CardContent as n, CardDescription as r, CardHeader as i, CardTitle as a } from "./Card.js";
3
+ import { Button as o } from "./Button.js";
4
+ import { Input as s } from "./Input.js";
5
+ import { Badge as c } from "./Badge.js";
6
+ import "../hooks/index.js";
7
+ import { useHandoffConfig as l, useUpsertHandoffConfig as u } from "../hooks/useHandoffs.js";
8
+ import { BotmanorHandoffFallbackBehavior as d } from "../../generated/wspace-types.js";
9
+ import { useEffect as f, useState as p } from "react";
10
+ import { jsx as m, jsxs as h } from "react/jsx-runtime";
11
+ // src/botlit/components/HandoffConfigPanel.tsx
12
+ function g(e) {
13
+ return {
14
+ enabled: e?.enabled ?? !1,
15
+ explicitRequest: e?.explicitRequest ?? !0,
16
+ lowConfidence: e?.lowConfidence ?? !1,
17
+ lowConfidenceThreshold: String(e?.lowConfidenceThreshold ?? .3),
18
+ repeatedFailures: e?.repeatedFailures ?? !1,
19
+ repeatedFailuresConsecutive: String(e?.repeatedFailuresConsecutive ?? 3),
20
+ policyRefusal: e?.policyRefusal ?? !1,
21
+ customIntentRows: (e?.customIntents ?? []).map((e) => `${e.name}|${e.pattern}|${e.isRegex ? "regex" : "text"}`).join("\n"),
22
+ targetUserIds: (e?.targetUserIds ?? []).join(", "),
23
+ targetRole: e?.targetRole ?? "",
24
+ notifyInApp: e?.notifyInApp ?? !0,
25
+ notifyEmail: e?.notifyEmail ?? !1,
26
+ notifyPush: e?.notifyPush ?? !1,
27
+ fallbackBehavior: e?.fallbackBehavior ?? d.Continue,
28
+ handoffMessage: e?.handoffMessage ?? ""
29
+ };
30
+ }
31
+ function _(e, t, n, r) {
32
+ let i = Number(e);
33
+ return Number.isFinite(i) ? Math.min(Math.max(i, n), r) : t;
34
+ }
35
+ function v(e) {
36
+ return {
37
+ enabled: e.enabled,
38
+ explicitRequest: e.explicitRequest,
39
+ lowConfidence: e.lowConfidence,
40
+ lowConfidenceThreshold: _(e.lowConfidenceThreshold, .3, 0, 1),
41
+ repeatedFailures: e.repeatedFailures,
42
+ repeatedFailuresConsecutive: Math.trunc(_(e.repeatedFailuresConsecutive, 3, 2, 10)),
43
+ policyRefusal: e.policyRefusal,
44
+ customIntents: e.customIntentRows.split("\n").map((e) => e.trim()).filter(Boolean).map((e) => {
45
+ let [t = "", n = "", r = "text"] = e.split("|");
46
+ return {
47
+ name: t.trim(),
48
+ pattern: n.trim(),
49
+ isRegex: r.trim() === "regex"
50
+ };
51
+ }),
52
+ targetUserIds: e.targetUserIds.split(",").map((e) => e.trim()).filter(Boolean),
53
+ targetRole: e.targetRole.trim() || null,
54
+ notifyInApp: e.notifyInApp,
55
+ notifyEmail: e.notifyEmail,
56
+ notifyPush: e.notifyPush,
57
+ fallbackBehavior: e.fallbackBehavior,
58
+ handoffMessage: e.handoffMessage.trim() || null
59
+ };
60
+ }
61
+ var y = ({ agentId: d }) => {
62
+ let _ = e(), y = l(d), [b, x] = u(d), [S, C] = p(() => g(y.data)), [w, T] = p(null);
63
+ f(() => {
64
+ y.data && C(g(y.data));
65
+ }, [y.data]);
66
+ let E = (e) => C((t) => ({
67
+ ...t,
68
+ ...e
69
+ })), D = async () => {
70
+ T(null);
71
+ try {
72
+ await b(v(S));
73
+ } catch (e) {
74
+ T(e instanceof Error ? e.message : "Failed to save handoff configuration");
75
+ }
76
+ };
77
+ return y.loading ? /* @__PURE__ */ m("p", {
78
+ role: "status",
79
+ children: _("botlit.handoffs.config.loading", "Loading handoff settings…")
80
+ }) : y.error ? /* @__PURE__ */ h("div", {
81
+ role: "alert",
82
+ children: [/* @__PURE__ */ m("p", { children: _("botlit.handoffs.config.error", "Handoff settings could not be loaded.") }), /* @__PURE__ */ m(o, {
83
+ variant: "outline",
84
+ onClick: () => void y.refetch(),
85
+ children: _("botlit.common.retry", "Retry")
86
+ })]
87
+ }) : /* @__PURE__ */ h(t, { children: [/* @__PURE__ */ h(i, { children: [/* @__PURE__ */ h(a, {
88
+ className: "flex items-center gap-2",
89
+ children: [_("botlit.handoffs.config.title", "Human Handoff"), S.enabled ? /* @__PURE__ */ m(c, {
90
+ variant: "success",
91
+ children: _("botlit.handoffs.config.enabled", "Enabled")
92
+ }) : /* @__PURE__ */ m(c, {
93
+ variant: "outline",
94
+ children: _("botlit.handoffs.config.disabled", "Disabled")
95
+ })]
96
+ }), /* @__PURE__ */ m(r, { children: _("botlit.handoffs.config.description", "Detect when a live conversation needs a human — an explicit request, a low-confidence reply, repeated failures, a policy-blocked response, or a custom intent — and hand it to your team automatically.") })] }), /* @__PURE__ */ h(n, {
97
+ className: "grid gap-6",
98
+ children: [
99
+ /* @__PURE__ */ h("label", {
100
+ className: "flex items-center gap-2 text-sm font-medium",
101
+ children: [/* @__PURE__ */ m("input", {
102
+ type: "checkbox",
103
+ checked: S.enabled,
104
+ onChange: (e) => E({ enabled: e.target.checked })
105
+ }), _("botlit.handoffs.config.enableLabel", "Enable automated human handoff for this agent")]
106
+ }),
107
+ /* @__PURE__ */ h("fieldset", {
108
+ className: "grid gap-3 rounded-card border border-border-seam p-4",
109
+ children: [
110
+ /* @__PURE__ */ m("legend", {
111
+ className: "px-1 text-sm font-semibold",
112
+ children: _("botlit.handoffs.config.triggers", "Triggers")
113
+ }),
114
+ /* @__PURE__ */ h("label", {
115
+ className: "flex items-center gap-2 text-sm",
116
+ children: [/* @__PURE__ */ m("input", {
117
+ type: "checkbox",
118
+ checked: S.explicitRequest,
119
+ onChange: (e) => E({ explicitRequest: e.target.checked })
120
+ }), _("botlit.handoffs.config.explicitRequest", "End user asks for a human (\"speak to a human\", \"talk to a person\", …)")]
121
+ }),
122
+ /* @__PURE__ */ h("div", {
123
+ className: "flex flex-wrap items-center gap-2 text-sm",
124
+ children: [/* @__PURE__ */ h("label", {
125
+ className: "flex items-center gap-2",
126
+ children: [/* @__PURE__ */ m("input", {
127
+ type: "checkbox",
128
+ checked: S.lowConfidence,
129
+ onChange: (e) => E({ lowConfidence: e.target.checked })
130
+ }), _("botlit.handoffs.config.lowConfidence", "Reply confidence below")]
131
+ }), /* @__PURE__ */ m(s, {
132
+ className: "w-24",
133
+ inputMode: "decimal",
134
+ value: S.lowConfidenceThreshold,
135
+ onChange: (e) => E({ lowConfidenceThreshold: e.target.value }),
136
+ "aria-label": _("botlit.handoffs.config.lowConfidenceThreshold", "Confidence threshold")
137
+ })]
138
+ }),
139
+ /* @__PURE__ */ h("div", {
140
+ className: "flex flex-wrap items-center gap-2 text-sm",
141
+ children: [/* @__PURE__ */ h("label", {
142
+ className: "flex items-center gap-2",
143
+ children: [/* @__PURE__ */ m("input", {
144
+ type: "checkbox",
145
+ checked: S.repeatedFailures,
146
+ onChange: (e) => E({ repeatedFailures: e.target.checked })
147
+ }), _("botlit.handoffs.config.repeatedFailures", "This many consecutive failed runs:")]
148
+ }), /* @__PURE__ */ m(s, {
149
+ className: "w-24",
150
+ inputMode: "numeric",
151
+ value: S.repeatedFailuresConsecutive,
152
+ onChange: (e) => E({ repeatedFailuresConsecutive: e.target.value }),
153
+ "aria-label": _("botlit.handoffs.config.repeatedFailuresCount", "Consecutive failure count")
154
+ })]
155
+ }),
156
+ /* @__PURE__ */ h("label", {
157
+ className: "flex items-center gap-2 text-sm",
158
+ children: [/* @__PURE__ */ m("input", {
159
+ type: "checkbox",
160
+ checked: S.policyRefusal,
161
+ onChange: (e) => E({ policyRefusal: e.target.checked })
162
+ }), _("botlit.handoffs.config.policyRefusal", "Reply was blocked by a workspace content policy")]
163
+ }),
164
+ /* @__PURE__ */ h("label", {
165
+ className: "grid gap-1 text-sm",
166
+ children: [_("botlit.handoffs.config.customIntents", "Custom intents (one per line: name|pattern|text or regex)"), /* @__PURE__ */ m("textarea", {
167
+ className: "min-h-20 rounded-md border border-border-default bg-bg-surface px-3 py-2 font-mono text-xs",
168
+ value: S.customIntentRows,
169
+ onChange: (e) => E({ customIntentRows: e.target.value }),
170
+ placeholder: "refund rage|refund me|text\ncancel order|cancel\\s+order|regex"
171
+ })]
172
+ })
173
+ ]
174
+ }),
175
+ /* @__PURE__ */ h("fieldset", {
176
+ className: "grid gap-3 rounded-card border border-border-seam p-4",
177
+ children: [
178
+ /* @__PURE__ */ m("legend", {
179
+ className: "px-1 text-sm font-semibold",
180
+ children: _("botlit.handoffs.config.targets", "Who takes over")
181
+ }),
182
+ /* @__PURE__ */ h("label", {
183
+ className: "grid gap-1 text-sm",
184
+ children: [_("botlit.handoffs.config.targetUsers", "Specific users (auth user ids, comma-separated)"), /* @__PURE__ */ m(s, {
185
+ value: S.targetUserIds,
186
+ onChange: (e) => E({ targetUserIds: e.target.value }),
187
+ placeholder: "user-id-1, user-id-2"
188
+ })]
189
+ }),
190
+ /* @__PURE__ */ h("label", {
191
+ className: "grid gap-1 text-sm",
192
+ children: [_("botlit.handoffs.config.targetRole", "Or a workspace role (e.g. admin, owner)"), /* @__PURE__ */ m(s, {
193
+ value: S.targetRole,
194
+ onChange: (e) => E({ targetRole: e.target.value }),
195
+ placeholder: "admin"
196
+ })]
197
+ })
198
+ ]
199
+ }),
200
+ /* @__PURE__ */ h("fieldset", {
201
+ className: "grid gap-3 rounded-card border border-border-seam p-4",
202
+ children: [/* @__PURE__ */ m("legend", {
203
+ className: "px-1 text-sm font-semibold",
204
+ children: _("botlit.handoffs.config.notify", "Notify")
205
+ }), [
206
+ [
207
+ "notifyInApp",
208
+ "botlit.handoffs.config.notifyInApp",
209
+ "In-app notification"
210
+ ],
211
+ [
212
+ "notifyEmail",
213
+ "botlit.handoffs.config.notifyEmail",
214
+ "Email"
215
+ ],
216
+ [
217
+ "notifyPush",
218
+ "botlit.handoffs.config.notifyPush",
219
+ "Push (mobile/desktop)"
220
+ ]
221
+ ].map(([e, t, n]) => /* @__PURE__ */ h("label", {
222
+ className: "flex items-center gap-2 text-sm",
223
+ children: [/* @__PURE__ */ m("input", {
224
+ type: "checkbox",
225
+ checked: S[e],
226
+ onChange: (t) => E({ [e]: t.target.checked })
227
+ }), _(t, n)]
228
+ }, e))]
229
+ }),
230
+ /* @__PURE__ */ h("fieldset", {
231
+ className: "grid gap-3 rounded-card border border-border-seam p-4",
232
+ children: [
233
+ /* @__PURE__ */ m("legend", {
234
+ className: "px-1 text-sm font-semibold",
235
+ children: _("botlit.handoffs.config.behaviour", "While a handoff is pending")
236
+ }),
237
+ /* @__PURE__ */ h("label", {
238
+ className: "grid gap-1 text-sm",
239
+ children: [_("botlit.handoffs.config.fallbackBehaviour", "Fallback behaviour"), /* @__PURE__ */ h("select", {
240
+ className: "h-10 rounded-md border border-border-default bg-bg-surface px-3",
241
+ value: S.fallbackBehavior,
242
+ onChange: (e) => E({ fallbackBehavior: e.target.value }),
243
+ children: [/* @__PURE__ */ m("option", {
244
+ value: "CONTINUE",
245
+ children: _("botlit.handoffs.config.fallbackContinue", "Bot keeps answering until a human accepts")
246
+ }), /* @__PURE__ */ m("option", {
247
+ value: "ABSTAIN",
248
+ children: _("botlit.handoffs.config.fallbackAbstain", "Bot stops replying as soon as a handoff opens")
249
+ })]
250
+ })]
251
+ }),
252
+ /* @__PURE__ */ h("label", {
253
+ className: "grid gap-1 text-sm",
254
+ children: [_("botlit.handoffs.config.handoffMessage", "Message shown to the end user when a handoff opens"), /* @__PURE__ */ m(s, {
255
+ value: S.handoffMessage,
256
+ onChange: (e) => E({ handoffMessage: e.target.value }),
257
+ placeholder: "You're being connected with a human…"
258
+ })]
259
+ })
260
+ ]
261
+ }),
262
+ w ? /* @__PURE__ */ m("p", {
263
+ role: "alert",
264
+ className: "text-sm text-status-danger-text",
265
+ children: w
266
+ }) : null,
267
+ x.error && !w ? /* @__PURE__ */ m("p", {
268
+ role: "alert",
269
+ className: "text-sm text-status-danger-text",
270
+ children: x.error.message
271
+ }) : null,
272
+ x.data ? /* @__PURE__ */ m("p", {
273
+ className: "text-sm text-status-success-text",
274
+ children: _("botlit.handoffs.config.saved", "Handoff configuration saved.")
275
+ }) : null,
276
+ /* @__PURE__ */ m("div", { children: /* @__PURE__ */ m(o, {
277
+ onClick: () => void D(),
278
+ disabled: x.loading,
279
+ children: x.loading ? _("botlit.handoffs.config.saving", "Saving…") : _("botlit.handoffs.config.save", "Save handoff settings")
280
+ }) })
281
+ ]
282
+ })] });
283
+ };
284
+ export { y as HandoffConfigPanel };
285
+
286
+ //# sourceMappingURL=HandoffConfigPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HandoffConfigPanel.js","names":["draftFrom","config","intent","BotmanorHandoffFallbackBehavior","numberOr","parsed","value","min","max","fallback","buildInput","draft","line","name","pattern","kind","HandoffConfigPanel","t","useTr","useHandoffConfig","agentId","save","saveState","useUpsertHandoffConfig","setDraft","useState","saveError","setSaveError","patch","current","partial","onSave","error","Button","Card","CardHeader","CardTitle","Badge","CardDescription","CardContent","event","Input","key","labelKey","label"],"sources":["../../../src/botlit/components/HandoffConfigPanel.tsx"],"sourcesContent":["/**\n * Handoff Config Panel (BOFF-5813)\n * @module botlit/components\n *\n * Per-agent escalation configuration: which triggers hand a conversation to\n * a human, who gets notified, and how the bot behaves while a handoff is\n * pending. Saved through `upsertHandoffConfig` on wspace-botmanor-svc.\n */\nimport type { FC } from 'react';\nimport { useEffect, useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from './Card';\nimport { Button } from './Button';\nimport { Input } from './Input';\nimport { Badge } from './Badge';\nimport { useHandoffConfig, useUpsertHandoffConfig } from '../hooks';\nimport type { HandoffConfigRecord } from '../hooks';\nimport {\n BotmanorHandoffFallbackBehavior,\n type BotmanorHandoffConfigInput,\n} from '../../generated/wspace-types';\n\ninterface DraftState {\n enabled: boolean;\n explicitRequest: boolean;\n lowConfidence: boolean;\n lowConfidenceThreshold: string;\n repeatedFailures: boolean;\n repeatedFailuresConsecutive: string;\n policyRefusal: boolean;\n customIntentRows: string; // \"name|pattern|regex\" per line\n targetUserIds: string; // comma-separated\n targetRole: string;\n notifyInApp: boolean;\n notifyEmail: boolean;\n notifyPush: boolean;\n fallbackBehavior: BotmanorHandoffFallbackBehavior;\n handoffMessage: string;\n}\n\nfunction draftFrom(config: HandoffConfigRecord | null | undefined): DraftState {\n return {\n enabled: config?.enabled ?? false,\n explicitRequest: config?.explicitRequest ?? true,\n lowConfidence: config?.lowConfidence ?? false,\n lowConfidenceThreshold: String(config?.lowConfidenceThreshold ?? 0.3),\n repeatedFailures: config?.repeatedFailures ?? false,\n repeatedFailuresConsecutive: String(config?.repeatedFailuresConsecutive ?? 3),\n policyRefusal: config?.policyRefusal ?? false,\n customIntentRows: (config?.customIntents ?? [])\n .map((intent) => `${intent.name}|${intent.pattern}|${intent.isRegex ? 'regex' : 'text'}`)\n .join('\\n'),\n targetUserIds: (config?.targetUserIds ?? []).join(', '),\n targetRole: config?.targetRole ?? '',\n notifyInApp: config?.notifyInApp ?? true,\n notifyEmail: config?.notifyEmail ?? false,\n notifyPush: config?.notifyPush ?? false,\n fallbackBehavior: config?.fallbackBehavior ?? BotmanorHandoffFallbackBehavior.Continue,\n handoffMessage: config?.handoffMessage ?? '',\n };\n}\n\n/** Parse a free-text numeric field, falling back and clamping to the bounds the backend enforces. */\nfunction numberOr(value: string, fallback: number, min: number, max: number): number {\n const parsed = Number(value);\n if (!Number.isFinite(parsed)) return fallback;\n return Math.min(Math.max(parsed, min), max);\n}\n\nfunction buildInput(draft: DraftState): BotmanorHandoffConfigInput {\n return {\n enabled: draft.enabled,\n explicitRequest: draft.explicitRequest,\n lowConfidence: draft.lowConfidence,\n lowConfidenceThreshold: numberOr(draft.lowConfidenceThreshold, 0.3, 0, 1),\n repeatedFailures: draft.repeatedFailures,\n repeatedFailuresConsecutive: Math.trunc(numberOr(draft.repeatedFailuresConsecutive, 3, 2, 10)),\n policyRefusal: draft.policyRefusal,\n customIntents: draft.customIntentRows\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => {\n const [name = '', pattern = '', kind = 'text'] = line.split('|');\n return { name: name.trim(), pattern: pattern.trim(), isRegex: kind.trim() === 'regex' };\n }),\n targetUserIds: draft.targetUserIds\n .split(',')\n .map((value) => value.trim())\n .filter(Boolean),\n targetRole: draft.targetRole.trim() || null,\n notifyInApp: draft.notifyInApp,\n notifyEmail: draft.notifyEmail,\n notifyPush: draft.notifyPush,\n fallbackBehavior: draft.fallbackBehavior,\n handoffMessage: draft.handoffMessage.trim() || null,\n };\n}\n\nexport const HandoffConfigPanel: FC<{ agentId: string }> = ({ agentId }) => {\n const t = useTr();\n const config = useHandoffConfig(agentId);\n const [save, saveState] = useUpsertHandoffConfig(agentId);\n const [draft, setDraft] = useState<DraftState>(() => draftFrom(config.data));\n const [saveError, setSaveError] = useState<string | null>(null);\n\n useEffect(() => {\n if (config.data) setDraft(draftFrom(config.data));\n }, [config.data]);\n\n const patch = (partial: Partial<DraftState>) =>\n setDraft((current) => ({ ...current, ...partial }));\n\n const onSave = async () => {\n setSaveError(null);\n try {\n await save(buildInput(draft));\n } catch (error) {\n setSaveError(error instanceof Error ? error.message : 'Failed to save handoff configuration');\n }\n };\n\n if (config.loading)\n return <p role=\"status\">{t('botlit.handoffs.config.loading', 'Loading handoff settings…')}</p>;\n if (config.error) {\n return (\n <div role=\"alert\">\n <p>{t('botlit.handoffs.config.error', 'Handoff settings could not be loaded.')}</p>\n <Button variant=\"outline\" onClick={() => void config.refetch()}>\n {t('botlit.common.retry', 'Retry')}\n </Button>\n </div>\n );\n }\n\n return (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n {t('botlit.handoffs.config.title', 'Human Handoff')}\n {draft.enabled ? (\n <Badge variant=\"success\">{t('botlit.handoffs.config.enabled', 'Enabled')}</Badge>\n ) : (\n <Badge variant=\"outline\">{t('botlit.handoffs.config.disabled', 'Disabled')}</Badge>\n )}\n </CardTitle>\n <CardDescription>\n {t(\n 'botlit.handoffs.config.description',\n 'Detect when a live conversation needs a human — an explicit request, a low-confidence reply, repeated failures, a policy-blocked response, or a custom intent — and hand it to your team automatically.'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"grid gap-6\">\n <label className=\"flex items-center gap-2 text-sm font-medium\">\n <input\n type=\"checkbox\"\n checked={draft.enabled}\n onChange={(event) => patch({ enabled: event.target.checked })}\n />\n {t('botlit.handoffs.config.enableLabel', 'Enable automated human handoff for this agent')}\n </label>\n\n <fieldset className=\"grid gap-3 rounded-card border border-border-seam p-4\">\n <legend className=\"px-1 text-sm font-semibold\">\n {t('botlit.handoffs.config.triggers', 'Triggers')}\n </legend>\n\n <label className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={draft.explicitRequest}\n onChange={(event) => patch({ explicitRequest: event.target.checked })}\n />\n {t(\n 'botlit.handoffs.config.explicitRequest',\n 'End user asks for a human (\"speak to a human\", \"talk to a person\", …)'\n )}\n </label>\n\n <div className=\"flex flex-wrap items-center gap-2 text-sm\">\n <label className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n checked={draft.lowConfidence}\n onChange={(event) => patch({ lowConfidence: event.target.checked })}\n />\n {t('botlit.handoffs.config.lowConfidence', 'Reply confidence below')}\n </label>\n <Input\n className=\"w-24\"\n inputMode=\"decimal\"\n value={draft.lowConfidenceThreshold}\n onChange={(event) => patch({ lowConfidenceThreshold: event.target.value })}\n aria-label={t(\n 'botlit.handoffs.config.lowConfidenceThreshold',\n 'Confidence threshold'\n )}\n />\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2 text-sm\">\n <label className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n checked={draft.repeatedFailures}\n onChange={(event) => patch({ repeatedFailures: event.target.checked })}\n />\n {t('botlit.handoffs.config.repeatedFailures', 'This many consecutive failed runs:')}\n </label>\n <Input\n className=\"w-24\"\n inputMode=\"numeric\"\n value={draft.repeatedFailuresConsecutive}\n onChange={(event) => patch({ repeatedFailuresConsecutive: event.target.value })}\n aria-label={t(\n 'botlit.handoffs.config.repeatedFailuresCount',\n 'Consecutive failure count'\n )}\n />\n </div>\n\n <label className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={draft.policyRefusal}\n onChange={(event) => patch({ policyRefusal: event.target.checked })}\n />\n {t(\n 'botlit.handoffs.config.policyRefusal',\n 'Reply was blocked by a workspace content policy'\n )}\n </label>\n\n <label className=\"grid gap-1 text-sm\">\n {t(\n 'botlit.handoffs.config.customIntents',\n 'Custom intents (one per line: name|pattern|text or regex)'\n )}\n <textarea\n className=\"min-h-20 rounded-md border border-border-default bg-bg-surface px-3 py-2 font-mono text-xs\"\n value={draft.customIntentRows}\n onChange={(event) => patch({ customIntentRows: event.target.value })}\n placeholder={'refund rage|refund me|text\\ncancel order|cancel\\\\s+order|regex'}\n />\n </label>\n </fieldset>\n\n <fieldset className=\"grid gap-3 rounded-card border border-border-seam p-4\">\n <legend className=\"px-1 text-sm font-semibold\">\n {t('botlit.handoffs.config.targets', 'Who takes over')}\n </legend>\n <label className=\"grid gap-1 text-sm\">\n {t(\n 'botlit.handoffs.config.targetUsers',\n 'Specific users (auth user ids, comma-separated)'\n )}\n <Input\n value={draft.targetUserIds}\n onChange={(event) => patch({ targetUserIds: event.target.value })}\n placeholder=\"user-id-1, user-id-2\"\n />\n </label>\n <label className=\"grid gap-1 text-sm\">\n {t('botlit.handoffs.config.targetRole', 'Or a workspace role (e.g. admin, owner)')}\n <Input\n value={draft.targetRole}\n onChange={(event) => patch({ targetRole: event.target.value })}\n placeholder=\"admin\"\n />\n </label>\n </fieldset>\n\n <fieldset className=\"grid gap-3 rounded-card border border-border-seam p-4\">\n <legend className=\"px-1 text-sm font-semibold\">\n {t('botlit.handoffs.config.notify', 'Notify')}\n </legend>\n {(\n [\n ['notifyInApp', 'botlit.handoffs.config.notifyInApp', 'In-app notification'],\n ['notifyEmail', 'botlit.handoffs.config.notifyEmail', 'Email'],\n ['notifyPush', 'botlit.handoffs.config.notifyPush', 'Push (mobile/desktop)'],\n ] as const\n ).map(([key, labelKey, label]) => (\n <label key={key} className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={draft[key]}\n onChange={(event) => patch({ [key]: event.target.checked })}\n />\n {t(labelKey, label)}\n </label>\n ))}\n </fieldset>\n\n <fieldset className=\"grid gap-3 rounded-card border border-border-seam p-4\">\n <legend className=\"px-1 text-sm font-semibold\">\n {t('botlit.handoffs.config.behaviour', 'While a handoff is pending')}\n </legend>\n <label className=\"grid gap-1 text-sm\">\n {t('botlit.handoffs.config.fallbackBehaviour', 'Fallback behaviour')}\n <select\n className=\"h-10 rounded-md border border-border-default bg-bg-surface px-3\"\n value={draft.fallbackBehavior}\n onChange={(event) =>\n patch({ fallbackBehavior: event.target.value as BotmanorHandoffFallbackBehavior })\n }\n >\n <option value=\"CONTINUE\">\n {t(\n 'botlit.handoffs.config.fallbackContinue',\n 'Bot keeps answering until a human accepts'\n )}\n </option>\n <option value=\"ABSTAIN\">\n {t(\n 'botlit.handoffs.config.fallbackAbstain',\n 'Bot stops replying as soon as a handoff opens'\n )}\n </option>\n </select>\n </label>\n <label className=\"grid gap-1 text-sm\">\n {t(\n 'botlit.handoffs.config.handoffMessage',\n 'Message shown to the end user when a handoff opens'\n )}\n <Input\n value={draft.handoffMessage}\n onChange={(event) => patch({ handoffMessage: event.target.value })}\n placeholder=\"You're being connected with a human…\"\n />\n </label>\n </fieldset>\n\n {saveError ? (\n <p role=\"alert\" className=\"text-sm text-status-danger-text\">\n {saveError}\n </p>\n ) : null}\n {saveState.error && !saveError ? (\n <p role=\"alert\" className=\"text-sm text-status-danger-text\">\n {saveState.error.message}\n </p>\n ) : null}\n {saveState.data ? (\n <p className=\"text-sm text-status-success-text\">\n {t('botlit.handoffs.config.saved', 'Handoff configuration saved.')}\n </p>\n ) : null}\n\n <div>\n <Button onClick={() => void onSave()} disabled={saveState.loading}>\n {saveState.loading\n ? t('botlit.handoffs.config.saving', 'Saving…')\n : t('botlit.handoffs.config.save', 'Save handoff settings')}\n </Button>\n </div>\n </CardContent>\n </Card>\n );\n};\n"],"mappings":"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"}
@@ -33,3 +33,5 @@ export { useMyUserPlatformConnection, useInitiateSlackConnect, useCompleteSlackC
33
33
  export type { UserPlatformConnectionData, GlobalChannelData } from './useUserPlatformConnection';
34
34
  export { useAiPredictions, useSetAiPredictionStatus, useSupervisorConfig, useConfigureSupervisor, useRunSupervisorNow, useSupervisorRuns, aiOperationsKeys, predictionSeverity, predictionSubjectName, } from './useAiOperations';
35
35
  export type { AiPredictionRecord, AiPredictionsFilter, SupervisorConfigRecord, SupervisorRunRecord, RunSupervisorNowResult, } from './useAiOperations';
36
+ export { useHandoffConfig, useHandoffQueue, useConversationHandoff, useUpsertHandoffConfig, useRequestHandoff, useAcceptHandoff, useReleaseHandoff, useResolveHandoff, useRejectHandoff, isActiveHandoff, ACTIVE_HANDOFF_STATUSES, } from './useHandoffs';
37
+ export type { HandoffConfigRecord, HandoffCustomIntentRecord, HandoffEventRecord, HandoffRecord, } from './useHandoffs';
@@ -15,4 +15,5 @@ import { storePackageDescription as ee, storePackageName as te, useInstallPackag
15
15
  import "./useLLMProviders.js";
16
16
  import { useInitiateSlackConnect as le, useLinkIntegrationConnection as ue, useMyUserPlatformConnection as de, useRevokeSlackConnection as fe, useToggleSlackNotifications as pe } from "./useUserPlatformConnection.js";
17
17
  import { useConfigureSupervisor as me, useRunSupervisorNow as he, useSupervisorConfig as ge, useSupervisorRuns as _e } from "./useAiOperations.js";
18
- export { m as a2aAgentSkillCount, r as isMCPServerHealthy, i as mcpServerDescription, a as mcpServerEndpoint, R as promptTemplateVariables, g as routeMetadataString, ee as storePackageDescription, te as storePackageName, G as summariseExecutions, h as useA2AAgents, t as useAgents, j as useApplyRetention, _ as useBotChannelRoutes, e as useBots, q as useBucket, J as useBucketTree, Y as useBuckets, v as useChannelConnector, y as useChannelConnectors, b as useChannelRoutes, X as useChildBuckets, me as useConfigureSupervisor, Z as useCreateBucket, x as useCreateChannelConnector, S as useCreateChannelRoute, o as useCreateMCPServer, E as useCreatePolicy, z as useCreatePromptTemplate, N as useCreateSkill, Q as useDeleteBucket, C as useDeleteChannelConnector, w as useDeleteChannelRoute, s as useDeleteMCPServer, D as useDeletePolicy, B as useDeletePromptTemplate, P as useDeleteSkill, K as useExecutions, le as useInitiateSlackConnect, ne as useInstallPackage, re as useInstalledPackages, ue as useLinkIntegrationConnection, c as useMCPResources, l as useMCPServer, u as useMCPTools, de as useMyUserPlatformConnection, ie as usePinPackageVersion, O as usePolicies, k as usePolicy, V as usePromptTemplate, H as usePromptTemplates, U as useRenderPromptTemplate, M as useRetentionStatus, n as useRetrievalProfiles, fe as useRevokeSlackConnection, he as useRunSupervisorNow, F as useSkill, I as useSkills, ae as useStorePackage, oe as useStorePackages, ge as useSupervisorConfig, _e as useSupervisorRuns, d as useTestMCPConnection, pe as useToggleSlackNotifications, se as useUninstallPackage, $ as useUpdateBucket, T as useUpdateChannelConnector, ce as useUpdateInstalledPackage, f as useUpdateMCPServer, p as useUpdateMCPTool, A as useUpdatePolicy, W as useUpdatePromptTemplate, L as useUpdateSkill };
18
+ import { useAcceptHandoff as ve, useHandoffConfig as ye, useHandoffQueue as be, useRejectHandoff as xe, useReleaseHandoff as Se, useResolveHandoff as Ce, useUpsertHandoffConfig as we } from "./useHandoffs.js";
19
+ export { m as a2aAgentSkillCount, r as isMCPServerHealthy, i as mcpServerDescription, a as mcpServerEndpoint, R as promptTemplateVariables, g as routeMetadataString, ee as storePackageDescription, te as storePackageName, G as summariseExecutions, h as useA2AAgents, ve as useAcceptHandoff, t as useAgents, j as useApplyRetention, _ as useBotChannelRoutes, e as useBots, q as useBucket, J as useBucketTree, Y as useBuckets, v as useChannelConnector, y as useChannelConnectors, b as useChannelRoutes, X as useChildBuckets, me as useConfigureSupervisor, Z as useCreateBucket, x as useCreateChannelConnector, S as useCreateChannelRoute, o as useCreateMCPServer, E as useCreatePolicy, z as useCreatePromptTemplate, N as useCreateSkill, Q as useDeleteBucket, C as useDeleteChannelConnector, w as useDeleteChannelRoute, s as useDeleteMCPServer, D as useDeletePolicy, B as useDeletePromptTemplate, P as useDeleteSkill, K as useExecutions, ye as useHandoffConfig, be as useHandoffQueue, le as useInitiateSlackConnect, ne as useInstallPackage, re as useInstalledPackages, ue as useLinkIntegrationConnection, c as useMCPResources, l as useMCPServer, u as useMCPTools, de as useMyUserPlatformConnection, ie as usePinPackageVersion, O as usePolicies, k as usePolicy, V as usePromptTemplate, H as usePromptTemplates, xe as useRejectHandoff, Se as useReleaseHandoff, U as useRenderPromptTemplate, Ce as useResolveHandoff, M as useRetentionStatus, n as useRetrievalProfiles, fe as useRevokeSlackConnection, he as useRunSupervisorNow, F as useSkill, I as useSkills, ae as useStorePackage, oe as useStorePackages, ge as useSupervisorConfig, _e as useSupervisorRuns, d as useTestMCPConnection, pe as useToggleSlackNotifications, se as useUninstallPackage, $ as useUpdateBucket, T as useUpdateChannelConnector, ce as useUpdateInstalledPackage, f as useUpdateMCPServer, p as useUpdateMCPTool, A as useUpdatePolicy, W as useUpdatePromptTemplate, L as useUpdateSkill, we as useUpsertHandoffConfig };
@@ -0,0 +1,78 @@
1
+ import { BotmanorHandoffFallbackBehavior, BotmanorHandoffStatus, BotmanorHandoffTrigger, BotmanorHandoffConfigInput } from '../../generated/wspace-types';
2
+ import { MutationState, QueryResult } from './internal/workspaceGateway';
3
+ export interface HandoffCustomIntentRecord {
4
+ name: string;
5
+ pattern: string;
6
+ isRegex: boolean;
7
+ }
8
+ export interface HandoffConfigRecord {
9
+ agentId: string;
10
+ enabled: boolean;
11
+ explicitRequest: boolean;
12
+ lowConfidence: boolean;
13
+ lowConfidenceThreshold: number;
14
+ repeatedFailures: boolean;
15
+ repeatedFailuresConsecutive: number;
16
+ policyRefusal: boolean;
17
+ customIntents: HandoffCustomIntentRecord[];
18
+ targetUserIds: string[];
19
+ targetRole?: string | null;
20
+ notifyInApp: boolean;
21
+ notifyEmail: boolean;
22
+ notifyPush: boolean;
23
+ fallbackBehavior: BotmanorHandoffFallbackBehavior;
24
+ handoffMessage?: string | null;
25
+ updatedAt?: string | null;
26
+ }
27
+ export interface HandoffEventRecord {
28
+ at: string;
29
+ actorId: string;
30
+ from?: BotmanorHandoffStatus | null;
31
+ to: BotmanorHandoffStatus;
32
+ note?: string | null;
33
+ }
34
+ export interface HandoffRecord {
35
+ id: string;
36
+ agentId: string;
37
+ conversationKey: string;
38
+ conversationId?: string | null;
39
+ status: BotmanorHandoffStatus;
40
+ trigger: BotmanorHandoffTrigger;
41
+ reason: string;
42
+ userMessage?: string | null;
43
+ assignedToId?: string | null;
44
+ executionId?: string | null;
45
+ events: HandoffEventRecord[];
46
+ createdAt: string;
47
+ acceptedAt?: string | null;
48
+ resolvedAt?: string | null;
49
+ releasedAt?: string | null;
50
+ }
51
+ export declare const ACTIVE_HANDOFF_STATUSES: readonly BotmanorHandoffStatus[];
52
+ export declare function isActiveHandoff(status: BotmanorHandoffStatus): boolean;
53
+ export declare function useHandoffConfig(agentId: string | undefined): QueryResult<HandoffConfigRecord | null>;
54
+ export interface HandoffQueueResult {
55
+ items: HandoffRecord[];
56
+ total: number;
57
+ hasMore: boolean;
58
+ }
59
+ export declare function useHandoffQueue(options: {
60
+ agentId?: string;
61
+ statuses?: BotmanorHandoffStatus[];
62
+ }): QueryResult<HandoffQueueResult>;
63
+ export declare function useConversationHandoff(agentId: string | undefined, conversationKey: string | undefined): QueryResult<HandoffRecord | null>;
64
+ export declare function useUpsertHandoffConfig(agentId: string): readonly [(input: BotmanorHandoffConfigInput) => Promise<HandoffConfigRecord>, MutationState<HandoffConfigRecord>];
65
+ export declare function useRequestHandoff(): readonly [(input: {
66
+ agentId: string;
67
+ conversationKey: string;
68
+ reason?: string;
69
+ }) => Promise<HandoffRecord>, MutationState<HandoffRecord>];
70
+ interface HandoffTransitionResult {
71
+ id: string;
72
+ status: BotmanorHandoffStatus;
73
+ }
74
+ export declare function useAcceptHandoff(): readonly [(id: string) => Promise<HandoffTransitionResult>, MutationState<HandoffTransitionResult>];
75
+ export declare function useReleaseHandoff(): readonly [(id: string) => Promise<HandoffTransitionResult>, MutationState<HandoffTransitionResult>];
76
+ export declare function useResolveHandoff(): readonly [(id: string) => Promise<HandoffTransitionResult>, MutationState<HandoffTransitionResult>];
77
+ export declare function useRejectHandoff(): readonly [(id: string) => Promise<HandoffTransitionResult>, MutationState<HandoffTransitionResult>];
78
+ export {};
@@ -0,0 +1,77 @@
1
+ import { AcceptHandoffDocument as e, HandoffConfigDocument as t, HandoffQueueDocument as n, RejectHandoffDocument as r, ReleaseHandoffDocument as i, ResolveHandoffDocument as a, UpsertHandoffConfigDocument as o } from "../../generated/wspace-operations.js";
2
+ import { BotmanorHandoffStatus as s } from "../../generated/wspace-types.js";
3
+ import { useWorkspaceId as c, useWorkspaceMutation as l, useWorkspaceQuery as u } from "./internal/workspaceGateway.js";
4
+ s.Requested, s.Assigned, s.Accepted;
5
+ function d(e) {
6
+ let n = c();
7
+ return u({
8
+ document: t,
9
+ variables: { agentId: e ?? "" },
10
+ select: (e) => e?.handoffConfig ?? null,
11
+ fallback: null,
12
+ enabled: !!(n && e),
13
+ errorMessage: "Failed to load handoff configuration"
14
+ });
15
+ }
16
+ var f = 100;
17
+ function p(e) {
18
+ let t = c();
19
+ return u({
20
+ document: n,
21
+ variables: {
22
+ ...e.agentId ? { agentId: e.agentId } : {},
23
+ ...e.statuses && e.statuses.length > 0 ? { statuses: e.statuses } : {},
24
+ pagination: {
25
+ limit: f,
26
+ offset: 0
27
+ }
28
+ },
29
+ select: (e) => ({
30
+ items: e?.handoffQueue.items ?? [],
31
+ total: e?.handoffQueue.total ?? 0,
32
+ hasMore: e?.handoffQueue.hasMore ?? !1
33
+ }),
34
+ fallback: {
35
+ items: [],
36
+ total: 0,
37
+ hasMore: !1
38
+ },
39
+ enabled: !!t,
40
+ errorMessage: "Failed to load the handoff queue"
41
+ });
42
+ }
43
+ function m(e) {
44
+ let [t, n] = l({
45
+ document: o,
46
+ variables: (t) => ({
47
+ agentId: e,
48
+ input: t
49
+ }),
50
+ select: (e) => e?.upsertHandoffConfig,
51
+ errorMessage: "Failed to save handoff configuration"
52
+ });
53
+ return [t, n];
54
+ }
55
+ function h(e, t, n) {
56
+ return l({
57
+ document: e,
58
+ variables: (e) => ({ id: e }),
59
+ select: t,
60
+ errorMessage: n
61
+ });
62
+ }
63
+ function g() {
64
+ return h(e, (e) => e?.acceptHandoff, "Failed to accept the handoff");
65
+ }
66
+ function _() {
67
+ return h(i, (e) => e?.releaseHandoff, "Failed to release the handoff");
68
+ }
69
+ function v() {
70
+ return h(a, (e) => e?.resolveHandoff, "Failed to resolve the handoff");
71
+ }
72
+ function y() {
73
+ return h(r, (e) => e?.rejectHandoff, "Failed to reject the handoff");
74
+ }
75
+ export { g as useAcceptHandoff, d as useHandoffConfig, p as useHandoffQueue, y as useRejectHandoff, _ as useReleaseHandoff, v as useResolveHandoff, m as useUpsertHandoffConfig };
76
+
77
+ //# sourceMappingURL=useHandoffs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useHandoffs.js","names":["BotmanorHandoffStatus","useHandoffConfig","workspaceId","useWorkspaceId","useWorkspaceQuery","HandoffConfigDocument","agentId","data","QUEUE_PAGE_LIMIT","useHandoffQueue","HandoffQueueDocument","options","useUpsertHandoffConfig","mutate","state","useWorkspaceMutation","UpsertHandoffConfigDocument","useHandoffTransition","useAcceptHandoff","AcceptHandoffDocument","useReleaseHandoff","ReleaseHandoffDocument","useResolveHandoff","ResolveHandoffDocument","useRejectHandoff","RejectHandoffDocument"],"sources":["../../../src/botlit/hooks/useHandoffs.ts"],"sourcesContent":["/**\n * Handoff hooks (BOFF-5813)\n * @module botlit/hooks\n *\n * Backed by the live `handoffConfig` / `handoffQueue` / `conversationHandoff`\n * queries and the upsert / request / accept / release / resolve / reject\n * mutations on wspace-botmanor-svc.\n */\n\nimport {\n AcceptHandoffDocument,\n ConversationHandoffDocument,\n HandoffConfigDocument,\n HandoffQueueDocument,\n RejectHandoffDocument,\n ReleaseHandoffDocument,\n RequestHandoffDocument,\n ResolveHandoffDocument,\n UpsertHandoffConfigDocument,\n type AcceptHandoffMutation,\n type ConversationHandoffQuery,\n type HandoffConfigQuery,\n type HandoffQueueQuery,\n type RejectHandoffMutation,\n type ReleaseHandoffMutation,\n type RequestHandoffMutation,\n type ResolveHandoffMutation,\n type UpsertHandoffConfigMutation,\n} from '../../generated/wspace-operations';\nimport {\n BotmanorHandoffFallbackBehavior,\n BotmanorHandoffStatus,\n BotmanorHandoffTrigger,\n type BotmanorHandoffConfigInput,\n} from '../../generated/wspace-types';\nimport {\n useWorkspaceId,\n useWorkspaceMutation,\n useWorkspaceQuery,\n type MutationState,\n type QueryResult,\n} from './internal/workspaceGateway';\n\nexport interface HandoffCustomIntentRecord {\n name: string;\n pattern: string;\n isRegex: boolean;\n}\n\nexport interface HandoffConfigRecord {\n agentId: string;\n enabled: boolean;\n explicitRequest: boolean;\n lowConfidence: boolean;\n lowConfidenceThreshold: number;\n repeatedFailures: boolean;\n repeatedFailuresConsecutive: number;\n policyRefusal: boolean;\n customIntents: HandoffCustomIntentRecord[];\n targetUserIds: string[];\n targetRole?: string | null;\n notifyInApp: boolean;\n notifyEmail: boolean;\n notifyPush: boolean;\n fallbackBehavior: BotmanorHandoffFallbackBehavior;\n handoffMessage?: string | null;\n updatedAt?: string | null;\n}\n\nexport interface HandoffEventRecord {\n at: string;\n actorId: string;\n from?: BotmanorHandoffStatus | null;\n to: BotmanorHandoffStatus;\n note?: string | null;\n}\n\nexport interface HandoffRecord {\n id: string;\n agentId: string;\n conversationKey: string;\n conversationId?: string | null;\n status: BotmanorHandoffStatus;\n trigger: BotmanorHandoffTrigger;\n reason: string;\n userMessage?: string | null;\n assignedToId?: string | null;\n executionId?: string | null;\n events: HandoffEventRecord[];\n createdAt: string;\n acceptedAt?: string | null;\n resolvedAt?: string | null;\n releasedAt?: string | null;\n}\n\nexport const ACTIVE_HANDOFF_STATUSES: readonly BotmanorHandoffStatus[] = [\n BotmanorHandoffStatus.Requested,\n BotmanorHandoffStatus.Assigned,\n BotmanorHandoffStatus.Accepted,\n];\n\nexport function isActiveHandoff(status: BotmanorHandoffStatus): boolean {\n return ACTIVE_HANDOFF_STATUSES.includes(status);\n}\n\nexport function useHandoffConfig(\n agentId: string | undefined\n): QueryResult<HandoffConfigRecord | null> {\n const workspaceId = useWorkspaceId();\n return useWorkspaceQuery<HandoffConfigQuery, HandoffConfigRecord | null>({\n document: HandoffConfigDocument,\n variables: { agentId: agentId ?? '' },\n select: (data) => data?.handoffConfig ?? null,\n fallback: null,\n enabled: Boolean(workspaceId && agentId),\n errorMessage: 'Failed to load handoff configuration',\n });\n}\n\nexport interface HandoffQueueResult {\n items: HandoffRecord[];\n total: number;\n hasMore: boolean;\n}\n\nconst QUEUE_PAGE_LIMIT = 100;\n\nexport function useHandoffQueue(options: {\n agentId?: string;\n statuses?: BotmanorHandoffStatus[];\n}): QueryResult<HandoffQueueResult> {\n const workspaceId = useWorkspaceId();\n return useWorkspaceQuery<HandoffQueueQuery, HandoffQueueResult>({\n document: HandoffQueueDocument,\n variables: {\n ...(options.agentId ? { agentId: options.agentId } : {}),\n ...(options.statuses && options.statuses.length > 0 ? { statuses: options.statuses } : {}),\n pagination: { limit: QUEUE_PAGE_LIMIT, offset: 0 },\n },\n select: (data) => ({\n items: data?.handoffQueue.items ?? [],\n total: data?.handoffQueue.total ?? 0,\n hasMore: data?.handoffQueue.hasMore ?? false,\n }),\n fallback: { items: [], total: 0, hasMore: false },\n enabled: Boolean(workspaceId),\n errorMessage: 'Failed to load the handoff queue',\n });\n}\n\nexport function useConversationHandoff(\n agentId: string | undefined,\n conversationKey: string | undefined\n): QueryResult<HandoffRecord | null> {\n const workspaceId = useWorkspaceId();\n return useWorkspaceQuery<ConversationHandoffQuery, HandoffRecord | null>({\n document: ConversationHandoffDocument,\n variables: { agentId: agentId ?? '', conversationKey: conversationKey ?? '' },\n select: (data) => data?.conversationHandoff ?? null,\n fallback: null,\n enabled: Boolean(workspaceId && agentId && conversationKey),\n errorMessage: 'Failed to load the conversation handoff',\n });\n}\n\nexport function useUpsertHandoffConfig(agentId: string) {\n const [mutate, state] = useWorkspaceMutation<\n UpsertHandoffConfigMutation,\n BotmanorHandoffConfigInput,\n HandoffConfigRecord\n >({\n document: UpsertHandoffConfigDocument,\n variables: (input) => ({ agentId, input }),\n select: (data) => data?.upsertHandoffConfig,\n errorMessage: 'Failed to save handoff configuration',\n });\n return [mutate, state] as const;\n}\n\nexport function useRequestHandoff() {\n const [mutate, state] = useWorkspaceMutation<\n RequestHandoffMutation,\n { agentId: string; conversationKey: string; reason?: string },\n HandoffRecord\n >({\n document: RequestHandoffDocument,\n variables: (input) => ({ ...input }),\n select: (data) => data?.requestHandoff,\n errorMessage: 'Failed to request a human',\n });\n return [mutate, state] as const;\n}\n\ninterface HandoffTransitionResult {\n id: string;\n status: BotmanorHandoffStatus;\n}\n\nfunction useHandoffTransition<TMutation>(\n document: Parameters<typeof useWorkspaceMutation>[0]['document'],\n select: (data: TMutation | undefined) => HandoffTransitionResult | undefined,\n errorMessage: string\n): readonly [\n (id: string) => Promise<HandoffTransitionResult>,\n MutationState<HandoffTransitionResult>,\n] {\n return useWorkspaceMutation<TMutation, string, HandoffTransitionResult>({\n document,\n variables: (id) => ({ id }),\n select,\n errorMessage,\n });\n}\n\nexport function useAcceptHandoff() {\n return useHandoffTransition<AcceptHandoffMutation>(\n AcceptHandoffDocument,\n (data) => data?.acceptHandoff,\n 'Failed to accept the handoff'\n );\n}\n\nexport function useReleaseHandoff() {\n return useHandoffTransition<ReleaseHandoffMutation>(\n ReleaseHandoffDocument,\n (data) => data?.releaseHandoff,\n 'Failed to release the handoff'\n );\n}\n\nexport function useResolveHandoff() {\n return useHandoffTransition<ResolveHandoffMutation>(\n ResolveHandoffDocument,\n (data) => data?.resolveHandoff,\n 'Failed to resolve the handoff'\n );\n}\n\nexport function useRejectHandoff() {\n return useHandoffTransition<RejectHandoffMutation>(\n RejectHandoffDocument,\n (data) => data?.rejectHandoff,\n 'Failed to reject the handoff'\n );\n}\n"],"mappings":";;;AAgGEA,EAAsB,WACtBA,EAAsB,UACtBA,EAAsB;AAOxB,SAAgBC,EACd,GACyC;CACzC,IAAMC,IAAcC,EAAe;CACnC,OAAOC,EAAkE;EACvE,UAAUC;EACV,WAAW,EAAE,SAASC,KAAW,GAAG;EACpC,SAAS,MAASC,GAAM,iBAAiB;EACzC,UAAU;EACV,SAAS,GAAQL,KAAeI;EAChC,cAAc;CAChB,CAAC;AACH;AAQA,IAAME,IAAmB;AAEzB,SAAgBC,EAAgB,GAGI;CAClC,IAAMP,IAAcC,EAAe;CACnC,OAAOC,EAAyD;EAC9D,UAAUM;EACV,WAAW;GACT,GAAIC,EAAQ,UAAU,EAAE,SAASA,EAAQ,QAAQ,IAAI,CAAC;GACtD,GAAIA,EAAQ,YAAYA,EAAQ,SAAS,SAAS,IAAI,EAAE,UAAUA,EAAQ,SAAS,IAAI,CAAC;GACxF,YAAY;IAAE,OAAOH;IAAkB,QAAQ;GAAE;EACnD;EACA,SAAS,OAAU;GACjB,OAAOD,GAAM,aAAa,SAAS,CAAC;GACpC,OAAOA,GAAM,aAAa,SAAS;GACnC,SAASA,GAAM,aAAa,WAAW;EACzC;EACA,UAAU;GAAE,OAAO,CAAC;GAAG,OAAO;GAAG,SAAS;EAAM;EAChD,SAAS,EAAQL;EACjB,cAAc;CAChB,CAAC;AACH;AAiBA,SAAgBU,EAAuB,GAAiB;CACtD,IAAM,CAACC,GAAQC,KAASC,EAItB;EACA,UAAUC;EACV,YAAY,OAAW;GAAE;GAAS;EAAM;EACxC,SAAS,MAAST,GAAM;EACxB,cAAc;CAChB,CAAC;CACD,OAAO,CAACM,GAAQC,CAAK;AACvB;AAqBA,SAASG,EACP,GACA,GACA,GAIA;CACA,OAAOF,EAAiE;EACtE;EACA,YAAY,OAAQ,EAAE,MAAG;EACzB;EACA;CACF,CAAC;AACH;AAEA,SAAgBG,IAAmB;CACjC,OAAOD,EACLE,IACC,MAASZ,GAAM,eAChB,8BACF;AACF;AAEA,SAAgBa,IAAoB;CAClC,OAAOH,EACLI,IACC,MAASd,GAAM,gBAChB,+BACF;AACF;AAEA,SAAgBe,IAAoB;CAClC,OAAOL,EACLM,IACC,MAAShB,GAAM,gBAChB,+BACF;AACF;AAEA,SAAgBiB,IAAmB;CACjC,OAAOP,EACLQ,IACC,MAASlB,GAAM,eAChB,8BACF;AACF"}