From a10b02afc4fe53ca938d4bf01a1c239aac680262 Mon Sep 17 00:00:00 2001 From: Andrew Barba Date: Wed, 29 Jul 2026 17:31:03 -0400 Subject: [PATCH 1/5] chore(e2e): add Postgres workflow world matrix Signed-off-by: Andrew Barba --- .github/workflows/e2e-postgres.yml | 233 ++++++++ e2e/README.md | 69 ++- .../agent-basic-runtime/agent/agent.ts | 3 + e2e/fixtures/agent-basic-runtime/package.json | 1 + .../agent-cancellation/agent/agent.ts | 3 + e2e/fixtures/agent-cancellation/package.json | 1 + e2e/fixtures/agent-channels/agent/agent.ts | 3 + e2e/fixtures/agent-channels/package.json | 1 + .../agent/agent.ts | 2 + .../agent-compaction-regressions/package.json | 1 + e2e/fixtures/agent-model/agent/agent.ts | 2 + e2e/fixtures/agent-model/package.json | 1 + .../agent-openapi-swagger/agent/agent.ts | 3 + .../agent-openapi-swagger/package.json | 1 + .../agent-prompt-cache/agent/agent.ts | 3 + e2e/fixtures/agent-prompt-cache/package.json | 1 + e2e/fixtures/agent-schedules/agent/agent.ts | 3 + e2e/fixtures/agent-schedules/package.json | 1 + .../agent-session-limits/agent/agent.ts | 3 + .../agent-session-limits/package.json | 1 + e2e/fixtures/agent-skills/agent/agent.ts | 3 + e2e/fixtures/agent-skills/package.json | 1 + .../agent-subagents-hitl/agent/agent.ts | 3 + .../agent-subagents-hitl/package.json | 1 + e2e/fixtures/agent-subagents/agent/agent.ts | 3 + e2e/fixtures/agent-subagents/package.json | 1 + .../agent-tools-hitl-openai/agent/agent.ts | 3 + .../agent-tools-hitl-openai/package.json | 1 + e2e/fixtures/agent-tools-hitl/agent/agent.ts | 3 + e2e/fixtures/agent-tools-hitl/package.json | 1 + .../agent-tools-sandbox/agent/agent.ts | 3 + e2e/fixtures/agent-tools-sandbox/package.json | 1 + e2e/fixtures/agent-tools/agent/agent.ts | 3 + e2e/fixtures/agent-tools/package.json | 1 + .../agent-workflow-stress/agent/agent.ts | 3 + .../agent-workflow-stress/package.json | 1 + e2e/fixtures/dist-extensions/agent/agent.ts | 3 + e2e/fixtures/dist-extensions/package.json | 1 + e2e/fixtures/extensions/agent/agent.ts | 3 + e2e/fixtures/extensions/package.json | 1 + pnpm-lock.yaml | 515 ++++++++++++++++-- pnpm-workspace.yaml | 1 + 42 files changed, 837 insertions(+), 55 deletions(-) create mode 100644 .github/workflows/e2e-postgres.yml diff --git a/.github/workflows/e2e-postgres.yml b/.github/workflows/e2e-postgres.yml new file mode 100644 index 000000000..d686c2e26 --- /dev/null +++ b/.github/workflows/e2e-postgres.yml @@ -0,0 +1,233 @@ +name: E2E Tests (Postgres) + +on: + workflow_dispatch: + pull_request: + +concurrency: + group: e2e-postgres-${{ github.ref }} + cancel-in-progress: true + +jobs: + # The stable aggregate check must report on every PR. This job decides + # relevance so the matrix can skip at the job level without starting a + # PostgreSQL service container for every fixture on unrelated changes. + changes: + name: changes + runs-on: ubuntu-latest + outputs: + relevant: ${{ steps.filter.outputs.relevant }} + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + fetch-depth: 2 + + - name: Check changed paths + id: filter + run: | + if [ "${{ github.event_name }}" != "pull_request" ]; then + echo "relevant=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + # HEAD is the PR merge commit; HEAD^1 is the base branch tip, so + # this diff is exactly the PR's changed files. + if git diff --name-only HEAD^1 HEAD | grep -qE '^(packages/eve/|apps/fixtures/|e2e/|pnpm-workspace\.yaml$|pnpm-lock\.yaml$|\.github/workflows/e2e-postgres\.yml$|\.github/scripts/discover-e2e-fixtures\.sh$)'; then + echo "relevant=true" >> "$GITHUB_OUTPUT" + else + echo "relevant=false" >> "$GITHUB_OUTPUT" + fi + + discover-fixtures: + name: discover-fixtures + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.discover.outputs.matrix }} + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Discover eval fixtures + id: discover + run: .github/scripts/discover-e2e-fixtures.sh + + e2e: + name: e2e-postgres (${{ matrix.fixture.name }}, ${{ matrix.model.name }}) + runs-on: ubuntu-latest + needs: [changes, discover-fixtures] + if: needs.changes.outputs.relevant == 'true' + strategy: + fail-fast: false + matrix: + fixture: ${{ fromJSON(needs.discover-fixtures.outputs.matrix) }} + model: + - name: openai-sol + id: openai/gpt-5.6-sol + - name: anthropic-opus + id: anthropic/claude-opus-5 + + services: + postgres: + image: postgres:18-alpine + env: + POSTGRES_DB: world + POSTGRES_PASSWORD: world + POSTGRES_USER: world + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready --username=world --dbname=world" + --health-interval 5s + --health-timeout 5s + --health-retries 12 + + env: + AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }} + EVE_E2E_MODEL: ${{ matrix.model.id }} + EVE_E2E_WORKFLOW_WORLD: "@workflow/world-postgres" + EVE_EVAL_JUNIT_DIR: ${{ github.workspace }}/.junit + WORKFLOW_POSTGRES_MAX_POOL_SIZE: "52" + WORKFLOW_POSTGRES_URL: postgres://world:world@127.0.0.1:5432/world + WORKFLOW_POSTGRES_WORKER_CONCURRENCY: "50" + + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Setup pnpm + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6 + + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + with: + node-version-file: .nvmrc + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build eve package + # Full build, not build:js: the deployed/runtime bundles must carry the + # stamped package version (scripts/stamp-version-tokens.mjs) and docs. + run: pnpm --filter eve run build + + - name: Build extension fixtures + # Extension fixtures ship no committed `dist/`; produce it here so + # consuming fixtures resolve the built artifacts. `--if-present` skips + # extension fixtures without a build script. The update re-packs the + # `file:`-protocol store copies so they pick up the fresh dist. + run: | + pnpm --filter "./e2e/fixtures/*-extension" run --if-present build + pnpm --filter dist-extensions update gizmo-extension gadget-extension + + - name: Stage workspace extension fixtures as dist-only + # Removing author source proves the production build consumes the same + # agent-shaped dist trees registry packages ship. + run: | + mv e2e/fixtures/toolkit-extension/extension "$RUNNER_TEMP/toolkit-extension-source" + mv e2e/fixtures/js-only-extension/extension "$RUNNER_TEMP/js-only-extension-source" + + - name: Bootstrap Workflow Postgres schema + working-directory: ${{ matrix.fixture.dir }} + run: pnpm exec bootstrap + + - name: Build fixture, start production server, and run evals + env: + POSTGRES_CONTAINER_ID: ${{ job.services.postgres.id }} + run: | + set -euo pipefail + mkdir -p "$EVE_EVAL_JUNIT_DIR" + cd "${{ matrix.fixture.dir }}" + + pnpm exec eve build + + server_log="$EVE_EVAL_JUNIT_DIR/${{ matrix.fixture.name }}-${{ matrix.model.name }}-server.log" + pnpm exec eve start --host 127.0.0.1 --port 3000 >"$server_log" 2>&1 & + server_pid=$! + + cleanup() { + set +e + kill "$server_pid" 2>/dev/null + wait "$server_pid" 2>/dev/null + } + trap cleanup EXIT + + ready=false + for _ in {1..120}; do + if curl --fail --silent http://127.0.0.1:3000/eve/v1/health >/dev/null; then + ready=true + break + fi + if ! kill -0 "$server_pid" 2>/dev/null; then + cat "$server_log" + exit 1 + fi + sleep 0.5 + done + if [ "$ready" != "true" ]; then + cat "$server_log" + echo "Timed out waiting for the Postgres-backed eve server." + exit 1 + fi + + if ! pnpm exec eve eval --strict --verbose \ + --url http://127.0.0.1:3000 \ + --junit "$EVE_EVAL_JUNIT_DIR/${{ matrix.fixture.name }}-${{ matrix.model.name }}.xml"; then + cat "$server_log" + exit 1 + fi + + run_count="$( + docker exec "$POSTGRES_CONTAINER_ID" \ + psql --username=world --dbname=world --tuples-only --no-align \ + --command="SELECT count(*) FROM workflow.workflow_runs;" + )" + if ! [[ "$run_count" =~ ^[0-9]+$ ]] || [ "$run_count" -lt 1 ]; then + cat "$server_log" + echo "Expected Postgres-backed workflow runs, found: $run_count" + exit 1 + fi + echo "Verified $run_count workflow run(s) in PostgreSQL." + + - name: Upload eval artifacts + if: failure() + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v6 + with: + name: eval-artifacts-postgres-${{ matrix.fixture.name }}-${{ matrix.model.name }} + path: | + .junit + e2e/fixtures/*/.eve/evals + apps/fixtures/*/.eve/evals + include-hidden-files: true + if-no-files-found: ignore + retention-days: 7 + + e2e-required: + name: e2e-postgres + runs-on: ubuntu-latest + needs: [changes, e2e] + if: always() + steps: + - name: Require successful e2e matrix when relevant + env: + CHANGES_RESULT: ${{ needs.changes.result }} + E2E_RESULT: ${{ needs.e2e.result }} + RELEVANT: ${{ needs.changes.outputs.relevant }} + run: | + if [ "$CHANGES_RESULT" != "success" ]; then + echo "Change detection result: $CHANGES_RESULT" + exit 1 + fi + if [ "$RELEVANT" != "true" ]; then + echo "No Postgres e2e-relevant changes." + exit 0 + fi + if [ "$E2E_RESULT" != "success" ]; then + echo "E2E matrix result: $E2E_RESULT" + exit 1 + fi diff --git a/e2e/README.md b/e2e/README.md index ae3e85edb..977585d05 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -12,10 +12,12 @@ cd e2e/fixtures/agent-basic-runtime EVE_E2E_MODEL="openai/gpt-5.6-sol" pnpm exec eve eval --strict ``` -Every retained e2e eval is deterministic and self-contained. Coverage that -needs external services or injected env is intentionally not part of this -suite. Most fixtures use the shared model-provider credentials; dedicated -runtime stress fixtures may use an authored deterministic model instead. +Every retained e2e eval is deterministic and self-contained. Eval files do +not start external services or require fixture-specific injected env. The CI +harness may provide world-level infrastructure, such as the ephemeral +PostgreSQL service used by the Postgres matrix. Most fixtures use the shared +model-provider credentials; dedicated runtime stress fixtures may use an +authored deterministic model instead. Each retained fixture package also exposes the same command as: @@ -30,6 +32,40 @@ script: pnpm test:e2e ``` +## Postgres + +Postgres e2e runs the same fixture evals against a self-hosted production +server backed by `@workflow/world-postgres`. Each matrix leg owns an isolated +PostgreSQL service, bootstraps its schema, builds the fixture, starts it with +`eve start`, and targets that server with `eve eval --url`. + +Fixture root agents read `EVE_E2E_WORKFLOW_WORLD` into +`experimental.workflow.world`. The variable is unset in the local and Vercel +suites, preserving their host defaults; the Postgres workflow sets it to +`@workflow/world-postgres` while compiling the production server. The world +package is a direct fixture dependency pinned through the workspace catalog +to the same `@workflow/*` line as eve. + +The per-fixture lifecycle is: + +```sh +export EVE_E2E_WORKFLOW_WORLD="@workflow/world-postgres" +export WORKFLOW_POSTGRES_URL="postgres://world:world@127.0.0.1:5432/world" + +pnpm exec bootstrap +pnpm exec eve build +pnpm exec eve start --host 127.0.0.1 --port 3000 + +# In a second process: +pnpm exec eve eval --strict --url http://127.0.0.1:3000 +``` + +After the eval succeeds, CI requires at least one row in +`workflow.workflow_runs`. This proves the fixture used Postgres rather than +silently falling back to the local world. Dev-only schedule dispatch evals +skip against this production target, matching their Vercel behavior; the +local matrix retains that development-route coverage. + ## Vercel Vercel e2e uses the same fixture evals against immutable preview deployment @@ -107,6 +143,9 @@ When adding e2e coverage: - Keep it runnable with only `eve eval --strict`. - Keep it deterministic: no external service startup or injected env requirements (beyond model-provider credentials). +- Keep the root `agent.ts` selectable through `EVE_E2E_WORKFLOW_WORLD` and + declare `@workflow/world-postgres` as a direct dependency so fixture + discovery automatically adds it to the Postgres matrix. - If the behavior cannot fit that shape yet, leave it out and rebuild it later as a first-class eval story. @@ -121,10 +160,10 @@ with these model entries: The short name is the stable Actions check identifier; the full id selects the provider model. Updating a model version does not rename required checks. -Each workflow also publishes one stable aggregate check, `e2e-local` or -`e2e-vercel`, which succeeds only when every fixture and model leg succeeds. -Require those two checks in the repository ruleset so newly added fixtures and -models become required automatically. +Each workflow also publishes one stable aggregate check: `e2e-local`, +`e2e-postgres`, or `e2e-vercel`. Each aggregate succeeds only when every +fixture and model leg succeeds. Require all three checks in the repository +ruleset so newly added fixtures and models become required automatically. Each leg exports the selected id as `EVE_E2E_MODEL` before it runs: @@ -147,5 +186,19 @@ DEPLOYMENT_URL="$(vc deploy --prebuilt --yes --target=preview \ npx eve eval --strict --url "$DEPLOYMENT_URL" --junit "$JUNIT_PATH" ``` +`.github/workflows/e2e-postgres.yml` starts PostgreSQL as a job service and +runs a self-hosted production build: + +```sh +pnpm exec bootstrap +pnpm exec eve build +pnpm exec eve start --host 127.0.0.1 --port 3000 +pnpm exec eve eval --strict --url http://127.0.0.1:3000 --junit "$JUNIT_PATH" +``` + +The Postgres matrix skips at the job level on irrelevant changes so those PRs +do not start service containers. Its stable aggregate check still reports and +succeeds on every PR. + TUI smoke scripts are not e2e. They live under `packages/eve/test/tui-client` and run through `pnpm test:tui`. diff --git a/e2e/fixtures/agent-basic-runtime/agent/agent.ts b/e2e/fixtures/agent-basic-runtime/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/agent-basic-runtime/agent/agent.ts +++ b/e2e/fixtures/agent-basic-runtime/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-basic-runtime/package.json b/e2e/fixtures/agent-basic-runtime/package.json index a4ae9f403..261913a93 100644 --- a/e2e/fixtures/agent-basic-runtime/package.json +++ b/e2e/fixtures/agent-basic-runtime/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-cancellation/agent/agent.ts b/e2e/fixtures/agent-cancellation/agent/agent.ts index cc302c34c..b1b4987a3 100644 --- a/e2e/fixtures/agent-cancellation/agent/agent.ts +++ b/e2e/fixtures/agent-cancellation/agent/agent.ts @@ -1,5 +1,8 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", }); diff --git a/e2e/fixtures/agent-cancellation/package.json b/e2e/fixtures/agent-cancellation/package.json index a12b59d1f..d80350919 100644 --- a/e2e/fixtures/agent-cancellation/package.json +++ b/e2e/fixtures/agent-cancellation/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-channels/agent/agent.ts b/e2e/fixtures/agent-channels/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/agent-channels/agent/agent.ts +++ b/e2e/fixtures/agent-channels/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-channels/package.json b/e2e/fixtures/agent-channels/package.json index f8eddfeda..81d51aa49 100644 --- a/e2e/fixtures/agent-channels/package.json +++ b/e2e/fixtures/agent-channels/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "ai": "catalog:", "eve": "workspace:*", "zod": "catalog:" diff --git a/e2e/fixtures/agent-compaction-regressions/agent/agent.ts b/e2e/fixtures/agent-compaction-regressions/agent/agent.ts index 8835c5758..0e6a639b3 100644 --- a/e2e/fixtures/agent-compaction-regressions/agent/agent.ts +++ b/e2e/fixtures/agent-compaction-regressions/agent/agent.ts @@ -13,6 +13,7 @@ import { TASK_TAIL_SENTINEL, } from "../constants"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; const TEST_CONTEXT_WINDOW_TOKENS = 32_000; const MAX_TOOL_CALLS = 10; @@ -223,6 +224,7 @@ const taskModel = mockModel({ }); export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: taskModel, modelContextWindowTokens: TEST_CONTEXT_WINDOW_TOKENS, compaction: { diff --git a/e2e/fixtures/agent-compaction-regressions/package.json b/e2e/fixtures/agent-compaction-regressions/package.json index d7b7410c0..86e47c9de 100644 --- a/e2e/fixtures/agent-compaction-regressions/package.json +++ b/e2e/fixtures/agent-compaction-regressions/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-model/agent/agent.ts b/e2e/fixtures/agent-model/agent/agent.ts index e41aed518..68dd5011d 100644 --- a/e2e/fixtures/agent-model/agent/agent.ts +++ b/e2e/fixtures/agent-model/agent/agent.ts @@ -1,6 +1,7 @@ import { defineAgent, defineDynamic, type DynamicResolveContext } from "eve"; const model = process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; /** * Dynamic-model e2e fixture. Resolves at `turn.started` (not the usual @@ -8,6 +9,7 @@ const model = process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol"; * and resolver-failure degradation. */ export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: defineDynamic({ fallback: model, events: { diff --git a/e2e/fixtures/agent-model/package.json b/e2e/fixtures/agent-model/package.json index 91c7b0edf..57534dd41 100644 --- a/e2e/fixtures/agent-model/package.json +++ b/e2e/fixtures/agent-model/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@workflow/world-postgres": "catalog:", "eve": "workspace:*" }, "devDependencies": { diff --git a/e2e/fixtures/agent-openapi-swagger/agent/agent.ts b/e2e/fixtures/agent-openapi-swagger/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/agent-openapi-swagger/agent/agent.ts +++ b/e2e/fixtures/agent-openapi-swagger/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-openapi-swagger/package.json b/e2e/fixtures/agent-openapi-swagger/package.json index e0fc08001..5ef7f6abb 100644 --- a/e2e/fixtures/agent-openapi-swagger/package.json +++ b/e2e/fixtures/agent-openapi-swagger/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-prompt-cache/agent/agent.ts b/e2e/fixtures/agent-prompt-cache/agent/agent.ts index 843fdf3cf..d5ccb4f79 100644 --- a/e2e/fixtures/agent-prompt-cache/agent/agent.ts +++ b/e2e/fixtures/agent-prompt-cache/agent/agent.ts @@ -2,6 +2,8 @@ import { createAnthropic } from "@ai-sdk/anthropic"; import { type AgentDefinition, defineAgent } from "eve"; import { vercelOidc } from "eve/agents/auth"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + /** * Prompt-cache e2e fixture. * @@ -43,6 +45,7 @@ const anthropic = createAnthropic({ }); const agent: AgentDefinition = defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: anthropic(promptCacheModel), modelContextWindowTokens: 200_000, }); diff --git a/e2e/fixtures/agent-prompt-cache/package.json b/e2e/fixtures/agent-prompt-cache/package.json index bd33a72fa..3375c11e4 100644 --- a/e2e/fixtures/agent-prompt-cache/package.json +++ b/e2e/fixtures/agent-prompt-cache/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@ai-sdk/anthropic": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-schedules/agent/agent.ts b/e2e/fixtures/agent-schedules/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/agent-schedules/agent/agent.ts +++ b/e2e/fixtures/agent-schedules/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-schedules/package.json b/e2e/fixtures/agent-schedules/package.json index d663ae712..59cf5d534 100644 --- a/e2e/fixtures/agent-schedules/package.json +++ b/e2e/fixtures/agent-schedules/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-session-limits/agent/agent.ts b/e2e/fixtures/agent-session-limits/agent/agent.ts index 444d86c29..3ab7ce4f3 100644 --- a/e2e/fixtures/agent-session-limits/agent/agent.ts +++ b/e2e/fixtures/agent-session-limits/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", // A one-token input budget guarantees every completed model call crosses // the limit, so the next conversation turn deterministically parks on the diff --git a/e2e/fixtures/agent-session-limits/package.json b/e2e/fixtures/agent-session-limits/package.json index 0ad51e2e9..eb0d9ad9c 100644 --- a/e2e/fixtures/agent-session-limits/package.json +++ b/e2e/fixtures/agent-session-limits/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-skills/agent/agent.ts b/e2e/fixtures/agent-skills/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/agent-skills/agent/agent.ts +++ b/e2e/fixtures/agent-skills/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-skills/package.json b/e2e/fixtures/agent-skills/package.json index b561d5b81..334a1711a 100644 --- a/e2e/fixtures/agent-skills/package.json +++ b/e2e/fixtures/agent-skills/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-subagents-hitl/agent/agent.ts b/e2e/fixtures/agent-subagents-hitl/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/agent-subagents-hitl/agent/agent.ts +++ b/e2e/fixtures/agent-subagents-hitl/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-subagents-hitl/package.json b/e2e/fixtures/agent-subagents-hitl/package.json index d654ceb16..789e7d50f 100644 --- a/e2e/fixtures/agent-subagents-hitl/package.json +++ b/e2e/fixtures/agent-subagents-hitl/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-subagents/agent/agent.ts b/e2e/fixtures/agent-subagents/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/agent-subagents/agent/agent.ts +++ b/e2e/fixtures/agent-subagents/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-subagents/package.json b/e2e/fixtures/agent-subagents/package.json index 1424d6b5c..36bba8c17 100644 --- a/e2e/fixtures/agent-subagents/package.json +++ b/e2e/fixtures/agent-subagents/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts b/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts index 006ed0c4d..4af93d626 100644 --- a/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts +++ b/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts @@ -1,5 +1,7 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + /** * HITL fixture whose OpenAI matrix leg covers the Responses provider path * (https://github.com/vercel/eve/issues/236). Approval-gated executable @@ -7,5 +9,6 @@ import { defineAgent } from "eve"; * validated by OpenAI's `function_call` / `function_call_output` pairing. */ export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", }); diff --git a/e2e/fixtures/agent-tools-hitl-openai/package.json b/e2e/fixtures/agent-tools-hitl-openai/package.json index 9d0ece5a1..091d3ad65 100644 --- a/e2e/fixtures/agent-tools-hitl-openai/package.json +++ b/e2e/fixtures/agent-tools-hitl-openai/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-tools-hitl/agent/agent.ts b/e2e/fixtures/agent-tools-hitl/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/agent-tools-hitl/agent/agent.ts +++ b/e2e/fixtures/agent-tools-hitl/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools-hitl/package.json b/e2e/fixtures/agent-tools-hitl/package.json index 20fc21652..3edcdb469 100644 --- a/e2e/fixtures/agent-tools-hitl/package.json +++ b/e2e/fixtures/agent-tools-hitl/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-tools-sandbox/agent/agent.ts b/e2e/fixtures/agent-tools-sandbox/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/agent-tools-sandbox/agent/agent.ts +++ b/e2e/fixtures/agent-tools-sandbox/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools-sandbox/package.json b/e2e/fixtures/agent-tools-sandbox/package.json index ddbc45eda..3774c135c 100644 --- a/e2e/fixtures/agent-tools-sandbox/package.json +++ b/e2e/fixtures/agent-tools-sandbox/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-tools/agent/agent.ts b/e2e/fixtures/agent-tools/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/agent-tools/agent/agent.ts +++ b/e2e/fixtures/agent-tools/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools/package.json b/e2e/fixtures/agent-tools/package.json index 339edee71..68aaff61b 100644 --- a/e2e/fixtures/agent-tools/package.json +++ b/e2e/fixtures/agent-tools/package.json @@ -15,6 +15,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-workflow-stress/agent/agent.ts b/e2e/fixtures/agent-workflow-stress/agent/agent.ts index aee410f61..718767c6d 100644 --- a/e2e/fixtures/agent-workflow-stress/agent/agent.ts +++ b/e2e/fixtures/agent-workflow-stress/agent/agent.ts @@ -1,7 +1,10 @@ import { defineAgent } from "eve"; import { mockModel } from "eve/evals"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: mockModel( ({ lastUserMessage, userMessageCount }) => `stress-ack:${userMessageCount}:${lastUserMessage ?? ""}`, diff --git a/e2e/fixtures/agent-workflow-stress/package.json b/e2e/fixtures/agent-workflow-stress/package.json index 6f795ef69..dc0070582 100644 --- a/e2e/fixtures/agent-workflow-stress/package.json +++ b/e2e/fixtures/agent-workflow-stress/package.json @@ -14,6 +14,7 @@ "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "ai": "catalog:", "eve": "workspace:*" }, diff --git a/e2e/fixtures/dist-extensions/agent/agent.ts b/e2e/fixtures/dist-extensions/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/dist-extensions/agent/agent.ts +++ b/e2e/fixtures/dist-extensions/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/dist-extensions/package.json b/e2e/fixtures/dist-extensions/package.json index bfc477429..cf7ba9332 100644 --- a/e2e/fixtures/dist-extensions/package.json +++ b/e2e/fixtures/dist-extensions/package.json @@ -10,6 +10,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "gadget-extension": "file:../gadget-extension", "gizmo-extension": "file:../gizmo-extension" diff --git a/e2e/fixtures/extensions/agent/agent.ts b/e2e/fixtures/extensions/agent/agent.ts index 93907447f..413f92fcb 100644 --- a/e2e/fixtures/extensions/agent/agent.ts +++ b/e2e/fixtures/extensions/agent/agent.ts @@ -1,6 +1,9 @@ import { defineAgent } from "eve"; +const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + export default defineAgent({ + experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/extensions/package.json b/e2e/fixtures/extensions/package.json index efc5834e7..f8e8be6fa 100644 --- a/e2e/fixtures/extensions/package.json +++ b/e2e/fixtures/extensions/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "gizmo-extension": "workspace:*", "js-only-extension": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index da0a62e02..408220e68 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,6 +51,9 @@ catalogs: '@vercel/sandbox': specifier: 2.8.0 version: 2.8.0 + '@workflow/world-postgres': + specifier: 5.0.0-beta.29 + version: 5.0.0-beta.29 ai: specifier: ^7.0.38 version: 7.0.38 @@ -142,7 +145,7 @@ importers: version: 1.1.1(react@19.2.6) '@vercel/analytics': specifier: 2.0.1 - version: 2.0.1(2e1d1ea39f306c545b71c35841ac134e) + version: 2.0.1(@sveltejs/kit@2.61.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.56.1(@typescript-eslint/types@8.59.4))(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.59.4))(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)))(next@16.3.0-preview.6(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(nuxt@4.4.6(41ce06a5c11c989752f5b4fadc9496f0))(react@19.2.6)(svelte@5.56.1(@typescript-eslint/types@8.59.4))(vue@3.5.35(typescript@6.0.3)) '@vercel/eve-catalog': specifier: workspace:* version: link:../../packages/eve-catalog @@ -151,7 +154,7 @@ importers: version: 1.15.2(@svta/cml-cta@1.0.1(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1))(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1)(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@10.2.2))(next@16.3.0-preview.6(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@10.2.2)(tailwindcss@4.3.0)(unified@11.0.5)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) '@vercel/speed-insights': specifier: 2.0.0 - version: 2.0.0(2e1d1ea39f306c545b71c35841ac134e) + version: 2.0.0(@sveltejs/kit@2.61.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.56.1(@typescript-eslint/types@8.59.4))(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.59.4))(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)))(next@16.3.0-preview.6(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(nuxt@4.4.6(41ce06a5c11c989752f5b4fadc9496f0))(react@19.2.6)(svelte@5.56.1(@typescript-eslint/types@8.59.4))(vue@3.5.35(typescript@6.0.3)) '@vgpu/core': specifier: 0.0.7 version: 0.0.7 @@ -293,7 +296,7 @@ importers: version: 0.2.4(ai@7.0.38(zod@4.4.3))(chat@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3) '@vercel/connect': specifier: 'catalog:' - version: 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) + version: 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.1)) @@ -381,7 +384,7 @@ importers: version: 0.41.2 '@vercel/connect': specifier: 'catalog:' - version: 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) + version: 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) '@vercel/oidc': specifier: 3.8.0 version: 3.8.0 @@ -473,7 +476,7 @@ importers: version: link:../../../packages/eve nuxt: specifier: ^4.0.0 - version: 4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@25.9.1)(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(@vue/compiler-sfc@3.5.39)(aws4fetch@1.0.20)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue-tsc@3.3.6(typescript@6.0.3))(yaml@2.9.0) + version: 4.4.6(f32df07d5233da3a29c17b72e1467465) vue: specifier: ^3.5.0 version: 3.5.35(typescript@6.0.3) @@ -530,6 +533,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -555,6 +561,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -580,6 +589,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) ai: specifier: 'catalog:' version: 7.0.38(zod@4.4.3) @@ -608,6 +620,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -624,6 +639,9 @@ importers: e2e/fixtures/agent-model: dependencies: + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -646,6 +664,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -665,6 +686,9 @@ importers: '@ai-sdk/anthropic': specifier: 'catalog:' version: 4.0.18(zod@4.4.3) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -690,6 +714,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -715,6 +742,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -765,6 +795,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -790,6 +823,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -806,6 +842,9 @@ importers: e2e/fixtures/agent-subagents-hitl: dependencies: + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -834,6 +873,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -859,6 +901,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -884,6 +929,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -909,6 +957,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -934,6 +985,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) ai: specifier: 'catalog:' version: 7.0.38(zod@4.4.3) @@ -950,6 +1004,9 @@ importers: e2e/fixtures/dist-extensions: dependencies: + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -969,6 +1026,9 @@ importers: e2e/fixtures/extensions: dependencies: + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) eve: specifier: workspace:* version: link:../../../packages/eve @@ -1069,7 +1129,7 @@ importers: version: 3.24.0(@aws-sdk/credential-provider-web-identity@3.972.49)(supports-color@10.2.2)(zod@4.4.3) nitro: specifier: 3.0.260610-beta - version: 3.0.260610-beta(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(chokidar@5.0.0)(dotenv@17.4.2)(giget@3.3.0)(ioredis@5.11.1(supports-color@10.2.2))(jiti@2.7.0)(lru-cache@11.5.2)(rollup@4.62.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) + version: 3.0.260610-beta(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(chokidar@5.0.0)(dotenv@17.4.2)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1))(giget@3.3.0)(ioredis@5.11.1(supports-color@10.2.2))(jiti@2.7.0)(lru-cache@11.5.2)(rollup@4.62.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) undici: specifier: 8.9.0 version: 8.9.0 @@ -2738,6 +2798,9 @@ packages: resolution: {integrity: sha512-9tU0h6O/Ao9k53TQSgLs6D/mN++wKTHPIpT8tbPaayhOL3e4OhtJ3t+OD42avMe2pBmFcdRUVOSpZvqytxvWEg==} engines: {node: '>=12.0.0'} + '@graphile/logger@0.2.0': + resolution: {integrity: sha512-jjcWBokl9eb1gVJ85QmoaQ73CQ52xAaOCF29ukRbYNl6lY+ts0ErTaDYOBlejcbUs2OpaiqYLO5uDhyLFzWw4w==} + '@grpc/grpc-js@1.14.4': resolution: {integrity: sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ==} engines: {node: '>=12.10.0'} @@ -6434,6 +6497,9 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/interpret@1.1.4': + resolution: {integrity: sha512-r+tPKWHYqaxJOYA3Eik0mMi+SEREqOXLmsooRFmc6GHv7nWUDixFtKN+cegvsPlDcEZd9wxsdp041v2imQuvag==} + '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -6473,9 +6539,15 @@ packages: '@types/node@20.11.0': resolution: {integrity: sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==} + '@types/node@22.20.1': + resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} + '@types/node@25.9.1': resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==} + '@types/pg@8.20.0': + resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} + '@types/pngjs@6.0.5': resolution: {integrity: sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ==} @@ -6496,6 +6568,9 @@ packages: '@types/retry@0.12.0': resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + '@types/semver@7.7.1': + resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -7313,6 +7388,10 @@ packages: '@opentelemetry/api': optional: true + '@workflow/world-postgres@5.0.0-beta.29': + resolution: {integrity: sha512-OaqDbvtM1mfsQtzOndyepyPARYXkWWZc53wcV3U3l65K8rMFjwX3TG+721wpEnIvWiFBVD3MJ8HjgnIIQG/1Hw==} + hasBin: true + '@workflow/world-vercel@5.0.0-beta.33': resolution: {integrity: sha512-6MWaWw85145AInDBYql33XPETAjrOvu40wJYje/JwJwkFtOrGSx2B2vjbNxscafsN9TIZYUCRdK53spcqsMNzg==} peerDependencies: @@ -8245,6 +8324,15 @@ packages: cose-base@2.2.0: resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + cosmiconfig@9.0.2: resolution: {integrity: sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==} engines: {node: '>=14'} @@ -8749,10 +8837,106 @@ packages: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} + dotenv@17.3.1: + resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + engines: {node: '>=12'} + dotenv@17.4.2: resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} + drizzle-orm@0.45.2: + resolution: {integrity: sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==} + peerDependencies: + '@aws-sdk/client-rds-data': '>=3' + '@cloudflare/workers-types': '>=4' + '@electric-sql/pglite': '>=0.2.0' + '@libsql/client': '>=0.10.0' + '@libsql/client-wasm': '>=0.10.0' + '@neondatabase/serverless': '>=0.10.0' + '@op-engineering/op-sqlite': '>=2' + '@opentelemetry/api': ^1.4.1 + '@planetscale/database': '>=1.13' + '@prisma/client': '*' + '@tidbcloud/serverless': '*' + '@types/better-sqlite3': '*' + '@types/pg': '*' + '@types/sql.js': '*' + '@upstash/redis': '>=1.34.7' + '@vercel/postgres': '>=0.8.0' + '@xata.io/client': '*' + better-sqlite3: '>=7' + bun-types: '*' + expo-sqlite: '>=14.0.0' + gel: '>=2' + knex: '*' + kysely: '*' + mysql2: '>=2' + pg: '>=8' + postgres: '>=3' + prisma: '*' + sql.js: '>=1' + sqlite3: '>=5' + peerDependenciesMeta: + '@aws-sdk/client-rds-data': + optional: true + '@cloudflare/workers-types': + optional: true + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + '@libsql/client-wasm': + optional: true + '@neondatabase/serverless': + optional: true + '@op-engineering/op-sqlite': + optional: true + '@opentelemetry/api': + optional: true + '@planetscale/database': + optional: true + '@prisma/client': + optional: true + '@tidbcloud/serverless': + optional: true + '@types/better-sqlite3': + optional: true + '@types/pg': + optional: true + '@types/sql.js': + optional: true + '@upstash/redis': + optional: true + '@vercel/postgres': + optional: true + '@xata.io/client': + optional: true + better-sqlite3: + optional: true + bun-types: + optional: true + expo-sqlite: + optional: true + gel: + optional: true + knex: + optional: true + kysely: + optional: true + mysql2: + optional: true + pg: + optional: true + postgres: + optional: true + prisma: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -9790,6 +9974,15 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graphile-config@0.0.1-beta.18: + resolution: {integrity: sha512-uMdF9Rt8/NwT1wVXNleYgM5ro2hHDodHiKA3efJhgdU8iP+r/hksnghOHreMva0sF5tV73f4TpiELPUR0g7O9w==} + engines: {node: '>=16'} + + graphile-worker@0.16.6: + resolution: {integrity: sha512-e7gGYDmGqzju2l83MpzX8vNG/lOtVJiSzI3eZpAFubSxh/cxs7sRrRGBGjzBP1kNG0H+c95etPpNRNlH65PYhw==} + engines: {node: '>=14.0.0'} + hasBin: true + gray-matter@4.0.3: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} @@ -10113,6 +10306,10 @@ packages: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} + interpret@3.1.1: + resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} + engines: {node: '>=10.13.0'} + invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} @@ -11999,6 +12196,40 @@ packages: perfect-debounce@2.1.0: resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + pg-cloudflare@1.4.0: + resolution: {integrity: sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==} + + pg-connection-string@2.14.0: + resolution: {integrity: sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.14.0: + resolution: {integrity: sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.15.0: + resolution: {integrity: sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.20.0: + resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + phase@0.0.1: resolution: {integrity: sha512-QTeTClFj700SPwdgfVckQ8uO/dquPO5MdxHpSLCOtKpJbLrpUrFnEVhoCuQKXMSWXNIMlnwPsKQ7fqfXCX6BJg==} engines: {node: 24.x} @@ -12266,6 +12497,22 @@ packages: resolution: {integrity: sha512-lW616l85ucIQL+FocMmL7pQFPqBmwejrCMg+iPxyImlrANNJG9NHq/RkyCZopDhd8C3LA03PHRJDjkbGu8vvug==} engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + powershell-utils@0.1.0: resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} engines: {node: '>=20'} @@ -13716,6 +13963,9 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} @@ -14513,6 +14763,10 @@ packages: resolution: {integrity: sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==} engines: {node: '>=16.0.0'} + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -16074,7 +16328,7 @@ snapshots: eve: link:packages/eve zod: 4.4.3 optionalDependencies: - '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) + '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) transitivePeerDependencies: - '@ai-sdk/workflow' - '@workflow/ai' @@ -16087,7 +16341,7 @@ snapshots: octokit: 5.0.5 zod: 4.4.3 optionalDependencies: - '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) + '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) eve: link:packages/eve '@google/genai@1.52.0(@modelcontextprotocol/sdk@1.29.0(supports-color@10.2.2)(zod@4.4.3))(bufferutil@4.1.0)(supports-color@10.2.2)': @@ -16115,6 +16369,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@graphile/logger@0.2.0': {} + '@grpc/grpc-js@1.14.4': dependencies: '@grpc/proto-loader': 0.8.1 @@ -16931,7 +17187,7 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/nitro-server@4.4.6(5af45ff6ce88146737a84f10936700d8)': + '@nuxt/nitro-server@4.4.6(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1))(esbuild@0.28.1)(ioredis@5.11.1(supports-color@10.2.2))(magicast@0.5.3)(nuxt@4.4.6(41ce06a5c11c989752f5b4fadc9496f0))(oxc-parser@0.131.0)(rolldown@1.1.5)(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@nuxt/devalue': 2.0.2 '@nuxt/kit': 4.4.6(magicast@0.5.3) @@ -16948,8 +17204,8 @@ snapshots: impound: 1.1.5(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.62.2)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) klona: 2.0.6 mocked-exports: 0.1.1 - nitropack: 2.13.4(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(oxc-parser@0.131.0)(rolldown@1.1.5)(srvx@0.11.22)(supports-color@10.2.2)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) - nuxt: 4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@25.9.1)(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(@vue/compiler-sfc@3.5.39)(aws4fetch@1.0.20)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue-tsc@3.3.6(typescript@6.0.3))(yaml@2.9.0) + nitropack: 2.13.4(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1))(oxc-parser@0.131.0)(rolldown@1.1.5)(srvx@0.11.22)(supports-color@10.2.2)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) + nuxt: 4.4.6(41ce06a5c11c989752f5b4fadc9496f0) nypm: 0.6.8 ohash: 2.0.11 pathe: 2.0.3 @@ -16957,7 +17213,7 @@ snapshots: std-env: 4.2.0 ufo: 1.6.4 unctx: 2.5.0 - unstorage: 1.17.5(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4)(ioredis@5.11.1(supports-color@10.2.2)) + unstorage: 1.17.5(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(ioredis@5.11.1(supports-color@10.2.2)) vue: 3.5.35(typescript@6.0.3) vue-bundle-renderer: 2.3.1 vue-devtools-stub: 0.1.0 @@ -17010,7 +17266,7 @@ snapshots: - xml2js optional: true - '@nuxt/nitro-server@4.4.6(d7661b23bdde68362333e80e2569dc53)': + '@nuxt/nitro-server@4.4.6(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1))(esbuild@0.28.1)(ioredis@5.11.1(supports-color@10.2.2))(magicast@0.5.3)(nuxt@4.4.6(f32df07d5233da3a29c17b72e1467465))(oxc-parser@0.131.0)(rolldown@1.1.5)(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(typescript@6.0.3)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@nuxt/devalue': 2.0.2 '@nuxt/kit': 4.4.6(magicast@0.5.3) @@ -17027,8 +17283,8 @@ snapshots: impound: 1.1.5(esbuild@0.28.1)(rolldown@1.1.5)(rollup@4.62.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) klona: 2.0.6 mocked-exports: 0.1.1 - nitropack: 2.13.4(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(oxc-parser@0.131.0)(rolldown@1.1.5)(srvx@0.11.22)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) - nuxt: 4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@25.9.1)(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(@vue/compiler-sfc@3.5.39)(aws4fetch@1.0.20)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue-tsc@3.3.6(typescript@6.0.3))(yaml@2.9.0) + nitropack: 2.13.4(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1))(oxc-parser@0.131.0)(rolldown@1.1.5)(srvx@0.11.22)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) + nuxt: 4.4.6(f32df07d5233da3a29c17b72e1467465) nypm: 0.6.8 ohash: 2.0.11 pathe: 2.0.3 @@ -17036,7 +17292,7 @@ snapshots: std-env: 4.2.0 ufo: 1.6.4 unctx: 2.5.0 - unstorage: 1.17.5(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4)(ioredis@5.11.1(supports-color@10.2.2)) + unstorage: 1.17.5(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(ioredis@5.11.1(supports-color@10.2.2)) vue: 3.5.35(typescript@6.0.3) vue-bundle-renderer: 2.3.1 vue-devtools-stub: 0.1.0 @@ -17105,7 +17361,7 @@ snapshots: rc9: 3.0.1 std-env: 4.2.0 - '@nuxt/vite-builder@4.4.6(65326fc791d4735547fd3a6298d65608)': + '@nuxt/vite-builder@4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@types/node@25.9.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(nuxt@4.4.6(41ce06a5c11c989752f5b4fadc9496f0))(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vue-tsc@3.3.6(typescript@6.0.3))(vue@3.5.35(typescript@6.0.3))(yaml@2.9.0)': dependencies: '@nuxt/kit': 4.4.6(magicast@0.5.3) '@rollup/plugin-replace': 6.0.3(rollup@4.62.2) @@ -17123,7 +17379,7 @@ snapshots: magic-string: 0.30.21 mlly: 1.8.2 mocked-exports: 0.1.1 - nuxt: 4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@25.9.1)(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(@vue/compiler-sfc@3.5.39)(aws4fetch@1.0.20)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue-tsc@3.3.6(typescript@6.0.3))(yaml@2.9.0) + nuxt: 4.4.6(41ce06a5c11c989752f5b4fadc9496f0) nypm: 0.6.8 pathe: 2.0.3 pkg-types: 2.3.1 @@ -17165,8 +17421,9 @@ snapshots: - vti - vue-tsc - yaml + optional: true - '@nuxt/vite-builder@4.4.6(bd1799bb420f4f18d539b3aab18f78ee)': + '@nuxt/vite-builder@4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@types/node@25.9.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(nuxt@4.4.6(f32df07d5233da3a29c17b72e1467465))(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vue-tsc@3.3.6(typescript@6.0.3))(vue@3.5.35(typescript@6.0.3))(yaml@2.9.0)': dependencies: '@nuxt/kit': 4.4.6(magicast@0.5.3) '@rollup/plugin-replace': 6.0.3(rollup@4.62.2) @@ -17184,7 +17441,7 @@ snapshots: magic-string: 0.30.21 mlly: 1.8.2 mocked-exports: 0.1.1 - nuxt: 4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@25.9.1)(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(@vue/compiler-sfc@3.5.39)(aws4fetch@1.0.20)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue-tsc@3.3.6(typescript@6.0.3))(yaml@2.9.0) + nuxt: 4.4.6(f32df07d5233da3a29c17b72e1467465) nypm: 0.6.8 pathe: 2.0.3 pkg-types: 2.3.1 @@ -17226,7 +17483,6 @@ snapshots: - vti - vue-tsc - yaml - optional: true '@octokit/app@16.1.2': dependencies: @@ -17378,7 +17634,7 @@ snapshots: '@onkernel/eve-extension@0.1.3(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve)': dependencies: - '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) + '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) eve: link:packages/eve zod: 4.4.3 transitivePeerDependencies: @@ -19923,6 +20179,10 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/interpret@1.1.4': + dependencies: + '@types/node': 25.9.1 + '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': @@ -19962,10 +20222,20 @@ snapshots: dependencies: undici-types: 5.26.5 + '@types/node@22.20.1': + dependencies: + undici-types: 6.21.0 + '@types/node@25.9.1': dependencies: undici-types: 7.24.6 + '@types/pg@8.20.0': + dependencies: + '@types/node': 25.9.1 + pg-protocol: 1.15.0 + pg-types: 2.2.0 + '@types/pngjs@6.0.5': dependencies: '@types/node': 25.9.1 @@ -19986,6 +20256,8 @@ snapshots: '@types/retry@0.12.0': {} + '@types/semver@7.7.1': {} + '@types/trusted-types@2.0.7': {} '@types/unist@2.0.11': {} @@ -20282,11 +20554,11 @@ snapshots: optionalDependencies: next: 16.3.0-preview.6(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@vercel/analytics@2.0.1(2e1d1ea39f306c545b71c35841ac134e)': + '@vercel/analytics@2.0.1(@sveltejs/kit@2.61.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.56.1(@typescript-eslint/types@8.59.4))(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.59.4))(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)))(next@16.3.0-preview.6(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(nuxt@4.4.6(41ce06a5c11c989752f5b4fadc9496f0))(react@19.2.6)(svelte@5.56.1(@typescript-eslint/types@8.59.4))(vue@3.5.35(typescript@6.0.3))': optionalDependencies: '@sveltejs/kit': 2.61.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.56.1(@typescript-eslint/types@8.59.4))(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.59.4))(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) next: 16.3.0-preview.6(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - nuxt: 4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@25.9.1)(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(@vue/compiler-sfc@3.5.39)(aws4fetch@1.0.20)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue-tsc@3.3.6(typescript@6.0.3))(yaml@2.9.0) + nuxt: 4.4.6(41ce06a5c11c989752f5b4fadc9496f0) react: 19.2.6 svelte: 5.56.1(@typescript-eslint/types@8.59.4) vue: 3.5.35(typescript@6.0.3) @@ -20353,7 +20625,7 @@ snapshots: dependencies: execa: 5.1.1 - '@vercel/connect@0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve)': + '@vercel/connect@0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve)': dependencies: '@vercel/oidc': 3.8.0 optionalDependencies: @@ -20755,11 +21027,11 @@ snapshots: dependencies: zod: 4.4.3 - '@vercel/speed-insights@2.0.0(2e1d1ea39f306c545b71c35841ac134e)': + '@vercel/speed-insights@2.0.0(@sveltejs/kit@2.61.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.56.1(@typescript-eslint/types@8.59.4))(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.59.4))(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)))(next@16.3.0-preview.6(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(nuxt@4.4.6(41ce06a5c11c989752f5b4fadc9496f0))(react@19.2.6)(svelte@5.56.1(@typescript-eslint/types@8.59.4))(vue@3.5.35(typescript@6.0.3))': optionalDependencies: '@sveltejs/kit': 2.61.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.56.1(@typescript-eslint/types@8.59.4))(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.59.4))(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) next: 16.3.0-preview.6(@babel/core@7.29.0(supports-color@10.2.2))(@opentelemetry/api@1.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - nuxt: 4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@25.9.1)(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(@vue/compiler-sfc@3.5.39)(aws4fetch@1.0.20)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue-tsc@3.3.6(typescript@6.0.3))(yaml@2.9.0) + nuxt: 4.4.6(41ce06a5c11c989752f5b4fadc9496f0) react: 19.2.6 svelte: 5.56.1(@typescript-eslint/types@8.59.4) vue: 3.5.35(typescript@6.0.3) @@ -21090,6 +21362,53 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.1 + '@workflow/world-postgres@5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2)': + dependencies: + '@vercel/queue': 0.4.0(@opentelemetry/api@1.9.1) + '@workflow/errors': 5.0.0-beta.13 + '@workflow/utils': 5.0.0-beta.7 + '@workflow/world': 5.0.0-beta.23 + '@workflow/world-local': 5.0.0-beta.31(@opentelemetry/api@1.9.1) + cbor-x: 1.6.0 + dotenv: 17.3.1 + drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1) + graphile-worker: 0.16.6(supports-color@10.2.2)(typescript@7.0.2) + pg: 8.20.0 + ulid: 3.0.2 + zod: 4.3.6 + transitivePeerDependencies: + - '@aws-sdk/client-rds-data' + - '@cloudflare/workers-types' + - '@electric-sql/pglite' + - '@libsql/client' + - '@libsql/client-wasm' + - '@neondatabase/serverless' + - '@op-engineering/op-sqlite' + - '@opentelemetry/api' + - '@planetscale/database' + - '@prisma/client' + - '@tidbcloud/serverless' + - '@types/better-sqlite3' + - '@types/pg' + - '@types/sql.js' + - '@upstash/redis' + - '@vercel/postgres' + - '@xata.io/client' + - better-sqlite3 + - bun-types + - expo-sqlite + - gel + - knex + - kysely + - mysql2 + - pg-native + - postgres + - prisma + - sql.js + - sqlite3 + - supports-color + - typescript + '@workflow/world-vercel@5.0.0-beta.33(@opentelemetry/api@1.9.1)': dependencies: '@vercel/oidc': 3.2.0 @@ -22118,6 +22437,15 @@ snapshots: dependencies: layout-base: 2.0.1 + cosmiconfig@8.3.6(typescript@7.0.2): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 7.0.2 + cosmiconfig@9.0.2(typescript@6.0.3): dependencies: env-paths: 2.2.1 @@ -22468,7 +22796,9 @@ snapshots: dayjs@1.11.20: {} - db0@0.3.4: {} + db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)): + optionalDependencies: + drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1) dc-browser@1.0.4: {} @@ -22636,8 +22966,18 @@ snapshots: dotenv@16.6.1: {} + dotenv@17.3.1: {} + dotenv@17.4.2: {} + drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1): + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@types/pg': 8.20.0 + '@upstash/redis': 1.38.0 + pg: 8.20.0 + sql.js: 1.14.1 + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -24072,6 +24412,36 @@ snapshots: graceful-fs@4.2.11: {} + graphile-config@0.0.1-beta.18(supports-color@10.2.2): + dependencies: + '@types/interpret': 1.1.4 + '@types/node': 22.20.1 + '@types/semver': 7.7.1 + chalk: 4.1.2 + debug: 4.4.3(supports-color@10.2.2) + interpret: 3.1.1 + semver: 7.8.4 + tslib: 2.8.1 + yargs: 17.7.3 + transitivePeerDependencies: + - supports-color + + graphile-worker@0.16.6(supports-color@10.2.2)(typescript@7.0.2): + dependencies: + '@graphile/logger': 0.2.0 + '@types/debug': 4.1.13 + '@types/pg': 8.20.0 + cosmiconfig: 8.3.6(typescript@7.0.2) + graphile-config: 0.0.1-beta.18(supports-color@10.2.2) + json5: 2.2.3 + pg: 8.20.0 + tslib: 2.8.1 + yargs: 17.7.3 + transitivePeerDependencies: + - pg-native + - supports-color + - typescript + gray-matter@4.0.3: dependencies: js-yaml: 3.14.2 @@ -24547,6 +24917,8 @@ snapshots: internmap@2.0.3: {} + interpret@3.1.1: {} + invariant@2.2.4: dependencies: loose-envify: 1.4.0 @@ -26194,11 +26566,11 @@ snapshots: abort-controller-x: 0.5.0 nice-grpc-common: 2.0.3 - nitro@3.0.260610-beta(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(chokidar@5.0.0)(dotenv@17.4.2)(giget@3.3.0)(ioredis@5.11.1(supports-color@10.2.2))(jiti@2.7.0)(lru-cache@11.5.2)(rollup@4.62.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)): + nitro@3.0.260610-beta(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(chokidar@5.0.0)(dotenv@17.4.2)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1))(giget@3.3.0)(ioredis@5.11.1(supports-color@10.2.2))(jiti@2.7.0)(lru-cache@11.5.2)(rollup@4.62.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)): dependencies: consola: 3.4.2 crossws: 0.4.10(srvx@0.11.22) - db0: 0.3.4 + db0: 0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)) env-runner: 0.1.16 h3: 2.0.1-rc.22(crossws@0.4.10(srvx@0.11.22)) hookable: 6.1.1 @@ -26209,7 +26581,7 @@ snapshots: rolldown: 1.1.5 srvx: 0.11.22 unenv: 2.0.0-rc.24 - unstorage: 2.0.0-alpha.7(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(chokidar@5.0.0)(db0@0.3.4)(ioredis@5.11.1(supports-color@10.2.2))(lru-cache@11.5.2)(ofetch@2.0.0-alpha.3) + unstorage: 2.0.0-alpha.7(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(chokidar@5.0.0)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(ioredis@5.11.1(supports-color@10.2.2))(lru-cache@11.5.2)(ofetch@2.0.0-alpha.3) optionalDependencies: dotenv: 17.4.2 giget: 3.3.0 @@ -26248,7 +26620,7 @@ snapshots: - uploadthing - wrangler - nitropack@2.13.4(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(oxc-parser@0.131.0)(rolldown@1.1.5)(srvx@0.11.22)(supports-color@10.2.2)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)): + nitropack@2.13.4(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1))(oxc-parser@0.131.0)(rolldown@1.1.5)(srvx@0.11.22)(supports-color@10.2.2)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)): dependencies: '@cloudflare/kv-asset-handler': 0.4.2 '@rollup/plugin-alias': 6.0.0(rollup@4.62.2) @@ -26269,7 +26641,7 @@ snapshots: cookie-es: 2.0.1 croner: 10.0.1 crossws: 0.3.5 - db0: 0.3.4 + db0: 0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)) defu: 6.1.7 destr: 2.0.5 dot-prop: 10.1.0 @@ -26315,7 +26687,7 @@ snapshots: unenv: 2.0.0-rc.24 unimport: 6.3.0(esbuild@0.28.1)(oxc-parser@0.131.0)(rolldown@1.1.5)(rollup@4.62.2)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) unplugin-utils: 0.3.2 - unstorage: 1.17.5(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4)(ioredis@5.11.1(supports-color@10.2.2)) + unstorage: 1.17.5(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(ioredis@5.11.1(supports-color@10.2.2)) untyped: 2.0.0 unwasm: 0.5.3 youch: 4.1.1 @@ -26360,7 +26732,7 @@ snapshots: - webpack optional: true - nitropack@2.13.4(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(oxc-parser@0.131.0)(rolldown@1.1.5)(srvx@0.11.22)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)): + nitropack@2.13.4(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1))(oxc-parser@0.131.0)(rolldown@1.1.5)(srvx@0.11.22)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)): dependencies: '@cloudflare/kv-asset-handler': 0.4.2 '@rollup/plugin-alias': 6.0.0(rollup@4.62.2) @@ -26381,7 +26753,7 @@ snapshots: cookie-es: 2.0.1 croner: 10.0.1 crossws: 0.3.5 - db0: 0.3.4 + db0: 0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)) defu: 6.1.7 destr: 2.0.5 dot-prop: 10.1.0 @@ -26427,7 +26799,7 @@ snapshots: unenv: 2.0.0-rc.24 unimport: 6.3.0(esbuild@0.28.1)(oxc-parser@0.131.0)(rolldown@1.1.5)(rollup@4.62.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) unplugin-utils: 0.3.2 - unstorage: 1.17.5(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4)(ioredis@5.11.1(supports-color@10.2.2)) + unstorage: 1.17.5(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(ioredis@5.11.1(supports-color@10.2.2)) untyped: 2.0.0 unwasm: 0.5.3 youch: 4.1.1 @@ -26565,16 +26937,16 @@ snapshots: nullthrows@1.1.1: {} - nuxt@4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@25.9.1)(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(@vue/compiler-sfc@3.5.39)(aws4fetch@1.0.20)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue-tsc@3.3.6(typescript@6.0.3))(yaml@2.9.0): + nuxt@4.4.6(41ce06a5c11c989752f5b4fadc9496f0): dependencies: '@dxup/nuxt': 0.4.1(magicast@0.5.3)(typescript@6.0.3) '@nuxt/cli': 3.37.0(@nuxt/schema@4.4.6)(cac@6.7.14)(commander@14.0.3)(magicast@0.5.3)(supports-color@10.2.2) '@nuxt/devtools': 3.2.4(bufferutil@4.1.0)(supports-color@10.2.2)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue@3.5.35(typescript@6.0.3)) '@nuxt/kit': 4.4.6(magicast@0.5.3) - '@nuxt/nitro-server': 4.4.6(5af45ff6ce88146737a84f10936700d8) + '@nuxt/nitro-server': 4.4.6(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1))(esbuild@0.28.1)(ioredis@5.11.1(supports-color@10.2.2))(magicast@0.5.3)(nuxt@4.4.6(41ce06a5c11c989752f5b4fadc9496f0))(oxc-parser@0.131.0)(rolldown@1.1.5)(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(typescript@6.0.3)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) '@nuxt/schema': 4.4.6 '@nuxt/telemetry': 2.8.0(@nuxt/kit@4.4.6(magicast@0.5.3)) - '@nuxt/vite-builder': 4.4.6(bd1799bb420f4f18d539b3aab18f78ee) + '@nuxt/vite-builder': 4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@types/node@25.9.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(nuxt@4.4.6(41ce06a5c11c989752f5b4fadc9496f0))(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vue-tsc@3.3.6(typescript@6.0.3))(vue@3.5.35(typescript@6.0.3))(yaml@2.9.0) '@unhead/vue': 2.1.15(vue@3.5.35(typescript@6.0.3)) '@vue/shared': 3.5.39 chokidar: 5.0.0 @@ -26702,16 +27074,16 @@ snapshots: - yaml optional: true - nuxt@4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@parcel/watcher@2.5.6)(@types/node@25.9.1)(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(@vue/compiler-sfc@3.5.39)(aws4fetch@1.0.20)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue-tsc@3.3.6(typescript@6.0.3))(yaml@2.9.0): + nuxt@4.4.6(f32df07d5233da3a29c17b72e1467465): dependencies: '@dxup/nuxt': 0.4.1(magicast@0.5.3)(typescript@6.0.3) '@nuxt/cli': 3.37.0(@nuxt/schema@4.4.6)(cac@6.7.14)(commander@14.0.3)(magicast@0.5.3)(supports-color@10.2.2) '@nuxt/devtools': 3.2.4(bufferutil@4.1.0)(supports-color@10.2.2)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0))(vue@3.5.35(typescript@6.0.3)) '@nuxt/kit': 4.4.6(magicast@0.5.3) - '@nuxt/nitro-server': 4.4.6(d7661b23bdde68362333e80e2569dc53) + '@nuxt/nitro-server': 4.4.6(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1))(esbuild@0.28.1)(ioredis@5.11.1(supports-color@10.2.2))(magicast@0.5.3)(nuxt@4.4.6(f32df07d5233da3a29c17b72e1467465))(oxc-parser@0.131.0)(rolldown@1.1.5)(rollup@4.62.2)(srvx@0.11.22)(supports-color@10.2.2)(typescript@6.0.3)(vite@8.1.5(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.9.0)) '@nuxt/schema': 4.4.6 '@nuxt/telemetry': 2.8.0(@nuxt/kit@4.4.6(magicast@0.5.3)) - '@nuxt/vite-builder': 4.4.6(65326fc791d4735547fd3a6298d65608) + '@nuxt/vite-builder': 4.4.6(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0(supports-color@10.2.2)))(@types/node@25.9.1)(eslint@10.4.0(jiti@2.7.0)(supports-color@10.2.2))(lightningcss@1.32.0)(magicast@0.5.3)(nuxt@4.4.6(f32df07d5233da3a29c17b72e1467465))(optionator@0.9.4)(oxlint@1.73.0)(rolldown@1.1.5)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.5)(rollup@4.62.2))(rollup@4.62.2)(supports-color@10.2.2)(terser@5.49.0)(tsx@4.21.0)(typescript@6.0.3)(vue-tsc@3.3.6(typescript@6.0.3))(vue@3.5.35(typescript@6.0.3))(yaml@2.9.0) '@unhead/vue': 2.1.15(vue@3.5.35(typescript@6.0.3)) '@vue/shared': 3.5.39 chokidar: 5.0.0 @@ -27413,6 +27785,41 @@ snapshots: perfect-debounce@2.1.0: {} + pg-cloudflare@1.4.0: + optional: true + + pg-connection-string@2.14.0: {} + + pg-int8@1.0.1: {} + + pg-pool@3.14.0(pg@8.20.0): + dependencies: + pg: 8.20.0 + + pg-protocol@1.15.0: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.1 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg@8.20.0: + dependencies: + pg-connection-string: 2.14.0 + pg-pool: 3.14.0(pg@8.20.0) + pg-protocol: 1.15.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.4.0 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + phase@0.0.1(react@19.2.6): optionalDependencies: react: 19.2.6 @@ -27684,6 +28091,16 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postgres-array@2.0.0: {} + + postgres-bytea@1.0.1: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + powershell-utils@0.1.0: {} preact-render-to-string@6.5.11(preact@10.24.3): @@ -29624,6 +30041,8 @@ snapshots: undici-types@5.26.5: {} + undici-types@6.21.0: {} + undici-types@7.24.6: {} undici@5.28.4: @@ -29833,7 +30252,7 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 - unstorage@1.17.5(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4)(ioredis@5.11.1(supports-color@10.2.2)): + unstorage@1.17.5(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(ioredis@5.11.1(supports-color@10.2.2)): dependencies: anymatch: 3.1.3 chokidar: 5.0.0 @@ -29848,17 +30267,17 @@ snapshots: '@vercel/blob': 2.4.0 '@vercel/functions': 3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)) aws4fetch: 1.0.20 - db0: 0.3.4 + db0: 0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)) ioredis: 5.11.1(supports-color@10.2.2) - unstorage@2.0.0-alpha.7(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(chokidar@5.0.0)(db0@0.3.4)(ioredis@5.11.1(supports-color@10.2.2))(lru-cache@11.5.2)(ofetch@2.0.0-alpha.3): + unstorage@2.0.0-alpha.7(@upstash/redis@1.38.0)(@vercel/blob@2.4.0)(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)))(aws4fetch@1.0.20)(chokidar@5.0.0)(db0@0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)))(ioredis@5.11.1(supports-color@10.2.2))(lru-cache@11.5.2)(ofetch@2.0.0-alpha.3): optionalDependencies: '@upstash/redis': 1.38.0 '@vercel/blob': 2.4.0 '@vercel/functions': 3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.21.1(bufferutil@4.1.0)) aws4fetch: 1.0.20 chokidar: 5.0.0 - db0: 0.3.4 + db0: 0.3.4(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(pg@8.20.0)(sql.js@1.14.1)) ioredis: 5.11.1(supports-color@10.2.2) lru-cache: 11.5.2 ofetch: 2.0.0-alpha.3 @@ -30489,6 +30908,8 @@ snapshots: xml-naming@0.1.0: {} + xtend@4.0.2: {} + y18n@5.0.8: {} yallist@3.1.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 302fa1eb2..707282ee8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -39,6 +39,7 @@ catalog: "@vercel/connect": "0.4.2" "@vercel/otel": "2.1.3" "@vercel/sandbox": "2.8.0" + "@workflow/world-postgres": "5.0.0-beta.29" ai: "^7.0.38" marked: "17.0.6" next: "16.3.0-preview.6" From 1238adecefc605881edfd2fc76056b27e538abd7 Mon Sep 17 00:00:00 2001 From: Andrew Barba Date: Wed, 29 Jul 2026 18:01:58 -0400 Subject: [PATCH 2/5] chore(e2e): share fixture agent config Signed-off-by: Andrew Barba --- .github/scripts/discover-e2e-fixtures.sh | 49 +++++++++++ e2e/README.md | 20 +++-- .../agent-basic-runtime/agent/agent.ts | 5 +- e2e/fixtures/agent-basic-runtime/package.json | 1 + .../agent-cancellation/agent/agent.ts | 5 +- e2e/fixtures/agent-cancellation/package.json | 1 + e2e/fixtures/agent-channels/agent/agent.ts | 5 +- e2e/fixtures/agent-channels/package.json | 1 + .../agent/agent.ts | 4 +- .../agent-compaction-regressions/package.json | 1 + e2e/fixtures/agent-model/agent/agent.ts | 5 +- e2e/fixtures/agent-model/package.json | 1 + .../agent-openapi-swagger/agent/agent.ts | 5 +- .../agent-openapi-swagger/package.json | 1 + .../agent-prompt-cache/agent/agent.ts | 5 +- e2e/fixtures/agent-prompt-cache/package.json | 1 + e2e/fixtures/agent-schedules/agent/agent.ts | 5 +- e2e/fixtures/agent-schedules/package.json | 1 + .../agent-session-limits/agent/agent.ts | 5 +- .../agent-session-limits/package.json | 1 + .../agent-session-timeout/agent/agent.ts | 2 + .../agent-session-timeout/package.json | 2 + e2e/fixtures/agent-skills/agent/agent.ts | 5 +- e2e/fixtures/agent-skills/package.json | 1 + .../agent-subagents-hitl/agent/agent.ts | 5 +- .../agent-subagents-hitl/package.json | 1 + e2e/fixtures/agent-subagents/agent/agent.ts | 5 +- e2e/fixtures/agent-subagents/package.json | 1 + .../agent-tools-hitl-openai/agent/agent.ts | 5 +- .../agent-tools-hitl-openai/package.json | 1 + e2e/fixtures/agent-tools-hitl/agent/agent.ts | 5 +- e2e/fixtures/agent-tools-hitl/package.json | 1 + .../agent-tools-sandbox/agent/agent.ts | 5 +- e2e/fixtures/agent-tools-sandbox/package.json | 1 + e2e/fixtures/agent-tools/agent/agent.ts | 5 +- e2e/fixtures/agent-tools/package.json | 1 + .../agent-workflow-stress/agent/agent.ts | 5 +- .../agent-workflow-stress/package.json | 1 + e2e/fixtures/dist-extensions/agent/agent.ts | 5 +- e2e/fixtures/dist-extensions/package.json | 1 + e2e/fixtures/e2e-config/package.json | 17 ++++ e2e/fixtures/e2e-config/src/index.ts | 17 ++++ e2e/fixtures/e2e-config/tsconfig.json | 17 ++++ e2e/fixtures/extensions/agent/agent.ts | 5 +- e2e/fixtures/extensions/package.json | 1 + pnpm-lock.yaml | 87 +++++++++++++++++-- 46 files changed, 253 insertions(+), 71 deletions(-) create mode 100644 e2e/fixtures/e2e-config/package.json create mode 100644 e2e/fixtures/e2e-config/src/index.ts create mode 100644 e2e/fixtures/e2e-config/tsconfig.json diff --git a/.github/scripts/discover-e2e-fixtures.sh b/.github/scripts/discover-e2e-fixtures.sh index 4b3918f8b..7987304ff 100755 --- a/.github/scripts/discover-e2e-fixtures.sh +++ b/.github/scripts/discover-e2e-fixtures.sh @@ -9,9 +9,11 @@ set -euo pipefail roots=("e2e/fixtures" "apps/fixtures") entries=() +fixture_dirs=() while IFS= read -r evals_dir; do dir="${evals_dir%/evals}" name="$(basename "$dir")" + fixture_dirs+=("$dir") entries+=("{\"name\":\"${name}\",\"dir\":\"${dir}\"}") done < <( for root in "${roots[@]}"; do @@ -25,6 +27,53 @@ if [ "${#entries[@]}" -eq 0 ]; then exit 1 fi +node --input-type=module - "${fixture_dirs[@]}" <<'NODE' +import { existsSync, readFileSync } from "node:fs"; +import { join } from "node:path"; + +const failures = []; +for (const fixtureDir of process.argv.slice(2)) { + const packagePath = join(fixtureDir, "package.json"); + const agentPath = join(fixtureDir, "agent", "agent.ts"); + + if (!existsSync(packagePath)) { + failures.push(`${fixtureDir}: missing package.json`); + continue; + } + if (!existsSync(agentPath)) { + failures.push(`${fixtureDir}: missing agent/agent.ts`); + continue; + } + + const manifest = JSON.parse(readFileSync(packagePath, "utf8")); + const dependencies = manifest.dependencies ?? {}; + if (dependencies["@eve-e2e/config"] !== "workspace:*") { + failures.push(`${fixtureDir}: dependencies must include @eve-e2e/config as workspace:*`); + } + if (dependencies["@workflow/world-postgres"] !== "catalog:") { + failures.push( + `${fixtureDir}: dependencies must include @workflow/world-postgres from the catalog`, + ); + } + + const agentSource = readFileSync(agentPath, "utf8"); + if ( + !agentSource.includes("@eve-e2e/config") || + !agentSource.includes("...e2eAgentConfig()") + ) { + failures.push(`${fixtureDir}: root agent must spread ...e2eAgentConfig()`); + } +} + +if (failures.length > 0) { + console.error("Invalid e2e fixture contract:"); + for (const failure of failures) { + console.error(`- ${failure}`); + } + process.exit(1); +} +NODE + matrix="[$( IFS=, echo "${entries[*]}" diff --git a/e2e/README.md b/e2e/README.md index 977585d05..79d0aab35 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -39,12 +39,13 @@ server backed by `@workflow/world-postgres`. Each matrix leg owns an isolated PostgreSQL service, bootstraps its schema, builds the fixture, starts it with `eve start`, and targets that server with `eve eval --url`. -Fixture root agents read `EVE_E2E_WORKFLOW_WORLD` into -`experimental.workflow.world`. The variable is unset in the local and Vercel -suites, preserving their host defaults; the Postgres workflow sets it to -`@workflow/world-postgres` while compiling the production server. The world -package is a direct fixture dependency pinned through the workspace catalog -to the same `@workflow/*` line as eve. +Fixture root agents spread `e2eAgentConfig()` from the private +`@eve-e2e/config` workspace package. The helper reads +`EVE_E2E_WORKFLOW_WORLD` into `experimental.workflow.world`. The variable is +unset in the local and Vercel suites, preserving their host defaults; the +Postgres workflow sets it to `@workflow/world-postgres` while compiling the +production server. The world package remains a direct fixture dependency, +pinned through the workspace catalog to the same `@workflow/*` line as eve. The per-fixture lifecycle is: @@ -143,9 +144,10 @@ When adding e2e coverage: - Keep it runnable with only `eve eval --strict`. - Keep it deterministic: no external service startup or injected env requirements (beyond model-provider credentials). -- Keep the root `agent.ts` selectable through `EVE_E2E_WORKFLOW_WORLD` and - declare `@workflow/world-postgres` as a direct dependency so fixture - discovery automatically adds it to the Postgres matrix. +- Spread `e2eAgentConfig()` from `@eve-e2e/config` in the root `agent.ts`. +- Declare `@eve-e2e/config` and `@workflow/world-postgres` as direct + dependencies. Fixture discovery validates this contract before adding the + fixture to any matrix. - If the behavior cannot fit that shape yet, leave it out and rebuild it later as a first-class eval story. diff --git a/e2e/fixtures/agent-basic-runtime/agent/agent.ts b/e2e/fixtures/agent-basic-runtime/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/agent-basic-runtime/agent/agent.ts +++ b/e2e/fixtures/agent-basic-runtime/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-basic-runtime/package.json b/e2e/fixtures/agent-basic-runtime/package.json index 261913a93..0157fe04f 100644 --- a/e2e/fixtures/agent-basic-runtime/package.json +++ b/e2e/fixtures/agent-basic-runtime/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-cancellation/agent/agent.ts b/e2e/fixtures/agent-cancellation/agent/agent.ts index b1b4987a3..d9746266b 100644 --- a/e2e/fixtures/agent-cancellation/agent/agent.ts +++ b/e2e/fixtures/agent-cancellation/agent/agent.ts @@ -1,8 +1,7 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", }); diff --git a/e2e/fixtures/agent-cancellation/package.json b/e2e/fixtures/agent-cancellation/package.json index d80350919..4f50390ba 100644 --- a/e2e/fixtures/agent-cancellation/package.json +++ b/e2e/fixtures/agent-cancellation/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-channels/agent/agent.ts b/e2e/fixtures/agent-channels/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/agent-channels/agent/agent.ts +++ b/e2e/fixtures/agent-channels/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-channels/package.json b/e2e/fixtures/agent-channels/package.json index 81d51aa49..6e795186b 100644 --- a/e2e/fixtures/agent-channels/package.json +++ b/e2e/fixtures/agent-channels/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-compaction-regressions/agent/agent.ts b/e2e/fixtures/agent-compaction-regressions/agent/agent.ts index 0e6a639b3..15c03b266 100644 --- a/e2e/fixtures/agent-compaction-regressions/agent/agent.ts +++ b/e2e/fixtures/agent-compaction-regressions/agent/agent.ts @@ -1,3 +1,4 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; import { mockModel, type MockModelRequest } from "eve/evals"; @@ -13,7 +14,6 @@ import { TASK_TAIL_SENTINEL, } from "../constants"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; const TEST_CONTEXT_WINDOW_TOKENS = 32_000; const MAX_TOOL_CALLS = 10; @@ -224,7 +224,7 @@ const taskModel = mockModel({ }); export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: taskModel, modelContextWindowTokens: TEST_CONTEXT_WINDOW_TOKENS, compaction: { diff --git a/e2e/fixtures/agent-compaction-regressions/package.json b/e2e/fixtures/agent-compaction-regressions/package.json index 86e47c9de..ba5a4255f 100644 --- a/e2e/fixtures/agent-compaction-regressions/package.json +++ b/e2e/fixtures/agent-compaction-regressions/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-model/agent/agent.ts b/e2e/fixtures/agent-model/agent/agent.ts index 68dd5011d..a2c3f984c 100644 --- a/e2e/fixtures/agent-model/agent/agent.ts +++ b/e2e/fixtures/agent-model/agent/agent.ts @@ -1,15 +1,14 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent, defineDynamic, type DynamicResolveContext } from "eve"; const model = process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - /** * Dynamic-model e2e fixture. Resolves at `turn.started` (not the usual * `session.started`) so one session can exercise selection, null fallback, * and resolver-failure degradation. */ export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: defineDynamic({ fallback: model, events: { diff --git a/e2e/fixtures/agent-model/package.json b/e2e/fixtures/agent-model/package.json index 57534dd41..bbcd3d842 100644 --- a/e2e/fixtures/agent-model/package.json +++ b/e2e/fixtures/agent-model/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@workflow/world-postgres": "catalog:", "eve": "workspace:*" }, diff --git a/e2e/fixtures/agent-openapi-swagger/agent/agent.ts b/e2e/fixtures/agent-openapi-swagger/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/agent-openapi-swagger/agent/agent.ts +++ b/e2e/fixtures/agent-openapi-swagger/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-openapi-swagger/package.json b/e2e/fixtures/agent-openapi-swagger/package.json index 5ef7f6abb..23f47bddb 100644 --- a/e2e/fixtures/agent-openapi-swagger/package.json +++ b/e2e/fixtures/agent-openapi-swagger/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-prompt-cache/agent/agent.ts b/e2e/fixtures/agent-prompt-cache/agent/agent.ts index d5ccb4f79..d26bccd65 100644 --- a/e2e/fixtures/agent-prompt-cache/agent/agent.ts +++ b/e2e/fixtures/agent-prompt-cache/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { createAnthropic } from "@ai-sdk/anthropic"; import { type AgentDefinition, defineAgent } from "eve"; import { vercelOidc } from "eve/agents/auth"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - /** * Prompt-cache e2e fixture. * @@ -45,7 +44,7 @@ const anthropic = createAnthropic({ }); const agent: AgentDefinition = defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: anthropic(promptCacheModel), modelContextWindowTokens: 200_000, }); diff --git a/e2e/fixtures/agent-prompt-cache/package.json b/e2e/fixtures/agent-prompt-cache/package.json index 3375c11e4..e42edd3cc 100644 --- a/e2e/fixtures/agent-prompt-cache/package.json +++ b/e2e/fixtures/agent-prompt-cache/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@ai-sdk/anthropic": "catalog:", + "@eve-e2e/config": "workspace:*", "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" diff --git a/e2e/fixtures/agent-schedules/agent/agent.ts b/e2e/fixtures/agent-schedules/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/agent-schedules/agent/agent.ts +++ b/e2e/fixtures/agent-schedules/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-schedules/package.json b/e2e/fixtures/agent-schedules/package.json index 59cf5d534..ac0406cfd 100644 --- a/e2e/fixtures/agent-schedules/package.json +++ b/e2e/fixtures/agent-schedules/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-session-limits/agent/agent.ts b/e2e/fixtures/agent-session-limits/agent/agent.ts index 3ab7ce4f3..a832d3338 100644 --- a/e2e/fixtures/agent-session-limits/agent/agent.ts +++ b/e2e/fixtures/agent-session-limits/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", // A one-token input budget guarantees every completed model call crosses // the limit, so the next conversation turn deterministically parks on the diff --git a/e2e/fixtures/agent-session-limits/package.json b/e2e/fixtures/agent-session-limits/package.json index eb0d9ad9c..7acfc567b 100644 --- a/e2e/fixtures/agent-session-limits/package.json +++ b/e2e/fixtures/agent-session-limits/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-session-timeout/agent/agent.ts b/e2e/fixtures/agent-session-timeout/agent/agent.ts index 9b2fcae12..2b1141e68 100644 --- a/e2e/fixtures/agent-session-timeout/agent/agent.ts +++ b/e2e/fixtures/agent-session-timeout/agent/agent.ts @@ -1,9 +1,11 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; import { mockModel } from "eve/evals"; const ACTIVE_TURN_DELAY_MS = 1_500; export default defineAgent({ + ...e2eAgentConfig(), model: mockModel(async ({ lastUserMessage }) => { if (lastUserMessage?.includes("SLOW-TURN") === true) { await new Promise((resolve) => setTimeout(resolve, ACTIVE_TURN_DELAY_MS)); diff --git a/e2e/fixtures/agent-session-timeout/package.json b/e2e/fixtures/agent-session-timeout/package.json index 2b033a4cc..61c6382a4 100644 --- a/e2e/fixtures/agent-session-timeout/package.json +++ b/e2e/fixtures/agent-session-timeout/package.json @@ -11,9 +11,11 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", + "@workflow/world-postgres": "catalog:", "ai": "catalog:", "eve": "workspace:*" }, diff --git a/e2e/fixtures/agent-skills/agent/agent.ts b/e2e/fixtures/agent-skills/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/agent-skills/agent/agent.ts +++ b/e2e/fixtures/agent-skills/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-skills/package.json b/e2e/fixtures/agent-skills/package.json index 334a1711a..776c663a3 100644 --- a/e2e/fixtures/agent-skills/package.json +++ b/e2e/fixtures/agent-skills/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-subagents-hitl/agent/agent.ts b/e2e/fixtures/agent-subagents-hitl/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/agent-subagents-hitl/agent/agent.ts +++ b/e2e/fixtures/agent-subagents-hitl/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-subagents-hitl/package.json b/e2e/fixtures/agent-subagents-hitl/package.json index 789e7d50f..281703653 100644 --- a/e2e/fixtures/agent-subagents-hitl/package.json +++ b/e2e/fixtures/agent-subagents-hitl/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" diff --git a/e2e/fixtures/agent-subagents/agent/agent.ts b/e2e/fixtures/agent-subagents/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/agent-subagents/agent/agent.ts +++ b/e2e/fixtures/agent-subagents/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-subagents/package.json b/e2e/fixtures/agent-subagents/package.json index 36bba8c17..927e0e7a6 100644 --- a/e2e/fixtures/agent-subagents/package.json +++ b/e2e/fixtures/agent-subagents/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts b/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts index 4af93d626..903467432 100644 --- a/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts +++ b/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts @@ -1,7 +1,6 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - /** * HITL fixture whose OpenAI matrix leg covers the Responses provider path * (https://github.com/vercel/eve/issues/236). Approval-gated executable @@ -9,6 +8,6 @@ const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; * validated by OpenAI's `function_call` / `function_call_output` pairing. */ export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", }); diff --git a/e2e/fixtures/agent-tools-hitl-openai/package.json b/e2e/fixtures/agent-tools-hitl-openai/package.json index 091d3ad65..cc6b941e9 100644 --- a/e2e/fixtures/agent-tools-hitl-openai/package.json +++ b/e2e/fixtures/agent-tools-hitl-openai/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-tools-hitl/agent/agent.ts b/e2e/fixtures/agent-tools-hitl/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/agent-tools-hitl/agent/agent.ts +++ b/e2e/fixtures/agent-tools-hitl/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools-hitl/package.json b/e2e/fixtures/agent-tools-hitl/package.json index 3edcdb469..53f095904 100644 --- a/e2e/fixtures/agent-tools-hitl/package.json +++ b/e2e/fixtures/agent-tools-hitl/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-tools-sandbox/agent/agent.ts b/e2e/fixtures/agent-tools-sandbox/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/agent-tools-sandbox/agent/agent.ts +++ b/e2e/fixtures/agent-tools-sandbox/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools-sandbox/package.json b/e2e/fixtures/agent-tools-sandbox/package.json index 3774c135c..80a28ed79 100644 --- a/e2e/fixtures/agent-tools-sandbox/package.json +++ b/e2e/fixtures/agent-tools-sandbox/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/agent-tools/agent/agent.ts b/e2e/fixtures/agent-tools/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/agent-tools/agent/agent.ts +++ b/e2e/fixtures/agent-tools/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools/package.json b/e2e/fixtures/agent-tools/package.json index 68aaff61b..5ab1294cc 100644 --- a/e2e/fixtures/agent-tools/package.json +++ b/e2e/fixtures/agent-tools/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@eve-e2e/dynamic-import-dependency": "file:./fixtures/dynamic-import-dependency", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", diff --git a/e2e/fixtures/agent-workflow-stress/agent/agent.ts b/e2e/fixtures/agent-workflow-stress/agent/agent.ts index 718767c6d..0f813a9db 100644 --- a/e2e/fixtures/agent-workflow-stress/agent/agent.ts +++ b/e2e/fixtures/agent-workflow-stress/agent/agent.ts @@ -1,10 +1,9 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; import { mockModel } from "eve/evals"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: mockModel( ({ lastUserMessage, userMessageCount }) => `stress-ack:${userMessageCount}:${lastUserMessage ?? ""}`, diff --git a/e2e/fixtures/agent-workflow-stress/package.json b/e2e/fixtures/agent-workflow-stress/package.json index dc0070582..aa07a981a 100644 --- a/e2e/fixtures/agent-workflow-stress/package.json +++ b/e2e/fixtures/agent-workflow-stress/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", diff --git a/e2e/fixtures/dist-extensions/agent/agent.ts b/e2e/fixtures/dist-extensions/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/dist-extensions/agent/agent.ts +++ b/e2e/fixtures/dist-extensions/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/dist-extensions/package.json b/e2e/fixtures/dist-extensions/package.json index cf7ba9332..351cffbc1 100644 --- a/e2e/fixtures/dist-extensions/package.json +++ b/e2e/fixtures/dist-extensions/package.json @@ -10,6 +10,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "gadget-extension": "file:../gadget-extension", diff --git a/e2e/fixtures/e2e-config/package.json b/e2e/fixtures/e2e-config/package.json new file mode 100644 index 000000000..fe666d38e --- /dev/null +++ b/e2e/fixtures/e2e-config/package.json @@ -0,0 +1,17 @@ +{ + "name": "@eve-e2e/config", + "version": "0.0.0", + "private": true, + "type": "module", + "exports": { + ".": "./src/index.ts" + }, + "scripts": { + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@types/node": "catalog:", + "eve": "workspace:*", + "typescript": "catalog:" + } +} diff --git a/e2e/fixtures/e2e-config/src/index.ts b/e2e/fixtures/e2e-config/src/index.ts new file mode 100644 index 000000000..7a8942be6 --- /dev/null +++ b/e2e/fixtures/e2e-config/src/index.ts @@ -0,0 +1,17 @@ +import type { AgentDefinition } from "eve"; + +type E2EAgentConfig = Pick; + +/** + * Returns the harness-owned configuration shared by e2e fixture root agents. + */ +export function e2eAgentConfig(): E2EAgentConfig { + const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; + if (workflowWorld === undefined) { + return {}; + } + + return { + experimental: { workflow: { world: workflowWorld } }, + }; +} diff --git a/e2e/fixtures/e2e-config/tsconfig.json b/e2e/fixtures/e2e-config/tsconfig.json new file mode 100644 index 000000000..e4c8332fa --- /dev/null +++ b/e2e/fixtures/e2e-config/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "esnext", + "moduleResolution": "bundler", + "outDir": "dist", + "rootDir": ".", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "noEmit": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"] +} diff --git a/e2e/fixtures/extensions/agent/agent.ts b/e2e/fixtures/extensions/agent/agent.ts index 413f92fcb..465271af8 100644 --- a/e2e/fixtures/extensions/agent/agent.ts +++ b/e2e/fixtures/extensions/agent/agent.ts @@ -1,9 +1,8 @@ +import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; -const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; - export default defineAgent({ - experimental: workflowWorld === undefined ? undefined : { workflow: { world: workflowWorld } }, + ...e2eAgentConfig(), model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/extensions/package.json b/e2e/fixtures/extensions/package.json index f8e8be6fa..072ec4a81 100644 --- a/e2e/fixtures/extensions/package.json +++ b/e2e/fixtures/extensions/package.json @@ -11,6 +11,7 @@ "test:e2e": "eve eval --strict" }, "dependencies": { + "@eve-e2e/config": "workspace:*", "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "gizmo-extension": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 408220e68..881765f90 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -296,7 +296,7 @@ importers: version: 0.2.4(ai@7.0.38(zod@4.4.3))(chat@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3) '@vercel/connect': specifier: 'catalog:' - version: 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) + version: 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.1)) @@ -384,7 +384,7 @@ importers: version: 0.41.2 '@vercel/connect': specifier: 'catalog:' - version: 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) + version: 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) '@vercel/oidc': specifier: 3.8.0 version: 3.8.0 @@ -524,6 +524,9 @@ importers: e2e/fixtures/agent-basic-runtime: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -552,6 +555,9 @@ importers: e2e/fixtures/agent-cancellation: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -580,6 +586,9 @@ importers: e2e/fixtures/agent-channels: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -611,6 +620,9 @@ importers: e2e/fixtures/agent-compaction-regressions: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -639,6 +651,9 @@ importers: e2e/fixtures/agent-model: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@workflow/world-postgres': specifier: 'catalog:' version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) @@ -655,6 +670,9 @@ importers: e2e/fixtures/agent-openapi-swagger: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -686,6 +704,9 @@ importers: '@ai-sdk/anthropic': specifier: 'catalog:' version: 4.0.18(zod@4.4.3) + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@workflow/world-postgres': specifier: 'catalog:' version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) @@ -705,6 +726,9 @@ importers: e2e/fixtures/agent-schedules: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -733,6 +757,9 @@ importers: e2e/fixtures/agent-session-limits: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -761,6 +788,9 @@ importers: e2e/fixtures/agent-session-timeout: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -770,6 +800,9 @@ importers: '@vercel/otel': specifier: 'catalog:' version: 2.1.3(@opentelemetry/api-logs@0.221.0)(@opentelemetry/api@1.9.1)(@opentelemetry/instrumentation@0.219.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)) + '@workflow/world-postgres': + specifier: 'catalog:' + version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) ai: specifier: 'catalog:' version: 7.0.38(zod@4.4.3) @@ -786,6 +819,9 @@ importers: e2e/fixtures/agent-skills: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -814,6 +850,9 @@ importers: e2e/fixtures/agent-subagents: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -842,6 +881,9 @@ importers: e2e/fixtures/agent-subagents-hitl: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@workflow/world-postgres': specifier: 'catalog:' version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) @@ -861,6 +903,9 @@ importers: e2e/fixtures/agent-tools: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@eve-e2e/dynamic-import-dependency': specifier: file:./fixtures/dynamic-import-dependency version: file:e2e/fixtures/agent-tools/fixtures/dynamic-import-dependency @@ -892,6 +937,9 @@ importers: e2e/fixtures/agent-tools-hitl: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -920,6 +968,9 @@ importers: e2e/fixtures/agent-tools-hitl-openai: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -948,6 +999,9 @@ importers: e2e/fixtures/agent-tools-sandbox: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -976,6 +1030,9 @@ importers: e2e/fixtures/agent-workflow-stress: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@opentelemetry/core': specifier: 'catalog:' version: 2.6.1(@opentelemetry/api@1.9.1) @@ -1004,6 +1061,9 @@ importers: e2e/fixtures/dist-extensions: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@workflow/world-postgres': specifier: 'catalog:' version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) @@ -1024,8 +1084,23 @@ importers: specifier: 'catalog:' version: 7.0.2 + e2e/fixtures/e2e-config: + devDependencies: + '@types/node': + specifier: 'catalog:' + version: 25.9.1 + eve: + specifier: workspace:* + version: link:../../../packages/eve + typescript: + specifier: 'catalog:' + version: 7.0.2 + e2e/fixtures/extensions: dependencies: + '@eve-e2e/config': + specifier: workspace:* + version: link:../e2e-config '@workflow/world-postgres': specifier: 'catalog:' version: 5.0.0-beta.29(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(@upstash/redis@1.38.0)(sql.js@1.14.1)(supports-color@10.2.2)(typescript@7.0.2) @@ -16328,7 +16403,7 @@ snapshots: eve: link:packages/eve zod: 4.4.3 optionalDependencies: - '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) + '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) transitivePeerDependencies: - '@ai-sdk/workflow' - '@workflow/ai' @@ -16341,7 +16416,7 @@ snapshots: octokit: 5.0.5 zod: 4.4.3 optionalDependencies: - '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) + '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) eve: link:packages/eve '@google/genai@1.52.0(@modelcontextprotocol/sdk@1.29.0(supports-color@10.2.2)(zod@4.4.3))(bufferutil@4.1.0)(supports-color@10.2.2)': @@ -17634,7 +17709,7 @@ snapshots: '@onkernel/eve-extension@0.1.3(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve)': dependencies: - '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) + '@vercel/connect': 0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve) eve: link:packages/eve zod: 4.4.3 transitivePeerDependencies: @@ -20625,7 +20700,7 @@ snapshots: dependencies: execa: 5.1.1 - '@vercel/connect@0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(bufferutil@4.1.0)(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve)': + '@vercel/connect@0.4.2(@ai-sdk/mcp@2.0.16(zod@4.4.3))(@auth/core@0.41.2)(@chat-adapter/slack@4.34.0(ai@7.0.38(zod@4.4.3))(supports-color@10.2.2)(zod@4.4.3))(ai@7.0.38(zod@4.4.3))(eve@packages+eve)': dependencies: '@vercel/oidc': 3.8.0 optionalDependencies: From b012a852a8e6bf7283b8fa19447de337215829b0 Mon Sep 17 00:00:00 2001 From: Andrew Barba Date: Wed, 29 Jul 2026 18:21:28 -0400 Subject: [PATCH 3/5] chore(e2e): simplify shared fixture config Signed-off-by: Andrew Barba --- .github/scripts/discover-e2e-fixtures.sh | 49 ------------------- e2e/README.md | 16 +++--- .../agent-basic-runtime/agent/agent.ts | 1 - .../agent-cancellation/agent/agent.ts | 1 - e2e/fixtures/agent-channels/agent/agent.ts | 1 - .../agent-openapi-swagger/agent/agent.ts | 1 - e2e/fixtures/agent-schedules/agent/agent.ts | 1 - .../agent-session-limits/agent/agent.ts | 1 - e2e/fixtures/agent-skills/agent/agent.ts | 1 - .../agent-subagents-hitl/agent/agent.ts | 1 - e2e/fixtures/agent-subagents/agent/agent.ts | 1 - .../agent-tools-hitl-openai/agent/agent.ts | 1 - e2e/fixtures/agent-tools-hitl/agent/agent.ts | 1 - .../agent-tools-sandbox/agent/agent.ts | 1 - e2e/fixtures/agent-tools/agent/agent.ts | 1 - e2e/fixtures/dist-extensions/agent/agent.ts | 1 - e2e/fixtures/e2e-config/src/index.ts | 6 ++- e2e/fixtures/extensions/agent/agent.ts | 1 - 18 files changed, 12 insertions(+), 74 deletions(-) diff --git a/.github/scripts/discover-e2e-fixtures.sh b/.github/scripts/discover-e2e-fixtures.sh index 7987304ff..4b3918f8b 100755 --- a/.github/scripts/discover-e2e-fixtures.sh +++ b/.github/scripts/discover-e2e-fixtures.sh @@ -9,11 +9,9 @@ set -euo pipefail roots=("e2e/fixtures" "apps/fixtures") entries=() -fixture_dirs=() while IFS= read -r evals_dir; do dir="${evals_dir%/evals}" name="$(basename "$dir")" - fixture_dirs+=("$dir") entries+=("{\"name\":\"${name}\",\"dir\":\"${dir}\"}") done < <( for root in "${roots[@]}"; do @@ -27,53 +25,6 @@ if [ "${#entries[@]}" -eq 0 ]; then exit 1 fi -node --input-type=module - "${fixture_dirs[@]}" <<'NODE' -import { existsSync, readFileSync } from "node:fs"; -import { join } from "node:path"; - -const failures = []; -for (const fixtureDir of process.argv.slice(2)) { - const packagePath = join(fixtureDir, "package.json"); - const agentPath = join(fixtureDir, "agent", "agent.ts"); - - if (!existsSync(packagePath)) { - failures.push(`${fixtureDir}: missing package.json`); - continue; - } - if (!existsSync(agentPath)) { - failures.push(`${fixtureDir}: missing agent/agent.ts`); - continue; - } - - const manifest = JSON.parse(readFileSync(packagePath, "utf8")); - const dependencies = manifest.dependencies ?? {}; - if (dependencies["@eve-e2e/config"] !== "workspace:*") { - failures.push(`${fixtureDir}: dependencies must include @eve-e2e/config as workspace:*`); - } - if (dependencies["@workflow/world-postgres"] !== "catalog:") { - failures.push( - `${fixtureDir}: dependencies must include @workflow/world-postgres from the catalog`, - ); - } - - const agentSource = readFileSync(agentPath, "utf8"); - if ( - !agentSource.includes("@eve-e2e/config") || - !agentSource.includes("...e2eAgentConfig()") - ) { - failures.push(`${fixtureDir}: root agent must spread ...e2eAgentConfig()`); - } -} - -if (failures.length > 0) { - console.error("Invalid e2e fixture contract:"); - for (const failure of failures) { - console.error(`- ${failure}`); - } - process.exit(1); -} -NODE - matrix="[$( IFS=, echo "${entries[*]}" diff --git a/e2e/README.md b/e2e/README.md index 79d0aab35..7b1f5551d 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -40,12 +40,13 @@ PostgreSQL service, bootstraps its schema, builds the fixture, starts it with `eve start`, and targets that server with `eve eval --url`. Fixture root agents spread `e2eAgentConfig()` from the private -`@eve-e2e/config` workspace package. The helper reads -`EVE_E2E_WORKFLOW_WORLD` into `experimental.workflow.world`. The variable is -unset in the local and Vercel suites, preserving their host defaults; the -Postgres workflow sets it to `@workflow/world-postgres` while compiling the -production server. The world package remains a direct fixture dependency, -pinned through the workspace catalog to the same `@workflow/*` line as eve. +`@eve-e2e/config` workspace package. The helper selects the root agent model +from `EVE_E2E_MODEL` and reads `EVE_E2E_WORKFLOW_WORLD` into +`experimental.workflow.world`. The world variable is unset in the local and +Vercel suites, preserving their host defaults; the Postgres workflow sets it +to `@workflow/world-postgres` while compiling the production server. The world +package remains a direct fixture dependency, pinned through the workspace +catalog to the same `@workflow/*` line as eve. The per-fixture lifecycle is: @@ -146,8 +147,7 @@ When adding e2e coverage: requirements (beyond model-provider credentials). - Spread `e2eAgentConfig()` from `@eve-e2e/config` in the root `agent.ts`. - Declare `@eve-e2e/config` and `@workflow/world-postgres` as direct - dependencies. Fixture discovery validates this contract before adding the - fixture to any matrix. + dependencies. - If the behavior cannot fit that shape yet, leave it out and rebuild it later as a first-class eval story. diff --git a/e2e/fixtures/agent-basic-runtime/agent/agent.ts b/e2e/fixtures/agent-basic-runtime/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/agent-basic-runtime/agent/agent.ts +++ b/e2e/fixtures/agent-basic-runtime/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-cancellation/agent/agent.ts b/e2e/fixtures/agent-cancellation/agent/agent.ts index d9746266b..a2715dfff 100644 --- a/e2e/fixtures/agent-cancellation/agent/agent.ts +++ b/e2e/fixtures/agent-cancellation/agent/agent.ts @@ -3,5 +3,4 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", }); diff --git a/e2e/fixtures/agent-channels/agent/agent.ts b/e2e/fixtures/agent-channels/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/agent-channels/agent/agent.ts +++ b/e2e/fixtures/agent-channels/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-openapi-swagger/agent/agent.ts b/e2e/fixtures/agent-openapi-swagger/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/agent-openapi-swagger/agent/agent.ts +++ b/e2e/fixtures/agent-openapi-swagger/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-schedules/agent/agent.ts b/e2e/fixtures/agent-schedules/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/agent-schedules/agent/agent.ts +++ b/e2e/fixtures/agent-schedules/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-session-limits/agent/agent.ts b/e2e/fixtures/agent-session-limits/agent/agent.ts index a832d3338..c9cad500f 100644 --- a/e2e/fixtures/agent-session-limits/agent/agent.ts +++ b/e2e/fixtures/agent-session-limits/agent/agent.ts @@ -3,7 +3,6 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", // A one-token input budget guarantees every completed model call crosses // the limit, so the next conversation turn deterministically parks on the // session-limit continuation prompt. diff --git a/e2e/fixtures/agent-skills/agent/agent.ts b/e2e/fixtures/agent-skills/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/agent-skills/agent/agent.ts +++ b/e2e/fixtures/agent-skills/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-subagents-hitl/agent/agent.ts b/e2e/fixtures/agent-subagents-hitl/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/agent-subagents-hitl/agent/agent.ts +++ b/e2e/fixtures/agent-subagents-hitl/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-subagents/agent/agent.ts b/e2e/fixtures/agent-subagents/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/agent-subagents/agent/agent.ts +++ b/e2e/fixtures/agent-subagents/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts b/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts index 903467432..3b81e2012 100644 --- a/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts +++ b/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts @@ -9,5 +9,4 @@ import { defineAgent } from "eve"; */ export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", }); diff --git a/e2e/fixtures/agent-tools-hitl/agent/agent.ts b/e2e/fixtures/agent-tools-hitl/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/agent-tools-hitl/agent/agent.ts +++ b/e2e/fixtures/agent-tools-hitl/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools-sandbox/agent/agent.ts b/e2e/fixtures/agent-tools-sandbox/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/agent-tools-sandbox/agent/agent.ts +++ b/e2e/fixtures/agent-tools-sandbox/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools/agent/agent.ts b/e2e/fixtures/agent-tools/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/agent-tools/agent/agent.ts +++ b/e2e/fixtures/agent-tools/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/dist-extensions/agent/agent.ts b/e2e/fixtures/dist-extensions/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/dist-extensions/agent/agent.ts +++ b/e2e/fixtures/dist-extensions/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/e2e-config/src/index.ts b/e2e/fixtures/e2e-config/src/index.ts index 7a8942be6..500b394e3 100644 --- a/e2e/fixtures/e2e-config/src/index.ts +++ b/e2e/fixtures/e2e-config/src/index.ts @@ -1,17 +1,19 @@ import type { AgentDefinition } from "eve"; -type E2EAgentConfig = Pick; +type E2EAgentConfig = Pick; /** * Returns the harness-owned configuration shared by e2e fixture root agents. */ export function e2eAgentConfig(): E2EAgentConfig { + const model = process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol"; const workflowWorld = process.env.EVE_E2E_WORKFLOW_WORLD; if (workflowWorld === undefined) { - return {}; + return { model }; } return { + model, experimental: { workflow: { world: workflowWorld } }, }; } diff --git a/e2e/fixtures/extensions/agent/agent.ts b/e2e/fixtures/extensions/agent/agent.ts index 465271af8..384bb0e2a 100644 --- a/e2e/fixtures/extensions/agent/agent.ts +++ b/e2e/fixtures/extensions/agent/agent.ts @@ -3,6 +3,5 @@ import { defineAgent } from "eve"; export default defineAgent({ ...e2eAgentConfig(), - model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); From 0707afcef2d3ec171d54a5499f09af857ff85c2f Mon Sep 17 00:00:00 2001 From: Andrew Barba Date: Wed, 29 Jul 2026 20:50:31 -0400 Subject: [PATCH 4/5] chore(e2e): split model and workflow world coverage Signed-off-by: Andrew Barba --- .changeset/focused-e2e-world-models.md | 5 + .github/scripts/discover-e2e-fixtures.mjs | 334 ++++++++++++++ .github/scripts/discover-e2e-fixtures.sh | 33 +- .github/workflows/e2e-local.yml | 146 ++++-- .github/workflows/e2e-postgres.yml | 42 +- .github/workflows/e2e-vercel.yml | 83 ++-- CONTRIBUTING.md | 28 +- e2e/README.md | 284 +++++++----- .../evals/runtime/image-attachment.eval.ts | 6 +- .../cancellation/cancel-subagent.eval.ts | 4 +- .../agent/agent.ts | 2 - .../agent-compaction-regressions/package.json | 2 - .../dynamic-model/turn-selection.eval.ts | 2 +- .../agent-prompt-cache/agent/agent.ts | 2 - e2e/fixtures/agent-prompt-cache/package.json | 2 - .../agent-tools-hitl-openai/agent/agent.ts | 3 +- .../agent-tools-hitl-openai/package.json | 2 - e2e/fixtures/agent-tools-hitl/agent/agent.ts | 3 +- e2e/fixtures/agent-tools-hitl/package.json | 2 - .../evals/sandbox/redeploy.eval.ts | 23 +- e2e/fixtures/agent-tools/agent/agent.ts | 3 +- e2e/fixtures/agent-tools/package.json | 2 - e2e/suites.json | 73 +++ .../runtime/agent/mock-model-adapter.test.ts | 427 ++++++++++++++++++ .../src/runtime/agent/mock-model-adapter.ts | 341 ++++++++++---- .../src/runtime/agent/mock-model-fixtures.ts | 198 +++++++- .../src/runtime/agent/mock-model-programs.ts | 366 +++++++++++++++ pnpm-lock.yaml | 30 -- 28 files changed, 2047 insertions(+), 401 deletions(-) create mode 100644 .changeset/focused-e2e-world-models.md create mode 100644 .github/scripts/discover-e2e-fixtures.mjs create mode 100644 e2e/suites.json create mode 100644 packages/eve/src/runtime/agent/mock-model-programs.ts diff --git a/.changeset/focused-e2e-world-models.md b/.changeset/focused-e2e-world-models.md new file mode 100644 index 000000000..f41d650ee --- /dev/null +++ b/.changeset/focused-e2e-world-models.md @@ -0,0 +1,5 @@ +--- +"eve": patch +--- + +Expand the internal deterministic model adapter for world-focused e2e coverage, including subagent, repeated-tool, fan-out, silent-completion, and schema-derived tool-input programs. Authored `eve-mock/*` models remain intact when automatic model replacement is enabled. diff --git a/.github/scripts/discover-e2e-fixtures.mjs b/.github/scripts/discover-e2e-fixtures.mjs new file mode 100644 index 000000000..ea294c3b7 --- /dev/null +++ b/.github/scripts/discover-e2e-fixtures.mjs @@ -0,0 +1,334 @@ +#!/usr/bin/env node + +import { appendFile, readFile, readdir, stat } from "node:fs/promises"; +import { basename, join } from "node:path"; + +const FIXTURE_ROOTS = ["e2e/fixtures", "apps/fixtures"]; +const MANIFEST_PATH = "e2e/suites.json"; +const EVAL_SOURCE_FILE_PATTERN = /\.[cm]?[jt]sx?$/u; +const JUDGE_USAGE_PATTERN = /\bt\s*\.\s*judge\b/u; +const MODEL_ALIAS_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u; + +function fail(message) { + throw new Error(message); +} + +function isRecord(value) { + return value !== null && typeof value === "object" && !Array.isArray(value); +} + +async function isDirectory(path) { + try { + return (await stat(path)).isDirectory(); + } catch (error) { + if (error?.code === "ENOENT") { + return false; + } + throw error; + } +} + +async function discoverFixtures() { + const fixtureDirs = []; + + for (const root of FIXTURE_ROOTS) { + if (!(await isDirectory(root))) { + continue; + } + + for (const entry of await readdir(root, { withFileTypes: true })) { + if (!entry.isDirectory()) { + continue; + } + + const fixtureDir = join(root, entry.name); + if (await isDirectory(join(fixtureDir, "evals"))) { + fixtureDirs.push(fixtureDir); + } + } + } + + return fixtureDirs.sort(); +} + +async function walkEvalSourceFiles(directory) { + const files = []; + + for (const entry of await readdir(directory, { withFileTypes: true })) { + const path = join(directory, entry.name); + if (entry.isDirectory()) { + files.push(...(await walkEvalSourceFiles(path))); + } else if (entry.isFile() && EVAL_SOURCE_FILE_PATTERN.test(entry.name)) { + files.push(path); + } + } + + return files; +} + +async function assertNoJudgeUsage(fixtureDir) { + for (const path of await walkEvalSourceFiles(join(fixtureDir, "evals"))) { + const source = await readFile(path, "utf8"); + if (JUDGE_USAGE_PATTERN.test(stripCommentsAndStringLiterals(source))) { + fail(`World-suite fixture ${fixtureDir} uses t.judge in ${path}.`); + } + } +} + +function stripCommentsAndStringLiterals(source) { + let code = ""; + let state = "code"; + let templateExpressionDepth = 0; + + for (let index = 0; index < source.length; index += 1) { + const character = source[index]; + const next = source[index + 1]; + + if (state === "code") { + if (templateExpressionDepth > 0 && character === "{") { + code += character; + templateExpressionDepth += 1; + } else if (templateExpressionDepth > 0 && character === "}") { + templateExpressionDepth -= 1; + code += templateExpressionDepth === 0 ? " " : character; + if (templateExpressionDepth === 0) { + state = "template"; + } + } else if (character === "/" && next === "/") { + code += " "; + state = "line-comment"; + index += 1; + } else if (character === "/" && next === "*") { + code += " "; + state = "block-comment"; + index += 1; + } else if (character === "`") { + code += " "; + state = "template"; + } else if (character === "'" || character === '"') { + code += " "; + state = character; + } else { + code += character; + } + continue; + } + + if (state === "template") { + if (character === "\\") { + code += " "; + if (next !== undefined) { + code += next === "\n" ? "\n" : " "; + index += 1; + } + } else if (character === "`") { + code += " "; + state = "code"; + } else if (character === "$" && next === "{") { + code += " "; + state = "code"; + templateExpressionDepth = 1; + index += 1; + } else { + code += character === "\n" ? "\n" : " "; + } + continue; + } + + if (state === "line-comment") { + if (character === "\n") { + code += "\n"; + state = "code"; + } else { + code += " "; + } + continue; + } + + if (state === "block-comment") { + if (character === "*" && next === "/") { + code += " "; + state = "code"; + index += 1; + } else { + code += character === "\n" ? "\n" : " "; + } + continue; + } + + if (character === "\\") { + code += " "; + if (next !== undefined) { + code += next === "\n" ? "\n" : " "; + index += 1; + } + } else if (character === state) { + code += " "; + state = "code"; + } else { + code += character === "\n" ? "\n" : " "; + } + } + + return code; +} + +function validateModelAliases(value) { + if (!isRecord(value) || Object.keys(value).length === 0) { + fail(`${MANIFEST_PATH} must define a non-empty modelAliases object.`); + } + + for (const [alias, modelId] of Object.entries(value)) { + if ( + !MODEL_ALIAS_PATTERN.test(alias) || + typeof modelId !== "string" || + modelId.trim().length === 0 + ) { + fail(`Invalid model alias ${JSON.stringify(alias)} in ${MANIFEST_PATH}.`); + } + } + + return value; +} + +function validateFixtureAssignment(fixtureDir, value, modelAliases) { + if (!isRecord(value)) { + fail(`Fixture assignment for ${fixtureDir} must be an object.`); + } + + if (value.suite === "worlds") { + const keys = Object.keys(value); + if (keys.length !== 1 || keys[0] !== "suite") { + fail(`World-suite fixture ${fixtureDir} must use exactly {"suite":"worlds"}.`); + } + return value; + } + + if (value.suite === "models") { + const keys = Object.keys(value).sort(); + if (keys.length !== 2 || keys[0] !== "models" || keys[1] !== "suite") { + fail(`Model-suite fixture ${fixtureDir} must contain only suite and models.`); + } + if (!Array.isArray(value.models) || value.models.length === 0) { + fail(`Model-suite fixture ${fixtureDir} must select at least one model alias.`); + } + + const uniqueModels = new Set(value.models); + if (uniqueModels.size !== value.models.length) { + fail(`Model-suite fixture ${fixtureDir} contains duplicate model aliases.`); + } + for (const alias of value.models) { + if (typeof alias !== "string" || !Object.hasOwn(modelAliases, alias)) { + fail(`Model-suite fixture ${fixtureDir} references invalid model alias ${String(alias)}.`); + } + } + return value; + } + + fail(`Fixture ${fixtureDir} has invalid suite ${JSON.stringify(value.suite)}.`); +} + +async function emitOutput(name, value) { + const line = `${name}=${JSON.stringify(value)}\n`; + const outputPath = process.env.GITHUB_OUTPUT; + + if (outputPath === undefined || outputPath.length === 0) { + process.stdout.write(line); + } else { + await appendFile(outputPath, line); + } +} + +async function main() { + const discoveredDirs = await discoverFixtures(); + if (discoveredDirs.length === 0) { + fail("No e2e fixtures with an evals/ directory were found."); + } + + const manifest = JSON.parse(await readFile(MANIFEST_PATH, "utf8")); + if (!isRecord(manifest)) { + fail(`${MANIFEST_PATH} must contain an object.`); + } + const manifestKeys = Object.keys(manifest).sort(); + if ( + manifestKeys.length !== 2 || + manifestKeys[0] !== "fixtures" || + manifestKeys[1] !== "modelAliases" + ) { + fail(`${MANIFEST_PATH} must contain exactly modelAliases and fixtures.`); + } + + const modelAliases = validateModelAliases(manifest.modelAliases); + if (!isRecord(manifest.fixtures)) { + fail(`${MANIFEST_PATH} must define a fixtures object keyed by fixture path.`); + } + + const discoveredSet = new Set(discoveredDirs); + const configuredDirs = Object.keys(manifest.fixtures).sort(); + const missingAssignments = discoveredDirs.filter((dir) => !(dir in manifest.fixtures)); + const staleAssignments = configuredDirs.filter((dir) => !discoveredSet.has(dir)); + + if (missingAssignments.length > 0) { + fail(`Fixtures missing from ${MANIFEST_PATH}: ${missingAssignments.join(", ")}`); + } + if (staleAssignments.length > 0) { + fail(`Stale fixture assignments in ${MANIFEST_PATH}: ${staleAssignments.join(", ")}`); + } + + const names = new Map(); + for (const dir of discoveredDirs) { + const name = basename(dir); + const previousDir = names.get(name); + if (previousDir !== undefined) { + fail(`Duplicate fixture name ${name}: ${previousDir} and ${dir}`); + } + names.set(name, dir); + } + + const modelInclude = []; + const worldInclude = []; + + for (const fixtureDir of discoveredDirs) { + const fixtureName = basename(fixtureDir); + const assignment = validateFixtureAssignment( + fixtureDir, + manifest.fixtures[fixtureDir], + modelAliases, + ); + + if (assignment.suite === "worlds") { + await assertNoJudgeUsage(fixtureDir); + worldInclude.push({ + fixture_dir: fixtureDir, + fixture_name: fixtureName, + }); + continue; + } + + for (const modelName of assignment.models) { + modelInclude.push({ + fixture_dir: fixtureDir, + fixture_name: fixtureName, + model_id: modelAliases[modelName], + model_name: modelName, + }); + } + } + + if (modelInclude.length === 0 || worldInclude.length === 0) { + fail("Both the models and worlds suites must contain at least one fixture."); + } + + const modelMatrix = { include: modelInclude }; + const worldMatrix = { include: worldInclude }; + console.log( + `Discovered ${modelInclude.length} model leg(s) and ${worldInclude.length} world fixture(s).`, + ); + await emitOutput("model_matrix", modelMatrix); + await emitOutput("world_matrix", worldMatrix); +} + +main().catch((error) => { + console.error(error instanceof Error ? error.message : error); + process.exitCode = 1; +}); diff --git a/.github/scripts/discover-e2e-fixtures.sh b/.github/scripts/discover-e2e-fixtures.sh index 4b3918f8b..e8a6f3aec 100755 --- a/.github/scripts/discover-e2e-fixtures.sh +++ b/.github/scripts/discover-e2e-fixtures.sh @@ -1,34 +1,5 @@ #!/usr/bin/env bash -# Discover e2e fixture directories for the CI matrix. -# -# A fixture qualifies when it has an `evals/` directory under one of the -# fixture roots. Emits a JSON array of `{ name, dir }` objects (sorted by dir) -# to the `matrix` GitHub Actions output for the workflow's `fixture` axis. +# Discover and validate the model and workflow-world e2e suites. set -euo pipefail -roots=("e2e/fixtures" "apps/fixtures") - -entries=() -while IFS= read -r evals_dir; do - dir="${evals_dir%/evals}" - name="$(basename "$dir")" - entries+=("{\"name\":\"${name}\",\"dir\":\"${dir}\"}") -done < <( - for root in "${roots[@]}"; do - [ -d "$root" ] || continue - find "$root" -mindepth 2 -maxdepth 2 -type d -name evals - done | sort -) - -if [ "${#entries[@]}" -eq 0 ]; then - echo "No e2e fixtures with an evals/ directory were found." >&2 - exit 1 -fi - -matrix="[$( - IFS=, - echo "${entries[*]}" -)]" - -echo "Discovered fixtures: ${matrix}" -echo "matrix=${matrix}" >>"${GITHUB_OUTPUT:-/dev/stdout}" +node .github/scripts/discover-e2e-fixtures.mjs diff --git a/.github/workflows/e2e-local.yml b/.github/workflows/e2e-local.yml index c76c03635..0bc64ee44 100644 --- a/.github/workflows/e2e-local.yml +++ b/.github/workflows/e2e-local.yml @@ -13,8 +13,8 @@ jobs: # every PR. An `on.pull_request.paths` filter would leave them permanently # "expected" on PRs that don't touch e2e-relevant paths, blocking merge. # Instead the workflow always triggers, this job decides relevance, and the - # matrix jobs skip when nothing relevant changed — skipped required checks - # count as satisfied. + # stable aggregate below succeeds without starting matrix legs when nothing + # relevant changed. changes: name: changes runs-on: ubuntu-latest @@ -36,7 +36,7 @@ jobs: fi # HEAD is the PR merge commit; HEAD^1 is the base branch tip, so # this diff is exactly the PR's changed files. - if git diff --name-only HEAD^1 HEAD | grep -qE '^(packages/eve/|apps/fixtures/|e2e/|pnpm-workspace\.yaml$|pnpm-lock\.yaml$|\.github/workflows/e2e-local\.yml$|\.github/scripts/discover-e2e-fixtures\.sh$)'; then + if git diff --name-only HEAD^1 HEAD | grep -qE '^(packages/eve/|apps/fixtures/|e2e/|pnpm-workspace\.yaml$|pnpm-lock\.yaml$|\.github/workflows/e2e-local\.yml$|\.github/scripts/discover-e2e-fixtures\.(sh|mjs)$)'; then echo "relevant=true" >> "$GITHUB_OUTPUT" else echo "relevant=false" >> "$GITHUB_OUTPUT" @@ -46,7 +46,8 @@ jobs: name: discover-fixtures runs-on: ubuntu-latest outputs: - matrix: ${{ steps.discover.outputs.matrix }} + model_matrix: ${{ steps.discover.outputs.model_matrix }} + world_matrix: ${{ steps.discover.outputs.world_matrix }} steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -57,58 +58,44 @@ jobs: id: discover run: .github/scripts/discover-e2e-fixtures.sh - e2e: - name: e2e-local (${{ matrix.fixture.name }}, ${{ matrix.model.name }}) + e2e-models: + name: e2e-models-local (${{ matrix.fixture_name }}, ${{ matrix.model_name }}) runs-on: ubuntu-latest needs: [changes, discover-fixtures] - # No job-level `if`: the stable aggregate check below requires a successful - # matrix result. Guarding each step lets an irrelevant diff satisfy it in - # seconds without running setup or evals. + if: needs.changes.outputs.relevant == 'true' strategy: fail-fast: false - matrix: - fixture: ${{ fromJSON(needs.discover-fixtures.outputs.matrix) }} - model: - - name: openai-sol - id: openai/gpt-5.6-sol - - name: anthropic-opus - id: anthropic/claude-opus-5 + matrix: ${{ fromJSON(needs.discover-fixtures.outputs.model_matrix) }} env: AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }} - EVE_E2E_MODEL: ${{ matrix.model.id }} + EVE_E2E_MODEL: ${{ matrix.model_id }} EVE_EVAL_JUNIT_DIR: ${{ github.workspace }}/.junit steps: - name: Checkout code - if: needs.changes.outputs.relevant == 'true' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: Setup pnpm - if: needs.changes.outputs.relevant == 'true' uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6 - name: Setup Node.js - if: needs.changes.outputs.relevant == 'true' uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version-file: .nvmrc cache: "pnpm" - name: Install dependencies - if: needs.changes.outputs.relevant == 'true' run: pnpm install --frozen-lockfile - name: Build eve package - if: needs.changes.outputs.relevant == 'true' # Full build, not build:js: the deployed/runtime bundles must carry the # stamped package version (scripts/stamp-version-tokens.mjs) and docs. run: pnpm --filter eve run build - name: Build extension fixtures - if: needs.changes.outputs.relevant == 'true' # Extension fixtures ship no committed `dist/`; produce it here so # consuming fixtures resolve the built artifacts. `--if-present` skips # extension fixtures without a build script. The update re-packs the @@ -119,7 +106,6 @@ jobs: pnpm --filter dist-extensions update gizmo-extension gadget-extension - name: Stage workspace extension fixtures as dist-only - if: needs.changes.outputs.relevant == 'true' # Removing author source proves the workspace consumer discovers and # compiles the same agent-shaped dist trees we publish. Toolkit covers # the rich TypeScript surface; js-only covers pure JavaScript authoring. @@ -128,18 +114,93 @@ jobs: mv e2e/fixtures/js-only-extension/extension "$RUNNER_TEMP/js-only-extension-source" - name: Run fixture evals - if: needs.changes.outputs.relevant == 'true' run: | mkdir -p "$EVE_EVAL_JUNIT_DIR" - cd "${{ matrix.fixture.dir }}" + cd "${{ matrix.fixture_dir }}" pnpm exec eve eval --strict --verbose \ - --junit "$EVE_EVAL_JUNIT_DIR/${{ matrix.fixture.name }}-${{ matrix.model.name }}.xml" + --junit "$EVE_EVAL_JUNIT_DIR/models-local-${{ matrix.fixture_name }}-${{ matrix.model_name }}.xml" - name: Upload eval artifacts - if: (failure()) && needs.changes.outputs.relevant == 'true' + if: failure() uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v6 with: - name: eval-artifacts-${{ matrix.fixture.name }}-${{ matrix.model.name }} + name: eval-artifacts-models-local-${{ matrix.fixture_name }}-${{ matrix.model_name }} + path: | + .junit + e2e/fixtures/*/.eve/evals + apps/fixtures/*/.eve/evals + include-hidden-files: true + if-no-files-found: ignore + retention-days: 7 + + e2e-worlds: + name: e2e-worlds-local (${{ matrix.fixture_name }}, mock) + runs-on: ubuntu-latest + needs: [changes, discover-fixtures] + if: needs.changes.outputs.relevant == 'true' + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.discover-fixtures.outputs.world_matrix) }} + + env: + AI_GATEWAY_API_KEY: invalid-e2e-world-suite-key + EVE_E2E_MODEL: openai/gpt-5.6-sol + EVE_EVAL_JUNIT_DIR: ${{ github.workspace }}/.junit + EVE_MOCK_AUTHORED_MODELS: "1" + + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Setup pnpm + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6 + + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + with: + node-version-file: .nvmrc + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build eve package + # Full build, not build:js: the deployed/runtime bundles must carry the + # stamped package version (scripts/stamp-version-tokens.mjs) and docs. + run: pnpm --filter eve run build + + - name: Build extension fixtures + # Extension fixtures ship no committed `dist/`; produce it here so + # consuming fixtures resolve the built artifacts. `--if-present` skips + # extension fixtures without a build script. The update re-packs the + # `file:`-protocol store copies so they pick up the fresh dist — + # a plain reinstall short-circuits and leaves them stale. + run: | + pnpm --filter "./e2e/fixtures/*-extension" run --if-present build + pnpm --filter dist-extensions update gizmo-extension gadget-extension + + - name: Stage workspace extension fixtures as dist-only + # Removing author source proves the workspace consumer discovers and + # compiles the same agent-shaped dist trees we publish. Toolkit covers + # the rich TypeScript surface; js-only covers pure JavaScript authoring. + run: | + mv e2e/fixtures/toolkit-extension/extension "$RUNNER_TEMP/toolkit-extension-source" + mv e2e/fixtures/js-only-extension/extension "$RUNNER_TEMP/js-only-extension-source" + + - name: Run fixture evals + run: | + mkdir -p "$EVE_EVAL_JUNIT_DIR" + cd "${{ matrix.fixture_dir }}" + pnpm exec eve eval --strict --verbose \ + --junit "$EVE_EVAL_JUNIT_DIR/worlds-local-${{ matrix.fixture_name }}-mock.xml" + + - name: Upload eval artifacts + if: failure() + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v6 + with: + name: eval-artifacts-worlds-local-${{ matrix.fixture_name }}-mock path: | .junit e2e/fixtures/*/.eve/evals @@ -151,14 +212,31 @@ jobs: e2e-required: name: e2e-local runs-on: ubuntu-latest - needs: [e2e] + needs: [changes, discover-fixtures, e2e-models, e2e-worlds] if: always() steps: - - name: Require successful e2e matrix + - name: Require successful e2e suites when relevant env: - E2E_RESULT: ${{ needs.e2e.result }} + CHANGES_RESULT: ${{ needs.changes.result }} + DISCOVERY_RESULT: ${{ needs.discover-fixtures.result }} + MODEL_RESULT: ${{ needs.e2e-models.result }} + RELEVANT: ${{ needs.changes.outputs.relevant }} + WORLD_RESULT: ${{ needs.e2e-worlds.result }} run: | - if [ "$E2E_RESULT" != "success" ]; then - echo "E2E matrix result: $E2E_RESULT" + if [ "$CHANGES_RESULT" != "success" ]; then + echo "Change detection result: $CHANGES_RESULT" + exit 1 + fi + if [ "$DISCOVERY_RESULT" != "success" ]; then + echo "Fixture discovery result: $DISCOVERY_RESULT" + exit 1 + fi + if [ "$RELEVANT" != "true" ]; then + echo "No local e2e-relevant changes." + exit 0 + fi + if [ "$MODEL_RESULT" != "success" ] || [ "$WORLD_RESULT" != "success" ]; then + echo "Model suite result: $MODEL_RESULT" + echo "World suite result: $WORLD_RESULT" exit 1 fi diff --git a/.github/workflows/e2e-postgres.yml b/.github/workflows/e2e-postgres.yml index d686c2e26..c54e35ed7 100644 --- a/.github/workflows/e2e-postgres.yml +++ b/.github/workflows/e2e-postgres.yml @@ -33,7 +33,7 @@ jobs: fi # HEAD is the PR merge commit; HEAD^1 is the base branch tip, so # this diff is exactly the PR's changed files. - if git diff --name-only HEAD^1 HEAD | grep -qE '^(packages/eve/|apps/fixtures/|e2e/|pnpm-workspace\.yaml$|pnpm-lock\.yaml$|\.github/workflows/e2e-postgres\.yml$|\.github/scripts/discover-e2e-fixtures\.sh$)'; then + if git diff --name-only HEAD^1 HEAD | grep -qE '^(packages/eve/|apps/fixtures/|e2e/|pnpm-workspace\.yaml$|pnpm-lock\.yaml$|\.github/workflows/e2e-postgres\.yml$|\.github/scripts/discover-e2e-fixtures\.(sh|mjs)$)'; then echo "relevant=true" >> "$GITHUB_OUTPUT" else echo "relevant=false" >> "$GITHUB_OUTPUT" @@ -43,7 +43,7 @@ jobs: name: discover-fixtures runs-on: ubuntu-latest outputs: - matrix: ${{ steps.discover.outputs.matrix }} + world_matrix: ${{ steps.discover.outputs.world_matrix }} steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -54,20 +54,14 @@ jobs: id: discover run: .github/scripts/discover-e2e-fixtures.sh - e2e: - name: e2e-postgres (${{ matrix.fixture.name }}, ${{ matrix.model.name }}) + e2e-worlds: + name: e2e-worlds-postgres (${{ matrix.fixture_name }}, mock) runs-on: ubuntu-latest needs: [changes, discover-fixtures] if: needs.changes.outputs.relevant == 'true' strategy: fail-fast: false - matrix: - fixture: ${{ fromJSON(needs.discover-fixtures.outputs.matrix) }} - model: - - name: openai-sol - id: openai/gpt-5.6-sol - - name: anthropic-opus - id: anthropic/claude-opus-5 + matrix: ${{ fromJSON(needs.discover-fixtures.outputs.world_matrix) }} services: postgres: @@ -85,10 +79,11 @@ jobs: --health-retries 12 env: - AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }} - EVE_E2E_MODEL: ${{ matrix.model.id }} + AI_GATEWAY_API_KEY: invalid-e2e-world-suite-key + EVE_E2E_MODEL: openai/gpt-5.6-sol EVE_E2E_WORKFLOW_WORLD: "@workflow/world-postgres" EVE_EVAL_JUNIT_DIR: ${{ github.workspace }}/.junit + EVE_MOCK_AUTHORED_MODELS: "1" WORKFLOW_POSTGRES_MAX_POOL_SIZE: "52" WORKFLOW_POSTGRES_URL: postgres://world:world@127.0.0.1:5432/world WORKFLOW_POSTGRES_WORKER_CONCURRENCY: "50" @@ -133,7 +128,7 @@ jobs: mv e2e/fixtures/js-only-extension/extension "$RUNNER_TEMP/js-only-extension-source" - name: Bootstrap Workflow Postgres schema - working-directory: ${{ matrix.fixture.dir }} + working-directory: ${{ matrix.fixture_dir }} run: pnpm exec bootstrap - name: Build fixture, start production server, and run evals @@ -142,11 +137,11 @@ jobs: run: | set -euo pipefail mkdir -p "$EVE_EVAL_JUNIT_DIR" - cd "${{ matrix.fixture.dir }}" + cd "${{ matrix.fixture_dir }}" pnpm exec eve build - server_log="$EVE_EVAL_JUNIT_DIR/${{ matrix.fixture.name }}-${{ matrix.model.name }}-server.log" + server_log="$EVE_EVAL_JUNIT_DIR/worlds-postgres-${{ matrix.fixture_name }}-mock-server.log" pnpm exec eve start --host 127.0.0.1 --port 3000 >"$server_log" 2>&1 & server_pid=$! @@ -177,7 +172,7 @@ jobs: if ! pnpm exec eve eval --strict --verbose \ --url http://127.0.0.1:3000 \ - --junit "$EVE_EVAL_JUNIT_DIR/${{ matrix.fixture.name }}-${{ matrix.model.name }}.xml"; then + --junit "$EVE_EVAL_JUNIT_DIR/worlds-postgres-${{ matrix.fixture_name }}-mock.xml"; then cat "$server_log" exit 1 fi @@ -198,7 +193,7 @@ jobs: if: failure() uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v6 with: - name: eval-artifacts-postgres-${{ matrix.fixture.name }}-${{ matrix.model.name }} + name: eval-artifacts-worlds-postgres-${{ matrix.fixture_name }}-mock path: | .junit e2e/fixtures/*/.eve/evals @@ -210,24 +205,29 @@ jobs: e2e-required: name: e2e-postgres runs-on: ubuntu-latest - needs: [changes, e2e] + needs: [changes, discover-fixtures, e2e-worlds] if: always() steps: - name: Require successful e2e matrix when relevant env: CHANGES_RESULT: ${{ needs.changes.result }} - E2E_RESULT: ${{ needs.e2e.result }} + DISCOVERY_RESULT: ${{ needs.discover-fixtures.result }} + E2E_RESULT: ${{ needs.e2e-worlds.result }} RELEVANT: ${{ needs.changes.outputs.relevant }} run: | if [ "$CHANGES_RESULT" != "success" ]; then echo "Change detection result: $CHANGES_RESULT" exit 1 fi + if [ "$DISCOVERY_RESULT" != "success" ]; then + echo "Fixture discovery result: $DISCOVERY_RESULT" + exit 1 + fi if [ "$RELEVANT" != "true" ]; then echo "No Postgres e2e-relevant changes." exit 0 fi if [ "$E2E_RESULT" != "success" ]; then - echo "E2E matrix result: $E2E_RESULT" + echo "World suite result: $E2E_RESULT" exit 1 fi diff --git a/.github/workflows/e2e-vercel.yml b/.github/workflows/e2e-vercel.yml index 21d5518ee..52a094fa4 100644 --- a/.github/workflows/e2e-vercel.yml +++ b/.github/workflows/e2e-vercel.yml @@ -13,8 +13,8 @@ jobs: # every PR. An `on.pull_request.paths` filter would leave them permanently # "expected" on PRs that don't touch e2e-relevant paths, blocking merge. # Instead the workflow always triggers, this job decides relevance, and the - # matrix jobs skip when nothing relevant changed — skipped required checks - # count as satisfied. + # stable aggregate below succeeds without starting matrix legs when nothing + # relevant changed. changes: name: changes runs-on: ubuntu-latest @@ -36,7 +36,7 @@ jobs: fi # HEAD is the PR merge commit; HEAD^1 is the base branch tip, so # this diff is exactly the PR's changed files. - if git diff --name-only HEAD^1 HEAD | grep -qE '^(packages/eve/|apps/fixtures/|e2e/|pnpm-workspace\.yaml$|pnpm-lock\.yaml$|scripts/build-profile-report\.mjs$|\.github/workflows/e2e-vercel\.yml$|\.github/scripts/discover-e2e-fixtures\.sh$)'; then + if git diff --name-only HEAD^1 HEAD | grep -qE '^(packages/eve/|apps/fixtures/|e2e/|pnpm-workspace\.yaml$|pnpm-lock\.yaml$|scripts/build-profile-report\.mjs$|\.github/workflows/e2e-vercel\.yml$|\.github/scripts/discover-e2e-fixtures\.(sh|mjs)$)'; then echo "relevant=true" >> "$GITHUB_OUTPUT" else echo "relevant=false" >> "$GITHUB_OUTPUT" @@ -46,7 +46,7 @@ jobs: name: discover-fixtures runs-on: ubuntu-latest outputs: - matrix: ${{ steps.discover.outputs.matrix }} + world_matrix: ${{ steps.discover.outputs.world_matrix }} steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -57,26 +57,20 @@ jobs: id: discover run: .github/scripts/discover-e2e-fixtures.sh - e2e: - name: e2e-vercel (${{ matrix.fixture.name }}, ${{ matrix.model.name }}) + e2e-worlds: + name: e2e-worlds-vercel (${{ matrix.fixture_name }}, mock) runs-on: ubuntu-latest needs: [changes, discover-fixtures] - # No job-level `if`: the stable aggregate check below requires a successful - # matrix result. Guarding each step lets an irrelevant diff satisfy it in - # seconds without running setup or evals. + if: needs.changes.outputs.relevant == 'true' strategy: fail-fast: false - matrix: - fixture: ${{ fromJSON(needs.discover-fixtures.outputs.matrix) }} - model: - - name: openai-sol - id: openai/gpt-5.6-sol - - name: anthropic-opus - id: anthropic/claude-opus-5 + matrix: ${{ fromJSON(needs.discover-fixtures.outputs.world_matrix) }} env: - EVE_E2E_MODEL: ${{ matrix.model.id }} + AI_GATEWAY_API_KEY: invalid-e2e-world-suite-key + EVE_E2E_MODEL: openai/gpt-5.6-sol EVE_EVAL_JUNIT_DIR: ${{ github.workspace }}/.junit + EVE_MOCK_AUTHORED_MODELS: "1" VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} @@ -84,34 +78,28 @@ jobs: steps: - name: Checkout code - if: needs.changes.outputs.relevant == 'true' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: Setup pnpm - if: needs.changes.outputs.relevant == 'true' uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6 - name: Setup Node.js - if: needs.changes.outputs.relevant == 'true' uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version-file: .nvmrc cache: "pnpm" - name: Install dependencies - if: needs.changes.outputs.relevant == 'true' run: pnpm install --frozen-lockfile - name: Build eve package - if: needs.changes.outputs.relevant == 'true' # Full build, not build:js: the deployed/runtime bundles must carry the # stamped package version (scripts/stamp-version-tokens.mjs) and docs. run: pnpm --filter eve run build - name: Build extension fixtures - if: needs.changes.outputs.relevant == 'true' # Extension fixtures ship no committed `dist/`; produce it here so # consuming fixtures resolve the built artifacts. `--if-present` skips # extension fixtures without a build script. The update re-packs the @@ -122,7 +110,6 @@ jobs: pnpm --filter dist-extensions update gizmo-extension gadget-extension - name: Stage workspace extension fixtures as dist-only - if: needs.changes.outputs.relevant == 'true' # Removing author source proves the deployment consumes the same # agent-shaped dist trees registry packages ship. Toolkit covers the # rich TypeScript surface; js-only covers pure JavaScript authoring. @@ -131,13 +118,12 @@ jobs: mv e2e/fixtures/js-only-extension/extension "$RUNNER_TEMP/js-only-extension-source" - name: Deploy fixture and run evals - if: needs.changes.outputs.relevant == 'true' env: - EVE_BUILD_PROFILE: ${{ runner.temp }}/eve-build-profile-${{ matrix.fixture.name }}-${{ matrix.model.name }}.json + EVE_BUILD_PROFILE: ${{ runner.temp }}/eve-build-profile-worlds-vercel-${{ matrix.fixture_name }}-mock.json run: | set -euo pipefail mkdir -p "$EVE_EVAL_JUNIT_DIR" - cd "${{ matrix.fixture.dir }}" + cd "${{ matrix.fixture_dir }}" token_args=() if [ -n "${VERCEL_TOKEN:-}" ]; then @@ -161,10 +147,13 @@ jobs: VERCEL_PROJECT_ID="$VERCEL_PROJECT_ID" \ pnpm exec eve build --profile "$EVE_BUILD_PROFILE" DEPLOYMENT_URL="$(pnpm exec vc deploy --prebuilt --yes --target=preview \ - --env "EVE_E2E_MODEL=$EVE_E2E_MODEL" "${token_args[@]}" | tail -n 1)" + --env "AI_GATEWAY_API_KEY=$AI_GATEWAY_API_KEY" \ + --env "EVE_E2E_MODEL=$EVE_E2E_MODEL" \ + --env "EVE_MOCK_AUTHORED_MODELS=$EVE_MOCK_AUTHORED_MODELS" \ + "${token_args[@]}" | tail -n 1)" npx eve eval --strict --verbose --url "$DEPLOYMENT_URL" \ - --junit "$EVE_EVAL_JUNIT_DIR/${{ matrix.fixture.name }}-${{ matrix.model.name }}.xml" + --junit "$EVE_EVAL_JUNIT_DIR/worlds-vercel-${{ matrix.fixture_name }}-mock.xml" # Redeploy-tagged evals rebuild and redeploy the fixture from inside # the eval body, repointing a run-scoped alias at each new @@ -172,21 +161,20 @@ jobs: # never change what they serve) and are skipped in the main suite # above because EVE_E2E_REDEPLOY_ALIAS is unset there. if npx eve eval --tag redeploy --list >/dev/null 2>&1; then - ALIAS="eve-e2e-${{ matrix.fixture.name }}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-${{ strategy.job-index }}.vercel.app" + ALIAS="eve-e2e-${{ matrix.fixture_name }}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-${{ strategy.job-index }}.vercel.app" # vc alias does not infer the team from the project link the way # link/deploy do, so pass the scope explicitly. pnpm exec vc alias set "$DEPLOYMENT_URL" "$ALIAS" "${token_args[@]}" "${scope_args[@]}" EVE_E2E_REDEPLOY_ALIAS="$ALIAS" \ npx eve eval --tag redeploy --strict --verbose \ --url "https://$ALIAS" \ - --junit "$EVE_EVAL_JUNIT_DIR/${{ matrix.fixture.name }}-${{ matrix.model.name }}-redeploy.xml" + --junit "$EVE_EVAL_JUNIT_DIR/worlds-vercel-${{ matrix.fixture_name }}-mock-redeploy.xml" fi - name: Log deployable build timing - if: needs.changes.outputs.relevant == 'true' env: - BUILD_PROFILE: ${{ runner.temp }}/eve-build-profile-${{ matrix.fixture.name }}-${{ matrix.model.name }}.json - FIXTURE_PATH: ${{ matrix.fixture.dir }} + BUILD_PROFILE: ${{ runner.temp }}/eve-build-profile-worlds-vercel-${{ matrix.fixture_name }}-mock.json + FIXTURE_PATH: ${{ matrix.fixture_dir }} run: | node ./scripts/build-profile-report.mjs \ --profile "$BUILD_PROFILE" \ @@ -196,10 +184,10 @@ jobs: --output-format build-time - name: Upload eval artifacts - if: (failure()) && needs.changes.outputs.relevant == 'true' + if: failure() uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v6 with: - name: eval-artifacts-vercel-${{ matrix.fixture.name }}-${{ matrix.model.name }} + name: eval-artifacts-worlds-vercel-${{ matrix.fixture_name }}-mock path: | .junit e2e/fixtures/*/.eve/evals @@ -211,14 +199,29 @@ jobs: e2e-required: name: e2e-vercel runs-on: ubuntu-latest - needs: [e2e] + needs: [changes, discover-fixtures, e2e-worlds] if: always() steps: - - name: Require successful e2e matrix + - name: Require successful e2e suite when relevant env: - E2E_RESULT: ${{ needs.e2e.result }} + CHANGES_RESULT: ${{ needs.changes.result }} + DISCOVERY_RESULT: ${{ needs.discover-fixtures.result }} + E2E_RESULT: ${{ needs.e2e-worlds.result }} + RELEVANT: ${{ needs.changes.outputs.relevant }} run: | + if [ "$CHANGES_RESULT" != "success" ]; then + echo "Change detection result: $CHANGES_RESULT" + exit 1 + fi + if [ "$DISCOVERY_RESULT" != "success" ]; then + echo "Fixture discovery result: $DISCOVERY_RESULT" + exit 1 + fi + if [ "$RELEVANT" != "true" ]; then + echo "No Vercel e2e-relevant changes." + exit 0 + fi if [ "$E2E_RESULT" != "success" ]; then - echo "E2E matrix result: $E2E_RESULT" + echo "World suite result: $E2E_RESULT" exit 1 fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c8156cbb..bd3b7a669 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,18 +64,28 @@ pnpm test:tui # TUI smoke scripts (not e2e) E2E tests are fixture-owned evals. Run them from the fixture directory: ```bash -cd e2e/fixtures/agent-basic-runtime -pnpm exec eve eval --strict +cd e2e/fixtures/agent-tools +EVE_E2E_MODEL="openai/gpt-5.6-sol" pnpm exec eve eval --strict ``` -The fixture agents and judges run against real models (`openai/gpt-5.5`), so -the environment must provide the corresponding model-provider credentials. +CI splits e2e coverage by the dimension under test. Five provider-sensitive +fixtures form eight live-model legs against the Local world; these require the +credential for their assigned model. The other 15 fixtures run with +deterministic models against the Local, Vercel, and Postgres worlds: + +```bash +cd e2e/fixtures/agent-basic-runtime +EVE_MOCK_AUTHORED_MODELS=1 \ + AI_GATEWAY_API_KEY="invalid-e2e-world-suite-key" \ + pnpm exec eve eval --strict +``` -Vercel e2e builds that same fixture directory with `VERCEL=1`, deploys the -fixture's prebuilt Vercel output, and runs evals against the immutable -deployment URL. All fixture deployments link to the same Vercel project id; the -shared project's Preview env must provide those same model-provider -credentials. +World fixtures cannot use live providers or model judges. The invalid Gateway +credential makes an accidental provider path fail, and CI propagates mock mode +through Vercel deployments and redeployments. Fixture ownership and meaningful +provider assignments live in [`e2e/suites.json`](./e2e/suites.json); see +[`e2e/README.md`](./e2e/README.md) for the complete Local, Vercel, and Postgres +commands. CI intentionally has no full fixture × model × world matrix. Do not commit fixture trees under `packages/eve/test/fixtures/` — scenario app content is defined inline as `ScenarioAppDescriptor` objects under `packages/eve/src/internal/testing/scenario-apps/` (CI enforces this). diff --git a/e2e/README.md b/e2e/README.md index 7b1f5551d..4edd0b6e7 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -3,23 +3,48 @@ End-to-end coverage is fixture-owned `eve eval` runs. The suite only runs fixture eval files from the fixture directory. +CI separates the dimension under test instead of crossing every fixture, +model, and Workflow world: + +- The **model suite** runs provider-sensitive fixtures against the local world. + Its five fixtures expand to eight live-model legs. +- The **world suite** runs the other 15 fixtures with deterministic mock models + against the Local, Vercel, and Postgres worlds, for 45 legs. + +This produces 53 focused legs while retaining every fixture. There is no +nightly, manual, or other full cross-product matrix. + ## Local -Run evals from the fixture directory: +Run a model-suite fixture from its directory with one of its assigned models: ```sh -cd e2e/fixtures/agent-basic-runtime +cd e2e/fixtures/agent-tools EVE_E2E_MODEL="openai/gpt-5.6-sol" pnpm exec eve eval --strict ``` -Every retained e2e eval is deterministic and self-contained. Eval files do -not start external services or require fixture-specific injected env. The CI -harness may provide world-level infrastructure, such as the ephemeral -PostgreSQL service used by the Postgres matrix. Most fixtures use the shared -model-provider credentials; dedicated runtime stress fixtures may use an -authored deterministic model instead. +Model-suite runs require the credential for the selected provider. They use the +local Workflow world so failures exercise model and provider behavior without +also varying deployment infrastructure. -Each retained fixture package also exposes the same command as: +Run a world-suite fixture locally with deterministic authored models: + +```sh +cd e2e/fixtures/agent-basic-runtime +EVE_MOCK_AUTHORED_MODELS=1 \ + AI_GATEWAY_API_KEY="invalid-e2e-world-suite-key" \ + pnpm exec eve eval --strict +``` + +`EVE_MOCK_AUTHORED_MODELS=1` replaces authored provider models with eve's +deterministic mock adapter. Models already authored as `eve-mock/*` remain +intact so fixtures can supply their own deterministic programs. The invalid +Gateway credential is a canary: a regression that escapes the adapter fails +instead of using a live provider. World fixtures cannot use `t.judge`; +discovery rejects that assignment, so their assertions never invoke a live +model judge. + +Each fixture package also exposes its eval command as: ```sh pnpm --filter agent-basic-runtime test:e2e @@ -32,26 +57,101 @@ script: pnpm test:e2e ``` +Use the explicit environment from the examples above when reproducing a +particular CI suite. + +## Suite ownership + +[`suites.json`](./suites.json) assigns every discovered fixture path to exactly +one suite. Its internal CI interface is: + +```json +{ + "modelAliases": { + "openai-sol": "openai/gpt-5.6-sol", + "anthropic-opus": "anthropic/claude-opus-5" + }, + "fixtures": { + "e2e/fixtures/agent-tools": { + "suite": "models", + "models": ["openai-sol", "anthropic-opus"] + }, + "e2e/fixtures/agent-basic-runtime": { + "suite": "worlds" + } + } +} +``` + +Model aliases are stable CI identifiers: + +- `openai-sol` selects `openai/gpt-5.6-sol`. +- `anthropic-opus` selects `anthropic/claude-opus-5`. + +The provider assignments are intentionally narrow and meaningful: + +- `agent-compaction-regressions`: `openai-sol`, `anthropic-opus` +- `agent-prompt-cache`: `anthropic-opus` +- `agent-tools`: `openai-sol`, `anthropic-opus` +- `agent-tools-hitl`: `openai-sol`, `anthropic-opus` +- `agent-tools-hitl-openai`: `openai-sol` + +Those assignments produce the eight Local model legs. Every other fixture is +in the world suite, including `agent-model` and the Vercel redeploy coverage in +`agent-tools-sandbox`. + +Fixture names remain derived from directory names. Discovery fails when a +fixture is missing from the manifest, a manifest path is stale, two paths +derive the same name, a model alias is unknown, or a world fixture contains a +`t.judge` call. + +Run discovery from the repository root to validate the manifest and print the +`model_matrix` and `world_matrix` GitHub Actions outputs: + +```sh +.github/scripts/discover-e2e-fixtures.sh +``` + +When adding e2e coverage: + +- Put the eval in the fixture app's `evals/` directory. +- Add its path to `suites.json` as either a model fixture with explicit model + aliases or a world fixture. +- Choose the model suite only when provider behavior, prompt handling, or model + latency is part of the contract; otherwise choose the world suite. +- Keep it runnable with `eve eval --strict` and deterministic within its suite. +- World fixtures must not use live providers or model judges. +- World fixture root agents spread `e2eAgentConfig()` from + `@eve-e2e/config` and declare `@eve-e2e/config` plus + `@workflow/world-postgres` as direct dependencies. +- Do not add world configuration or Postgres dependencies to model-only + fixtures. + +Fixture discovery accepts `e2e/fixtures/*` and `apps/fixtures/*` apps with an +`evals/` directory. Shared development apps should stay out of the e2e matrix +unless they intentionally own evals. + ## Postgres -Postgres e2e runs the same fixture evals against a self-hosted production -server backed by `@workflow/world-postgres`. Each matrix leg owns an isolated -PostgreSQL service, bootstraps its schema, builds the fixture, starts it with -`eve start`, and targets that server with `eve eval --url`. +Postgres e2e runs the 15 world fixtures against a self-hosted production server +backed by `@workflow/world-postgres`. Each leg owns an isolated PostgreSQL +service, bootstraps its schema, builds the fixture, starts it with `eve start`, +and targets that server with `eve eval --url`. -Fixture root agents spread `e2eAgentConfig()` from the private -`@eve-e2e/config` workspace package. The helper selects the root agent model -from `EVE_E2E_MODEL` and reads `EVE_E2E_WORKFLOW_WORLD` into -`experimental.workflow.world`. The world variable is unset in the local and -Vercel suites, preserving their host defaults; the Postgres workflow sets it -to `@workflow/world-postgres` while compiling the production server. The world -package remains a direct fixture dependency, pinned through the workspace -catalog to the same `@workflow/*` line as eve. +World fixture root agents spread `e2eAgentConfig()` from the private +`@eve-e2e/config` workspace package. The helper reads +`EVE_E2E_WORKFLOW_WORLD` into `experimental.workflow.world`. The variable is +unset in Local and Vercel, preserving their host defaults; Postgres sets it to +`@workflow/world-postgres` while compiling the production server. The world +package is a direct fixture dependency, pinned through the workspace catalog to +the same `@workflow/*` line as eve. The per-fixture lifecycle is: ```sh export EVE_E2E_WORKFLOW_WORLD="@workflow/world-postgres" +export EVE_MOCK_AUTHORED_MODELS="1" +export AI_GATEWAY_API_KEY="invalid-e2e-world-suite-key" export WORKFLOW_POSTGRES_URL="postgres://world:world@127.0.0.1:5432/world" pnpm exec bootstrap @@ -65,109 +165,76 @@ pnpm exec eve eval --strict --url http://127.0.0.1:3000 After the eval succeeds, CI requires at least one row in `workflow.workflow_runs`. This proves the fixture used Postgres rather than silently falling back to the local world. Dev-only schedule dispatch evals -skip against this production target, matching their Vercel behavior; the -local matrix retains that development-route coverage. +skip against this production target, matching their Vercel behavior; the Local +world suite retains that development-route coverage. ## Vercel -Vercel e2e uses the same fixture evals against immutable preview deployment -URLs. All fixture deployments link to the same Vercel project id; isolation -comes from the deployment URL returned by `vc deploy --prebuilt`. +Vercel e2e deploys the 15 world fixtures to immutable preview URLs. All fixture +deployments link to the same Vercel project id; isolation comes from the URL +returned by `vc deploy --prebuilt`. One-time project setup: - Configure the shared Vercel project for Node.js 24. -- Provide the model-provider credentials needed by `EVE_E2E_MODEL` in the - project's Preview environment. - Provide `VERCEL_TOKEN`, `VERCEL_ORG_ID`, and `VERCEL_PROJECT_ID` in CI. -Run a fixture against Vercel from its directory: +The workflow passes mock mode and the invalid Gateway credential to every +initial and in-test redeployment. Provider credentials are not required by the +world suite. + +Run a world fixture against Vercel from its directory: ```sh vc link --yes --project "$VERCEL_PROJECT_ID" vc env pull --yes --environment=preview VERCEL=1 VERCEL_ENV=preview VERCEL_TARGET_ENV=preview \ VERCEL_PROJECT_ID="$VERCEL_PROJECT_ID" \ + EVE_MOCK_AUTHORED_MODELS=1 \ + AI_GATEWAY_API_KEY="invalid-e2e-world-suite-key" \ pnpm exec eve build DEPLOYMENT_URL="$(vc deploy --prebuilt --yes --target=preview \ - --env "EVE_E2E_MODEL=$EVE_E2E_MODEL" | tail -n 1)" + --env "EVE_MOCK_AUTHORED_MODELS=1" \ + --env "AI_GATEWAY_API_KEY=invalid-e2e-world-suite-key" | tail -n 1)" npx eve eval --strict --url "$DEPLOYMENT_URL" ``` Do not set `VERCEL_TEAM_ID` at build: sandbox template keys must derive identically at build and runtime, and Vercel has no team variable at runtime. -### Redeploy suite +### Redeploy coverage `agent-tools-sandbox/evals/sandbox/redeploy.eval.ts` proves sandbox semantics across deployment updates as they behave on preview targets: a parked session -keeps working (with its `/workspace` state intact) when messages route through -a new deployment, its turns stay pinned to the deployment that created it -(branch-less CLI preview deploys cannot resolve a "latest" deployment; see -`shouldRouteToLatestDeployment` in `execution/workflow-runtime.ts`), and new -sessions adopt the new deployment — a skill added by the redeploy loads there. -The pinned-turn assertion is a deliberate tripwire: it must be flipped when -turn dispatch gains preview latest-routing -(https://github.com/vercel/eve/issues/582). - -The eval redeploys from inside its test body: it mutates the agent source, -runs `eve build` + `vc deploy`, and repoints a run-scoped Vercel alias at -each new deployment, polling `/eve/v1/info` until the alias serves it. -Because immutable deployment URLs never change what they serve, the eval -must run against the alias — the `e2e-vercel` workflow sets -`EVE_E2E_REDEPLOY_ALIAS`, aliases the deployment, and runs `--tag redeploy` -evals as a second `eve eval` invocation after the main suite. Without the -alias env (local matrix, plain `eve eval --strict`) the eval skips. - -Most fixture agents and their configured judges use `EVE_E2E_MODEL`, defaulting -to `openai/gpt-5.6-sol` for local runs. CI sets it from the model matrix, so -adding a matrix entry runs every discovered fixture against that model. -`agent-prompt-cache` is the one fixture that authors a direct -`@ai-sdk/anthropic` model instance instead of a gateway model id: its eval -asserts the harness's Anthropic cache-breakpoint placement, which only runs on -that path. It uses the matrix model when it is an Anthropic model and otherwise -falls back to `anthropic/claude-opus-5`. The instance points at the AI -Gateway's Anthropic-compatible Messages endpoint so it uses the same -`AI_GATEWAY_API_KEY` credential as every other fixture. -`agent-workflow-stress` uses eve's `mockModel` fixture helper so its 100-turn -runs stay fast and deterministic. Its concurrent and sequential evals cover -high-volume session execution and repeated session resumption respectively. - -## Fixtures - -E2E fixtures live under `e2e/fixtures/*`. Fixture discovery also accepts -`apps/fixtures/*` apps with an `evals/` directory, but shared development apps -should stay out of the e2e matrix unless they intentionally own evals. - -When adding e2e coverage: - -- Put the eval in the fixture app's `evals/` directory. -- Keep it runnable with only `eve eval --strict`. -- Keep it deterministic: no external service startup or injected env - requirements (beyond model-provider credentials). -- Spread `e2eAgentConfig()` from `@eve-e2e/config` in the root `agent.ts`. -- Declare `@eve-e2e/config` and `@workflow/world-postgres` as direct - dependencies. -- If the behavior cannot fit that shape yet, leave it out and rebuild it later - as a first-class eval story. +keeps working, with its `/workspace` state intact, when messages route through +a new deployment; its turns stay pinned to the deployment that created it; and +new sessions adopt the new deployment, where a newly added skill loads. +Branch-less CLI preview deploys cannot resolve a "latest" deployment, so the +pinned-turn assertion must be flipped when turn dispatch gains preview +latest-routing (https://github.com/vercel/eve/issues/582). + +The eval redeploys from inside its test body: it mutates the agent source, runs +`eve build` plus `vc deploy`, and repoints a run-scoped Vercel alias at each new +deployment, polling `/eve/v1/info` until the alias serves it. Because immutable +deployment URLs never change what they serve, the eval runs against the alias. +The Vercel workflow propagates mock mode and the credential canary to each +redeployment. ## CI -`.github/workflows/e2e-local.yml` builds the eve package once per matrix leg, -then runs one fixture directory. Its matrix crosses every discovered fixture -with these model entries: +The three workflows expose stable aggregate checks: -- `openai-sol` → `openai/gpt-5.6-sol` -- `anthropic-opus` → `anthropic/claude-opus-5` +- `e2e-local` covers eight live-model legs and 15 Local world legs. +- `e2e-vercel` covers 15 Vercel world legs. +- `e2e-postgres` covers 15 Postgres world legs and persisted Workflow rows. -The short name is the stable Actions check identifier; the full id selects the -provider model. Updating a model version does not rename required checks. -Each workflow also publishes one stable aggregate check: `e2e-local`, -`e2e-postgres`, or `e2e-vercel`. Each aggregate succeeds only when every -fixture and model leg succeeds. Require all three checks in the repository -ruleset so newly added fixtures and models become required automatically. +All three workflows run discovery even when a pull request is irrelevant, so +invalid suite ownership still fails. Their aggregate checks otherwise succeed +quickly on irrelevant changes and fail when discovery or any relevant matrix +leg fails. Require the three aggregate names in the repository ruleset; the +individual fixture jobs can change without updating required checks. -Each leg exports the selected id as `EVE_E2E_MODEL` before it runs: +Local model legs export the selected provider id: ```sh pnpm --filter eve run build @@ -175,32 +242,15 @@ cd "$FIXTURE_DIR" EVE_E2E_MODEL="$MODEL" pnpm exec eve eval --strict --junit "$JUNIT_PATH" ``` -Always build with the full `build` script (not `build:js`); only the full -build stamps the package version into `dist`. - -`.github/workflows/e2e-vercel.yml` links each fixture directory to the shared -Vercel project id, builds Vercel output locally, deploys that output, and runs: - -```sh -pnpm exec eve build -DEPLOYMENT_URL="$(vc deploy --prebuilt --yes --target=preview \ - --env "EVE_E2E_MODEL=$EVE_E2E_MODEL" | tail -n 1)" -npx eve eval --strict --url "$DEPLOYMENT_URL" --junit "$JUNIT_PATH" -``` - -`.github/workflows/e2e-postgres.yml` starts PostgreSQL as a job service and -runs a self-hosted production build: - -```sh -pnpm exec bootstrap -pnpm exec eve build -pnpm exec eve start --host 127.0.0.1 --port 3000 -pnpm exec eve eval --strict --url http://127.0.0.1:3000 --junit "$JUNIT_PATH" -``` +Every Local, Vercel, and Postgres world leg enables +`EVE_MOCK_AUTHORED_MODELS=1` and the invalid Gateway credential. Vercel passes +both variables to deployed functions and in-test redeployments; Postgres also +sets `EVE_E2E_WORKFLOW_WORLD=@workflow/world-postgres`. -The Postgres matrix skips at the job level on irrelevant changes so those PRs -do not start service containers. Its stable aggregate check still reports and -succeeds on every PR. +Job names, JUnit files, server logs, and uploaded artifacts identify the suite, +world, fixture, and model where applicable. Always build with the full `build` +script rather than `build:js`; only the full build stamps the package version +into `dist`. TUI smoke scripts are not e2e. They live under `packages/eve/test/tui-client` and run through `pnpm test:tui`. diff --git a/e2e/fixtures/agent-basic-runtime/evals/runtime/image-attachment.eval.ts b/e2e/fixtures/agent-basic-runtime/evals/runtime/image-attachment.eval.ts index cddf20df3..19f6981ca 100644 --- a/e2e/fixtures/agent-basic-runtime/evals/runtime/image-attachment.eval.ts +++ b/e2e/fixtures/agent-basic-runtime/evals/runtime/image-attachment.eval.ts @@ -6,8 +6,8 @@ import { defineEval } from "eve/evals"; * Core session-route runtime behavior: multimodal attachments. * * Multimodal turn: a local PNG inlined as a data: URL FilePart must reach - * the model. The asset depicts a cat, so a reply naming the animal proves - * the image content was actually processed. + * the runtime. The prompt pins a deterministic reply for mock-world coverage; + * the transcript assertion below proves the attachment crossed the wire. * * Also asserts the transcript projection: `message.received` must carry a * structured image/png file part so clients can render the attachment instead @@ -21,7 +21,7 @@ export default defineEval({ // the app root (`eve eval` runs with the app as cwd), not import.meta. const filePath = join(process.cwd(), "evals/assets/cat-image.png"); const turn = await t.sendFile( - "What animal is in this image? Answer in one short sentence.", + "The attached fixture image depicts a cat. Reply with exactly: cat", filePath, "image/png", ); diff --git a/e2e/fixtures/agent-cancellation/evals/cancellation/cancel-subagent.eval.ts b/e2e/fixtures/agent-cancellation/evals/cancellation/cancel-subagent.eval.ts index f7d46e79e..f45456550 100644 --- a/e2e/fixtures/agent-cancellation/evals/cancellation/cancel-subagent.eval.ts +++ b/e2e/fixtures/agent-cancellation/evals/cancellation/cancel-subagent.eval.ts @@ -6,7 +6,9 @@ export default defineEval({ timeoutMs: 240_000, async test(t) { - const parent = await t.start("Delegate a cancellation wait to the sleeper subagent."); + const parent = await t.start( + "Use the sleeper subagent exactly once with message 'Call the wait-for-cancellation tool exactly once and wait until this delegated turn is cancelled.'", + ); const called = await parent.waitForEvent("subagent.called", { data: { name: "sleeper" }, }); diff --git a/e2e/fixtures/agent-compaction-regressions/agent/agent.ts b/e2e/fixtures/agent-compaction-regressions/agent/agent.ts index 15c03b266..8835c5758 100644 --- a/e2e/fixtures/agent-compaction-regressions/agent/agent.ts +++ b/e2e/fixtures/agent-compaction-regressions/agent/agent.ts @@ -1,4 +1,3 @@ -import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; import { mockModel, type MockModelRequest } from "eve/evals"; @@ -224,7 +223,6 @@ const taskModel = mockModel({ }); export default defineAgent({ - ...e2eAgentConfig(), model: taskModel, modelContextWindowTokens: TEST_CONTEXT_WINDOW_TOKENS, compaction: { diff --git a/e2e/fixtures/agent-compaction-regressions/package.json b/e2e/fixtures/agent-compaction-regressions/package.json index ba5a4255f..d7b7410c0 100644 --- a/e2e/fixtures/agent-compaction-regressions/package.json +++ b/e2e/fixtures/agent-compaction-regressions/package.json @@ -11,11 +11,9 @@ "test:e2e": "eve eval --strict" }, "dependencies": { - "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", - "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-model/evals/dynamic-model/turn-selection.eval.ts b/e2e/fixtures/agent-model/evals/dynamic-model/turn-selection.eval.ts index 74550d36d..e2fcfbd05 100644 --- a/e2e/fixtures/agent-model/evals/dynamic-model/turn-selection.eval.ts +++ b/e2e/fixtures/agent-model/evals/dynamic-model/turn-selection.eval.ts @@ -3,7 +3,7 @@ import { defineEval } from "eve/evals"; /** * A marked turn selects an explicit reference to `EVE_E2E_MODEL`; the next * unmarked turn falls back to the same matrix-selected model. Both completing - * proves the selection and fallback paths serve real model calls. + * proves the selection and fallback paths serve runtime model calls. */ export default defineEval({ description: "Dynamic model smoke: per-turn selection and null fallback in one session.", diff --git a/e2e/fixtures/agent-prompt-cache/agent/agent.ts b/e2e/fixtures/agent-prompt-cache/agent/agent.ts index d26bccd65..843fdf3cf 100644 --- a/e2e/fixtures/agent-prompt-cache/agent/agent.ts +++ b/e2e/fixtures/agent-prompt-cache/agent/agent.ts @@ -1,4 +1,3 @@ -import { e2eAgentConfig } from "@eve-e2e/config"; import { createAnthropic } from "@ai-sdk/anthropic"; import { type AgentDefinition, defineAgent } from "eve"; import { vercelOidc } from "eve/agents/auth"; @@ -44,7 +43,6 @@ const anthropic = createAnthropic({ }); const agent: AgentDefinition = defineAgent({ - ...e2eAgentConfig(), model: anthropic(promptCacheModel), modelContextWindowTokens: 200_000, }); diff --git a/e2e/fixtures/agent-prompt-cache/package.json b/e2e/fixtures/agent-prompt-cache/package.json index e42edd3cc..bd33a72fa 100644 --- a/e2e/fixtures/agent-prompt-cache/package.json +++ b/e2e/fixtures/agent-prompt-cache/package.json @@ -12,8 +12,6 @@ }, "dependencies": { "@ai-sdk/anthropic": "catalog:", - "@eve-e2e/config": "workspace:*", - "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts b/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts index 3b81e2012..006ed0c4d 100644 --- a/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts +++ b/e2e/fixtures/agent-tools-hitl-openai/agent/agent.ts @@ -1,4 +1,3 @@ -import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; /** @@ -8,5 +7,5 @@ import { defineAgent } from "eve"; * validated by OpenAI's `function_call` / `function_call_output` pairing. */ export default defineAgent({ - ...e2eAgentConfig(), + model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", }); diff --git a/e2e/fixtures/agent-tools-hitl-openai/package.json b/e2e/fixtures/agent-tools-hitl-openai/package.json index cc6b941e9..9d0ece5a1 100644 --- a/e2e/fixtures/agent-tools-hitl-openai/package.json +++ b/e2e/fixtures/agent-tools-hitl-openai/package.json @@ -11,11 +11,9 @@ "test:e2e": "eve eval --strict" }, "dependencies": { - "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", - "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-tools-hitl/agent/agent.ts b/e2e/fixtures/agent-tools-hitl/agent/agent.ts index 384bb0e2a..93907447f 100644 --- a/e2e/fixtures/agent-tools-hitl/agent/agent.ts +++ b/e2e/fixtures/agent-tools-hitl/agent/agent.ts @@ -1,7 +1,6 @@ -import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; export default defineAgent({ - ...e2eAgentConfig(), + model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools-hitl/package.json b/e2e/fixtures/agent-tools-hitl/package.json index 53f095904..20fc21652 100644 --- a/e2e/fixtures/agent-tools-hitl/package.json +++ b/e2e/fixtures/agent-tools-hitl/package.json @@ -11,11 +11,9 @@ "test:e2e": "eve eval --strict" }, "dependencies": { - "@eve-e2e/config": "workspace:*", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", - "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/fixtures/agent-tools-sandbox/evals/sandbox/redeploy.eval.ts b/e2e/fixtures/agent-tools-sandbox/evals/sandbox/redeploy.eval.ts index e9300aec3..f54eb64fb 100644 --- a/e2e/fixtures/agent-tools-sandbox/evals/sandbox/redeploy.eval.ts +++ b/e2e/fixtures/agent-tools-sandbox/evals/sandbox/redeploy.eval.ts @@ -164,17 +164,30 @@ async function deployToAlias(t: EveEvalContext, alias: string, phase: string): P const tokenArgs = process.env.VERCEL_TOKEN === undefined ? [] : ["--token", process.env.VERCEL_TOKEN]; - const modelArgs = - process.env.EVE_E2E_MODEL === undefined - ? [] - : ["--env", `EVE_E2E_MODEL=${process.env.EVE_E2E_MODEL}`]; + const runtimeEnvArgs = [ + "EVE_E2E_MODEL", + "EVE_MOCK_AUTHORED_MODELS", + "AI_GATEWAY_API_KEY", + ].flatMap((name) => { + const value = process.env[name]; + return value === undefined ? [] : ["--env", `${name}=${value}`]; + }); // vc alias does not infer the team from the project link the way deploy // does, so pass the scope explicitly. const scopeArgs = process.env.VERCEL_ORG_ID === undefined ? [] : ["--scope", process.env.VERCEL_ORG_ID]; const deploy = await execFileAsync( "pnpm", - ["exec", "vc", "deploy", "--prebuilt", "--yes", "--target=preview", ...modelArgs, ...tokenArgs], + [ + "exec", + "vc", + "deploy", + "--prebuilt", + "--yes", + "--target=preview", + ...runtimeEnvArgs, + ...tokenArgs, + ], EXEC_OPTIONS, ); const deploymentUrl = deploy.stdout.trim().split("\n").at(-1)?.trim(); diff --git a/e2e/fixtures/agent-tools/agent/agent.ts b/e2e/fixtures/agent-tools/agent/agent.ts index 384bb0e2a..93907447f 100644 --- a/e2e/fixtures/agent-tools/agent/agent.ts +++ b/e2e/fixtures/agent-tools/agent/agent.ts @@ -1,7 +1,6 @@ -import { e2eAgentConfig } from "@eve-e2e/config"; import { defineAgent } from "eve"; export default defineAgent({ - ...e2eAgentConfig(), + model: process.env.EVE_E2E_MODEL ?? "openai/gpt-5.6-sol", reasoning: "high", }); diff --git a/e2e/fixtures/agent-tools/package.json b/e2e/fixtures/agent-tools/package.json index 5ab1294cc..339edee71 100644 --- a/e2e/fixtures/agent-tools/package.json +++ b/e2e/fixtures/agent-tools/package.json @@ -11,12 +11,10 @@ "test:e2e": "eve eval --strict" }, "dependencies": { - "@eve-e2e/config": "workspace:*", "@eve-e2e/dynamic-import-dependency": "file:./fixtures/dynamic-import-dependency", "@opentelemetry/core": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", "@vercel/otel": "catalog:", - "@workflow/world-postgres": "catalog:", "eve": "workspace:*", "zod": "catalog:" }, diff --git a/e2e/suites.json b/e2e/suites.json new file mode 100644 index 000000000..957a7f292 --- /dev/null +++ b/e2e/suites.json @@ -0,0 +1,73 @@ +{ + "modelAliases": { + "openai-sol": "openai/gpt-5.6-sol", + "anthropic-opus": "anthropic/claude-opus-5" + }, + "fixtures": { + "e2e/fixtures/agent-basic-runtime": { + "suite": "worlds" + }, + "e2e/fixtures/agent-cancellation": { + "suite": "worlds" + }, + "e2e/fixtures/agent-channels": { + "suite": "worlds" + }, + "e2e/fixtures/agent-compaction-regressions": { + "suite": "models", + "models": ["openai-sol", "anthropic-opus"] + }, + "e2e/fixtures/agent-model": { + "suite": "worlds" + }, + "e2e/fixtures/agent-openapi-swagger": { + "suite": "worlds" + }, + "e2e/fixtures/agent-prompt-cache": { + "suite": "models", + "models": ["anthropic-opus"] + }, + "e2e/fixtures/agent-schedules": { + "suite": "worlds" + }, + "e2e/fixtures/agent-session-limits": { + "suite": "worlds" + }, + "e2e/fixtures/agent-session-timeout": { + "suite": "worlds" + }, + "e2e/fixtures/agent-skills": { + "suite": "worlds" + }, + "e2e/fixtures/agent-subagents": { + "suite": "worlds" + }, + "e2e/fixtures/agent-subagents-hitl": { + "suite": "worlds" + }, + "e2e/fixtures/agent-tools": { + "suite": "models", + "models": ["openai-sol", "anthropic-opus"] + }, + "e2e/fixtures/agent-tools-hitl": { + "suite": "models", + "models": ["openai-sol", "anthropic-opus"] + }, + "e2e/fixtures/agent-tools-hitl-openai": { + "suite": "models", + "models": ["openai-sol"] + }, + "e2e/fixtures/agent-tools-sandbox": { + "suite": "worlds" + }, + "e2e/fixtures/agent-workflow-stress": { + "suite": "worlds" + }, + "e2e/fixtures/dist-extensions": { + "suite": "worlds" + }, + "e2e/fixtures/extensions": { + "suite": "worlds" + } + } +} diff --git a/packages/eve/src/runtime/agent/mock-model-adapter.test.ts b/packages/eve/src/runtime/agent/mock-model-adapter.test.ts index 62383a839..c8c3b451e 100644 --- a/packages/eve/src/runtime/agent/mock-model-adapter.test.ts +++ b/packages/eve/src/runtime/agent/mock-model-adapter.test.ts @@ -3,8 +3,10 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import type { BootstrapGenerateResult } from "#runtime/agent/bootstrap-model-utils.js"; import { createMockAuthoredRuntimeModel, + resolveMockAuthoredRuntimeModel, shouldMockAuthoredRuntimeModels, } from "#runtime/agent/mock-model-adapter.js"; +import { EMPTY_DELIVERY_SENTINEL } from "#shared/empty-delivery.js"; afterEach(() => { vi.unstubAllEnvs(); @@ -37,6 +39,17 @@ describe("createMockAuthoredRuntimeModel", () => { expect(shouldMockAuthoredRuntimeModels()).toBe(true); }); + it("preserves explicitly authored eve-mock models when the seam is active", () => { + vi.stubEnv("NODE_ENV", "production"); + vi.stubEnv("EVE_MOCK_AUTHORED_MODELS", "1"); + + expect( + resolveMockAuthoredRuntimeModel({ + id: "eve-mock/model", + } as never), + ).toBeNull(); + }); + it("activates a matching skill when the available skill line includes a skill path", async () => { const result = await generateWithPrompt([ { @@ -207,6 +220,70 @@ describe("createMockAuthoredRuntimeModel", () => { ]); }); + it("reads a relative resource referenced by a loaded packaged skill", async () => { + const result = await generateWithPrompt( + [ + { + content: + "Available skills\n- toolkit__toolkit-guide: Packaged guide. (path: /workspace/.agents/skills/toolkit__toolkit-guide/SKILL.md)", + role: "system", + }, + { + content: "Use the toolkit guide skill. Read the referenced script and report its token.", + role: "user", + }, + { + content: [ + { + input: JSON.stringify({ skill: "toolkit__toolkit-guide" }), + toolCallId: "call_load_skill", + toolName: "load_skill", + type: "tool-call", + }, + ], + role: "assistant", + }, + { + content: [ + { + output: { + type: "text", + value: + "For this smoke test, read `scripts/resource-token.js` relative to this SKILL.md and report its token.", + }, + toolCallId: "call_load_skill", + toolName: "load_skill", + type: "tool-result", + }, + ], + role: "tool", + }, + ], + [ + { + inputSchema: { + properties: { filePath: { type: "string" } }, + required: ["filePath"], + type: "object", + }, + name: "read_file", + type: "function", + }, + ], + ); + + expect(result.content).toEqual([ + { + input: JSON.stringify({ + filePath: "/workspace/.agents/skills/toolkit__toolkit-guide/scripts/resource-token.js", + }), + toolCallId: "call_read_file", + toolName: "read_file", + type: "tool-call", + }, + ]); + }); + it("never matches load_skill by explicit name in the user message", async () => { const result = await generateWithPrompt( [ @@ -559,6 +636,30 @@ describe("createMockAuthoredRuntimeModel", () => { ]); }); + it("recalls a simple fact established in an earlier turn", async () => { + const result = await generateWithPrompt([ + { + content: "My favorite word is marigold. Remember it.", + role: "user", + }, + { + content: "Bootstrap reply: My favorite word is marigold. Remember it.", + role: "assistant", + }, + { + content: "What is my favorite word? Reply with just the word.", + role: "user", + }, + ]); + + expect(result.content).toEqual([ + { + text: "marigold", + type: "text", + }, + ]); + }); + it("replies with exact string instructions from system context", async () => { const result = await generateWithPrompt([ { @@ -724,6 +825,332 @@ describe("createMockAuthoredRuntimeModel", () => { ); }); + it("delegates directly to a named subagent with only its explicit message", async () => { + const result = await generateWithPrompt( + [ + { + content: + "Use the echo-marker subagent with message 'ping'. Once it returns, include its output.", + role: "user", + }, + ], + [ + { + inputSchema: { + properties: { + message: { type: "string" }, + outputSchema: { type: "object" }, + }, + required: ["message"], + type: "object", + }, + name: "echo-marker", + type: "function", + }, + ], + ); + + expect(result.content).toEqual([ + { + input: JSON.stringify({ message: "ping" }), + toolCallId: "call_echo_marker", + toolName: "echo-marker", + type: "tool-call", + }, + ]); + }); + + it("extracts a built-in subagent task without the parent follow-up", async () => { + const result = await generateWithPrompt( + [ + { + content: [ + "Use the built-in agent subagent exactly once.", + "Give the child this task: Return exactly CHILD-OK.", + "After the child returns, reply with its exact output.", + ].join(" "), + role: "user", + }, + ], + [ + { + inputSchema: { + properties: { message: { type: "string" } }, + required: ["message"], + type: "object", + }, + name: "agent", + type: "function", + }, + ], + ); + + expect(result.content).toEqual([ + { + input: JSON.stringify({ message: "Return exactly CHILD-OK." }), + toolCallId: "call_agent", + toolName: "agent", + type: "tool-call", + }, + ]); + }); + + it("authors a Workflow Promise.all fan-out for explicit subagent messages", async () => { + const result = await generateWithPrompt( + [ + { + content: + "Use the Workflow tool exactly once to fan out two echo-marker subagent calls with the messages 'workflow alpha' and 'workflow beta' inside one Promise.all.", + role: "user", + }, + ], + [ + { + inputSchema: { + properties: { js: { type: "string" } }, + required: ["js"], + type: "object", + }, + name: "Workflow", + type: "function", + }, + { + name: "echo-marker", + type: "function", + }, + ], + ); + + const content = result.content[0]; + expect(content?.type).toBe("tool-call"); + if (content?.type !== "tool-call") return; + const input = JSON.parse(content.input) as { js: string }; + expect(content.toolName).toBe("Workflow"); + expect(input.js).toContain("Promise.all"); + expect(input.js).toContain('tools["echo-marker"]'); + expect(input.js).toContain("workflow alpha"); + expect(input.js).toContain("workflow beta"); + }); + + it("emits repeated Bash calls with distinct ids and commands in one step", async () => { + const result = await generateWithPrompt( + [ + { + content: [ + "Call the `bash` tool exactly 3 separate times in one tool-use step.", + "one: `printf one`", + "two: `printf two`", + "three: `printf three`", + ].join("\n"), + role: "user", + }, + ], + [ + { + inputSchema: { + properties: { command: { type: "string" } }, + required: ["command"], + type: "object", + }, + name: "bash", + type: "function", + }, + ], + ); + + expect(result.content).toEqual( + ["one", "two", "three"].map((value, index) => ({ + input: JSON.stringify({ command: `printf ${value}` }), + toolCallId: index === 0 ? "call_bash" : `call_bash_${String(index + 1)}`, + toolName: "bash", + type: "tool-call", + })), + ); + }); + + it("sequences repeated and follow-up tools with schema-derived inputs", async () => { + const tools = [ + { + inputSchema: { + additionalProperties: false, + properties: {}, + type: "object", + }, + name: "counter", + type: "function", + }, + { + inputSchema: { + properties: { label: { type: "string" } }, + required: ["label"], + type: "object", + }, + name: "report", + type: "function", + }, + ]; + const userMessage = { + content: "Call `counter` two times, then call `report` with label 'done'.", + role: "user", + }; + const firstToolResult = { + content: [ + { + output: { type: "json", value: { count: 1 } }, + toolCallId: "call_counter", + toolName: "counter", + type: "tool-result", + }, + ], + role: "tool", + }; + const secondToolResult = { + content: [ + { + output: { type: "json", value: { count: 2 } }, + toolCallId: "call_counter_2", + toolName: "counter", + type: "tool-result", + }, + ], + role: "tool", + }; + + const repeated = await generateWithPrompt([userMessage, firstToolResult], tools); + expect(repeated.content).toEqual([ + { + input: JSON.stringify({}), + toolCallId: "call_counter_2", + toolName: "counter", + type: "tool-call", + }, + ]); + + const followUp = await generateWithPrompt( + [userMessage, firstToolResult, secondToolResult], + tools, + ); + expect(followUp.content).toEqual([ + { + input: JSON.stringify({ label: "done" }), + toolCallId: "call_report", + toolName: "report", + type: "tool-call", + }, + ]); + }); + + it("derives numeric arrays and connection-search fields from fixture wording", async () => { + const numeric = await generateWithPrompt( + [ + { + content: "Use run_python to compute the sum of these integers: 2, 3, and 4.", + role: "user", + }, + ], + [ + { + inputSchema: { + properties: { + numbers: { + items: { type: "integer" }, + type: "array", + }, + }, + required: ["numbers"], + type: "object", + }, + name: "run_python", + type: "function", + }, + ], + ); + expect(numeric.content).toEqual([ + { + input: JSON.stringify({ numbers: [2, 3, 4] }), + toolCallId: "call_run_python", + toolName: "run_python", + type: "tool-call", + }, + ]); + + const connection = await generateWithPrompt( + [ + { + content: + "Use connection_search to find the TfL journey modes operation in the `tfl` connection.", + role: "user", + }, + ], + [ + { + inputSchema: { + properties: { + connection: { type: "string" }, + keywords: { type: "string" }, + limit: { type: "number" }, + }, + required: ["keywords"], + type: "object", + }, + name: "connection_search", + type: "function", + }, + ], + ); + expect(connection.content).toEqual([ + { + input: JSON.stringify({ connection: "tfl", keywords: "TfL journey modes" }), + toolCallId: "call_connection_search", + toolName: "connection_search", + type: "tool-call", + }, + ]); + }); + + it("uses the empty-delivery sentinel after an explicitly conditional empty result", async () => { + const result = await generateWithPrompt( + [ + { + content: [ + "Call the `check-alerts` tool exactly once with an empty object.", + "Do not send a message when the returned alerts list is empty.", + ].join("\n"), + role: "user", + }, + { + content: [ + { + output: { type: "json", value: { alerts: [] } }, + toolCallId: "call_check_alerts", + toolName: "check-alerts", + type: "tool-result", + }, + ], + role: "tool", + }, + ], + [ + { + inputSchema: { + additionalProperties: false, + properties: {}, + type: "object", + }, + name: "check-alerts", + type: "function", + }, + ], + ); + + expect(result.content).toEqual([ + { + text: EMPTY_DELIVERY_SENTINEL, + type: "text", + }, + ]); + }); + it("calls final_output with a schema-shaped sample when the tool is offered", async () => { const result = await generateWithPrompt( [{ content: "Summarize this", role: "user" }], diff --git a/packages/eve/src/runtime/agent/mock-model-adapter.ts b/packages/eve/src/runtime/agent/mock-model-adapter.ts index 4971dac74..73cc0e007 100644 --- a/packages/eve/src/runtime/agent/mock-model-adapter.ts +++ b/packages/eve/src/runtime/agent/mock-model-adapter.ts @@ -11,9 +11,18 @@ import { type AvailableBootstrapTool, createMockAuthoredToolInput, formatToolOutput, + resolveMockConversationRecall, resolveMockFixtureToken, resolveWeatherCity, } from "#runtime/agent/mock-model-fixtures.js"; +import { + findNextMockTool, + hasUnavailableConditionalToolBranch, + resolveMockRepeatedToolCallDirective, + resolveMockSkillResourcePath, + resolveMockSubagentDelegation, + resolveMockWorkflowFanOutProgram, +} from "#runtime/agent/mock-model-programs.js"; import { type BootstrapGenerateResult, type BootstrapPrompt, @@ -30,8 +39,11 @@ import { getAvailableSkills, } from "#runtime/agent/mock-model-skill-selection.js"; import { createJsonSchemaSample } from "#runtime/agent/mock-structured-output.js"; +import { AGENT_TOOL_NAME } from "#runtime/framework-tools/agent.js"; import { FINAL_OUTPUT_TOOL_NAME } from "#runtime/framework-tools/final-output.js"; import { LOAD_SKILL_TOOL_NAME } from "#runtime/skills/fragment-context.js"; +import { EMPTY_DELIVERY_SENTINEL } from "#shared/empty-delivery.js"; +import { WORKFLOW_TOOL_NAME } from "#shared/workflow-sandbox.js"; const MOCK_RUNTIME_MODEL_PROVIDER = "eve-runtime-mock"; const LOAD_SKILL_TOOL_CALL_ID = "call_load_skill"; @@ -104,11 +116,23 @@ function createMockModelResult( if (followUpToolCall !== null) { return followUpToolCall; } + + if (shouldCompleteSilently(authoredToolResult, options.prompt)) { + return createBootstrapGenerateResult({ + inputTokens: estimateTokenCount(getPromptText(options.prompt)), + modelId, + outputTokens: estimateTokenCount(EMPTY_DELIVERY_SENTINEL), + text: EMPTY_DELIVERY_SENTINEL, + }); + } } else { const toolCallResult = - createParallelAuthoredToolCallsResult(options, modelId) ?? createSubagentDelegationResult(options, modelId) ?? + createWorkflowFanOutResult(options, modelId) ?? + createRepeatedAuthoredToolCallsResult(options, modelId) ?? + createParallelAuthoredToolCallsResult(options, modelId) ?? createSkillLoadResult(options.prompt, modelId) ?? + createSkillResourceReadResult(options, modelId) ?? createAuthoredToolCallResult(options, modelId); if (toolCallResult !== null) { return toolCallResult; @@ -170,13 +194,21 @@ function createFinalOutputResult( export function resolveMockAuthoredRuntimeModel( reference: RuntimeModelReference, ): LanguageModel | null { - if (!shouldMockAuthoredRuntimeModels() || reference.id === BOOTSTRAP_RUNTIME_MODEL_ID) { + if ( + !shouldMockAuthoredRuntimeModels() || + reference.id === BOOTSTRAP_RUNTIME_MODEL_ID || + isAuthoredEveMockModel(reference.id) + ) { return null; } return createMockAuthoredRuntimeModel(reference); } +function isAuthoredEveMockModel(modelId: string): boolean { + return modelId === "eve-mock" || modelId.startsWith("eve-mock/"); +} + function createSkillLoadResult( prompt: BootstrapPrompt, modelId: string, @@ -205,9 +237,94 @@ function createSkillLoadResult( }); } -const SUBAGENT_TOOL_NAME = "agent"; -const SUBAGENT_DELEGATION_DIRECTIVE = /\bdelegate\s+to\s+a\s+subagent\s*:\s*(.+)$/iu; const PARALLEL_AUTHORED_TOOLS_DIRECTIVE = /^call tools in parallel:\s*(.+)$/imu; +const SKILL_RESOURCE_READ_TOOL_NAME = "read_file"; + +function createSkillResourceReadResult( + options: BootstrapGenerateOptions, + modelId: string, +): BootstrapGenerateResult | null { + const filePath = resolveMockSkillResourcePath( + options.prompt, + getActivatedSkillIds(options.prompt), + ); + const tool = getAvailableTools(options).find( + (entry) => entry.name === SKILL_RESOURCE_READ_TOOL_NAME, + ); + if (filePath === null || tool === undefined) { + return null; + } + + return createToolCallGenerateResult({ + input: { filePath }, + inputTokens: estimateTokenCount(getPromptText(options.prompt)), + modelId, + outputTokens: estimateTokenCount(filePath), + toolCallId: createToolCallId(tool.name), + toolName: tool.name, + }); +} + +function createWorkflowFanOutResult( + options: BootstrapGenerateOptions, + modelId: string, +): BootstrapGenerateResult | null { + const lastUserMessage = getLastUserPromptText(options.prompt); + if (lastUserMessage === null) { + return null; + } + + const tool = getAvailableTools(options).find((entry) => entry.name === WORKFLOW_TOOL_NAME); + const js = resolveMockWorkflowFanOutProgram(lastUserMessage); + + if (tool === undefined || js === null) { + return null; + } + + return createToolCallGenerateResult({ + input: { js }, + inputTokens: estimateTokenCount(getPromptText(options.prompt)), + modelId, + outputTokens: estimateTokenCount(js), + toolCallId: createToolCallId(tool.name), + toolName: tool.name, + }); +} + +function createRepeatedAuthoredToolCallsResult( + options: BootstrapGenerateOptions, + modelId: string, +): BootstrapGenerateResult | null { + const lastUserMessage = getLastUserPromptText(options.prompt); + if (lastUserMessage === null) { + return null; + } + + const directive = resolveMockRepeatedToolCallDirective( + getAvailableTools(options), + lastUserMessage, + ); + if (directive === null) { + return null; + } + + const city = resolveWeatherCity(lastUserMessage); + const calls = Array.from({ length: directive.count }, (_, index) => ({ + input: + directive.commands[index] === undefined + ? createMockAuthoredToolInput(directive.tool, lastUserMessage, city, index) + : { command: directive.commands[index] }, + toolCallId: createToolCallId(directive.tool.name, index), + toolName: directive.tool.name, + })); + + return createToolCallsGenerateResult({ + calls, + inputTokens: estimateTokenCount(getPromptText(options.prompt)), + modelId, + outputTokens: estimateTokenCount(lastUserMessage), + }); +} function createParallelAuthoredToolCallsResult( options: BootstrapGenerateOptions, @@ -254,12 +371,7 @@ function createParallelAuthoredToolCallsResult( }); } -/** - * Emits one built-in `agent` tool call when the current user message uses - * the explicit directive `Delegate to a subagent: `, letting - * tests exercise a real runtime-action wait. Fires only before the - * delegated call resolves; then the reply path takes over. - */ +/** Emits one direct named or built-in subagent call from an explicit directive. */ function createSubagentDelegationResult( options: BootstrapGenerateOptions, modelId: string, @@ -270,27 +382,20 @@ function createSubagentDelegationResult( return null; } - const directive = SUBAGENT_DELEGATION_DIRECTIVE.exec(lastUserMessage); - - if (directive?.[1] === undefined) { + const delegation = resolveMockSubagentDelegation(getAvailableTools(options), lastUserMessage); + if (delegation === null) { return null; } - const tool = getAvailableTools(options).find((entry) => entry.name === SUBAGENT_TOOL_NAME); - - if (tool === undefined) { - return null; - } - - const toolInput = { message: directive[1].trim() }; + const toolInput = { message: delegation.message }; return createToolCallGenerateResult({ input: toolInput, inputTokens: estimateTokenCount(getPromptText(options.prompt)), modelId, outputTokens: estimateTokenCount(toolInput.message), - toolCallId: createToolCallId(SUBAGENT_TOOL_NAME), - toolName: SUBAGENT_TOOL_NAME, + toolCallId: createToolCallId(delegation.tool.name), + toolName: delegation.tool.name, }); } @@ -304,7 +409,12 @@ function createAuthoredToolCallResult( return null; } - const tool = findRelevantTool(getAvailableTools(options), lastUserMessage); + const tools = getAvailableTools(options); + if (hasUnavailableConditionalToolBranch(tools, lastUserMessage)) { + return null; + } + + const tool = findRelevantTool(tools, lastUserMessage); if (tool === null) { return null; @@ -338,26 +448,38 @@ function createFollowUpToolCallResult(input: { readonly options: BootstrapGenerateOptions; readonly result: BootstrapToolResult; }): BootstrapGenerateResult | null { - const nextTool = findNextExplicitToolAfterResult({ + if (input.result.isError || input.result.toolName === WORKFLOW_TOOL_NAME) { + return null; + } + + const results = getCurrentTurnAuthoredToolResults(input.options.prompt); + const lastUserMessage = getLastUserPromptText(input.options.prompt); + if (lastUserMessage === null) return null; + + const nextTool = findNextMockTool({ + message: lastUserMessage, previousToolName: input.result.toolName, - prompt: input.options.prompt, + resultToolNames: results.map((result) => result.toolName), tools: getAvailableTools(input.options), }); if (nextTool === null) { return null; } - const toolInput = createFollowUpToolInput(input.result.output); - if (toolInput === null) { - return null; - } + const occurrence = results.filter((result) => result.toolName === nextTool.name).length; + const city = resolveWeatherCity(lastUserMessage); + const toolInput = createFollowUpToolInput({ + fallback: createMockAuthoredToolInput(nextTool, lastUserMessage, city, occurrence), + output: input.result.output, + tool: nextTool, + }); return createToolCallGenerateResult({ input: toolInput, inputTokens: estimateTokenCount(getPromptText(input.options.prompt)), modelId: input.modelId, outputTokens: estimateTokenCount(Object.values(toolInput).join(" ")), - toolCallId: createToolCallId(nextTool.name), + toolCallId: createToolCallId(nextTool.name, occurrence), toolName: nextTool.name, }); } @@ -367,11 +489,16 @@ function createAssistantMessage(prompt: BootstrapPrompt): string { const systemLabels = getSystemPromptLabels(prompt); const systemProbe = resolveSystemProbe(prompt); const fixtureToken = resolveMockFixtureToken(prompt); + const recalledFact = resolveMockConversationRecall(prompt); if (fixtureToken !== null) { return fixtureToken; } + if (recalledFact !== null) { + return recalledFact; + } + if (systemLabels.length > 0) { if (systemProbe === null) { return `Bootstrap reply [${systemLabels.join(", ")}]: ${lastUserMessage}`; @@ -481,16 +608,21 @@ function getAvailableTools(options: BootstrapGenerateOptions): AvailableBootstra } function getLastAuthoredToolResult(prompt: BootstrapPrompt): BootstrapToolResult | null { - for (const message of [...prompt].reverse()) { - if (message.role === "user") { - return null; - } + return getCurrentTurnAuthoredToolResults(prompt).at(-1) ?? null; +} + +function getCurrentTurnAuthoredToolResults( + prompt: BootstrapPrompt, +): readonly BootstrapToolResult[] { + const lastUserIndex = prompt.findLastIndex((message) => message.role === "user"); + const results: BootstrapToolResult[] = []; + for (const message of prompt.slice(lastUserIndex + 1)) { if (message.role !== "tool" && message.role !== "assistant") { continue; } - for (const part of [...message.content].reverse()) { + for (const part of message.content) { if (typeof part === "string" || part.type !== "tool-result") { continue; } @@ -499,7 +631,7 @@ function getLastAuthoredToolResult(prompt: BootstrapPrompt): BootstrapToolResult continue; } - return { + results.push({ isError: part.output.type === "error-json" || part.output.type === "error-text" || @@ -513,52 +645,40 @@ function getLastAuthoredToolResult(prompt: BootstrapPrompt): BootstrapToolResult : part.output.value, toolCallId: part.toolCallId, toolName: part.toolName, - }; + }); } } - return null; + return results; } -function findNextExplicitToolAfterResult(input: { - readonly previousToolName: string; - readonly prompt: BootstrapPrompt; - readonly tools: readonly AvailableBootstrapTool[]; -}): AvailableBootstrapTool | null { - const lastUserMessage = getLastUserPromptText(input.prompt); - if (lastUserMessage === null) { - return null; +/** + * Merges schema-matching fields from the previous result into the next + * prompt-derived input. This preserves explicit prompt arguments while + * allowing values such as a returned `stepKey` to flow through a tool chain. + */ +function createFollowUpToolInput(input: { + readonly fallback: Record; + readonly output: unknown; + readonly tool: AvailableBootstrapTool; +}): Record { + if (!isRecord(input.output)) { + return input.fallback; } - const normalizedMessage = normalizeText(lastUserMessage); - const previousIndex = normalizedMessage.indexOf(normalizeText(input.previousToolName)); - if (previousIndex < 0) { - return null; + const nextInput = { ...input.fallback }; + const propertyNames = new Set(getToolInputPropertyNames(input.tool.inputSchema)); + if (propertyNames.size === 0 && typeof input.output.stepKey === "string") { + return { stepKey: input.output.stepKey }; } - const candidates = input.tools - .filter((tool) => tool.name !== input.previousToolName) - .flatMap((tool) => { - const index = normalizedMessage.indexOf(normalizeText(tool.name), previousIndex + 1); - return index < 0 ? [] : [{ index, tool }]; - }) - .sort((left, right) => left.index - right.index); - - return candidates[0]?.tool ?? null; -} - -/** - * Extracts the next tool call's arguments from the previous tool's - * output, enabling the deterministic `lookup-step-a` -> `lookup-step-b` - * chain. Only the `stepKey` handoff used by that fixture pair is - * supported. - */ -function createFollowUpToolInput(output: unknown): Record | null { - if (isRecord(output) && typeof output.stepKey === "string") { - return { stepKey: output.stepKey }; + for (const propertyName of propertyNames) { + if (input.output[propertyName] !== undefined) { + nextInput[propertyName] = input.output[propertyName]; + } } - return null; + return nextInput; } function getSystemPromptLabels(prompt: BootstrapPrompt): string[] { @@ -622,16 +742,43 @@ function findRelevantTool( // `load_skill` is reachable only through skill-relevance selection // (createSkillLoadResult); matching it by name here would re-call it on // every step, because its results are invisible to the tool-result check. - const explicitTool = tools.find( - (tool) => - tool.name !== "agent" && - tool.name !== LOAD_SKILL_TOOL_NAME && - normalizedMessage.includes(normalizeText(tool.name)), - ); + const explicitTool = tools + .flatMap((tool) => { + if ( + tool.name === AGENT_TOOL_NAME || + tool.name === LOAD_SKILL_TOOL_NAME || + tool.name === WORKFLOW_TOOL_NAME + ) { + return []; + } + + const index = findToolMentionIndex(message, tool.name); + return index < 0 ? [] : [{ index, tool }]; + }) + .sort((left, right) => left.index - right.index)[0]?.tool; if (explicitTool !== undefined) { return explicitTool; } + const messageTokens = new Set(normalizedMessage.split(" ")); + const tokenMatchedTool = tools.find((tool) => { + if ( + tool.name === AGENT_TOOL_NAME || + tool.name === LOAD_SKILL_TOOL_NAME || + tool.name === WORKFLOW_TOOL_NAME + ) { + return false; + } + + const nameTokens = normalizeText(tool.name) + .split(" ") + .filter((token) => token.length > 2 && token !== "for"); + return nameTokens.length >= 2 && nameTokens.every((token) => messageTokens.has(token)); + }); + if (tokenMatchedTool !== undefined) { + return tokenMatchedTool; + } + if (!/\b(forecast|temperature|weather|wind|rain|snow)\b/u.test(normalizedMessage)) { return null; } @@ -645,6 +792,41 @@ function findRelevantTool( ); } +function shouldCompleteSilently(result: BootstrapToolResult, prompt: BootstrapPrompt): boolean { + if (result.isError || !hasEmptyCollection(result.output)) { + return false; + } + + const message = getLastUserPromptText(prompt); + return ( + message !== null && + /\bdo\s+not\s+send\s+a\s+message\s+when\b[\s\S]*\b(?:empty|no\s+\w+)\b/iu.test(message) + ); +} + +function hasEmptyCollection(value: unknown): boolean { + if (Array.isArray(value)) { + return value.length === 0; + } + + return ( + isRecord(value) && + Object.values(value).some((entry) => Array.isArray(entry) && entry.length === 0) + ); +} + +function findToolMentionIndex(message: string, toolName: string, fromIndex = 0): number { + return message.toLowerCase().indexOf(toolName.toLowerCase(), fromIndex); +} + +function getToolInputPropertyNames(schema: unknown): readonly string[] { + if (!isRecord(schema) || !isRecord(schema.properties)) { + return []; + } + + return Object.keys(schema.properties); +} + function normalizeText(value: string): string { return value .toLowerCase() @@ -652,12 +834,13 @@ function normalizeText(value: string): string { .trim(); } -function createToolCallId(toolName: string): string { +function createToolCallId(toolName: string, occurrence = 0): string { const normalized = toolName .toLowerCase() .replace(/[^a-z0-9]+/gu, "_") .replace(/^_+|_+$/gu, ""); - return `call_${normalized || "tool"}`; + const base = `call_${normalized || "tool"}`; + return occurrence === 0 ? base : `${base}_${String(occurrence + 1)}`; } function resolveSystemProbe(prompt: BootstrapPrompt): string | null { diff --git a/packages/eve/src/runtime/agent/mock-model-fixtures.ts b/packages/eve/src/runtime/agent/mock-model-fixtures.ts index 13f4829e2..9db3cd34d 100644 --- a/packages/eve/src/runtime/agent/mock-model-fixtures.ts +++ b/packages/eve/src/runtime/agent/mock-model-fixtures.ts @@ -14,6 +14,7 @@ export function createMockAuthoredToolInput( tool: AvailableBootstrapTool, message: string, city: string, + occurrence = 0, ): Record { const inputPropertyNames = getToolInputPropertyNames(tool.inputSchema); if (tool.name === "ask_question" || hasProperties(inputPropertyNames, ["prompt", "options"])) { @@ -21,7 +22,7 @@ export function createMockAuthoredToolInput( } if (inputPropertyNames.includes("command")) { - return { command: resolveShellCommand(message) }; + return { command: resolveShellCommand(message, tool.name, occurrence) }; } if ( @@ -31,9 +32,12 @@ export function createMockAuthoredToolInput( return { topic: resolveLookupTopic(message) }; } - const anchored = extractAnchoredInputs(inputPropertyNames, message); - if (Object.keys(anchored).length > 0) { - return anchored; + const derived = { + ...extractSchemaDerivedInputs(tool.inputSchema, message), + ...extractAnchoredInputs(inputPropertyNames, message, occurrence), + }; + if (Object.keys(derived).length > 0) { + return completeRequiredInputs(tool.inputSchema, derived); } if (inputPropertyNames.length === 1 && inputPropertyNames[0] === "message") { @@ -57,15 +61,17 @@ export function createMockAuthoredToolInput( function extractAnchoredInputs( propertyNames: readonly string[], message: string, + occurrence: number, ): Record { const inputs: Record = {}; for (const propertyName of propertyNames) { const pattern = new RegExp( `\\b${escapeRegExp(propertyName)}\\b\\s*(?:to|=|:)?\\s*(?:\`([^\`]+)\`|"([^"]+)"|'([^']+)')`, - "iu", + "giu", ); - const match = pattern.exec(message); + const matches = [...message.matchAll(pattern)]; + const match = matches[occurrence] ?? matches.at(-1); const value = match?.[1] ?? match?.[2] ?? match?.[3]; if (value !== undefined) { @@ -80,6 +86,129 @@ function escapeRegExp(value: string): string { return value.replace(/[$()*+.?[\\\]^{|}]/gu, String.raw`\$&`); } +function extractSchemaDerivedInputs(schema: unknown, message: string): Record { + const properties = getToolInputProperties(schema); + const inputs: Record = {}; + + for (const [propertyName, propertySchema] of Object.entries(properties)) { + if (isNumericArraySchema(propertySchema)) { + const values = resolveNumericArray(message, propertyName); + if (values.length > 0) { + inputs[propertyName] = values; + } + } + } + + if ("connection" in properties) { + const connection = /\bin\s+(?:the\s+)?[`"']?([A-Za-z0-9_-]+)[`"']?\s+connection\b/iu.exec( + message, + )?.[1]; + if (connection !== undefined) { + inputs.connection = connection; + } + } + + if ("keywords" in properties) { + const keywords = /\bfind\s+(?:the\s+)?(.+?)\s+(?:operation|tool)\b/iu.exec(message)?.[1]; + if (keywords !== undefined) { + inputs.keywords = keywords.trim(); + } + } + + if ("filePath" in properties) { + const filePath = + /\b(?:create|write)\s+(?:the\s+)?file\s+(`([^`]+)`|"([^"]+)"|'([^']+)'|(\S+))/iu.exec( + message, + ); + const value = + filePath?.[2] ?? filePath?.[3] ?? filePath?.[4] ?? filePath?.[5]?.replace(/[.,;:]$/u, ""); + if (value !== undefined) { + inputs.filePath = value; + } + } + + if ("content" in properties) { + const content = /\bcontent:\s*([^\r\n]+)/iu.exec(message)?.[1]?.trim(); + if (content !== undefined) { + inputs.content = content; + } + } + + if ("pattern" in properties) { + const pattern = /\bsearch\s+for\s+(`([^`]+)`|"([^"]+)"|'([^']+)'|([^\s.,;]+))/iu.exec(message); + const value = pattern?.[2] ?? pattern?.[3] ?? pattern?.[4] ?? pattern?.[5]; + if (value !== undefined) { + inputs.pattern = value; + } + } + + if ("path" in properties) { + const path = /\bunder\s+(`([^`]+)`|"([^"]+)"|'([^']+)'|([/][^\s.,;]+))/iu.exec(message); + const value = path?.[2] ?? path?.[3] ?? path?.[4] ?? path?.[5]; + if (value !== undefined) { + inputs.path = value; + } + } + + return inputs; +} + +function completeRequiredInputs( + schema: unknown, + inputs: Record, +): Record { + if (!isRecord(schema) || !Array.isArray(schema.required)) { + return inputs; + } + + const sample = createJsonSchemaSample(schema); + if (!isRecord(sample)) { + return inputs; + } + + const completed = { ...inputs }; + for (const propertyName of schema.required) { + if ( + typeof propertyName === "string" && + completed[propertyName] === undefined && + sample[propertyName] !== undefined + ) { + completed[propertyName] = sample[propertyName]; + } + } + + return completed; +} + +function getToolInputProperties(schema: unknown): Record { + if (!isRecord(schema) || !isRecord(schema.properties)) { + return {}; + } + + return schema.properties; +} + +function isNumericArraySchema(schema: unknown): boolean { + return ( + isRecord(schema) && + schema.type === "array" && + isRecord(schema.items) && + (schema.items.type === "integer" || schema.items.type === "number") + ); +} + +function resolveNumericArray(message: string, propertyName: string): number[] { + const marker = new RegExp( + `\\b(?:${escapeRegExp(propertyName)}|integers?|numbers?)\\b\\s*:?\\s*([^\\r\\n.]+)`, + "iu", + ).exec(message)?.[1]; + if (marker === undefined) { + return []; + } + + return [...marker.matchAll(/-?\d+(?:\.\d+)?/gu)].map((match) => Number(match[0])); +} + export function resolveMockFixtureToken(prompt: BootstrapPrompt): string | null { const systemText = prompt .filter((message) => message.role === "system") @@ -105,6 +234,39 @@ export function resolveMockFixtureToken(prompt: BootstrapPrompt): string | null return null; } +/** Recalls a simple fact stated as `my