@copilotkit/aimock 1.37.3 → 1.38.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.
Files changed (166) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +35 -0
  4. package/README.md +27 -9
  5. package/dist/agui-recorder.cjs +6 -0
  6. package/dist/agui-recorder.cjs.map +1 -1
  7. package/dist/agui-recorder.d.cts.map +1 -1
  8. package/dist/agui-recorder.d.ts.map +1 -1
  9. package/dist/agui-recorder.js +6 -0
  10. package/dist/agui-recorder.js.map +1 -1
  11. package/dist/agui-types.d.ts.map +1 -1
  12. package/dist/api-key-auth.cjs +166 -0
  13. package/dist/api-key-auth.cjs.map +1 -0
  14. package/dist/api-key-auth.d.cts +17 -0
  15. package/dist/api-key-auth.d.cts.map +1 -0
  16. package/dist/api-key-auth.d.ts +17 -0
  17. package/dist/api-key-auth.d.ts.map +1 -0
  18. package/dist/api-key-auth.js +158 -0
  19. package/dist/api-key-auth.js.map +1 -0
  20. package/dist/cli.cjs +4 -1
  21. package/dist/cli.cjs.map +1 -1
  22. package/dist/cli.js +4 -1
  23. package/dist/cli.js.map +1 -1
  24. package/dist/config-loader.cjs +4 -2
  25. package/dist/config-loader.cjs.map +1 -1
  26. package/dist/config-loader.d.cts +2 -1
  27. package/dist/config-loader.d.cts.map +1 -1
  28. package/dist/config-loader.d.ts +2 -1
  29. package/dist/config-loader.d.ts.map +1 -1
  30. package/dist/config-loader.js +5 -3
  31. package/dist/config-loader.js.map +1 -1
  32. package/dist/fal-audio.cjs +2 -0
  33. package/dist/fal-audio.cjs.map +1 -1
  34. package/dist/fal-audio.d.cts.map +1 -1
  35. package/dist/fal-audio.d.ts.map +1 -1
  36. package/dist/fal-audio.js +2 -0
  37. package/dist/fal-audio.js.map +1 -1
  38. package/dist/fal.cjs +4 -1
  39. package/dist/fal.cjs.map +1 -1
  40. package/dist/fal.d.cts.map +1 -1
  41. package/dist/fal.d.ts.map +1 -1
  42. package/dist/fal.js +4 -1
  43. package/dist/fal.js.map +1 -1
  44. package/dist/fixture-loader.cjs +0 -0
  45. package/dist/fixture-loader.cjs.map +1 -1
  46. package/dist/fixture-loader.d.cts +3 -1
  47. package/dist/fixture-loader.d.cts.map +1 -1
  48. package/dist/fixture-loader.d.ts +3 -1
  49. package/dist/fixture-loader.d.ts.map +1 -1
  50. package/dist/fixture-loader.js +0 -0
  51. package/dist/fixture-loader.js.map +1 -1
  52. package/dist/grok-video.cjs +9 -2
  53. package/dist/grok-video.cjs.map +1 -1
  54. package/dist/grok-video.js +10 -3
  55. package/dist/grok-video.js.map +1 -1
  56. package/dist/helpers.cjs +16 -22
  57. package/dist/helpers.cjs.map +1 -1
  58. package/dist/helpers.d.cts.map +1 -1
  59. package/dist/helpers.d.ts.map +1 -1
  60. package/dist/helpers.js +16 -21
  61. package/dist/helpers.js.map +1 -1
  62. package/dist/index.d.cts +2 -2
  63. package/dist/index.d.ts +2 -2
  64. package/dist/llmock.cjs +14 -3
  65. package/dist/llmock.cjs.map +1 -1
  66. package/dist/llmock.d.cts +4 -2
  67. package/dist/llmock.d.cts.map +1 -1
  68. package/dist/llmock.d.ts +4 -2
  69. package/dist/llmock.d.ts.map +1 -1
  70. package/dist/llmock.js +15 -5
  71. package/dist/llmock.js.map +1 -1
  72. package/dist/messages.cjs +4 -4
  73. package/dist/messages.cjs.map +1 -1
  74. package/dist/messages.d.cts.map +1 -1
  75. package/dist/messages.d.ts.map +1 -1
  76. package/dist/messages.js +4 -4
  77. package/dist/messages.js.map +1 -1
  78. package/dist/openrouter-chat.cjs +333 -0
  79. package/dist/openrouter-chat.cjs.map +1 -0
  80. package/dist/openrouter-chat.js +325 -0
  81. package/dist/openrouter-chat.js.map +1 -0
  82. package/dist/openrouter-video.cjs +24 -7
  83. package/dist/openrouter-video.cjs.map +1 -1
  84. package/dist/openrouter-video.d.cts.map +1 -1
  85. package/dist/openrouter-video.d.ts.map +1 -1
  86. package/dist/openrouter-video.js +25 -8
  87. package/dist/openrouter-video.js.map +1 -1
  88. package/dist/provider-auth.cjs +20 -0
  89. package/dist/provider-auth.cjs.map +1 -1
  90. package/dist/provider-auth.js +20 -1
  91. package/dist/provider-auth.js.map +1 -1
  92. package/dist/recorder.cjs +51 -9
  93. package/dist/recorder.cjs.map +1 -1
  94. package/dist/recorder.d.cts.map +1 -1
  95. package/dist/recorder.d.ts.map +1 -1
  96. package/dist/recorder.js +52 -12
  97. package/dist/recorder.js.map +1 -1
  98. package/dist/responses.cjs +200 -89
  99. package/dist/responses.cjs.map +1 -1
  100. package/dist/responses.d.cts +18 -3
  101. package/dist/responses.d.cts.map +1 -1
  102. package/dist/responses.d.ts +18 -3
  103. package/dist/responses.d.ts.map +1 -1
  104. package/dist/responses.js +199 -90
  105. package/dist/responses.js.map +1 -1
  106. package/dist/router.cjs +41 -6
  107. package/dist/router.cjs.map +1 -1
  108. package/dist/router.d.cts.map +1 -1
  109. package/dist/router.d.ts.map +1 -1
  110. package/dist/router.js +41 -7
  111. package/dist/router.js.map +1 -1
  112. package/dist/server.cjs +156 -66
  113. package/dist/server.cjs.map +1 -1
  114. package/dist/server.d.cts +1 -1
  115. package/dist/server.d.cts.map +1 -1
  116. package/dist/server.d.ts +1 -1
  117. package/dist/server.d.ts.map +1 -1
  118. package/dist/server.js +157 -68
  119. package/dist/server.js.map +1 -1
  120. package/dist/sse-writer.cjs +3 -0
  121. package/dist/sse-writer.cjs.map +1 -1
  122. package/dist/sse-writer.d.cts +8 -0
  123. package/dist/sse-writer.d.cts.map +1 -1
  124. package/dist/sse-writer.d.ts +8 -0
  125. package/dist/sse-writer.d.ts.map +1 -1
  126. package/dist/sse-writer.js +3 -0
  127. package/dist/sse-writer.js.map +1 -1
  128. package/dist/stream-collapse.cjs +26 -0
  129. package/dist/stream-collapse.cjs.map +1 -1
  130. package/dist/stream-collapse.d.cts +7 -0
  131. package/dist/stream-collapse.d.cts.map +1 -1
  132. package/dist/stream-collapse.d.ts +7 -0
  133. package/dist/stream-collapse.d.ts.map +1 -1
  134. package/dist/stream-collapse.js +26 -0
  135. package/dist/stream-collapse.js.map +1 -1
  136. package/dist/transcription.cjs +49 -2
  137. package/dist/transcription.cjs.map +1 -1
  138. package/dist/transcription.d.cts.map +1 -1
  139. package/dist/transcription.d.ts.map +1 -1
  140. package/dist/transcription.js +50 -3
  141. package/dist/transcription.js.map +1 -1
  142. package/dist/types.d.cts +202 -5
  143. package/dist/types.d.cts.map +1 -1
  144. package/dist/types.d.ts +202 -5
  145. package/dist/types.d.ts.map +1 -1
  146. package/dist/vector-types.d.cts.map +1 -1
  147. package/dist/veo-video.cjs +9 -2
  148. package/dist/veo-video.cjs.map +1 -1
  149. package/dist/veo-video.js +10 -3
  150. package/dist/veo-video.js.map +1 -1
  151. package/dist/ws-realtime.cjs +306 -57
  152. package/dist/ws-realtime.cjs.map +1 -1
  153. package/dist/ws-realtime.d.cts +1 -0
  154. package/dist/ws-realtime.d.cts.map +1 -1
  155. package/dist/ws-realtime.d.ts +1 -0
  156. package/dist/ws-realtime.d.ts.map +1 -1
  157. package/dist/ws-realtime.js +307 -58
  158. package/dist/ws-realtime.js.map +1 -1
  159. package/dist/ws-responses.cjs +11 -6
  160. package/dist/ws-responses.cjs.map +1 -1
  161. package/dist/ws-responses.d.cts.map +1 -1
  162. package/dist/ws-responses.d.ts.map +1 -1
  163. package/dist/ws-responses.js +12 -7
  164. package/dist/ws-responses.js.map +1 -1
  165. package/package.json +1 -1
  166. package/skills/write-fixtures/SKILL.md +81 -47
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.cts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UA0IiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA6MU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;+BAG3C,eACT,QAAQ"}
1
+ {"version":3,"file":"recorder.d.cts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAkMiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA6MU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;+BAG3C,eACT,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.ts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UA0IiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA6MU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;+BAG3C,eACT,QAAQ"}
1
+ {"version":3,"file":"recorder.d.ts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAkMiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA6MU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;+BAG3C,eACT,QAAQ"}
package/dist/recorder.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { DEFAULT_TEST_ID } from "./constants.js";
2
2
  import { normalizeModelName } from "./model-utils.js";
