Commit dede867
authored
feat: reasoning, web search, and thinking event support (#62)
## Summary
Adds support for reasoning and web search events in fixture responses
across multiple providers:
- **OpenAI Responses API**: Optional `reasoning` field on `TextResponse`
emits `response.reasoning_summary_text.delta` events before text
content. Optional `webSearches` field emits `response.web_search_call`
events.
- **Anthropic Claude**: `reasoning` field emits `thinking` content
blocks before text in `/v1/messages`.
- Both HTTP SSE and WebSocket transports supported.
- Backward compatible — existing fixtures work unchanged.
Closes #60
## Changes
- **`src/types.ts`**: `TextResponse` extended with optional `reasoning?:
string` and `webSearches?: string[]`
- **`src/responses.ts`**: `buildTextStreamEvents` accepts optional
reasoning/webSearches and prepends the appropriate events with correct
`output_index` adjustment. Private helpers `buildReasoningStreamEvents`
and `buildWebSearchStreamEvents` handle individual event sequences.
Non-streaming `buildTextResponse` includes reasoning and web search
output items.
- **`src/messages.ts`**: Emits `thinking` content blocks when
`reasoning` is present (both streaming and non-streaming). Warns when
`webSearches` is used (not supported by Claude API).
- **`src/ws-responses.ts`**: Passes reasoning/webSearches through to
`buildTextStreamEvents` (no duplicated logic)
- **`src/fixture-loader.ts`**: Validates `reasoning` (string) and
`webSearches` (array of strings). Warns on empty reasoning.
- **`src/stream-collapse.ts`**: Extracts reasoning from
`response.reasoning_summary_text.delta`, text from
`response.output_text.delta`, and web searches from
`response.output_item.done` web_search_call events. Claude collapse
extracts reasoning from `thinking_delta` events.
## Example
```typescript
mock.addFixture({
match: { userMessage: "hello" },
response: {
content: "Based on my research, here's what I found.",
reasoning: "Let me think about what the user is asking...",
webSearches: ["latest greeting conventions 2025"],
},
});
```
## Test plan
- [x] Reasoning events emitted correctly in Responses API SSE
- [x] Reasoning deltas reconstruct full text
- [x] Web search events emitted before text events
- [x] Web search items contain query strings
- [x] Combined reasoning + web search + text streaming
- [x] Non-streaming responses include reasoning and web search output
items
- [x] Anthropic thinking blocks (streaming and non-streaming)
- [x] Backward compatibility — plain text fixtures unchanged
- [x] WebSocket reasoning passthrough
- [x] Fixture-loader validation (reasoning type, empty string,
webSearches type/elements)
- [x] Stream-collapse extraction (OpenAI reasoning/text/web search,
Anthropic thinking)
- [x] All 1333 tests pass
- [x] Prettier, ESLint clean10 files changed
Lines changed: 1113 additions & 46 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
844 | 844 | | |
845 | 845 | | |
846 | 846 | | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
| 911 | + | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
847 | 918 | | |
0 commit comments