Skip to content

fix(custom-tools): skip title conflicts when persisting inline tools from a workflow save - #9198

Merged
waleedlatif1 merged 2 commits into
stagingfrom
fix/custom-tools-persist-title-conflict
Oct 18, 2026
Merged

waleedlatif1 merged 2 commits into
stagingfrom
fix/custom-tools-persist-title-conflict

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Inline custom tools on an agent block (imported graphs, legacy format) carry no toolId. The first save inserts a workspace row under a generated id that is never written back to the block, so every later save of the same workflow re-offers the tool with no id, hits the workspace title-uniqueness guard on the row that same flow created, and throws. upsertCustomTools runs the batch in one transaction, so every other tool in that save is rolled back too, and the save logs "Some custom tools failed to persist".
  • Split the batch write in operations.ts into a shared loop with a title-conflict policy. upsertCustomTools keeps its signature and runs it with 'error'. The new upsertCustomToolsSkippingTakenTitles runs it with 'skip': the insert uses ON CONFLICT (workspace_id, title) DO NOTHING, so a title that already exists (including one a concurrent save just committed) is left untouched and the rest of the batch persists. It returns the skipped titles.
  • persistCustomToolsToDatabase (the post-commit step of the shared workflow state replace and of workflow import) now calls the skipping variant, and saved counts only the tools actually written.
  • Why skip instead of adopting a same-titled row: adopting is only safe when the row is provably the same tool, and then writing it again changes nothing but updatedAt. When it is not the same tool, it is an unrelated library tool that must not be overwritten. Both cases come down to leaving the row alone, so skip is the smaller change. The block still runs from its inline definition either way.
  • Behaviour that stays the same: the explicit create/update paths (POST /api/tools/custom, the v2 create use case) still call upsertCustomTools, so a duplicate title still throws and the whole batch rolls back (500 on the internal route, 409 on v2, as before). Id-resolved updates and legacy-tool updates are untouched. The only persistence change is that a conflicting title no longer fails the batch.

Type of Change

  • Bug fix

Testing

  • New custom-tools-persistence.integration.ts against real Postgres: saving the same graph twice (inline tool without toolId) returns no errors on the second save, persists the new tool next to it, and reports only that tool as saved; two concurrent saves of the same new tool both succeed and leave one row; an existing workspace tool with the same title keeps its code; upsertCustomTools without the option still rejects a duplicate title and rolls back the rest of its batch.
  • The first two cases fail on the pre-fix code (the second save returns the title error and the new tool is never written).
  • Existing unit suites for persistence, operations, and the custom-tool use cases pass.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Oct 18, 2026 9:14pm UTC

Request Review

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files

Reply with feedback, questions, or to request a fix.

Turn on auto-fix | Re-trigger cubic

Comment thread apps/sim/lib/workflows/custom-tools/operations.ts Outdated
Comment thread apps/sim/lib/workflows/persistence/custom-tools-persistence.ts Outdated
@greptile-apps

greptile-apps Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no blocking issues were found.

Summary

Workflow saves and imports now skip inserts whose titles already exist, without overwriting those tools or rolling back other inserts.

  • Workflow saves skip inline tools whose titles are already in use.

Reviews (2) · Last reviewed commit: "fix(custom-tools): count skipped titles ..." · Reviewed by Greptile

Comment thread apps/sim/lib/workflows/persistence/custom-tools-persistence.ts Outdated
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

@waleedlatif1
waleedlatif1 merged commit 4c02fa1 into staging Oct 18, 2026
54 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/custom-tools-persist-title-conflict branch October 18, 2026 22:12

This branch was previously deployed

1 inactive deployment
Preview — 727af416 Deployed Oct 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant