coze-coding-dev-sdk 0.5.15__tar.gz → 0.5.16__tar.gz

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 (92) hide show
  1. {coze_coding_dev_sdk-0.5.15/coze_coding_dev_sdk.egg-info → coze_coding_dev_sdk-0.5.16}/PKG-INFO +1 -1
  2. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/supabase.py +79 -26
  3. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/core/__init__.py +1 -0
  4. coze_coding_dev_sdk-0.5.16/coze_coding_dev_sdk/core/url_utils.py +256 -0
  5. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/fetch/client.py +5 -0
  6. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/image/client.py +5 -0
  7. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/llm/client.py +13 -0
  8. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/supabase/client.py +80 -0
  9. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/supabase/models.py +31 -1
  10. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/video/client.py +5 -0
  11. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/video_edit/video_edit.py +16 -0
  12. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16/coze_coding_dev_sdk.egg-info}/PKG-INFO +1 -1
  13. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk.egg-info/SOURCES.txt +1 -0
  14. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/pyproject.toml +1 -1
  15. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/CHANGELOG.md +0 -0
  16. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/LICENSE +0 -0
  17. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/MANIFEST.in +0 -0
  18. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/README.md +0 -0
  19. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/__init__.py +0 -0
  20. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/__init__.py +0 -0
  21. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/chat.py +0 -0
  22. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/cli.py +0 -0
  23. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/constants.py +0 -0
  24. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/db.py +0 -0
  25. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/document.py +0 -0
  26. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/embedding.py +0 -0
  27. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/image.py +0 -0
  28. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/knowledge.py +0 -0
  29. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/search.py +0 -0
  30. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/storage.py +0 -0
  31. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/utils.py +0 -0
  32. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/video.py +0 -0
  33. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/video_edit.py +0 -0
  34. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/cli/voice.py +0 -0
  35. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/core/client.py +0 -0
  36. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/core/config.py +0 -0
  37. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/core/exceptions.py +0 -0
  38. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/database/__init__.py +0 -0
  39. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/database/client.py +0 -0
  40. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/database/migration.py +0 -0
  41. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/document/__init__.py +0 -0
  42. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/document/client.py +0 -0
  43. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/document/docx_generator.py +0 -0
  44. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/document/models.py +0 -0
  45. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/document/pdf_generator.py +0 -0
  46. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/document/pptx_generator.py +0 -0
  47. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/document/xlsx_generator.py +0 -0
  48. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/embedding/__init__.py +0 -0
  49. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/embedding/client.py +0 -0
  50. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/embedding/models.py +0 -0
  51. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/fetch/__init__.py +0 -0
  52. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/fetch/models.py +0 -0
  53. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/image/__init__.py +0 -0
  54. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/image/models.py +0 -0
  55. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/knowledge/__init__.py +0 -0
  56. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/knowledge/client.py +0 -0
  57. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/knowledge/models.py +0 -0
  58. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/llm/__init__.py +0 -0
  59. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/llm/models.py +0 -0
  60. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/memory/__init__.py +0 -0
  61. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/memory/client.py +0 -0
  62. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/report/__init__.py +0 -0
  63. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/report/buffer.py +0 -0
  64. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/report/client.py +0 -0
  65. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/report/interceptors/__init__.py +0 -0
  66. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/report/interceptors/boto3_hook.py +0 -0
  67. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/report/interceptors/httpx_transport.py +0 -0
  68. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/report/models.py +0 -0
  69. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/report/singleton.py +0 -0
  70. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/report/utils.py +0 -0
  71. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/s3/__init__.py +0 -0
  72. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/s3/client.py +0 -0
  73. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/s3/models.py +0 -0
  74. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/search/__init__.py +0 -0
  75. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/search/client.py +0 -0
  76. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/search/models.py +0 -0
  77. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/supabase/__init__.py +0 -0
  78. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/video/__init__.py +0 -0
  79. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/video/models.py +0 -0
  80. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/video_edit/__init__.py +0 -0
  81. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/video_edit/examples.py +0 -0
  82. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/video_edit/frame_extractor.py +0 -0
  83. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/video_edit/models.py +0 -0
  84. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/voice/__init__.py +0 -0
  85. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/voice/asr.py +0 -0
  86. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/voice/models.py +0 -0
  87. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk/voice/tts.py +0 -0
  88. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk.egg-info/dependency_links.txt +0 -0
  89. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk.egg-info/entry_points.txt +0 -0
  90. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk.egg-info/requires.txt +0 -0
  91. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/coze_coding_dev_sdk.egg-info/top_level.txt +0 -0
  92. {coze_coding_dev_sdk-0.5.15 → coze_coding_dev_sdk-0.5.16}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coze-coding-dev-sdk
3
- Version: 0.5.15
3
+ Version: 0.5.16
4
4
  Summary: Coze Coding Dev SDK - 优雅的多功能 AI SDK,支持图片生成、视频生成、语音合成、语音识别、大语言模型、联网搜索和文本/多模态 Embedding。包含命令行工具 coze-coding-ai,支持 Context 上下文追踪
5
5
  Author-email: Coze Coding Integration Team <support@coze.com>
