fix(workbench): persist Pro conversation titles #3213
Workflow file for this run
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
| name: CI | |
| on: | |
| push: | |
| # Integration branches are listed here as well as below: a pull_request run | |
| # only ever proves one part merged into the branch, so without a push | |
| # trigger the accumulated state of the branch that eventually reaches main | |
| # is never built on its own. | |
| branches: [main, integration/kv-asset-server-backend, integration/agent-workbench] | |
| pull_request: | |
| branches: | |
| [ | |
| main, | |
| feat/maic-editor-v0, | |
| feat/maic-editor-v1, | |
| runtime-server-backend, | |
| integration/kv-asset-server-backend, | |
| integration/agent-workbench, | |
| ] | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| # Never cancel a main run. Each main run validates only its own push range, so | |
| # a superseded run takes the range that contained a package change with it and | |
| # the replacement, comparing against the cancelled tip, sees nothing. | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| check: | |
| name: Lint, Typecheck & Unit Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| # Cheap bash-only check so a broken helper fails before pnpm install. | |
| # Quiet annotations: the expected-failure case would otherwise paint | |
| # the check with a fake ::error::. | |
| - name: Parallel runner self-test | |
| env: | |
| CI_PARALLEL_ANNOTATE: '0' | |
| run: | | |
| set -euo pipefail | |
| scripts/ci-run-parallel.sh ok 'true' ok2 'true' | |
| if scripts/ci-run-parallel.sh ok 'true' bad 'exit 7'; then | |
| echo 'ci-run-parallel.sh should have failed' | |
| exit 1 | |
| fi | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| - name: Package version bumps | |
| if: github.event_name == 'pull_request' | |
| run: node scripts/check-package-version-bumps.mjs "$BASE_SHA" | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| # A branch creation or a force push reports an unusable `before`. Fail | |
| # rather than substituting HEAD^: a force push can replace many commits at | |
| # once, so the previous commit is not the range that needs checking, and | |
| # publishing requires this run to be green. | |
| - name: Package version bumps (main push) | |
| if: github.event_name == 'push' | |
| run: | | |
| set -euo pipefail | |
| base="$BEFORE_SHA" | |
| if [ -z "$base" ] || ! git rev-parse --verify --quiet "$base^{commit}" >/dev/null; then | |
| echo "::error::Push range base ${base:-<empty>} is unavailable, so this push cannot be checked." | |
| echo "Re-run after the branch has an ordinary push range, or verify the versions by hand." | |
| exit 1 | |
| fi | |
| node scripts/check-package-version-bumps.mjs "$base" | |
| env: | |
| BEFORE_SHA: ${{ github.event.before }} | |
| # The tarball smoke test proves this about the bytes that would actually | |
| # be published, but it installs five package tarballs, so it runs only on | |
| # the release path. This is the cheap source-level form, here so that a | |
| # pull request restoring `workspace:*` fails at review time rather than at | |
| # release time, after a version number has already been spent. | |
| - name: Internal dependency ranges | |
| run: node scripts/check-internal-dependency-ranges.mjs | |
| - run: pnpm install --frozen-lockfile | |
| # `postinstall` builds all five @openmaic packages, and some of them | |
| # generate tracked, publishable files (renderer's fonts.css and its KaTeX | |
| # font snapshot). The publish workflow refuses to release when the build | |
| # rewrites one; catching it here means a stale generated file is a pull | |
| # request failure instead of a release failure. | |
| # | |
| # Against GITHUB_SHA, not the index or HEAD: a bare `git diff` misses | |
| # staged changes, while install code can create a commit and move HEAD. | |
| # This check exists precisely because code ran before it, so its reference | |
| # point must be something that code cannot move. Disabling replacement | |
| # objects also prevents a local replace ref from redirecting the commit. | |
| - name: Verify the install did not rewrite tracked package files | |
| run: | | |
| set -euo pipefail | |
| actual_head="$(git --no-replace-objects rev-parse HEAD)" | |
| if [ "$actual_head" != "$GITHUB_SHA" ]; then | |
| echo "::error::HEAD moved from $GITHUB_SHA to $actual_head during installation." | |
| exit 1 | |
| fi | |
| if ! git --no-replace-objects diff --quiet "$GITHUB_SHA" -- packages/@openmaic; then | |
| echo "::error::Installing rewrote tracked files under packages/@openmaic." | |
| echo "Regenerate them and commit the result." | |
| git --no-replace-objects --no-pager diff --stat "$GITHUB_SHA" -- packages/@openmaic | |
| exit 1 | |
| fi | |
| echo "Tracked package files match the commit under test." | |
| # These four do not share state. Sequential they were ~2 minutes; the | |
| # slowest (ESLint) is the new bound. | |
| - name: Prettier, ESLint, TypeScript, i18n | |
| run: | | |
| scripts/ci-run-parallel.sh \ | |
| 'prettier' 'pnpm check' \ | |
| 'eslint' 'pnpm lint' \ | |
| 'tsc' 'npx tsc --noEmit' \ | |
| 'i18n' 'pnpm check:i18n-keys' | |
| # Keep these sequential. Running root vitest alongside the storage | |
| # package on a 4-core runner made 5s-timeout tests flake (CPU | |
| # contention, not a product regression). | |
| - name: Unit Tests | |
| run: pnpm test | |
| - name: Unit Tests (importer) | |
| run: pnpm --filter @openmaic/importer test | |
| - name: Unit Tests (dsl) | |
| run: pnpm --filter @openmaic/dsl test | |
| - name: TypeScript (generation) | |
| run: pnpm --filter @openmaic/generation run typecheck | |
| - name: Unit Tests (generation) | |
| run: pnpm --filter @openmaic/generation test | |
| - name: Node consumer smoke (generation scene) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| port=43127 | |
| node scripts/generation-node-smoke-server.mjs --port "$port" >"$RUNNER_TEMP/generation-smoke-server.log" 2>&1 & | |
| server_pid=$! | |
| cleanup() { | |
| kill "$server_pid" 2>/dev/null || true | |
| wait "$server_pid" 2>/dev/null || true | |
| } | |
| trap cleanup EXIT | |
| for attempt in {1..50}; do | |
| if node -e "fetch('http://127.0.0.1:$port/health').then(r => { if (!r.ok) process.exit(1) }).catch(() => process.exit(1))"; then | |
| break | |
| fi | |
| if [ "$attempt" -eq 50 ]; then | |
| cat "$RUNNER_TEMP/generation-smoke-server.log" | |
| exit 1 | |
| fi | |
| sleep 0.1 | |
| done | |
| output="$(node scripts/generation-node-smoke.mjs \ | |
| --requirement "Explain dependency injection" \ | |
| --endpoint "http://127.0.0.1:$port" \ | |
| --model smoke-model)" | |
| printf '%s\n' "$output" | |
| node -e 'const value = JSON.parse(process.argv[1]); if (!Array.isArray(value.outlines) || value.outlines.length === 0 || !value.scene || value.sceneValidation?.valid !== true) process.exit(1)' "$output" | |
| # Covers the package's own test tree, which the root tsc reaches only by an | |
| # incidental glob. The device-scope guard is written as `@ts-expect-error` | |
| # probes in those tests, and a probe nothing type-checks proves nothing. | |
| - name: TypeScript (storage, incl. tests) | |
| run: pnpm --filter @openmaic/storage run typecheck | |
| - name: Unit Tests (storage) | |
| run: pnpm --filter @openmaic/storage test | |
| render-service: | |
| name: Render Service (typecheck + tests) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| # The producer dep bundles puppeteer; skip its Chromium download — the unit | |
| # tests exercise the service's boundaries (unzip, admission, body caps) and | |
| # never launch a browser. | |
| env: | |
| PUPPETEER_SKIP_DOWNLOAD: "true" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| # render-service is its own npm package (own lockfile, Node-only deps), | |
| # excluded from the root eslint/tsc/pnpm workspace — so it gets its own | |
| # install + quality gate here rather than riding on the `check` job. | |
| cache: npm | |
| cache-dependency-path: render-service/package-lock.json | |
| - name: Install | |
| working-directory: render-service | |
| run: npm ci | |
| - name: TypeScript | |
| working-directory: render-service | |
| run: npm run typecheck | |
| - name: Unit Tests | |
| working-directory: render-service | |
| run: npm test | |
| - name: Build container image | |
| run: docker build --tag openmaic-render-service:ci render-service | |
| e2e: | |
| name: E2E Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| - run: pnpm install --frozen-lockfile | |
| # Browser tarballs live under ~/.cache/ms-playwright. A cold download of | |
| # Chromium from the Playwright CDN has sat for 20+ minutes on this runner | |
| # fleet; a lockfile-keyed cache turns that into a restore. | |
| - name: Cache Playwright browsers | |
| id: playwright-cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }} | |
| # Browser tarball only. `install-deps` talks to Ubuntu apt; on this | |
| # runner fleet that mirror has sat through the whole 15-minute job | |
| # budget. ubuntu-latest already ships the libraries Chromium needs. | |
| # Bound the Microsoft CDN download so a stall retries instead of hanging. | |
| - name: Install Playwright Chromium | |
| run: | | |
| set -euo pipefail | |
| for attempt in 1 2 3; do | |
| if timeout -k 10 240 pnpm exec playwright install chromium; then | |
| exit 0 | |
| fi | |
| echo "Playwright Chromium download attempt ${attempt} failed, retrying..." | |
| sleep 5 | |
| done | |
| echo "::error::Playwright Chromium download failed after 3 attempts." | |
| exit 1 | |
| # Measures the emitted cover cards in Chromium. Lives with the unit tests | |
| # (it needs the compiler), but only this job has a browser, so it runs | |
| # here with the flag that turns a missing one into a failure. | |
| - name: Cover-card layout guardrail | |
| run: pnpm exec vitest run tests/video-export/cover-card-layout.browser.test.ts | |
| env: | |
| COVER_LAYOUT_BROWSER: '1' | |
| - name: Interactive static HTML Chromium smoke | |
| run: pnpm exec vitest run tests/video-export/interactive-static-html.browser.test.ts | |
| env: | |
| INTERACTIVE_STATIC_BROWSER: '1' | |
| # runner.* is only valid in step contexts (not job-level env). | |
| - name: Materialize Hyperframes lint samples | |
| run: pnpm exec vitest run tests/video-export/e2e-materialize.test.ts | |
| env: | |
| HF_E2E_DIR: ${{ runner.temp }}/openmaic-hyperframes-samples | |
| # Hyperframes 0.7.60 reports warning-only lint with exit status zero, so | |
| # require its plain clean summary as well as a successful process. | |
| - name: Lint Hyperframes samples | |
| shell: bash | |
| env: | |
| HF_E2E_DIR: ${{ runner.temp }}/openmaic-hyperframes-samples | |
| run: | | |
| set -euo pipefail | |
| for sample in quiz pbl-v2 pbl-legacy pbl-dense mixed arabic interactive-static; do | |
| dir="$HF_E2E_DIR/$sample" | |
| if output="$(pnpm exec hyperframes lint "$dir" 2>&1)"; then | |
| status=0 | |
| else | |
| status=$? | |
| fi | |
| printf '%s\n' "$output" | |
| if [ "$status" -ne 0 ]; then | |
| echo "::error::Hyperframes lint failed for $sample (exit $status)." | |
| exit "$status" | |
| fi | |
| if ! grep -Fq -- '0 errors, 0 warnings' <<<"$output"; then | |
| echo "::error::Hyperframes lint for $sample did not report zero errors and zero warnings." | |
| exit 1 | |
| fi | |
| done | |
| # Incremental compilation artifacts only. Keyed on the lockfile plus | |
| # next.config.ts so a dependency or webpack-rule change misses; source | |
| # edits still reuse the restore-key prefix. | |
| - name: Cache Next.js build | |
| uses: actions/cache@v4 | |
| with: | |
| path: .next/cache | |
| key: ${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('next.config.ts') }} | |
| restore-keys: | | |
| ${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml') }}- | |
| # Dedicated so a cold `next build` is not charged against Playwright's | |
| # webServer readiness budget (120s). NEXT_PUBLIC_MAIC_EDITOR_ENABLED is a | |
| # build-time flag and must be set here, not only on `pnpm start`. | |
| - name: Build | |
| run: pnpm build | |
| env: | |
| NEXT_PUBLIC_MAIC_EDITOR_ENABLED: 'true' | |
| - name: Run e2e tests | |
| run: pnpm exec playwright test | |
| - uses: actions/upload-artifact@v4 | |
| if: failure() | |
| with: | |
| name: playwright-report | |
| path: playwright-report/ | |
| retention-days: 7 |