feat(agent): add postSettingsTool to update a post's settings via the agent - #1877
Merged
Conversation
Adds postsListTool (agent / MCP) so an agent can find the org's posts. It calls the same PostsService.getPosts as the public "List Posts" endpoint (GET /public/v1/posts), with the same inputs (startDate, endDate, optional customer) and the same source data, so the tool and the API stay aligned instead of drifting into a separate query. Each item carries the post id (to pass to updatePostSettingsTool), publish date, state, content, channel and current provider settings. Also selects `settings` in getPosts, so both the tool and the public List Posts endpoint now return each post's provider settings (needed to know which posts require a settings change). This adds a `settings` field to the GET /public/v1/posts response. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tomer
getPosts declared the integration relation filter twice in the same where
object: once with { deletedAt: null, organizationId } and again, only when
a customer is passed, with { customerId }. The second key overwrote the
first, so filtering by customer dropped the soft-delete and org checks and
surfaced posts on soft-deleted integrations. Merge customerId into the
single integration filter instead (as getPostsList already does).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
An external MCP agent (Claude Code), right after listing posts, offered the user to delete one - there is no delete tool, so the offer was a hallucination. External clients never see the internal agent prompt; the only text they read is the tool descriptions and the agent/ask_postiz description, so the guard has to live there: - postsListTool description: posts cannot be deleted through these tools; never offer deletion, point the user to the Postiz app. - Agent description: "manage and schedule" -> "schedule and list", so external clients don't infer edit/delete capabilities from "manage". Validated: re-ran the same flow in Claude Code, claude.ai and ChatGPT over MCP - no delete offers.
… agent
Thin agent/MCP wrapper over PostsService.updatePostSettings (shipped in
the public-API PR): converts the agent's [{key,value}] settings into an
object and calls the shared service method, so the tool and the
PUT /public/v1/posts/:id/settings endpoint share one path and cannot
drift. Errors are returned as {errors} so the agent can read and retry.
Registered in the tool list; the agent prompt tells it to find posts
with postsListTool, apply settings changes directly with
postSettingsTool (never the populated modal, which would duplicate the
post), and that there is no delete capability.
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
Comment on lines
+769
to
+772
| const coverPath = isArticle | ||
| ? firstPost?.settings?.article_cover?.path | ||
| : undefined; | ||
| const coverMediaId = coverPath |
There was a problem hiding this comment.
Bug: The article_cover image path is not resolved to an absolute path before being passed to readOrFetch, causing file-not-found errors for images stored with relative paths.
Severity: HIGH
Suggested Fix
The article_cover.path should be resolved to an absolute path before being passed to readOrFetch. This can be done by applying the same logic used in updateMedia, which prepends process.env.UPLOAD_DIRECTORY to relative paths. Ensure the path is resolved before it is used.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: libraries/nestjs-libraries/src/integrations/social/x.provider.ts#L769-L772
Potential issue: The `article_cover` path for X articles is retrieved from post
`settings` and used directly in `readOrFetch`. Unlike regular media paths processed via
`updateMedia`, this path is not resolved to an absolute filesystem path. If the
`article_cover.path` is stored as a relative path (e.g., `uploads/image.jpg`),
`readOrFetch` will fail when calling `readFileSync` because it requires an absolute path
or a full HTTP URL. This will cause the finalization of any X article post with a
locally-hosted cover image to fail.
Did we get this right? 👍 / 👎 to inform future reviews.
# Conflicts: # libraries/nestjs-libraries/src/chat/load.tools.service.ts # libraries/nestjs-libraries/src/chat/tools/tool.list.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
⛔ DO NOT MERGE BEFORE #1816
This PR is stacked on #1816 (
feat/agent-list-posts) and must not be merged until #1816 is merged. The agent needspostsListTool(from #1816) to find the post ids this tool operates on, and merging a stacked PR before its base folds it into the base branch instead of main.Why
Completes the agent side of the batch-settings-update flow (a user scheduled dozens of TikTok posts with the wrong posting method and wanted an agent to fix them): #1816 lets the agent list posts, #1817 (merged) added the update capability as
PUT /public/v1/posts/:id/settings+PostsService.updatePostSettings, and this PR exposes that same service method as an agent/MCP tool. This is the settings-only rework of the closed #1689, per its review feedback.What changed
postSettingsTool(agent / MCP): thin wrapper overPostsService.updatePostSettings- converts the agent's[{key, value}]settings into an object and calls the shared method, so the tool and the public endpoint share one path (Controller -> Service -> Repository) and cannot drift. Merges only the passed keys into the existing settings; content and publish date stay untouched, so the running publish workflow is never restarted. Errors come back as{errors}so the agent can read and retry.postsListTool, apply settings changes directly withpostSettingsTool, never open the populated modal for an existing post (it only creates, so editing through it would duplicate), and there is no delete capability (never offer deletion).Testing (end to end)
Verified with three MCP clients: Claude Code (local MCP), and claude.ai + ChatGPT custom connectors over a cloudflared tunnel - in all of them the agent listed the posts, updated the draft's settings via
postSettingsTool, and relayed the guards correctly.postSettingsToolon a future TikTok draft:content_posting_methodUPLOAD -> DIRECT_POST (the exact original use case) - applied, and merge semantics verified: only the passed key changed; title, privacy, toggles, content, publish date and state untouched.Found in passing (pre-existing, all surfaces, not addressed here): the LinkedIn providers never declare their
dto, sovalidatePostsskips settings-DTO validation for LinkedIn entirely (LinkedinDtoexists but is unwired) - a wrongly-typed settings value is accepted. Follow-up candidate.Related changes in other repos
postSettingsToolin the MCP docs + the Update Post Settings endpoint page (branchfeat/update-post-settings-docs).