@jterrazz/test 6.5.1 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +21 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -8
- package/dist/index.d.ts +10 -8
- package/dist/index.js +21 -8
- package/dist/index.js.map +1 -1
- package/dist/intercept.cjs +107 -105
- package/dist/intercept.cjs.map +1 -1
- package/dist/intercept.d.cts +26 -42
- package/dist/intercept.d.ts +26 -42
- package/dist/intercept.js +107 -105
- package/dist/intercept.js.map +1 -1
- package/dist/types.d.cts +7 -1
- package/dist/types.d.ts +7 -1
- package/package.json +1 -1
package/dist/intercept.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/builder/common/intercept/adapters/anthropic.ts
|
|
2
2
|
const ANTHROPIC_MESSAGES_URL = "https://api.anthropic.com/v1/messages";
|
|
3
|
-
function matchesFilter
|
|
3
|
+
function matchesFilter(body, filter) {
|
|
4
4
|
if (filter.model) {
|
|
5
5
|
const model = body?.model;
|
|
6
6
|
if (typeof filter.model === "string" && model !== filter.model) return false;
|
|
@@ -31,7 +31,7 @@ const anthropic = {
|
|
|
31
31
|
return {
|
|
32
32
|
method: "POST",
|
|
33
33
|
url: ANTHROPIC_MESSAGES_URL,
|
|
34
|
-
match: filter ? (body) => matchesFilter
|
|
34
|
+
match: filter ? (body) => matchesFilter(body, filter) : void 0
|
|
35
35
|
};
|
|
36
36
|
},
|
|
37
37
|
response(data) {
|
|
@@ -76,42 +76,54 @@ const anthropic = {
|
|
|
76
76
|
};
|
|
77
77
|
//#endregion
|
|
78
78
|
//#region src/builder/common/intercept/adapters/http.ts
|
|
79
|
+
/** Default wrap: raw JSON data becomes the response body. */
|
|
80
|
+
function wrapJson(data) {
|
|
81
|
+
return {
|
|
82
|
+
status: 200,
|
|
83
|
+
body: data
|
|
84
|
+
};
|
|
85
|
+
}
|
|
79
86
|
/**
|
|
80
87
|
* Generic HTTP intercept helpers for any URL.
|
|
81
88
|
*
|
|
82
89
|
* @example
|
|
83
|
-
* .intercept(http.get('https://api.example.com/data'),
|
|
84
|
-
* .intercept(http.post('https://api.stripe.com/v1/charges'), {
|
|
90
|
+
* .intercept(http.get('https://api.example.com/data'), 'response.json')
|
|
91
|
+
* .intercept(http.post('https://api.stripe.com/v1/charges'), http.json({ id: 'ch_...' }))
|
|
85
92
|
*/
|
|
86
93
|
const http = {
|
|
87
94
|
get(url) {
|
|
88
95
|
return {
|
|
89
96
|
method: "GET",
|
|
90
|
-
url
|
|
97
|
+
url,
|
|
98
|
+
wrap: wrapJson
|
|
91
99
|
};
|
|
92
100
|
},
|
|
93
101
|
post(url) {
|
|
94
102
|
return {
|
|
95
103
|
method: "POST",
|
|
96
|
-
url
|
|
104
|
+
url,
|
|
105
|
+
wrap: wrapJson
|
|
97
106
|
};
|
|
98
107
|
},
|
|
99
108
|
put(url) {
|
|
100
109
|
return {
|
|
101
110
|
method: "PUT",
|
|
102
|
-
url
|
|
111
|
+
url,
|
|
112
|
+
wrap: wrapJson
|
|
103
113
|
};
|
|
104
114
|
},
|
|
105
115
|
delete(url) {
|
|
106
116
|
return {
|
|
107
117
|
method: "DELETE",
|
|
108
|
-
url
|
|
118
|
+
url,
|
|
119
|
+
wrap: wrapJson
|
|
109
120
|
};
|
|
110
121
|
},
|
|
111
122
|
any(url) {
|
|
112
123
|
return {
|
|
113
124
|
method: "*",
|
|
114
|
-
url
|
|
125
|
+
url,
|
|
126
|
+
wrap: wrapJson
|
|
115
127
|
};
|
|
116
128
|
},
|
|
117
129
|
json(data, status = 200) {
|
|
@@ -131,25 +143,25 @@ const http = {
|
|
|
131
143
|
//#region src/builder/common/intercept/adapters/openai.ts
|
|
132
144
|
const OPENAI_CHAT_URL = "https://api.openai.com/v1/chat/completions";
|
|
133
145
|
const OPENAI_RESPONSES_URL = "https://api.openai.com/v1/responses";
|
|
134
|
-
function
|
|
146
|
+
function matchesChatFilter(body, filter) {
|
|
135
147
|
if (filter.model) {
|
|
136
148
|
const model = body?.model;
|
|
137
149
|
if (typeof filter.model === "string" && model !== filter.model) return false;
|
|
138
150
|
if (filter.model instanceof RegExp && !filter.model.test(model ?? "")) return false;
|
|
139
151
|
}
|
|
140
152
|
if (filter.system) {
|
|
141
|
-
const
|
|
142
|
-
if (typeof filter.system === "string" && !
|
|
143
|
-
if (filter.system instanceof RegExp && !filter.system.test(
|
|
153
|
+
const msg = body?.messages?.find((m) => m.role === "system")?.content ?? "";
|
|
154
|
+
if (typeof filter.system === "string" && !msg.includes(filter.system)) return false;
|
|
155
|
+
if (filter.system instanceof RegExp && !filter.system.test(msg)) return false;
|
|
144
156
|
}
|
|
145
157
|
if (filter.user) {
|
|
146
|
-
const
|
|
147
|
-
if (typeof filter.user === "string" && !
|
|
148
|
-
if (filter.user instanceof RegExp && !filter.user.test(
|
|
158
|
+
const msg = body?.messages?.find((m) => m.role === "user")?.content ?? "";
|
|
159
|
+
if (typeof filter.user === "string" && !msg.includes(filter.user)) return false;
|
|
160
|
+
if (filter.user instanceof RegExp && !filter.user.test(msg)) return false;
|
|
149
161
|
}
|
|
150
162
|
if (filter.tools) {
|
|
151
|
-
const
|
|
152
|
-
if (!filter.tools.every((t) =>
|
|
163
|
+
const names = body?.tools?.map((t) => t.function?.name).filter(Boolean) ?? [];
|
|
164
|
+
if (!filter.tools.every((t) => names.includes(t))) return false;
|
|
153
165
|
}
|
|
154
166
|
if (filter.temperature !== void 0 && body?.temperature !== filter.temperature) return false;
|
|
155
167
|
return true;
|
|
@@ -163,91 +175,94 @@ function matchesResponsesFilter(body, filter) {
|
|
|
163
175
|
if (filter.system) {
|
|
164
176
|
const instructions = body?.instructions ?? "";
|
|
165
177
|
const systemInput = body?.input?.find?.((m) => m.role === "system")?.content ?? "";
|
|
166
|
-
const
|
|
167
|
-
if (typeof filter.system === "string" && !
|
|
168
|
-
if (filter.system instanceof RegExp && !filter.system.test(
|
|
178
|
+
const text = instructions || systemInput;
|
|
179
|
+
if (typeof filter.system === "string" && !text.includes(filter.system)) return false;
|
|
180
|
+
if (filter.system instanceof RegExp && !filter.system.test(text)) return false;
|
|
169
181
|
}
|
|
170
182
|
if (filter.user) {
|
|
171
|
-
const
|
|
172
|
-
if (typeof filter.user === "string" && !
|
|
173
|
-
if (filter.user instanceof RegExp && !filter.user.test(
|
|
183
|
+
const msgs = (body?.input ?? []).filter((m) => m.role === "user").map((m) => typeof m.content === "string" ? m.content : JSON.stringify(m.content)).join(" ");
|
|
184
|
+
if (typeof filter.user === "string" && !msgs.includes(filter.user)) return false;
|
|
185
|
+
if (filter.user instanceof RegExp && !filter.user.test(msgs)) return false;
|
|
174
186
|
}
|
|
175
187
|
if (filter.tools) {
|
|
176
|
-
const
|
|
177
|
-
if (!filter.tools.every((t) =>
|
|
188
|
+
const names = body?.tools?.map((t) => t.name ?? t.function?.name).filter(Boolean) ?? [];
|
|
189
|
+
if (!filter.tools.every((t) => names.includes(t))) return false;
|
|
178
190
|
}
|
|
179
191
|
return true;
|
|
180
192
|
}
|
|
193
|
+
function buildChatReply(data) {
|
|
194
|
+
const content = typeof data === "string" ? data : JSON.stringify(data);
|
|
195
|
+
return {
|
|
196
|
+
status: 200,
|
|
197
|
+
body: {
|
|
198
|
+
id: "chatcmpl-test",
|
|
199
|
+
object: "chat.completion",
|
|
200
|
+
created: Math.floor(Date.now() / 1e3),
|
|
201
|
+
model: "gpt-4o-test",
|
|
202
|
+
choices: [{
|
|
203
|
+
index: 0,
|
|
204
|
+
message: {
|
|
205
|
+
role: "assistant",
|
|
206
|
+
content
|
|
207
|
+
},
|
|
208
|
+
finish_reason: "stop"
|
|
209
|
+
}],
|
|
210
|
+
usage: {
|
|
211
|
+
prompt_tokens: 10,
|
|
212
|
+
completion_tokens: 10,
|
|
213
|
+
total_tokens: 20
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function buildResponsesReply(data) {
|
|
219
|
+
const text = typeof data === "string" ? data : JSON.stringify(data);
|
|
220
|
+
return {
|
|
221
|
+
status: 200,
|
|
222
|
+
body: {
|
|
223
|
+
id: "resp-test",
|
|
224
|
+
object: "response",
|
|
225
|
+
created_at: Math.floor(Date.now() / 1e3),
|
|
226
|
+
model: "gpt-4o-test",
|
|
227
|
+
output: [{
|
|
228
|
+
type: "message",
|
|
229
|
+
id: "msg-test",
|
|
230
|
+
role: "assistant",
|
|
231
|
+
content: [{
|
|
232
|
+
type: "output_text",
|
|
233
|
+
text,
|
|
234
|
+
annotations: []
|
|
235
|
+
}]
|
|
236
|
+
}],
|
|
237
|
+
usage: {
|
|
238
|
+
input_tokens: 10,
|
|
239
|
+
output_tokens: 10,
|
|
240
|
+
total_tokens: 20
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
}
|
|
181
245
|
/**
|
|
182
246
|
* OpenAI API intercept helpers.
|
|
183
247
|
*/
|
|
184
248
|
const openai = {
|
|
185
|
-
|
|
249
|
+
request(filter) {
|
|
186
250
|
return {
|
|
187
251
|
method: "POST",
|
|
188
252
|
url: OPENAI_CHAT_URL,
|
|
189
|
-
match: filter ? (body) =>
|
|
253
|
+
match: filter ? (body) => matchesChatFilter(body, filter) : void 0,
|
|
254
|
+
wrap: buildChatReply
|
|
190
255
|
};
|
|
191
256
|
},
|
|
192
|
-
|
|
257
|
+
agent(filter, url) {
|
|
193
258
|
return {
|
|
194
259
|
method: "POST",
|
|
195
260
|
url: url ?? OPENAI_RESPONSES_URL,
|
|
196
|
-
match: filter ? (body) => matchesResponsesFilter(body, filter) : void 0
|
|
197
|
-
|
|
198
|
-
},
|
|
199
|
-
responsesResponse(data) {
|
|
200
|
-
const text = typeof data === "string" ? data : JSON.stringify(data);
|
|
201
|
-
return {
|
|
202
|
-
status: 200,
|
|
203
|
-
body: {
|
|
204
|
-
id: "resp-test",
|
|
205
|
-
object: "response",
|
|
206
|
-
created_at: Math.floor(Date.now() / 1e3),
|
|
207
|
-
model: "gpt-4o-test",
|
|
208
|
-
output: [{
|
|
209
|
-
type: "message",
|
|
210
|
-
id: "msg-test",
|
|
211
|
-
role: "assistant",
|
|
212
|
-
content: [{
|
|
213
|
-
type: "output_text",
|
|
214
|
-
text,
|
|
215
|
-
annotations: []
|
|
216
|
-
}]
|
|
217
|
-
}],
|
|
218
|
-
usage: {
|
|
219
|
-
input_tokens: 10,
|
|
220
|
-
output_tokens: 10,
|
|
221
|
-
total_tokens: 20
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
},
|
|
226
|
-
response(data) {
|
|
227
|
-
const content = typeof data === "string" ? data : JSON.stringify(data);
|
|
228
|
-
return {
|
|
229
|
-
status: 200,
|
|
230
|
-
body: {
|
|
231
|
-
id: "chatcmpl-test",
|
|
232
|
-
object: "chat.completion",
|
|
233
|
-
created: Math.floor(Date.now() / 1e3),
|
|
234
|
-
model: "gpt-4o-test",
|
|
235
|
-
choices: [{
|
|
236
|
-
index: 0,
|
|
237
|
-
message: {
|
|
238
|
-
role: "assistant",
|
|
239
|
-
content
|
|
240
|
-
},
|
|
241
|
-
finish_reason: "stop"
|
|
242
|
-
}],
|
|
243
|
-
usage: {
|
|
244
|
-
prompt_tokens: 10,
|
|
245
|
-
completion_tokens: 10,
|
|
246
|
-
total_tokens: 20
|
|
247
|
-
}
|
|
248
|
-
}
|
|
261
|
+
match: filter ? (body) => matchesResponsesFilter(body, filter) : void 0,
|
|
262
|
+
wrap: buildResponsesReply
|
|
249
263
|
};
|
|
250
264
|
},
|
|
265
|
+
reply: buildChatReply,
|
|
251
266
|
error(status, message) {
|
|
252
267
|
return {
|
|
253
268
|
status,
|
|
@@ -259,28 +274,7 @@ const openai = {
|
|
|
259
274
|
};
|
|
260
275
|
},
|
|
261
276
|
malformed(content) {
|
|
262
|
-
return
|
|
263
|
-
status: 200,
|
|
264
|
-
body: {
|
|
265
|
-
id: "chatcmpl-test",
|
|
266
|
-
object: "chat.completion",
|
|
267
|
-
created: Math.floor(Date.now() / 1e3),
|
|
268
|
-
model: "gpt-4o-test",
|
|
269
|
-
choices: [{
|
|
270
|
-
index: 0,
|
|
271
|
-
message: {
|
|
272
|
-
role: "assistant",
|
|
273
|
-
content
|
|
274
|
-
},
|
|
275
|
-
finish_reason: "stop"
|
|
276
|
-
}],
|
|
277
|
-
usage: {
|
|
278
|
-
prompt_tokens: 10,
|
|
279
|
-
completion_tokens: 10,
|
|
280
|
-
total_tokens: 20
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
};
|
|
277
|
+
return buildChatReply(content);
|
|
284
278
|
},
|
|
285
279
|
timeout() {
|
|
286
280
|
return {
|
|
@@ -288,7 +282,15 @@ const openai = {
|
|
|
288
282
|
body: {},
|
|
289
283
|
delay: 3e4
|
|
290
284
|
};
|
|
291
|
-
}
|
|
285
|
+
},
|
|
286
|
+
chat(filter) {
|
|
287
|
+
return openai.request(filter);
|
|
288
|
+
},
|
|
289
|
+
response: buildChatReply,
|
|
290
|
+
responses(filter, url) {
|
|
291
|
+
return openai.agent(filter, url);
|
|
292
|
+
},
|
|
293
|
+
responsesResponse: buildResponsesReply
|
|
292
294
|
};
|
|
293
295
|
//#endregion
|
|
294
296
|
export { anthropic, http, openai };
|
package/dist/intercept.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intercept.js","names":["matchesFilter"],"sources":["../src/builder/common/intercept/adapters/anthropic.ts","../src/builder/common/intercept/adapters/http.ts","../src/builder/common/intercept/adapters/openai.ts"],"sourcesContent":["import type { InterceptResponse, InterceptTrigger } from '../types.js';\n\nconst ANTHROPIC_MESSAGES_URL = 'https://api.anthropic.com/v1/messages';\n\nexport interface AnthropicMessagesFilter {\n /** Match by model name. */\n model?: RegExp | string;\n /** Match by system message content. */\n system?: RegExp | string;\n /** Match by user message content. */\n user?: RegExp | string;\n /** Match by tool names. */\n tools?: string[];\n}\n\nfunction matchesFilter(body: any, filter: AnthropicMessagesFilter): boolean {\n if (filter.model) {\n const model = body?.model;\n if (typeof filter.model === 'string' && model !== filter.model) {\n return false;\n }\n if (filter.model instanceof RegExp && !filter.model.test(model ?? '')) {\n return false;\n }\n }\n\n if (filter.system) {\n const system = typeof body?.system === 'string' ? body.system : '';\n if (typeof filter.system === 'string' && !system.includes(filter.system)) {\n return false;\n }\n if (filter.system instanceof RegExp && !filter.system.test(system)) {\n return false;\n }\n }\n\n if (filter.user) {\n const userMsg = body?.messages?.find((m: any) => m.role === 'user')?.content ?? '';\n const text = typeof userMsg === 'string' ? userMsg : JSON.stringify(userMsg);\n if (typeof filter.user === 'string' && !text.includes(filter.user)) {\n return false;\n }\n if (filter.user instanceof RegExp && !filter.user.test(text)) {\n return false;\n }\n }\n\n if (filter.tools) {\n const requestTools = body?.tools?.map((t: any) => t.name).filter(Boolean) ?? [];\n if (!filter.tools.every((t) => requestTools.includes(t))) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Anthropic API intercept helpers.\n */\nexport const anthropic = {\n /**\n * Trigger: match Anthropic messages API requests.\n */\n messages(filter?: AnthropicMessagesFilter): InterceptTrigger {\n return {\n method: 'POST',\n url: ANTHROPIC_MESSAGES_URL,\n match: filter ? (body: unknown) => matchesFilter(body, filter) : undefined,\n };\n },\n\n /** Response: wrap data in Anthropic messages format. */\n response(data: unknown): InterceptResponse {\n const content = typeof data === 'string' ? data : JSON.stringify(data);\n return {\n status: 200,\n body: {\n id: 'msg-test',\n type: 'message',\n role: 'assistant',\n content: [{ type: 'text', text: content }],\n model: 'claude-sonnet-4-20250514',\n stop_reason: 'end_turn',\n usage: { input_tokens: 10, output_tokens: 10 },\n },\n };\n },\n\n /** Response: return an Anthropic error. */\n error(status: number, message?: string): InterceptResponse {\n return {\n status,\n body: {\n type: 'error',\n error: {\n type: status === 429 ? 'rate_limit_error' : 'api_error',\n message: message ?? `Anthropic error (${status})`,\n },\n },\n };\n },\n\n /** Response: simulate a timeout. */\n timeout(): InterceptResponse {\n return { status: 200, body: {}, delay: 30_000 };\n },\n};\n","import type { InterceptResponse, InterceptTrigger } from '../types.js';\n\n/**\n * Generic HTTP intercept helpers for any URL.\n *\n * @example\n * .intercept(http.get('https://api.example.com/data'), { body: [...] })\n * .intercept(http.post('https://api.stripe.com/v1/charges'), { body: { id: 'ch_...' } })\n */\nexport const http = {\n /** Trigger: match GET requests to a URL pattern. */\n get(url: RegExp | string): InterceptTrigger {\n return { method: 'GET', url };\n },\n\n /** Trigger: match POST requests to a URL pattern. */\n post(url: RegExp | string): InterceptTrigger {\n return { method: 'POST', url };\n },\n\n /** Trigger: match PUT requests to a URL pattern. */\n put(url: RegExp | string): InterceptTrigger {\n return { method: 'PUT', url };\n },\n\n /** Trigger: match DELETE requests to a URL pattern. */\n delete(url: RegExp | string): InterceptTrigger {\n return { method: 'DELETE', url };\n },\n\n /** Trigger: match any method to a URL pattern. */\n any(url: RegExp | string): InterceptTrigger {\n return { method: '*', url };\n },\n\n /** Response: simple JSON success. */\n json(data: unknown, status = 200): InterceptResponse {\n return { status, body: data };\n },\n\n /** Response: error with message. */\n error(status: number, message?: string): InterceptResponse {\n return { status, body: { error: message ?? `HTTP ${status}` } };\n },\n};\n","import type { InterceptResponse, InterceptTrigger } from '../types.js';\n\nconst OPENAI_CHAT_URL = 'https://api.openai.com/v1/chat/completions';\nconst OPENAI_RESPONSES_URL = 'https://api.openai.com/v1/responses';\n\nexport interface OpenAIChatFilter {\n /** Match by model name (exact string or regex). */\n model?: RegExp | string;\n /** Match by system message content (regex or substring). */\n system?: RegExp | string;\n /** Match by user message content (regex or substring). */\n user?: RegExp | string;\n /** Match by tool/function names present in the request. */\n tools?: string[];\n /** Match by temperature value. */\n temperature?: number;\n}\n\nfunction matchesFilter(body: any, filter: OpenAIChatFilter): boolean {\n if (filter.model) {\n const model = body?.model;\n if (typeof filter.model === 'string' && model !== filter.model) {\n return false;\n }\n if (filter.model instanceof RegExp && !filter.model.test(model ?? '')) {\n return false;\n }\n }\n\n if (filter.system) {\n const systemMsg = body?.messages?.find((m: any) => m.role === 'system')?.content ?? '';\n if (typeof filter.system === 'string' && !systemMsg.includes(filter.system)) {\n return false;\n }\n if (filter.system instanceof RegExp && !filter.system.test(systemMsg)) {\n return false;\n }\n }\n\n if (filter.user) {\n const userMsg = body?.messages?.find((m: any) => m.role === 'user')?.content ?? '';\n if (typeof filter.user === 'string' && !userMsg.includes(filter.user)) {\n return false;\n }\n if (filter.user instanceof RegExp && !filter.user.test(userMsg)) {\n return false;\n }\n }\n\n if (filter.tools) {\n const requestTools = body?.tools?.map((t: any) => t.function?.name).filter(Boolean) ?? [];\n if (!filter.tools.every((t) => requestTools.includes(t))) {\n return false;\n }\n }\n\n if (filter.temperature !== undefined && body?.temperature !== filter.temperature) {\n return false;\n }\n\n return true;\n}\n\n/** Responses API filter — uses `input` array instead of `messages`. */\nexport interface OpenAIResponsesFilter {\n /** Match by model name. */\n model?: RegExp | string;\n /** Match by system instruction content. */\n system?: RegExp | string;\n /** Match by user input content. */\n user?: RegExp | string;\n /** Match by tool names. */\n tools?: string[];\n}\n\nfunction matchesResponsesFilter(body: any, filter: OpenAIResponsesFilter): boolean {\n if (filter.model) {\n const model = body?.model;\n if (typeof filter.model === 'string' && model !== filter.model) {\n return false;\n }\n if (filter.model instanceof RegExp && !filter.model.test(model ?? '')) {\n return false;\n }\n }\n\n if (filter.system) {\n const instructions = body?.instructions ?? '';\n const systemInput = body?.input?.find?.((m: any) => m.role === 'system')?.content ?? '';\n const systemText = instructions || systemInput;\n if (typeof filter.system === 'string' && !systemText.includes(filter.system)) {\n return false;\n }\n if (filter.system instanceof RegExp && !filter.system.test(systemText)) {\n return false;\n }\n }\n\n if (filter.user) {\n const userInputs = (body?.input ?? [])\n .filter((m: any) => m.role === 'user')\n .map((m: any) =>\n typeof m.content === 'string' ? m.content : JSON.stringify(m.content),\n )\n .join(' ');\n if (typeof filter.user === 'string' && !userInputs.includes(filter.user)) {\n return false;\n }\n if (filter.user instanceof RegExp && !filter.user.test(userInputs)) {\n return false;\n }\n }\n\n if (filter.tools) {\n const requestTools =\n body?.tools?.map((t: any) => t.name ?? t.function?.name).filter(Boolean) ?? [];\n if (!filter.tools.every((t) => requestTools.includes(t))) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * OpenAI API intercept helpers.\n */\nexport const openai = {\n /**\n * Trigger: match OpenAI chat completion requests.\n *\n * @param filter - Optional filters to narrow which requests match.\n *\n * @example\n * openai.chat() // any chat call\n * openai.chat({ model: 'gpt-4o' }) // specific model\n * openai.chat({ system: /classify/ }) // system prompt contains \"classify\"\n * openai.chat({ tools: ['extract_facts'] }) // function calling\n */\n chat(filter?: OpenAIChatFilter): InterceptTrigger {\n return {\n method: 'POST',\n url: OPENAI_CHAT_URL,\n match: filter ? (body: unknown) => matchesFilter(body, filter) : undefined,\n };\n },\n\n /**\n * Trigger: match OpenAI Responses API requests (AI SDK v5+).\n *\n * @param filter - Optional filters. Supports custom gateway URLs.\n * @param url - Override URL for custom gateways (e.g. 'https://gateway.example.com/v1/responses').\n *\n * @example\n * openai.responses() // default URL\n * openai.responses({ user: /Report Ingestion/ }) // match by prompt content\n * openai.responses({ model: 'gpt-4o' }, 'https://my-gateway/v1/responses') // custom gateway\n */\n responses(filter?: OpenAIResponsesFilter, url?: string): InterceptTrigger {\n return {\n method: 'POST',\n url: url ?? OPENAI_RESPONSES_URL,\n match: filter ? (body: unknown) => matchesResponsesFilter(body, filter) : undefined,\n };\n },\n\n /**\n * Response: wrap data in OpenAI Responses API format (AI SDK v5+).\n *\n * @example\n * openai.responsesResponse({ categories: ['TECH'] })\n */\n responsesResponse(data: unknown): InterceptResponse {\n const text = typeof data === 'string' ? data : JSON.stringify(data);\n return {\n status: 200,\n body: {\n id: 'resp-test',\n object: 'response',\n created_at: Math.floor(Date.now() / 1000),\n model: 'gpt-4o-test',\n output: [\n {\n type: 'message',\n id: 'msg-test',\n role: 'assistant',\n content: [{ type: 'output_text', text, annotations: [] }],\n },\n ],\n usage: {\n input_tokens: 10,\n output_tokens: 10,\n total_tokens: 20,\n },\n },\n };\n },\n\n /**\n * Response: wrap data in OpenAI chat completion format.\n *\n * @param data - The content to return (will be JSON.stringified if not a string).\n *\n * @example\n * openai.response({ categories: ['TECH'] })\n */\n response(data: unknown): InterceptResponse {\n const content = typeof data === 'string' ? data : JSON.stringify(data);\n return {\n status: 200,\n body: {\n id: 'chatcmpl-test',\n object: 'chat.completion',\n created: Math.floor(Date.now() / 1000),\n model: 'gpt-4o-test',\n choices: [\n {\n index: 0,\n message: { role: 'assistant', content },\n finish_reason: 'stop',\n },\n ],\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n },\n };\n },\n\n /** Response: return an OpenAI error. */\n error(status: number, message?: string): InterceptResponse {\n return {\n status,\n body: {\n error: {\n message: message ?? `OpenAI error (${status})`,\n type: status === 429 ? 'rate_limit_error' : 'api_error',\n code: status === 429 ? 'rate_limit_exceeded' : null,\n },\n },\n };\n },\n\n /** Response: return malformed (non-JSON) content. */\n malformed(content: string): InterceptResponse {\n return {\n status: 200,\n body: {\n id: 'chatcmpl-test',\n object: 'chat.completion',\n created: Math.floor(Date.now() / 1000),\n model: 'gpt-4o-test',\n choices: [\n {\n index: 0,\n message: { role: 'assistant', content },\n finish_reason: 'stop',\n },\n ],\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n },\n };\n },\n\n /** Response: simulate a timeout (30s delay). */\n timeout(): InterceptResponse {\n return {\n status: 200,\n body: {},\n delay: 30_000,\n };\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"intercept.js","names":[],"sources":["../src/builder/common/intercept/adapters/anthropic.ts","../src/builder/common/intercept/adapters/http.ts","../src/builder/common/intercept/adapters/openai.ts"],"sourcesContent":["import type { InterceptResponse, InterceptTrigger } from '../types.js';\n\nconst ANTHROPIC_MESSAGES_URL = 'https://api.anthropic.com/v1/messages';\n\nexport interface AnthropicMessagesFilter {\n /** Match by model name. */\n model?: RegExp | string;\n /** Match by system message content. */\n system?: RegExp | string;\n /** Match by user message content. */\n user?: RegExp | string;\n /** Match by tool names. */\n tools?: string[];\n}\n\nfunction matchesFilter(body: any, filter: AnthropicMessagesFilter): boolean {\n if (filter.model) {\n const model = body?.model;\n if (typeof filter.model === 'string' && model !== filter.model) {\n return false;\n }\n if (filter.model instanceof RegExp && !filter.model.test(model ?? '')) {\n return false;\n }\n }\n\n if (filter.system) {\n const system = typeof body?.system === 'string' ? body.system : '';\n if (typeof filter.system === 'string' && !system.includes(filter.system)) {\n return false;\n }\n if (filter.system instanceof RegExp && !filter.system.test(system)) {\n return false;\n }\n }\n\n if (filter.user) {\n const userMsg = body?.messages?.find((m: any) => m.role === 'user')?.content ?? '';\n const text = typeof userMsg === 'string' ? userMsg : JSON.stringify(userMsg);\n if (typeof filter.user === 'string' && !text.includes(filter.user)) {\n return false;\n }\n if (filter.user instanceof RegExp && !filter.user.test(text)) {\n return false;\n }\n }\n\n if (filter.tools) {\n const requestTools = body?.tools?.map((t: any) => t.name).filter(Boolean) ?? [];\n if (!filter.tools.every((t) => requestTools.includes(t))) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Anthropic API intercept helpers.\n */\nexport const anthropic = {\n /**\n * Trigger: match Anthropic messages API requests.\n */\n messages(filter?: AnthropicMessagesFilter): InterceptTrigger {\n return {\n method: 'POST',\n url: ANTHROPIC_MESSAGES_URL,\n match: filter ? (body: unknown) => matchesFilter(body, filter) : undefined,\n };\n },\n\n /** Response: wrap data in Anthropic messages format. */\n response(data: unknown): InterceptResponse {\n const content = typeof data === 'string' ? data : JSON.stringify(data);\n return {\n status: 200,\n body: {\n id: 'msg-test',\n type: 'message',\n role: 'assistant',\n content: [{ type: 'text', text: content }],\n model: 'claude-sonnet-4-20250514',\n stop_reason: 'end_turn',\n usage: { input_tokens: 10, output_tokens: 10 },\n },\n };\n },\n\n /** Response: return an Anthropic error. */\n error(status: number, message?: string): InterceptResponse {\n return {\n status,\n body: {\n type: 'error',\n error: {\n type: status === 429 ? 'rate_limit_error' : 'api_error',\n message: message ?? `Anthropic error (${status})`,\n },\n },\n };\n },\n\n /** Response: simulate a timeout. */\n timeout(): InterceptResponse {\n return { status: 200, body: {}, delay: 30_000 };\n },\n};\n","import type { InterceptResponse, InterceptTrigger } from '../types.js';\n\n/** Default wrap: raw JSON data becomes the response body. */\nfunction wrapJson(data: unknown): InterceptResponse {\n return { status: 200, body: data };\n}\n\n/**\n * Generic HTTP intercept helpers for any URL.\n *\n * @example\n * .intercept(http.get('https://api.example.com/data'), 'response.json')\n * .intercept(http.post('https://api.stripe.com/v1/charges'), http.json({ id: 'ch_...' }))\n */\nexport const http = {\n /** Trigger: match GET requests to a URL pattern. */\n get(url: RegExp | string): InterceptTrigger {\n return { method: 'GET', url, wrap: wrapJson };\n },\n\n /** Trigger: match POST requests to a URL pattern. */\n post(url: RegExp | string): InterceptTrigger {\n return { method: 'POST', url, wrap: wrapJson };\n },\n\n /** Trigger: match PUT requests to a URL pattern. */\n put(url: RegExp | string): InterceptTrigger {\n return { method: 'PUT', url, wrap: wrapJson };\n },\n\n /** Trigger: match DELETE requests to a URL pattern. */\n delete(url: RegExp | string): InterceptTrigger {\n return { method: 'DELETE', url, wrap: wrapJson };\n },\n\n /** Trigger: match any method to a URL pattern. */\n any(url: RegExp | string): InterceptTrigger {\n return { method: '*', url, wrap: wrapJson };\n },\n\n /** Response: simple JSON success. */\n json(data: unknown, status = 200): InterceptResponse {\n return { status, body: data };\n },\n\n /** Response: error with message. */\n error(status: number, message?: string): InterceptResponse {\n return { status, body: { error: message ?? `HTTP ${status}` } };\n },\n};\n","import type { InterceptResponse, InterceptTrigger } from '../types.js';\n\nconst OPENAI_CHAT_URL = 'https://api.openai.com/v1/chat/completions';\nconst OPENAI_RESPONSES_URL = 'https://api.openai.com/v1/responses';\n\n// ── Chat Completions filters ──\n\nexport interface OpenAIChatFilter {\n model?: RegExp | string;\n system?: RegExp | string;\n user?: RegExp | string;\n tools?: string[];\n temperature?: number;\n}\n\nfunction matchesChatFilter(body: any, filter: OpenAIChatFilter): boolean {\n if (filter.model) {\n const model = body?.model;\n if (typeof filter.model === 'string' && model !== filter.model) {\n return false;\n }\n if (filter.model instanceof RegExp && !filter.model.test(model ?? '')) {\n return false;\n }\n }\n if (filter.system) {\n const msg = body?.messages?.find((m: any) => m.role === 'system')?.content ?? '';\n if (typeof filter.system === 'string' && !msg.includes(filter.system)) {\n return false;\n }\n if (filter.system instanceof RegExp && !filter.system.test(msg)) {\n return false;\n }\n }\n if (filter.user) {\n const msg = body?.messages?.find((m: any) => m.role === 'user')?.content ?? '';\n if (typeof filter.user === 'string' && !msg.includes(filter.user)) {\n return false;\n }\n if (filter.user instanceof RegExp && !filter.user.test(msg)) {\n return false;\n }\n }\n if (filter.tools) {\n const names = body?.tools?.map((t: any) => t.function?.name).filter(Boolean) ?? [];\n if (!filter.tools.every((t) => names.includes(t))) {\n return false;\n }\n }\n if (filter.temperature !== undefined && body?.temperature !== filter.temperature) {\n return false;\n }\n return true;\n}\n\n// ── Responses API filters ──\n\nexport interface OpenAIResponsesFilter {\n model?: RegExp | string;\n system?: RegExp | string;\n user?: RegExp | string;\n tools?: string[];\n}\n\nfunction matchesResponsesFilter(body: any, filter: OpenAIResponsesFilter): boolean {\n if (filter.model) {\n const model = body?.model;\n if (typeof filter.model === 'string' && model !== filter.model) {\n return false;\n }\n if (filter.model instanceof RegExp && !filter.model.test(model ?? '')) {\n return false;\n }\n }\n if (filter.system) {\n const instructions = body?.instructions ?? '';\n const systemInput = body?.input?.find?.((m: any) => m.role === 'system')?.content ?? '';\n const text = instructions || systemInput;\n if (typeof filter.system === 'string' && !text.includes(filter.system)) {\n return false;\n }\n if (filter.system instanceof RegExp && !filter.system.test(text)) {\n return false;\n }\n }\n if (filter.user) {\n const msgs = (body?.input ?? [])\n .filter((m: any) => m.role === 'user')\n .map((m: any) =>\n typeof m.content === 'string' ? m.content : JSON.stringify(m.content),\n )\n .join(' ');\n if (typeof filter.user === 'string' && !msgs.includes(filter.user)) {\n return false;\n }\n if (filter.user instanceof RegExp && !filter.user.test(msgs)) {\n return false;\n }\n }\n if (filter.tools) {\n const names =\n body?.tools?.map((t: any) => t.name ?? t.function?.name).filter(Boolean) ?? [];\n if (!filter.tools.every((t) => names.includes(t))) {\n return false;\n }\n }\n return true;\n}\n\n// ── Response builders ──\n\nfunction buildChatReply(data: unknown): InterceptResponse {\n const content = typeof data === 'string' ? data : JSON.stringify(data);\n return {\n status: 200,\n body: {\n id: 'chatcmpl-test',\n object: 'chat.completion',\n created: Math.floor(Date.now() / 1000),\n model: 'gpt-4o-test',\n choices: [{ index: 0, message: { role: 'assistant', content }, finish_reason: 'stop' }],\n usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 },\n },\n };\n}\n\nfunction buildResponsesReply(data: unknown): InterceptResponse {\n const text = typeof data === 'string' ? data : JSON.stringify(data);\n return {\n status: 200,\n body: {\n id: 'resp-test',\n object: 'response',\n created_at: Math.floor(Date.now() / 1000),\n model: 'gpt-4o-test',\n output: [\n {\n type: 'message',\n id: 'msg-test',\n role: 'assistant',\n content: [{ type: 'output_text', text, annotations: [] }],\n },\n ],\n usage: { input_tokens: 10, output_tokens: 10, total_tokens: 20 },\n },\n };\n}\n\n// ── Public API ──\n\n/**\n * OpenAI API intercept helpers.\n */\nexport const openai = {\n /**\n * Trigger: match Chat Completions API requests.\n *\n * @example\n * openai.request() // any chat call\n * openai.request({ model: 'gpt-4o' }) // specific model\n * openai.request({ system: /classify/ }) // system prompt match\n */\n request(filter?: OpenAIChatFilter): InterceptTrigger {\n return {\n method: 'POST',\n url: OPENAI_CHAT_URL,\n match: filter ? (body: unknown) => matchesChatFilter(body, filter) : undefined,\n wrap: buildChatReply,\n };\n },\n\n /**\n * Trigger: match Responses API requests (AI SDK v5+) with auto-wrapping.\n * When used with a JSON file, the data is automatically wrapped in the\n * Responses API envelope.\n *\n * @param filter - Optional body filters.\n * @param url - Custom gateway URL (default: api.openai.com).\n *\n * @example\n * openai.agent({ user: /Report Ingestion/ }, GATEWAY)\n */\n agent(filter?: OpenAIResponsesFilter, url?: string): InterceptTrigger {\n return {\n method: 'POST',\n url: url ?? OPENAI_RESPONSES_URL,\n match: filter ? (body: unknown) => matchesResponsesFilter(body, filter) : undefined,\n wrap: buildResponsesReply,\n };\n },\n\n /**\n * Response: wrap data in Chat Completions format.\n *\n * @example\n * openai.reply({ categories: ['TECH'] })\n */\n reply: buildChatReply,\n\n /** Response: return an OpenAI error. */\n error(status: number, message?: string): InterceptResponse {\n return {\n status,\n body: {\n error: {\n message: message ?? `OpenAI error (${status})`,\n type: status === 429 ? 'rate_limit_error' : 'api_error',\n code: status === 429 ? 'rate_limit_exceeded' : null,\n },\n },\n };\n },\n\n /** Response: return malformed content. */\n malformed(content: string): InterceptResponse {\n return buildChatReply(content);\n },\n\n /** Response: simulate a timeout. */\n timeout(): InterceptResponse {\n return { status: 200, body: {}, delay: 30_000 };\n },\n\n // ── Legacy aliases ──\n\n /** @deprecated Use openai.request() instead. */\n chat(filter?: OpenAIChatFilter): InterceptTrigger {\n return openai.request(filter);\n },\n\n /** @deprecated Use openai.reply() instead. */\n response: buildChatReply,\n\n /** @deprecated Use openai.agent() instead. */\n responses(filter?: OpenAIResponsesFilter, url?: string): InterceptTrigger {\n return openai.agent(filter, url);\n },\n\n /** @deprecated Use openai.reply() or .intercept(trigger, 'file.json') instead. */\n responsesResponse: buildResponsesReply,\n};\n"],"mappings":"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"}
|
package/dist/types.d.cts
CHANGED
|
@@ -7,8 +7,14 @@ interface InterceptTrigger {
|
|
|
7
7
|
method: string;
|
|
8
8
|
/** URL pattern to match (string for exact prefix, RegExp for pattern). */
|
|
9
9
|
url: RegExp | string;
|
|
10
|
-
/** Optional request body matcher
|
|
10
|
+
/** Optional request body matcher - the handler only fires if this returns true. */
|
|
11
11
|
match?: (body: unknown) => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Optional wrapper - transforms raw JSON data into a provider-specific response.
|
|
14
|
+
* Used when .intercept(trigger, 'file.json') loads a file: the raw data is
|
|
15
|
+
* passed through wrap() to produce the correct response envelope.
|
|
16
|
+
*/
|
|
17
|
+
wrap?: (data: unknown) => InterceptResponse;
|
|
12
18
|
}
|
|
13
19
|
/**
|
|
14
20
|
* An intercept response describes what to return when the trigger matches.
|
package/dist/types.d.ts
CHANGED
|
@@ -7,8 +7,14 @@ interface InterceptTrigger {
|
|
|
7
7
|
method: string;
|
|
8
8
|
/** URL pattern to match (string for exact prefix, RegExp for pattern). */
|
|
9
9
|
url: RegExp | string;
|
|
10
|
-
/** Optional request body matcher
|
|
10
|
+
/** Optional request body matcher - the handler only fires if this returns true. */
|
|
11
11
|
match?: (body: unknown) => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Optional wrapper - transforms raw JSON data into a provider-specific response.
|
|
14
|
+
* Used when .intercept(trigger, 'file.json') loads a file: the raw data is
|
|
15
|
+
* passed through wrap() to produce the correct response envelope.
|
|
16
|
+
*/
|
|
17
|
+
wrap?: (data: unknown) => InterceptResponse;
|
|
12
18
|
}
|
|
13
19
|
/**
|
|
14
20
|
* An intercept response describes what to return when the trigger matches.
|