Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion apps/frontend/src/components/launches/calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,21 @@ const usePostActions = (onMutate?: () => void) => {
};

const data = await (await fetch(`/posts/group/${post.group}`)).json();

// The group rotates on every edit - if the post was edited elsewhere
// (another tab, the agent) this calendar entry is stale.
if (!data?.posts?.length) {
toaster.show(
t(
'post_changed_elsewhere',
'This post was changed or deleted, refreshing the calendar'
),
'warning'
);
mutate();
return;
}

const date = !isDuplicate
? null
: (await (await fetch('/posts/find-slot')).json()).date;
Expand Down Expand Up @@ -170,7 +185,7 @@ const usePostActions = (onMutate?: () => void) => {
title: ``,
});
},
[integrations, fetch, modal, mutate]
[integrations, fetch, modal, mutate, toaster, t]
);

const copyDebugJson = useCallback(
Expand Down
7 changes: 6 additions & 1 deletion libraries/nestjs-libraries/src/chat/load.tools.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export class LoadToolsService {

You are an agent that helps manage and schedule social media posts for users, you can:
- Schedule posts into the future, or now, adding texts, images and videos
- List upcoming scheduled posts and drafts (postsListTool)
- Update scheduled posts that were not published yet: settings, date and content (updatePostTool)
- Generate pictures for posts
- Generate videos for posts
- Generate text for posts
Expand All @@ -76,12 +78,15 @@ export class LoadToolsService {
- In every message I will send you the list of needed social medias (id and platform), if you already have the information use it, if not, use the integrationSchema tool to get it.
- Make sure you always take the last information I give you about the socials, it might have changed.
- Before scheduling a post, always make sure you ask the user confirmation by providing all the details of the post (text, images, videos, date, time, social media platform, account).
- When the user asks to change existing posts (for example "update all my future tiktok posts"), use postsListTool to find the matching upcoming posts (it is paginated - keep fetching while hasMore is true), show the user which posts you are about to change and what will change, and after they confirm run updatePostTool once per post.
- Changes to an EXISTING post (reschedule, edit text, change settings) must always be applied directly with updatePostTool - never open the "modal with populated content" for an existing post. That modal only creates a NEW post, so using it to edit would duplicate the post instead of changing it. If the user explicitly wants to edit a post in a visual modal, tell them to open that post in the Postiz calendar, because you can only open the modal for brand new posts.
- You can create, list and update posts, but you CANNOT delete posts - there is no delete capability. Never offer to delete a post. If the user asks you to delete a post, tell them you are not able to delete posts because deletion is a destructive action, and they should delete it themselves in the Postiz app (the calendar). You can still offer to update the post instead.
- Between tools, we will reference things like: [output:name] and [input:name] to set the information right.
- When outputting a date for the user, make sure it's human readable with time
- The content of the post, HTML, Each line must be wrapped in <p> here is the possible tags: h1, h2, h3, u, strong, li, ul, p (you can\'t have u and strong together), don't use a "code" box
${renderArray(
[
'If the user confirm, ask if they would like to get a modal with populated content without scheduling the post yet or if they want to schedule it right away.',
'When scheduling a NEW post, if the user confirms, ask whether they would like a modal with the populated content (without scheduling yet) or to schedule it right away. This modal is ONLY for brand new posts - never offer it for changes to an existing post; apply those directly with updatePostTool.',
],
!!ui
)}
Expand Down
123 changes: 123 additions & 0 deletions libraries/nestjs-libraries/src/chat/tools/posts.list.tool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { AgentToolInterface } from '@gitroom/nestjs-libraries/chat/agent.tool.interface';
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
import { Injectable } from '@nestjs/common';
import { PostsService } from '@gitroom/nestjs-libraries/database/prisma/posts/posts.service';
import { checkAuth } from '@gitroom/nestjs-libraries/chat/auth.context';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';

dayjs.extend(utc);

const parseSettings = (settings: string | null) => {
try {
return JSON.parse(settings || '{}');
} catch (err) {
return {};
}
};

@Injectable()
export class PostsListTool implements AgentToolInterface {
constructor(private _postsService: PostsService) {}
name = 'postsListTool';

run() {
return createTool({
id: 'postsListTool',
mcp: {
annotations: {
title: 'List Upcoming Posts',
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false,
},
},
description: `
List the organization's upcoming (not-yet-published) posts - both drafts and scheduled posts whose publish time is still in the future. By default returns all of them, so "list all my unpublished posts" is a single call with no arguments.
Only future posts are returned; past posts (including old forgotten drafts) are never listed.
Optionally narrow with "state" to only drafts or only scheduled posts.
Each item has a "state" (draft or scheduled) and its current provider settings, so you can tell which posts need a change.
Use this to find the posts the user wants to inspect or update - pass the returned "id" to updatePostTool.
Results are paginated (20 per page), use "page" and "hasMore" to fetch all of them.
`,
inputSchema: z.object({
platform: z
.string()
.optional()
.describe(
'Filter by platform identifier, for example: tiktok, linkedin, x'
),
integrationId: z
.string()
.optional()
.describe('Filter by a specific integration (channel) id'),
state: z
.enum(['scheduled', 'draft'])
.optional()
.describe(
'Omit to get all upcoming posts (future drafts + future scheduled). "scheduled" = only future scheduled posts. "draft" = only future drafts. Past posts are never returned.'
),
page: z.number().optional().describe('Page number, starting at 0'),
}),
outputSchema: z.object({
output: z.object({
posts: z.array(
z.object({
id: z
.string()
.describe('Pass this to updatePostTool to update the post'),
publishDate: z.string().describe('UTC time'),
state: z.enum(['draft', 'scheduled']),
platform: z.string(),
integrationId: z.string(),
integrationName: z.string(),
content: z.string(),
settings: z.any(),
})
),
total: z.number(),
page: z.number(),
hasMore: z.boolean(),
}),
}),
execute: async (inputData, context) => {
checkAuth(inputData, context);
const organizationId = JSON.parse(
(context?.requestContext as any)?.get('organization') as string
).id;

const list = await this._postsService.getAgentPostsList(
organizationId,
{
integrationId: inputData.integrationId,
platform: inputData.platform,
state: inputData.state,
page: inputData.page,
}
);

return {
output: {
posts: list.posts.map((p) => ({
id: p.id,
publishDate: dayjs(p.publishDate)
.utc()
.format('YYYY-MM-DDTHH:mm:ss'),
state: p.state === 'DRAFT' ? 'draft' : 'scheduled',
platform: p.integration.providerIdentifier,
integrationId: p.integration.id,
integrationName: p.integration.name,
content: p.content || '',
settings: parseSettings(p.settings),
})),
total: list.total,
page: list.page,
hasMore: list.hasMore,
},
};
},
});
}
}
4 changes: 4 additions & 0 deletions libraries/nestjs-libraries/src/chat/tools/tool.list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ import { GenerateImageTool } from '@gitroom/nestjs-libraries/chat/tools/generate
import { IntegrationListTool } from '@gitroom/nestjs-libraries/chat/tools/integration.list.tool';
import { GroupListTool } from '@gitroom/nestjs-libraries/chat/tools/group.list.tool';
import { UploadFromUrlTool } from '@gitroom/nestjs-libraries/chat/tools/upload.from.url.tool';
import { PostsListTool } from '@gitroom/nestjs-libraries/chat/tools/posts.list.tool';
import { UpdatePostTool } from '@gitroom/nestjs-libraries/chat/tools/update.post.tool';

export const toolList = [
IntegrationListTool,
GroupListTool,
IntegrationValidationTool,
IntegrationTriggerTool,
IntegrationSchedulePostTool,
PostsListTool,
UpdatePostTool,
GenerateVideoOptionsTool,
VideoFunctionTool,
GenerateVideoTool,
Expand Down
Loading
Loading