PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.2.25
MxChat – AI Chatbot & Content Generation for WordPress v3.2.25
3.2.25 3.2.24 3.2.23 3.2.22 3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 All 156 releases
← All changes | includes/class-mxchat-tool-registry.php +65 -16 3.2.17 → 3.2.25 View file →
@@ -86,13 +86,23 @@
86 86 * Normalize a stored OPT_TOOLS entry into [ enabled(bool), usage_hint(string) ].
87 87 * Accepts BOTH the legacy bare-bool shape AND the new
88 88 * { enabled, usage_hint } object shape (back-compat, HARD — plan 27d3e6).
89 89 *
90 - * @param mixed $saved The stored entry, or null when the tool is unset.
91 - * @param bool $is_cautious Whether the tool defaults off (sensitive).
90 + * A tool may ship a catalog `default_hint` (plan caee10). It applies ONLY
91 + * when the stored entry carries no `usage_hint` KEY AT ALL — an absent key
92 + * means the owner has never been shown a hint for this tool, so seeding one
93 + * is new guidance rather than an override. A key that is PRESENT BUT EMPTY
94 + * is an owner who deliberately cleared the box, and it stays empty. That
95 + * distinction is the whole correctness of the default and it mirrors the
96 + * `array_key_exists` idiom this function already uses for `enabled`.
97 + *
98 + * @param mixed $saved The stored entry, or null when the tool is unset.
99 + * @param bool $is_cautious Whether the tool defaults off (sensitive).
100 + * @param string $default_hint Catalog-shipped hint, used only on an ABSENT key.
92 101 * @return array{0:bool,1:string}
93 102 */
94 - public static function resolve_tool_setting($saved, $is_cautious) {
103 + public static function resolve_tool_setting($saved, $is_cautious, $default_hint = '') {
104 + $default_hint = self::clip_hint($default_hint);
95 105 if (is_array($saved)) {
96 106 // Object shape. An absent 'enabled' key means the owner never turned
97 107 // this tool on → OFF. AI Tools default to ZERO active on a fresh
98 108 // install (plan d450a7: presence = active; nothing fires until the
@@ -103,16 +113,25 @@
103 113 // on by an accidental save.)
104 114 $enabled = array_key_exists('enabled', $saved)
105 115 ? (bool) $saved['enabled']
106 116 : false;
107 - $hint = isset($saved['usage_hint']) ? (string) $saved['usage_hint'] : '';
117 + // NOTE: array_key_exists, NOT isset — isset() is false for a stored
118 + // null and would silently re-seed the default over a cleared hint.
119 + $hint = array_key_exists('usage_hint', $saved)
120 + ? (string) $saved['usage_hint']
121 + : $default_hint;
108 122 return array($enabled, $hint);
109 123 }
110 124 if ($saved === null) {
111 - return array(false, ''); // unset → OFF (no tool active until added)
125 + // Unset → OFF (no tool active until added), but the catalog default
126 + // hint applies: nothing has been stored for this tool yet.
127 + return array(false, $default_hint);
112 128 }
113 - // Legacy bare-bool: a plain true/false enables/disables with no hint.
114 - return array((bool) $saved, '');
129 + // Legacy bare-bool: a plain true/false enables/disables. Written before
130 + // hints existed (pre-27d3e6), so it carries no usage_hint key either —
131 + // it gets the catalog default too, or a site that enabled the tool back
132 + // then would stay silently hint-less forever.
133 + return array((bool) $saved, $default_hint);
115 134 }
116 135
117 136 /** Trim + length-bound a usage hint before it is stored or sent to the model. */
118 137 private static function clip_hint($s) {
@@ -152,8 +171,9 @@
152 171 // customer PII
153 172 'mxchat_handle_order_history',
154 173 // disruptive handoff / data-collection flows
155 174 'mxchat_live_agent_handover', 'mxchat_telegram_live_agent_handover',
175 + 'mxchat_webhook_live_agent_handover',
156 176 'mxchat_handle_email_capture', 'mxchat_handle_form_collection',
157 177 ));
158 178 }
159 179
@@ -219,16 +239,33 @@
219 239 'mxchat_handle_email_capture' => array(
220 240 'label' => __('Collect Email', 'mxchat'),
221 241 'description' => __('Begin collecting the visitor\'s email address for the mailing list.', 'mxchat'),
222 242 ),
243 + // The two handoff tools ship a default usage hint (plan caee10).
244 + // "Escalate when you don't know" is the most-requested handoff
245 + // behavior, and the base description says only WHAT the tool does,
246 + // never WHEN — so before this, the behavior worked only for an owner
247 + // who independently guessed they had to type the condition into the
248 + // hint box. The second clause is deliberate: a bare "when you don't
249 + // know" invites the model to escalate on small talk.
223 250 'mxchat_live_agent_handover' => array(
224 - 'label' => __('Hand Off to Live Agent (Slack)', 'mxchat'),
225 - 'description' => __('Transfer the conversation to a human support agent on Slack.', 'mxchat'),
251 + 'label' => __('Hand Off to Live Agent (Slack)', 'mxchat'),
252 + 'description' => __('Transfer the conversation to a human support agent on Slack.', 'mxchat'),
253 + 'default_hint' => __('Use this when the visitor has asked something you cannot answer from the knowledge base, or has asked twice about the same unresolved problem.', 'mxchat'),
226 254 ),
227 255 'mxchat_telegram_live_agent_handover' => array(
228 - 'label' => __('Hand Off to Live Agent (Telegram)', 'mxchat'),
229 - 'description' => __('Transfer the conversation to a human support agent on Telegram.', 'mxchat'),
256 + 'label' => __('Hand Off to Live Agent (Telegram)', 'mxchat'),
257 + 'description' => __('Transfer the conversation to a human support agent on Telegram.', 'mxchat'),
258 + 'default_hint' => __('Use this when the visitor has asked something you cannot answer from the knowledge base, or has asked twice about the same unresolved problem.', 'mxchat'),
230 259 ),
260 + // Webhook destination (plan d88e22): outbound-only — the handoff is
261 + // POSTed to the owner's configured URL and the conversation stays in
262 + // AI mode; the receiving system follows up out-of-band.
263 + 'mxchat_webhook_live_agent_handover' => array(
264 + 'label' => __('Hand Off to Live Agent (Webhook)', 'mxchat'),
265 + 'description' => __('Notify the site\'s human support team about this conversation via the configured webhook. The team follows up separately; you keep assisting meanwhile.', 'mxchat'),
266 + 'default_hint' => __('Use this when the visitor has asked something you cannot answer from the knowledge base, or has asked twice about the same unresolved problem.', 'mxchat'),
267 + ),
231 268 ));
232 269 }
233 270
234 271 /* ------------------------------------------------------------------ *
@@ -286,8 +323,12 @@
286 323 'ui_self_saves' => array_key_exists('ui_self_saves', $meta) ? !empty($meta['ui_self_saves']) : true,
287 324 // Admin-facing setup metadata (plan 183856) — core tools only.
288 325 'requires_key' => isset($meta['requires_key']) ? $meta['requires_key'] : '',
289 326 'setup_note' => isset($meta['setup_note']) ? $meta['setup_note'] : '',
327 + // Catalog-shipped "when to use" default (plan caee10). Applied
328 + // only when the stored entry has no usage_hint key — see
329 + // resolve_tool_setting(). Core tools only in this build.
330 + 'default_hint' => isset($meta['default_hint']) ? $meta['default_hint'] : '',
290 331 );
291 332 }
292 333
293 334 // 2) Active add-on callbacks (canonical: the live filter).
@@ -367,9 +408,13 @@
367 408 $tools = array();
368 409 foreach ($entries as $fn => $e) {
369 410 $is_cautious = in_array($fn, $cautious, true);
370 411 $saved = array_key_exists($fn, $enabled_map) ? $enabled_map[$fn] : null;
371 - list($enabled, $usage_hint) = self::resolve_tool_setting($saved, $is_cautious);
412 + list($enabled, $usage_hint) = self::resolve_tool_setting(
413 + $saved,
414 + $is_cautious,
415 + isset($e['default_hint']) ? $e['default_hint'] : ''
416 + );
372 417 $tools[] = array(
373 418 'name' => self::tool_name($fn),
374 419 'callback' => $fn,
375 420 'label' => $e['label'],
@@ -406,12 +451,13 @@
406 451 }
407 452
408 453 /**
409 454 * Withhold each live-agent handover tool outside ITS channel's availability
410 - * schedule (plans 8ccaa2 + 99d7a4). Slack and Telegram carry independent
411 - * schedules: if Slack is off-hours but Telegram is staffed, the Telegram
412 - * handoff stays offered and only the Slack one is withheld — and vice
413 - * versa. Off-hours the bot must not DANGLE a human it cannot reach, so the
455 + * schedule (plans 8ccaa2 + 99d7a4; webhook added by d88e22). Slack,
456 + * Telegram, and the webhook destination carry independent schedules: if
457 + * Slack is off-hours but Telegram is staffed, the Telegram handoff stays
458 + * offered and only the Slack one is withheld — and likewise for each other
459 + * pair. Off-hours the bot must not DANGLE a human it cannot reach, so the
414 460 * tool never reaches the model in the first place.
415 461 *
416 462 * Applied HERE and deliberately NOT in available_tools(): that function
417 463 * feeds the admin AI Tools checklist, which must keep showing the owner's
@@ -435,8 +481,11 @@
435 481 $withhold[] = 'mxchat_live_agent_handover';
436 482 }
437 483 if (!MxChat_Live_Agent_Schedule::is_within_hours('telegram')) {
438 484 $withhold[] = 'mxchat_telegram_live_agent_handover';
485 + }
486 + if (!MxChat_Live_Agent_Schedule::is_within_hours('webhook')) {
487 + $withhold[] = 'mxchat_webhook_live_agent_handover';
439 488 }
440 489 if (empty($withhold)) {
441 490 return $tools;
442 491 }