feat: add session metadata filter - #591
Conversation
|
| * (exact string equality; extra session keys are allowed). `undefined` or `{}` | ||
| * means no metadata filter. | ||
| */ | ||
| metadata: SessionMetadata | undefined; |
There was a problem hiding this comment.
Metadata filter lacks contract tests
Medium Severity
listSessions now filters on metadata, but storeContractSuite.ts only threads metadata: undefined through existing cases. Postgres uses @>, SQLite uses json_each on a JSONB blob, and in-memory uses JS equality. Shared filter invariants belong in the contract suite so those backends cannot silently diverge.
Additional Locations (1)
Triggered by project rule: @truefoundry/trueforge-core review rules
Reviewed by Cursor Bugbot for commit dff7976. Configure here.
| .string() | ||
| .min(1) | ||
| .max(SESSION_METADATA_MAX_KEY_LENGTH) | ||
| .regex(SESSION_METADATA_KEY_PATTERN) |
There was a problem hiding this comment.
Stricter metadata keys break reads
Medium Severity
SessionMetadataSchema now rejects keys that are not alphanumeric plus . _ : -. The same schema parses persisted session.metadata on read. Existing rows with previously valid keys (spaces, slashes, leading _) will fail get/list with no data rewrite.
Additional Locations (2)
Triggered by project rule: @truefoundry/trueforge review rules
Reviewed by Cursor Bugbot for commit dff7976. Configure here.
| * (exact string equality; extra session keys are allowed). `undefined` or `{}` | ||
| * means no metadata filter. | ||
| */ | ||
| metadata: SessionMetadata | undefined; |
There was a problem hiding this comment.
Published packages missing changeset
Low Severity
This PR changes shipped packages @truefoundry/trueforge-core and @truefoundry/trueforge and does not add a .changeset/*.md file. Existing session-metadata.md covers the earlier metadata column, not this list filter. Run pnpm changeset for those two packages.
Additional Locations (1)
Triggered by project rule: TrueForge review rules
Reviewed by Cursor Bugbot for commit dff7976. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
There are 4 total unresolved issues (including 3 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 14561cf. Configure here.
| start_timestamp: startTimestamp != null ? startTimestamp?.toISOString() : undefined, | ||
| end_timestamp: endTimestamp != null ? endTimestamp?.toISOString() : undefined, | ||
| agent_id: agentId, | ||
| metadata: metadata != null ? toJson(metadata) : undefined, |
There was a problem hiding this comment.
SDK metadata filter serializes JSON
High Severity
sessions.list JSON-stringifies metadata into a bare metadata query param. The server only accepts metadata[key]=value and rejects that form, so SDK callers who pass metadata get an error instead of filtered sessions.
Reviewed by Cursor Bugbot for commit 14561cf. Configure here.


Summary
Closes #
Changes
How was this tested?
Checklist
pnpm build,pnpm test,pnpm typecheck,pnpm lint:ci, andpnpm format:checkpass locallypackages/trueforge-sdk,.github/fern/openapi/openapi.json,docs/openapi.json) — fork PRs omit SDK regen; maintainers regenerate after merge.env.exampleupdated if configuration or behavior changedNote
Medium Risk
Adds a new list API filter and query parsing surface, plus a Postgres GIN migration; behavior is covered by tests but affects session listing for all tenants.
Overview
List sessions now accepts optional
metadata[key]=valuefilters (OpenAPI deepObject). Sessions must contain all specified key/value pairs (exact match; extra metadata on the session is allowed). The list handler parses Hono’s flat query keys viafoldListSessionsMetadataQuery/parseListSessionsQuery, with validation caps (e.g. max 10 filter keys) and rejection of baremetadata=, nested brackets, and duplicate keys.Session metadata keys are tightened with a regex so keys cannot include
[]or whitespace—aligned with deepObject query encoding and reserved nested forms. Create-session validation tests cover invalid charset keys.Persistence:
listSessionsgains an optionalmetadatafilter on the store contract; in-memory, Postgres (metadata @>+ new GIN index migration), and SQLite (json_each) all implement containment filtering. SDK/OpenAPI/Fern docs and generated client passmetadataonsessions.list(); Fernobject-query-parametersis enabled for this shape.Reviewed by Cursor Bugbot for commit 14561cf. Bugbot is set up for automated code reviews on this repo. Configure here.