Skip to content

fix(evals): persist inline dataset runs without version ids#1108

Merged
omeraplak merged 3 commits into
mainfrom
fix/evals-inline-dataset-run-ingestion
Feb 25, 2026
Merged

fix(evals): persist inline dataset runs without version ids#1108
omeraplak merged 3 commits into
mainfrom
fix/evals-inline-dataset-run-ingestion

Conversation

@omeraplak

@omeraplak omeraplak commented Feb 25, 2026

Copy link
Copy Markdown
Member

PR Checklist

Please check if your PR fulfills the following requirements:

Bugs / Features

What is the current behavior?

Offline eval runs using inline datasets (dataset: { items: [...] }) are not persisted correctly.

Two issues were observed:

  1. Run creation was skipped when dataset.versionId was missing.
  2. Result append could fail for inline items because datasetItemId was sent as a non-UUID string, while API expects UUID for dataset_item_id.

What is the new behavior?

  1. Run creation is now allowed even when dataset.versionId is missing.
  2. datasetItemId is normalized before append:
    • UUID values are sent as-is.
    • Non-UUID inline item IDs are sent as null and tracked via datasetItemHash.

This allows inline dataset offline eval runs to be created, appended, and completed successfully, and appear in Console runs.

fixes (issue)

Notes for reviewers

  • Updated tests in packages/evals/src/voltops/run.spec.ts and packages/evals/src/experiment/run-experiment.spec.ts.
  • Local validation executed:
    • pnpm --filter @voltagent/evals test
    • pnpm --filter @voltagent/evals build
    • pnpm --filter voltagent-example-with-offline-evals build

Summary by cubic

Fixes offline eval runs with inline datasets so they persist correctly. Run creation works without dataset.versionId, and non-UUID inline item IDs are sent as null and tracked via datasetItemHash.

  • Bug Fixes
    • Allow run creation when dataset.versionId is missing.
    • Normalize datasetItemId: UUIDs pass through; non-UUIDs become null with datasetItemHash fallback.
    • Update tests; add changeset for patch release.

Written for commit 4a4394e. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed offline evaluation runs to persist correctly when using inline datasets with string item IDs.
    • Enabled run creation and result syncing even when dataset version IDs are absent.
    • Improved dataset item ID normalization to prevent API failures with inline datasets.
  • Tests

    • Added and updated tests to verify dataset item ID validation and inline dataset handling.

@changeset-bot

changeset-bot Bot commented Feb 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4a4394e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@voltagent/evals Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ghost

This comment has been minimized.

@coderabbitai

coderabbitai Bot commented Feb 25, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This pull request enables offline evaluation runs to persist when using inline datasets by removing the dataset.versionId requirement. It introduces datasetItemId normalization logic that treats UUID-format IDs separately from non-UUID IDs, preventing API failures with string-based inline dataset items.

Changes

Cohort / File(s) Summary
Changeset Documentation
.changeset/soft-dots-bow.md
Documents fix for offline evaluation runs with inline datasets; introduces datasetItemId payload normalization for UUID vs. non-UUID item IDs.
Package Configuration
examples/with-chat-sdk/package.json
Reorders "private" field position within JSON object without functional impact.
Core Run Logic
packages/evals/src/voltops/run.ts
Removes dataset.versionId guard in #canCreateRun and #createRun; adds normalizeDatasetItemId() function to validate UUID format and return null for non-UUID IDs; preserves datasetItemHash computation.
Test Updates
packages/evals/src/voltops/run.spec.ts, packages/evals/src/experiment/run-experiment.spec.ts
Introduces dataset item ID constants; updates assertions to verify run creation without dataset version; adds test case for inline items with null datasetItemId and non-null datasetItemHash.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A Rabbit's Ode to Inline Runs

No version? No fuss! Our runs now persist,
With UUIDs gleaming where strings would have missed.
Inline datasets dance through the offline night,
Hash-tracked string IDs keep the payload just right.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main fix: enabling persistence of inline dataset runs without version IDs, which directly matches the core objective of the changeset.
Description check ✅ Passed The PR description covers all required template sections with sufficient detail: checklist items are marked, current behavior describes two specific bugs, new behavior explains the fixes with technical context, and reviewers' notes document testing and validation performed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/evals-inline-dataset-run-ingestion

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 3 files

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Feb 25, 2026

Copy link
Copy Markdown

Deploying voltagent with  Cloudflare Pages  Cloudflare Pages

Latest commit: 489e462
Status: ✅  Deploy successful!
Preview URL: https://8d437ed9.voltagent.pages.dev
Branch Preview URL: https://fix-evals-inline-dataset-run.voltagent.pages.dev

View logs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/evals/src/voltops/run.ts (2)

