@copilotkitnext/runtime 1.51.2-next.1 → 1.51.3-next.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/express.js CHANGED
@@ -377,7 +377,7 @@ async function handleStopAgent({
377
377
  // package.json
378
378
  var package_default = {
379
379
  name: "@copilotkitnext/runtime",
380
- version: "1.51.2-next.1",
380
+ version: "1.51.3-next.0",
381
381
  description: "Server-side runtime package for CopilotKit2",
382
382
  main: "dist/index.js",
383
383
  types: "dist/index.d.ts",
@@ -413,7 +413,6 @@ var package_default = {
413
413
  "@types/express": "^4.17.21",
414
414
  "@types/node": "^22.15.3",
415
415
  eslint: "^9.30.0",
416
- openai: "^5.9.0",
417
416
  supertest: "^7.1.1",
418
417
  tsup: "^8.5.0",
419
418
  typescript: "5.8.2",
@@ -426,11 +425,14 @@ var package_default = {
426
425
  "@copilotkitnext/shared": "workspace:*",
427
426
  cors: "^2.8.5",
428
427
  express: "^4.21.2",
429
- hono: "^4.6.13",
428
+ hono: "^4.11.4",
430
429
  rxjs: "7.8.1"
431
430
  },
432
431
  peerDependencies: {
433
- openai: "^5.9.0"
432
+ "@ag-ui/client": "0.0.42",
433
+ "@ag-ui/core": "0.0.42",
434
+ "@ag-ui/encoder": "0.0.42",
435
+ "@copilotkitnext/shared": "workspace:*"
434
436
  },
435
437
  peerDependenciesMeta: {},
436
438
  engines: {
@@ -528,73 +530,135 @@ async function handleGetRuntimeInfo({
528
530
  }
529
531
 
530
532
  // src/handlers/handle-transcribe.ts
533
+ var import_shared2 = require("@copilotkitnext/shared");
534
+ var ERROR_STATUS_CODES = {
535
+ [import_shared2.TranscriptionErrorCode.SERVICE_NOT_CONFIGURED]: 503,
536
+ [import_shared2.TranscriptionErrorCode.INVALID_AUDIO_FORMAT]: 400,
537
+ [import_shared2.TranscriptionErrorCode.AUDIO_TOO_LONG]: 400,
538
+ [import_shared2.TranscriptionErrorCode.AUDIO_TOO_SHORT]: 400,
539
+ [import_shared2.TranscriptionErrorCode.RATE_LIMITED]: 429,
540
+ [import_shared2.TranscriptionErrorCode.AUTH_FAILED]: 401,
541
+ [import_shared2.TranscriptionErrorCode.PROVIDER_ERROR]: 500,
542
+ [import_shared2.TranscriptionErrorCode.NETWORK_ERROR]: 502,
543
+ [import_shared2.TranscriptionErrorCode.INVALID_REQUEST]: 400
544
+ };
545
+ var VALID_AUDIO_TYPES = [
546
+ "audio/mpeg",
547
+ "audio/mp3",
548
+ "audio/mp4",
549
+ "audio/wav",
550
+ "audio/webm",
551
+ "audio/ogg",
552
+ "audio/flac",
553
+ "audio/aac"
554
+ ];
555
+ function isValidAudioType(type) {
556
+ const baseType = type.split(";")[0]?.trim() ?? "";
557
+ return VALID_AUDIO_TYPES.includes(baseType) || baseType === "" || baseType === "application/octet-stream";
558
+ }
559
+ function createErrorResponse(errorResponse) {
560
+ const status = ERROR_STATUS_CODES[errorResponse.error] ?? 500;
561
+ return new Response(JSON.stringify(errorResponse), {
562
+ status,
563
+ headers: { "Content-Type": "application/json" }
564
+ });
565
+ }
566
+ function base64ToFile(base64, mimeType, filename) {
567
+ const base64Data = base64.includes(",") ? base64.split(",")[1] ?? base64 : base64;
568
+ const binaryString = atob(base64Data);
569
+ const bytes = new Uint8Array(binaryString.length);
570
+ for (let i = 0; i < binaryString.length; i++) {
571
+ bytes[i] = binaryString.charCodeAt(i);
572
+ }
573
+ return new File([bytes], filename, { type: mimeType });
574
+ }
575
+ async function extractAudioFromFormData(request) {
576
+ const formData = await request.formData();
577
+ const audioFile = formData.get("audio");
578
+ if (!audioFile || !(audioFile instanceof File)) {
579
+ const err = import_shared2.TranscriptionErrors.invalidRequest(
580
+ "No audio file found in form data. Please include an 'audio' field."
581
+ );
582
+ return { error: createErrorResponse(err) };
583
+ }
584
+ if (!isValidAudioType(audioFile.type)) {
585
+ const err = import_shared2.TranscriptionErrors.invalidAudioFormat(audioFile.type, VALID_AUDIO_TYPES);
586
+ return { error: createErrorResponse(err) };
587
+ }
588
+ return { file: audioFile };
589
+ }
590
+ async function extractAudioFromJson(request) {
591
+ let body;
592
+ try {
593
+ body = await request.json();
594
+ } catch {
595
+ const err = import_shared2.TranscriptionErrors.invalidRequest("Request body must be valid JSON");
596
+ return { error: createErrorResponse(err) };
597
+ }
598
+ if (!body.audio || typeof body.audio !== "string") {
599
+ const err = import_shared2.TranscriptionErrors.invalidRequest(
600
+ "Request must include 'audio' field with base64-encoded audio data"
601
+ );
602
+ return { error: createErrorResponse(err) };
603
+ }
604
+ if (!body.mimeType || typeof body.mimeType !== "string") {
605
+ const err = import_shared2.TranscriptionErrors.invalidRequest(
606
+ "Request must include 'mimeType' field (e.g., 'audio/webm')"
607
+ );
608
+ return { error: createErrorResponse(err) };
609
+ }
610
+ if (!isValidAudioType(body.mimeType)) {
611
+ const err = import_shared2.TranscriptionErrors.invalidAudioFormat(body.mimeType, VALID_AUDIO_TYPES);
612
+ return { error: createErrorResponse(err) };
613
+ }
614
+ try {
615
+ const filename = body.filename || "recording.webm";
616
+ const file = base64ToFile(body.audio, body.mimeType, filename);
617
+ return { file };
618
+ } catch {
619
+ const err = import_shared2.TranscriptionErrors.invalidRequest("Failed to decode base64 audio data");
620
+ return { error: createErrorResponse(err) };
621
+ }
622
+ }
623
+ function categorizeProviderError(error) {
624
+ const message = error instanceof Error ? error.message : "Unknown error occurred";
625
+ const errorStr = String(error).toLowerCase();
626
+ if (errorStr.includes("rate") || errorStr.includes("429") || errorStr.includes("too many")) {
627
+ return import_shared2.TranscriptionErrors.rateLimited();
628
+ }
629
+ if (errorStr.includes("auth") || errorStr.includes("401") || errorStr.includes("api key") || errorStr.includes("unauthorized")) {
630
+ return import_shared2.TranscriptionErrors.authFailed();
631
+ }
632
+ if (errorStr.includes("too long") || errorStr.includes("duration") || errorStr.includes("length")) {
633
+ return import_shared2.TranscriptionErrors.audioTooLong();
634
+ }
635
+ return import_shared2.TranscriptionErrors.providerError(message);
636
+ }
531
637
  async function handleTranscribe({
532
638
  runtime,
533
639
  request
534
640
  }) {
535
641
  try {
536
642
  if (!runtime.transcriptionService) {
537
- return new Response(
538
- JSON.stringify({
539
- error: "Transcription service not configured",
540
- message: "No transcription service has been configured in the runtime"
541
- }),
542
- {
543
- status: 503,
544
- headers: { "Content-Type": "application/json" }
545
- }
546
- );
547
- }
548
- const contentType = request.headers.get("content-type");
549
- if (!contentType || !contentType.includes("multipart/form-data")) {
550
- return new Response(
551
- JSON.stringify({
552
- error: "Invalid content type",
553
- message: "Request must contain multipart/form-data with an audio file"
554
- }),
555
- {
556
- status: 400,
557
- headers: { "Content-Type": "application/json" }
558
- }
559
- );
643
+ const err = import_shared2.TranscriptionErrors.serviceNotConfigured();
644
+ return createErrorResponse(err);
560
645
  }
561
- const formData = await request.formData();
562
- const audioFile = formData.get("audio");
563
- if (!audioFile || !(audioFile instanceof File)) {
564
- return new Response(
565
- JSON.stringify({
566
- error: "Missing audio file",
567
- message: "No audio file found in form data. Please include an 'audio' field."
568
- }),
569
- {
570
- status: 400,
571
- headers: { "Content-Type": "application/json" }
572
- }
646
+ const contentType = request.headers.get("content-type") || "";
647
+ let extractResult;
648
+ if (contentType.includes("multipart/form-data")) {
649
+ extractResult = await extractAudioFromFormData(request);
650
+ } else if (contentType.includes("application/json")) {
651
+ extractResult = await extractAudioFromJson(request);
652
+ } else {
653
+ const err = import_shared2.TranscriptionErrors.invalidRequest(
654
+ "Request must be multipart/form-data or application/json with base64 audio"
573
655
  );
656
+ return createErrorResponse(err);
574
657
  }
575
- const validAudioTypes = [
576
- "audio/mpeg",
577
- "audio/mp3",
578
- "audio/mp4",
579
- "audio/wav",
580
- "audio/webm",
581
- "audio/ogg",
582
- "audio/flac",
583
- "audio/aac"
584
- ];
585
- const isValidType = validAudioTypes.includes(audioFile.type) || audioFile.type === "" || audioFile.type === "application/octet-stream";
586
- if (!isValidType) {
587
- return new Response(
588
- JSON.stringify({
589
- error: "Invalid file type",
590
- message: `Unsupported audio file type: ${audioFile.type}. Supported types: ${validAudioTypes.join(", ")}, or files with unknown/empty types`
591
- }),
592
- {
593
- status: 400,
594
- headers: { "Content-Type": "application/json" }
595
- }
596
- );
658
+ if ("error" in extractResult) {
659
+ return extractResult.error;
597
660
  }
661
+ const audioFile = extractResult.file;
598
662
  const transcription = await runtime.transcriptionService.transcribeFile({
599
663
  audioFile,
600
664
  mimeType: audioFile.type,
@@ -612,24 +676,15 @@ async function handleTranscribe({
612
676
  }
613
677
  );
614
678
  } catch (error) {
615
- return new Response(
616
- JSON.stringify({
617
- error: "Transcription failed",
618
- message: error instanceof Error ? error.message : "Unknown error occurred during transcription"
619
- }),
620
- {
621
- status: 500,
622
- headers: { "Content-Type": "application/json" }
623
- }
624
- );
679
+ return createErrorResponse(categorizeProviderError(error));
625
680
  }
626
681
  }
627
682
 
628
683
  // src/endpoints/express.ts
629
- var import_shared4 = require("@copilotkitnext/shared");
684
+ var import_shared5 = require("@copilotkitnext/shared");
630
685
 
631
686
  // src/middleware.ts
632
- var import_shared2 = require("@copilotkitnext/shared");
687
+ var import_shared3 = require("@copilotkitnext/shared");
633
688
  async function callBeforeRequestMiddleware({
634
689
  runtime,
635
690
  request,
@@ -640,7 +695,7 @@ async function callBeforeRequestMiddleware({
640
695
  if (typeof mw === "function") {
641
696
  return mw({ runtime, request, path });
642
697
  }
643
- import_shared2.logger.warn({ mw }, "Unsupported beforeRequestMiddleware value \u2013 skipped");
698
+ import_shared3.logger.warn({ mw }, "Unsupported beforeRequestMiddleware value \u2013 skipped");
644
699
  return;
645
700
  }
646
701
  async function callAfterRequestMiddleware({
@@ -653,14 +708,14 @@ async function callAfterRequestMiddleware({
653
708
  if (typeof mw === "function") {
654
709
  return mw({ runtime, response, path });
655
710
  }
656
- import_shared2.logger.warn({ mw }, "Unsupported afterRequestMiddleware value \u2013 skipped");
711
+ import_shared3.logger.warn({ mw }, "Unsupported afterRequestMiddleware value \u2013 skipped");
657
712
  }
658
713
 
659
714
  // src/endpoints/express-utils.ts
660
715
  var import_node_stream = require("stream");
661
716
  var import_node_stream2 = require("stream");
662
717
  var import_node_util = require("util");
663
- var import_shared3 = require("@copilotkitnext/shared");
718
+ var import_shared4 = require("@copilotkitnext/shared");
664
719
  var streamPipeline = (0, import_node_util.promisify)(import_node_stream2.pipeline);
665
720
  var METHODS_WITHOUT_BODY = /* @__PURE__ */ new Set(["GET", "HEAD"]);
666
721
  function createFetchRequestFromExpress(req) {
@@ -696,7 +751,7 @@ function createFetchRequestFromExpress(req) {
696
751
  if (body !== void 0) {
697
752
  init.body = body;
698
753
  }
699
- import_shared3.logger.info(
754
+ import_shared4.logger.info(
700
755
  {
701
756
  url,
702
757
  method,
@@ -708,7 +763,7 @@ function createFetchRequestFromExpress(req) {
708
763
  );
709
764
  } else {
710
765
  headers.delete("content-length");
711
- import_shared3.logger.warn(
766
+ import_shared4.logger.warn(
712
767
  { url, method },
713
768
  "Request stream already consumed but no body was available; sending empty body"
714
769
  );
@@ -736,13 +791,13 @@ function createFetchRequestFromExpress(req) {
736
791
  headers.set("content-type", contentType);
737
792
  }
738
793
  init.body = body;
739
- import_shared3.logger.info(
794
+ import_shared4.logger.info(
740
795
  { url, method },
741
796
  "Request stream disturbed while constructing Request; reused parsed body"
742
797
  );
743
798
  } else {
744
799
  init.body = void 0;
745
- import_shared3.logger.warn(
800
+ import_shared4.logger.warn(
746
801
  { url, method },
747
802
  "Request stream was disturbed; falling back to empty body"
748
803
  );
@@ -839,7 +894,7 @@ function createRouteHandler(runtime, factory) {
839
894
  request = maybeModifiedRequest;
840
895
  }
841
896
  } catch (error) {
842
- import_shared4.logger.error({ err: error, url: request.url, path }, "Error running before request middleware");
897
+ import_shared5.logger.error({ err: error, url: request.url, path }, "Error running before request middleware");
843
898
  if (error instanceof Response) {
844
899
  try {
845
900
  await sendFetchResponse(res, error);
@@ -855,7 +910,7 @@ function createRouteHandler(runtime, factory) {
855
910
  const response = await factory({ request, req });
856
911
  await sendFetchResponse(res, response);
857
912
  callAfterRequestMiddleware({ runtime, response, path }).catch((error) => {
858
- import_shared4.logger.error({ err: error, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
913
+ import_shared5.logger.error({ err: error, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
859
914
  });
860
915
  } catch (error) {
861
916
  if (error instanceof Response) {
@@ -866,11 +921,11 @@ function createRouteHandler(runtime, factory) {
866
921
  return;
867
922
  }
868
923
  callAfterRequestMiddleware({ runtime, response: error, path }).catch((mwError) => {
869
- import_shared4.logger.error({ err: mwError, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
924
+ import_shared5.logger.error({ err: mwError, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
870
925
  });
871
926
  return;
872
927
  }
873
- import_shared4.logger.error({ err: error, url: request.url, path }, "Error running request handler");
928
+ import_shared5.logger.error({ err: error, url: request.url, path }, "Error running request handler");
874
929
  next(error);
875
930
  }
876
931
  };
@@ -903,7 +958,7 @@ function joinPath(basePath, suffix) {
903
958
  // src/endpoints/express-single.ts
904
959
  var import_express2 = __toESM(require("express"));
905
960
  var import_cors2 = __toESM(require("cors"));
906
- var import_shared5 = require("@copilotkitnext/shared");
961
+ var import_shared6 = require("@copilotkitnext/shared");
907
962
 
908
963
  // src/endpoints/single-route-helpers.ts
909
964
  var METHOD_NAMES = [
@@ -1017,7 +1072,7 @@ function createSingleRouteHandler(runtime) {
1017
1072
  request = maybeModifiedRequest;
1018
1073
  }
1019
1074
  } catch (error) {
1020
- import_shared5.logger.error({ err: error, url: request.url, path }, "Error running before request middleware");
1075
+ import_shared6.logger.error({ err: error, url: request.url, path }, "Error running before request middleware");
1021
1076
  if (error instanceof Response) {
1022
1077
  try {
1023
1078
  await sendFetchResponse(res, error);
@@ -1034,7 +1089,7 @@ function createSingleRouteHandler(runtime) {
1034
1089
  methodCall = await parseMethodCall(request);
1035
1090
  } catch (error) {
1036
1091
  if (error instanceof Response) {
1037
- import_shared5.logger.warn({ url: request.url }, "Invalid single-route payload");
1092
+ import_shared6.logger.warn({ url: request.url }, "Invalid single-route payload");
1038
1093
  try {
1039
1094
  await sendFetchResponse(res, error);
1040
1095
  } catch (streamError) {
@@ -1042,7 +1097,7 @@ function createSingleRouteHandler(runtime) {
1042
1097
  }
1043
1098
  return;
1044
1099
  }
1045
- import_shared5.logger.warn({ err: error, url: request.url }, "Invalid single-route payload");
1100
+ import_shared6.logger.warn({ err: error, url: request.url }, "Invalid single-route payload");
1046
1101
  res.status(400).json({
1047
1102
  error: "invalid_request",
1048
1103
  message: error instanceof Error ? error.message : "Invalid request payload"
@@ -1075,7 +1130,8 @@ function createSingleRouteHandler(runtime) {
1075
1130
  break;
1076
1131
  }
1077
1132
  case "transcribe": {
1078
- response = await handleTranscribe({ runtime, request });
1133
+ const handlerRequest = createJsonRequest(request, methodCall.body);
1134
+ response = await handleTranscribe({ runtime, request: handlerRequest });
1079
1135
  break;
1080
1136
  }
1081
1137
  default: {
@@ -1085,7 +1141,7 @@ function createSingleRouteHandler(runtime) {
1085
1141
  }
1086
1142
  await sendFetchResponse(res, response);
1087
1143
  callAfterRequestMiddleware({ runtime, response, path }).catch((error) => {
1088
- import_shared5.logger.error({ err: error, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
1144
+ import_shared6.logger.error({ err: error, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
1089
1145
  });
1090
1146
  } catch (error) {
1091
1147
  if (error instanceof Response) {
@@ -1096,11 +1152,11 @@ function createSingleRouteHandler(runtime) {
1096
1152
  return;
1097
1153
  }
1098
1154
  callAfterRequestMiddleware({ runtime, response: error, path }).catch((mwError) => {
1099
- import_shared5.logger.error({ err: mwError, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
1155
+ import_shared6.logger.error({ err: mwError, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
1100
1156
  });
1101
1157
  return;
1102
1158
  }
1103
- import_shared5.logger.error({ err: error, url: request.url, path }, "Error running single-route handler");
1159
+ import_shared6.logger.error({ err: error, url: request.url, path }, "Error running single-route handler");
1104
1160
  next(error);
1105
1161
  }
1106
1162
  };