Skip to content

Comments

fix(workflow): persist execution metadata and fix SQL metadata filters#1085

Merged
omeraplak merged 1 commit intomainfrom
fix/workflow-execution-metadata-filters
Feb 19, 2026
Merged

fix(workflow): persist execution metadata and fix SQL metadata filters#1085
omeraplak merged 1 commit intomainfrom
fix/workflow-execution-metadata-filters

Conversation

@omeraplak
Copy link
Member

@omeraplak omeraplak commented Feb 19, 2026

PR Checklist

Please check if your PR fulfills the following requirements:

Bugs / Features

What is the current behavior?

/workflows/executions metadata filters (metadata JSON and metadata.<key>) can fail even when execution metadata is provided.

  • Workflow execution options metadata was not persisted into workflow state.
  • SQLite-based adapters compared JSON using json_extract(metadata, ?) = json(?), which does not match text values like "acme".

What is the new behavior?

  • Workflow options.metadata is persisted on workflow state creation.
  • Existing execution metadata is preserved during cancelled/error updates.
  • Server workflow execution schema accepts options.metadata.
  • LibSQL and Cloudflare D1 metadata filters now use JSON-aware comparisons that correctly match scalar values.
  • Added regression tests for:
    • core workflow metadata persistence
    • server-core schema acceptance for options.metadata
    • libsql metadata filter SQL generation
    • cloudflare-d1 metadata filter SQL generation

fixes (issue)

N/A

Notes for reviewers

  • Added changeset: .changeset/workflow-execution-metadata-filters.md
  • Smoke-tested workflow execution listing filters with Postgres and LibSQL after these fixes.

Summary by cubic

Persisted workflow execution metadata and fixed metadata filters so /workflows/executions reliably matches JSON values across adapters. Server now accepts options.metadata, and metadata is preserved on cancel/error updates.

  • New Features

    • Persist options.metadata when creating workflow state.
    • Preserve existing metadata during cancelled/error state updates.
    • Accept options.metadata in server-core execution request schema.
  • Bug Fixes

    • Use JSON-aware comparisons in LibSQL and Cloudflare D1 filters to correctly match scalar values for metadata and metadata..
    • Added regression tests for metadata persistence, schema acceptance, and SQL generation across adapters.

Written for commit ea3e904. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

  • New Features

    • Workflow executions now support custom metadata that persists across execution states.
    • Added metadata-aware filtering for workflow execution queries, enabling tenant and user-based filtering.
    • Server API now accepts metadata in workflow execution requests.
  • Bug Fixes

    • Fixed JSON metadata query comparisons for accurate filtering in LibSQL and Cloudflare D1.

@changeset-bot
Copy link

changeset-bot bot commented Feb 19, 2026

🦋 Changeset detected

Latest commit: ea3e904

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

This PR includes changesets to release 4 packages
Name Type
@voltagent/core Patch
@voltagent/server-core Patch
@voltagent/libsql Patch
@voltagent/cloudflare-d1 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

@joggrbot

This comment has been minimized.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

This PR adds workflow execution metadata filtering support by persisting options.metadata in workflow execution states, accepting metadata in server schemas, and fixing JSON metadata query comparisons for LibSQL and Cloudflare D1 adapters to enable tenant/user-aware filtering.

Changes

Cohort / File(s) Summary
Changeset Documentation
.changeset/workflow-execution-metadata-filters.md
Documents patch version bumps and functional changes for metadata filtering improvements across @voltagent/core, @voltagent/server-core, @voltagent/libsql, and @voltagent/cloudflare-d1.
Core Workflow Metadata Support
packages/core/src/workflow/types.ts, packages/core/src/workflow/core.ts, packages/core/src/workflow/core.spec.ts
Adds optional metadata field to WorkflowRunOptions, introduces mergeExecutionMetadata helper to persist and merge metadata through workflow state lifecycle, and adds test validating metadata persists in workflow state.
LibSQL Adapter Filtering
packages/libsql/src/memory-core.ts, packages/libsql/src/memory-v2-adapter.spec.ts
Updates JSON metadata query comparison from json_extract(metadata, ?) = json(?) to json_extract(metadata, ?) = json_extract(json(?), '$') to properly compare JSON-stored metadata values.
Cloudflare D1 Adapter Filtering
packages/cloudflare-d1/src/memory-adapter.ts, packages/cloudflare-d1/src/memory-adapter.spec.ts
Applies same JSON metadata comparison fix as LibSQL and adds comprehensive test validating queryWorkflowRuns correctly handles JSON decoding and metadata filtering with proper SQL construction.
Server Schema Changes
packages/server-core/src/schemas/agent.schemas.ts, packages/server-core/src/schemas/agent.schemas.spec.ts
Accepts optional metadata field in WorkflowExecutionRequestSchema options and adds test validating options.metadata is correctly preserved in parsed requests.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server as Server<br/>(Schema)
    participant Workflow as Workflow Core<br/>(core.ts)
    participant Memory as Memory Adapter<br/>(queryWorkflowRuns)
    participant DB as Database

    Client->>Server: POST /workflows/executions<br/>{options: {metadata: {...}}}
    Server->>Server: Validate with<br/>WorkflowExecutionRequestSchema
    Server->>Workflow: Execute workflow<br/>with metadata in options
    Workflow->>Workflow: Extract options.metadata<br/>into workflow state
    Workflow->>Memory: Update state with<br/>persisted metadata
    Memory->>DB: Write workflow state<br/>with metadata field
    
    Client->>Server: GET /workflows/executions<br/>?metadata.tenant=x
    Server->>Memory: Query with<br/>metadata filter
    Memory->>DB: Execute query with<br/>json_extract(metadata, path)<br/>= json_extract(json(value), '$')
    DB->>Memory: Return filtered<br/>results
    Memory->>Server: Decode JSON fields<br/>& return executions
    Server->>Client: Filtered workflow executions
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 Metadata hops through our burrow of state,
From client to core, it won't be too late,
JSON extractions compare with finesse,
Filtering workflows by tenant's request! 🌿

