@agentrysh/mcp 0.0.10 → 0.0.13
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/dist/api.d.ts +254 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +104 -3
- package/dist/api.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +987 -5
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
package/dist/tools.js
CHANGED
|
@@ -57,6 +57,70 @@ export const TOOL_DESCRIPTORS = [
|
|
|
57
57
|
additionalProperties: false,
|
|
58
58
|
},
|
|
59
59
|
},
|
|
60
|
+
{
|
|
61
|
+
name: "agentry_publish_query",
|
|
62
|
+
description: "Mint a public-fetchable URL for a specific recipe + params combination. The returned " +
|
|
63
|
+
"URL can be embedded in a PUBLIC dashboard (your marketing site, a customer-facing " +
|
|
64
|
+
"metrics page, etc.) — visitors fetch the rendered query results without an account, " +
|
|
65
|
+
"credential, or session." +
|
|
66
|
+
"" +
|
|
67
|
+
"Auth model: the URL embeds the user's `agp_…` PUBLIC key (auto-minted at login alongside " +
|
|
68
|
+
"the private `agk_…`). agp_ is read-only AND can only fetch publications you explicitly " +
|
|
69
|
+
"created. Even if the URL leaks to the entire internet, the worst case is that the SAME " +
|
|
70
|
+
"(recipe + params) query you already chose to make public can be re-fetched. No other " +
|
|
71
|
+
"data is reachable." +
|
|
72
|
+
"" +
|
|
73
|
+
"Workflow: ASK the user what to publish (which metric, which params), call this tool, " +
|
|
74
|
+
"embed the returned `public_url?key=<agp_…>` in their page. CORS is open. Revoke with " +
|
|
75
|
+
"agentry_revoke_publication.",
|
|
76
|
+
inputSchema: {
|
|
77
|
+
type: "object",
|
|
78
|
+
properties: {
|
|
79
|
+
project_id: { type: "string" },
|
|
80
|
+
recipe_id: {
|
|
81
|
+
type: "string",
|
|
82
|
+
description: "ID from agentry_list_recipes. Bound to this publication permanently — to change " +
|
|
83
|
+
"the recipe, revoke + republish.",
|
|
84
|
+
},
|
|
85
|
+
params: {
|
|
86
|
+
type: "object",
|
|
87
|
+
description: "Recipe params (matches recipe.params schema). Bound to this publication.",
|
|
88
|
+
},
|
|
89
|
+
description: {
|
|
90
|
+
type: "string",
|
|
91
|
+
description: "What this dashboard widget shows — for your own future reference in " +
|
|
92
|
+
"agentry_list_publications.",
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
required: ["recipe_id"],
|
|
96
|
+
additionalProperties: false,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: "agentry_list_publications",
|
|
101
|
+
description: "List active public-fetchable query publications for this project. Returns each one's " +
|
|
102
|
+
"public_url + last_used_at. Use this to audit what's currently exposed publicly.",
|
|
103
|
+
inputSchema: {
|
|
104
|
+
type: "object",
|
|
105
|
+
properties: { project_id: { type: "string" } },
|
|
106
|
+
additionalProperties: false,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: "agentry_revoke_publication",
|
|
111
|
+
description: "Revoke a public-fetchable query publication. The public_url will start returning 410 " +
|
|
112
|
+
"(Gone). Use when the dashboard widget is decommissioned or the embedded URL leaks " +
|
|
113
|
+
"somewhere unintended.",
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: "object",
|
|
116
|
+
properties: {
|
|
117
|
+
project_id: { type: "string" },
|
|
118
|
+
publication_id: { type: "string" },
|
|
119
|
+
},
|
|
120
|
+
required: ["publication_id"],
|
|
121
|
+
additionalProperties: false,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
60
124
|
{
|
|
61
125
|
name: "agentry_configure_session_replay",
|
|
62
126
|
description: "Enable / disable / customize PostHog session replay for the user's project. " +
|
|
@@ -122,16 +186,420 @@ export const TOOL_DESCRIPTORS = [
|
|
|
122
186
|
{
|
|
123
187
|
name: "agentry_session_replay_status",
|
|
124
188
|
description: "Get the current session-replay configuration for the user's project AND a deep-link " +
|
|
125
|
-
"URL into PostHog's Replay tab
|
|
189
|
+
"URL into PostHog's Replay tab. For programmatic recording retrieval (returning the " +
|
|
190
|
+
"list of recordings or player URLs), call agentry_list_session_replays / " +
|
|
191
|
+
"agentry_get_session_replay — both work as of 2026-05-15 (master Personal API Key " +
|
|
192
|
+
"now has session_recording:read scope).",
|
|
193
|
+
inputSchema: {
|
|
194
|
+
type: "object",
|
|
195
|
+
properties: {
|
|
196
|
+
project_id: { type: "string" },
|
|
197
|
+
},
|
|
198
|
+
additionalProperties: false,
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// PostHog per-user-team CRUD: feature flags, cohorts, surveys, session
|
|
203
|
+
// recordings retrieval. Each wraps an /api/projects/<team_id>/<resource>/
|
|
204
|
+
// endpoint on the user's per-user PostHog team. Master Personal API Key
|
|
205
|
+
// has `*` scope as of 2026-05-15 so all of these are live.
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
{
|
|
208
|
+
name: "agentry_list_feature_flags",
|
|
209
|
+
description: "List feature flags on the user's PostHog project. Use this to inspect what flags " +
|
|
210
|
+
"exist before creating new ones, or to find a flag's id to update/delete it. Each " +
|
|
211
|
+
"flag has: id, key, name, active, filters (rollout rules), created_at.",
|
|
212
|
+
inputSchema: {
|
|
213
|
+
type: "object",
|
|
214
|
+
properties: {
|
|
215
|
+
project_id: { type: "string" },
|
|
216
|
+
limit: { type: "number", description: "Max flags to return (default 100, max 200)." },
|
|
217
|
+
},
|
|
218
|
+
additionalProperties: false,
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
name: "agentry_get_feature_flag",
|
|
223
|
+
description: "Fetch a single feature flag's full configuration (filters, variants, conditions).",
|
|
224
|
+
inputSchema: {
|
|
225
|
+
type: "object",
|
|
226
|
+
properties: {
|
|
227
|
+
project_id: { type: "string" },
|
|
228
|
+
flag_id: {
|
|
229
|
+
type: "string",
|
|
230
|
+
description: "Numeric id from agentry_list_feature_flags (NOT the flag's key string).",
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
required: ["flag_id"],
|
|
234
|
+
additionalProperties: false,
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: "agentry_create_feature_flag",
|
|
239
|
+
description: "Create a new feature flag. Two shapes supported:" +
|
|
240
|
+
"" +
|
|
241
|
+
" - Simple: pass {key, name?, active?, rollout_percentage?} — single-group filter at " +
|
|
242
|
+
" the given % rollout (0-100). Default: active=true, rollout=100." +
|
|
126
243
|
"" +
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
|
|
244
|
+
" - Advanced: pass {key, name?, active?, filters} — `filters` is PostHog's raw filter " +
|
|
245
|
+
" object ({groups: [{properties: [...], rollout_percentage}], multivariate?, …}). " +
|
|
246
|
+
" Use this for property-targeted rules, multi-variant flags, or cohort-scoped flags.",
|
|
247
|
+
inputSchema: {
|
|
248
|
+
type: "object",
|
|
249
|
+
properties: {
|
|
250
|
+
project_id: { type: "string" },
|
|
251
|
+
key: { type: "string", description: "Stable slug used in code (e.g. `new-checkout-flow`)." },
|
|
252
|
+
name: { type: "string", description: "Human label (defaults to key)." },
|
|
253
|
+
active: { type: "boolean", description: "Default true." },
|
|
254
|
+
rollout_percentage: { type: "number", description: "0–100 (simple shape)." },
|
|
255
|
+
filters: { type: "object", description: "Raw PostHog filter object (advanced shape)." },
|
|
256
|
+
},
|
|
257
|
+
required: ["key"],
|
|
258
|
+
additionalProperties: false,
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "agentry_update_feature_flag",
|
|
263
|
+
description: "Patch a feature flag. Toggle on/off via {active}, change rollout via {rollout_percentage}, " +
|
|
264
|
+
"rename via {name}, or replace targeting with {filters}.",
|
|
131
265
|
inputSchema: {
|
|
132
266
|
type: "object",
|
|
133
267
|
properties: {
|
|
134
268
|
project_id: { type: "string" },
|
|
269
|
+
flag_id: { type: "string" },
|
|
270
|
+
active: { type: "boolean" },
|
|
271
|
+
name: { type: "string" },
|
|
272
|
+
rollout_percentage: { type: "number" },
|
|
273
|
+
filters: { type: "object" },
|
|
274
|
+
},
|
|
275
|
+
required: ["flag_id"],
|
|
276
|
+
additionalProperties: false,
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
name: "agentry_delete_feature_flag",
|
|
281
|
+
description: "Soft-delete a feature flag (sets deleted=true; recoverable in PostHog's web UI).",
|
|
282
|
+
inputSchema: {
|
|
283
|
+
type: "object",
|
|
284
|
+
properties: {
|
|
285
|
+
project_id: { type: "string" },
|
|
286
|
+
flag_id: { type: "string" },
|
|
287
|
+
},
|
|
288
|
+
required: ["flag_id"],
|
|
289
|
+
additionalProperties: false,
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: "agentry_list_cohorts",
|
|
294
|
+
description: "List cohorts (dynamic user segments) on the user's PostHog project. Cohorts are " +
|
|
295
|
+
"groups of users matching a filter (e.g. 'users who did event X in last 30 days'). " +
|
|
296
|
+
"Used by feature-flag targeting and HogQL queries.",
|
|
297
|
+
inputSchema: {
|
|
298
|
+
type: "object",
|
|
299
|
+
properties: {
|
|
300
|
+
project_id: { type: "string" },
|
|
301
|
+
},
|
|
302
|
+
additionalProperties: false,
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
name: "agentry_get_cohort",
|
|
307
|
+
description: "Fetch a single cohort's definition (filters, last calculation time, count).",
|
|
308
|
+
inputSchema: {
|
|
309
|
+
type: "object",
|
|
310
|
+
properties: {
|
|
311
|
+
project_id: { type: "string" },
|
|
312
|
+
cohort_id: { type: "string" },
|
|
313
|
+
},
|
|
314
|
+
required: ["cohort_id"],
|
|
315
|
+
additionalProperties: false,
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
name: "agentry_create_cohort",
|
|
320
|
+
description: "Create a cohort. Two shapes supported:" +
|
|
321
|
+
"" +
|
|
322
|
+
" - Simple: {name, event, days?} — users who fired `event` at least once in the last " +
|
|
323
|
+
" N days (days defaults to 30)." +
|
|
324
|
+
"" +
|
|
325
|
+
" - Advanced: {name, groups} — `groups` is PostHog's raw cohort-group filter array, " +
|
|
326
|
+
" for property-targeted or multi-condition cohorts.",
|
|
327
|
+
inputSchema: {
|
|
328
|
+
type: "object",
|
|
329
|
+
properties: {
|
|
330
|
+
project_id: { type: "string" },
|
|
331
|
+
name: { type: "string" },
|
|
332
|
+
event: { type: "string", description: "Event name (simple shape)." },
|
|
333
|
+
days: { type: "number", description: "Lookback window in days (default 30, simple shape)." },
|
|
334
|
+
groups: { type: "array", description: "Raw PostHog cohort-group filters (advanced shape)." },
|
|
335
|
+
},
|
|
336
|
+
required: ["name"],
|
|
337
|
+
additionalProperties: false,
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
name: "agentry_delete_cohort",
|
|
342
|
+
description: "Soft-delete a cohort (recoverable in PostHog's web UI).",
|
|
343
|
+
inputSchema: {
|
|
344
|
+
type: "object",
|
|
345
|
+
properties: {
|
|
346
|
+
project_id: { type: "string" },
|
|
347
|
+
cohort_id: { type: "string" },
|
|
348
|
+
},
|
|
349
|
+
required: ["cohort_id"],
|
|
350
|
+
additionalProperties: false,
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
name: "agentry_list_surveys",
|
|
355
|
+
description: "List surveys on the user's PostHog project. A survey is a popup/banner/widget the " +
|
|
356
|
+
"customer's PostHog-JS-enabled site renders to ask users a question (NPS, CSAT, " +
|
|
357
|
+
"free-text). Responses land as `survey sent` events.",
|
|
358
|
+
inputSchema: {
|
|
359
|
+
type: "object",
|
|
360
|
+
properties: {
|
|
361
|
+
project_id: { type: "string" },
|
|
362
|
+
},
|
|
363
|
+
additionalProperties: false,
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
name: "agentry_get_survey",
|
|
368
|
+
description: "Fetch a single survey's definition. To read responses, query HogQL: " +
|
|
369
|
+
"`SELECT properties FROM events WHERE event = 'survey sent' AND properties.\\$survey_id = '<id>'`.",
|
|
370
|
+
inputSchema: {
|
|
371
|
+
type: "object",
|
|
372
|
+
properties: {
|
|
373
|
+
project_id: { type: "string" },
|
|
374
|
+
survey_id: { type: "string" },
|
|
375
|
+
},
|
|
376
|
+
required: ["survey_id"],
|
|
377
|
+
additionalProperties: false,
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
name: "agentry_create_survey",
|
|
382
|
+
description: "Create a survey. Quick shape: {name, question, question_type?} for a single-question " +
|
|
383
|
+
"popover (question_type defaults to 'open' — also 'rating', 'single_choice', " +
|
|
384
|
+
"'multiple_choice', 'link'). Advanced: pass {name, questions: [...]} for multi-question. " +
|
|
385
|
+
"" +
|
|
386
|
+
"Surveys are created in DRAFT — pass start_date (ISO) to launch immediately, or call " +
|
|
387
|
+
"PATCH /surveys/:id with {start_date} later.",
|
|
388
|
+
inputSchema: {
|
|
389
|
+
type: "object",
|
|
390
|
+
properties: {
|
|
391
|
+
project_id: { type: "string" },
|
|
392
|
+
name: { type: "string" },
|
|
393
|
+
type: {
|
|
394
|
+
type: "string",
|
|
395
|
+
enum: ["popover", "widget", "button", "api"],
|
|
396
|
+
description: "Render style. Default 'popover'.",
|
|
397
|
+
},
|
|
398
|
+
question: { type: "string", description: "Single-question quick shape." },
|
|
399
|
+
question_type: {
|
|
400
|
+
type: "string",
|
|
401
|
+
enum: ["open", "rating", "single_choice", "multiple_choice", "link"],
|
|
402
|
+
},
|
|
403
|
+
questions: { type: "array", description: "Multi-question array (advanced shape)." },
|
|
404
|
+
description: { type: "string" },
|
|
405
|
+
linked_flag_id: { type: "number" },
|
|
406
|
+
targeting_flag_id: { type: "number" },
|
|
407
|
+
conditions: { type: "object" },
|
|
408
|
+
appearance: { type: "object" },
|
|
409
|
+
start_date: { type: "string", description: "ISO timestamp to launch immediately." },
|
|
410
|
+
},
|
|
411
|
+
required: ["name"],
|
|
412
|
+
additionalProperties: false,
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
name: "agentry_delete_survey",
|
|
417
|
+
description: "Delete a survey (PostHog hard-deletes survey rows on DELETE).",
|
|
418
|
+
inputSchema: {
|
|
419
|
+
type: "object",
|
|
420
|
+
properties: {
|
|
421
|
+
project_id: { type: "string" },
|
|
422
|
+
survey_id: { type: "string" },
|
|
423
|
+
},
|
|
424
|
+
required: ["survey_id"],
|
|
425
|
+
additionalProperties: false,
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
name: "agentry_list_session_replays",
|
|
430
|
+
description: "List session recordings on the user's PostHog project. Use this to find replays " +
|
|
431
|
+
"linked to a user (distinct_id) or a time range — e.g. when investigating an error, " +
|
|
432
|
+
"filter by the affected user's distinct_id to find the recording leading up to it. " +
|
|
433
|
+
"" +
|
|
434
|
+
"Note: session replay must be ENABLED first (call agentry_configure_session_replay). " +
|
|
435
|
+
"Recordings are only captured while a strategy is on.",
|
|
436
|
+
inputSchema: {
|
|
437
|
+
type: "object",
|
|
438
|
+
properties: {
|
|
439
|
+
project_id: { type: "string" },
|
|
440
|
+
distinct_id: {
|
|
441
|
+
type: "string",
|
|
442
|
+
description: "Filter to one user (e.g. from a case's affected_users).",
|
|
443
|
+
},
|
|
444
|
+
date_from: { type: "string", description: "ISO timestamp lower bound." },
|
|
445
|
+
date_to: { type: "string", description: "ISO timestamp upper bound." },
|
|
446
|
+
limit: { type: "number", description: "Max recordings (default 25, max 100)." },
|
|
447
|
+
},
|
|
448
|
+
additionalProperties: false,
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
name: "agentry_get_session_replay",
|
|
453
|
+
description: "Fetch a single session recording's metadata + player URL. Open `player_url` in a " +
|
|
454
|
+
"browser to watch. For programmatic DOM-event inspection (the rrweb snapshots), " +
|
|
455
|
+
"call agentry_get_replay_snapshots.",
|
|
456
|
+
inputSchema: {
|
|
457
|
+
type: "object",
|
|
458
|
+
properties: {
|
|
459
|
+
project_id: { type: "string" },
|
|
460
|
+
replay_id: { type: "string" },
|
|
461
|
+
},
|
|
462
|
+
required: ["replay_id"],
|
|
463
|
+
additionalProperties: false,
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
name: "agentry_get_replay_snapshots",
|
|
468
|
+
description: "Fetch the rrweb-format DOM snapshots for one recording. Each snapshot has type " +
|
|
469
|
+
"(Meta / FullSnapshot / IncrementalSnapshot — values 4 / 2 / 3) and timestamp. " +
|
|
470
|
+
"For agent inspection: filter type=3 events for user actions (clicks, scrolls, " +
|
|
471
|
+
"inputs). Useful for reconstructing exactly what the user did before an error.",
|
|
472
|
+
inputSchema: {
|
|
473
|
+
type: "object",
|
|
474
|
+
properties: {
|
|
475
|
+
project_id: { type: "string" },
|
|
476
|
+
replay_id: { type: "string" },
|
|
477
|
+
source: {
|
|
478
|
+
type: "string",
|
|
479
|
+
enum: ["realtime", "blob"],
|
|
480
|
+
description: "PostHog snapshot source. 'realtime' for live, 'blob' for archived.",
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
required: ["replay_id"],
|
|
484
|
+
additionalProperties: false,
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
name: "agentry_evaluate_feature_flag",
|
|
489
|
+
description: "Evaluate feature flags for one user (distinct_id). Two shapes:" +
|
|
490
|
+
"" +
|
|
491
|
+
" - Pass `key` to get a single flag's value (boolean / variant string / null if " +
|
|
492
|
+
" not active for this user)." +
|
|
493
|
+
" - Omit `key` to get a map of all currently-active flags for the user." +
|
|
494
|
+
"" +
|
|
495
|
+
"Use this when investigating a bug — 'is this user in the new checkout flow?' is " +
|
|
496
|
+
"one call away. Pass `person_properties` to override the stored properties for " +
|
|
497
|
+
"what-if evaluation.",
|
|
498
|
+
inputSchema: {
|
|
499
|
+
type: "object",
|
|
500
|
+
properties: {
|
|
501
|
+
project_id: { type: "string" },
|
|
502
|
+
distinct_id: { type: "string", description: "Stable per-user id, same as case.affected_users[].distinct_id." },
|
|
503
|
+
key: { type: "string", description: "Flag key. Omit to get all flags." },
|
|
504
|
+
person_properties: { type: "object", description: "Override stored properties for what-if." },
|
|
505
|
+
groups: { type: "object", description: "Group analytics overrides if your flag targets groups." },
|
|
506
|
+
},
|
|
507
|
+
required: ["distinct_id"],
|
|
508
|
+
additionalProperties: false,
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
name: "agentry_get_distinct_id_summary",
|
|
513
|
+
description: "One-call user dossier. Returns: PostHog person properties, total event count, " +
|
|
514
|
+
"first/last seen, last 20 events, recent session recordings (if replay is on), and " +
|
|
515
|
+
"a deep-link URL into PostHog's persons UI. Use this when investigating a case — " +
|
|
516
|
+
"the affected_users[].distinct_id from agentry_get_case lets you build the full " +
|
|
517
|
+
"picture without 3+ separate HogQL calls.",
|
|
518
|
+
inputSchema: {
|
|
519
|
+
type: "object",
|
|
520
|
+
properties: {
|
|
521
|
+
project_id: { type: "string" },
|
|
522
|
+
distinct_id: { type: "string" },
|
|
523
|
+
},
|
|
524
|
+
required: ["distinct_id"],
|
|
525
|
+
additionalProperties: false,
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
name: "agentry_survey_responses",
|
|
530
|
+
description: "Roll-up of survey responses. Returns: the survey definition (questions + choice " +
|
|
531
|
+
"labels), a response_distribution (counts per choice), the last 50 free-text " +
|
|
532
|
+
"responses with timestamps, and a web UI deep-link. Saves the agent from composing " +
|
|
533
|
+
"HogQL with $survey_response property unpacking.",
|
|
534
|
+
inputSchema: {
|
|
535
|
+
type: "object",
|
|
536
|
+
properties: {
|
|
537
|
+
project_id: { type: "string" },
|
|
538
|
+
survey_id: { type: "string" },
|
|
539
|
+
},
|
|
540
|
+
required: ["survey_id"],
|
|
541
|
+
additionalProperties: false,
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
name: "agentry_create_ab_test",
|
|
546
|
+
description: "Composite tool: creates a multivariate feature flag AND returns the bound " +
|
|
547
|
+
"conversion-rate HogQL query an agent can run later via agentry_analytics_query. " +
|
|
548
|
+
"" +
|
|
549
|
+
"Pass `name`, `success_event` (e.g. 'checkout_completed'), and `variants` (array of " +
|
|
550
|
+
"{key} — auto-split rollout if rollout_percentage not given; must sum to 100 if " +
|
|
551
|
+
"any are explicit). Optional flag_key (default: slugified name)." +
|
|
552
|
+
"" +
|
|
553
|
+
"Returns: flag_id, conversion_query string, web_ui_url. Recommended: ≥1000 users " +
|
|
554
|
+
"per variant before drawing conclusions.",
|
|
555
|
+
inputSchema: {
|
|
556
|
+
type: "object",
|
|
557
|
+
properties: {
|
|
558
|
+
project_id: { type: "string" },
|
|
559
|
+
name: { type: "string" },
|
|
560
|
+
flag_key: { type: "string", description: "Override the slugified name." },
|
|
561
|
+
success_event: { type: "string", description: "The event whose conversion you're measuring." },
|
|
562
|
+
variants: {
|
|
563
|
+
type: "array",
|
|
564
|
+
items: {
|
|
565
|
+
type: "object",
|
|
566
|
+
properties: {
|
|
567
|
+
key: { type: "string" },
|
|
568
|
+
name: { type: "string" },
|
|
569
|
+
rollout_percentage: { type: "number" },
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
description: "Min 2 variants. Auto-split if rollout_percentage omitted.",
|
|
573
|
+
},
|
|
574
|
+
},
|
|
575
|
+
required: ["name", "success_event", "variants"],
|
|
576
|
+
additionalProperties: false,
|
|
577
|
+
},
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
name: "agentry_recent_changes",
|
|
581
|
+
description: "Read the agent-mutation audit log. Returns every flag/cohort/survey/publication/" +
|
|
582
|
+
"session-replay mutation the agent (or anyone with your `agk_` key) has made in the " +
|
|
583
|
+
"last N hours." +
|
|
584
|
+
"" +
|
|
585
|
+
"Default window is 24 hours. Pass `hours` to widen — 48, 72, 168 (week), max 720 (30d)." +
|
|
586
|
+
"Pass `action_prefix` (e.g. 'feature_flag.' / 'cohort.' / 'survey.' / 'publication.' / " +
|
|
587
|
+
"'session_replay.') or `resource_type` to filter. Use this as a periodic " +
|
|
588
|
+
"'what-did-the-agent-do' check when leaving agents to run unattended.",
|
|
589
|
+
inputSchema: {
|
|
590
|
+
type: "object",
|
|
591
|
+
properties: {
|
|
592
|
+
hours: { type: "number", description: "Lookback window. 1..720. Default 24." },
|
|
593
|
+
action_prefix: {
|
|
594
|
+
type: "string",
|
|
595
|
+
description: "Filter by action prefix (e.g. 'feature_flag.' matches both create + delete).",
|
|
596
|
+
},
|
|
597
|
+
resource_type: {
|
|
598
|
+
type: "string",
|
|
599
|
+
enum: ["feature_flag", "cohort", "survey", "publication", "session_replay", "ab_test"],
|
|
600
|
+
},
|
|
601
|
+
project_id: { type: "string", description: "Restrict to one project." },
|
|
602
|
+
limit: { type: "number", description: "Max rows (default 200, max 500)." },
|
|
135
603
|
},
|
|
136
604
|
additionalProperties: false,
|
|
137
605
|
},
|
|
@@ -910,6 +1378,12 @@ function persistKeyResponse(cfg, resp) {
|
|
|
910
1378
|
const next = {
|
|
911
1379
|
...cfg,
|
|
912
1380
|
api_key: resp.api_key,
|
|
1381
|
+
// Persist the agp_ public key too (returned by login response). Only
|
|
1382
|
+
// overwrite if the new response provides one; rotation/repair paths
|
|
1383
|
+
// don't necessarily return public keys.
|
|
1384
|
+
...(resp.public_api_key && !resp.public_api_key.startsWith("(redacted")
|
|
1385
|
+
? { public_api_key: resp.public_api_key }
|
|
1386
|
+
: {}),
|
|
913
1387
|
};
|
|
914
1388
|
saveConfig(next);
|
|
915
1389
|
return next;
|
|
@@ -980,6 +1454,22 @@ export async function dispatchTool(name, args) {
|
|
|
980
1454
|
return await handleRotateKey();
|
|
981
1455
|
case "agentry_repair_analytics":
|
|
982
1456
|
return await handleRepairAnalytics();
|
|
1457
|
+
case "agentry_publish_query":
|
|
1458
|
+
return await handlePublishQuery({
|
|
1459
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1460
|
+
recipe_id: String(a.recipe_id ?? ""),
|
|
1461
|
+
params: a.params && typeof a.params === "object"
|
|
1462
|
+
? a.params
|
|
1463
|
+
: undefined,
|
|
1464
|
+
description: a.description ? String(a.description) : undefined,
|
|
1465
|
+
});
|
|
1466
|
+
case "agentry_list_publications":
|
|
1467
|
+
return await handleListPublications(a.project_id ? String(a.project_id) : undefined);
|
|
1468
|
+
case "agentry_revoke_publication":
|
|
1469
|
+
return await handleRevokePublication({
|
|
1470
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1471
|
+
publication_id: String(a.publication_id ?? ""),
|
|
1472
|
+
});
|
|
983
1473
|
case "agentry_configure_session_replay":
|
|
984
1474
|
return await handleConfigureSessionReplay({
|
|
985
1475
|
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
@@ -993,6 +1483,147 @@ export async function dispatchTool(name, args) {
|
|
|
993
1483
|
});
|
|
994
1484
|
case "agentry_session_replay_status":
|
|
995
1485
|
return await handleSessionReplayStatus(a.project_id ? String(a.project_id) : undefined);
|
|
1486
|
+
case "agentry_list_feature_flags":
|
|
1487
|
+
return await handleListFeatureFlags({
|
|
1488
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1489
|
+
limit: typeof a.limit === "number" ? a.limit : undefined,
|
|
1490
|
+
});
|
|
1491
|
+
case "agentry_get_feature_flag":
|
|
1492
|
+
return await handleGetFeatureFlag({
|
|
1493
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1494
|
+
flag_id: String(a.flag_id ?? ""),
|
|
1495
|
+
});
|
|
1496
|
+
case "agentry_create_feature_flag":
|
|
1497
|
+
return await handleCreateFeatureFlag({
|
|
1498
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1499
|
+
key: String(a.key ?? ""),
|
|
1500
|
+
name: a.name ? String(a.name) : undefined,
|
|
1501
|
+
active: typeof a.active === "boolean" ? a.active : undefined,
|
|
1502
|
+
rollout_percentage: typeof a.rollout_percentage === "number" ? a.rollout_percentage : undefined,
|
|
1503
|
+
filters: a.filters && typeof a.filters === "object" ? a.filters : undefined,
|
|
1504
|
+
});
|
|
1505
|
+
case "agentry_update_feature_flag":
|
|
1506
|
+
return await handleUpdateFeatureFlag({
|
|
1507
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1508
|
+
flag_id: String(a.flag_id ?? ""),
|
|
1509
|
+
active: typeof a.active === "boolean" ? a.active : undefined,
|
|
1510
|
+
name: a.name ? String(a.name) : undefined,
|
|
1511
|
+
rollout_percentage: typeof a.rollout_percentage === "number" ? a.rollout_percentage : undefined,
|
|
1512
|
+
filters: a.filters && typeof a.filters === "object" ? a.filters : undefined,
|
|
1513
|
+
});
|
|
1514
|
+
case "agentry_delete_feature_flag":
|
|
1515
|
+
return await handleDeleteFeatureFlag({
|
|
1516
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1517
|
+
flag_id: String(a.flag_id ?? ""),
|
|
1518
|
+
});
|
|
1519
|
+
case "agentry_list_cohorts":
|
|
1520
|
+
return await handleListCohorts(a.project_id ? String(a.project_id) : undefined);
|
|
1521
|
+
case "agentry_get_cohort":
|
|
1522
|
+
return await handleGetCohort({
|
|
1523
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1524
|
+
cohort_id: String(a.cohort_id ?? ""),
|
|
1525
|
+
});
|
|
1526
|
+
case "agentry_create_cohort":
|
|
1527
|
+
return await handleCreateCohort({
|
|
1528
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1529
|
+
name: String(a.name ?? ""),
|
|
1530
|
+
event: a.event ? String(a.event) : undefined,
|
|
1531
|
+
days: typeof a.days === "number" ? a.days : undefined,
|
|
1532
|
+
groups: Array.isArray(a.groups) ? a.groups : undefined,
|
|
1533
|
+
});
|
|
1534
|
+
case "agentry_delete_cohort":
|
|
1535
|
+
return await handleDeleteCohort({
|
|
1536
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1537
|
+
cohort_id: String(a.cohort_id ?? ""),
|
|
1538
|
+
});
|
|
1539
|
+
case "agentry_list_surveys":
|
|
1540
|
+
return await handleListSurveys(a.project_id ? String(a.project_id) : undefined);
|
|
1541
|
+
case "agentry_get_survey":
|
|
1542
|
+
return await handleGetSurvey({
|
|
1543
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1544
|
+
survey_id: String(a.survey_id ?? ""),
|
|
1545
|
+
});
|
|
1546
|
+
case "agentry_create_survey":
|
|
1547
|
+
return await handleCreateSurvey({
|
|
1548
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1549
|
+
name: String(a.name ?? ""),
|
|
1550
|
+
type: a.type ? String(a.type) : undefined,
|
|
1551
|
+
question: a.question ? String(a.question) : undefined,
|
|
1552
|
+
question_type: a.question_type
|
|
1553
|
+
? String(a.question_type)
|
|
1554
|
+
: undefined,
|
|
1555
|
+
questions: Array.isArray(a.questions) ? a.questions : undefined,
|
|
1556
|
+
description: a.description ? String(a.description) : undefined,
|
|
1557
|
+
linked_flag_id: typeof a.linked_flag_id === "number" ? a.linked_flag_id : undefined,
|
|
1558
|
+
targeting_flag_id: typeof a.targeting_flag_id === "number" ? a.targeting_flag_id : undefined,
|
|
1559
|
+
conditions: a.conditions && typeof a.conditions === "object" ? a.conditions : undefined,
|
|
1560
|
+
appearance: a.appearance && typeof a.appearance === "object" ? a.appearance : undefined,
|
|
1561
|
+
start_date: a.start_date ? String(a.start_date) : undefined,
|
|
1562
|
+
});
|
|
1563
|
+
case "agentry_delete_survey":
|
|
1564
|
+
return await handleDeleteSurvey({
|
|
1565
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1566
|
+
survey_id: String(a.survey_id ?? ""),
|
|
1567
|
+
});
|
|
1568
|
+
case "agentry_list_session_replays":
|
|
1569
|
+
return await handleListSessionReplays({
|
|
1570
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1571
|
+
distinct_id: a.distinct_id ? String(a.distinct_id) : undefined,
|
|
1572
|
+
date_from: a.date_from ? String(a.date_from) : undefined,
|
|
1573
|
+
date_to: a.date_to ? String(a.date_to) : undefined,
|
|
1574
|
+
limit: typeof a.limit === "number" ? a.limit : undefined,
|
|
1575
|
+
});
|
|
1576
|
+
case "agentry_get_session_replay":
|
|
1577
|
+
return await handleGetSessionReplay({
|
|
1578
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1579
|
+
replay_id: String(a.replay_id ?? ""),
|
|
1580
|
+
});
|
|
1581
|
+
case "agentry_get_replay_snapshots":
|
|
1582
|
+
return await handleGetReplaySnapshots({
|
|
1583
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1584
|
+
replay_id: String(a.replay_id ?? ""),
|
|
1585
|
+
source: a.source ? String(a.source) : undefined,
|
|
1586
|
+
});
|
|
1587
|
+
case "agentry_evaluate_feature_flag":
|
|
1588
|
+
return await handleEvaluateFeatureFlag({
|
|
1589
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1590
|
+
distinct_id: String(a.distinct_id ?? ""),
|
|
1591
|
+
key: a.key ? String(a.key) : undefined,
|
|
1592
|
+
person_properties: a.person_properties && typeof a.person_properties === "object"
|
|
1593
|
+
? a.person_properties
|
|
1594
|
+
: undefined,
|
|
1595
|
+
groups: a.groups && typeof a.groups === "object"
|
|
1596
|
+
? a.groups
|
|
1597
|
+
: undefined,
|
|
1598
|
+
});
|
|
1599
|
+
case "agentry_get_distinct_id_summary":
|
|
1600
|
+
return await handleGetDistinctIdSummary({
|
|
1601
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1602
|
+
distinct_id: String(a.distinct_id ?? ""),
|
|
1603
|
+
});
|
|
1604
|
+
case "agentry_survey_responses":
|
|
1605
|
+
return await handleSurveyResponses({
|
|
1606
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1607
|
+
survey_id: String(a.survey_id ?? ""),
|
|
1608
|
+
});
|
|
1609
|
+
case "agentry_create_ab_test":
|
|
1610
|
+
return await handleCreateAbTest({
|
|
1611
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1612
|
+
name: String(a.name ?? ""),
|
|
1613
|
+
flag_key: a.flag_key ? String(a.flag_key) : undefined,
|
|
1614
|
+
success_event: String(a.success_event ?? ""),
|
|
1615
|
+
variants: Array.isArray(a.variants)
|
|
1616
|
+
? a.variants
|
|
1617
|
+
: [],
|
|
1618
|
+
});
|
|
1619
|
+
case "agentry_recent_changes":
|
|
1620
|
+
return await handleRecentChanges({
|
|
1621
|
+
hours: typeof a.hours === "number" ? a.hours : undefined,
|
|
1622
|
+
action_prefix: a.action_prefix ? String(a.action_prefix) : undefined,
|
|
1623
|
+
resource_type: a.resource_type ? String(a.resource_type) : undefined,
|
|
1624
|
+
project_id: a.project_id ? String(a.project_id) : undefined,
|
|
1625
|
+
limit: typeof a.limit === "number" ? a.limit : undefined,
|
|
1626
|
+
});
|
|
996
1627
|
case "agentry_list_projects":
|
|
997
1628
|
return await handleListProjects();
|
|
998
1629
|
case "agentry_create_project":
|
|
@@ -1391,6 +2022,65 @@ async function handleRepairAnalytics() {
|
|
|
1391
2022
|
};
|
|
1392
2023
|
}
|
|
1393
2024
|
}
|
|
2025
|
+
async function handlePublishQuery(input) {
|
|
2026
|
+
const cfg = loadConfig();
|
|
2027
|
+
const picked = pickProject(cfg, input.project_id);
|
|
2028
|
+
if (!picked) {
|
|
2029
|
+
return {
|
|
2030
|
+
error: {
|
|
2031
|
+
code: "no_project",
|
|
2032
|
+
message: "No project_id given and no default project set.",
|
|
2033
|
+
next_action: "Pass project_id, or call agentry_create_project.",
|
|
2034
|
+
},
|
|
2035
|
+
};
|
|
2036
|
+
}
|
|
2037
|
+
const resp = await api.publishQuery(cfg, picked.id, {
|
|
2038
|
+
recipe_id: input.recipe_id,
|
|
2039
|
+
params: input.params,
|
|
2040
|
+
description: input.description,
|
|
2041
|
+
});
|
|
2042
|
+
// Help the agent: fetch the user's agp_ key from the local config and
|
|
2043
|
+
// append it as a query param to the public URL.
|
|
2044
|
+
const agp = cfg.public_api_key ?? null;
|
|
2045
|
+
const embeddableUrl = agp ? `${resp.public_url}?key=${agp}` : resp.public_url;
|
|
2046
|
+
return {
|
|
2047
|
+
...resp,
|
|
2048
|
+
embeddable_url: embeddableUrl,
|
|
2049
|
+
next_action: agp
|
|
2050
|
+
? "Embed embeddable_url in the public dashboard. CORS is open. Revoke any time with " +
|
|
2051
|
+
"agentry_revoke_publication if it's leaked or no longer needed."
|
|
2052
|
+
: "Your agp_ public key isn't cached locally yet — call agentry_login to mint it. Once " +
|
|
2053
|
+
"minted, paste it as ?key=<agp_…> on the public_url to embed.",
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
async function handleListPublications(projectId) {
|
|
2057
|
+
const cfg = loadConfig();
|
|
2058
|
+
const picked = pickProject(cfg, projectId);
|
|
2059
|
+
if (!picked) {
|
|
2060
|
+
return {
|
|
2061
|
+
error: {
|
|
2062
|
+
code: "no_project",
|
|
2063
|
+
message: "No project_id given and no default project set.",
|
|
2064
|
+
next_action: "Pass project_id.",
|
|
2065
|
+
},
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
return await api.listPublications(cfg, picked.id);
|
|
2069
|
+
}
|
|
2070
|
+
async function handleRevokePublication(input) {
|
|
2071
|
+
const cfg = loadConfig();
|
|
2072
|
+
const picked = pickProject(cfg, input.project_id);
|
|
2073
|
+
if (!picked) {
|
|
2074
|
+
return {
|
|
2075
|
+
error: {
|
|
2076
|
+
code: "no_project",
|
|
2077
|
+
message: "No project_id given and no default project set.",
|
|
2078
|
+
next_action: "Pass project_id.",
|
|
2079
|
+
},
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2082
|
+
return await api.revokePublication(cfg, picked.id, input.publication_id);
|
|
2083
|
+
}
|
|
1394
2084
|
async function handleConfigureSessionReplay(input) {
|
|
1395
2085
|
const cfg = loadConfig();
|
|
1396
2086
|
const picked = pickProject(cfg, input.project_id);
|
|
@@ -1425,6 +2115,298 @@ async function handleSessionReplayStatus(projectId) {
|
|
|
1425
2115
|
}
|
|
1426
2116
|
return await api.getSessionReplayStatus(cfg, picked.id);
|
|
1427
2117
|
}
|
|
2118
|
+
// ---------------------------------------------------------------------------
|
|
2119
|
+
// PostHog per-user-team CRUD handlers.
|
|
2120
|
+
// Shared helper for the "no project" error envelope to keep handlers terse.
|
|
2121
|
+
// ---------------------------------------------------------------------------
|
|
2122
|
+
function pickOrError(cfg, projectId) {
|
|
2123
|
+
const picked = pickProject(cfg, projectId);
|
|
2124
|
+
if (!picked) {
|
|
2125
|
+
return {
|
|
2126
|
+
ok: false,
|
|
2127
|
+
error: {
|
|
2128
|
+
error: {
|
|
2129
|
+
code: "no_project",
|
|
2130
|
+
message: "No project_id given and no default project set.",
|
|
2131
|
+
next_action: "Pass project_id, or call agentry_create_project.",
|
|
2132
|
+
},
|
|
2133
|
+
},
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
return { ok: true, id: picked.id };
|
|
2137
|
+
}
|
|
2138
|
+
async function handleListFeatureFlags(input) {
|
|
2139
|
+
const cfg = loadConfig();
|
|
2140
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2141
|
+
if (!r.ok)
|
|
2142
|
+
return r.error;
|
|
2143
|
+
return await api.listFeatureFlags(cfg, r.id, { limit: input.limit });
|
|
2144
|
+
}
|
|
2145
|
+
async function handleGetFeatureFlag(input) {
|
|
2146
|
+
if (!input.flag_id) {
|
|
2147
|
+
return { error: { code: "invalid_payload", message: "flag_id is required.", next_action: "Pass flag_id (numeric, from agentry_list_feature_flags)." } };
|
|
2148
|
+
}
|
|
2149
|
+
const cfg = loadConfig();
|
|
2150
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2151
|
+
if (!r.ok)
|
|
2152
|
+
return r.error;
|
|
2153
|
+
return await api.getFeatureFlag(cfg, r.id, input.flag_id);
|
|
2154
|
+
}
|
|
2155
|
+
async function handleCreateFeatureFlag(input) {
|
|
2156
|
+
if (!input.key) {
|
|
2157
|
+
return { error: { code: "invalid_payload", message: "key is required.", next_action: "Pass key (slug, e.g. 'new-checkout-flow')." } };
|
|
2158
|
+
}
|
|
2159
|
+
const cfg = loadConfig();
|
|
2160
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2161
|
+
if (!r.ok)
|
|
2162
|
+
return r.error;
|
|
2163
|
+
return await api.createFeatureFlag(cfg, r.id, {
|
|
2164
|
+
key: input.key,
|
|
2165
|
+
name: input.name,
|
|
2166
|
+
active: input.active,
|
|
2167
|
+
rollout_percentage: input.rollout_percentage,
|
|
2168
|
+
filters: input.filters,
|
|
2169
|
+
});
|
|
2170
|
+
}
|
|
2171
|
+
async function handleUpdateFeatureFlag(input) {
|
|
2172
|
+
if (!input.flag_id) {
|
|
2173
|
+
return { error: { code: "invalid_payload", message: "flag_id is required.", next_action: "Pass flag_id (numeric)." } };
|
|
2174
|
+
}
|
|
2175
|
+
const cfg = loadConfig();
|
|
2176
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2177
|
+
if (!r.ok)
|
|
2178
|
+
return r.error;
|
|
2179
|
+
return await api.updateFeatureFlag(cfg, r.id, input.flag_id, {
|
|
2180
|
+
active: input.active,
|
|
2181
|
+
name: input.name,
|
|
2182
|
+
rollout_percentage: input.rollout_percentage,
|
|
2183
|
+
filters: input.filters,
|
|
2184
|
+
});
|
|
2185
|
+
}
|
|
2186
|
+
async function handleDeleteFeatureFlag(input) {
|
|
2187
|
+
if (!input.flag_id) {
|
|
2188
|
+
return { error: { code: "invalid_payload", message: "flag_id is required.", next_action: "Pass flag_id (numeric)." } };
|
|
2189
|
+
}
|
|
2190
|
+
const cfg = loadConfig();
|
|
2191
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2192
|
+
if (!r.ok)
|
|
2193
|
+
return r.error;
|
|
2194
|
+
return await api.deleteFeatureFlag(cfg, r.id, input.flag_id);
|
|
2195
|
+
}
|
|
2196
|
+
async function handleListCohorts(projectId) {
|
|
2197
|
+
const cfg = loadConfig();
|
|
2198
|
+
const r = pickOrError(cfg, projectId);
|
|
2199
|
+
if (!r.ok)
|
|
2200
|
+
return r.error;
|
|
2201
|
+
return await api.listCohorts(cfg, r.id);
|
|
2202
|
+
}
|
|
2203
|
+
async function handleGetCohort(input) {
|
|
2204
|
+
if (!input.cohort_id) {
|
|
2205
|
+
return { error: { code: "invalid_payload", message: "cohort_id is required.", next_action: "Pass cohort_id (numeric)." } };
|
|
2206
|
+
}
|
|
2207
|
+
const cfg = loadConfig();
|
|
2208
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2209
|
+
if (!r.ok)
|
|
2210
|
+
return r.error;
|
|
2211
|
+
return await api.getCohort(cfg, r.id, input.cohort_id);
|
|
2212
|
+
}
|
|
2213
|
+
async function handleCreateCohort(input) {
|
|
2214
|
+
if (!input.name) {
|
|
2215
|
+
return { error: { code: "invalid_payload", message: "name is required.", next_action: "Pass cohort name." } };
|
|
2216
|
+
}
|
|
2217
|
+
if (!input.event && (!input.groups || input.groups.length === 0)) {
|
|
2218
|
+
return {
|
|
2219
|
+
error: {
|
|
2220
|
+
code: "invalid_payload",
|
|
2221
|
+
message: "Cohort body must include 'event' (simple shape) or 'groups' (advanced shape).",
|
|
2222
|
+
next_action: "Pass event='signup_completed' (last N days) or pass groups: [...PostHog filter format].",
|
|
2223
|
+
},
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
const cfg = loadConfig();
|
|
2227
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2228
|
+
if (!r.ok)
|
|
2229
|
+
return r.error;
|
|
2230
|
+
const body = input.groups
|
|
2231
|
+
? { name: input.name, groups: input.groups }
|
|
2232
|
+
: { name: input.name, event: input.event, days: input.days };
|
|
2233
|
+
return await api.createCohort(cfg, r.id, body);
|
|
2234
|
+
}
|
|
2235
|
+
async function handleDeleteCohort(input) {
|
|
2236
|
+
if (!input.cohort_id) {
|
|
2237
|
+
return { error: { code: "invalid_payload", message: "cohort_id is required.", next_action: "Pass cohort_id (numeric)." } };
|
|
2238
|
+
}
|
|
2239
|
+
const cfg = loadConfig();
|
|
2240
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2241
|
+
if (!r.ok)
|
|
2242
|
+
return r.error;
|
|
2243
|
+
return await api.deleteCohort(cfg, r.id, input.cohort_id);
|
|
2244
|
+
}
|
|
2245
|
+
async function handleListSurveys(projectId) {
|
|
2246
|
+
const cfg = loadConfig();
|
|
2247
|
+
const r = pickOrError(cfg, projectId);
|
|
2248
|
+
if (!r.ok)
|
|
2249
|
+
return r.error;
|
|
2250
|
+
return await api.listSurveys(cfg, r.id);
|
|
2251
|
+
}
|
|
2252
|
+
async function handleGetSurvey(input) {
|
|
2253
|
+
if (!input.survey_id) {
|
|
2254
|
+
return { error: { code: "invalid_payload", message: "survey_id is required.", next_action: "Pass survey_id." } };
|
|
2255
|
+
}
|
|
2256
|
+
const cfg = loadConfig();
|
|
2257
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2258
|
+
if (!r.ok)
|
|
2259
|
+
return r.error;
|
|
2260
|
+
return await api.getSurvey(cfg, r.id, input.survey_id);
|
|
2261
|
+
}
|
|
2262
|
+
async function handleCreateSurvey(input) {
|
|
2263
|
+
if (!input.name) {
|
|
2264
|
+
return { error: { code: "invalid_payload", message: "name is required.", next_action: "Pass survey name." } };
|
|
2265
|
+
}
|
|
2266
|
+
if (!input.question && (!input.questions || input.questions.length === 0)) {
|
|
2267
|
+
return {
|
|
2268
|
+
error: {
|
|
2269
|
+
code: "invalid_payload",
|
|
2270
|
+
message: "Survey must include 'question' (simple) or 'questions' (multi).",
|
|
2271
|
+
next_action: "Pass question='How likely are you to recommend us?' OR questions: [{type, question}, ...]",
|
|
2272
|
+
},
|
|
2273
|
+
};
|
|
2274
|
+
}
|
|
2275
|
+
const cfg = loadConfig();
|
|
2276
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2277
|
+
if (!r.ok)
|
|
2278
|
+
return r.error;
|
|
2279
|
+
return await api.createSurvey(cfg, r.id, {
|
|
2280
|
+
name: input.name,
|
|
2281
|
+
type: input.type,
|
|
2282
|
+
question: input.question,
|
|
2283
|
+
question_type: input.question_type,
|
|
2284
|
+
questions: input.questions,
|
|
2285
|
+
description: input.description,
|
|
2286
|
+
linked_flag_id: input.linked_flag_id,
|
|
2287
|
+
targeting_flag_id: input.targeting_flag_id,
|
|
2288
|
+
conditions: input.conditions,
|
|
2289
|
+
appearance: input.appearance,
|
|
2290
|
+
start_date: input.start_date,
|
|
2291
|
+
});
|
|
2292
|
+
}
|
|
2293
|
+
async function handleDeleteSurvey(input) {
|
|
2294
|
+
if (!input.survey_id) {
|
|
2295
|
+
return { error: { code: "invalid_payload", message: "survey_id is required.", next_action: "Pass survey_id." } };
|
|
2296
|
+
}
|
|
2297
|
+
const cfg = loadConfig();
|
|
2298
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2299
|
+
if (!r.ok)
|
|
2300
|
+
return r.error;
|
|
2301
|
+
return await api.deleteSurvey(cfg, r.id, input.survey_id);
|
|
2302
|
+
}
|
|
2303
|
+
async function handleListSessionReplays(input) {
|
|
2304
|
+
const cfg = loadConfig();
|
|
2305
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2306
|
+
if (!r.ok)
|
|
2307
|
+
return r.error;
|
|
2308
|
+
return await api.listSessionReplays(cfg, r.id, {
|
|
2309
|
+
distinctId: input.distinct_id,
|
|
2310
|
+
dateFrom: input.date_from,
|
|
2311
|
+
dateTo: input.date_to,
|
|
2312
|
+
limit: input.limit,
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
async function handleGetSessionReplay(input) {
|
|
2316
|
+
if (!input.replay_id) {
|
|
2317
|
+
return { error: { code: "invalid_payload", message: "replay_id is required.", next_action: "Pass replay_id from agentry_list_session_replays." } };
|
|
2318
|
+
}
|
|
2319
|
+
const cfg = loadConfig();
|
|
2320
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2321
|
+
if (!r.ok)
|
|
2322
|
+
return r.error;
|
|
2323
|
+
return await api.getSessionReplay(cfg, r.id, input.replay_id);
|
|
2324
|
+
}
|
|
2325
|
+
async function handleGetReplaySnapshots(input) {
|
|
2326
|
+
if (!input.replay_id) {
|
|
2327
|
+
return { error: { code: "invalid_payload", message: "replay_id is required.", next_action: "Pass replay_id from agentry_list_session_replays." } };
|
|
2328
|
+
}
|
|
2329
|
+
const cfg = loadConfig();
|
|
2330
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2331
|
+
if (!r.ok)
|
|
2332
|
+
return r.error;
|
|
2333
|
+
return await api.getReplaySnapshots(cfg, r.id, input.replay_id, input.source);
|
|
2334
|
+
}
|
|
2335
|
+
async function handleEvaluateFeatureFlag(input) {
|
|
2336
|
+
if (!input.distinct_id) {
|
|
2337
|
+
return { error: { code: "invalid_payload", message: "distinct_id is required.", next_action: "Pass the user identifier (same as case.affected_users[].distinct_id)." } };
|
|
2338
|
+
}
|
|
2339
|
+
const cfg = loadConfig();
|
|
2340
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2341
|
+
if (!r.ok)
|
|
2342
|
+
return r.error;
|
|
2343
|
+
return await api.evaluateFeatureFlag(cfg, r.id, {
|
|
2344
|
+
distinct_id: input.distinct_id,
|
|
2345
|
+
key: input.key,
|
|
2346
|
+
person_properties: input.person_properties,
|
|
2347
|
+
groups: input.groups,
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2350
|
+
async function handleGetDistinctIdSummary(input) {
|
|
2351
|
+
if (!input.distinct_id) {
|
|
2352
|
+
return { error: { code: "invalid_payload", message: "distinct_id is required.", next_action: "Pass the user identifier." } };
|
|
2353
|
+
}
|
|
2354
|
+
const cfg = loadConfig();
|
|
2355
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2356
|
+
if (!r.ok)
|
|
2357
|
+
return r.error;
|
|
2358
|
+
return await api.getDistinctIdSummary(cfg, r.id, input.distinct_id);
|
|
2359
|
+
}
|
|
2360
|
+
async function handleSurveyResponses(input) {
|
|
2361
|
+
if (!input.survey_id) {
|
|
2362
|
+
return { error: { code: "invalid_payload", message: "survey_id is required.", next_action: "Pass survey_id from agentry_list_surveys." } };
|
|
2363
|
+
}
|
|
2364
|
+
const cfg = loadConfig();
|
|
2365
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2366
|
+
if (!r.ok)
|
|
2367
|
+
return r.error;
|
|
2368
|
+
return await api.getSurveyResponses(cfg, r.id, input.survey_id);
|
|
2369
|
+
}
|
|
2370
|
+
async function handleCreateAbTest(input) {
|
|
2371
|
+
if (!input.name) {
|
|
2372
|
+
return { error: { code: "invalid_payload", message: "name is required.", next_action: "Pass an A/B test name." } };
|
|
2373
|
+
}
|
|
2374
|
+
if (!input.success_event) {
|
|
2375
|
+
return { error: { code: "invalid_payload", message: "success_event is required.", next_action: "Pass the conversion event name (e.g. 'checkout_completed')." } };
|
|
2376
|
+
}
|
|
2377
|
+
if (!Array.isArray(input.variants) || input.variants.length < 2) {
|
|
2378
|
+
return { error: { code: "invalid_payload", message: "variants must be ≥2 entries.", next_action: "Pass variants: [{key:'control'},{key:'treatment'}]." } };
|
|
2379
|
+
}
|
|
2380
|
+
const cfg = loadConfig();
|
|
2381
|
+
const r = pickOrError(cfg, input.project_id);
|
|
2382
|
+
if (!r.ok)
|
|
2383
|
+
return r.error;
|
|
2384
|
+
return await api.createAbTest(cfg, r.id, {
|
|
2385
|
+
name: input.name,
|
|
2386
|
+
flag_key: input.flag_key,
|
|
2387
|
+
success_event: input.success_event,
|
|
2388
|
+
variants: input.variants,
|
|
2389
|
+
});
|
|
2390
|
+
}
|
|
2391
|
+
async function handleRecentChanges(input) {
|
|
2392
|
+
const cfg = loadConfig();
|
|
2393
|
+
if (!cfg.api_key) {
|
|
2394
|
+
return {
|
|
2395
|
+
error: {
|
|
2396
|
+
code: "no_key",
|
|
2397
|
+
message: "No API key on file.",
|
|
2398
|
+
next_action: "Call agentry_login.",
|
|
2399
|
+
},
|
|
2400
|
+
};
|
|
2401
|
+
}
|
|
2402
|
+
return await api.listRecentChanges(cfg, {
|
|
2403
|
+
hours: input.hours,
|
|
2404
|
+
actionPrefix: input.action_prefix,
|
|
2405
|
+
resourceType: input.resource_type,
|
|
2406
|
+
projectId: input.project_id,
|
|
2407
|
+
limit: input.limit,
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
1428
2410
|
async function handleListProjects() {
|
|
1429
2411
|
const cfg = loadConfig();
|
|
1430
2412
|
if (!cfg.api_key) {
|