Skip to content

Commit 19b2703

Browse files
authored
feat: HITL continuation recording/replay support (#233)
## Summary Closes #232. Adds `toolCallId`-based fixture matching so aimock can record and replay HITL (Human-in-the-Loop) continuation requests — the second leg of a `useHumanInTheLoop` flow where the last message is `role: "tool"` instead of `role: "user"`. - Add `toolCallId?: string` to `AGUIFixtureMatch` and `AGUIConfigFixture` - Add `getLastMessageIfToolResult` helper (checks absolute last message only) - Add `toolCallId` check in `matchesFixture` (AND logic with existing fields) - Recorder uses tool-result-first priority: `toolCallId` → user message → sentinel fallback - Add `onToolResult(toolCallId, events, delayMs?)` fluent API method - Config loader passes through `toolCallId` in events path, warns on text shorthand misuse - Export `getLastMessageIfToolResult` from both entry points Also hardens the recorder against pre-existing robustness issues surfaced during CR: - Guard against recording fixtures from error (non-2xx) upstream responses - Add `settled` flag to prevent double-settle on error+end race - Skip disk write for predicate fixtures (`__NO_USER_MESSAGE__` sentinel was semantically broken on reload) - Include parse error reason in SSE warning log ## Test plan - 19 new tests (51 total), all passing - Matcher: toolCallId match, wrong ID, non-tool message, absent toolCallId, AND logic with message, AND logic with stateKey - Fluent API: onToolResult registers and matches, onToolResult with delayMs - Recorder: continuation writes toolCallId fixture, continuation replay, normal request still writes message, sentinel fallback, priority test (tool result wins over user message in history) - Integration: full HITL round-trip — record both legs, replay both without upstream 🤖 Generated with [Claude Code](https://claude.com/claude-code)
2 parents 0b8924f + 3b3fcdb commit 19b2703

13 files changed

Lines changed: 615 additions & 62 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"source": {
1010
"source": "npm",
1111
"package": "@copilotkit/aimock",
12-
"version": "^1.26.1"
12+
"version": "^1.27.0"
1313
},
1414
"description": "Fixture authoring skill for @copilotkit/aimock — LLM, multimedia (image/TTS/transcription/video), MCP, A2A, AG-UI, vector, embeddings, structured output, sequential responses, streaming physics, record/replay, agent loop patterns, and debugging"
1515
}

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aimock",
3-
"version": "1.26.1",
3+
"version": "1.27.0",
44
"description": "Fixture authoring guidance for @copilotkit/aimock — LLM, multimedia, MCP, A2A, AG-UI, vector, and service mocking",
55
"author": {
66
"name": "CopilotKit"

CHANGELOG.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22

33
## [Unreleased]
44

5-
### Fixed
5+
## [1.27.0] - 2026-05-20
66

7-
- **AG-UI recorder**`extractLastUserMessage` now walks structured `content`
8-
arrays (e.g. `[{ type: "text", text: "..." }, { type: "document", source: ... }]`)
9-
and joins their text parts. Previously, structured content fell back to the
10-
`__NO_USER_MESSAGE__` sentinel, producing fixtures that couldn't replay.
7+
### Added
118

12-
### Changed
9+
- **HITL continuation recording/replay support**`toolCallId` matching for continuation fixtures. New `toolCallId` field on `AGUIFixtureMatch` and `AGUIConfigFixture`. `getLastMessageIfToolResult` helper and `onToolResult` fluent API. Recorder uses tool-result-first priority for continuation fixtures. ([#233](https://github.com/CopilotKit/aimock/pull/233), closes [#232](https://github.com/CopilotKit/aimock/issues/232))
10+
11+
### Fixed
1312

14-
- **`AGUIMessage.content` type widened** to `string | AGUIMessageContentPart[]`.
15-
New exported type `AGUIMessageContentPart` describes the per-part shape.
13+
- **Walk structured content arrays in `extractLastUserMessage`** — handle multimodal user content (`AGUIMessageContentPart[]`) by joining text parts and skipping non-text. Export `NO_USER_MESSAGE_SENTINEL` constant and `AGUIMessageContentPart` type. ([#231](https://github.com/CopilotKit/aimock/pull/231))
14+
- **Harden recorder against error responses, double-settle, and broken sentinel persistence** — guard against recording fixtures from non-2xx upstream responses, add `settled` flag to prevent error+end race, skip disk write for predicate fixtures (sentinel was semantically broken on reload), include parse error reason in SSE warning log
1615

1716
## [1.26.1] - 2026-05-19
1817

charts/aimock/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ name: aimock
33
description: Mock infrastructure for AI application testing (OpenAI, Anthropic, Gemini, MCP, A2A, vector)
44
type: application
55
version: 0.1.0
6-
appVersion: "1.26.1"
6+
appVersion: "1.27.0"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@copilotkit/aimock",
3-
"version": "1.26.1",
3+
"version": "1.27.0",
44
"description": "Mock infrastructure for AI application testing — LLM APIs, image generation, text-to-speech, transcription, audio generation, video generation, MCP tools, A2A agents, AG-UI event streams, vector databases, search, rerank, and moderation. One package, one port, zero dependencies.",
55
"license": "MIT",
66
"keywords": [

0 commit comments

Comments
 (0)