Skip to content

feat: add requestTransform for deterministic matching and recording#79

Merged
jpr5 merged 1 commit into
mainfrom
feat/request-transform
Apr 6, 2026
Merged

feat: add requestTransform for deterministic matching and recording#79
jpr5 merged 1 commit into
mainfrom
feat/request-transform

Conversation

@jpr5

@jpr5 jpr5 commented Apr 6, 2026

Copy link
Copy Markdown
Contributor

Summary

From #63. Full credit to @iskhakovt, this is just me taking on the rebase/re-do work from the large 1.7.0 PR that just merged.

Adds requestTransform to MockServerOptions — a function that normalizes requests before both matching and recording, solving the problem of dynamic data (timestamps, UUIDs, session IDs) causing fixture mismatches on replay.

const mock = new LLMock({
  requestTransform: (req) => ({
    ...req,
    messages: req.messages.map(m => ({
      ...m,
      content: typeof m.content === "string"
        ? m.content.replace(/\d{4}-\d{2}-\d{2}T[\d:.+Z]+/g, "")
        : m.content,
    })),
  }),
});

Recording: saves the transformed match key — no timestamps in fixture.
Matching: transforms incoming request before comparison — same clean key.

When requestTransform is set, string matching switches from includes (substring) to === (exact equality). Without a transform, existing includes behavior is preserved (backward compatible).

Changes

  • types.ts: Add requestTransform to MockServerOptions and HandlerDefaults
  • router.ts: Optional 4th param on matchFixture, exact match when transform set
  • server.ts: Thread transform into defaults
  • recorder.ts: Apply transform before match key extraction
  • All 15 provider handlers: Pass defaults.requestTransform to matchFixture
  • docs/record-replay.html: Document the feature with use case and example
  • 16 new tests covering basic transform, exact vs includes, backward compat, embeddings, predicates, streaming, tool calls

Attribution

Based on the design by @iskhakovt in #63, rebuilt cleanly on the 1.7.0 codebase. The original PR had 100 commits and was conflicting after the v1.7.0 rebrand — this is a fresh implementation of the same concept.

Test plan

  • npx vitest run — 2064 tests pass (58 files)
  • npx tsc --noEmit — clean
  • Backward compatible — no transform = existing includes behavior unchanged

Normalizes requests before matching and recording to handle dynamic
data (timestamps, UUIDs, session IDs) in prompts. When set, string
matching switches from includes to exact equality to prevent false
positives from shortened keys.

Applied across all 15 provider handlers + recorder. 16 new tests.

Based on the design by @iskhakovt in #63, rebuilt on the 1.7.0 codebase.
@pkg-pr-new

pkg-pr-new Bot commented Apr 6, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/CopilotKit/aimock/@copilotkit/aimock@79

commit: aafe82a

@jpr5

jpr5 commented Apr 6, 2026

Copy link
Copy Markdown
Contributor Author

Full credit to @iskhakovt, this is just his work rebuilt on top of the new release of aimock.

@jpr5
jpr5 merged commit a989617 into main Apr 6, 2026
18 checks passed
@jpr5
jpr5 deleted the feat/request-transform branch April 6, 2026 15:30
jpr5 added a commit that referenced this pull request Apr 6, 2026
## v1.8.0

### Features
- `requestTransform` — deterministic matching and recording (#79, based
on @iskhakovt's #63)
- Reasoning/thinking for OpenAI Chat Completions (#62 by @erezcor)
- Reasoning for Gemini, Bedrock, Bedrock Converse, Ollama (#81)
- Web search events for OpenAI Responses API (#62)

### Fixes
- Migration page health checks (#80)
- Stream collapse reasoning event handling
- GitHub URLs, OG image, drift docs reframe

### Versions bumped
- `package.json` → 1.8.0
- `plugin.json` → 1.8.0
- `marketplace.json` → ^1.8.0
- `Chart.yaml` appVersion → 1.8.0
- `aimock-pytest/_version.py` AIMOCK_VERSION → 1.8.0
- `CHANGELOG.md` — full v1.8.0 + retroactive v1.7.0 entries

2,090 tests across 59 files. Build clean.
jpr5 added a commit that referenced this pull request Jul 15, 2026
)

## Summary

Adds `requestTransform` to `MockServerOptions` — a function that
normalizes requests before both matching and recording, solving the
problem of dynamic data (timestamps, UUIDs, session IDs) causing fixture
mismatches on replay.

Full credit to @iskhakovt for the patch.

```typescript
const mock = new LLMock({
  requestTransform: (req) => ({
    ...req,
    messages: req.messages.map(m => ({
      ...m,
      content: typeof m.content === "string"
        ? m.content.replace(/\d{4}-\d{2}-\d{2}T[\d:.+Z]+/g, "")
        : m.content,
    })),
  }),
});
```

**Recording**: saves the transformed match key — no timestamps in
fixture.
**Matching**: transforms incoming request before comparison — same clean
key.

When `requestTransform` is set, string matching switches from `includes`
(substring) to `===` (exact equality). Without a transform, existing
`includes` behavior is preserved (backward compatible).

## Changes

- `types.ts`: Add `requestTransform` to `MockServerOptions` and
`HandlerDefaults`
- `router.ts`: Optional 4th param on `matchFixture`, exact match when
transform set
- `server.ts`: Thread transform into defaults
- `recorder.ts`: Apply transform before match key extraction
- All 15 provider handlers: Pass `defaults.requestTransform` to
`matchFixture`
- `docs/record-replay.html`: Document the feature with use case and
example
- 16 new tests covering basic transform, exact vs includes, backward
compat, embeddings, predicates, streaming, tool calls

## Attribution

Based on the design by @iskhakovt in #63, rebuilt cleanly on the 1.7.0
codebase. The original PR had 100 commits and was conflicting after the
v1.7.0 rebrand — this is a fresh implementation of the same concept.

## Test plan

- [x] `npx vitest run` — 2064 tests pass (58 files)
- [x] `npx tsc --noEmit` — clean
- [x] Backward compatible — no transform = existing `includes` behavior
unchanged
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