@thanh01.pmt/curriculum-kit 1.0.14 → 1.0.16

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.
@@ -262,26 +262,38 @@ function extractThoughtAndContent(rawText) {
262
262
  content: content.trim()
263
263
  };
264
264
  }
265
- function createIdleAbortController(idleMs) {
265
+ function createStreamAbortController(options) {
266
+ const envIdle = Number(process.env.ARTIFACT_STREAM_IDLE_TIMEOUT_MS || process.env.STREAM_IDLE_TIMEOUT_MS);
267
+ const envTotal = Number(process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS || process.env.STREAM_TOTAL_TIMEOUT_MS);
268
+ const idleMs = Number.isFinite(options?.idleMs) && options.idleMs > 0 ? options.idleMs : Number.isFinite(envIdle) && envIdle > 0 ? envIdle : DEFAULT_ARTIFACT_STREAM_IDLE_MS;
269
+ const totalMs = Number.isFinite(options?.totalMs) && options.totalMs > 0 ? options.totalMs : Number.isFinite(envTotal) && envTotal > 0 ? envTotal : DEFAULT_ARTIFACT_STREAM_TOTAL_MS;
266
270
  const controller = new AbortController();
267
- let timer = null;
268
- const arm = () => {
269
- if (timer) clearTimeout(timer);
270
- timer = setTimeout(
271
+ let idleTimer = null;
272
+ let totalTimer = null;
273
+ const armIdle = () => {
274
+ if (idleTimer) clearTimeout(idleTimer);
275
+ idleTimer = setTimeout(
271
276
  () => controller.abort(new Error(`Idle timeout: no data for ${Math.round(idleMs / 1e3)}s`)),
272
277
  idleMs
273
278
  );
274
- timer?.unref?.();
279
+ idleTimer?.unref?.();
275
280
  };
276
- arm();
281
+ armIdle();
282
+ if (totalMs > 0) {
283
+ totalTimer = setTimeout(
284
+ () => controller.abort(new Error(`Total stream timeout after ${Math.round(totalMs / 1e3)}s`)),
285
+ totalMs
286
+ );
287
+ totalTimer?.unref?.();
288
+ }
277
289
  return {
278
290
  signal: controller.signal,
279
- /** Reset the idle window (call on every received chunk). */
280
- kick: arm,
281
- /** Clear the pending timer once the request lifecycle is over. */
291
+ kick: armIdle,
282
292
  dispose: () => {
283
- if (timer) clearTimeout(timer);
284
- timer = null;
293
+ if (idleTimer) clearTimeout(idleTimer);
294
+ if (totalTimer) clearTimeout(totalTimer);
295
+ idleTimer = null;
296
+ totalTimer = null;
285
297
  }
286
298
  };
287
299
  }
@@ -468,7 +480,7 @@ Guidelines:
468
480
  if (isNvidiaPreferred || uniqueNvidiaModels.length > 0) {
469
481
  for (const model of uniqueNvidiaModels) {
470
482
  try {
471
- const idle = createIdleAbortController(18e4);
483
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
472
484
  const res = await fetch("https://integrate.api.nvidia.com/v1/chat/completions", {
473
485
  method: "POST",
474
486
  headers: {
@@ -512,7 +524,7 @@ Guidelines:
512
524
  const uniqueOrModels = Array.from(new Set(openrouterModels));
513
525
  for (const model of uniqueOrModels) {
514
526
  try {
515
- const idle = createIdleAbortController(18e4);
527
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
516
528
  const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
517
529
  method: "POST",
518
530
  headers: {
@@ -551,7 +563,7 @@ Guidelines:
551
563
  const dsModel = options.model?.includes("deepseek-reasoner") ? "deepseek-reasoner" : "deepseek-chat";
552
564
  if (isModelAllowed(dsModel)) {
553
565
  try {
554
- const idle = createIdleAbortController(18e4);
566
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
555
567
  const res = await fetch("https://api.deepseek.com/chat/completions", {
556
568
  method: "POST",
557
569
  headers: {
@@ -586,7 +598,7 @@ Guidelines:
586
598
  const baseUrl = alibabaKey.startsWith("sk-sp-") ? "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions" : "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions";
587
599
  for (const qwenModel of qwenModels) {
588
600
  try {
589
- const idle = createIdleAbortController(18e4);
601
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
590
602
  const payload = {
591
603
  model: qwenModel,
592
604
  messages: formattedMessages,
@@ -629,7 +641,7 @@ Guidelines:
629
641
  ];
630
642
  for (const gModel of geminiModels) {
631
643
  try {
632
- const idle = createIdleAbortController(18e4);
644
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
633
645
  const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${gModel}:streamGenerateContent?alt=sse&key=${geminiKey}`, {
634
646
  method: "POST",
635
647
  headers: { "Content-Type": "application/json" },
@@ -665,7 +677,7 @@ Guidelines:
665
677
  const { provider, model } = target;
666
678
  if (provider === "nvidia" && nvidiaKey && isProviderEnabled("nvidia")) {
667
679
  try {
668
- const idle = createIdleAbortController(18e4);
680
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
669
681
  const res = await fetch("https://integrate.api.nvidia.com/v1/chat/completions", {
670
682
  method: "POST",
671
683
  headers: {
@@ -697,7 +709,7 @@ Guidelines:
697
709
  }
698
710
  } else if (provider === "openrouter" && openrouterKey && isProviderEnabled("openrouter")) {
699
711
  try {
700
- const idle = createIdleAbortController(18e4);
712
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
701
713
  const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
702
714
  method: "POST",
703
715
  headers: {
@@ -732,7 +744,7 @@ Guidelines:
732
744
  } else if ((provider === "alibaba" || provider === "dashscope") && alibabaKey && isProviderEnabled("alibaba")) {
733
745
  const baseUrl = alibabaKey.startsWith("sk-sp-") ? "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions" : "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions";
734
746
  try {
735
- const idle = createIdleAbortController(18e4);
747
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
736
748
  const res = await fetch(baseUrl, {
737
749
  method: "POST",
738
750
  headers: {
@@ -764,7 +776,7 @@ Guidelines:
764
776
  }
765
777
  } else if ((provider === "google" || provider === "gemini") && geminiKey && (isProviderEnabled("gemini") || isProviderEnabled("google"))) {
766
778
  try {
767
- const idle = createIdleAbortController(18e4);
779
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
768
780
  const res = await fetch(
769
781
  `https://generativelanguage.googleapis.com/v1beta/models/${model}:streamGenerateContent?alt=sse&key=${geminiKey}`,
770
782
  {
@@ -812,9 +824,12 @@ Guidelines:
812
824
  rawError: providerErrors
813
825
  });
814
826
  }
827
+ var DEFAULT_ARTIFACT_STREAM_IDLE_MS, DEFAULT_ARTIFACT_STREAM_TOTAL_MS;
815
828
  var init_streamRunner = __esm({
816
829
  "src/ai/streamRunner.ts"() {
817
830
  init_errors();
831
+ DEFAULT_ARTIFACT_STREAM_IDLE_MS = 45e3;
832
+ DEFAULT_ARTIFACT_STREAM_TOTAL_MS = 42e4;
818
833
  }
819
834
  });
820
835