6
6
  Maintainer-email: Coze Coding Integration Team <support@coze.com>
@@ -509,7 +509,7 @@ def auth():
509
509
  pass
510
510
 
511
511
 
512
- @auth.command("get-config")
512
+ @auth.command("get-config-v2")
513
513
  @click.option("--mock", is_flag=True, help="使用 mock 模式(测试运行,不会真正执行操作)")
514
514
  @click.option(
515
515
  "--header",
@@ -533,20 +533,55 @@ def auth_get_config(mock: bool, header: tuple, verbose: bool):
533
533
  console.print("[yellow]🧪 Mock 模式已启用(测试运行)[/yellow]")
534
534
 
535
535
  client = SupabaseClient(config, ctx=ctx, custom_headers=custom_headers, verbose=verbose)
536
- response = client.get_auth_config()
536
+ response = client.get_auth_config_v2()
537
537
 
538
538
  if response.code != 0:
539
539
  console.print(f"[red]Error: {response.msg}[/red]")
540
540
  return
541
541
 
542
- console.print(json.dumps(response.config.__dict__ if response.config else None, indent=2, ensure_ascii=False))
542
+ AUTH_STATUS_NOT_INITIALIZED = 1
543
+ AUTH_STATUS_NOT_SUPPORT_SUPABASE = 2
544
+ AUTH_STATUS_ENABLED = 3
545
+ AUTH_STATUS_DISABLED = 4
546
+ AUTH_STATUS_NOT_SUPPORT_PROJECT_TYPE = 5
547
+
548
+ if response.status == AUTH_STATUS_NOT_INITIALIZED:
549
+ console.print("[red]Error: Auth 尚未初始化,请先初始化 Supabase[/red]")
550
+ return
551
+ elif response.status == AUTH_STATUS_NOT_SUPPORT_SUPABASE:
552
+ console.print("[red]Error: 当前项目非 Supabase 数据库类型,不支持 Auth 集成配置[/red]")
553
+ return
554
+ elif response.status == AUTH_STATUS_DISABLED:
555
+ console.print("[red]Error: Auth 功能已被禁用[/red]")
556
+ return
557
+ elif response.status == AUTH_STATUS_NOT_SUPPORT_PROJECT_TYPE:
558
+ console.print("[red]Error: 当前项目类型,不支持 Auth 集成配置[/red]")
559
+ return
560
+ elif response.status != AUTH_STATUS_ENABLED:
561
+ console.print(f"[red]Error: Auth 状态异常 (status={response.status})[/red]")
562
+ return
563
+
564
+ result = None
565
+ if response.config:
566
+ result = {
567
+ "status": response.status,
568
+ "config": {
569
+ "project_id": response.config.project_id,
570
+ "icon_url": response.config.icon_url,
571
+ "name": response.config.name,
572
+ "email_config": response.config.email_config.__dict__ if response.config.email_config else None,
573
+ "phone_config": response.config.phone_config.__dict__ if response.config.phone_config else None,
574
+ },
575
+ }
576
+ console.print(json.dumps(result, indent=2, ensure_ascii=False))
543
577
 
544
578
  except Exception as e:
545
579
  console.print(f"[red]✗ Error: {str(e)}[/red]")
546
580
  raise click.Abort()
547
581
 
548
582
 
549
- @auth.command("update-config")
583
+ @auth.command("update-config-v2")
584
+ @click.option("--name", help="项目名称")
550
585
  @click.option("--site-url", help="站点 URL,用于邮件中的链接跳转地址(如 'https://myapp.com')")
551
586
  @click.option("--disable-signup/--enable-signup", default=None, help="禁用/启用用户自助注册功能")
552
587
  @click.option("--external-email-enabled/--external-email-disabled", default=None, help="启用/禁用邮箱认证方式")
@@ -563,6 +598,7 @@ def auth_get_config(mock: bool, header: tuple, verbose: bool):
563
598
  @click.option("--smtp-admin-email", help="发件人邮箱地址,例如 'noreply@myapp.com'")
564
599
  @click.option("--smtp-sender-name", help="发件人显示名称,例如 'My App'")
565
600
  @click.option("--smtp-max-frequency", type=int, help="同一邮箱的最小发送间隔(秒),用于防止滥用")
601
+ @click.option("--external-phone-enabled/--external-phone-disabled", default=None, help="启用/禁用手机号认证方式")
566
602
  @click.option("--mock", is_flag=True, help="使用 mock 模式(测试运行,不会真正执行操作)")
567
603
  @click.option(
568
604
  "--header",
@@ -572,6 +608,7 @@ def auth_get_config(mock: bool, header: tuple, verbose: bool):
572
608
  )
573
609
  @click.option("--verbose", "-v", is_flag=True, help="显示详细的 HTTP 请求和响应日志")
574
610
  def auth_update_config(
611
+ name: Optional[str],
575
612
  site_url: Optional[str],
576
613
  disable_signup: Optional[bool],
577
614
  external_email_enabled: Optional[bool],
@@ -588,27 +625,31 @@ def auth_update_config(
588
625
  smtp_admin_email: Optional[str],
589
626
  smtp_sender_name: Optional[str],
590
627
  smtp_max_frequency: Optional[int],
628
+ external_phone_enabled: Optional[bool],
591
629
  mock: bool,
592
630
  header: tuple,
593
631
  verbose: bool,
594
632
  ):
595
- """更新 Auth 认证配置。
633
+ """更新 Auth 认证配置(V2)。
596
634
 
597
635
  至少需要提供一个配置项。更新 SMTP 配置后建议测试邮件发送功能。
598
636
 
599
637
  \b
600
638
  示例:
601
- # 更新站点 URL 和启用注册
602
- coze-coding-ai supabase auth update-config --site-url "https://myapp.com" --enable-signup
639
+ # 更新项目名称和站点 URL
640
+ npx coze-coding-ai supabase auth update-config-v2 --name "My Project" --site-url "https://myapp.com" --enable-signup
603
641
 
604
642
  # 配置 SMTP 邮件服务
605
- coze-coding-ai supabase auth update-config \\
643
+ npx coze-coding-ai supabase auth update-config-v2 \\
606
644
  --smtp-host "smtp.sendgrid.net" \\
607
645
  --smtp-port 587 \\
608
646
  --smtp-user "apikey" \\
609
647
  --smtp-pass "SG.xxx" \\
610
648
  --smtp-admin-email "noreply@myapp.com" \\
611
649
  --smtp-sender-name "My App"
650
+
651
+ # 启用手机号认证
652
+ npx coze-coding-ai supabase auth update-config-v2 --external-phone-enabled
612
653
  """
613
654
  try:
614
655
  from .utils import parse_headers
@@ -623,51 +664,63 @@ def auth_update_config(
623
664
  console.print("[yellow]🧪 Mock 模式已启用(测试运行)[/yellow]")
624
665
 
625
666
  auth_config = {}
667
+ if name is not None:
668
+ auth_config["app_name"] = name
669
+
670
+ email_config = {}
626
671
  if site_url is not None:
627
- auth_config["site_url"] = site_url
672
+ email_config["site_url"] = site_url
628
673
  if disable_signup is not None:
629
- auth_config["disable_signup"] = disable_signup
674
+ email_config["disable_signup"] = disable_signup
630
675
  if external_email_enabled is not None:
631
- auth_config["external_email_enabled"] = external_email_enabled
676
+ email_config["external_email_enabled"] = external_email_enabled
632
677
  if mailer_autoconfirm is not None:
633
- auth_config["mailer_autoconfirm"] = mailer_autoconfirm
678
+ email_config["mailer_auto_confirm"] = mailer_autoconfirm
634
679
  if double_confirm_changes is not None:
635
- auth_config["double_confirm_changes"] = double_confirm_changes
680
+ email_config["double_confirm_changes"] = double_confirm_changes
636
681
  if mailer_secure_email_change_enabled is not None:
637
- auth_config["mailer_secure_email_change_enabled"] = mailer_secure_email_change_enabled
682
+ email_config["mailer_secure_email_change_enabled"] = mailer_secure_email_change_enabled
638
683
  if mailer_otp_exp is not None:
639
- auth_config["mailer_otp_exp"] = mailer_otp_exp
684
+ email_config["mailer_otp_exp"] = mailer_otp_exp
640
685
  if password_min_length is not None:
641
- auth_config["password_min_length"] = password_min_length
686
+ email_config["password_min_length"] = password_min_length
642
687
  if password_required_characters is not None:
643
- auth_config["password_required_characters"] = password_required_characters
688
+ email_config["password_required_characters"] = password_required_characters
644
689
  if smtp_host is not None:
645
- auth_config["smtp_host"] = smtp_host
690
+ email_config["smtp_host"] = smtp_host
646
691
  if smtp_port is not None:
647
- auth_config["smtp_port"] = smtp_port
692
+ email_config["smtp_port"] = smtp_port
648
693
  if smtp_user is not None:
649
- auth_config["smtp_user"] = smtp_user
694
+ email_config["smtp_user"] = smtp_user
650
695
  if smtp_pass is not None:
651
- auth_config["smtp_pass"] = smtp_pass
696
+ email_config["smtp_pass"] = smtp_pass
652
697
  if smtp_admin_email is not None:
653
- auth_config["smtp_admin_email"] = smtp_admin_email
698
+ email_config["smtp_admin_email"] = smtp_admin_email
654
699
  if smtp_sender_name is not None:
655
- auth_config["smtp_sender_name"] = smtp_sender_name
700
+ email_config["smtp_sender_name"] = smtp_sender_name
656
701
  if smtp_max_frequency is not None:
657
- auth_config["smtp_max_frequency"] = smtp_max_frequency
702
+ email_config["smtp_max_frequency"] = smtp_max_frequency
703
+ if email_config:
704
+ auth_config["email_config"] = email_config
705
+
706
+ phone_config = {}
707
+ if external_phone_enabled is not None:
708
+ phone_config["external_phone_enabled"] = external_phone_enabled
709
+ if phone_config:
710
+ auth_config["phone_config"] = phone_config
658
711
 
659
712
  if not auth_config:
660
713
  console.print("[red]Error: 至少需要提供一个配置项[/red]")
661
714
  return
662
715
 
663
716
  client = SupabaseClient(config, ctx=ctx, custom_headers=custom_headers, verbose=verbose)
664
- response = client.update_auth_config(auth_config)
717
+ response = client.update_auth_config_v2(auth_config)
665
718
 
666
719
  if response.code != 0:
667
720
  console.print(f"[red]Error: {response.msg}[/red]")
668
721
  return
669
722
 
670
- console.print(json.dumps({"success": response.success}, indent=2, ensure_ascii=False))
723
+ console.print(json.dumps({"success": response.success, "should_update_ui": response.should_update_ui}, indent=2, ensure_ascii=False))
671
724
 
672
725
  except Exception as e:
673
726
  console.print(f"[red]✗ Error: {str(e)}[/red]")
@@ -7,6 +7,7 @@ from .exceptions import (
7
7
  NetworkError,
8
8
  ValidationError
9
9
  )
10
+ from .url_utils import validate_url, URLValidationError
10
11
 
11
12
  try:
12
13
  from .. import __version__
@@ -0,0 +1,256 @@
1
+ """
2
+ URL 校验工具模块
3
+ 提供 URL 格式校验、协议校验、本地地址拦截、临时URL检测和可达性预检功能
4
+ """
5
+
6
+ from urllib.parse import urlparse
7
+ from typing import Optional
8
+
9
+ from .exceptions import ValidationError
10
+
11
+
12
+ # 禁止访问的本地主机名(字符串级别匹配,不做 DNS 解析)
13
+ _LOCAL_HOSTS = frozenset({"localhost", "127.0.0.1", "0.0.0.0", "::1"})
14
+
15
+ # 允许的协议
16
+ _ALLOWED_SCHEMES = frozenset({"http", "https"})
17
+
18
+ # 沙箱代理 URL 的特征路径
19
+ _SANDBOX_PROXY_PATH = "/api/sandbox/coze_coding/file/proxy"
20
+
21
+ # 临时 URL 的域名+路径特征
22
+ _EPHEMERAL_URL_PATTERNS = [
23
+ ("code.coze.cn", _SANDBOX_PROXY_PATH),
24
+ ]
25
+
26
+
27
+ class URLValidationError(ValidationError):
28
+ """URL 校验失败异常"""
29
+
30
+ def __init__(self, message: str, url: Optional[str] = None):
31
+ super().__init__(message=message, field="url", value=url)
32
+ self.url = url
33
+
34
+
35
+ def _is_local_path(value: str) -> bool:
36
+ """判断字符串是否看起来像本地文件路径"""
37
+ if not value:
38
+ return False
39
+ # Unix 绝对路径: /Users/xxx, /tmp/file.png
40
+ if value.startswith("/"):
41
+ return True
42
+ # 相对路径: ./file.png, ../assets/img.jpg
43
+ if value.startswith("./") or value.startswith("../"):
44
+ return True
45
+ # Home 目录: ~/Downloads/file.png
46
+ if value.startswith("~/"):
47
+ return True
48
+ # Windows 绝对路径: C:\Users\xxx, D:/files/img.png
49
+ if len(value) >= 3 and value[0].isalpha() and value[1] == ":" and value[2] in ("/", "\\"):
50
+ return True
51
+ return False
52
+
53
+
54
+ def validate_url(
55
+ url: str,
56
+ *,
57
+ allow_head_check: bool = True,
58
+ timeout: int = 5,
59
+ ) -> str:
60
+ """
61
+ 校验 URL 合法性,不触发实际内容下载。
62
+
63
+ 检查项:
64
+ 1. 非空、字符串类型校验
65
+ 2. URL 格式校验(scheme + netloc)
66
+ 3. 协议校验:仅允许 http/https
67
+ 4. 本地地址拦截:禁止 localhost/127.0.0.1/0.0.0.0/::1
68
+ 5. 可选 HEAD 预检:确认 URL 可达(不下载内容)
69
+
70
+ 注意:不做 DNS 解析到 IP 再判断私有网段的检查,避免误杀(如内部 CDN 域名解析到内网 IP 的合法场景)。
71
+
72
+ Args:
73
+ url: 待校验的 URL 字符串
74
+ allow_head_check: 是否发送 HEAD 请求预检可达性
75
+ timeout: HEAD 预检超时秒数,默认 5
76
+
77
+ Returns:
78
+ str: 经过 strip 的合法 URL
79
+
80
+ Raises:
81
+ URLValidationError: URL 校验失败
82
+ """
83
+ # 1. 基本校验
84
+ if not url or not isinstance(url, str):
85
+ raise URLValidationError("URL cannot be empty", url=url if isinstance(url, str) else None)
86
+
87
+ url = url.strip()
88
+
89
+ if not url:
90
+ raise URLValidationError("URL cannot be empty", url=url)
91
+
92
+ # 2. 格式校验
93
+ try:
94
+ parsed = urlparse(url)
95
+ except Exception:
96
+ if _is_local_path(url):
97
+ raise URLValidationError(
98
+ f"The input appears to be a local file path: {url}. "
99
+ f"Please upload it using the Storage skill first to get a persistent HTTP URL.",
100
+ url=url,
101
+ )
102
+ raise URLValidationError(f"Invalid URL format: {url}", url=url)
103
+
104
+ if not parsed.scheme or not parsed.netloc:
105
+ if _is_local_path(url):
106
+ raise URLValidationError(
107
+ f"The input appears to be a local file path: {url}. "
108
+ f"Please upload it using the Storage skill first to get a persistent HTTP URL.",
109
+ url=url,
110
+ )
111
+ raise URLValidationError(
112
+ f"Invalid URL format (missing scheme or host): {url}", url=url
113
+ )
114
+
115
+ # 3. 协议校验
116
+ if parsed.scheme.lower() not in _ALLOWED_SCHEMES:
117
+ raise URLValidationError(
118
+ f"Unsupported scheme '{parsed.scheme}', only http/https allowed",
119
+ url=url,
120
+ )
121
+
122
+ # 4. 本地地址拦截(字符串匹配,不做 DNS 解析)
123
+ hostname = parsed.hostname
124
+ if not hostname:
125
+ raise URLValidationError(f"Cannot extract hostname from URL: {url}", url=url)
126
+
127
+ if hostname.lower() in _LOCAL_HOSTS:
128
+ raise URLValidationError(
129
+ f"Access to local address is not allowed: {hostname}", url=url
130
+ )
131
+
132
+ # 5. 临时 URL 检测(沙箱代理等)
133
+ if is_ephemeral_url(url):
134
+ raise URLValidationError(
135
+ f"This URL appears to be a temporary sandbox proxy URL that may expire. "
136
+ f"Please download the file and upload it to persistent storage (Storage skill) first.",
137
+ url=url,
138
+ )
139
+
140
+ # 6. 可选 HEAD 预检
141
+ if allow_head_check:
142
+ _head_check(url, timeout=timeout)
143
+
144
+ return url
145
+
146
+
147
+ def is_ephemeral_url(url: str) -> bool:
148
+ """
149
+ 检测 URL 是否为临时/可能失效的地址。
150
+
151
+ 当前检测规则:
152
+ 1. 沙箱文件代理 URL(code.coze.cn/api/sandbox/coze_coding/file/proxy)
153
+ - 带有 expire_time、sign、nonce 参数
154
+ - 这类 URL 有签名过期机制,不适合长期使用
155
+
156
+ Args:
157
+ url: 待检测的 URL
158
+
159
+ Returns:
160
+ bool: True 表示是临时 URL,应先上传到持久存储
161
+ """
162
+ try:
163
+ parsed = urlparse(url)
164
+ except Exception:
165
+ return False
166
+
167
+ hostname = (parsed.hostname or "").lower()
168
+ path = parsed.path or ""
169
+
170
+ for pattern_host, pattern_path in _EPHEMERAL_URL_PATTERNS:
171
+ if hostname == pattern_host and path.startswith(pattern_path):
172
+ return True
173
+
174
+ return False
175
+
176
+
177
+ def _head_check(url: str, *, timeout: int = 5) -> None:
178
+ """
179
+ 发送 HEAD 请求预检 URL 可达性,不下载内容。
180
+ 如果服务器不支持 HEAD(返回 405),降级尝试 GET + Range: bytes=0-0。
181
+ """
182
+ import urllib.request
183
+
184
+ # 尝试 HEAD
185
+ req = urllib.request.Request(url, method="HEAD")
186
+ req.add_header("User-Agent", "CozeSDK-URLValidator/1.0")
187
+ try:
188
+ with urllib.request.urlopen(req, timeout=timeout) as resp:
189
+ if resp.status >= 400:
190
+ raise URLValidationError(
191
+ f"URL is not reachable: HTTP {resp.status}", url=url
192
+ )
193
+ except urllib.error.HTTPError as e:
194
+ if e.code == 405:
195
+ # 服务器不支持 HEAD,降级用 GET + Range
196
+ _range_check(url, timeout=timeout)
197
+ elif e.code >= 400:
198
+ raise URLValidationError(
199
+ f"URL is not reachable: HTTP {e.code}", url=url
200
+ )
201
+ else:
202
+ raise
203
+ except urllib.error.URLError as e:
204
+ raise URLValidationError(
205
+ f"URL is not reachable (network error: {e.reason}). Please check if the URL is correct and accessible.",
206
+ url=url,
207
+ )
208
+ except Exception as e:
209
+ if isinstance(e, URLValidationError):
210
+ raise
211
+ raise URLValidationError(
212
+ f"URL is not reachable ({e}). Please check if the URL is correct and accessible.",
213
+ url=url,
214
+ )
215
+
216
+
217
+ def _range_check(url: str, *, timeout: int = 5) -> None:
218
+ """
219
+ GET + Range: bytes=0-0 降级预检,只取 1 字节。
220
+ 如果服务器连 Range GET 也拒绝(405/400),仍视为可达——
221
+ 因为返回 HTTP 响应本身就证明服务器在线。
222
+ 只有 404/5xx/网络不可达才判定为不可达。
223
+ """
224
+ import urllib.request
225
+
226
+ req = urllib.request.Request(url, method="GET")
227
+ req.add_header("User-Agent", "CozeSDK-URLValidator/1.0")
228
+ req.add_header("Range", "bytes=0-0")
229
+ try:
230
+ with urllib.request.urlopen(req, timeout=timeout) as resp:
231
+ # 206 Partial Content 或 200 都说明可达
232
+ if resp.status >= 400:
233
+ raise URLValidationError(
234
+ f"URL is not reachable: HTTP {resp.status}", url=url
235
+ )
236
+ except urllib.error.HTTPError as e:
237
+ # 405/400 = 服务器在线但不支持此方法,视为可达
238
+ if e.code in (405, 400):
239
+ return
240
+ # 404/403/5xx = 资源不存在或服务异常
241
+ if e.code >= 400:
242
+ raise URLValidationError(
243
+ f"URL is not reachable: HTTP {e.code}", url=url
244
+ )
245
+ except urllib.error.URLError as e:
246
+ raise URLValidationError(
247
+ f"URL is not reachable (network error: {e.reason}). Please check if the URL is correct and accessible.",
248
+ url=url,
249
+ )
250
+ except Exception as e:
251
+ if isinstance(e, URLValidationError):
252
+ raise
253
+ raise URLValidationError(
254
+ f"URL is not reachable ({e}). Please check if the URL is correct and accessible.",
255
+ url=url,
256
+ )
@@ -55,6 +55,11 @@ class FetchClient(BaseClient):
55
55
 
56
56
  @observe(name="fetch_url")
57
57
  def fetch(self, url: str) -> FetchResponse:
58
+ from ..core.url_utils import validate_url
59
+
60
+ # URL 校验:格式、协议、SSRF 防护(不做 HEAD 预检,由后端 fetch 服务处理)
61
+ url = validate_url(url)
62
+
58
63
  request = FetchRequest(url=url)
59
64
 
60
65
  response = self._request(
@@ -7,6 +7,7 @@ from cozeloop.decorator import observe
7
7
  from ..core.client import BaseClient
8
8
  from ..core.config import Config
9
9
  from ..core.exceptions import APIError
10
+ from ..core.url_utils import validate_url
10
11
  from .models import ImageConfig, ImageGenerationRequest, ImageGenerationResponse
11
12
 
12
13
 
@@ -54,6 +55,10 @@ class ImageGenerationClient(BaseClient):
54
55
  if watermark is not None:
55
56
  request_params["watermark"] = watermark
56
57
  if image is not None:
58
+ if isinstance(image, list):
59
+ image = [validate_url(u) for u in image]
60
+ else:
61
+ image = validate_url(image)
57
62
  request_params["image"] = image
58
63
  if response_format is not None:
59
64
  request_params["response_format"] = response_format
@@ -12,6 +12,7 @@ from langchain_core.messages import (
12
12
  from langchain_openai import ChatOpenAI
13
13
 
14
14
  from ..core.config import Config
15
+ from ..core.url_utils import validate_url
15
16
  from .models import LLMConfig
16
17
 
17
18
 
@@ -185,6 +186,18 @@ class LLMClient:
185
186
  msg.response_metadata["id"] = previous_response_id
186
187
  break
187
188
 
189
+ if not any(isinstance(msg, HumanMessage) for msg in messages):
190
+ raise ValueError("messages must contain at least one HumanMessage, otherwise the API request will fail validation.")
191
+
192
+ for msg in messages:
193
+ if isinstance(msg.content, list):
194
+ for part in msg.content:
195
+ if isinstance(part, dict):
196
+ if part.get("type") == "image_url" and "image_url" in part:
197
+ part["image_url"]["url"] = validate_url(part["image_url"]["url"])
198
+ elif part.get("type") == "video_url" and "video_url" in part:
199
+ part["video_url"]["url"] = validate_url(part["video_url"]["url"])
200
+
188
201
  llm = self._create_llm(
189
202
  llm_config,
190
203
  use_caching=use_caching,
@@ -6,7 +6,9 @@ from ..core.client import BaseClient
6
6
  from ..core.config import Config
7
7
  from .models import (
8
8
  AuthEmailConfig,
9
+ AuthPhoneConfig,
9
10
  BlockedQueryInfo,
11
+ ProjectAuthConfigV2,
10
12
  Bucket,
11
13
  ConnectionStateCount,
12
14
  ConnectionStats,
@@ -30,6 +32,8 @@ from .models import (
30
32
  TableSizeInfo,
31
33
  UpdateAuthConfigResponse,
32
34
  UpdateBucketResponse,
35
+ GetAuthConfigV2Response,
36
+ UpdateAuthConfigV2Response,
33
37
  )
34
38
 
35
39
 
@@ -324,6 +328,62 @@ class SupabaseClient(BaseClient):
324
328
 
325
329
  return GetAuthConfigResponse(config=config, code=code, msg=msg)
326
330
 
331
+
332
+ def get_auth_config_v2(self) -> GetAuthConfigV2Response:
333
+ response = self._request(
334
+ method="POST",
335
+ url=f"{self.base_url}/v2/supabase/auth/config/get",
336
+ json={},
337
+ headers=self._get_headers(),
338
+ )
339
+
340
+ code = response.get("code", 0)
341
+ msg = response.get("msg", "")
342
+ status = response.get("Status", 0)
343
+
344
+ config = None
345
+ c = response.get("Config")
346
+ if c:
347
+ email_config = None
348
+ ec = c.get("EmailConfig")
349
+ if ec:
350
+ email_config = AuthEmailConfig(
351
+ external_email_enabled=ec.get("external_email_enabled"),
352
+ disable_signup=ec.get("disable_signup"),
353
+ mailer_auto_confirm=ec.get("mailer_auto_confirm"),
354
+ double_confirm_changes=ec.get("double_confirm_changes"),
355
+ mailer_secure_email_change_enabled=ec.get("mailer_secure_email_change_enabled"),
356
+ mailer_otp_exp=ec.get("mailer_otp_exp"),
357
+ password_min_length=ec.get("password_min_length"),
358
+ password_required_characters=ec.get("password_required_characters"),
359
+ site_url=ec.get("site_url"),
360
+ smtp_host=ec.get("smtp_host"),
361
+ smtp_port=ec.get("smtp_port"),
362
+ smtp_user=ec.get("smtp_user"),
363
+ smtp_pass=ec.get("smtp_pass"),
364
+ smtp_admin_email=ec.get("smtp_admin_email"),
365
+ smtp_sender_name=ec.get("smtp_sender_name"),
366
+ smtp_max_frequency=ec.get("smtp_max_frequency"),
367
+ )
368
+
369
+ phone_config = None
370
+ pc = c.get("PhoneConfig")
371
+ if pc:
372
+ phone_config = AuthPhoneConfig(
373
+ external_phone_enabled=pc.get("external_phone_enabled"),
374
+ )
375
+
376
+ config = ProjectAuthConfigV2(
377
+ project_id=c.get("ProjectID", 0),
378
+ icon_uri=c.get("IconURI", ""),
379
+ icon_url=c.get("IconURL", ""),
380
+ name=c.get("Name", ""),
381
+ email_config=email_config,
382
+ phone_config=phone_config,
383
+ )
384
+
385
+ return GetAuthConfigV2Response(config=config, code=code, msg=msg, status=status)
386
+
327
387
  def update_auth_config(
328
388
  self,
329
389
  config: Optional[Dict] = None,
@@ -345,6 +405,26 @@ class SupabaseClient(BaseClient):
345
405
  msg=response.get("msg", ""),
346
406
  )
347
407
 
408
+ def update_auth_config_v2(
409
+ self,
410
+ config: Optional[Dict] = None,
411
+ ) -> UpdateAuthConfigV2Response:
412
+ payload: Dict = config if config is not None else {}
413
+
414
+ response = self._request(
415
+ method="POST",
416
+ url=f"{self.base_url}/v2/supabase/auth/config/update",
417
+ json=payload,
418
+ headers=self._get_headers(),
419
+ )
420
+
421
+ return UpdateAuthConfigV2Response(
422
+ should_update_ui=response.get("should_update_ui", False),
423
+ success=response.get("success", False),
424
+ code=response.get("code", 0),
425
+ msg=response.get("msg", ""),
426
+ )
427
+
348
428
  def diagnose_database(
349
429
  self,
350
430
  env: Optional[str] = None,
@@ -37,7 +37,7 @@ class Bucket:
37
37
  class AuthEmailConfig:
38
38
  external_email_enabled: Optional[bool] = None
39
39
  disable_signup: Optional[bool] = None
40
- mailer_autoconfirm: Optional[bool] = None
40
+ mailer_auto_confirm: Optional[bool] = None
41
41
  double_confirm_changes: Optional[bool] = None
42
42
  mailer_secure_email_change_enabled: Optional[bool] = None
43
43
  mailer_otp_exp: Optional[int] = None
@@ -53,6 +53,20 @@ class AuthEmailConfig:
53
53
  smtp_max_frequency: Optional[int] = None
54
54
 
55
55
 
56
+ @dataclass
57
+ class AuthPhoneConfig:
58
+ external_phone_enabled: Optional[bool] = None
59
+
60
+ @dataclass
61
+ class ProjectAuthConfigV2:
62
+ project_id: int = 0
63
+ icon_uri: str = ""
64
+ icon_url: str = ""
65
+ name: str = ""
66
+ email_config: Optional[AuthEmailConfig] = None
67
+ phone_config: Optional[AuthPhoneConfig] = None
68
+
69
+
56
70
  @dataclass
57
71
  class ListEdgeFunctionsResponse:
58
72
  functions: List[EdgeFunction] = field(default_factory=list)
@@ -127,6 +141,14 @@ class GetAuthConfigResponse:
127
141
  msg: str = ""
128
142
 
129
143
 
144
+ @dataclass
145
+ class GetAuthConfigV2Response:
146
+ status: int = 0
147
+ config: Optional[ProjectAuthConfigV2] = None
148
+ code: int = 0
149
+ msg: str = ""
150
+
151
+
130
152
  @dataclass
131
153
  class UpdateAuthConfigResponse:
132
154
  success: bool = False
@@ -134,6 +156,14 @@ class UpdateAuthConfigResponse:
134
156
  msg: str = ""
135
157
 
136
158
 
159
+ @dataclass
160
+ class UpdateAuthConfigV2Response:
161
+ should_update_ui: bool = False
162
+ success: bool = False
163
+ code: int = 0
164
+ msg: str = ""
165
+
166
+
137
167
  # Database Diagnostic
138
168
 
139
169
 
@@ -9,6 +9,7 @@ from cozeloop.decorator import observe
9
9
  from ..core.client import BaseClient
10
10
  from ..core.config import Config
11
11
  from ..core.exceptions import APIError
12
+ from ..core.url_utils import validate_url
12
13
  from .models import (
13
14
  ImageURLContent,
14
15
  TextContent,
@@ -131,6 +132,10 @@ class VideoGenerationClient(BaseClient):
131
132
  """
132
133
  poll_interval = 5
133
134
 
135
+ for item in content_items:
136
+ if isinstance(item, ImageURLContent):
137
+ item.image_url.url = validate_url(item.image_url.url)
138
+
134
139
  request_data = {
135
140
  "model": model,
136
141
  "content": [item.model_dump() for item in content_items],
@@ -8,6 +8,7 @@ from coze_coding_utils.runtime_ctx.context import Context
8
8
  from ..core.client import BaseClient
9
9
  from ..core.config import Config
10
10
  from ..core.exceptions import APIError
11
+ from ..core.url_utils import validate_url
11
12
  from .models import (
12
13
  AddSubtitlesRequest,
13
14
  AudioExtractRequest,
@@ -59,6 +60,10 @@ class VideoEditClient(BaseClient):
59
60
  Raises:
60
61
  APIError: 当添加字幕失败时
61
62
  """
63
+ video = validate_url(video)
64
+ if subtitle_url is not None:
65
+ subtitle_url = validate_url(subtitle_url)
66
+
62
67
  request_params = {
63
68
  "video": video,
64
69
  "subtitle_config": subtitle_config,
@@ -129,6 +134,8 @@ class VideoEditClient(BaseClient):
129
134
  Raises:
130
135
  APIError: 当视频拼接失败时
131
136
  """
137
+ videos = [validate_url(v) for v in videos]
138
+
132
139
  request_params = {"videos": videos}
133
140
  if transitions is not None:
134
141
  request_params["transitions"] = transitions
@@ -198,6 +205,9 @@ class VideoEditClient(BaseClient):
198
205
  Raises:
199
206
  APIError: 当视频音频合成失败时
200
207
  """
208
+ video = validate_url(video)
209
+ audio = validate_url(audio)
210
+
201
211
  request_params = {
202
212
  "video": video,
203
213
  "audio": audio,
@@ -269,6 +279,8 @@ class VideoEditClient(BaseClient):
269
279
  Raises:
270
280
  APIError: 当语音转字幕失败时
271
281
  """
282
+ source = validate_url(source)
283
+
272
284
  request_params = {"source": source}
273
285
  if subtitle_type is not None:
274
286
  request_params["subtitle_type"] = subtitle_type
@@ -332,6 +344,8 @@ class VideoEditClient(BaseClient):
332
344
  Raises:
333
345
  APIError: 当音频提取失败时
334
346
  """
347
+ video = validate_url(video)
348
+
335
349
  request_params = {"video": video}
336
350
  if format is not None:
337
351
  request_params["format"] = format
@@ -397,6 +411,8 @@ class VideoEditClient(BaseClient):
397
411
  Raises:
398
412
  APIError: 当视频裁剪失败时
399
413
  """
414
+ video = validate_url(video)
415
+
400
416
  request_params = {"video": video}
401
417
  if start_time is not None:
402
418
  request_params["start_time"] = start_time
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coze-coding-dev-sdk
3
- Version: 0.5.15
3
+ Version: 0.5.16
4
4
  Summary: Coze Coding Dev SDK - 优雅的多功能 AI SDK,支持图片生成、视频生成、语音合成、语音识别、大语言模型、联网搜索和文本/多模态 Embedding。包含命令行工具 coze-coding-ai,支持 Context 上下文追踪
5
5
  Author-email: Coze Coding Integration Team <support@coze.com>
6
6
  Maintainer-email: Coze Coding Integration Team <support@coze.com>
@@ -30,6 +30,7 @@ coze_coding_dev_sdk/core/__init__.py
30
30
  coze_coding_dev_sdk/core/client.py
31
31
  coze_coding_dev_sdk/core/config.py
32
32
  coze_coding_dev_sdk/core/exceptions.py
33
+ coze_coding_dev_sdk/core/url_utils.py
33
34
  coze_coding_dev_sdk/database/__init__.py
34
35
  coze_coding_dev_sdk/database/client.py
35
36
  coze_coding_dev_sdk/database/migration.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "coze-coding-dev-sdk"
7
- version = "0.5.15"
7
+ version = "0.5.16"
8
8
  description = "Coze Coding Dev SDK - 优雅的多功能 AI SDK,支持图片生成、视频生成、语音合成、语音识别、大语言模型、联网搜索和文本/多模态 Embedding。包含命令行工具 coze-coding-ai,支持 Context 上下文追踪"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"