@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.
@@ -1,4 +1,4 @@
1
- import { S as StreamRunnerOptions } from '../streamRunner-CcpmxOf1.cjs';
1
+ import { S as StreamRunnerOptions } from '../streamRunner-DtQq0HV_.cjs';
2
2
 
3
3
  /**
4
4
  * Media Types — image generation, image search, video search cho học liệu.
@@ -57,6 +57,8 @@ interface GenerateImageOptions {
57
57
  provider?: MediaProvider;
58
58
  /** API key override (nếu không dùng env) */
59
59
  apiKey?: string;
60
+ /** Timeout tổng cho request sinh ảnh (mặc định 420_000ms = 7 phút) */
61
+ timeoutMs?: number;
60
62
  }
61
63
  interface SearchImageOptions {
62
64
  query: string;
@@ -1,4 +1,4 @@
1
- import { S as StreamRunnerOptions } from '../streamRunner-CcpmxOf1.js';
1
+ import { S as StreamRunnerOptions } from '../streamRunner-DtQq0HV_.js';
2
2
 
3
3
  /**
4
4
  * Media Types — image generation, image search, video search cho học liệu.
@@ -57,6 +57,8 @@ interface GenerateImageOptions {
57
57
  provider?: MediaProvider;
58
58
  /** API key override (nếu không dùng env) */
59
59
  apiKey?: string;
60
+ /** Timeout tổng cho request sinh ảnh (mặc định 420_000ms = 7 phút) */
61
+ timeoutMs?: number;
60
62
  }
61
63
  interface SearchImageOptions {
62
64
  query: string;
@@ -41,6 +41,10 @@ function resolveApiKey(options) {
41
41
  }
42
42
  return { provider, key };
43
43
  }
44
+ function resolveImageTimeout(options) {
45
+ const envTimeout = Number(process.env.IMAGE_GEN_TIMEOUT_MS || process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS);
46
+ return Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : 42e4;
47
+ }
44
48
  async function generateWithGemini(options, key) {
45
49
  const finalPrompt = buildImagePrompt(options);
46
50
  const model = "gemini-2.0-flash-exp";
@@ -51,7 +55,7 @@ async function generateWithGemini(options, key) {
51
55
  contents: [{ parts: [{ text: finalPrompt }] }],
52
56
  generationConfig: { responseModalities: ["TEXT", "IMAGE"] }
53
57
  }),
54
- signal: AbortSignal.timeout(9e4)
58
+ signal: AbortSignal.timeout(resolveImageTimeout(options))
55
59
  });
56
60
  if (!res.ok) {
57
61
  const body = await res.text().catch(() => "");
@@ -84,7 +88,7 @@ async function generateWithOpenAI(options, key) {
84
88
  size: sizeMap[options.aspectRatio || "1:1"] || "1024x1024",
85
89
  n: 1
86
90
  }),
87
- signal: AbortSignal.timeout(9e4)
91
+ signal: AbortSignal.timeout(resolveImageTimeout(options))
88
92
  });
89
93
  if (!res.ok) {
90
94
  const body = await res.text().catch(() => "");
@@ -495,26 +499,40 @@ function extractThoughtAndContent(rawText) {
495
499
  content: content.trim()
496
500
  };
497
501
  }
