Skip to content

feat(knowledge): add Live sync option to KB connectors + fix embedding billing#3916

Merged
waleedlatif1 merged 12 commits intostagingfrom
feat/kb-connector-live-sync-option
Apr 3, 2026
Merged

feat(knowledge): add Live sync option to KB connectors + fix embedding billing#3916
waleedlatif1 merged 12 commits intostagingfrom
feat/kb-connector-live-sync-option

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • Adds a "Live" sync option (every 5 minutes) to KB connector modals, gated to Max and Enterprise plan users
  • Disabled with a "Max" badge for free users — same badge pattern as Sim Mailer in settings
  • Server-side 403 guard on both POST and PATCH if a sub-hourly interval is submitted without a Max plan
  • Self-hosted and dev environments bypass the gate
  • Fixes missing embedding cost billing: `generateEmbeddings` now returns `totalTokens`, `isBYOK`, and `modelName`; `processDocumentAsync` calls `recordUsage` after successful embedding insertion
  • BYOK workspaces are excluded from billing; Azure (system-level key) is billed correctly
  • Uses `calculateCost` + `getCostMultiplier` consistent with how billing works across the rest of the platform

Type of Change

  • New feature
  • Bug fix

Testing

Tested manually

Checklist

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

…nterprise users

Adds a "Live" (every 5 min) sync frequency option gated to Max and Enterprise plan users.
Includes client-side badge + disabled state, shared sync intervals constant, and server-side
plan validation on both POST and PATCH connector routes.
Adds billing tracking to the KB embedding pipeline, which was previously
generating OpenAI API calls with no cost recorded. Token counts are now
captured from the actual API response and recorded via recordUsage after
successful embedding insertion. BYOK workspaces are excluded from billing.
Applies to all execution paths: direct, BullMQ, and Trigger.dev.
…n modelName

- Use calculateCost() from @/providers/utils instead of inline formula, consistent
  with how LLM billing works throughout the platform
- Return modelName from GenerateEmbeddingsResult so billing uses the actual model
  (handles custom Azure deployments) instead of a hardcoded fallback string
- Fix docs-chunker.ts empty-path fallback to satisfy full GenerateEmbeddingsResult type
@cursor
Copy link
Copy Markdown

cursor bot commented Apr 3, 2026

PR Summary

Medium Risk
Adds subscription-gated behavior to connector creation/updates and introduces new billing writes based on embedding token usage, which can affect customer entitlements and cost accounting if incorrect.

Overview
Adds a "Live" (5-minute) sync frequency option for knowledge base connectors, shown in the add/edit connector modals and disabled for non-Max plans with a MaxBadge.

Enforces the same gate server-side by rejecting connector POST/PATCH requests that set a sub-hourly syncIntervalMinutes unless hasLiveSyncAccess allows it (self-hosted bypass).

Fixes embedding billing by extending generateEmbeddings to return { embeddings, totalTokens, isBYOK, modelName }, updating callers accordingly, and recording knowledge-base model usage after successful document embedding insertion (skipping BYOK), including a DB enum migration for the new usage-log source.

Reviewed by Cursor Bugbot for commit 80e97aa. Configure here.

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 3, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 3, 2026 9:51pm

Request Review

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 3, 2026

Greptile Summary

This PR adds a "Live" (every 5 minutes) sync option to Knowledge Base connector modals, gated behind Max/Enterprise plan access both client-side (disabled button + MaxBadge) and server-side (403 guard in POST and PATCH handlers). It also fixes a billing gap where embedding costs were never recorded: generateEmbeddings now returns totalTokens, isBYOK, and modelName, and processDocumentAsync calls recordUsage + checkAndBillOverageThreshold after a successful embedding insert.