🚥 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 clearly describes the main change: fixing workflow execution metadata persistence and SQL metadata filters across adapters.
Description check ✅ Passed The description fully addresses the template with current behavior, new behavior, tests added, changeset included, and comprehensive notes for reviewers.

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

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/workflow-execution-metadata-filters

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.

Copy link
Contributor

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

Choose a reason for hiding this comment

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

No issues found across 10 files

@cloudflare-workers-and-pages
Copy link

Deploying voltagent with  Cloudflare Pages  Cloudflare Pages

Latest commit: ea3e904
Status: ✅  Deploy successful!
Preview URL: https://4615fbbc.voltagent.pages.dev
Branch Preview URL: https://fix-workflow-execution-metad.voltagent.pages.dev

View logs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/cloudflare-d1/src/memory-adapter.spec.ts (1)

57-60: Decoded metadata field not asserted.

The mock row has metadata: '{"tenantId":"acme"}', but the decoded result is never checked. The three other JSON-decoded fields (input, context, workflowState) are verified; skipping metadata leaves its decode path untested.

🔍 Suggested additional assertion
 expect(result[0]?.workflowState).toEqual({ phase: "done" });
+expect(result[0]?.metadata).toEqual({ tenantId: "acme" });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cloudflare-d1/src/memory-adapter.spec.ts` around lines 57 - 60, Add
an assertion that verifies the decoded metadata field on the returned row: after
the existing checks on result, assert that result[0]?.metadata equals the parsed
object { tenantId: "acme" } (the mock row used has metadata:
'{"tenantId":"acme"}'), so the decode path for metadata is covered alongside
input, context, and workflowState.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/cloudflare-d1/src/memory-adapter.spec.ts`:
- Around line 65-70: The test currently asserts the lower-bound "created_at >="
but never checks the upper-bound; update the spec to also assert that the
generated SQL string contains the upper-bound condition "created_at <=" (e.g.,
add expect(sql).toContain("created_at <=")) and optionally verify the
corresponding args entry in the args array matches the supplied `to` value (use
the existing `sql` and `args` variables in memory-adapter.spec.ts to locate
where to add these assertions).

---

Nitpick comments:
In `@packages/cloudflare-d1/src/memory-adapter.spec.ts`:
- Around line 57-60: Add an assertion that verifies the decoded metadata field
on the returned row: after the existing checks on result, assert that
result[0]?.metadata equals the parsed object { tenantId: "acme" } (the mock row
used has metadata: '{"tenantId":"acme"}'), so the decode path for metadata is
covered alongside input, context, and workflowState.

Comment on lines +65 to +70
expect(sql).toContain("workflow_id = ?");
expect(sql).toContain("status = ?");
expect(sql).toContain("created_at >=");
expect(sql).toContain("user_id = ?");
expect(sql).toContain("json_extract(metadata, ?) = json_extract(json(?), '$')");
expect(sql).toContain("ORDER BY created_at DESC");
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

to-filter SQL condition is not asserted.

The test verifies created_at >= (for from) and includes the to-date value in the args array, but never checks the upper-bound SQL condition (e.g., created_at <=). A bug that emits the wrong operator or omits the clause entirely would pass this test.

🔍 Suggested additional assertion
 expect(sql).toContain("created_at >=");
+expect(sql).toContain("created_at <=");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
expect(sql).toContain("workflow_id = ?");
expect(sql).toContain("status = ?");
expect(sql).toContain("created_at >=");
expect(sql).toContain("user_id = ?");
expect(sql).toContain("json_extract(metadata, ?) = json_extract(json(?), '$')");
expect(sql).toContain("ORDER BY created_at DESC");
expect(sql).toContain("workflow_id = ?");
expect(sql).toContain("status = ?");
expect(sql).toContain("created_at >=");
expect(sql).toContain("created_at <=");
expect(sql).toContain("user_id = ?");
expect(sql).toContain("json_extract(metadata, ?) = json_extract(json(?), '$')");
expect(sql).toContain("ORDER BY created_at DESC");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cloudflare-d1/src/memory-adapter.spec.ts` around lines 65 - 70, The
test currently asserts the lower-bound "created_at >=" but never checks the
upper-bound; update the spec to also assert that the generated SQL string
contains the upper-bound condition "created_at <=" (e.g., add
expect(sql).toContain("created_at <=")) and optionally verify the corresponding
args entry in the args array matches the supplied `to` value (use the existing
`sql` and `args` variables in memory-adapter.spec.ts to locate where to add
these assertions).

@omeraplak omeraplak merged commit f275daf into main Feb 19, 2026
23 checks passed
@omeraplak omeraplak deleted the fix/workflow-execution-metadata-filters branch February 19, 2026 22:23
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