PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.5
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.5
2.4.5 2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 All 69 releases
fluent-support / app / Modules / MCP / PromptsRegistrar.php

PromptsRegistrar.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.4.5, at app/Modules/MCP/PromptsRegistrar.php

182 lines 8.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentSupport\App\Modules\MCP;
4
5 use FluentSupport\App\Modules\MCP\Support\AbilityGuard;
6
7 /**
8 * MCP prompts: ready-made starting points a person picks in their MCP client
9 * (often as a slash command). Each is an ability that returns prompt messages;
10 * the adapter lists them under prompts/list. They only write instructions, so
11 * the tools they point to still enforce every permission.
12 *
13 * Prompt text is English and not translatable, like the tool descriptions.
14 */
15 class PromptsRegistrar
16 {
17 const PERIODS = ['24h', '7d', '30d', '90d'];
18
19 public static function getDefinitions(): array
20 {
21 return [
22 'fluent-support/triage-queue' => [
23 'label' => __('Triage my queue', 'fluent-support'),
24 'description' => 'Go through the tickets waiting on an agent and propose an action for each, without sending anything until you approve.',
25 'input_schema' => [
26 'type' => 'object',
27 'properties' => [
28 'scope' => ['type' => 'string', 'enum' => ['mine', 'team'], 'description' => 'mine: your tickets (default). team: every ticket you can see.'],
29 ],
30 ],
31 'execute_callback' => [self::class, 'triageQueue'],
32 ],
33 'fluent-support/draft-reply' => [
34 'label' => __('Draft a reply', 'fluent-support'),
35 'description' => 'Read a ticket and save a draft reply for review. Nothing is sent.',
36 'input_schema' => [
37 'type' => 'object',
38 'properties' => [
39 'ticket_id' => ['type' => 'string', 'description' => 'The ticket ID'],
40 'guidance' => ['type' => 'string', 'description' => 'Optional: what the reply should say or do'],
41 ],
42 'required' => ['ticket_id'],
43 ],
44 'execute_callback' => [self::class, 'draftReply'],
45 ],
46 'fluent-support/summarize-ticket' => [
47 'label' => __('Summarize a ticket', 'fluent-support'),
48 'description' => 'Summarize a ticket for a teammate taking it over, and optionally save the summary as an internal note.',
49 'input_schema' => [
50 'type' => 'object',
51 'properties' => [
52 'ticket_id' => ['type' => 'string', 'description' => 'The ticket ID'],
53 'save_note' => ['type' => 'string', 'enum' => ['no', 'yes'], 'description' => 'yes: save the summary as an internal note'],
54 ],
55 'required' => ['ticket_id'],
56 ],
57 'execute_callback' => [self::class, 'summarizeTicket'],
58 ],
59 'fluent-support/support-report' => [
60 'label' => __('Support report', 'fluent-support'),
61 'description' => 'Write a short report on support volume, response times and workload for a period.',
62 'input_schema' => [
63 'type' => 'object',
64 'properties' => [
65 'period' => ['type' => 'string', 'enum' => self::PERIODS, 'description' => 'Reporting period (default 7d)'],
66 ],
67 ],
68 'execute_callback' => [self::class, 'supportReport'],
69 ],
70 ];
71 }
72
73 public static function register()
74 {
75 foreach (self::getDefinitions() as $name => $definition) {
76 wp_register_ability($name, [
77 'label' => $definition['label'],
78 'description' => $definition['description'],
79 'category' => 'fluent-support',
80 'input_schema' => $definition['input_schema'],
81 'execute_callback' => $definition['execute_callback'],
82 'permission_callback' => function () use ($name) {
83 return AbilityGuard::check($name);
84 },
85 'meta' => [
86 'show_in_rest' => true,
87 'mcp' => ['public' => true, 'type' => 'prompt'],
88 'annotations' => ['readonly' => true],
89 ],
90 ]);
91 }
92 }
93
94 public static function triageQueue($params)
95 {
96 $team = (($params['scope'] ?? 'mine') === 'team');
97
98 $source = $team
99 ? '1. Call get-support-context, then list-tickets with waiting_for_reply=true, sort_by=waiting_since, order=ASC, per_page=25. Use meta.paging.next_cursor for more pages.'
100 : '1. Call get-support-context and start with my_queue.awaiting_your_reply. If awaiting_your_reply_truncated is true, call list-tickets with agent_id set to your agent ID, waiting_for_reply=true, sort_by=waiting_since, order=ASC.';
101
102 return self::messages(implode("\n", [
103 'Triage my Fluent Support queue.',
104 '',
105 $source,
106 '2. Use each row\'s preview, customer, tags and waiting time. Open a ticket with get-ticket only when the preview is not enough to decide.',
107 '3. For each ticket choose one action: reply, ask a teammate (internal note with a mention), assign, tag, close, or leave it.',
108 '4. Show me a table first: ticket, customer, waiting time, proposed action and a one-line reason. Oldest first.',
109 '5. Wait for my go-ahead. Then save replies as drafts (reply-to-ticket with draft=true) unless I say to send them. Never close or delete a ticket without my approval.',
110 ]));
111 }
112
113 public static function draftReply($params)
114 {
115 $ticketId = absint($params['ticket_id'] ?? 0);
116 $guidance = trim(sanitize_textarea_field((string) ($params['guidance'] ?? '')));
117
118 $lines = [
119 "Draft a reply to Fluent Support ticket #{$ticketId}.",
120 '',
121 "1. Call get-ticket with ticket_id={$ticketId}. Read the whole thread, the customer's previous tickets and any purchase or CRM data.",
122 '2. Read the reply_email template: the customer gets it with [YOUR MESSAGE] replaced by your reply, so leave out any greeting, sign-off or signature it already has.',
123 '3. Call list-saved-replies with a short search for this topic and reuse a saved answer when one fits.',
124 '4. Write the reply in Markdown. Answer the customer\'s latest message directly, in their language, and ask for any detail you still need.',
125 "5. Save it with reply-to-ticket, ticket_id={$ticketId}, draft=true. Do not send it. Tell me the draft ID and show me the text.",
126 ];
127
128 if ($guidance !== '') {
129 $lines[] = '';
130 $lines[] = 'My guidance for this reply: ' . $guidance;
131 }
132
133 return self::messages(implode("\n", $lines));
134 }
135
136 public static function summarizeTicket($params)
137 {
138 $ticketId = absint($params['ticket_id'] ?? 0);
139 $saveNote = (($params['save_note'] ?? 'no') === 'yes');
140
141 $lines = [
142 "Summarize Fluent Support ticket #{$ticketId} for a teammate who is taking it over.",
143 '',
144 "1. Call get-ticket with ticket_id={$ticketId} and get-ticket-activity with ticket_id={$ticketId}.",
145 '2. Cover: the problem, what has been tried, the current state, who the ticket is waiting on, and the next step.',
146 '3. Keep it under 150 words. Use the customer\'s own words for the problem where you can.',
147 ];
148
149 $lines[] = $saveNote
150 ? "4. Save the summary with add-internal-note on ticket {$ticketId}, then show it to me."
151 : '4. Show me the summary. Do not change the ticket.';
152
153 return self::messages(implode("\n", $lines));
154 }
155
156 public static function supportReport($params)
157 {
158 $period = in_array($params['period'] ?? '', self::PERIODS, true) ? $params['period'] : '7d';
159
160 return self::messages(implode("\n", [
161 "Write a Fluent Support report for the last {$period}.",
162 '',
163 "1. Call get-support-insights with period={$period}, and get-support-context.",
164 '2. Cover ticket volume and its trend, first-response and resolution times, tickets waiting on an agent versus on the customer, and each agent\'s open and closed counts.',
165 '3. List the five tickets that have waited longest on an agent.',
166 '4. End with three concrete recommendations. Keep the report under 300 words and use a table for per-agent numbers.',
167 ]));
168 }
169
170 private static function messages($text)
171 {
172 return [
173 'messages' => [
174 [
175 'role' => 'user',
176 'content' => ['type' => 'text', 'text' => $text],
177 ],
178 ],
179 ];
180 }
181 }
182