@hyperstar/mcp 0.1.6 → 0.1.10
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/README.md +84 -24
- package/dist/auth/cli-auth-client.js +0 -1
- package/dist/auth/cli-auth-state.js +0 -1
- package/dist/auth/local-callback.js +0 -1
- package/dist/auth/pkce.js +0 -1
- package/dist/bulk-email-guidance.js +0 -1
- package/dist/bulk-email-inputs.d.ts +254 -0
- package/dist/bulk-email-inputs.js +168 -0
- package/dist/bulk-email-tool-body.d.ts +6 -0
- package/dist/bulk-email-tool-body.js +37 -0
- package/dist/campaign-creator-selection.js +0 -1
- package/dist/cli.js +2 -6
- package/dist/config.js +15 -2
- package/dist/discovery.d.ts +6 -0
- package/dist/discovery.js +62 -0
- package/dist/http.js +0 -1
- package/dist/index.js +0 -1
- package/dist/package-metadata.d.ts +2 -0
- package/dist/package-metadata.js +12 -0
- package/dist/schemas.js +0 -1
- package/dist/search-result-projection.d.ts +3 -1
- package/dist/search-result-projection.js +33 -3
- package/dist/server.js +7 -2
- package/dist/tool-descriptions.d.ts +19 -0
- package/dist/tool-descriptions.js +19 -0
- package/dist/tool-guidance.d.ts +10 -0
- package/dist/tool-guidance.js +82 -0
- package/dist/tool-http-helpers.js +0 -1
- package/dist/tool-inputs.d.ts +324 -95
- package/dist/tool-inputs.js +87 -92
- package/dist/tool-result.js +0 -1
- package/dist/tools.js +34 -52
- package/dist/workflow-content.d.ts +43 -0
- package/dist/workflow-content.js +153 -0
- package/dist/workspaces.d.ts +1 -1
- package/dist/workspaces.js +12 -45
- package/package.json +25 -2
- package/dist/auth/cli-auth-client.js.map +0 -1
- package/dist/auth/cli-auth-state.js.map +0 -1
- package/dist/auth/local-callback.js.map +0 -1
- package/dist/auth/pkce.js.map +0 -1
- package/dist/bulk-email-guidance.js.map +0 -1
- package/dist/campaign-creator-selection.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/http.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/schemas.js.map +0 -1
- package/dist/search-result-projection.js.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/tool-http-helpers.js.map +0 -1
- package/dist/tool-inputs.js.map +0 -1
- package/dist/tool-result.js.map +0 -1
- package/dist/tools.js.map +0 -1
- package/dist/workspaces.js.map +0 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { campaignCreatorSelectionBody } from "./campaign-creator-selection.js";
|
|
2
|
+
import { compactJsonObject } from "./tool-http-helpers.js";
|
|
3
|
+
/** Build the campaign bulk-email readiness request body. */
|
|
4
|
+
export function readinessRequestBody(input) {
|
|
5
|
+
return campaignRecipientTargetBody(input);
|
|
6
|
+
}
|
|
7
|
+
/** Build the campaign bulk-email job request body. */
|
|
8
|
+
export function startBulkEmailRequestBody(input) {
|
|
9
|
+
return compactJsonObject([
|
|
10
|
+
["subject", input.subject],
|
|
11
|
+
["body_text", input.body_text],
|
|
12
|
+
["from_email", input.from_email],
|
|
13
|
+
["attachments", input.attachments],
|
|
14
|
+
...campaignRecipientTargetEntries(input),
|
|
15
|
+
["form_id", input.form_id],
|
|
16
|
+
["form_language", input.form_language],
|
|
17
|
+
["idempotency_key", input.idempotency_key],
|
|
18
|
+
["send_confirmation", input.send_confirmation],
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
function campaignRecipientTargetBody(input) {
|
|
22
|
+
return compactJsonObject(campaignRecipientTargetEntries(input));
|
|
23
|
+
}
|
|
24
|
+
function campaignRecipientTargetEntries(input) {
|
|
25
|
+
return [
|
|
26
|
+
[
|
|
27
|
+
"campaign_creator_ids",
|
|
28
|
+
"campaign_creator_ids" in input ? input.campaign_creator_ids : undefined,
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
"campaign_creator_selection",
|
|
32
|
+
campaignCreatorSelectionBody("campaign_creator_selection" in input
|
|
33
|
+
? input.campaign_creator_selection
|
|
34
|
+
: undefined),
|
|
35
|
+
],
|
|
36
|
+
];
|
|
37
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -278,19 +278,16 @@ function resolveLoginAppBaseUrl(env, apiBaseUrl) {
|
|
|
278
278
|
}
|
|
279
279
|
return appBaseUrlForApiBaseUrl(apiBaseUrl);
|
|
280
280
|
}
|
|
281
|
-
/** Map
|
|
281
|
+
/** Map public Product API origins to their matching frontend origins. */
|
|
282
282
|
function appBaseUrlForApiBaseUrl(apiBaseUrl) {
|
|
283
283
|
const origin = new URL(apiBaseUrl).origin;
|
|
284
|
-
if (origin === "https://autopilot.dev.hyper-star.org") {
|
|
285
|
-
return "https://app.dev.hyper-star.org";
|
|
286
|
-
}
|
|
287
284
|
if (origin === "https://autopilot.hyper-star.org") {
|
|
288
285
|
return DEFAULT_APP_BASE_URL;
|
|
289
286
|
}
|
|
290
287
|
if (origin === DEFAULT_API_BASE_URL) {
|
|
291
288
|
return DEFAULT_APP_BASE_URL;
|
|
292
289
|
}
|
|
293
|
-
throw new Error("Set HYPERSTAR_APP_BASE_URL when HYPERSTAR_API_BASE_URL does not use
|
|
290
|
+
throw new Error("Set HYPERSTAR_APP_BASE_URL when HYPERSTAR_API_BASE_URL does not use the production Hyperstar API origin");
|
|
294
291
|
}
|
|
295
292
|
/** Open the system browser for the authorization request. */
|
|
296
293
|
async function openBrowser(url) {
|
|
@@ -323,4 +320,3 @@ if (isDirectCliInvocation(import.meta.url, process.argv[1])) {
|
|
|
323
320
|
process.exitCode = exitCode;
|
|
324
321
|
});
|
|
325
322
|
}
|
|
326
|
-
//# sourceMappingURL=cli.js.map
|
package/dist/config.js
CHANGED
|
@@ -26,7 +26,14 @@ export function loadConfig(options = process.env) {
|
|
|
26
26
|
if (state === null) {
|
|
27
27
|
throw new Error("Run `hyperstar login` or set HYPERSTAR_API_KEY");
|
|
28
28
|
}
|
|
29
|
-
const
|
|
29
|
+
const stateApiBaseUrl = normalizeBaseUrl(state.apiBaseUrl, "stored Hyperstar auth API base URL");
|
|
30
|
+
const rawCliApiBaseUrl = env.HYPERSTAR_API_BASE_URL?.trim();
|
|
31
|
+
const cliApiBaseUrl = normalizeBaseUrl(rawCliApiBaseUrl === undefined || rawCliApiBaseUrl.length === 0
|
|
32
|
+
? stateApiBaseUrl
|
|
33
|
+
: rawCliApiBaseUrl, "HYPERSTAR_API_BASE_URL");
|
|
34
|
+
if (rawCliApiBaseUrl !== undefined && rawCliApiBaseUrl.length > 0) {
|
|
35
|
+
assertCliApiBaseUrlMatchesState(cliApiBaseUrl, stateApiBaseUrl);
|
|
36
|
+
}
|
|
30
37
|
const cliAppBaseUrl = normalizeBaseUrl(env.HYPERSTAR_APP_BASE_URL?.trim() ?? state.appBaseUrl, "HYPERSTAR_APP_BASE_URL");
|
|
31
38
|
const client = createCliAuthClient({
|
|
32
39
|
apiBaseUrl: cliApiBaseUrl,
|
|
@@ -79,6 +86,13 @@ export function redactSecret(value) {
|
|
|
79
86
|
function isValidApiKeyHeaderValue(value) {
|
|
80
87
|
return /^[\x21-\x7e]+$/.test(value);
|
|
81
88
|
}
|
|
89
|
+
/** Refuse to send persisted CLI tokens to a different API base URL. */
|
|
90
|
+
function assertCliApiBaseUrlMatchesState(requestedApiBaseUrl, stateApiBaseUrl) {
|
|
91
|
+
if (requestedApiBaseUrl === stateApiBaseUrl) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
throw new Error("Run `hyperstar login` again before changing HYPERSTAR_API_BASE_URL");
|
|
95
|
+
}
|
|
82
96
|
/** Normalize an env-provided base URL. */
|
|
83
97
|
export function normalizeBaseUrl(rawBaseUrl, envName) {
|
|
84
98
|
let parsed;
|
|
@@ -98,4 +112,3 @@ export function normalizeBaseUrl(rawBaseUrl, envName) {
|
|
|
98
112
|
}
|
|
99
113
|
return parsed.toString().replace(/\/+$/, "");
|
|
100
114
|
}
|
|
101
|
-
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export type HyperstarDiscoveryOptions = {
|
|
3
|
+
readonly apiBaseUrl: string;
|
|
4
|
+
};
|
|
5
|
+
/** Register static MCP resources and prompts that explain Hyperstar workflows. */
|
|
6
|
+
export declare function registerHyperstarDiscovery(server: McpServer, options: HyperstarDiscoveryOptions): void;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { buildWorkflowMarkdown, workflowGuideResourceDefinitions, } from "./workflow-content.js";
|
|
2
|
+
const workflowPromptDefinitions = [
|
|
3
|
+
{
|
|
4
|
+
name: "hyperstar_headless_workflow",
|
|
5
|
+
title: "Hyperstar Headless Workflow",
|
|
6
|
+
description: "Use Hyperstar search, campaign, bulk email, and inbox tools in the recommended order.",
|
|
7
|
+
kind: "headless-workflow",
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
name: "hyperstar_search_to_campaign",
|
|
11
|
+
title: "Hyperstar Search To Campaign",
|
|
12
|
+
description: "Search creators with compact results and save selected results to a campaign.",
|
|
13
|
+
kind: "search-to-campaign",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "hyperstar_bulk_email_safety",
|
|
17
|
+
title: "Hyperstar Bulk Email Safety",
|
|
18
|
+
description: "Check readiness and idempotency before a real bulk-email send.",
|
|
19
|
+
kind: "bulk-email-safety",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "hyperstar_inbox_workflow",
|
|
23
|
+
title: "Hyperstar Inbox Workflow",
|
|
24
|
+
description: "Read, triage, and reply to inbox threads safely.",
|
|
25
|
+
kind: "inbox",
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
/** Register static MCP resources and prompts that explain Hyperstar workflows. */
|
|
29
|
+
export function registerHyperstarDiscovery(server, options) {
|
|
30
|
+
void options;
|
|
31
|
+
for (const resource of workflowGuideResourceDefinitions) {
|
|
32
|
+
server.registerResource(resource.name, resource.uri, {
|
|
33
|
+
title: resource.title,
|
|
34
|
+
description: resource.description,
|
|
35
|
+
mimeType: "text/markdown",
|
|
36
|
+
}, (uri) => ({
|
|
37
|
+
contents: [
|
|
38
|
+
{
|
|
39
|
+
uri: uri.toString(),
|
|
40
|
+
mimeType: "text/markdown",
|
|
41
|
+
text: buildWorkflowMarkdown(resource.kind),
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
for (const prompt of workflowPromptDefinitions) {
|
|
47
|
+
server.registerPrompt(prompt.name, {
|
|
48
|
+
title: prompt.title,
|
|
49
|
+
description: prompt.description,
|
|
50
|
+
}, () => ({
|
|
51
|
+
messages: [
|
|
52
|
+
{
|
|
53
|
+
role: "user",
|
|
54
|
+
content: {
|
|
55
|
+
type: "text",
|
|
56
|
+
text: buildWorkflowMarkdown(prompt.kind),
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
}
|
package/dist/http.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { JsonObjectSchema } from "./schemas.js";
|
|
3
|
+
/** Read package metadata from the package root at runtime. */
|
|
4
|
+
export function packageVersion() {
|
|
5
|
+
const raw = readFileSync(new URL("../package.json", import.meta.url), "utf8");
|
|
6
|
+
const metadata = JsonObjectSchema.parse(JSON.parse(raw));
|
|
7
|
+
const version = metadata.version;
|
|
8
|
+
if (typeof version !== "string" || version.trim().length === 0) {
|
|
9
|
+
throw new Error("package.json version is missing");
|
|
10
|
+
}
|
|
11
|
+
return version;
|
|
12
|
+
}
|
package/dist/schemas.js
CHANGED
|
@@ -66,4 +66,3 @@ export const BulkEmailJobResponseSchema = JsonObjectSchema;
|
|
|
66
66
|
export const InboxThreadPageResponseSchema = JsonObjectSchema;
|
|
67
67
|
export const InboxAggregatesResponseSchema = JsonObjectSchema;
|
|
68
68
|
export const InboxWorkspaceStateResponseSchema = JsonObjectSchema;
|
|
69
|
-
//# sourceMappingURL=schemas.js.map
|
|
@@ -7,4 +7,6 @@ export type SearchResultPage = {
|
|
|
7
7
|
readonly limit: number;
|
|
8
8
|
};
|
|
9
9
|
/** Project search results to the requested MCP-facing detail level. */
|
|
10
|
-
export declare function projectSearchResultPage(page: SearchResultPage, detailLevel: SearchResultDetailLevel
|
|
10
|
+
export declare function projectSearchResultPage(page: SearchResultPage, detailLevel: SearchResultDetailLevel, searchId?: string, options?: {
|
|
11
|
+
readonly deterministicNextPage?: boolean;
|
|
12
|
+
}): JsonObject;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { compactJsonObject } from "./tool-http-helpers.js";
|
|
2
2
|
/** Project search results to the requested MCP-facing detail level. */
|
|
3
|
-
export function projectSearchResultPage(page, detailLevel) {
|
|
3
|
+
export function projectSearchResultPage(page, detailLevel, searchId, options = {}) {
|
|
4
|
+
const pagination = paginationGuidance(page, searchId, options);
|
|
4
5
|
if (detailLevel === "full") {
|
|
5
|
-
return { ...page, detail_level: detailLevel };
|
|
6
|
+
return { ...page, detail_level: detailLevel, ...pagination };
|
|
6
7
|
}
|
|
7
8
|
return {
|
|
8
9
|
...page,
|
|
9
10
|
creators: page.creators.map(compactCreatorSummary),
|
|
10
11
|
detail_level: detailLevel,
|
|
12
|
+
...pagination,
|
|
11
13
|
};
|
|
12
14
|
}
|
|
13
15
|
/** Return a compact creator summary suitable for model context. */
|
|
@@ -71,4 +73,32 @@ function stringArrayValue(value) {
|
|
|
71
73
|
}
|
|
72
74
|
return value;
|
|
73
75
|
}
|
|
74
|
-
|
|
76
|
+
function paginationGuidance(page, searchId, options) {
|
|
77
|
+
const nextOffset = page.offset + page.limit;
|
|
78
|
+
const hasMore = nextOffset < page.total;
|
|
79
|
+
const includeDeterministicNext = options.deterministicNextPage !== false &&
|
|
80
|
+
hasMore &&
|
|
81
|
+
searchId !== undefined;
|
|
82
|
+
return compactJsonObject([
|
|
83
|
+
["has_more", hasMore],
|
|
84
|
+
["next_offset", hasMore ? nextOffset : undefined],
|
|
85
|
+
[
|
|
86
|
+
"agent_guidance",
|
|
87
|
+
searchId === undefined
|
|
88
|
+
? undefined
|
|
89
|
+
: "Use search_id server-side for campaign import. Page with get_search_results only when the user needs more creator summaries; do not load every creator into context.",
|
|
90
|
+
],
|
|
91
|
+
["next_tool", includeDeterministicNext ? "get_search_results" : undefined],
|
|
92
|
+
[
|
|
93
|
+
"next_arguments",
|
|
94
|
+
includeDeterministicNext
|
|
95
|
+
? {
|
|
96
|
+
search_id: searchId,
|
|
97
|
+
offset: nextOffset,
|
|
98
|
+
limit: page.limit,
|
|
99
|
+
detail_level: "summary",
|
|
100
|
+
}
|
|
101
|
+
: undefined,
|
|
102
|
+
],
|
|
103
|
+
]);
|
|
104
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { registerHyperstarDiscovery } from "./discovery.js";
|
|
2
3
|
import { createHyperstarClient } from "./http.js";
|
|
4
|
+
import { packageVersion } from "./package-metadata.js";
|
|
3
5
|
import { registerHyperstarTools } from "./tools.js";
|
|
4
6
|
/** Create the Hyperstar MCP server and register HTTP-backed workflow tools. */
|
|
5
7
|
export function createHyperstarMcpServer(config) {
|
|
6
|
-
const server = new McpServer({
|
|
8
|
+
const server = new McpServer({
|
|
9
|
+
name: "hyperstar",
|
|
10
|
+
version: packageVersion(),
|
|
11
|
+
});
|
|
12
|
+
registerHyperstarDiscovery(server, { apiBaseUrl: config.apiBaseUrl });
|
|
7
13
|
registerHyperstarTools(server, createHyperstarClient({ config }), config.authMode === "cli"
|
|
8
14
|
? { workspaceSelection: config.workspaceSelection }
|
|
9
15
|
: {});
|
|
10
16
|
return server;
|
|
11
17
|
}
|
|
12
|
-
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const TOOL_DESCRIPTIONS: {
|
|
2
|
+
readonly hyperstarWhoami: "Inspect the authenticated Hyperstar principal, workspace, scopes, and capabilities before running workflow tools.";
|
|
3
|
+
readonly listWorkspaces: "List Hyperstar workspaces available to the current auth session. In local browser CLI auth, call select_workspace next when a workspace is not selected.";
|
|
4
|
+
readonly selectWorkspace: "Persist the Hyperstar workspace selected for CLI-authenticated tools. Call hyperstar_whoami next to confirm scope.";
|
|
5
|
+
readonly workflowGuide: "Return the recommended Hyperstar workflow sequence, discovery resources, and send-safety notes.";
|
|
6
|
+
readonly searchCreators: "Create a creator search and return the first page as compact creator summaries. Filters use structured keys such as follower_range, avg_engagement_rate, avg_views, has_email, email_contactability, creator_language, category_1, category_name, gmv, and gpm. Put broad niches in query unless a platform-specific category field applies. Use search_id with save_search_results_to_campaign; request detail_level full only when raw rows are needed.";
|
|
7
|
+
readonly getSearchResults: "Page through an existing creator search. Defaults to compact creator summaries; use detail_level full only for raw detail-on-demand pages.";
|
|
8
|
+
readonly listCampaigns: "List campaigns in the authenticated workspace so agents can choose a campaign_id before saving search results.";
|
|
9
|
+
readonly createCampaign: "Create a campaign in the authenticated workspace. Use the returned campaign id with save_search_results_to_campaign.";
|
|
10
|
+
readonly saveSearchResultsToCampaign: "Save selected or top-ranked creator search results to a campaign roster server-side using search_id.";
|
|
11
|
+
readonly listCampaignCreators: "List creators saved on a campaign roster. Call check_bulk_email_readiness before any bulk-email send.";
|
|
12
|
+
readonly checkBulkEmailReadiness: "The final dry-run gate before bulk email. Requires recipient_target with exact IDs or a narrowed selection, checks those selected recipients, and returns sendability guidance.";
|
|
13
|
+
readonly startBulkEmail: "REAL SEND: start a campaign bulk-email job after readiness has passed and the user authorized sending. Requires recipient_target, an explicit idempotency key, and send_confirmation: \"user_authorized\".";
|
|
14
|
+
readonly getBulkEmailJob: "Read campaign bulk-email job status after start_bulk_email returns a job_id.";
|
|
15
|
+
readonly listInboxThreads: "List Hyperstar inbox threads with filters for triage before reading or replying.";
|
|
16
|
+
readonly getInboxAggregates: "Read aggregate counts for Hyperstar inbox filters to summarize inbox state.";
|
|
17
|
+
readonly updateInboxThreadState: "Archive, snooze, star, or set read state for one inbox thread without sending a message.";
|
|
18
|
+
readonly sendInboxReply: "REAL SEND: send one user-authorized reply to a Hyperstar inbox thread with an explicit idempotency key.";
|
|
19
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const TOOL_DESCRIPTIONS = {
|
|
2
|
+
hyperstarWhoami: "Inspect the authenticated Hyperstar principal, workspace, scopes, and capabilities before running workflow tools.",
|
|
3
|
+
listWorkspaces: "List Hyperstar workspaces available to the current auth session. In local browser CLI auth, call select_workspace next when a workspace is not selected.",
|
|
4
|
+
selectWorkspace: "Persist the Hyperstar workspace selected for CLI-authenticated tools. Call hyperstar_whoami next to confirm scope.",
|
|
5
|
+
workflowGuide: "Return the recommended Hyperstar workflow sequence, discovery resources, and send-safety notes.",
|
|
6
|
+
searchCreators: "Create a creator search and return the first page as compact creator summaries. Filters use structured keys such as follower_range, avg_engagement_rate, avg_views, has_email, email_contactability, creator_language, category_1, category_name, gmv, and gpm. Put broad niches in query unless a platform-specific category field applies. Use search_id with save_search_results_to_campaign; request detail_level full only when raw rows are needed.",
|
|
7
|
+
getSearchResults: "Page through an existing creator search. Defaults to compact creator summaries; use detail_level full only for raw detail-on-demand pages.",
|
|
8
|
+
listCampaigns: "List campaigns in the authenticated workspace so agents can choose a campaign_id before saving search results.",
|
|
9
|
+
createCampaign: "Create a campaign in the authenticated workspace. Use the returned campaign id with save_search_results_to_campaign.",
|
|
10
|
+
saveSearchResultsToCampaign: "Save selected or top-ranked creator search results to a campaign roster server-side using search_id.",
|
|
11
|
+
listCampaignCreators: "List creators saved on a campaign roster. Call check_bulk_email_readiness before any bulk-email send.",
|
|
12
|
+
checkBulkEmailReadiness: "The final dry-run gate before bulk email. Requires recipient_target with exact IDs or a narrowed selection, checks those selected recipients, and returns sendability guidance.",
|
|
13
|
+
startBulkEmail: 'REAL SEND: start a campaign bulk-email job after readiness has passed and the user authorized sending. Requires recipient_target, an explicit idempotency key, and send_confirmation: "user_authorized".',
|
|
14
|
+
getBulkEmailJob: "Read campaign bulk-email job status after start_bulk_email returns a job_id.",
|
|
15
|
+
listInboxThreads: "List Hyperstar inbox threads with filters for triage before reading or replying.",
|
|
16
|
+
getInboxAggregates: "Read aggregate counts for Hyperstar inbox filters to summarize inbox state.",
|
|
17
|
+
updateInboxThreadState: "Archive, snooze, star, or set read state for one inbox thread without sending a message.",
|
|
18
|
+
sendInboxReply: "REAL SEND: send one user-authorized reply to a Hyperstar inbox thread with an explicit idempotency key.",
|
|
19
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JsonObject } from "./http.js";
|
|
2
|
+
import type { CheckBulkEmailReadinessInput } from "./tool-inputs.js";
|
|
3
|
+
/** Add next-step guidance after creator search. */
|
|
4
|
+
export declare function searchGuidance(page: JsonObject): JsonObject;
|
|
5
|
+
/** Add deterministic next-step guidance after campaign import. */
|
|
6
|
+
export declare function campaignImportGuidance(payload: JsonObject, campaignId: number): JsonObject;
|
|
7
|
+
/** Add deterministic next-step guidance after listing campaign creators. */
|
|
8
|
+
export declare function campaignRosterGuidance(payload: JsonObject, campaignId: number): JsonObject;
|
|
9
|
+
/** Add send or no-send guidance after the readiness dry run. */
|
|
10
|
+
export declare function readinessGuidance(payload: JsonObject, input: CheckBulkEmailReadinessInput): JsonObject;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { campaignCreatorSelectionBody } from "./campaign-creator-selection.js";
|
|
2
|
+
import { compactJsonObject } from "./tool-http-helpers.js";
|
|
3
|
+
/** Add next-step guidance after creator search. */
|
|
4
|
+
export function searchGuidance(page) {
|
|
5
|
+
return {
|
|
6
|
+
...page,
|
|
7
|
+
next_tools: [
|
|
8
|
+
"list_campaigns",
|
|
9
|
+
"create_campaign",
|
|
10
|
+
"save_search_results_to_campaign",
|
|
11
|
+
],
|
|
12
|
+
agent_guidance: "Use list_campaigns or create_campaign to choose a campaign_id. If the user already supplied a campaign_id, call save_search_results_to_campaign with this search_id; do not load every creator into context.",
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** Add deterministic next-step guidance after campaign import. */
|
|
16
|
+
export function campaignImportGuidance(payload, campaignId) {
|
|
17
|
+
return {
|
|
18
|
+
...payload,
|
|
19
|
+
next_tool: "list_campaign_creators",
|
|
20
|
+
next_arguments: { campaign_id: campaignId },
|
|
21
|
+
agent_guidance: "Search results were saved server-side. Call list_campaign_creators to inspect the campaign roster before outreach.",
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Add deterministic next-step guidance after listing campaign creators. */
|
|
25
|
+
export function campaignRosterGuidance(payload, campaignId) {
|
|
26
|
+
return {
|
|
27
|
+
...payload,
|
|
28
|
+
next_tool: "check_bulk_email_readiness",
|
|
29
|
+
next_arguments: { campaign_id: campaignId },
|
|
30
|
+
next_required_arguments: ["recipient_target"],
|
|
31
|
+
agent_guidance: "Before any bulk email, call check_bulk_email_readiness with recipient_target set to exact campaign creator IDs or a narrowed selection filter.",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** Add send or no-send guidance after the readiness dry run. */
|
|
35
|
+
export function readinessGuidance(payload, input) {
|
|
36
|
+
const sendable = numberValue(payload.sendable);
|
|
37
|
+
const campaignCreatorIds = "campaign_creator_ids" in input ? input.campaign_creator_ids : undefined;
|
|
38
|
+
const campaignCreatorSelection = "campaign_creator_selection" in input
|
|
39
|
+
? input.campaign_creator_selection
|
|
40
|
+
: undefined;
|
|
41
|
+
if (sendable === undefined || sendable <= 0) {
|
|
42
|
+
return {
|
|
43
|
+
...payload,
|
|
44
|
+
agent_guidance: "Do not call start_bulk_email: no selected recipients are currently sendable. Adjust the campaign roster or recipient selection, then run check_bulk_email_readiness again.",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
...payload,
|
|
49
|
+
next_tool: "start_bulk_email",
|
|
50
|
+
next_arguments: compactJsonObject([
|
|
51
|
+
["campaign_id", input.campaign_id],
|
|
52
|
+
[
|
|
53
|
+
"recipient_target",
|
|
54
|
+
recipientTargetArgument(campaignCreatorIds, campaignCreatorSelection),
|
|
55
|
+
],
|
|
56
|
+
]),
|
|
57
|
+
next_required_arguments: [
|
|
58
|
+
"subject",
|
|
59
|
+
"body_text",
|
|
60
|
+
"idempotency_key",
|
|
61
|
+
"send_confirmation",
|
|
62
|
+
],
|
|
63
|
+
agent_guidance: 'Readiness passed. start_bulk_email performs a real send, so only call it after user authorization and after filling subject, body_text, a stable idempotency_key, and send_confirmation: "user_authorized".',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function recipientTargetArgument(ids, selection) {
|
|
67
|
+
if (ids !== undefined) {
|
|
68
|
+
return { type: "ids", campaign_creator_ids: [...ids] };
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
type: "selection",
|
|
72
|
+
campaign_creator_selection: selectionBody(selection) ?? {},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function selectionBody(selection) {
|
|
76
|
+
return campaignCreatorSelectionBody(selection);
|
|
77
|
+
}
|
|
78
|
+
function numberValue(value) {
|
|
79
|
+
return typeof value === "number" && Number.isFinite(value)
|
|
80
|
+
? value
|
|
81
|
+
: undefined;
|
|
82
|
+
}
|