Key changes:

  • SYNC_INTERVALS extracted to a shared consts.ts and the "Live" (5 min) entry added with requiresMax: true; MaxBadge component extracted to max-badge.tsx (resolves previous review comment)
  • hasLiveSyncAccess added to subscription.ts, mirroring hasInboxAccess logic but bypassing on !isHosted (self-hosted environments) rather than !isProd
  • generateEmbeddings return type changed from number[][] to GenerateEmbeddingsResult; all call sites updated (chunks service, docs-chunker, document service)
  • Billing in processDocumentAsync: tokens accumulated across batches, isBYOK/modelName captured once on the first batch; billing skipped for BYOK workspaces; a logger.warn is emitted when cost resolves to zero
  • DB migration 0185 adds knowledge-base to the usage_log_source Postgres enum
  • Tests updated to include usage in mock API responses via the shared mockNextFetchResponse helper

Confidence Score: 5/5

Safe to merge — no critical or blocking issues found; all three previous P1 concerns have been addressed.

All three P1 findings from the prior review round (billing metadata discarded in DocsChunker, isBYOK/modelName overwritten per batch, silent billing miss for Azure custom deployment names) have been resolved. The billing flow is well-structured, the server-side plan gate is consistent between POST and PATCH, the DB migration is correct, and tests were updated to cover the new usage field in mock responses.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/lib/knowledge/embeddings.ts Refactored generateEmbeddings to return a GenerateEmbeddingsResult struct; callEmbeddingAPI now returns { embeddings, totalTokens } from data.usage.total_tokens; all callers updated.
apps/sim/lib/knowledge/documents/service.ts Adds embedding-cost billing to processDocumentAsync: accumulates totalEmbeddingTokens across batches, calls recordUsage and checkAndBillOverageThreshold after successful processing; BYOK workspaces excluded; missing pricing entries emit a logger.warn.
apps/sim/lib/billing/core/subscription.ts Adds hasLiveSyncAccess gating sub-hourly sync to Max/Enterprise plans; also parallelises getHighestPrioritySubscription + getEffectiveBillingStatus calls inside hasInboxAccess.
apps/sim/app/api/knowledge/[id]/connectors/route.ts POST handler enforces live-sync gate: if syncIntervalMinutes is 1–59 and user lacks Max/Enterprise, returns 403.
apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/route.ts PATCH handler adds the same live-sync gate, guarded by parsed.data.syncIntervalMinutes !== undefined before the range check.
apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/consts.ts New shared SYNC_INTERVALS constant extracted from both modal files; adds Live (5 min) with requiresMax: true.
apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/max-badge.tsx New shared MaxBadge component extracted to eliminate markup duplication between add and edit connector modals.
packages/db/migrations/0185_new_gravity.sql Migration adds knowledge-base to the usage_log_source Postgres enum via standard ADD VALUE.

Sequence Diagram

sequenceDiagram
    participant UI as Connector Modal
    participant API as POST /connectors
    participant Sub as hasLiveSyncAccess
    participant DB as Database
    participant Embed as generateEmbeddings
    participant Billing as recordUsage

    UI->>API: POST { syncIntervalMinutes: 5 }
    API->>Sub: hasLiveSyncAccess(userId)
    Sub-->>API: true/false
    alt not Max/Enterprise
        API-->>UI: 403 Live sync requires Max
    else allowed
        API->>DB: Insert connector
        API-->>UI: 201 Created
    end

    Note over DB,Billing: Background: processDocumentAsync
    DB->>Embed: generateEmbeddings(texts, model, workspaceId)
    Embed-->>DB: { embeddings, totalTokens, isBYOK, modelName }
    DB->>DB: Insert embeddings + mark completed (transaction)
    alt !isBYOK && totalTokens > 0 && userId
        DB->>Billing: recordUsage({ cost, tokens })
        Billing->>Billing: checkAndBillOverageThreshold(userId)
    end
Loading

Reviews (4): Last reviewed commit: "fix(knowledge): call checkAndBillOverage..." | Re-trigger Greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 144b056. Configure here.

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit e92e3c9. Configure here.

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 80e97aa. Configure here.

