@agent-native/core 0.84.58 → 0.84.60

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,5 +1,22 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.84.60
4
+
5
+ ### Patch Changes
6
+
7
+ - 4b6ca6c: Loosen the document script CSP allowances so hosted Google Tag Manager scripts and framework inline bootstrap scripts do not trigger CSP violations.
8
+
9
+ ## 0.84.59
10
+
11
+ ### Patch Changes
12
+
13
+ - 13379f1: Fix empty responses from non-Anthropic models (GPT-5.x, Gemini) on the Builder
14
+ gateway. Action tool schemas generated from `z.record(...)` emitted a
15
+ `propertyNames` JSON Schema keyword that OpenAI's function-calling validator
16
+ rejects with `400 invalid_function_parameters`, producing an empty assistant
17
+ turn. Tool schemas now strip `propertyNames` so they stay portable across
18
+ providers (Anthropic already ignored it).
19
+
3
20
  ## 0.84.58
4
21
 
5
22
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.84.58",
3
+ "version": "0.84.60",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -832,6 +832,80 @@ function wrapRunWithAudit(
832
832
  // Schema → JSON Schema conversion
833
833
  // ---------------------------------------------------------------------------
834
834
 
835
+ // Keywords whose value is a single subschema.
836
+ const SUBSCHEMA_VALUE_KEYS = [
837
+ "items",
838
+ "additionalItems",
839
+ "contains",
840
+ "additionalProperties",
841
+ "not",
842
+ "if",
843
+ "then",
844
+ "else",
845
+ ] as const;
846
+ // Keywords whose value is an array of subschemas.
847
+ const SUBSCHEMA_ARRAY_KEYS = [
848
+ "allOf",
849
+ "anyOf",
850
+ "oneOf",
851
+ "prefixItems",
852
+ ] as const;
853
+ // Keywords whose value is a map of name → subschema.
854
+ const SUBSCHEMA_MAP_KEYS = [
855
+ "properties",
856
+ "patternProperties",
857
+ "$defs",
858
+ "definitions",
859
+ "dependentSchemas",
860
+ ] as const;
861
+
862
+ /**
863
+ * Remove JSON Schema keywords that some providers' function-calling schema
864
+ * validators reject. OpenAI (and Gemini via the Builder gateway) reject
865
+ * `propertyNames` — which Zod v4 emits for `z.record(z.string(), …)` — with a
866
+ * `400 invalid_function_parameters` error, causing the model turn to produce no
867
+ * content (surfacing as an empty assistant response). Anthropic ignores the
868
+ * keyword, so stripping it is safe across providers and keeps action schemas
869
+ * portable. `propertyNames` only constrained object *keys*; the value/shape of
870
+ * the object is unaffected by its removal.
871
+ *
872
+ * Only descends through actual subschema positions (properties, items, union
873
+ * branches, definitions, etc.) — never through value-bearing keywords like
874
+ * `default`, `const`, `enum`, or `examples`, whose objects may legitimately
875
+ * contain a `propertyNames` data key that must be preserved.
876
+ */
877
+ function stripUnsupportedSchemaKeywords<T>(node: T): T {
878
+ if (!node || typeof node !== "object" || Array.isArray(node)) return node;
879
+ const obj = node as Record<string, unknown>;
880
+
881
+ delete obj.propertyNames;
882
+
883
+ for (const key of SUBSCHEMA_VALUE_KEYS) {
884
+ // `items`/`additionalItems` may also be an array of subschemas.
885
+ const value = obj[key];
886
+ if (Array.isArray(value)) {
887
+ for (const sub of value) stripUnsupportedSchemaKeywords(sub);
888
+ } else {
889
+ stripUnsupportedSchemaKeywords(value);
890
+ }
891
+ }
892
+ for (const key of SUBSCHEMA_ARRAY_KEYS) {
893
+ const value = obj[key];
894
+ if (Array.isArray(value)) {
895
+ for (const sub of value) stripUnsupportedSchemaKeywords(sub);
896
+ }
897
+ }
898
+ for (const key of SUBSCHEMA_MAP_KEYS) {
899
+ const value = obj[key];
900
+ if (value && typeof value === "object" && !Array.isArray(value)) {
901
+ for (const sub of Object.values(value)) {
902
+ stripUnsupportedSchemaKeywords(sub);
903
+ }
904
+ }
905
+ }
906
+ return node;
907
+ }
908
+
835
909
  /**
836
910
  * Convert a Standard Schema to JSON Schema for the Claude API.
837
911
  * Tries vendor-specific toJSONSchema first (Zod v4), then falls back
@@ -855,7 +929,7 @@ function schemaToJsonSchema(
855
929
  if (result && typeof result === "object") {
856
930
  delete result.$schema;
857
931
  }
858
- return result as ActionTool["parameters"];
932
+ return stripUnsupportedSchemaKeywords(result) as ActionTool["parameters"];
859
933
  } catch {
860
934
  // Fall through to manual converter
861
935
  }
@@ -863,7 +937,7 @@ function schemaToJsonSchema(
863
937
 
864
938
  // Fallback: manual conversion from Zod v4 internal defs
865
939
  if (s._zod?.def) {
866
- return zodDefToJsonSchema(s._zod.def);
940
+ return stripUnsupportedSchemaKeywords(zodDefToJsonSchema(s._zod.def));
867
941
  }
868
942
 
869
943
  // Last resort: empty object schema
@@ -261,8 +261,7 @@ function applyDefaultSpeculationRulesHeader(
261
261
  * Extract the plain JS body from a `<script ...>body</script>` string.
262
262
  * Returns `null` if the input is falsy or has no recognisable `</script>` end.
263
263
  * Used to compute the sha256 hash of framework-injected inline scripts so the
264
- * hash can be listed in the `script-src` CSP directive without relying on
265
- * `'unsafe-inline'`.
264
+ * hash can be listed in app-owned `script-src` CSP directives.
266
265
  */
267
266
  function extractScriptBody(scriptTag: string | null): string | null {
268
267
  if (!scriptTag) return null;
@@ -547,13 +546,10 @@ function augmentExistingReportOnlyCspForFrameworkScripts(
547
546
  *
548
547
  * A third directive, `script-src`, is emitted via `Content-Security-Policy-
549
548
  * Report-Only` rather than enforced when the app has no existing document CSP.
550
- * The framework injects deterministic inline scripts (the Sentry config block,
551
- * whose hash is computed once at process startup from the resolved env vars,
552
- * and when `GA_MEASUREMENT_ID` is set the gtag config block, whose hash is
553
- * derived from the same string `wrapWithAnalytics` embeds). It also loads
554
- * Google Tag Manager / GA4 from `GA_CSP_SCRIPT_HOSTS`. All of those are listed
555
- * here so the report-only policy reflects the code the framework itself injects
556
- * instead of reporting a violation on every page load.
549
+ * The framework injects inline scripts for analytics, Sentry, and template
550
+ * setup, and hosted apps need Google Tag Manager to load without noisy CSP
551
+ * diagnostics. The report-only policy is intentionally permissive for scripts:
552
+ * it includes `'unsafe-inline'` plus the known GA/GTM loader hosts.
557
553
  *
558
554
  * If an app or host already sends an enforced CSP with `script-src`,
559
555
  * `script-src-elem`, `connect-src`, `img-src`, or `default-src`, we merge only
@@ -577,20 +573,22 @@ function applyDocumentCsp(headers: Headers, sentryScript: string | null): void {
577
573
  if (process.env.NODE_ENV !== "production") return;
578
574
  if (process.env.AGENT_NATIVE_DISABLE_DOC_CSP === "1") return;
579
575
 
580
- // script-src as Report-Only: list 'self', the framework-injected inline
581
- // script hashes (Sentry config + gtag config), and the Google Analytics /
582
- // Tag Manager loader hosts. These are exactly the scripts the framework
583
- // itself injects, so listing them keeps the report-only policy from flagging
584
- // GA on every page load (and keeps it safe to graduate to enforcement).
585
- // Template theme-init hashes are NOT included here — see function comment.
576
+ // script-src as Report-Only: keep this deliberately loose so the framework's
577
+ // injected analytics and template bootstrap scripts do not look blocked in
578
+ // browser diagnostics.
586
579
  const sentryBody = extractScriptBody(sentryScript);
587
580
  const sentryHash = sentryBody ? computeInlineScriptHash(sentryBody) : null;
588
581
  const gaInlineBody = getGaInlineConfigScriptBody();
589
582
  const gaHash = gaInlineBody ? computeInlineScriptHash(gaInlineBody) : null;
590
583
  const gaHosts = gaInlineBody ? [...GA_CSP_SCRIPT_HOSTS] : [];
591
- const gaScriptSrcTokens = [...(gaHash ? [gaHash] : []), ...gaHosts];
584
+ const gaScriptSrcTokens = [
585
+ "'unsafe-inline'",
586
+ ...(gaHash ? [gaHash] : []),
587
+ ...gaHosts,
588
+ ];
592
589
  const scriptSrcTokens = [
593
590
  "'self'",
591
+ "'unsafe-inline'",
594
592
  ...(sentryHash ? [sentryHash] : []),
595
593
  ...(gaHash ? [gaHash] : []),
596
594
  ...gaHosts,
@@ -637,6 +637,11 @@ const messages = {
637
637
  s3SecretAccessKeyLabel: "مفتاح الوصول السري",
638
638
  s3RegionLabel: "المنطقة",
639
639
  s3PublicBaseUrlLabel: "عنوان URL الأساسي العام",
640
+ s3UrlInvalid:
641
+ "يجب أن يكون عنوان URL صالحًا (مثال: https://s3.us-east-1.amazonaws.com)",
642
+ s3BucketInvalid:
643
+ "يجب أن يتكون اسم الحاوية من 3 إلى 63 حرفًا صغيرًا أو رقمًا أو شرطة",
644
+ s3RegionInvalid: 'يجب أن تكون منطقة صالحة (مثال: us-east-1) أو "auto"',
640
645
  apiSetup: "إعداد الذكاء الاصطناعي",
641
646
  apiSetupDescription:
642
647
  "صِل الذكاء الاصطناعي باستخدام أرصدة Builder.io المجانية أو مفاتيح LLM الخاصة بك.",
@@ -651,6 +656,8 @@ const messages = {
651
656
  providerKeysSet: "تم تعيين {{count}}",
652
657
  checkingProviderKeys: "جار فحص مفاتيح المزود…",
653
658
  keySet: "تم التعيين",
659
+ keyCleared: "تم مسح بيانات اعتماد التخزين",
660
+ clearAllS3: "مسح بيانات الاعتماد",
654
661
  replaceKey: "استبدال المفتاح…",
655
662
  pasteProviderKey: "الصق مفتاح مزود أولًا.",
656
663
  apiKeySaved: "تم حفظ مفتاح API",
@@ -662,6 +662,12 @@ Alle sichtbaren Änderungen für Clips-Nutzer werden hier dokumentiert. Du kanns
662
662
  s3SecretAccessKeyLabel: "Geheimer Zugriffsschlüssel",
663
663
  s3RegionLabel: "Übersetzt: Region",
664
664
  s3PublicBaseUrlLabel: "Öffentliche Basis-URL",
665
+ s3UrlInvalid:
666
+ "Muss eine gültige URL sein (z. B. https://s3.us-east-1.amazonaws.com)",
667
+ s3BucketInvalid:
668
+ "Bucket-Name muss 3–63 Kleinbuchstaben, Zahlen oder Bindestriche enthalten",
669
+ s3RegionInvalid:
670
+ 'Muss eine gültige Region sein (z. B. us-east-1) oder "auto"',
665
671
  apiSetup: "KI-Einrichtung",
666
672
  apiSetupDescription:
667
673
  "Verbinde KI mit kostenlosen Builder.io-Credits oder deinen eigenen LLM-Schlüsseln.",
@@ -676,6 +682,8 @@ Alle sichtbaren Änderungen für Clips-Nutzer werden hier dokumentiert. Du kanns
676
682
  providerKeysSet: "{{count}} gesetzt",
677
683
  checkingProviderKeys: "Anbieter-Schlüssel werden geprüft…",
678
684
  keySet: "Gesetzt",
685
+ keyCleared: "Speicher-Anmeldedaten gelöscht",
686
+ clearAllS3: "Anmeldedaten löschen",
679
687
  replaceKey: "Schlüssel ersetzen…",
680
688
  pasteProviderKey: "Füge zuerst einen Anbieter-Schlüssel ein.",
681
689
  apiKeySaved: "API-Schlüssel gespeichert",
@@ -637,6 +637,11 @@ All notable user-facing changes to Clips are documented here. Open it any time f
637
637
  s3SecretAccessKeyLabel: "Secret access key",
638
638
  s3RegionLabel: "Region",
639
639
  s3PublicBaseUrlLabel: "Public base URL",
640
+ s3UrlInvalid:
641
+ "Must be a valid URL (e.g. https://s3.us-east-1.amazonaws.com)",
642
+ s3BucketInvalid:
643
+ "Bucket name must be 3–63 lowercase letters, numbers, or hyphens",
644
+ s3RegionInvalid: 'Must be a valid region (e.g. us-east-1) or "auto"',
640
645
  apiSetup: "AI setup",
641
646
  apiSetupDescription:
642
647
  "Connect AI with Builder.io free credits or your own LLM keys.",
@@ -651,6 +656,8 @@ All notable user-facing changes to Clips are documented here. Open it any time f
651
656
  providerKeysSet: "{{count}} set",
652
657
  checkingProviderKeys: "Checking provider keys…",
653
658
  keySet: "Set",
659
+ keyCleared: "Storage credentials cleared",
660
+ clearAllS3: "Clear credentials",
654
661
  replaceKey: "Replace key…",
655
662
  pasteProviderKey: "Paste a provider key first.",
656
663
  apiKeySaved: "API key saved",
@@ -654,6 +654,11 @@ Todos los cambios visibles para los usuarios de Clips se documentan aquí. Puede
654
654
  s3SecretAccessKeyLabel: "Clave de acceso secreta",
655
655
  s3RegionLabel: "Región",
656
656
  s3PublicBaseUrlLabel: "URL base pública",
657
+ s3UrlInvalid:
658
+ "Debe ser una URL válida (p. ej. https://s3.us-east-1.amazonaws.com)",
659
+ s3BucketInvalid:
660
+ "El nombre del bucket debe tener 3–63 letras minúsculas, números o guiones",
661
+ s3RegionInvalid: 'Debe ser una región válida (p. ej. us-east-1) o "auto"',
657
662
  apiSetup: "Configuración de IA",
658
663
  apiSetupDescription:
659
664
  "Conecta IA con créditos gratis de Builder.io o tus propias claves LLM.",
@@ -668,6 +673,8 @@ Todos los cambios visibles para los usuarios de Clips se documentan aquí. Puede
668
673
  providerKeysSet: "{{count}} configuradas",
669
674
  checkingProviderKeys: "Comprobando claves de proveedor…",
670
675
  keySet: "Configurada",
676
+ keyCleared: "Credenciales de almacenamiento borradas",
677
+ clearAllS3: "Borrar credenciales",
671
678
  replaceKey: "Reemplazar clave…",
672
679
  pasteProviderKey: "Pega primero una clave de proveedor.",
673
680
  apiKeySaved: "Clave de API guardada",
@@ -655,6 +655,11 @@ Tous les changements visibles par les utilisateurs de Clips sont documentés ici
655
655
  s3SecretAccessKeyLabel: "Clé d’accès secrète",
656
656
  s3RegionLabel: "Région",
657
657
  s3PublicBaseUrlLabel: "URL de base publique",
658
+ s3UrlInvalid:
659
+ "Doit être une URL valide (ex. https://s3.us-east-1.amazonaws.com)",
660
+ s3BucketInvalid:
661
+ "Le nom du bucket doit contenir 3–63 lettres minuscules, chiffres ou tirets",
662
+ s3RegionInvalid: 'Doit être une région valide (ex. us-east-1) ou "auto"',
658
663
  apiSetup: "Configuration IA",
659
664
  apiSetupDescription:
660
665
  "Connectez l’IA avec les crédits gratuits Builder.io ou vos propres clés LLM.",
@@ -669,6 +674,8 @@ Tous les changements visibles par les utilisateurs de Clips sont documentés ici
669
674
  providerKeysSet: "{{count}} définies",
670
675
  checkingProviderKeys: "Vérification des clés fournisseur…",
671
676
  keySet: "Définie",
677
+ keyCleared: "Identifiants de stockage effacés",
678
+ clearAllS3: "Effacer les identifiants",
672
679
  replaceKey: "Remplacer la clé…",
673
680
  pasteProviderKey: "Collez d’abord une clé fournisseur.",
674
681
  apiKeySaved: "Clé API enregistrée",
@@ -635,6 +635,10 @@ Clips में उपयोगकर्ताओं को दिखने व
635
635
  s3SecretAccessKeyLabel: "गुप्त एक्सेस कुंजी",
636
636
  s3RegionLabel: "क्षेत्र",
637
637
  s3PublicBaseUrlLabel: "सार्वजनिक बेस URL",
638
+ s3UrlInvalid:
639
+ "एक मान्य URL होना चाहिए (उदा. https://s3.us-east-1.amazonaws.com)",
640
+ s3BucketInvalid: "बकेट नाम 3–63 लोअरकेस अक्षर, अंक या हाइफ़न होने चाहिए",
641
+ s3RegionInvalid: 'एक मान्य क्षेत्र (उदा. us-east-1) या "auto" होना चाहिए',
638
642
  apiSetup: "AI सेटअप",
639
643
  apiSetupDescription:
640
644
  "Builder.io मुफ्त क्रेडिट या अपनी LLM keys के साथ AI कनेक्ट करें.",
@@ -649,6 +653,8 @@ Clips में उपयोगकर्ताओं को दिखने व
649
653
  providerKeysSet: "{{count}} सेट",
650
654
  checkingProviderKeys: "प्रोवाइडर कीज़ जाँची जा रही हैं…",
651
655
  keySet: "सेट",
656
+ keyCleared: "स्टोरेज क्रेडेंशियल साफ़ किए गए",
657
+ clearAllS3: "क्रेडेंशियल साफ़ करें",
652
658
  replaceKey: "की बदलें…",
653
659
  pasteProviderKey: "पहले प्रोवाइडर की पेस्ट करें।",
654
660
  apiKeySaved: "API की सहेजी गई",
@@ -649,6 +649,12 @@ Clips のユーザー向けの主な変更はここに記録されます。コ
649
649
  s3SecretAccessKeyLabel: "シークレットアクセスキー",
650
650
  s3RegionLabel: "リージョン",
651
651
  s3PublicBaseUrlLabel: "公開ベース URL",
652
+ s3UrlInvalid:
653
+ "有効な URL を入力してください(例: https://s3.us-east-1.amazonaws.com)",
654
+ s3BucketInvalid:
655
+ "バケット名は 3〜63 文字の小文字、数字、またはハイフンで指定してください",
656
+ s3RegionInvalid:
657
+ '有効なリージョン(例: us-east-1)または "auto" を入力してください',
652
658
  apiSetup: "AI 設定",
653
659
  apiSetupDescription:
654
660
  "Builder.io の無料クレジット、または自分の LLM キーで AI を接続します。",
@@ -663,6 +669,8 @@ Clips のユーザー向けの主な変更はここに記録されます。コ
663
669
  providerKeysSet: "{{count}} 件設定済み",
664
670
  checkingProviderKeys: "プロバイダーキーを確認中…",
665
671
  keySet: "設定済み",
672
+ keyCleared: "ストレージ認証情報をクリアしました",
673
+ clearAllS3: "認証情報をクリア",
666
674
  replaceKey: "キーを置換…",
667
675
  pasteProviderKey: "先にプロバイダーキーを貼り付けてください。",
668
676
  apiKeySaved: "API キーを保存しました",
@@ -641,6 +641,11 @@ Clips의 모든 사용자 대상 변경 사항은 여기에 기록됩니다. 명
641
641
  s3SecretAccessKeyLabel: "비밀 액세스 키",
642
642
  s3RegionLabel: "리전",
643
643
  s3PublicBaseUrlLabel: "공개 기본 URL",
644
+ s3UrlInvalid:
645
+ "유효한 URL이어야 합니다 (예: https://s3.us-east-1.amazonaws.com)",
646
+ s3BucketInvalid:
647
+ "버킷 이름은 3–63자의 소문자, 숫자 또는 하이픈이어야 합니다",
648
+ s3RegionInvalid: '유효한 리전(예: us-east-1) 또는 "auto"이어야 합니다',
644
649
  apiSetup: "AI 설정",
645
650
  apiSetupDescription:
646
651
  "Builder.io 무료 크레딧 또는 직접 보유한 LLM 키로 AI를 연결하세요.",
@@ -655,6 +660,8 @@ Clips의 모든 사용자 대상 변경 사항은 여기에 기록됩니다. 명
655
660
  providerKeysSet: "{{count}}개 설정됨",
656
661
  checkingProviderKeys: "제공자 키 확인 중…",
657
662
  keySet: "설정됨",
663
+ keyCleared: "스토리지 자격 증명이 삭제되었습니다",
664
+ clearAllS3: "자격 증명 삭제",
658
665
  replaceKey: "키 바꾸기…",
659
666
  pasteProviderKey: "먼저 제공자 키를 붙여넣으세요.",
660
667
  apiKeySaved: "API 키가 저장됨",
@@ -652,6 +652,11 @@ Todas as mudanças visíveis para usuários do Clips são documentadas aqui. Voc
652
652
  s3SecretAccessKeyLabel: "Chave de acesso secreta",
653
653
  s3RegionLabel: "Região",
654
654
  s3PublicBaseUrlLabel: "URL base pública",
655
+ s3UrlInvalid:
656
+ "Deve ser uma URL válida (ex.: https://s3.us-east-1.amazonaws.com)",
657
+ s3BucketInvalid:
658
+ "O nome do bucket deve ter 3–63 letras minúsculas, números ou hifens",
659
+ s3RegionInvalid: 'Deve ser uma região válida (ex.: us-east-1) ou "auto"',
655
660
  apiSetup: "Configuração de IA",
656
661
  apiSetupDescription:
657
662
  "Conecte IA com créditos grátis da Builder.io ou suas próprias chaves LLM.",
@@ -666,6 +671,8 @@ Todas as mudanças visíveis para usuários do Clips são documentadas aqui. Voc
666
671
  providerKeysSet: "{{count}} configuradas",
667
672
  checkingProviderKeys: "Verificando chaves de provedor…",
668
673
  keySet: "Configurada",
674
+ keyCleared: "Credenciais de armazenamento limpas",
675
+ clearAllS3: "Limpar credenciais",
669
676
  replaceKey: "Substituir chave…",
670
677
  pasteProviderKey: "Cole primeiro uma chave de provedor.",
671
678
  apiKeySaved: "Chave de API salva",
@@ -614,6 +614,9 @@ Clips 中所有面向用户的重要更改都会记录在这里。你可以随
614
614
  s3SecretAccessKeyLabel: "秘密访问密钥",
615
615
  s3RegionLabel: "区域",
616
616
  s3PublicBaseUrlLabel: "公共基础 URL",
617
+ s3UrlInvalid: "必须是有效的 URL(例如 https://s3.us-east-1.amazonaws.com)",
618
+ s3BucketInvalid: "存储桶名称必须为 3–63 个小写字母、数字或连字符",
619
+ s3RegionInvalid: '必须是有效的区域(例如 us-east-1)或 "auto"',
617
620
  apiSetup: "AI 设置",
618
621
  apiSetupDescription: "使用 Builder.io 免费额度或你自己的 LLM 密钥连接 AI。",
619
622
  builderEasySetup: "Builder.io 免费额度",
@@ -626,6 +629,8 @@ Clips 中所有面向用户的重要更改都会记录在这里。你可以随
626
629
  providerKeysSet: "已设置 {{count}} 个",
627
630
  checkingProviderKeys: "正在检查提供方密钥…",
628
631
  keySet: "已设置",
632
+ keyCleared: "存储凭证已清除",
633
+ clearAllS3: "清除凭证",
629
634
  replaceKey: "替换密钥…",
630
635
  pasteProviderKey: "请先粘贴提供方密钥。",
631
636
  apiKeySaved: "API 密钥已保存",
@@ -607,6 +607,9 @@ const messages = {
607
607
  s3SecretAccessKeyLabel: "秘密存取金鑰",
608
608
  s3RegionLabel: "區域",
609
609
  s3PublicBaseUrlLabel: "公開基礎 URL",
610
+ s3UrlInvalid: "必須是有效的 URL(例如 https://s3.us-east-1.amazonaws.com)",
611
+ s3BucketInvalid: "儲存貯體名稱必須為 3–63 個小寫字母、數字或連字號",
612
+ s3RegionInvalid: '必須是有效的區域(例如 us-east-1)或 "auto"',
610
613
  apiSetup: "AI 設定",
611
614
  apiSetupDescription: "使用 Builder.io 免費額度或您自己的 LLM 金鑰連線 AI。",
612
615
  builderEasySetup: "Builder.io 免費額度",
@@ -619,6 +622,8 @@ const messages = {
619
622
  providerKeysSet: "已設定 {{count}} 個",
620
623
  checkingProviderKeys: "正在檢查提供方金鑰…",
621
624
  keySet: "已設定",
625
+ keyCleared: "儲存憑證已清除",
626
+ clearAllS3: "清除憑證",
622
627
  replaceKey: "替換金鑰…",
623
628
  pasteProviderKey: "請先貼上提供方金鑰。",
624
629
  apiKeySaved: "API 金鑰已儲存",