419-430: isUuid regex excludes RFC 9562 nil and max UUIDs — verify with API.

The regex [1-8] in the version nibble and [89ab] in the variant position correctly validates v1–v8 RFC 4122/9562 UUIDs. However, it will reject the nil UUID (00000000-0000-0000-0000-000000000000) and the max UUID (ffffffff-ffff-ffff-ffff-ffffffffffff) introduced in RFC 9562, sending them as null. If the API can legally store either of those as a dataset_item_id foreign key, callers using them as item IDs would silently lose the link.

This is almost certainly acceptable in practice (nil/max UUIDs are almost never used as real FK values), but worth a one-line comment in isUuid to document the intentional exclusion.

📝 Suggested inline doc
 function isUuid(value: string): boolean {
-  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
+  // Matches RFC 4122 / RFC 9562 v1–v8, variant-1 UUIDs.
+  // Nil and max UUIDs are intentionally excluded; they are not valid FK values.
+  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/evals/src/voltops/run.ts` around lines 419 - 430, Update
isUuid/normalizeDatasetItemId to document the intentional exclusion of the RFC
9562 nil and max UUIDs: add a concise one-line comment above isUuid (and/or
above normalizeDatasetItemId) stating that the regex deliberately validates RFC
4122/9562 version/variant bits for v1–v8 and therefore rejects the all-zero
(nil) and all-ff (max) UUIDs, so those values will be normalized to null;
mention that this is intentional to avoid silently accepting sentinel UUIDs as
real dataset_item_id foreign keys.

399-416: datasetItemHash always stringifies item.itemId ?? item.index — consider hash collision for numeric indices.

datasetItemHash: String(item.itemId ?? item.index) means that when item.itemId is undefined, the hash becomes the numeric index ("0", "1", …). Across multiple inline dataset runs, items at the same ordinal position in different runs will share the same datasetItemHash. Depending on how the API uses datasetItemHash to deduplicate or link results, this could cause subtle cross-run collisions.

This is pre-existing behavior (unchanged in this PR), but the new code path — where datasetItemId is forced to null — makes datasetItemHash the only correlation key for inline items, increasing the impact of this ambiguity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/evals/src/voltops/run.ts` around lines 399 - 416, datasetItemHash
currently uses String(item.itemId ?? item.index) which can collide across runs
when item.itemId is undefined; update the datasetItemHash computation in the
return block (the datasetItemHash variable) to derive a more robust unique key
by combining stable fields (e.g., item.index plus item.datasetVersionId or
datasetId and/or a run identifier) or by computing a short deterministic hash of
JSON.stringify({ index: item.index, datasetId: item.datasetId, datasetVersionId:
item.datasetVersionId }) so inline items across runs don’t share the same
"0","1",... keys; adjust where datasetItemHash is referenced elsewhere if
necessary and keep normalizeDatasetItemId usage unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/evals/src/voltops/run.ts`:
- Around line 419-430: Update isUuid/normalizeDatasetItemId to document the
intentional exclusion of the RFC 9562 nil and max UUIDs: add a concise one-line
comment above isUuid (and/or above normalizeDatasetItemId) stating that the
regex deliberately validates RFC 4122/9562 version/variant bits for v1–v8 and
therefore rejects the all-zero (nil) and all-ff (max) UUIDs, so those values
will be normalized to null; mention that this is intentional to avoid silently
accepting sentinel UUIDs as real dataset_item_id foreign keys.
- Around line 399-416: datasetItemHash currently uses String(item.itemId ??
item.index) which can collide across runs when item.itemId is undefined; update
the datasetItemHash computation in the return block (the datasetItemHash
variable) to derive a more robust unique key by combining stable fields (e.g.,
item.index plus item.datasetVersionId or datasetId and/or a run identifier) or
by computing a short deterministic hash of JSON.stringify({ index: item.index,
datasetId: item.datasetId, datasetVersionId: item.datasetVersionId }) so inline
items across runs don’t share the same "0","1",... keys; adjust where
datasetItemHash is referenced elsewhere if necessary and keep
normalizeDatasetItemId usage unchanged.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 391252d and 4a4394e.

📒 Files selected for processing (5)
  • .changeset/soft-dots-bow.md
  • examples/with-chat-sdk/package.json
  • packages/evals/src/experiment/run-experiment.spec.ts
  • packages/evals/src/voltops/run.spec.ts
  • packages/evals/src/voltops/run.ts

@omeraplak
omeraplak merged commit c1df46f into main Feb 25, 2026
22 of 23 checks passed
@omeraplak
omeraplak deleted the fix/evals-inline-dataset-run-ingestion branch February 25, 2026 02:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant