Skip to content

Commit ab3c65c

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
Merge remote-tracking branch 'origin/staging' into add-quickbooks-procurement
2 parents db63eba + edef789 commit ab3c65c

103 files changed

Lines changed: 8823 additions & 3485 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci-cache-cleanup.yml

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
name: CI Cache Cleanup
22

3-
# test-build.yml keys the Next.js build cache sticky disk per branch, so every PR
4-
# leaves a ~5 GB volume behind. Branches are short-lived; the disks aren't. Only
5-
# the pull_request disks are reclaimed — the push disks belong to main/staging/dev
6-
# and must stay warm.
3+
# DRAINING LEGACY DISKS ONLY. test-build.yml no longer mounts a Next.js build
4+
# cache — the Turbopack persistent cache measured 3.2x SLOWER than no cache, so it
5+
# is off. But every PR open while the per-branch key was live left a 5-12 GB volume
6+
# behind, and nothing else reclaims them. This keeps deleting them as those PRs
7+
# close.
8+
#
9+
# Delete this workflow once the backlog is drained (no PR predating the cache
10+
# removal is still open). It is a no-op for new PRs, which never create a disk.
711

812
on:
913
pull_request:
@@ -22,9 +26,12 @@ jobs:
2226
timeout-minutes: 5
2327

2428
steps:
25-
# Must stay byte-identical to the Mount Next.js build cache key in
26-
# test-build.yml, or this deletes nothing and the disks accumulate.
27-
# Non-blocking: PRs skipped by ci.yml's paths-ignore never made a disk.
29+
# A hard-coded legacy drain key. It no longer mirrors anything — the
30+
# Mount Next.js build cache step it used to match was removed with the
31+
# cache. Do not retarget or delete it while PRs from before that removal
32+
# are still open, or their 5-12 GB disks are never reclaimed.
33+
# Non-blocking: PRs skipped by ci.yml's paths-ignore never made a disk,
34+
# and neither does any PR opened after the removal.
2835
- name: Delete sticky disk
2936
uses: useblacksmith/stickydisk-delete@b41313d28b8647d72114c9ba3c96bb04061562b6 # v1
3037
continue-on-error: true

.github/workflows/test-build.yml

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,9 @@ jobs:
177177
- name: Install ripgrep
178178
run: command -v rg || (sudo apt-get update && sudo apt-get install -y ripgrep)
179179

180-
- name: Run tests with coverage
180+
# Named for what it does: `bun run test` is `vitest run`, with no
181+
# `--coverage`. See the Codecov note below.
182+
- name: Run tests
181183
env:
182184
NODE_OPTIONS: '--no-warnings --max-old-space-size=8192'
183185
NEXT_PUBLIC_APP_URL: 'https://www.sim.ai'
@@ -199,6 +201,14 @@ jobs:
199201
fi
200202
echo "✅ Schema and migrations are in sync"
201203
204+
# DEAD PATH: nothing generates `apps/sim/coverage`. The test step runs
205+
# `vitest run` without `--coverage`, and vitest.config.ts declares no
206+
# coverage provider, so this uploads nothing and still reports success in
207+
# ~1s (`fail_ci_if_error: false` hides it). `@vitest/coverage-v8` IS
208+
# installed, so wiring it up is possible — but coverage instrumentation
209+
# costs test time and nothing gates on the result today. Left in place
210+
# pending a decision to either enable coverage or drop this step; do not
211+
# read its green tick as "coverage was published".
202212
- name: Upload coverage to Codecov
203213
uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5
204214
with:
@@ -263,24 +273,12 @@ jobs:
263273
key: ${{ github.repository }}-turbo-cache-build-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}
264274
path: ./.turbo
265275

266-
# Turbopack's persistent build cache (NEXT_TURBOPACK_BUILD_CACHE below)
267-
# writes ~5 GB into .next/cache — a sticky disk mounts it in ~1s where an
268-
# actions/cache round-trip would eat the warm-build win.
269-
#
270-
# Keyed per branch, not just per event. A sticky disk is one mutable volume
271-
# per key: mounting clones the last committed snapshot, job end commits back
272-
# last-write-wins. An event-only key had every open PR restoring a cache
273-
# built from a different branch — 14.0 min vs 9.3 min for the single-writer
274-
# push disk on the same commit. Branch scoping also keeps us off
275-
# cross-commit restore, which turbopackFileSystemCacheForBuild (beta) does
276-
# not document as supported (vercel/next.js#87283: stale HTML from a cache
277-
# built at another commit). ci-cache-cleanup.yml reclaims the disks.
278-
- name: Mount Next.js build cache
279-
uses: ./.github/actions/cache-mount
280-
with:
281-
provider: ${{ vars.CI_PROVIDER }}
282-
key: ${{ github.repository }}-nextjs-cache-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ github.head_ref || github.ref_name }}
283-
path: ./apps/sim/.next/cache
276+
# No `.next/cache` mount: the Turbopack persistent build cache is off. A
277+
# controlled A/B on one branch (PR #6078) with a byte-identical module graph
278+
# measured compile at 113s with the cache off, 162s cold with it on, and
279+
# 360s warm — the cache made the same build 3.2x slower, and it grew
280+
# 5.1 GB -> 12 GB across two runs of an unchanged tree, so a disk degrades
281+
# the more it is used. Mounting a disk nothing reads would only cost storage.
284282

285283
# Running out of RAM kills the whole VM and surfaces only as "the runner
286284
# has received a shutdown signal" — no mention of memory, ~12 min in. Warn
@@ -300,13 +298,6 @@ jobs:
300298
- name: Install dependencies
301299
run: bun install --frozen-lockfile --ignore-scripts
302300

303-
# The disk mounts successfully whether or not it carried anything and turbo
304-
# buffers the build log, so cache warmth is otherwise unobservable — #5859
305-
# shipped a cache that carried almost nothing and it took a PR to notice.
306-
# Reported, never gated.
307-
- name: Report Next.js cache size (pre-build)
308-
run: du -sh apps/sim/.next/cache 2>/dev/null || echo 'cold — no cache restored'
309-
310301
- name: Build application
311302
env:
312303
NODE_OPTIONS: '--no-warnings --max-old-space-size=8192'
@@ -318,13 +309,4 @@ jobs:
318309
AWS_REGION: 'us-west-2'
319310
ENCRYPTION_KEY: '7cf672e460e430c1fba707575c2b0e2ad5a99dddf9b7b7e3b5646e630861db1c' # dummy key for CI only
320311
TURBO_CACHE_DIR: .turbo
321-
# Opt into Turbopack's persistent build cache (beta) for this CI check
322-
# build only. #5869's 105s-cold/22s-warm was measured locally and has
323-
# never reproduced in CI (compile has ranged 3.5-17.8 min) — local
324-
# numbers, not a CI target.
325-
NEXT_TURBOPACK_BUILD_CACHE: '1'
326312
run: bunx turbo run build --filter=sim
327-
328-
- name: Report Next.js cache size (post-build)
329-
if: always()
330-
run: du -sh apps/sim/.next/cache 2>/dev/null || echo 'no cache written'

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,14 @@ i18n.cache
102102
# Python (apps/pii tests/tooling)
103103
__pycache__/
104104
.pytest_cache/
105+
106+
# Local file-upload spill directory. `UPLOAD_DIR_SERVER` is
107+
# `join(process.cwd(), 'uploads')`, so it follows the cwd rather than a fixed
108+
# root: under `turbo run test` the cwd is apps/sim and `apps/sim/.gitignore`'s
109+
# `/uploads` catches it, but running vitest from the repo root drops ~40
110+
# `uploads/execution/**/large-value-*.json` files here instead.
111+
#
112+
# Anchored deliberately. An unanchored `uploads/` would also match
113+
# `apps/sim/lib/uploads/` — 61 files of tracked source — and silently ignore
114+
# anything added there later.
115+
/uploads

