posterly-mcp-server 0.43.4 → 0.43.6
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 +18 -18
- package/SUBMISSIONS.md +31 -4
- package/dist/lib/api-client.js +2 -2
- package/dist/lib/format.js +1 -1
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.js +1 -1
- package/dist/tools/ask-support.js +3 -3
- package/dist/tools/cancel-subscription.js +2 -2
- package/dist/tools/create-api-key.js +1 -1
- package/dist/tools/create-connect-session.js +3 -3
- package/dist/tools/create-post.js +6 -6
- package/dist/tools/create-posts-batch.js +2 -2
- package/dist/tools/delete-api-key.js +1 -1
- package/dist/tools/delete-post.js +2 -2
- package/dist/tools/generate-captions.js +1 -1
- package/dist/tools/generate-image.js +1 -1
- package/dist/tools/get-agent-signup-info.js +8 -8
- package/dist/tools/get-comment.js +1 -1
- package/dist/tools/get-connect-link.js +1 -1
- package/dist/tools/get-connect-session.js +4 -4
- package/dist/tools/get-mcp-status.js +4 -4
- package/dist/tools/get-post.js +1 -1
- package/dist/tools/get-signup-session.js +7 -7
- package/dist/tools/list-accounts.js +1 -1
- package/dist/tools/list-brands.js +1 -1
- package/dist/tools/list-comments.d.ts +4 -4
- package/dist/tools/list-comments.js +3 -3
- package/dist/tools/list-platforms.js +1 -1
- package/dist/tools/list-posts.js +3 -3
- package/dist/tools/reply-to-comment.js +1 -1
- package/dist/tools/start-signup.js +11 -11
- package/dist/tools/sync-inbox.js +2 -2
- package/dist/tools/update-post.js +2 -2
- package/dist/tools/upload-media-from-url.js +1 -1
- package/dist/tools/whoami.js +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/lib/api-client.ts +2 -2
- package/src/lib/format.ts +1 -1
- package/src/lib/version.ts +1 -1
- package/src/tools/ask-support.ts +3 -3
- package/src/tools/cancel-subscription.ts +2 -2
- package/src/tools/create-api-key.ts +1 -1
- package/src/tools/create-connect-session.ts +3 -3
- package/src/tools/create-post.ts +6 -6
- package/src/tools/create-posts-batch.ts +2 -2
- package/src/tools/delete-api-key.ts +1 -1
- package/src/tools/delete-post.ts +2 -2
- package/src/tools/generate-captions.ts +1 -1
- package/src/tools/generate-image.ts +1 -1
- package/src/tools/get-agent-signup-info.ts +8 -8
- package/src/tools/get-comment.ts +1 -1
- package/src/tools/get-connect-link.ts +1 -1
- package/src/tools/get-connect-session.ts +4 -4
- package/src/tools/get-mcp-status.ts +4 -4
- package/src/tools/get-post.ts +1 -1
- package/src/tools/get-signup-session.ts +7 -7
- package/src/tools/list-accounts.ts +1 -1
- package/src/tools/list-brands.ts +1 -1
- package/src/tools/list-comments.ts +4 -4
- package/src/tools/list-platforms.ts +1 -1
- package/src/tools/list-posts.ts +3 -3
- package/src/tools/reply-to-comment.ts +1 -1
- package/src/tools/start-signup.ts +11 -11
- package/src/tools/sync-inbox.ts +2 -2
- package/src/tools/update-post.ts +2 -2
- package/src/tools/upload-media-from-url.ts +1 -1
- package/src/tools/whoami.ts +1 -1
|
@@ -14,7 +14,7 @@ export const listBrandsTool = {
|
|
|
14
14
|
if (brands.length === 0) {
|
|
15
15
|
return input.workspace_id
|
|
16
16
|
? mdEmpty('brands', 'This workspace does not have any brands or clients yet.')
|
|
17
|
-
: mdEmpty('brands', 'No brands or clients were found for this API key.', 'Create a brand in the
|
|
17
|
+
: mdEmpty('brands', 'No brands or clients were found for this API key.', 'Create a brand in the posterly dashboard, then run this again.');
|
|
18
18
|
}
|
|
19
19
|
return [
|
|
20
20
|
mdTitle(`Brands (${brands.length})`),
|
|
@@ -6,13 +6,13 @@ export declare const listCommentsTool: {
|
|
|
6
6
|
inputSchema: z.ZodObject<{
|
|
7
7
|
workspace_id: z.ZodOptional<z.ZodString>;
|
|
8
8
|
account_id: z.ZodOptional<z.ZodNumber>;
|
|
9
|
-
platform: z.ZodOptional<z.ZodEnum<["instagram", "facebook", "threads"]>>;
|
|
9
|
+
platform: z.ZodOptional<z.ZodEnum<["instagram", "facebook", "threads", "linkedin"]>>;
|
|
10
10
|
filter: z.ZodOptional<z.ZodEnum<["all", "unread", "flagged"]>>;
|
|
11
11
|
search: z.ZodOptional<z.ZodString>;
|
|
12
12
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
13
13
|
offset: z.ZodOptional<z.ZodNumber>;
|
|
14
14
|
}, "strip", z.ZodTypeAny, {
|
|
15
|
-
platform?: "instagram" | "facebook" | "threads" | undefined;
|
|
15
|
+
platform?: "instagram" | "facebook" | "threads" | "linkedin" | undefined;
|
|
16
16
|
workspace_id?: string | undefined;
|
|
17
17
|
account_id?: number | undefined;
|
|
18
18
|
limit?: number | undefined;
|
|
@@ -20,7 +20,7 @@ export declare const listCommentsTool: {
|
|
|
20
20
|
filter?: "all" | "unread" | "flagged" | undefined;
|
|
21
21
|
search?: string | undefined;
|
|
22
22
|
}, {
|
|
23
|
-
platform?: "instagram" | "facebook" | "threads" | undefined;
|
|
23
|
+
platform?: "instagram" | "facebook" | "threads" | "linkedin" | undefined;
|
|
24
24
|
workspace_id?: string | undefined;
|
|
25
25
|
account_id?: number | undefined;
|
|
26
26
|
limit?: number | undefined;
|
|
@@ -31,7 +31,7 @@ export declare const listCommentsTool: {
|
|
|
31
31
|
execute(client: PosterlyClient, input: {
|
|
32
32
|
workspace_id?: string;
|
|
33
33
|
account_id?: number;
|
|
34
|
-
platform?: "instagram" | "facebook" | "threads";
|
|
34
|
+
platform?: "instagram" | "facebook" | "threads" | "linkedin";
|
|
35
35
|
filter?: "all" | "unread" | "flagged";
|
|
36
36
|
search?: string;
|
|
37
37
|
limit?: number;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { truncateText } from '../lib/format.js';
|
|
3
|
-
const INBOX_PLATFORMS = ['instagram', 'facebook', 'threads'];
|
|
3
|
+
const INBOX_PLATFORMS = ['instagram', 'facebook', 'threads', 'linkedin'];
|
|
4
4
|
export const listCommentsTool = {
|
|
5
5
|
name: 'list_comments',
|
|
6
|
-
description: 'List social inbox comments and replies for Instagram, Facebook Pages, and
|
|
6
|
+
description: 'List social inbox comments and replies for Instagram, Facebook Pages, Threads, and LinkedIn Pages. Filter by account, platform, unread/flagged, or search. Requires a Pro plan or higher plus posts:read.',
|
|
7
7
|
inputSchema: z.object({
|
|
8
8
|
workspace_id: z.string().optional().describe('Filter to a workspace ID from whoami.'),
|
|
9
9
|
account_id: z.number().int().positive().optional().describe('Social account ID from list_accounts.'),
|
|
10
|
-
platform: z.enum(INBOX_PLATFORMS).optional().describe('instagram, facebook, or
|
|
10
|
+
platform: z.enum(INBOX_PLATFORMS).optional().describe('instagram, facebook, threads, or linkedin.'),
|
|
11
11
|
filter: z.enum(['all', 'unread', 'flagged']).optional().describe('Comment filter. Defaults to all.'),
|
|
12
12
|
search: z.string().optional().describe('Search comment content or author username.'),
|
|
13
13
|
limit: z.number().int().min(1).max(100).optional().describe('Number of comments to return. Default 50, max 100.'),
|
|
@@ -15,6 +15,6 @@ export const listPlatformsTool = {
|
|
|
15
15
|
const helperCount = platform.helper_tools?.length || 0;
|
|
16
16
|
return `• ${platform.label} (${platform.id}): ${platform.status}; post types: ${platform.post_types.join(', ') || 'n/a'}; helpers: ${helperCount}; analytics: ${platform.analytics_supported ? 'yes' : 'no'}`;
|
|
17
17
|
});
|
|
18
|
-
return `
|
|
18
|
+
return `posterly platforms (${result.platforms.length}):\n${lines.join('\n')}`;
|
|
19
19
|
},
|
|
20
20
|
};
|
package/dist/tools/list-posts.js
CHANGED
|
@@ -42,7 +42,7 @@ export const listPostsTool = {
|
|
|
42
42
|
limit: input.limit || 20,
|
|
43
43
|
});
|
|
44
44
|
if (posts.length === 0) {
|
|
45
|
-
return 'No posts found matching your criteria.\n\nNext step for the AI agent: tell the user their
|
|
45
|
+
return 'No posts found matching your criteria.\n\nNext step for the AI agent: tell the user their posterly queue is clear for that filter, then ask what they want to schedule next.';
|
|
46
46
|
}
|
|
47
47
|
const lines = posts.map((p) => {
|
|
48
48
|
const date = formatLocalDateTime(p.scheduled_at);
|
|
@@ -64,8 +64,8 @@ export const listPostsTool = {
|
|
|
64
64
|
`Posts (${posts.length} of ${total}):`,
|
|
65
65
|
...lines,
|
|
66
66
|
'',
|
|
67
|
-
`View in
|
|
68
|
-
'Next step for the AI agent: summarize the queue in plain language and use the dashboard link above if the user wants to inspect it in
|
|
67
|
+
`View in posterly: ${dashboardUrlForPostList(posts)}`,
|
|
68
|
+
'Next step for the AI agent: summarize the queue in plain language and use the dashboard link above if the user wants to inspect it in posterly.',
|
|
69
69
|
].join('\n');
|
|
70
70
|
},
|
|
71
71
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export const replyToCommentTool = {
|
|
3
3
|
name: 'reply_to_comment',
|
|
4
|
-
description: 'Reply to an Instagram, Facebook Page, or
|
|
4
|
+
description: 'Reply to an Instagram, Facebook Page, Threads, or LinkedIn Page inbox comment. WRITE: posts to the social network. Facebook has no private comment replies. Threads has no DMs, so only public replies. Instagram supports public or private. LinkedIn Page comments are public replies only. Requires a Pro plan or higher plus posts:write. Pass confirm=true only after explicit user confirmation.',
|
|
5
5
|
inputSchema: z.object({
|
|
6
6
|
comment_id: z.string().min(1).describe('Comment ID from list_comments.'),
|
|
7
7
|
content: z.string().min(1).describe('Reply text to post.'),
|
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
const DEFAULT_RETURN_PATH = '/dashboard/api?api_signup=success';
|
|
3
3
|
export const startSignupTool = {
|
|
4
4
|
name: 'start_signup',
|
|
5
|
-
description: 'Start the public
|
|
5
|
+
description: 'Start the public posterly paid signup flow for a user before posterly API access exists. Returns a signup poll URL, a browser Checkout fallback URL, and, when enabled, a prepaid PaymentIntent the agent can pay with a Link Agent Wallet virtual card (credential_type: card). The user still sets a password and approves social OAuth in the browser. Never ask for card numbers, a posterly password, or social passwords in chat.',
|
|
6
6
|
inputSchema: z.object({
|
|
7
7
|
email: z
|
|
8
8
|
.string()
|
|
@@ -11,11 +11,11 @@ export const startSignupTool = {
|
|
|
11
11
|
name: z
|
|
12
12
|
.string()
|
|
13
13
|
.optional()
|
|
14
|
-
.describe('Optional user or workspace name to pass into
|
|
14
|
+
.describe('Optional user or workspace name to pass into posterly signup.'),
|
|
15
15
|
tier: z
|
|
16
16
|
.enum(['starter', 'pro', 'power_user', 'agency'])
|
|
17
17
|
.default('starter')
|
|
18
|
-
.describe('
|
|
18
|
+
.describe('posterly plan to start. Use starter unless the user explicitly chooses another plan.'),
|
|
19
19
|
interval: z
|
|
20
20
|
.enum(['month'])
|
|
21
21
|
.default('month')
|
|
@@ -27,7 +27,7 @@ export const startSignupTool = {
|
|
|
27
27
|
return_path: z
|
|
28
28
|
.string()
|
|
29
29
|
.default(DEFAULT_RETURN_PATH)
|
|
30
|
-
.describe('Where
|
|
30
|
+
.describe('Where posterly should continue after checkout and password setup.'),
|
|
31
31
|
source: z
|
|
32
32
|
.string()
|
|
33
33
|
.default('posterly_mcp_pre_auth_signup')
|
|
@@ -72,7 +72,7 @@ function formatSignupStart(response, includeRaw) {
|
|
|
72
72
|
const agentPay = response.agent_pay || session?.agent_pay;
|
|
73
73
|
const payment = response.payment || session?.payment;
|
|
74
74
|
const lines = [
|
|
75
|
-
'
|
|
75
|
+
'posterly signup started.',
|
|
76
76
|
sessionId ? `Signup session: ${sessionId}` : '',
|
|
77
77
|
`Status: ${status}`,
|
|
78
78
|
message ? `Message: ${message}` : '',
|
|
@@ -109,17 +109,17 @@ function formatSignupStart(response, includeRaw) {
|
|
|
109
109
|
'1. Prefer agent_pay: confirm the PaymentIntent with a one-time Link Agent Wallet virtual card (credential_type: card). Never paste card numbers into chat or send them to posterly.',
|
|
110
110
|
'2. If the user would rather pay on the website, send them the Checkout handoff URL instead.',
|
|
111
111
|
'3. Call get_signup_session with the signup session ID until the status changes.',
|
|
112
|
-
'4. Tell the user when
|
|
113
|
-
'5. If status becomes agent_access_required, ask the user to install or paste the
|
|
114
|
-
'6. Do not ask for card details, the
|
|
112
|
+
'4. Tell the user when posterly sends the password setup email. Password, social OAuth, and publish approval stay in the browser.',
|
|
113
|
+
'5. If status becomes agent_access_required, ask the user to install or paste the posterly MCP/API setup instructions into this trusted AI chat, then onboard them in this conversation (about you, connect, brand voice, first post). Do not send them to /onboarding-v2.',
|
|
114
|
+
'6. Do not ask for card details, the posterly password, social passwords, or OAuth codes.',
|
|
115
115
|
]
|
|
116
116
|
: [
|
|
117
117
|
'1. If you hold an approved payment credential such as a Link agent wallet, you can pay the Checkout handoff URL yourself: create a spend request for the amount and merchant above, get the user\'s approval in the wallet, then complete the Checkout page with that credential. Never paste card numbers into chat or send them to posterly.',
|
|
118
118
|
'2. Otherwise, send the Checkout handoff URL to the user so they can pay securely in their browser. Use the raw Stripe checkout URL only if you preserve the full URL including any fragment. posterly does not email this link, so do not tell the user to check their inbox at this stage.',
|
|
119
119
|
'3. Call get_signup_session with the signup session ID until the status changes.',
|
|
120
|
-
'4. Tell the user when
|
|
121
|
-
'5. If status becomes agent_access_required, ask the user to install or paste the
|
|
122
|
-
'6. Do not ask for card details, the
|
|
120
|
+
'4. Tell the user when posterly sends the password setup email.',
|
|
121
|
+
'5. If status becomes agent_access_required, ask the user to install or paste the posterly MCP/API setup instructions into this trusted AI chat, then onboard them in this conversation (about you, connect, brand voice, first post). Do not send them to /onboarding-v2.',
|
|
122
|
+
'6. Do not ask for card details, the posterly password, social passwords, or OAuth codes.',
|
|
123
123
|
]),
|
|
124
124
|
includeRaw ? `\nRaw signup response:\n${JSON.stringify(response, null, 2)}` : '',
|
|
125
125
|
];
|
package/dist/tools/sync-inbox.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export const syncInboxTool = {
|
|
3
3
|
name: 'sync_inbox',
|
|
4
|
-
description: 'Pull the latest Instagram, Facebook Page, or
|
|
4
|
+
description: 'Pull the latest Instagram, Facebook Page, Threads, or LinkedIn inbox data for one connected account. Honors a 30-second cooldown (60 seconds for LinkedIn). Threads and LinkedIn sync comments only (no DMs). Requires a Pro plan or higher plus posts:write.',
|
|
5
5
|
inputSchema: z.object({
|
|
6
6
|
account_id: z.number().int().positive().describe('Social account ID from list_accounts.'),
|
|
7
|
-
sync_type: z.enum(['all', 'dm', 'comments']).optional().describe('What to sync. Defaults to all. Threads
|
|
7
|
+
sync_type: z.enum(['all', 'dm', 'comments']).optional().describe('What to sync. Defaults to all. Threads and LinkedIn are comments-only.'),
|
|
8
8
|
workspace_id: z.string().optional().describe('Workspace ID from whoami.'),
|
|
9
9
|
}),
|
|
10
10
|
async execute(client, input) {
|
|
@@ -116,8 +116,8 @@ export const updatePostTool = {
|
|
|
116
116
|
.string()
|
|
117
117
|
.optional()
|
|
118
118
|
.describe('New scheduled time (ISO 8601, e.g. 2026-03-10T09:00:00Z)'),
|
|
119
|
-
media_url: z.string().optional().describe('New media URL. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into
|
|
120
|
-
media_urls: z.array(z.string()).optional().describe('New media URLs for carousel. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into
|
|
119
|
+
media_url: z.string().optional().describe('New media URL. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into posterly storage before the post is saved. Short-lived signed URLs must still be live when this tool runs.'),
|
|
120
|
+
media_urls: z.array(z.string()).optional().describe('New media URLs for carousel. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into posterly storage before the post is saved.'),
|
|
121
121
|
post_type: z
|
|
122
122
|
.string()
|
|
123
123
|
.optional()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export const uploadMediaFromUrlTool = {
|
|
3
3
|
name: 'upload_media_from_url',
|
|
4
|
-
description: 'Fetch an image or video from a public HTTPS URL into
|
|
4
|
+
description: 'Fetch an image or video from a public HTTPS URL into posterly storage. Returns a URL that can be used with create_post. You can also pass public HTTP(S) media URLs directly to create_post/update_post; use this tool when you want to upload once and reuse the returned posterly URL.',
|
|
5
5
|
inputSchema: z.object({
|
|
6
6
|
url: z.string().url().describe('Public HTTPS URL for the image or video. Local/private network URLs are blocked.'),
|
|
7
7
|
filename: z.string().optional().describe('Optional filename override.'),
|
package/dist/tools/whoami.js
CHANGED
|
@@ -7,7 +7,7 @@ export const whoamiTool = {
|
|
|
7
7
|
async execute(client) {
|
|
8
8
|
const info = await client.whoami();
|
|
9
9
|
return [
|
|
10
|
-
mdTitle('
|
|
10
|
+
mdTitle('posterly identity'),
|
|
11
11
|
mdKeyValue([
|
|
12
12
|
['User', info.user.email || code(info.user.id)],
|
|
13
13
|
['API scopes', info.api_key.scopes.join(', ') || 'none'],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "posterly-mcp-server",
|
|
3
|
-
"version": "0.43.
|
|
3
|
+
"version": "0.43.6",
|
|
4
4
|
"mcpName": "io.github.awpthorp/posterly",
|
|
5
5
|
"description": "MCP server for posterly: schedule and publish social media posts across 18 platforms from any MCP client (Claude, ChatGPT, Cursor, Windsurf, Cline, and more)",
|
|
6
6
|
"license": "MIT",
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.awpthorp/posterly",
|
|
4
4
|
"title": "posterly",
|
|
5
5
|
"description": "Validate, schedule, publish, and analyze social content across 18 platforms with posterly.",
|
|
6
|
-
"version": "0.43.
|
|
6
|
+
"version": "0.43.6",
|
|
7
7
|
"websiteUrl": "https://www.poster.ly/mcp",
|
|
8
8
|
"repository": {
|
|
9
9
|
"url": "https://github.com/awpthorp/posterly",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
{
|
|
15
15
|
"registryType": "npm",
|
|
16
16
|
"identifier": "posterly-mcp-server",
|
|
17
|
-
"version": "0.43.
|
|
17
|
+
"version": "0.43.6",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|
|
20
20
|
},
|
package/src/lib/api-client.ts
CHANGED
|
@@ -1109,7 +1109,7 @@ export class PosterlyClient {
|
|
|
1109
1109
|
private requireApiKey(): void {
|
|
1110
1110
|
if (!this.apiKey) {
|
|
1111
1111
|
throw new Error(
|
|
1112
|
-
'
|
|
1112
|
+
'posterly access is not installed yet. Use start_signup to begin paid setup, or set POSTERLY_API_KEY after signup.'
|
|
1113
1113
|
);
|
|
1114
1114
|
}
|
|
1115
1115
|
}
|
|
@@ -2155,7 +2155,7 @@ export function validatePosterlyBaseUrlForKeyUse(baseUrl: string): void {
|
|
|
2155
2155
|
!flagEnabled('POSTERLY_ALLOW_CUSTOM_BASE_URL')
|
|
2156
2156
|
) {
|
|
2157
2157
|
throw new Error(
|
|
2158
|
-
`Refusing to send an API key to custom host ${baseUrl}. Set POSTERLY_ALLOW_CUSTOM_BASE_URL=true only for a trusted
|
|
2158
|
+
`Refusing to send an API key to custom host ${baseUrl}. Set POSTERLY_ALLOW_CUSTOM_BASE_URL=true only for a trusted posterly deployment.`
|
|
2159
2159
|
);
|
|
2160
2160
|
}
|
|
2161
2161
|
}
|
package/src/lib/format.ts
CHANGED
|
@@ -103,7 +103,7 @@ export function mdSuccess(title: string, rows: Array<[string, CellValue]>, nextS
|
|
|
103
103
|
|
|
104
104
|
export function mdError(message: string): string {
|
|
105
105
|
return [
|
|
106
|
-
mdTitle('⚠️
|
|
106
|
+
mdTitle('⚠️ posterly tool error'),
|
|
107
107
|
`**Message:** ${message}`,
|
|
108
108
|
].join('\n');
|
|
109
109
|
}
|
package/src/lib/version.ts
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
// tool set (minus the intentional pre-auth signup tools that only this stdio
|
|
6
6
|
// package exposes). `npm run check:mcp-parity` enforces both the version match
|
|
7
7
|
// and the tool-list match, and runs in the pre-commit hook.
|
|
8
|
-
export const POSTERLY_MCP_VERSION = '0.43.
|
|
8
|
+
export const POSTERLY_MCP_VERSION = '0.43.6';
|
package/src/tools/ask-support.ts
CHANGED
|
@@ -20,7 +20,7 @@ function formatSupportAnswer(result: AskSupportResponse): string {
|
|
|
20
20
|
].filter(Boolean);
|
|
21
21
|
|
|
22
22
|
return [
|
|
23
|
-
mdTitle('
|
|
23
|
+
mdTitle('posterly Support'),
|
|
24
24
|
mdQuote(result.message?.content || 'No support answer returned.'),
|
|
25
25
|
sources.length ? mdSection('Sources', mdBullets(sources)) : '',
|
|
26
26
|
mdSection('Status', mdBullets(status)),
|
|
@@ -31,7 +31,7 @@ const supportInputSchema = z.object({
|
|
|
31
31
|
question: z.string().trim().min(1).max(4000),
|
|
32
32
|
workspace_id: z.string().optional().describe('Workspace to inspect. Omit to use the API-key scoped workspace or personal workspace.'),
|
|
33
33
|
conversation_id: z.string().optional().describe('Continue a previous support conversation.'),
|
|
34
|
-
page_url: z.string().max(2000).optional().describe('Optional
|
|
34
|
+
page_url: z.string().max(2000).optional().describe('Optional posterly page URL for context.'),
|
|
35
35
|
post_id: z.number().int().positive().optional().describe('Optional post ID to inspect directly.'),
|
|
36
36
|
referenced_post_ids: z.array(z.number().int().positive()).max(5).optional().describe('Optional post IDs to include in read-only diagnostics.'),
|
|
37
37
|
request_human: z.boolean().default(false).optional().describe('Ask for human review. Does not create a ticket unless confirm_escalation is also true.'),
|
|
@@ -49,7 +49,7 @@ async function executeSupport(client: PosterlyClient, input: AskSupportPayload)
|
|
|
49
49
|
export const askSupportTool = {
|
|
50
50
|
name: 'ask_support',
|
|
51
51
|
description:
|
|
52
|
-
'Ask
|
|
52
|
+
'Ask posterly Support AI an authenticated question using posterly docs plus read-only account/post diagnostics for the caller workspace. Requires POSTERLY_API_KEY with accounts:read and posts:read scopes. Human ticket creation requires request_human=true and confirm_escalation=true after explicit user confirmation.',
|
|
53
53
|
inputSchema: supportInputSchema,
|
|
54
54
|
execute: executeSupport,
|
|
55
55
|
};
|
|
@@ -28,11 +28,11 @@ function formatCanceled(result: CancelSubscriptionResponse): string {
|
|
|
28
28
|
export const cancelSubscriptionTool = {
|
|
29
29
|
name: 'cancel_subscription',
|
|
30
30
|
description:
|
|
31
|
-
"Cancel the authenticated user's posterly subscription. DESTRUCTIVE billing action; requires the billing:write scope. ALWAYS ask the user why they are cancelling FIRST and pass their answer as `reason` (one of the allowed values). By default
|
|
31
|
+
"Cancel the authenticated user's posterly subscription. DESTRUCTIVE billing action; requires the billing:write scope. ALWAYS ask the user why they are cancelling FIRST and pass their answer as `reason` (one of the allowed values). By default an active or trialing plan is set to cancel at the end of the current period. A past_due or unpaid plan always ends now, even when immediate is false: the unpaid renewal is dropped and payment retries stop. Pass immediate=true only when the user explicitly wants an active plan cancelled right now. Only call after the user explicitly confirms.",
|
|
32
32
|
inputSchema: z.object({
|
|
33
33
|
reason: z.enum(CANCELLATION_REASONS).describe('Why the user is cancelling. Ask the user before calling; do not guess.'),
|
|
34
34
|
feedback: z.string().max(2000).optional().describe('Optional free-text detail the user gave about why they are cancelling.'),
|
|
35
|
-
immediate: z.boolean().optional().describe('Cancel immediately instead of at period end. Defaults to false
|
|
35
|
+
immediate: z.boolean().optional().describe('Cancel immediately instead of at period end. Defaults to false. Ignored for past_due and unpaid plans, which always end now.'),
|
|
36
36
|
confirm: z.literal(true).describe('Must be true after the user explicitly confirms the cancellation.'),
|
|
37
37
|
}),
|
|
38
38
|
|
|
@@ -25,7 +25,7 @@ function formatCreatedApiKey(result: CreateApiKeyResponse): string {
|
|
|
25
25
|
export const createApiKeyTool = {
|
|
26
26
|
name: 'create_api_key',
|
|
27
27
|
description:
|
|
28
|
-
'Create a new
|
|
28
|
+
'Create a new posterly API key for the authenticated user. SECRET-CREATING WRITE: only use after explicit user confirmation. The new key can only request scopes already present on the calling dashboard-created API key; OAuth and managed assistant tokens cannot mint keys.',
|
|
29
29
|
inputSchema: z.object({
|
|
30
30
|
name: z.string().trim().min(1).max(120).optional().describe('Human-readable key name.'),
|
|
31
31
|
scopes: z.array(scopeSchema).min(1).max(8).optional().describe('Scopes for the new key. Omit to copy the calling key scopes. Cannot exceed the calling key scopes. billing:read and billing:write allow managing the posterly subscription (cancel/pause/resume/downgrade).'),
|
|
@@ -6,7 +6,7 @@ import { CONNECT_INPUTS } from '../generated/platform-manifest.js';
|
|
|
6
6
|
export const createConnectSessionTool = {
|
|
7
7
|
name: 'create_connect_session',
|
|
8
8
|
description:
|
|
9
|
-
'Create a short-lived
|
|
9
|
+
'Create a short-lived posterly dashboard handoff session for connecting a social account. Send the secure connection URL to the user, then poll get_connect_session to narrate progress. Do not ask for social media passwords or OAuth codes; posterly handles those browser steps.',
|
|
10
10
|
inputSchema: z.object({
|
|
11
11
|
platform: z
|
|
12
12
|
.enum(CONNECT_INPUTS)
|
|
@@ -38,7 +38,7 @@ export const createConnectSessionTool = {
|
|
|
38
38
|
function formatConnectSession(session: ConnectSession, includeRaw: boolean): string {
|
|
39
39
|
const connected = session.connected_count ?? session.connected_accounts?.length ?? 0;
|
|
40
40
|
return [
|
|
41
|
-
`
|
|
41
|
+
`posterly connect session created: ${session.id}`,
|
|
42
42
|
`Platform: ${session.platform}`,
|
|
43
43
|
`Status: ${session.status}`,
|
|
44
44
|
`Message: ${session.status_message}`,
|
|
@@ -49,7 +49,7 @@ function formatConnectSession(session: ConnectSession, includeRaw: boolean): str
|
|
|
49
49
|
`Expires: ${formatLocalDateTime(session.expires_at)}`,
|
|
50
50
|
`Dashboard connect page: ${DASHBOARD_CONNECT_URL}`,
|
|
51
51
|
'',
|
|
52
|
-
'Next step for the AI agent: send the secure connection URL to the user, explain that
|
|
52
|
+
'Next step for the AI agent: send the secure connection URL to the user, explain that posterly will handle the browser OAuth step, then poll get_connect_session until the account is connected or the session ends.',
|
|
53
53
|
includeRaw ? `\nRaw connect session:\n${JSON.stringify(session, null, 2)}` : '',
|
|
54
54
|
].filter(Boolean).join('\n');
|
|
55
55
|
}
|
package/src/tools/create-post.ts
CHANGED
|
@@ -141,11 +141,11 @@ export const createPostPayloadInputSchema = z.object({
|
|
|
141
141
|
.string()
|
|
142
142
|
.optional()
|
|
143
143
|
.describe('ISO 8601 datetime for scheduling (e.g. 2026-03-05T09:00:00Z). Omit for immediate publish.'),
|
|
144
|
-
media_url: z.string().optional().describe('Media URL to attach. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into
|
|
144
|
+
media_url: z.string().optional().describe('Media URL to attach. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into posterly storage before the post is saved. Short-lived signed URLs must still be live when this tool runs. For threads, attaches to the lead post only.'),
|
|
145
145
|
media_urls: z
|
|
146
146
|
.array(z.string())
|
|
147
147
|
.optional()
|
|
148
|
-
.describe('Multiple media URLs for carousel or multi-image posts. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into
|
|
148
|
+
.describe('Multiple media URLs for carousel or multi-image posts. Posterly storage URLs are used as-is; third-party HTTP(S) URLs are copied into posterly storage before the post is saved. For TikTok, 2 or more images auto-create a photo slideshow (up to 35 images) and every image is posted.'),
|
|
149
149
|
post_type: z
|
|
150
150
|
.string()
|
|
151
151
|
.optional()
|
|
@@ -235,9 +235,9 @@ export const createPostTool = {
|
|
|
235
235
|
'2. Show the user a preview containing ALL of: account(s) and platform(s), final caption text, scheduled time (in the user\'s timezone), media attached (if any), and workspace name.\n' +
|
|
236
236
|
'3. Get explicit confirmation from the user (e.g. "post it", "yes schedule that", "looks good") BEFORE calling this tool. Do NOT infer consent from earlier instructions like "post about X every Monday" - confirm each individual post or the entire batch.\n' +
|
|
237
237
|
'4. If scheduling multiple posts in one turn, list every post first and confirm the batch as a whole, then prefer `create_posts_batch` so they are created in one API request.\n\n' +
|
|
238
|
-
'AFTER CALLING: Tell the user the post was created, include the
|
|
238
|
+
'AFTER CALLING: Tell the user the post was created, include the posterly dashboard link returned by the tool, and offer the next natural action. Do not narrate raw HTTP, curl, or API plumbing.\n\n' +
|
|
239
239
|
'Provide either account_id OR username+platform to identify the account. If scheduled_at is omitted, the post publishes immediately. If workspace_id is omitted, the server resolves one from the social account, falling back to the caller\'s default (personal) workspace - pass workspace_id explicitly if the user has more than one workspace.\n\n' +
|
|
240
|
-
'MEDIA URLS: Posterly storage URLs are used as-is. Third-party HTTP(S) media URLs are copied into
|
|
240
|
+
'MEDIA URLS: Posterly storage URLs are used as-is. Third-party HTTP(S) media URLs are copied into posterly storage before the post is saved, so API-created posts do not later fail on expired signed URLs. Short-lived signed URLs must still be live when this tool runs. You can also call `upload_media_from_url` first if you want to upload once and reuse the returned posterly URL across posts.\n\n' +
|
|
241
241
|
'THREADS: Pass `thread_posts` (an array of 2+ strings) to schedule a multi-post thread on X (Twitter) or Threads (Meta). The first entry is the lead post; the rest are published as replies in the same chain. X entries are capped at 280 characters each (4000 for verified, 25000 for organization accounts); Threads entries are capped at 500 characters each. When `thread_posts` is set, `caption` is ignored.\n\n' +
|
|
242
242
|
'PLATFORM SETTINGS: Pass `platform_settings` for composer-equivalent controls: Facebook story/reel/backgrounds, YouTube title/privacy/thumbnail/brandPartner, LinkedIn document titles/mentions/polls/content_call_to_action_label (including BUY_NOW and SHOP_NOW), TikTok direct-post privacy/toggles/commercial disclosure, Pinterest board/title/link/product_tags, GBP event/offer/CTA/recurrence, X reply settings/polls/paid_partnership, Threads reply controls/text attachments/ghost posts/spoilers/reply approvals/GIPHY, Telegram polls/buttons/video cover/live photo, Slack markdown/blocks, Mastodon visibility/quote/poll (media+poll allowed), and Instagram feed/story/reel/carousel/native media tags/collaborators/first comments/trial Reels/is_ai_generated/audio_id. For Instagram, @username in caption is only a caption mention; `user_tags` creates native media tags and `collaborators` sends co-author invitations only when the selected Meta-linked account reports those capabilities. Call `get_platform_schema` with the account ID first. `instagram_settings` remains as a backwards-compatible alias.\n\n' +
|
|
243
243
|
'TIKTOK MEDIA: TikTok supports a single video or a photo slideshow of 1 to 35 images, never multiple videos. Image media auto-detects as a slideshow, so you usually do not set post_type or media_type for photos and every image is posted. Pass `platform_settings.media_type: "PHOTO"` to force a slideshow explicitly.',
|
|
@@ -268,7 +268,7 @@ export const createPostTool = {
|
|
|
268
268
|
`• Type: ${p.post_type}`,
|
|
269
269
|
`• Status: ${p.status}`,
|
|
270
270
|
`• Scheduled: ${when}`,
|
|
271
|
-
`• View in
|
|
271
|
+
`• View in posterly: ${dashboardUrl}`,
|
|
272
272
|
];
|
|
273
273
|
if (thread_posts) {
|
|
274
274
|
lines.push(`• Thread: ${thread_posts.length} posts`);
|
|
@@ -287,7 +287,7 @@ export const createPostTool = {
|
|
|
287
287
|
}
|
|
288
288
|
lines.push(
|
|
289
289
|
'',
|
|
290
|
-
'Next step for the AI agent: tell the user the post is in
|
|
290
|
+
'Next step for the AI agent: tell the user the post is in posterly, share the dashboard link above, then ask whether they want to create another post, adjust this one, or connect another account.',
|
|
291
291
|
);
|
|
292
292
|
return lines.join('\n');
|
|
293
293
|
},
|
|
@@ -11,7 +11,7 @@ export const createPostsBatchTool = {
|
|
|
11
11
|
'1. Call `whoami` at the start of any new session to confirm which workspace and user you are acting for.\n' +
|
|
12
12
|
'2. Show the user a preview of EVERY post: account/platform, final caption or thread text, scheduled time in their timezone, media, platform settings, and workspace.\n' +
|
|
13
13
|
'3. Get explicit confirmation for the whole batch before calling. Do not infer consent from an earlier content plan.\n\n' +
|
|
14
|
-
'AFTER CALLING: Summarize the batch result in natural language, include the
|
|
14
|
+
'AFTER CALLING: Summarize the batch result in natural language, include the posterly dashboard link returned by the tool, and avoid narrating raw HTTP, curl, or API plumbing.\n\n' +
|
|
15
15
|
'Each item accepts the same fields as `create_post`, including `thread_posts`, `platform_settings`, `instagram_settings`, media URLs, and workspace_id. The endpoint may partially succeed; failed items are returned with their index.',
|
|
16
16
|
inputSchema: z.object({
|
|
17
17
|
posts: z
|
|
@@ -37,7 +37,7 @@ export const createPostsBatchTool = {
|
|
|
37
37
|
`• Created: ${result.created}`,
|
|
38
38
|
`• Replayed: ${result.replayed}`,
|
|
39
39
|
`• Failed: ${result.failed}`,
|
|
40
|
-
`• View in
|
|
40
|
+
`• View in posterly: ${dashboardUrl}`,
|
|
41
41
|
];
|
|
42
42
|
|
|
43
43
|
for (const item of result.posts.slice(0, 25)) {
|
|
@@ -18,7 +18,7 @@ function formatDeletedApiKey(result: DeleteApiKeyResponse): string {
|
|
|
18
18
|
export const deleteApiKeyTool = {
|
|
19
19
|
name: 'delete_api_key',
|
|
20
20
|
description:
|
|
21
|
-
'Revoke a
|
|
21
|
+
'Revoke a posterly API key owned by the authenticated user. DESTRUCTIVE: call whoami or use a known key ID, show the user the exact key ID/prefix/name if available, and get explicit confirmation before calling. Cannot revoke the key currently authenticating this request, OAuth-issued keys, or managed assistant keys.',
|
|
22
22
|
inputSchema: z.object({
|
|
23
23
|
key_id: z.string().uuid().describe('API key ID to revoke. This is the API key resource ID, not the secret pst_live_ value.'),
|
|
24
24
|
confirm: z.literal(true).describe('Must be true after the user explicitly confirms API key revocation.'),
|
package/src/tools/delete-post.ts
CHANGED
|
@@ -22,8 +22,8 @@ export const deletePostTool = {
|
|
|
22
22
|
const result = await client.deletePost(input.post_id);
|
|
23
23
|
return [
|
|
24
24
|
`Post #${result.id} deleted successfully.`,
|
|
25
|
-
'It has been removed from the
|
|
26
|
-
`View queue in
|
|
25
|
+
'It has been removed from the posterly queue.',
|
|
26
|
+
`View queue in posterly: ${dashboardUrlForPosts()}`,
|
|
27
27
|
'',
|
|
28
28
|
'Next step for the AI agent: tell the user the post is gone and offer to create, reschedule, or review the next post.',
|
|
29
29
|
].join('\n');
|
|
@@ -43,7 +43,7 @@ export const generateCaptionsTool = {
|
|
|
43
43
|
preserve_call_to_action: z.boolean().default(true).optional(),
|
|
44
44
|
social_account_id: z.string().optional().describe('Optional connected account ID for brand voice and workspace billing context.'),
|
|
45
45
|
workspace_id: z.string().optional(),
|
|
46
|
-
manual_brand_voice: manualBrandVoiceSchema.optional().describe('Use when
|
|
46
|
+
manual_brand_voice: manualBrandVoiceSchema.optional().describe('Use when posterly asks for brand voice input.'),
|
|
47
47
|
}),
|
|
48
48
|
|
|
49
49
|
async execute(client: PosterlyClient, input: GenerateCaptionsPayload) {
|
|
@@ -5,7 +5,7 @@ import { mdKeyValue, mdTitle } from '../lib/format.js';
|
|
|
5
5
|
export const generateImageTool = {
|
|
6
6
|
name: 'generate_image',
|
|
7
7
|
description:
|
|
8
|
-
'Queue an AI image job via
|
|
8
|
+
'Queue an AI image job via posterly using Nano Banana (Gemini) or Grok Imagine Image 2.0 (xAI). Returns job_id. Poll get_image_job until status is completed, then pass urls to create_post as media_url / media_urls. Gemini thinking high does not change the credit price.\n\n' +
|
|
9
9
|
'COSTS CREDITS. Every call consumes part of the user\'s monthly AI image quota (or purchased credits once the quota is exhausted). Do NOT call speculatively - always describe the image you\'re about to generate (subject, style, aspect ratio, quality/thinking, resolution) to the user and get confirmation before calling.\n\n' +
|
|
10
10
|
'If the user is over their plan limit and has no credits, this tool returns a 402 with upgrade info. Surface that message verbatim - do not retry.\n\n' +
|
|
11
11
|
'Common aspect ratios by platform:\n' +
|
|
@@ -4,16 +4,16 @@ import type { PosterlyClient } from '../lib/api-client.js';
|
|
|
4
4
|
export const getAgentSignupInfoTool = {
|
|
5
5
|
name: 'get_agent_signup_info',
|
|
6
6
|
description:
|
|
7
|
-
'Explain how to use
|
|
7
|
+
'Explain how to use posterly MCP for agent-led signup before an API key exists, including the safe human-in-the-browser boundaries.',
|
|
8
8
|
inputSchema: z.object({}),
|
|
9
9
|
|
|
10
10
|
async execute(client: PosterlyClient) {
|
|
11
11
|
const authState = client.hasApiKey()
|
|
12
|
-
? '
|
|
13
|
-
: 'No
|
|
12
|
+
? 'posterly API key is installed. Authenticated scheduling and connect tools are available.'
|
|
13
|
+
: 'No posterly API key is installed. Only public setup tools are available until the user completes paid setup and gives this AI posterly access.';
|
|
14
14
|
|
|
15
15
|
return [
|
|
16
|
-
'
|
|
16
|
+
'posterly agent signup info',
|
|
17
17
|
'',
|
|
18
18
|
authState,
|
|
19
19
|
'',
|
|
@@ -22,7 +22,7 @@ export const getAgentSignupInfoTool = {
|
|
|
22
22
|
'- start_signup: starts paid signup and returns a signup poll URL, a browser Checkout fallback, and, when enabled, a prepaid PaymentIntent for a Link virtual card (credential_type: card).',
|
|
23
23
|
'- get_signup_session: polls payment, password, and agent-access status.',
|
|
24
24
|
'',
|
|
25
|
-
'After
|
|
25
|
+
'After posterly access is installed, onboard the user IN THIS chat (do not send them to /onboarding-v2):',
|
|
26
26
|
'- whoami: confirm the paid account and read onboarding.next_step.',
|
|
27
27
|
'- About you: confirm name and IANA timezone.',
|
|
28
28
|
'- create_connect_session / get_connect_session: first social account in the browser.',
|
|
@@ -31,17 +31,17 @@ export const getAgentSignupInfoTool = {
|
|
|
31
31
|
'',
|
|
32
32
|
'Conversation style:',
|
|
33
33
|
'- Keep the user updated in plain language: checkout pending, payment confirmed, password setup needed, account connected, post scheduled.',
|
|
34
|
-
'- Prefer the
|
|
34
|
+
'- Prefer the posterly dashboard links returned by tools when the user wants to inspect posts.',
|
|
35
35
|
'- Do not narrate raw curl, HTTP, JSON, API keys, or implementation details unless the user explicitly asks for debugging.',
|
|
36
36
|
'',
|
|
37
37
|
'Boundaries:',
|
|
38
38
|
'- Payment happens on Stripe Checkout, either by the user in their browser or by the agent with its own approved payment credential (for example a Link agent wallet); never card details in chat.',
|
|
39
39
|
'- Where enabled, payment can instead be a one-time Link Agent Wallet virtual card (credential_type: card) on a prepaid PaymentIntent.',
|
|
40
40
|
'- Never send card numbers to posterly. Confirm the PaymentIntent with Stripe, or send checkout_redirect_url.',
|
|
41
|
-
'- The user sets their
|
|
41
|
+
'- The user sets their posterly password in their browser.',
|
|
42
42
|
'- The user approves social OAuth in their browser.',
|
|
43
43
|
'- Publish approval stays with the user.',
|
|
44
|
-
'- The AI should never ask for card details,
|
|
44
|
+
'- The AI should never ask for card details, posterly passwords, social passwords, or OAuth codes.',
|
|
45
45
|
].join('\n');
|
|
46
46
|
},
|
|
47
47
|
};
|
package/src/tools/get-comment.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { formatLocalDateTime } from '../lib/format.js';
|
|
|
5
5
|
export const getCommentTool = {
|
|
6
6
|
name: 'get_comment',
|
|
7
7
|
description:
|
|
8
|
-
'Get one social inbox comment and its replies. Instagram, Facebook Page, and
|
|
8
|
+
'Get one social inbox comment and its replies. Instagram, Facebook Page, Threads, and LinkedIn Page comments. Requires a Pro plan or higher plus posts:read.',
|
|
9
9
|
inputSchema: z.object({
|
|
10
10
|
comment_id: z.string().min(1).describe('Comment ID from list_comments.'),
|
|
11
11
|
workspace_id: z.string().optional().describe('Filter to a workspace ID from whoami.'),
|
|
@@ -37,7 +37,7 @@ export const getConnectLinkTool = {
|
|
|
37
37
|
|
|
38
38
|
const options = result.connect_options || [];
|
|
39
39
|
const lines = options.map((option) => formatConnectOption(option, false));
|
|
40
|
-
return `
|
|
40
|
+
return `posterly connection options (${options.length}):\n${lines.join('\n\n')}`;
|
|
41
41
|
},
|
|
42
42
|
};
|
|
43
43
|
|
|
@@ -5,7 +5,7 @@ import { DASHBOARD_CONNECT_URL, formatConnectedAccounts, formatLocalDateTime } f
|
|
|
5
5
|
export const getConnectSessionTool = {
|
|
6
6
|
name: 'get_connect_session',
|
|
7
7
|
description:
|
|
8
|
-
'Poll a
|
|
8
|
+
'Poll a posterly connect session. Use the returned status and next-step guidance to keep the user updated in plain language. Stop when status is connected, failed, cancelled, or expired.',
|
|
9
9
|
inputSchema: z.object({
|
|
10
10
|
session_id: z.string().describe('Connect session ID returned by create_connect_session.'),
|
|
11
11
|
debug: z
|
|
@@ -26,7 +26,7 @@ export const getConnectSessionTool = {
|
|
|
26
26
|
function formatConnectSession(session: ConnectSession, includeRaw: boolean): string {
|
|
27
27
|
const connected = session.connected_count ?? session.connected_accounts?.length ?? 0;
|
|
28
28
|
return [
|
|
29
|
-
`
|
|
29
|
+
`posterly connect session: ${session.id}`,
|
|
30
30
|
`Platform: ${session.platform}`,
|
|
31
31
|
`Status: ${session.status}`,
|
|
32
32
|
`Message: ${session.status_message}`,
|
|
@@ -46,9 +46,9 @@ function guidanceForStatus(session: ConnectSession): string {
|
|
|
46
46
|
case 'created':
|
|
47
47
|
case 'opened':
|
|
48
48
|
case 'awaiting_provider':
|
|
49
|
-
return 'Next step for the AI agent: tell the user
|
|
49
|
+
return 'Next step for the AI agent: tell the user posterly is waiting for browser approval, then keep polling this session. Do not ask for social passwords or OAuth codes.';
|
|
50
50
|
case 'awaiting_credentials':
|
|
51
|
-
return 'Next step for the AI agent: tell the user
|
|
51
|
+
return 'Next step for the AI agent: tell the user posterly needs them to finish the browser credential step, then keep polling. Do not ask the user to paste credentials into chat.';
|
|
52
52
|
case 'connected':
|
|
53
53
|
return `Next step for the AI agent: tell the user ${formatConnectedAccounts(session.connected_accounts)} is connected, then ask what they want to schedule first or offer to create a test post.`;
|
|
54
54
|
case 'failed':
|