@setluca/mcp 0.1.1 → 0.2.1
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.
- package/CHANGELOG.md +110 -0
- package/README.md +178 -80
- package/dist/annotations.js +45 -0
- package/dist/completions.js +110 -0
- package/dist/config.js +55 -29
- package/dist/errors.js +56 -15
- package/dist/generated/openapi-inputs.js +4324 -1429
- package/dist/generated/openapi-outputs.js +21992 -8516
- package/dist/generated/route-catalog.js +1480 -0
- package/dist/http.js +97 -103
- package/dist/index.js +16 -10
- package/dist/oauth-resolver.js +59 -37
- package/dist/observability.js +12 -4
- package/dist/openapi-zod.js +138 -72
- package/dist/operations/catalog.js +50 -0
- package/dist/operations/groups/analytics.js +122 -0
- package/dist/operations/groups/bookings.js +189 -0
- package/dist/operations/groups/broadcasts.js +106 -0
- package/dist/operations/groups/cadences.js +14 -0
- package/dist/operations/groups/callEvents.js +131 -0
- package/dist/operations/groups/campaigns.js +132 -0
- package/dist/operations/groups/capabilities.js +8 -0
- package/dist/operations/groups/coach.js +43 -0
- package/dist/operations/groups/conversations.js +48 -0
- package/dist/operations/groups/insights.js +33 -0
- package/dist/operations/groups/integrations.js +80 -0
- package/dist/operations/groups/knowledge.js +34 -0
- package/dist/operations/groups/leads.js +101 -0
- package/dist/operations/groups/learning.js +24 -0
- package/dist/operations/groups/memory.js +27 -0
- package/dist/operations/groups/reports.js +14 -0
- package/dist/operations/groups/reviewQueue.js +57 -0
- package/dist/operations/groups/safety.js +8 -0
- package/dist/operations/groups/usage.js +13 -0
- package/dist/operations/groups/voice.js +14 -0
- package/dist/operations/groups/webhooks.js +76 -0
- package/dist/operations/manifest.js +40 -0
- package/dist/operations/registry.js +331 -0
- package/dist/operations.js +11 -780
- package/dist/optional-field.js +12 -0
- package/dist/page-shape.js +62 -0
- package/dist/pagination.js +165 -0
- package/dist/prompts.js +89 -8
- package/dist/provenance.js +18 -2
- package/dist/remote.js +80 -49
- package/dist/resilience.js +127 -0
- package/dist/resources.js +17 -2
- package/dist/scopes.js +154 -0
- package/dist/serialization.js +36 -0
- package/dist/server.js +258 -316
- package/dist/task-tools/analytics.js +168 -0
- package/dist/task-tools/bookings.js +157 -0
- package/dist/task-tools/cadences.js +65 -0
- package/dist/task-tools/calls.js +202 -0
- package/dist/task-tools/inbox.js +120 -0
- package/dist/task-tools/leads.js +123 -0
- package/dist/task-tools/runtime.js +92 -0
- package/dist/task-tools.js +21 -0
- package/dist/tool-cache.js +39 -0
- package/dist/tool.js +228 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/version.js +14 -0
- package/package.json +38 -34
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { op } from "../registry.js";
|
|
2
|
+
export const bookingsOperations = [
|
|
3
|
+
op({
|
|
4
|
+
id: "bookings.list",
|
|
5
|
+
title: "List bookings",
|
|
6
|
+
description: "List bookings. Query supports limit, cursor, status, and upcoming.",
|
|
7
|
+
redactedFields: ["bookings[].rawPayload"],
|
|
8
|
+
}),
|
|
9
|
+
op({
|
|
10
|
+
id: "bookings.create",
|
|
11
|
+
title: "Book a call",
|
|
12
|
+
description: "Create a provider-neutral booking record. Body requires leadId and slotAt.",
|
|
13
|
+
redactedFields: ["booking.rawPayload"],
|
|
14
|
+
}),
|
|
15
|
+
op({
|
|
16
|
+
id: "bookings.get",
|
|
17
|
+
title: "Get a booking",
|
|
18
|
+
description: "Read one booking: its slot, status, provider, and lead.",
|
|
19
|
+
redactedFields: ["booking.rawPayload"],
|
|
20
|
+
}),
|
|
21
|
+
op({
|
|
22
|
+
id: "bookings.availability",
|
|
23
|
+
title: "Read open call slots",
|
|
24
|
+
description: "List open slots the coach can actually be booked into. Check this before booking.",
|
|
25
|
+
}),
|
|
26
|
+
op({
|
|
27
|
+
id: "bookings.managedAvailability",
|
|
28
|
+
title: "Read Luca-managed call slots",
|
|
29
|
+
description: "List open slots for one of Luca's own call types, with calendar conflicts already removed.",
|
|
30
|
+
}),
|
|
31
|
+
op({
|
|
32
|
+
id: "bookings.types.list",
|
|
33
|
+
title: "List call types",
|
|
34
|
+
description: "List the call types a booking can use, with their duration and provider.",
|
|
35
|
+
}),
|
|
36
|
+
op({
|
|
37
|
+
id: "bookings.types.schedule",
|
|
38
|
+
title: "Read a call type's schedule",
|
|
39
|
+
description: "Read a call type's weekly schedule: the hours it can be booked and its time zone.",
|
|
40
|
+
}),
|
|
41
|
+
op({
|
|
42
|
+
id: "bookings.types.attendees",
|
|
43
|
+
title: "List a call type's attendees",
|
|
44
|
+
redactedFields: ["attendees[].email", "attendees[].name"],
|
|
45
|
+
description: "List the people invited to every call of this type, on top of the lead.",
|
|
46
|
+
}),
|
|
47
|
+
op({
|
|
48
|
+
id: "bookings.providers.list",
|
|
49
|
+
title: "List booking providers",
|
|
50
|
+
description: "List every booking provider, what each can do, and whether this coach's connection is healthy.",
|
|
51
|
+
}),
|
|
52
|
+
op({
|
|
53
|
+
id: "bookings.providers.get",
|
|
54
|
+
title: "Get a booking provider",
|
|
55
|
+
description: "List the event types and calendars in one connected provider account.",
|
|
56
|
+
}),
|
|
57
|
+
op({
|
|
58
|
+
id: "bookings.calendars.list",
|
|
59
|
+
title: "List connected calendars",
|
|
60
|
+
description: "List the calendars Luca reads for conflicts, and which one it writes new events to.",
|
|
61
|
+
}),
|
|
62
|
+
op({
|
|
63
|
+
id: "bookings.outcomeReasons.list",
|
|
64
|
+
title: "List loss reasons",
|
|
65
|
+
description: "List the reasons a sale can be lost or a call cancelled. Use one of these codes when recording an outcome.",
|
|
66
|
+
}),
|
|
67
|
+
op({
|
|
68
|
+
id: "bookings.outcome.get",
|
|
69
|
+
title: "Get a booking's outcome",
|
|
70
|
+
description: "Read where the sale stands on a booking, plus the version you send back to correct it.",
|
|
71
|
+
redactedFields: ["episode.note"],
|
|
72
|
+
}),
|
|
73
|
+
op({
|
|
74
|
+
id: "bookings.outcome.history",
|
|
75
|
+
title: "Read a booking's outcome history",
|
|
76
|
+
description: "Read every outcome ever recorded on a booking, in order. Corrections append rather than overwrite.",
|
|
77
|
+
redactedFields: ["episode.note", "events[].note"],
|
|
78
|
+
}),
|
|
79
|
+
op({
|
|
80
|
+
id: "bookings.needsOutcome",
|
|
81
|
+
title: "List calls with no outcome recorded",
|
|
82
|
+
description: "List attended calls with no outcome recorded yet. The work list for closing revenue attribution.",
|
|
83
|
+
redactedFields: ["bookings[].leadName"],
|
|
84
|
+
}),
|
|
85
|
+
op({
|
|
86
|
+
id: "bookings.lifecycleAttention",
|
|
87
|
+
title: "List bookings needing attention",
|
|
88
|
+
description: "List bookings where Luca's record and the provider's disagree and a human has to decide.",
|
|
89
|
+
redactedFields: ["bookings[].rawPayload"],
|
|
90
|
+
}),
|
|
91
|
+
op({
|
|
92
|
+
id: "bookings.brief",
|
|
93
|
+
title: "Read a pre-call brief",
|
|
94
|
+
description: "Read the pre-call brief: who the lead is, what they want, and the objections to expect.",
|
|
95
|
+
untrustedContent: true,
|
|
96
|
+
redactedFields: ["brief"],
|
|
97
|
+
}),
|
|
98
|
+
op({
|
|
99
|
+
id: "bookings.update",
|
|
100
|
+
title: "Reschedule or edit a booking",
|
|
101
|
+
description: "Reschedule or update booking status.",
|
|
102
|
+
redactedFields: ["booking.rawPayload"],
|
|
103
|
+
}),
|
|
104
|
+
op({
|
|
105
|
+
id: "bookings.cancel",
|
|
106
|
+
title: "Cancel a booking",
|
|
107
|
+
description: "Cancel a booking.",
|
|
108
|
+
redactedFields: ["booking.rawPayload"],
|
|
109
|
+
}),
|
|
110
|
+
op({
|
|
111
|
+
id: "bookings.outcome.record",
|
|
112
|
+
title: "Record a booking's outcome",
|
|
113
|
+
description: "Record what the call was worth: won, lost with a reason, or still open. To correct an earlier outcome send the expectedVersion you read; a stale version returns 409 with the current one.",
|
|
114
|
+
redactedFields: ["episode.note"],
|
|
115
|
+
}),
|
|
116
|
+
op({
|
|
117
|
+
id: "bookings.lifecycleResolution",
|
|
118
|
+
title: "Resolve a booking's lifecycle flag",
|
|
119
|
+
description: "Settle one booking whose record disagrees with the provider's: retry the sync, dismiss the duplicate, or keep Luca's version.",
|
|
120
|
+
redactedFields: ["booking.rawPayload"],
|
|
121
|
+
}),
|
|
122
|
+
op({
|
|
123
|
+
id: "bookings.providerSync.retry",
|
|
124
|
+
title: "Retry a booking's provider sync",
|
|
125
|
+
description: "Retry a failed write-back to the booking provider. A permanent failure returns 409 rather than retrying forever.",
|
|
126
|
+
}),
|
|
127
|
+
op({
|
|
128
|
+
id: "bookings.guestLinks.create",
|
|
129
|
+
title: "Create a guest link for a booking",
|
|
130
|
+
description: "Mint revocable reschedule and cancel links for one booking, so a lead can move the call without an account.",
|
|
131
|
+
}),
|
|
132
|
+
op({
|
|
133
|
+
id: "bookings.guestLinks.revoke",
|
|
134
|
+
title: "Revoke a booking's guest links",
|
|
135
|
+
description: "Kill every outstanding guest link on a booking at once.",
|
|
136
|
+
}),
|
|
137
|
+
op({
|
|
138
|
+
id: "bookings.outcomeReasons.create",
|
|
139
|
+
title: "Create a loss reason",
|
|
140
|
+
description: "Add a lost-sale or cancellation reason in the workspace's own wording. A code already in use returns 409.",
|
|
141
|
+
}),
|
|
142
|
+
op({
|
|
143
|
+
id: "bookings.outcomeReasons.update",
|
|
144
|
+
title: "Update a loss reason",
|
|
145
|
+
description: "Rename, reorder, or archive an outcome reason. Archiving hides it from the picker and leaves recorded outcomes alone.",
|
|
146
|
+
}),
|
|
147
|
+
op({
|
|
148
|
+
id: "bookings.types.create",
|
|
149
|
+
title: "Create a booking type",
|
|
150
|
+
description: "Define a bookable call: how long it runs, where it happens, and how it looks to the lead. Give it a schedule next \u2014 a booking type with no schedule offers no slots and will never appear in availability.",
|
|
151
|
+
}),
|
|
152
|
+
op({
|
|
153
|
+
id: "bookings.types.update",
|
|
154
|
+
title: "Update a booking type",
|
|
155
|
+
description: "Update only the fields you send on one booking type. Sending `location` replaces the whole location, because its shape depends on the type.",
|
|
156
|
+
}),
|
|
157
|
+
op({
|
|
158
|
+
id: "bookings.types.delete",
|
|
159
|
+
title: "Delete a booking type",
|
|
160
|
+
description: "Remove a booking type and get back the types that are left. Calls already booked against it are not cancelled.",
|
|
161
|
+
}),
|
|
162
|
+
op({
|
|
163
|
+
id: "bookings.types.schedule.replace",
|
|
164
|
+
title: "Replace a booking type schedule",
|
|
165
|
+
description: "Replace a booking type's schedule outright. Send every rule and override you want to keep \u2014 anything left out is dropped, which is also how you clear a day. Read the current schedule first unless you mean to start over.",
|
|
166
|
+
}),
|
|
167
|
+
op({
|
|
168
|
+
id: "bookings.types.attendees.add",
|
|
169
|
+
title: "Add a booking type attendee",
|
|
170
|
+
redactedFields: ["attendees[].email", "attendees[].name"],
|
|
171
|
+
description: "Add a standing attendee to one booking type, so they are invited to every call booked against it. Returns the full attendee list.",
|
|
172
|
+
}),
|
|
173
|
+
op({
|
|
174
|
+
id: "bookings.types.attendees.remove",
|
|
175
|
+
title: "Remove a booking type attendee",
|
|
176
|
+
redactedFields: ["attendees[].email", "attendees[].name"],
|
|
177
|
+
description: "Remove a standing attendee from one booking type and get back the ones that are left. Calls already booked keep the invitees they were created with.",
|
|
178
|
+
}),
|
|
179
|
+
op({
|
|
180
|
+
id: "bookings.calendars.select",
|
|
181
|
+
title: "Select a booking calendar",
|
|
182
|
+
description: "Add or update a calendar selection, either for conflict checks or as the destination new bookings are written to. The destination has to be writable: a read-only calendar returns 400, and a Google connection needing attention returns 409.",
|
|
183
|
+
}),
|
|
184
|
+
op({
|
|
185
|
+
id: "bookings.calendars.remove",
|
|
186
|
+
title: "Remove a booking calendar",
|
|
187
|
+
description: "Stop using a calendar for conflict checks or as the booking destination. The calendar itself is left alone in Google; only Luca's selection changes.",
|
|
188
|
+
}),
|
|
189
|
+
];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { op } from "../registry.js";
|
|
2
|
+
export const broadcastsOperations = [
|
|
3
|
+
op({
|
|
4
|
+
id: "broadcasts.list",
|
|
5
|
+
title: "List broadcasts",
|
|
6
|
+
description: "List broadcasts. Query supports limit, cursor, and status.",
|
|
7
|
+
}),
|
|
8
|
+
op({
|
|
9
|
+
id: "broadcasts.get",
|
|
10
|
+
title: "Get a broadcast",
|
|
11
|
+
description: "Get broadcast detail.",
|
|
12
|
+
redactedFields: [
|
|
13
|
+
"recipients[].messageBody",
|
|
14
|
+
"sampleMessages[].body",
|
|
15
|
+
"segmentSnapshot.excludedRecipients[].displayName",
|
|
16
|
+
"segmentSnapshot.leads[].customFields",
|
|
17
|
+
"segmentSnapshot.leads[].displayName",
|
|
18
|
+
],
|
|
19
|
+
}),
|
|
20
|
+
op({
|
|
21
|
+
id: "broadcasts.create",
|
|
22
|
+
title: "Create a broadcast",
|
|
23
|
+
description: "Create a broadcast draft. Body requires campaignId and name.",
|
|
24
|
+
redactedFields: [
|
|
25
|
+
"recipients[].messageBody",
|
|
26
|
+
"sampleMessages[].body",
|
|
27
|
+
"segmentSnapshot.excludedRecipients[].displayName",
|
|
28
|
+
"segmentSnapshot.leads[].customFields",
|
|
29
|
+
"segmentSnapshot.leads[].displayName",
|
|
30
|
+
],
|
|
31
|
+
}),
|
|
32
|
+
op({
|
|
33
|
+
id: "broadcasts.preview",
|
|
34
|
+
title: "Preview a broadcast",
|
|
35
|
+
description: "Refresh broadcast recipient and sample-message preview.",
|
|
36
|
+
redactedFields: [
|
|
37
|
+
"recipients[].messageBody",
|
|
38
|
+
"sampleMessages[].body",
|
|
39
|
+
"segmentSnapshot.excludedRecipients[].displayName",
|
|
40
|
+
"segmentSnapshot.leads[].customFields",
|
|
41
|
+
"segmentSnapshot.leads[].displayName",
|
|
42
|
+
],
|
|
43
|
+
}),
|
|
44
|
+
op({
|
|
45
|
+
id: "broadcasts.approve",
|
|
46
|
+
title: "Approve a broadcast",
|
|
47
|
+
description: "Approve a safe broadcast draft and snapshot recipients.",
|
|
48
|
+
redactedFields: [
|
|
49
|
+
"recipients[].messageBody",
|
|
50
|
+
"sampleMessages[].body",
|
|
51
|
+
"segmentSnapshot.excludedRecipients[].displayName",
|
|
52
|
+
"segmentSnapshot.leads[].customFields",
|
|
53
|
+
"segmentSnapshot.leads[].displayName",
|
|
54
|
+
],
|
|
55
|
+
}),
|
|
56
|
+
op({
|
|
57
|
+
id: "broadcasts.launch",
|
|
58
|
+
title: "Launch a broadcast",
|
|
59
|
+
confirmRequired: true,
|
|
60
|
+
description: "Launch an approved broadcast. Sends messages to live leads.",
|
|
61
|
+
redactedFields: [
|
|
62
|
+
"recipients[].messageBody",
|
|
63
|
+
"sampleMessages[].body",
|
|
64
|
+
"segmentSnapshot.excludedRecipients[].displayName",
|
|
65
|
+
"segmentSnapshot.leads[].customFields",
|
|
66
|
+
"segmentSnapshot.leads[].displayName",
|
|
67
|
+
],
|
|
68
|
+
}),
|
|
69
|
+
op({
|
|
70
|
+
id: "broadcasts.pause",
|
|
71
|
+
title: "Pause a broadcast",
|
|
72
|
+
description: "Pause a running broadcast with an optional operator reason.",
|
|
73
|
+
redactedFields: [
|
|
74
|
+
"recipients[].messageBody",
|
|
75
|
+
"sampleMessages[].body",
|
|
76
|
+
"segmentSnapshot.excludedRecipients[].displayName",
|
|
77
|
+
"segmentSnapshot.leads[].customFields",
|
|
78
|
+
"segmentSnapshot.leads[].displayName",
|
|
79
|
+
],
|
|
80
|
+
}),
|
|
81
|
+
op({
|
|
82
|
+
id: "broadcasts.retry",
|
|
83
|
+
title: "Retry a broadcast's failed sends",
|
|
84
|
+
confirmRequired: true,
|
|
85
|
+
description: "Retry failed broadcast recipients after operator review. Re-sends messages to leads.",
|
|
86
|
+
redactedFields: [
|
|
87
|
+
"recipients[].messageBody",
|
|
88
|
+
"sampleMessages[].body",
|
|
89
|
+
"segmentSnapshot.excludedRecipients[].displayName",
|
|
90
|
+
"segmentSnapshot.leads[].customFields",
|
|
91
|
+
"segmentSnapshot.leads[].displayName",
|
|
92
|
+
],
|
|
93
|
+
}),
|
|
94
|
+
op({
|
|
95
|
+
id: "broadcasts.cancel",
|
|
96
|
+
title: "Cancel a broadcast",
|
|
97
|
+
description: "Cancel a draft, approved, running, paused, or failed broadcast.",
|
|
98
|
+
redactedFields: [
|
|
99
|
+
"recipients[].messageBody",
|
|
100
|
+
"sampleMessages[].body",
|
|
101
|
+
"segmentSnapshot.excludedRecipients[].displayName",
|
|
102
|
+
"segmentSnapshot.leads[].customFields",
|
|
103
|
+
"segmentSnapshot.leads[].displayName",
|
|
104
|
+
],
|
|
105
|
+
}),
|
|
106
|
+
];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { op } from "../registry.js";
|
|
2
|
+
export const cadencesOperations = [
|
|
3
|
+
op({
|
|
4
|
+
id: "cadences.rescueStart",
|
|
5
|
+
title: "Start a silent-lead rescue",
|
|
6
|
+
confirmRequired: true,
|
|
7
|
+
description: "Enroll silent leads into the multi-day rescue cadence. Starts outbound touches to real leads.",
|
|
8
|
+
}),
|
|
9
|
+
op({
|
|
10
|
+
id: "cadences.pause",
|
|
11
|
+
title: "Pause a lead's cadence",
|
|
12
|
+
description: "Pause (cancel) a lead's running rescue cadence with an optional reason.",
|
|
13
|
+
}),
|
|
14
|
+
];
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { op } from "../registry.js";
|
|
2
|
+
export const callEventsOperations = [
|
|
3
|
+
op({
|
|
4
|
+
id: "callEvents.needingFeedback",
|
|
5
|
+
title: "List calls still needing a report",
|
|
6
|
+
description: "List calls whose time has passed that still need the coach to say what happened. The post-call work queue.",
|
|
7
|
+
redactedFields: [
|
|
8
|
+
"callEvents[].coachNotes",
|
|
9
|
+
"callEvents[].crmSyncError",
|
|
10
|
+
"callEvents[].feedbackFields.followUpNote",
|
|
11
|
+
"callEvents[].feedbackFields.surprise",
|
|
12
|
+
"callEvents[].leadName",
|
|
13
|
+
"callEvents[].summary",
|
|
14
|
+
"callEvents[].summaryStructured",
|
|
15
|
+
],
|
|
16
|
+
}),
|
|
17
|
+
op({
|
|
18
|
+
id: "callEvents.get",
|
|
19
|
+
title: "Get a call event",
|
|
20
|
+
description: "Read one call event: outcome, rating, summary, and CRM sync state.",
|
|
21
|
+
redactedFields: [
|
|
22
|
+
"callEvent.coachNotes",
|
|
23
|
+
"callEvent.crmSyncError",
|
|
24
|
+
"callEvent.feedbackFields.followUpNote",
|
|
25
|
+
"callEvent.feedbackFields.surprise",
|
|
26
|
+
"callEvent.leadName",
|
|
27
|
+
"callEvent.summary",
|
|
28
|
+
"callEvent.summaryStructured",
|
|
29
|
+
],
|
|
30
|
+
}),
|
|
31
|
+
op({
|
|
32
|
+
id: "callEvents.byBooking",
|
|
33
|
+
title: "Get a booking's call event",
|
|
34
|
+
description: "Find the call event attached to a booking. A booking whose call hasn't happened yet returns 404, which is normal.",
|
|
35
|
+
redactedFields: [
|
|
36
|
+
"callEvent.coachNotes",
|
|
37
|
+
"callEvent.crmSyncError",
|
|
38
|
+
"callEvent.feedbackFields.followUpNote",
|
|
39
|
+
"callEvent.feedbackFields.surprise",
|
|
40
|
+
"callEvent.leadName",
|
|
41
|
+
"callEvent.summary",
|
|
42
|
+
"callEvent.summaryStructured",
|
|
43
|
+
],
|
|
44
|
+
}),
|
|
45
|
+
op({
|
|
46
|
+
id: "callEvents.byLead",
|
|
47
|
+
title: "List a lead's call events",
|
|
48
|
+
description: "Read a lead's full call history, oldest first, so a second or third call reads in sequence.",
|
|
49
|
+
redactedFields: [
|
|
50
|
+
"callEvents[].coachNotes",
|
|
51
|
+
"callEvents[].crmSyncError",
|
|
52
|
+
"callEvents[].feedbackFields.followUpNote",
|
|
53
|
+
"callEvents[].feedbackFields.surprise",
|
|
54
|
+
"callEvents[].leadName",
|
|
55
|
+
"callEvents[].summary",
|
|
56
|
+
"callEvents[].summaryStructured",
|
|
57
|
+
],
|
|
58
|
+
}),
|
|
59
|
+
op({
|
|
60
|
+
id: "callEvents.feedback",
|
|
61
|
+
title: "Report how a call went",
|
|
62
|
+
untrustedContent: true,
|
|
63
|
+
description: "File the coach's report on how a call went. A completed or no_show outcome also records booking attendance, and a completed call queues its summary.",
|
|
64
|
+
redactedFields: [
|
|
65
|
+
"callEvent.coachNotes",
|
|
66
|
+
"callEvent.crmSyncError",
|
|
67
|
+
"callEvent.feedbackFields.followUpNote",
|
|
68
|
+
"callEvent.feedbackFields.surprise",
|
|
69
|
+
"callEvent.leadName",
|
|
70
|
+
"callEvent.summary",
|
|
71
|
+
"callEvent.summaryStructured",
|
|
72
|
+
],
|
|
73
|
+
}),
|
|
74
|
+
op({
|
|
75
|
+
id: "callEvents.summary.generate",
|
|
76
|
+
title: "Generate a call summary",
|
|
77
|
+
untrustedContent: true,
|
|
78
|
+
description: "Queue a fresh summary and return straight away. Poll the call event for the result.",
|
|
79
|
+
}),
|
|
80
|
+
op({
|
|
81
|
+
id: "callEvents.summary.replace",
|
|
82
|
+
title: "Replace a call summary",
|
|
83
|
+
untrustedContent: true,
|
|
84
|
+
description: "Replace the generated summary with the coach's own wording and push it. A summary already in the CRM updates that same note.",
|
|
85
|
+
redactedFields: [
|
|
86
|
+
"callEvent.coachNotes",
|
|
87
|
+
"callEvent.crmSyncError",
|
|
88
|
+
"callEvent.feedbackFields.followUpNote",
|
|
89
|
+
"callEvent.feedbackFields.surprise",
|
|
90
|
+
"callEvent.leadName",
|
|
91
|
+
"callEvent.summary",
|
|
92
|
+
"callEvent.summaryStructured",
|
|
93
|
+
],
|
|
94
|
+
}),
|
|
95
|
+
op({
|
|
96
|
+
id: "callEvents.pushToCrm",
|
|
97
|
+
title: "Push a call to the CRM",
|
|
98
|
+
untrustedContent: true,
|
|
99
|
+
description: "Send the current summary to the CRM now, without waiting out the review window. Re-pushing updates the existing note.",
|
|
100
|
+
}),
|
|
101
|
+
op({
|
|
102
|
+
id: "callEvents.undoOutcome",
|
|
103
|
+
title: "Undo a call's outcome",
|
|
104
|
+
untrustedContent: true,
|
|
105
|
+
description: "Clear a mistaken attendance mark and put the call back in the queue. The window is 48 hours from when the outcome was set.",
|
|
106
|
+
redactedFields: [
|
|
107
|
+
"callEvent.coachNotes",
|
|
108
|
+
"callEvent.crmSyncError",
|
|
109
|
+
"callEvent.feedbackFields.followUpNote",
|
|
110
|
+
"callEvent.feedbackFields.surprise",
|
|
111
|
+
"callEvent.leadName",
|
|
112
|
+
"callEvent.summary",
|
|
113
|
+
"callEvent.summaryStructured",
|
|
114
|
+
],
|
|
115
|
+
}),
|
|
116
|
+
op({
|
|
117
|
+
id: "callEvents.backfill",
|
|
118
|
+
title: "Backfill a booking's call event",
|
|
119
|
+
untrustedContent: true,
|
|
120
|
+
description: "Create a call event for a booking that predates automatic creation, then queue its summary. Safe to call twice: an existing call event comes back as is.",
|
|
121
|
+
redactedFields: [
|
|
122
|
+
"callEvent.coachNotes",
|
|
123
|
+
"callEvent.crmSyncError",
|
|
124
|
+
"callEvent.feedbackFields.followUpNote",
|
|
125
|
+
"callEvent.feedbackFields.surprise",
|
|
126
|
+
"callEvent.leadName",
|
|
127
|
+
"callEvent.summary",
|
|
128
|
+
"callEvent.summaryStructured",
|
|
129
|
+
],
|
|
130
|
+
}),
|
|
131
|
+
];
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { op } from "../registry.js";
|
|
2
|
+
export const campaignsOperations = [
|
|
3
|
+
op({
|
|
4
|
+
id: "campaigns.list",
|
|
5
|
+
title: "List campaigns",
|
|
6
|
+
description: "List campaigns. Query supports limit, cursor, and status.",
|
|
7
|
+
}),
|
|
8
|
+
op({
|
|
9
|
+
id: "campaigns.get",
|
|
10
|
+
title: "Get a campaign",
|
|
11
|
+
description: "Get campaign draft and latest published version.",
|
|
12
|
+
}),
|
|
13
|
+
op({
|
|
14
|
+
id: "campaigns.create",
|
|
15
|
+
title: "Create a campaign",
|
|
16
|
+
description: "Create a campaign draft. Body requires name and may include graph.",
|
|
17
|
+
}),
|
|
18
|
+
op({
|
|
19
|
+
id: "campaigns.generate",
|
|
20
|
+
title: "Generate a campaign draft",
|
|
21
|
+
description: "Generate a safe AI campaign plan without creating or publishing it.",
|
|
22
|
+
}),
|
|
23
|
+
op({
|
|
24
|
+
id: "campaigns.draft.update",
|
|
25
|
+
title: "Edit a campaign draft",
|
|
26
|
+
description: "Autosave a campaign draft.",
|
|
27
|
+
// The route requires an idempotency key; without this the tool never sends
|
|
28
|
+
// one and every call is rejected (the dead-tool the drift guard now flags).
|
|
29
|
+
}),
|
|
30
|
+
op({
|
|
31
|
+
id: "campaigns.enrollments.list",
|
|
32
|
+
title: "List a campaign's enrollments",
|
|
33
|
+
description: "List campaign enrollments.",
|
|
34
|
+
redactedFields: ["enrollments[].context"],
|
|
35
|
+
}),
|
|
36
|
+
op({
|
|
37
|
+
id: "campaigns.enroll",
|
|
38
|
+
title: "Enroll leads in a campaign",
|
|
39
|
+
confirmRequired: true,
|
|
40
|
+
description: "Enroll a lead in the latest published campaign version. Triggers the live campaign's automation for that lead.",
|
|
41
|
+
}),
|
|
42
|
+
op({
|
|
43
|
+
id: "campaigns.analytics",
|
|
44
|
+
title: "Read a campaign's results",
|
|
45
|
+
description: "Read campaign attribution and performance analytics.",
|
|
46
|
+
}),
|
|
47
|
+
op({
|
|
48
|
+
id: "campaigns.providerCapabilities",
|
|
49
|
+
title: "Check what a campaign's channel supports",
|
|
50
|
+
description: "Evaluate provider capability blockers for a campaign draft.",
|
|
51
|
+
}),
|
|
52
|
+
op({
|
|
53
|
+
id: "campaigns.commentEvents.list",
|
|
54
|
+
title: "List campaign comment events",
|
|
55
|
+
description: "List matched, suppressed, blocked, and replayed comment automation events.",
|
|
56
|
+
// Each event carries verbatim external-commenter text (`body`,
|
|
57
|
+
// `commenterDisplayName`), so this read must be framed untrusted even
|
|
58
|
+
// though the campaigns group is not blanket-untrusted.
|
|
59
|
+
untrustedContent: true,
|
|
60
|
+
redactedFields: [
|
|
61
|
+
"events[].aiClassification",
|
|
62
|
+
"events[].body",
|
|
63
|
+
"events[].commenterDisplayName",
|
|
64
|
+
"events[].matchExplanation",
|
|
65
|
+
"events[].matchResult",
|
|
66
|
+
"events[].providerSnapshot",
|
|
67
|
+
"events[].safetyNotes",
|
|
68
|
+
"events[].sourceMetadata",
|
|
69
|
+
],
|
|
70
|
+
}),
|
|
71
|
+
op({
|
|
72
|
+
id: "campaigns.simulations.list",
|
|
73
|
+
title: "List a campaign's simulations",
|
|
74
|
+
description: "List persisted campaign simulation runs.",
|
|
75
|
+
}),
|
|
76
|
+
op({
|
|
77
|
+
id: "campaigns.simulations.create",
|
|
78
|
+
title: "Simulate a campaign",
|
|
79
|
+
description: "Run a persisted dry-run simulation without sending messages.",
|
|
80
|
+
redactedFields: [
|
|
81
|
+
"generatedDrafts[]",
|
|
82
|
+
"input.lead",
|
|
83
|
+
"trace[].generatedDraft",
|
|
84
|
+
],
|
|
85
|
+
}),
|
|
86
|
+
op({
|
|
87
|
+
id: "campaigns.simulations.get",
|
|
88
|
+
title: "Get a campaign simulation",
|
|
89
|
+
description: "Get a campaign simulation run with trace.",
|
|
90
|
+
redactedFields: [
|
|
91
|
+
"generatedDrafts[]",
|
|
92
|
+
"input.lead",
|
|
93
|
+
"trace[].generatedDraft",
|
|
94
|
+
],
|
|
95
|
+
}),
|
|
96
|
+
op({
|
|
97
|
+
id: "campaigns.commentSimulationSuite.run",
|
|
98
|
+
title: "Run the comment automation suite",
|
|
99
|
+
redactedFields: [
|
|
100
|
+
"simulations[].generatedDrafts[]",
|
|
101
|
+
"simulations[].trace[].generatedDraft",
|
|
102
|
+
],
|
|
103
|
+
description: "Run the Instagram comment-to-DM simulation suite against a campaign. Any campaign that uses comment automation has to pass it before it can publish, so run this before reaching for publish.",
|
|
104
|
+
}),
|
|
105
|
+
op({
|
|
106
|
+
id: "campaigns.publish",
|
|
107
|
+
title: "Publish a campaign",
|
|
108
|
+
confirmRequired: true,
|
|
109
|
+
description: "Freeze the draft as a new immutable version and point new enrollments at it. Published versions never change, and enrollments against a live campaign reach real leads. Publish is blocked when the target provider cannot do something the campaign needs, so read the provider capabilities first.",
|
|
110
|
+
}),
|
|
111
|
+
op({
|
|
112
|
+
id: "campaigns.setStatus",
|
|
113
|
+
title: "Pause, resume, or archive a campaign",
|
|
114
|
+
description: "Pause, resume, or archive a campaign. A transition that does not make sense for the campaign's current state is rejected rather than forced through.",
|
|
115
|
+
}),
|
|
116
|
+
op({
|
|
117
|
+
id: "campaigns.duplicate",
|
|
118
|
+
title: "Duplicate a campaign",
|
|
119
|
+
description: "Copy a campaign into a fresh unpublished draft and leave the original alone. Use it to change a live campaign without touching what is currently running.",
|
|
120
|
+
}),
|
|
121
|
+
op({
|
|
122
|
+
id: "campaigns.versions.list",
|
|
123
|
+
title: "List campaign versions",
|
|
124
|
+
description: "List a campaign's published version history. Published versions cannot change, so this is the record of what actually ran rather than what the draft says today.",
|
|
125
|
+
}),
|
|
126
|
+
op({
|
|
127
|
+
id: "campaigns.enrollments.timeline",
|
|
128
|
+
title: "Read an enrollment timeline",
|
|
129
|
+
redactedFields: ["enrollment.context"],
|
|
130
|
+
description: "Read every step one enrollment has been through: what got sent, when, and how the lead responded.",
|
|
131
|
+
}),
|
|
132
|
+
];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { op } from "../registry.js";
|
|
2
|
+
export const coachOperations = [
|
|
3
|
+
op({
|
|
4
|
+
id: "coach.profile",
|
|
5
|
+
title: "Read the coach's profile",
|
|
6
|
+
description: "Read the coach's account record: name, timezone, business hours, and tone slider. Use it to know when the coach is reachable and how formal they want to sound.",
|
|
7
|
+
}),
|
|
8
|
+
op({
|
|
9
|
+
id: "coach.niche",
|
|
10
|
+
title: "Read the coach's niche",
|
|
11
|
+
description: "Read the coach's canonical niche, the cohort key their benchmarks are compared against.",
|
|
12
|
+
}),
|
|
13
|
+
op({
|
|
14
|
+
id: "coach.nicheProfile",
|
|
15
|
+
title: "Read the coach's niche profile",
|
|
16
|
+
description: "Read the coach's offer, audience, price range, promised outcomes, disqualifiers, and FAQs. This is the context that decides whether a lead is a fit.",
|
|
17
|
+
}),
|
|
18
|
+
op({
|
|
19
|
+
id: "coach.objectionPlaybook",
|
|
20
|
+
title: "Read the coach's objection playbook",
|
|
21
|
+
description: "Read how the coach wants each objection type handled — price, timing, trust, fit — before drafting a reply to one.",
|
|
22
|
+
}),
|
|
23
|
+
op({
|
|
24
|
+
id: "coach.postCallSettings",
|
|
25
|
+
title: "Read the post-call settings",
|
|
26
|
+
description: "Read the coach's post-call preferences: what gets summarized, what gets pushed to the CRM, and what the coach fills in themselves.",
|
|
27
|
+
}),
|
|
28
|
+
op({
|
|
29
|
+
id: "coach.postCallCrmMapping",
|
|
30
|
+
title: "Read the post-call CRM mapping",
|
|
31
|
+
description: "Read which CRM field each post-call value writes to. Check this before a CRM push to know what will land where.",
|
|
32
|
+
}),
|
|
33
|
+
op({
|
|
34
|
+
id: "coach.postCallDealSync",
|
|
35
|
+
title: "Read the post-call deal sync settings",
|
|
36
|
+
description: "Read the CRM pipeline and the stage each call outcome moves a deal to.",
|
|
37
|
+
}),
|
|
38
|
+
op({
|
|
39
|
+
id: "coach.auditLog",
|
|
40
|
+
title: "Read the audit log",
|
|
41
|
+
description: "Read the coach-visible audit trail, newest first, filterable by actor type, action, action prefix, or target. It is the one read that spans every domain, so use it to check what a previous run actually did instead of replaying each list route.",
|
|
42
|
+
}),
|
|
43
|
+
];
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { op } from "../registry.js";
|
|
2
|
+
export const conversationsOperations = [
|
|
3
|
+
op({
|
|
4
|
+
id: "conversations.list",
|
|
5
|
+
title: "List conversations",
|
|
6
|
+
description: "List recent conversations. Query supports limit, cursor, channel, and q.",
|
|
7
|
+
redactedFields: [
|
|
8
|
+
"conversations[].lastMessagePreview",
|
|
9
|
+
"conversations[].leadDisplayName",
|
|
10
|
+
],
|
|
11
|
+
}),
|
|
12
|
+
op({
|
|
13
|
+
id: "conversations.get",
|
|
14
|
+
title: "Get a conversation",
|
|
15
|
+
description: "Get a conversation with messages and lead context.",
|
|
16
|
+
redactedFields: [
|
|
17
|
+
"conversation.qualificationProgress",
|
|
18
|
+
"copilotContext.leadDisplayName",
|
|
19
|
+
"lead.customFields",
|
|
20
|
+
"lead.displayName",
|
|
21
|
+
"lead.externalUserId",
|
|
22
|
+
"messages[].body",
|
|
23
|
+
"messages[].media",
|
|
24
|
+
"messages[].mediaUrls",
|
|
25
|
+
"messages[].rawPayload",
|
|
26
|
+
"pendingReview.criticIssues",
|
|
27
|
+
"pendingReview.draftBody",
|
|
28
|
+
"pendingReview.qualification",
|
|
29
|
+
],
|
|
30
|
+
}),
|
|
31
|
+
op({
|
|
32
|
+
id: "conversations.messages",
|
|
33
|
+
title: "Read a conversation's messages",
|
|
34
|
+
description: "Page backward through a thread's older messages, for threads longer than the window the conversation read returns.",
|
|
35
|
+
redactedFields: [
|
|
36
|
+
"messages[].body",
|
|
37
|
+
"messages[].media",
|
|
38
|
+
"messages[].mediaUrls",
|
|
39
|
+
"messages[].rawPayload",
|
|
40
|
+
],
|
|
41
|
+
}),
|
|
42
|
+
op({
|
|
43
|
+
id: "conversations.send",
|
|
44
|
+
title: "Send a message to a lead",
|
|
45
|
+
confirmRequired: true,
|
|
46
|
+
description: "Send a message to the lead on their channel right away. This is the one conversation tool that reaches a real person without a reviewer seeing the message first, which is why it needs an explicit confirm. Prefer drafting into the review queue unless the coach has asked for this message to go out now.",
|
|
47
|
+
}),
|
|
48
|
+
];
|