apps/docs/app/[lang]/[[...slug]]/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
121121
const urlParts = page.url.split('/').filter(Boolean)
122122
let currentPath = ''
123123

124-
urlParts.forEach((part, index) => {
124+
urlParts.forEach((part: string, index: number) => {
125125
if (index === 0 && SUPPORTED_LANGUAGES.has(part)) {
126126
currentPath = `/${part}`
127127
return
@@ -131,7 +131,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
131131

132132
const name = part
133133
.split('-')
134-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
134+
.map((word: string) => word.charAt(0).toUpperCase() + word.slice(1))
135135
.join(' ')
136136

137137
if (index === urlParts.length - 1) {

apps/docs/app/api/chat/route.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import { openai } from '@ai-sdk/openai'
2-
import { convertToModelMessages, stepCountIs, streamText, tool, type UIMessage } from 'ai'
2+
import {
3+
convertToModelMessages,
4+
jsonSchema,
5+
stepCountIs,
6+
streamText,
7+
tool,
8+
type UIMessage,
9+
} from 'ai'
310
import { sql } from 'drizzle-orm'
4-
import { z } from 'zod'
511
import { db, docsEmbeddings } from '@/lib/db'
612
import { generateSearchEmbedding } from '@/lib/embeddings'
713

@@ -332,8 +338,21 @@ export async function POST(req: Request) {
332338
searchDocs: tool({
333339
description:
334340
'Search the Sim documentation for relevant content. Use this before answering any question about Sim.',
335-
inputSchema: z.object({
336-
query: z.string().describe('A focused natural-language search query.'),
341+
/**
342+
* The SDK's own schema helper instead of a zod schema: the `ai`
343+
* package's zod-v4 typings lag the workspace zod version, so a zod
344+
* object here fails the tool() overloads whenever the two drift.
345+
*/
346+
inputSchema: jsonSchema<{ query: string }>({
347+
type: 'object',
348+
properties: {
349+
query: {
350+
type: 'string',
351+
description: 'A focused natural-language search query.',
352+
},
353+
},
354+
required: ['query'],
355+
additionalProperties: false,
337356
}),
338357
execute: async ({ query }) => searchDocs(query, locale),
339358
}),

apps/docs/content/docs/en/platform/costs.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ By default, your usage is capped at the credits included in your plan. To allow
321321
| **Max** | Up to 10 ||
322322
| **Team / Enterprise** || Unlimited (Owners and Admins) |
323323

324-
Team and Enterprise plans unlock shared workspaces that belong to your organization. Every workspace created under a Team or Enterprise plan is organization-owned: Owners and Admins can create unlimited shared workspaces, while organization Members cannot create workspaces (personal workspaces created before joining the organization remain accessible). Internal members invited to a shared workspace join the organization and count toward your seat total — Enterprise invites require an available seat at invite time, while Team plans add a seat automatically when the invitee accepts. Existing Sim users who already belong to another organization can be added as external workspace members; they get workspace access without joining your organization or using one of your seats. When a Team or Enterprise subscription is cancelled or downgraded, existing shared workspaces remain accessible to current members but new invites are disabled until the organization is upgraded again.
324+
Team and Enterprise plans unlock shared workspaces that belong to your organization. Every workspace created under a Team or Enterprise plan is organization-owned: Owners and Admins can create unlimited shared workspaces, while organization Members cannot create workspaces. When someone joins the organization as an internal member, personal workspaces they own move into the organization and their usage is billed to it from then on. Internal members count toward your seat total — Enterprise invites require an available seat at invite time, while Team plans add a seat automatically when the invitee accepts. External workspace members get access to specific workspaces without joining your organization or using one of your seats; they must already be on a paid Sim plan (their own Pro or Max subscription, or another organization that seats them), and invitees who already belong to another organization always join this way. When a Team or Enterprise subscription is cancelled or downgraded, existing shared workspaces remain accessible to current members but new invites are disabled until the organization is upgraded again.
325325

326326
### Rate Limits
327327

0 commit comments

Comments
 (0)