3
+ import { isAuthenticatedRequest, isRecognizedApiKeyHeader } from "./api-key-auth.js";
3
4
  import { getTestId, slugifyContext, slugifyTestId } from "./helpers.js";
4
- import { getLastMessageByRole, getTextContent } from "./router.js";
5
+ import { currentTurnHasToolResult, getLastMessageByRole, getTextContent } from "./router.js";
5
6
  import { writeErrorResponse } from "./sse-writer.js";
6
7
  import { capturedRedactedData, collapseStreamingResponse } from "./stream-collapse.js";
7
8
  import { resolveUpstreamUrl } from "./url.js";
8
- import { applyProviderAuth } from "./provider-auth.js";
9
+ import { applyConfiguredProviderAuth, applyProviderAuth } from "./provider-auth.js";
9
10
  import * as http$1 from "node:http";
10
11
  import * as crypto$1 from "node:crypto";
11
12
  import * as https from "node:https";
@@ -14,6 +15,16 @@ import * as path from "node:path";
14
15
  import { StringDecoder } from "node:string_decoder";
15
16
 
16
17
  //#region src/recorder.ts
18
+ /** True when an SSE frame completes an OpenAI stream. */
19
+ function isTerminalSSEFrame(frame) {
20
+ const data = frame.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n").trim();
21
+ if (data === "[DONE]") return true;
22
+ try {
23
+ return JSON.parse(data).type === "transcript.text.done";
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
17
28
  /** Headers to strip when proxying — hop-by-hop (RFC 2616 §13.5.1) + client-set. */
18
29
  /**
19
30
  * Default ceiling (bytes) for the in-memory proxy-path buffer. Chosen well
@@ -97,11 +108,30 @@ function buildForwardHeaders(req) {
97
108
  const out = {};
98
109
  for (const [name, val] of Object.entries(req.headers)) {
99
110
  const lower = name.toLowerCase();
100
- if (val === void 0 || STRIP_HEADERS.has(lower) || lower.startsWith("x-aimock-chaos-")) continue;
111
+ if (val === void 0 || STRIP_HEADERS.has(lower) || lower.startsWith("x-aimock-chaos-") || isAuthenticatedRequest(req) && isRecognizedApiKeyHeader(lower)) continue;
101
112
  out[name] = Array.isArray(val) ? val.join(", ") : val;
102
113
  }
103
114
  return out;
104
115
  }
116
+ /** Remove every casing of a header from an egress map. */
117
+ function removeForwardHeader(headers, name) {
118
+ const lowerName = name.toLowerCase();
119
+ for (const key of Object.keys(headers)) if (key.toLowerCase() === lowerName) delete headers[key];
120
+ }
121
+ /**
122
+ * Construct the only safe egress map when inbound access control is enabled.
123
+ * Test credentials are always removed; a static configured provider credential
124
+ * is mandatory so an accepted test credential can never become an upstream one.
125
+ */
126
+ function prepareEgressHeaders(req, target, providerKey, configuredKey) {
127
+ const headers = buildForwardHeaders(req);
128
+ if (!isAuthenticatedRequest(req)) {
129
+ applyProviderAuth(headers, target, providerKey, configuredKey);
130
+ return headers;
131
+ }
132
+ for (const name of Object.keys(headers)) if (isRecognizedApiKeyHeader(name)) delete headers[name];
133
+ return configuredKey && applyConfiguredProviderAuth(headers, target, providerKey, configuredKey) ? headers : void 0;
134
+ }
105
135
  /**
106
136
  * Make an arbitrary string safe to set as an HTTP header value. Node's
107
137
  * `res.setHeader` throws ERR_INVALID_CHAR on anything outside Latin-1 (plus
@@ -230,8 +260,14 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
230
260
  return "relayed";
231
261
  }
232
262
  defaults.logger.warn(`NO FIXTURE MATCH — proxying to ${upstreamUrl}${pathname}`);
233
- const forwardHeaders = buildForwardHeaders(req);
234
- applyProviderAuth(forwardHeaders, target, providerKey, record.providerKeys?.[lookupKey]);
263
+ const forwardHeaders = prepareEgressHeaders(req, target, providerKey, record.providerKeys?.[lookupKey]);
264
+ if (!forwardHeaders) {
265
+ writeErrorResponse(res, 502, JSON.stringify({ error: {
266
+ message: "No configured provider credential",
267
+ type: "proxy_error"
268
+ } }));
269
+ return "relayed";
270
+ }
235
271
  const requestBody = rawBody ?? JSON.stringify(request);
236
272
  let upstreamStatus;
237
273
  let upstreamHeaders;
@@ -318,7 +354,8 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
318
354
  if (collapsed.truncated) defaults.logger.warn("Bedrock EventStream: CRC mismatch — response may be truncated");
319
355
  if (collapsed.droppedChunks && collapsed.droppedChunks > 0) defaults.logger.warn(`${collapsed.droppedChunks} chunk(s) dropped during stream collapse${collapsed.firstDroppedSample ? ` — first: ${collapsed.firstDroppedSample}` : ""}`);
320
356
  if (collapsed.harmonyUnparsed) defaults.logger.warn(`Harmony tokens present but unparseable — content preserved verbatim${collapsed.harmonyNote ? ` (${collapsed.harmonyNote})` : ""}`);
321
- if (collapsed.audioB64) {
357
+ if (collapsed.transcription) fixtureResponse = { transcription: collapsed.transcription };
358
+ else if (collapsed.audioB64) {
322
359
  const audioToolCallsSpread = collapsed.toolCalls && collapsed.toolCalls.length > 0 ? { toolCalls: collapsed.toolCalls.map((tc) => ({
323
360
  ...tc,
324
361
  name: tc.name ?? "",
@@ -411,7 +448,7 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
411
448
  json: parsedResponse,
412
449
  status: upstreamStatus
413
450
  };
414
- } else fixtureResponse = buildFixtureResponse(parsedResponse, upstreamStatus, defaults.logger);
451
+ } else fixtureResponse = buildFixtureResponse(parsedResponse, upstreamStatus, defaults.logger, request);
415
452
  }
416
453
  if (clientDisconnected) {
417
454
  if (!sawDone) {
@@ -644,7 +681,7 @@ function makeUpstreamRequest(target, headers, body, clientRes, method = "POST",
644
681
  const frame = parts[fi].trim();
645
682
  if (frame.length > 0) {
646
683
  frameTimestamps.push(Date.now());
647
- if (frame === "data: [DONE]") sawDone = true;
684
+ if (isTerminalSSEFrame(frame)) sawDone = true;
648
685
  }
649
686
  }
650
687
  if (!bufferTruncated) frameBuffer = parts[parts.length - 1];
@@ -737,7 +774,7 @@ function toToolCallArguments(raw) {
737
774
  * Detect the response format from the parsed upstream JSON and convert
738
775
  * it into an aimock FixtureResponse.
739
776
  */
740
- function buildFixtureResponse(parsed, status, logger) {
777
+ function buildFixtureResponse(parsed, status, logger, request) {
741
778
  if (parsed === null || parsed === void 0) return {
742
779
  error: {
743
780
  message: "Upstream returned non-JSON response",
@@ -790,10 +827,13 @@ function buildFixtureResponse(parsed, status, logger) {
790
827
  if (images.length === 1) return { image: images[0] };
791
828
  return { images };
792
829
  }
793
- if (typeof obj.text === "string" && (obj.task === "transcribe" || obj.language !== void 0 && obj.duration !== void 0) && !("choices" in obj) && !("candidates" in obj) && !("object" in obj) && !("message" in obj) && !("outputs" in obj)) return { transcription: {
830
+ const isTranscriptionRequest = request?._endpointType === "transcription" || request?._endpointType === "translation";
831
+ if (typeof obj.text === "string" && (isTranscriptionRequest || obj.task === "transcribe" || obj.language !== void 0 && obj.duration !== void 0) && !("choices" in obj) && !("candidates" in obj) && !("object" in obj) && !("message" in obj) && !("outputs" in obj)) return { transcription: {
794
832
  text: obj.text,
795
833
  ...obj.language ? { language: String(obj.language) } : {},
834
+ ...Array.isArray(obj.languages) ? { languages: obj.languages.filter((language) => typeof language === "object" && language !== null && typeof language.code === "string").map((language) => ({ code: language.code })) } : {},
796
835
  ...obj.duration !== void 0 ? { duration: Number(obj.duration) } : {},
836
+ ...obj.usage && typeof obj.usage === "object" ? { usage: obj.usage } : {},
797
837
  ...Array.isArray(obj.words) ? { words: obj.words } : {},
798
838
  ...Array.isArray(obj.segments) ? { segments: obj.segments } : {}
799
839
  } };
@@ -1101,7 +1141,7 @@ function buildFixtureMatch(request, recordConfig) {
1101
1141
  const messages = request.messages ?? [];
1102
1142
  if (messages.length > 0 && (request._endpointType === "chat" || request._endpointType === void 0)) {
1103
1143
  match.turnIndex = messages.filter((m) => m.role === "assistant").length;
1104
- match.hasToolResult = messages.some((m) => m.role === "tool");
1144
+ match.hasToolResult = currentTurnHasToolResult(messages);
1105
1145
  }
1106
1146
  if (request._context) match.context = request._context;
1107
1147
  return match;
@@ -1120,5 +1160,5 @@ function buildFixtureMetadata(request) {
1120
1160
  }
1121
1161
 
1122
1162
  //#endregion
1123
- export { buildFixtureMatch, buildForwardHeaders, clampTimeout, persistFixture, proxyAndRecord, sanitizeHeaderValue };
1163
+ export { buildFixtureMatch, buildForwardHeaders, clampTimeout, persistFixture, prepareEgressHeaders, proxyAndRecord, removeForwardHeader, sanitizeHeaderValue };
1124
1164
  //# sourceMappingURL=recorder.js.map