v0.6.85: mothership stream, resource column spacing, prospeo, findymail integrations, markdown google docs creation#4659
v0.6.85: mothership stream, resource column spacing, prospeo, findymail integrations, markdown google docs creation#4659waleedlatif1 wants to merge 10 commits into
Conversation
waleedlatif1
commented
May 19, 2026
- improvement(redis-cleanup): schedule, async workflow, hitl base64 cache cleanup (improvement(redis-cleanup): schedule, async workflow, hitl base64 cache cleanup #4646)
- improvement(mothership): abort path race preventing persistence (improvement(mothership): abort path race preventing persistence #4647)
- improvement(workspace): allocate more space to name column in resource tables (improvement(workspace): allocate more space to name column in resource tables #4645)
- fix(knowledge): preserve scroll position when toggling tokenizer in chunk viewer (fix(knowledge): preserve scroll position when toggling tokenizer in chunk viewer #4643)
- improvement(memory): replace unbounded server caches with lru-cache to fix heap growth (improvement(memory): replace unbounded server caches with lru-cache to fix heap growth #4652)
- feat(prospeo): add Prospeo integration for B2B contact enrichment and search (feat(prospeo): add Prospeo integration for B2B contact enrichment and search #4653)
- feat(findymail): add Findymail B2B contact data integration (feat(findymail): add Findymail B2B contact data integration #4654)
- improvement(workspace): fix resource table column proportions and toast stacking (improvement(workspace): fix resource table column proportions and toast stacking #4655)
- fix(tables): type-aware SQL casts for range filters on date columns (fix(tables): type-aware SQL casts for range filters on date columns #4657)
- feat(google_docs): opt-in Markdown formatting for create operation (feat(google_docs): opt-in Markdown formatting for create operation #4656)
…he cleanup (#4646) * improvement(redis-cleanup): schedule, async workflow, hitl bae64 cache cleanup * address comments
* improvement(mothership): abort path race preventing persistence * address comments * address bugbot comment
…hunk viewer (#4643) * fix(knowledge): preserve scroll position when toggling tokenizer in chunk viewer * fix(knowledge): skip scroll restore on initial mount of chunk editor * chore(dev): add dev:clean script to purge Turbopack cache
…o fix heap growth (#4652) * fix(memory): prune toolSchemaCache and semaphores to prevent heap growth toolSchemaCache (lib/copilot/chat/payload.ts): module-level Map keyed by userId:workspaceId never deleted expired entries, only checked TTL on read. With 100K+ unique user/workspace pairs each holding 50-200KB of tool schemas, this was the primary driver of the 24MB -> 25GB heap growth observed in CloudWatch. Add a setInterval sweep every 30s (matching the TTL) with .unref() so it does not prevent graceful shutdown. semaphores (lib/core/async-jobs/backends/database.ts): acquireSlot created Semaphore entries that releaseSlot never deleted. With per-execution UUID keys (e.g. scheduleJobId), each scheduled workflow run would add a permanent entry. Store the concurrency limit on the Semaphore struct and delete the entry from the Map when all slots are free and no waiters remain. validatorCache (lib/copilot/tools/server/generated-schema.ts): validated as bounded (93 tools x 2 schema kinds = 186 max entries, ~2-9MB). No fix needed. isolated-vm nativeContexts: validated as deferred GC, self-healed by worker rotation at MAX_EXECUTIONS_PER_WORKER=200. externalMB spikes trace to concurrent isolate heaps at peak load (128MB limit x active isolates), not a reference leak. No fix needed. * fix(memory): prune effectiveEnvCache and instrument cache sizes in telemetry effectiveEnvCache (lib/environment/utils.ts): same unbounded accumulation pattern as toolSchemaCache — module-level Map keyed by userId:workspaceId with a 15s TTL that is only checked on read, never proactively evicted. Adds a periodic sweep matching the TTL interval with .unref(). cache-registry (lib/monitoring/cache-registry.ts): lightweight registry so modules can expose their cache sizes to telemetry without coupling. toolSchemaCache and effectiveEnvCache both register on module load. memory-telemetry: emits cacheSizes in every Memory snapshot log so CloudWatch can confirm the caches stay bounded post-deploy. * improvement(memory): replace manual TTL Maps with lru-cache for toolSchemaCache and effectiveEnvCache Replaces the homegrown Map + setInterval sweep pattern with LRUCache from the lru-cache npm package, which is the standard Node.js solution for bounded in-process caching with TTL. Changes per cache: - Removes manual ToolSchemaCacheEntry / EffectiveEnvCacheEntry types - Removes setInterval sweep timers (and the .unref() boilerplate) - Removes the two-phase promise->value entry update inside the IIFE - Stores Promise<T> directly — in-flight and resolved states share one type - max: 200 (toolSchemaCache) / max: 500 (effectiveEnvCache) as hard ceilings - TTL behaviour and concurrent-request deduplication are preserved exactly - cache-registry .size reporting works unchanged via lru-cache's .size prop * fix(memory): remove redundant waiters guard in releaseSlot
… search (#4653) * feat(prospeo): add Prospeo integration for B2B contact enrichment and search Adds 8 operations: enrich person/company, bulk enrich person/company, search person/company, search suggestions, and account information. Uses X-KEY header auth. * refactor(prospeo): extract shared parse helpers into utils.ts
* feat(findymail): add Findymail B2B contact data integration Adds 11 tools covering verified email lookup (by name, LinkedIn, domain roles), email verification, reverse email lookup with profile enrichment, company info, employee discovery, phone lookup, technology stack detection, and credit checks. Single API-key block with operation dropdown, gradient-rendered icon, and generated docs. * fix(findymail): handle HTTP errors and surface last_detected_at - All 11 tools now check response.ok and return success:false with the API error message on non-2xx responses - search_technologies now maps last_detected_at to match lookup_technologies and the shared output schema - Restore file_v3 in docs icon-mapping (translated docs still reference it) * improvement(findymail): exclude operation from params transform Match the convention used by enrich/apify/box/calendly — destructure out operation before forwarding the rest to the tool call, so the operation key doesn't leak into the tool payload.
…st stacking (#4655) * improvement(workspace): fix resource table column proportions and toast stacking * fix(resource): restore scrollbar-gutter stable on table scroll container * fix(resource): remove scrollbar-gutter stable — single-table layout doesn't need it * fixed files cols * fix(findymail): add required enabled field to wandConfig entries * fix(findymail): remove optional from block outputs — not valid on BlockConfig output type * fixes * fix(files): use folderSizeMap for sort value so size sort matches display * files ref
…4657) * fix(tables): type-aware SQL casts for range filters on date columns * improvement(table): tighten filter-cast types & workspace guards - Drop redundant tableId/workspaceId from BulkUpdateData and BulkDeleteData; service uses table.id / table.workspaceId so column metadata and DB scope can't drift apart. - Add missing workspace-id guards to copilot user-table cases (insert_row, batch_insert_rows, update_row, batch_update_rows, rename); collapse duplicated rename check. - Add service-level integration tests that buildFilterClause/buildSortClause receive table.schema.columns from queryRows, updateRowsByFilter, deleteRowsByFilter. * improvement(table): cast jsonb date filters/sorts to timestamptz ::timestamp strips timezone offsets from ISO strings, making comparisons depend on the server TimeZone setting. ::timestamptz preserves the offset so chronological comparisons are correct regardless of server config. * improvement(table): correct JSDoc examples for required columns arg * improvement(table): validate range operator value types at SQL builder
…4656) * feat(google_docs): opt-in Markdown formatting for create operation * fix(google_docs): harden multipart boundary handoff and align postProcess guard
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Fixes cancelled copilot stream persistence/races: Refines table + workspace UI behavior: table row filtering now passes schema columns into Operational cleanup: scheduled and async workflow execution now always clears the per-execution base64 cache in Docs updates: File tool docs switch to Reviewed by Cursor Bugbot for commit 6827be7. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6827be7. Configure here.
| } | ||
| for (const folder of folders) getTotal(folder.id) | ||
| return totalSize | ||
| }, [files, folders]) |
There was a problem hiding this comment.
Folder size computation ignores files outside current view
Medium Severity
The folderSizeMap computation iterates over files to sum sizes per folder, but files likely represents only the files currently loaded/visible (possibly filtered or paginated), not all files in the workspace. This means folder sizes will be inaccurate — showing partial totals when files are filtered, searched, or paginated, and potentially showing EMPTY_CELL_PLACEHOLDER for folders that actually contain files not in the current view.
Reviewed by Cursor Bugbot for commit 6827be7. Configure here.
| onDismiss={dismissToast} | ||
| /> | ||
| ) | ||
| })} |
There was a problem hiding this comment.
Stacked toasts overlap hiding content behind newer ones
Medium Severity
All toast items use [grid-area:1/1] causing them to stack on the same grid cell. The stackOffset applies a horizontal translateX shift of only 3px * depth, meaning multiple toasts are nearly completely overlapping. With MAX_VISIBLE set to 4, four toasts would pile on top of each other with just 3–9px horizontal offset — making older toast content unreadable and their dismiss buttons inaccessible.
Reviewed by Cursor Bugbot for commit 6827be7. Configure here.
Greptile SummaryThis release bundles several independent improvements: a race-condition fix in the mothership stream's cancelled-completion path, LRU-backed server-side caches to bound heap growth, type-aware SQL casts for date/number range filters, and three new integrations (Prospeo, Findymail, Google Docs Markdown creation).
Confidence Score: 4/5Safe to merge; no data-loss or security regressions found. The cancel-path race fix uses a sound FOR UPDATE transaction approach. The SQL type-cast refactor is well-tested. The open questions around the Google Docs markdown path (string body serialization and boundary param mutation) should be confirmed before that feature is exercised in production, but neither represents a guaranteed breakage today. apps/sim/tools/google_docs/create.ts — confirm the tool execution framework handles a string return value from body() without JSON-stringifying it. Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant StopRoute as /chat/stop
participant PostCB as onComplete
participant DB as Postgres
Note over Client,DB: Cancel path - both paths run concurrently
Client->>StopRoute: POST stop
Client->>PostCB: abort signal fires
par Stop endpoint
StopRoute->>DB: SELECT FOR UPDATE WHERE chatId AND userId
DB-->>StopRoute: row with conversationId and messages
StopRoute->>StopRoute: ownsTurn check active-or-cleared policy
StopRoute->>DB: UPDATE messages append assistantMsg and stopped block
DB-->>StopRoute: updated
StopRoute->>Client: publishStatusChanged completed
and Completion callback
PostCB->>DB: SELECT FOR UPDATE WHERE chatId
DB-->>PostCB: row
PostCB->>PostCB: alreadyHasResponse check
alt not yet persisted
PostCB->>DB: UPDATE messages append assistantMsg and stopped block
else already persisted by stop
PostCB->>PostCB: outcome AssistantAlreadyPersisted
end
PostCB->>Client: publishStatusChanged if warranted
end
|
| @keyframes toast-enter { | ||
| from { | ||
| opacity: 0; | ||
| transform: translateY(8px) scale(0.97); | ||
| transform: translateX(var(--stack-offset, 0px)) translateY(8px) scale(0.97); | ||
| } | ||
| to { | ||
| opacity: 1; | ||
| transform: translateY(0) scale(1); | ||
| transform: translateX(var(--stack-offset, 0px)) translateY(0) scale(1); | ||
| } | ||
| } | ||
|
|
||
| @keyframes toast-exit { | ||
| from { | ||
| opacity: 1; | ||
| transform: translateY(0) scale(1); | ||
| transform: translateX(var(--stack-offset, 0px)) translateY(0) scale(1); | ||
| } | ||
| to { | ||
| opacity: 0; | ||
| transform: translateY(8px) scale(0.97); | ||
| transform: translateX(var(--stack-offset, 0px)) translateY(8px) scale(0.97); | ||
| } | ||
| } |
There was a problem hiding this comment.
The keyframe animations in
globals.css were updated to support the --stack-offset custom property for toast stacking. Per the project style rule, globals.css edits should be avoided and styles moved to local component files instead. CSS @keyframes are globally scoped and can't be co-located with a component module today, but the same visual effect is achievable without a globals.css change by applying the translateX directly on the element's style prop (which already sets --stack-offset) and using a Tailwind transition on transform. If the keyframe approach is kept, the impact here is minimal.
| @keyframes toast-enter { | |
| from { | |
| opacity: 0; | |
| transform: translateY(8px) scale(0.97); | |
| transform: translateX(var(--stack-offset, 0px)) translateY(8px) scale(0.97); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0) scale(1); | |
| transform: translateX(var(--stack-offset, 0px)) translateY(0) scale(1); | |
| } | |
| } | |
| @keyframes toast-exit { | |
| from { | |
| opacity: 1; | |
| transform: translateY(0) scale(1); | |
| transform: translateX(var(--stack-offset, 0px)) translateY(0) scale(1); | |
| } | |
| to { | |
| opacity: 0; | |
| transform: translateY(8px) scale(0.97); | |
| transform: translateX(var(--stack-offset, 0px)) translateY(8px) scale(0.97); | |
| } | |
| } | |
| @keyframes toast-enter { | |
| from { | |
| opacity: 0; | |
| transform: translateY(8px) scale(0.97); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0) scale(1); | |
| } | |
| } | |
| @keyframes toast-exit { | |
| from { | |
| opacity: 1; | |
| transform: translateY(0) scale(1); | |
| } | |
| to { | |
| opacity: 0; | |
| transform: translateY(8px) scale(0.97); | |
| } | |
| } |
Rule Used: Avoid editing the globals.css file unless absolute... (source)
Learned From
simstudioai/sim#367
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| @@ -69,18 +115,30 @@ export const createTool: ToolConfig<GoogleDocsToolParams, GoogleDocsCreateRespon | |||
| throw new Error('Title is required') | |||
| } | |||
|
|
|||
| const requestBody: any = { | |||
| const folderId = params.folderSelector || params.folderId | |||
| const metadata: Record<string, unknown> = { | |||
| name: params.title, | |||
There was a problem hiding this comment.
Boundary stashed via param mutation between headers() and body()
headers() writes _boundary onto the params object so body() can read it, creating a hidden execution-order dependency. If the tool execution framework ever evaluates body() before headers(), _boundary will be undefined and the function throws — producing an HTTP 400 to Google with a mismatched Content-Type. The loud throw is a good guard, but the better fix is to generate the boundary once outside both functions or derive it deterministically from params.