498
- function createIdleAbortController(idleMs) {
502
+ var DEFAULT_ARTIFACT_STREAM_IDLE_MS = 45e3;
503
+ var DEFAULT_ARTIFACT_STREAM_TOTAL_MS = 42e4;
504
+ function createStreamAbortController(options) {
505
+ const envIdle = Number(process.env.ARTIFACT_STREAM_IDLE_TIMEOUT_MS || process.env.STREAM_IDLE_TIMEOUT_MS);
506
+ const envTotal = Number(process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS || process.env.STREAM_TOTAL_TIMEOUT_MS);
507
+ const idleMs = Number.isFinite(options?.idleMs) && options.idleMs > 0 ? options.idleMs : Number.isFinite(envIdle) && envIdle > 0 ? envIdle : DEFAULT_ARTIFACT_STREAM_IDLE_MS;
508
+ const totalMs = Number.isFinite(options?.totalMs) && options.totalMs > 0 ? options.totalMs : Number.isFinite(envTotal) && envTotal > 0 ? envTotal : DEFAULT_ARTIFACT_STREAM_TOTAL_MS;
499
509
  const controller = new AbortController();
500
- let timer = null;
501
- const arm = () => {
502
- if (timer) clearTimeout(timer);
503
- timer = setTimeout(
510
+ let idleTimer = null;
511
+ let totalTimer = null;
512
+ const armIdle = () => {
513
+ if (idleTimer) clearTimeout(idleTimer);
514
+ idleTimer = setTimeout(
504
515
  () => controller.abort(new Error(`Idle timeout: no data for ${Math.round(idleMs / 1e3)}s`)),
505
516
  idleMs
506
517
  );
507
- timer?.unref?.();
518
+ idleTimer?.unref?.();
508
519
  };
509
- arm();
520
+ armIdle();
521
+ if (totalMs > 0) {
522
+ totalTimer = setTimeout(
523
+ () => controller.abort(new Error(`Total stream timeout after ${Math.round(totalMs / 1e3)}s`)),
524
+ totalMs
525
+ );
526
+ totalTimer?.unref?.();
527
+ }
510
528
  return {
511
529
  signal: controller.signal,
512
- /** Reset the idle window (call on every received chunk). */
513
- kick: arm,
514
- /** Clear the pending timer once the request lifecycle is over. */
530
+ kick: armIdle,
515
531
  dispose: () => {
516
- if (timer) clearTimeout(timer);
517
- timer = null;
532
+ if (idleTimer) clearTimeout(idleTimer);
533
+ if (totalTimer) clearTimeout(totalTimer);
534
+ idleTimer = null;
535
+ totalTimer = null;
518
536
  }
519
537
  };
520
538
  }
@@ -697,7 +715,7 @@ Guidelines:
697
715
  if (isNvidiaPreferred || uniqueNvidiaModels.length > 0) {
698
716
  for (const model of uniqueNvidiaModels) {
699
717
  try {
700
- const idle = createIdleAbortController(18e4);
718
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
701
719
  const res = await fetch("https://integrate.api.nvidia.com/v1/chat/completions", {
702
720
  method: "POST",
703
721
  headers: {
@@ -741,7 +759,7 @@ Guidelines:
741
759
  const uniqueOrModels = Array.from(new Set(openrouterModels));
742
760
  for (const model of uniqueOrModels) {
743
761
  try {
744
- const idle = createIdleAbortController(18e4);
762
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
745
763
  const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
746
764
  method: "POST",
747
765
  headers: {
@@ -780,7 +798,7 @@ Guidelines:
780
798
  const dsModel = options.model?.includes("deepseek-reasoner") ? "deepseek-reasoner" : "deepseek-chat";
781
799
  if (isModelAllowed(dsModel)) {
782
800
  try {
783
- const idle = createIdleAbortController(18e4);
801
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
784
802
  const res = await fetch("https://api.deepseek.com/chat/completions", {
785
803
  method: "POST",
786
804
  headers: {
@@ -815,7 +833,7 @@ Guidelines:
815
833
  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";
816
834
  for (const qwenModel of qwenModels) {
817
835
  try {
818
- const idle = createIdleAbortController(18e4);
836
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
819
837
  const payload = {
820
838
  model: qwenModel,
821
839
  messages: formattedMessages,
@@ -858,7 +876,7 @@ Guidelines:
858
876
  ];
859
877
  for (const gModel of geminiModels) {
860
878
  try {
861
- const idle = createIdleAbortController(18e4);
879
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
862
880
  const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${gModel}:streamGenerateContent?alt=sse&key=${geminiKey}`, {
863
881
  method: "POST",
864
882
  headers: { "Content-Type": "application/json" },
@@ -894,7 +912,7 @@ Guidelines:
894
912
  const { provider, model } = target;
895
913
  if (provider === "nvidia" && nvidiaKey && isProviderEnabled("nvidia")) {
896
914
  try {
897
- const idle = createIdleAbortController(18e4);
915
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
898
916
  const res = await fetch("https://integrate.api.nvidia.com/v1/chat/completions", {
899
917
  method: "POST",
900
918
  headers: {
@@ -926,7 +944,7 @@ Guidelines:
926
944
  }
927
945
  } else if (provider === "openrouter" && openrouterKey && isProviderEnabled("openrouter")) {
928
946
  try {
929
- const idle = createIdleAbortController(18e4);
947
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
930
948
  const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
931
949
  method: "POST",
932
950
  headers: {
@@ -961,7 +979,7 @@ Guidelines:
961
979
  } else if ((provider === "alibaba" || provider === "dashscope") && alibabaKey && isProviderEnabled("alibaba")) {
962
980
  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";
963
981
  try {
964
- const idle = createIdleAbortController(18e4);
982
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
965
983
  const res = await fetch(baseUrl, {
966
984
  method: "POST",
967
985
  headers: {
@@ -993,7 +1011,7 @@ Guidelines:
993
1011
  }
994
1012
  } else if ((provider === "google" || provider === "gemini") && geminiKey && (isProviderEnabled("gemini") || isProviderEnabled("google"))) {
995
1013
  try {
996
- const idle = createIdleAbortController(18e4);
1014
+ const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });
997
1015
  const res = await fetch(
998
1016
  `https://generativelanguage.googleapis.com/v1beta/models/${model}:streamGenerateContent?alt=sse&key=${geminiKey}`,
999
1017
  {