@waleedlatif1 waleedlatif1 merged commit a9c9ed8 into staging Apr 3, 2026
12 checks passed
@waleedlatif1 waleedlatif1 deleted the feat/kb-connector-live-sync-option branch April 3, 2026 21:59
abhinavDhulipala pushed a commit to abhinavDhulipala/sim that referenced this pull request Apr 4, 2026
…g billing (simstudioai#3916)

* feat(knowledge): add Live sync option to KB connector modal for Max/Enterprise users

Adds a "Live" (every 5 min) sync frequency option gated to Max and Enterprise plan users.
Includes client-side badge + disabled state, shared sync intervals constant, and server-side
plan validation on both POST and PATCH connector routes.

* fix(knowledge): record embedding usage cost for KB document processing

Adds billing tracking to the KB embedding pipeline, which was previously
generating OpenAI API calls with no cost recorded. Token counts are now
captured from the actual API response and recorded via recordUsage after
successful embedding insertion. BYOK workspaces are excluded from billing.
Applies to all execution paths: direct, BullMQ, and Trigger.dev.

* fix(knowledge): simplify embedding billing — use calculateCost, return modelName

- Use calculateCost() from @/providers/utils instead of inline formula, consistent
  with how LLM billing works throughout the platform
- Return modelName from GenerateEmbeddingsResult so billing uses the actual model
  (handles custom Azure deployments) instead of a hardcoded fallback string
- Fix docs-chunker.ts empty-path fallback to satisfy full GenerateEmbeddingsResult type

* fix(knowledge): remove dev bypass from hasLiveSyncAccess

* chore(knowledge): rename sync-intervals to consts, fix stale TSDoc comment

* improvement(knowledge): extract MaxBadge component, capture billing config once per document

* fix(knowledge): add knowledge-base to usage_log_source enum, fix docs-chunker type

* fix(knowledge): generate migration for knowledge-base usage_log_source enum value

* fix(knowledge): add knowledge-base to usage_log_source enum via drizzle-kit

* fix(knowledge): fix search embedding test mocks, parallelize billing lookups

* fix(knowledge): warn when embedding model has no pricing entry

* fix(knowledge): call checkAndBillOverageThreshold after embedding usage
waleedlatif1 added a commit that referenced this pull request Apr 4, 2026
…g billing (#3916)

* feat(knowledge): add Live sync option to KB connector modal for Max/Enterprise users

Adds a "Live" (every 5 min) sync frequency option gated to Max and Enterprise plan users.
Includes client-side badge + disabled state, shared sync intervals constant, and server-side
plan validation on both POST and PATCH connector routes.

* fix(knowledge): record embedding usage cost for KB document processing

Adds billing tracking to the KB embedding pipeline, which was previously
generating OpenAI API calls with no cost recorded. Token counts are now
captured from the actual API response and recorded via recordUsage after
successful embedding insertion. BYOK workspaces are excluded from billing.
Applies to all execution paths: direct, BullMQ, and Trigger.dev.

* fix(knowledge): simplify embedding billing — use calculateCost, return modelName

- Use calculateCost() from @/providers/utils instead of inline formula, consistent
  with how LLM billing works throughout the platform
- Return modelName from GenerateEmbeddingsResult so billing uses the actual model
  (handles custom Azure deployments) instead of a hardcoded fallback string
- Fix docs-chunker.ts empty-path fallback to satisfy full GenerateEmbeddingsResult type

* fix(knowledge): remove dev bypass from hasLiveSyncAccess

* chore(knowledge): rename sync-intervals to consts, fix stale TSDoc comment

* improvement(knowledge): extract MaxBadge component, capture billing config once per document

* fix(knowledge): add knowledge-base to usage_log_source enum, fix docs-chunker type

* fix(knowledge): generate migration for knowledge-base usage_log_source enum value

* fix(knowledge): add knowledge-base to usage_log_source enum via drizzle-kit

* fix(knowledge): fix search embedding test mocks, parallelize billing lookups

* fix(knowledge): warn when embedding model has no pricing entry

* fix(knowledge): call checkAndBillOverageThreshold after embedding usage
@waleedlatif1 waleedlatif1 restored the feat/kb-connector-live-sync-option branch April 4, 2026 23:43
@waleedlatif1 waleedlatif1 deleted the feat/kb-connector-live-sync-option branch April 5, 2026 01:20
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