veadk-python 0.2.6__py3-none-any.whl → 0.2.8__py3-none-any.whl

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.

Potentially problematic release.


This version of veadk-python might be problematic. Click here for more details.

Files changed (102) hide show
  1. veadk/agent.py +11 -18
  2. veadk/agent_builder.py +94 -0
  3. veadk/{database/__init__.py → auth/base_auth.py} +7 -2
  4. veadk/auth/veauth/apmplus_veauth.py +65 -0
  5. veadk/auth/veauth/ark_veauth.py +77 -0
  6. veadk/auth/veauth/base_veauth.py +50 -0
  7. veadk/auth/veauth/opensearch_veauth.py +75 -0
  8. veadk/auth/veauth/postgresql_veauth.py +75 -0
  9. veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
  10. veadk/auth/veauth/vesearch_veauth.py +62 -0
  11. veadk/cli/cli.py +4 -0
  12. veadk/cli/cli_deploy.py +3 -2
  13. veadk/cli/cli_eval.py +160 -0
  14. veadk/cli/cli_init.py +1 -1
  15. veadk/cli/cli_pipeline.py +220 -0
  16. veadk/cli/cli_prompt.py +4 -4
  17. veadk/cli/cli_web.py +3 -1
  18. veadk/config.py +45 -81
  19. veadk/configs/database_configs.py +117 -0
  20. veadk/configs/model_configs.py +74 -0
  21. veadk/configs/tool_configs.py +42 -0
  22. veadk/configs/tracing_configs.py +110 -0
  23. veadk/consts.py +13 -1
  24. veadk/evaluation/base_evaluator.py +60 -44
  25. veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +18 -12
  26. veadk/evaluation/eval_set_recorder.py +2 -2
  27. veadk/integrations/ve_code_pipeline/__init__.py +13 -0
  28. veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
  29. veadk/integrations/ve_cozeloop/__init__.py +13 -0
  30. veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
  31. veadk/integrations/ve_cr/ve_cr.py +20 -5
  32. veadk/integrations/ve_faas/template/cookiecutter.json +1 -1
  33. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +2 -2
  34. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +1 -1
  35. veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +1 -5
  36. veadk/integrations/ve_faas/ve_faas.py +351 -36
  37. veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +6 -3
  38. veadk/integrations/ve_tls/__init__.py +13 -0
  39. veadk/integrations/ve_tls/utils.py +117 -0
  40. veadk/integrations/ve_tls/ve_tls.py +208 -0
  41. veadk/integrations/ve_tos/ve_tos.py +71 -75
  42. veadk/knowledgebase/backends/__init__.py +13 -0
  43. veadk/knowledgebase/backends/base_backend.py +59 -0
  44. veadk/knowledgebase/backends/in_memory_backend.py +82 -0
  45. veadk/knowledgebase/backends/opensearch_backend.py +136 -0
  46. veadk/knowledgebase/backends/redis_backend.py +144 -0
  47. veadk/knowledgebase/backends/utils.py +91 -0
  48. veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +412 -0
  49. veadk/knowledgebase/knowledgebase.py +109 -55
  50. veadk/memory/__init__.py +22 -0
  51. veadk/memory/long_term_memory.py +120 -51
  52. veadk/memory/long_term_memory_backends/__init__.py +13 -0
  53. veadk/{database/base_database.py → memory/long_term_memory_backends/base_backend.py} +10 -22
  54. veadk/memory/long_term_memory_backends/in_memory_backend.py +65 -0
  55. veadk/memory/long_term_memory_backends/opensearch_backend.py +120 -0
  56. veadk/memory/long_term_memory_backends/redis_backend.py +127 -0
  57. veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +148 -0
  58. veadk/memory/short_term_memory.py +80 -72
  59. veadk/memory/short_term_memory_backends/__init__.py +13 -0
  60. veadk/memory/short_term_memory_backends/base_backend.py +31 -0
  61. veadk/memory/short_term_memory_backends/mysql_backend.py +41 -0
  62. veadk/memory/short_term_memory_backends/postgresql_backend.py +41 -0
  63. veadk/memory/short_term_memory_backends/sqlite_backend.py +48 -0
  64. veadk/memory/short_term_memory_processor.py +9 -4
  65. veadk/runner.py +204 -247
  66. veadk/tools/builtin_tools/vesearch.py +2 -2
  67. veadk/tools/builtin_tools/video_generate.py +27 -20
  68. veadk/tools/builtin_tools/web_scraper.py +1 -1
  69. veadk/tools/builtin_tools/web_search.py +7 -7
  70. veadk/tools/load_knowledgebase_tool.py +1 -1
  71. veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +20 -2
  72. veadk/tracing/telemetry/exporters/apmplus_exporter.py +178 -14
  73. veadk/tracing/telemetry/exporters/cozeloop_exporter.py +6 -9
  74. veadk/tracing/telemetry/exporters/inmemory_exporter.py +22 -8
  75. veadk/tracing/telemetry/exporters/tls_exporter.py +6 -10
  76. veadk/tracing/telemetry/opentelemetry_tracer.py +5 -8
  77. veadk/tracing/telemetry/telemetry.py +66 -60
  78. veadk/utils/logger.py +1 -1
  79. veadk/utils/misc.py +63 -0
  80. veadk/utils/volcengine_sign.py +6 -2
  81. veadk/version.py +1 -1
  82. {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/METADATA +16 -3
  83. {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/RECORD +93 -64
  84. veadk/database/database_adapter.py +0 -368
  85. veadk/database/database_factory.py +0 -80
  86. veadk/database/kv/redis_database.py +0 -159
  87. veadk/database/local_database.py +0 -61
  88. veadk/database/relational/mysql_database.py +0 -173
  89. veadk/database/vector/opensearch_vector_database.py +0 -263
  90. veadk/database/vector/type.py +0 -50
  91. veadk/database/viking/viking_database.py +0 -471
  92. veadk/database/viking/viking_memory_db.py +0 -525
  93. /veadk/{database/kv → auth}/__init__.py +0 -0
  94. /veadk/{database/relational → auth/veauth}/__init__.py +0 -0
  95. /veadk/{database/vector/__init__.py → auth/veauth/cozeloop_veauth.py} +0 -0
  96. /veadk/{database/viking → configs}/__init__.py +0 -0
  97. /veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{{ cookiecutter.app_name|replace('-', '_') }} → {{ cookiecutter.app_name }}}/__init__.py +0 -0
  98. /veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{{ cookiecutter.app_name|replace('-', '_') }} → {{ cookiecutter.app_name }}}/agent.py +0 -0
  99. {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/WHEEL +0 -0
  100. {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/entry_points.txt +0 -0
  101. {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/licenses/LICENSE +0 -0
  102. {veadk_python-0.2.6.dist-info → veadk_python-0.2.8.dist-info}/top_level.txt +0 -0
@@ -13,10 +13,10 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import json
16
+ import os
16
17
  import time
17
18
 
18
19
  import requests
19
- import typer
20
20
  import volcenginesdkcore
21
21
  import volcenginesdkvefaas
22
22
  from volcenginesdkvefaas.models.env_for_create_function_input import (
@@ -118,6 +118,7 @@ class VeFaaS:
118
118
  runtime="native-python3.10/v1",
119
119
  request_timeout=1800,
120
120
  envs=envs,
121
+ memory_mb=2048,
121
122
  )
122
123
  )
123
124
 
@@ -141,6 +142,8 @@ class VeFaaS:
141
142
  upstream_name: str,
142
143
  service_name: str,
143
144
  ):
145
+ enable_key_auth = os.getenv("VEFAAS_ENABLE_KEY_AUTH", "true").lower() == "true"
146
+
144
147
  response = ve_request(
145
148
  request_body={
146
149
  "Name": application_name,
@@ -152,7 +155,7 @@ class VeFaaS:
152
155
  "GatewayName": gateway_name,
153
156
  "ServiceName": service_name,
154
157
  "UpstreamName": upstream_name,
155
- "EnableKeyAuth": True,
158
+ "EnableKeyAuth": enable_key_auth,
156
159
  "EnableMcpSession": True,
157
160
  },
158
161
  "TemplateId": self.template_id,
@@ -191,16 +194,27 @@ class VeFaaS:
191
194
  time.sleep(10)
192
195
  status, full_response = self._get_application_status(app_id)
193
196
 
194
- assert status == "deploy_success", (
195
- f"Release application failed. Response: {full_response}"
196
- )
197
-
198
- cloud_resource = full_response["Result"]["CloudResource"]
199
- cloud_resource = json.loads(cloud_resource)
200
-
201
- url = cloud_resource["framework"]["url"]["system_url"]
202
-
203
- return url
197
+ if status == "deploy_success":
198
+ cloud_resource = full_response["Result"]["CloudResource"]
199
+ cloud_resource = json.loads(cloud_resource)
200
+ url = cloud_resource["framework"]["url"]["system_url"]
201
+ return url
202
+ else:
203
+ logger.error(
204
+ f"Release application failed. Application ID: {app_id}, Status: {status}"
205
+ )
206
+ import re
207
+
208
+ logs = "\n".join(self._get_application_logs(app_id=app_id))
209
+ log_text = re.sub(
210
+ r'([{"\']?(key|secret|token|pass|auth|credential|access|api|ak|sk|doubao|volces|coze)[^"\'\s]*["\']?\s*[:=]\s*)(["\']?)([^"\'\s]+)(["\']?)|([A-Za-z0-9+/=]{20,})',
211
+ lambda m: f"{m.group(1)}{m.group(3)}******{m.group(5)}"
212
+ if m.group(1)
213
+ else "******",
214
+ logs,
215
+ flags=re.IGNORECASE,
216
+ )
217
+ raise Exception(f"Release application failed. Logs:\n{log_text}")
204
218
 
205
219
  def _get_application_status(self, app_id: str):
206
220
  response = ve_request(
@@ -215,18 +229,51 @@ class VeFaaS:
215
229
  )
216
230
  return response["Result"]["Status"], response
217
231
 
218
- def _list_application(self):
219
- response = ve_request(
220
- request_body={},
221
- action="ListApplications",
222
- ak=self.ak,
223
- sk=self.sk,
224
- service="vefaas",
225
- version="2021-03-03",
226
- region="cn-beijing",
227
- host="open.volcengineapi.com",
228
- )
229
- return response["Result"]["Items"]
232
+ def _list_application(self, app_id: str = None, app_name: str = None):
233
+ # firt match app_id. if app_id is None,then match app_name and remove app_id
234
+ request_body = {
235
+ "OrderBy": {"Key": "CreateTime", "Ascend": False},
236
+ "FunctionId": app_id if app_id else None,
237
+ "Filters": [{"Item": {"Key": "Name", "Value": [app_name]}}]
238
+ if app_name and not app_id
239
+ else None,
240
+ }
241
+ # remove None
242
+ request_body = {k: v for k, v in request_body.items() if v is not None}
243
+
244
+ page_size = 50
245
+ page_number = 1
246
+ all_items = []
247
+ total_page = None
248
+ while True:
249
+ try:
250
+ request_body.update({"PageNumber": page_number, "PageSize": page_size})
251
+ response = ve_request(
252
+ request_body=request_body,
253
+ action="ListApplications",
254
+ ak=self.ak,
255
+ sk=self.sk,
256
+ service="vefaas",
257
+ version="2021-03-03",
258
+ region="cn-beijing",
259
+ host="open.volcengineapi.com",
260
+ )
261
+ result = response.get("Result", {})
262
+ items = result.get("Items", [])
263
+ all_items.extend(items)
264
+
265
+ if total_page is None:
266
+ total = result.get("Total", 0)
267
+ total_page = (total + page_size - 1) // page_size
268
+
269
+ if page_number >= total_page or not items:
270
+ break
271
+ page_number += 1
272
+ except Exception as e:
273
+ raise ValueError(
274
+ f"List application failed. Error: {str(e)}. Response: {response}."
275
+ )
276
+ return all_items
230
277
 
231
278
  def _update_function_code(
232
279
  self,
@@ -255,10 +302,6 @@ class VeFaaS:
255
302
 
256
303
  # Get application status and extract function info
257
304
  status, full_response = self._get_application_status(app_id)
258
- if status == "deploy_fail":
259
- raise ValueError(
260
- f"Cannot update failed application. Current status: {status}"
261
- )
262
305
 
263
306
  # Extract function name from application config
264
307
  cloud_resource = full_response["Result"]["CloudResource"]
@@ -302,7 +345,7 @@ class VeFaaS:
302
345
  def get_application_details(self, app_id: str = None, app_name: str = None):
303
346
  if not app_id and not app_name:
304
347
  raise ValueError("app_id and app_name cannot be both empty.")
305
- apps = self._list_application()
348
+ apps = self._list_application(app_id=app_id, app_name=app_name)
306
349
  if app_id:
307
350
  for app in apps:
308
351
  if app["Id"] == app_id:
@@ -314,7 +357,7 @@ class VeFaaS:
314
357
  return app
315
358
 
316
359
  def find_app_id_by_name(self, name: str):
317
- apps = self._list_application()
360
+ apps = self._list_application(app_name=name)
318
361
  for app in apps:
319
362
  if app["Name"] == name:
320
363
  return app["Id"]
@@ -334,12 +377,7 @@ class VeFaaS:
334
377
  host="open.volcengineapi.com",
335
378
  )
336
379
  except Exception as e:
337
- typer.echo(
338
- typer.style(
339
- f"Delete application failed. Response: {e}",
340
- fg=typer.colors.BRIGHT_RED,
341
- )
342
- )
380
+ logger.error(f"Delete application failed. Response: {e}")
343
381
 
344
382
  def deploy(
345
383
  self,
@@ -411,3 +449,280 @@ class VeFaaS:
411
449
  logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.")
412
450
 
413
451
  return url, app_id, function_id
452
+
453
+ def _create_image_function(self, function_name: str, image: str):
454
+ """Create function using container image instead of code upload."""
455
+ # Read environment variables from veadk configuration
456
+ envs = []
457
+ for key, value in veadk.config.veadk_environments.items():
458
+ envs.append(EnvForCreateFunctionInput(key=key, value=value))
459
+ logger.info(
460
+ f"Fetch {len(envs)} environment variables for image function.",
461
+ )
462
+
463
+ # Create function with container image source configuration
464
+ res = self.client.create_function(
465
+ volcenginesdkvefaas.CreateFunctionRequest(
466
+ command="bash ./run.sh", # Custom startup command
467
+ name=function_name,
468
+ description="Created by VeADK (Volcengine Agent Development Kit)",
469
+ tags=[TagForCreateFunctionInput(key="provider", value="veadk")],
470
+ runtime="native/v1", # Native runtime required for container images
471
+ source_type="image", # Set source type to container image
472
+ source=image, # Container image URL
473
+ request_timeout=1800, # Request timeout in seconds
474
+ envs=envs, # Environment variables from configuration
475
+ )
476
+ )
477
+
478
+ # Log function creation success without exposing sensitive information
479
+ logger.debug(
480
+ f"Function creation in {res.project_name} project with ID {res.id}"
481
+ )
482
+
483
+ function_id = res.id
484
+ logger.info(
485
+ f"Function {function_name} created with image {image} and ID {function_id}"
486
+ )
487
+
488
+ return function_name, function_id
489
+
490
+ def query_user_cr_vpc_tunnel(
491
+ self, registry_name: str, max_attempts: int = 6
492
+ ) -> bool:
493
+ """Query and enable CR VPC tunnel for user registry access."""
494
+ logger.info(f"Setting up CR VPC tunnel for registry: {registry_name}")
495
+ waiting_times = 30
496
+
497
+ try:
498
+ for attempt in range(max_attempts):
499
+ # Check current status
500
+ logger.info(
501
+ f"Checking tunnel status (attempt {attempt + 1}/{max_attempts})"
502
+ )
503
+ query_resp = ve_request(
504
+ request_body={"Registry": registry_name},
505
+ action="QueryUserCrVpcTunnel",
506
+ ak=self.ak,
507
+ sk=self.sk,
508
+ service="vefaas",
509
+ version="2021-03-03",
510
+ region="cn-beijing",
511
+ host="open.volcengineapi.com",
512
+ )
513
+
514
+ current_status = query_resp.get("Result", {}).get("Ready", False)
515
+ logger.info(f"Current tunnel status: {current_status}")
516
+
517
+ # Always try to enable
518
+ logger.info("Enable VPC tunnel")
519
+ enable_resp = ve_request(
520
+ request_body={"Registry": registry_name},
521
+ action="EnableUserCrVpcTunnel",
522
+ ak=self.ak,
523
+ sk=self.sk,
524
+ service="vefaas",
525
+ version="2021-03-03",
526
+ region="cn-beijing",
527
+ host="open.volcengineapi.com",
528
+ )
529
+
530
+ # Handle EnableUserCrVpcTunnel response correctly
531
+ enable_result = enable_resp.get("Result", {})
532
+ enable_status = enable_result.get("Status", "")
533
+ enable_message = enable_result.get("Message", "")
534
+
535
+ if enable_status == "success":
536
+ logger.info("Enable tunnel succeeded")
537
+ elif enable_status == "failed":
538
+ logger.warning(f"Enable tunnel failed: {enable_message}")
539
+ else:
540
+ logger.warning(f"Enable tunnel unknown status: {enable_status}")
541
+
542
+ # Verify final status
543
+ logger.info("Verifying tunnel status")
544
+ verify_resp = ve_request(
545
+ request_body={"Registry": registry_name},
546
+ action="QueryUserCrVpcTunnel",
547
+ ak=self.ak,
548
+ sk=self.sk,
549
+ service="vefaas",
550
+ version="2021-03-03",
551
+ region="cn-beijing",
552
+ host="open.volcengineapi.com",
553
+ )
554
+
555
+ final_status = verify_resp.get("Result", {}).get("Ready", False)
556
+ logger.info(f"Final tunnel status: {final_status}")
557
+
558
+ if final_status:
559
+ logger.info(
560
+ f"CR VPC tunnel successfully enabled for {registry_name}"
561
+ )
562
+ return True
563
+
564
+ # If not ready and not last attempt, wait and retry
565
+ if attempt < max_attempts - 1:
566
+ logger.warning(
567
+ f"Tunnel not ready, waiting {waiting_times}s before retry"
568
+ )
569
+ time.sleep(waiting_times)
570
+
571
+ except Exception as e:
572
+ raise ValueError(f"Failed to setup CR VPC tunnel: {str(e)}")
573
+
574
+ return False
575
+
576
+ def _create_image_function(self, function_name: str, image: str):
577
+ """Create function using container image instead of code upload."""
578
+ # Read environment variables from veadk configuration
579
+ envs = []
580
+ for key, value in veadk.config.veadk_environments.items():
581
+ envs.append(EnvForCreateFunctionInput(key=key, value=value))
582
+ logger.info(
583
+ f"Fetch {len(envs)} environment variables for image function.",
584
+ )
585
+
586
+ # Create function with container image source configuration
587
+ res = self.client.create_function(
588
+ volcenginesdkvefaas.CreateFunctionRequest(
589
+ command="bash ./run.sh", # Custom startup command
590
+ name=function_name,
591
+ description="Created by VeADK (Volcengine Agent Development Kit)",
592
+ tags=[TagForCreateFunctionInput(key="provider", value="veadk")],
593
+ runtime="native/v1", # Native runtime required for container images
594
+ source_type="image", # Set source type to container image
595
+ source=image, # Container image URL
596
+ request_timeout=1800, # Request timeout in seconds
597
+ envs=envs, # Environment variables from configuration
598
+ )
599
+ )
600
+
601
+ # Log function creation success without exposing sensitive information
602
+ logger.debug(
603
+ f"Function creation in {res.project_name} project with ID {res.id}"
604
+ )
605
+
606
+ function_id = res.id
607
+ logger.info(
608
+ f"Function {function_name} created with image {image} and ID {function_id}"
609
+ )
610
+
611
+ return function_name, function_id
612
+
613
+ def deploy_image(
614
+ self,
615
+ name: str,
616
+ image: str,
617
+ registry_name: str,
618
+ gateway_name: str = "",
619
+ gateway_service_name: str = "",
620
+ gateway_upstream_name: str = "",
621
+ ) -> tuple[str, str, str]:
622
+ """Deploy application using container image.
623
+
624
+ Args:
625
+ name (str): Application name.
626
+ image (str): Container image URL.
627
+ gateway_name (str, optional): Gateway name. Defaults to "".
628
+ gateway_service_name (str, optional): Gateway service name. Defaults to "".
629
+ gateway_upstream_name (str, optional): Gateway upstream name. Defaults to "".
630
+
631
+ Returns:
632
+ tuple[str, str, str]: (url, app_id, function_id)
633
+ """
634
+ # Validate application name format
635
+ is_ready = self.query_user_cr_vpc_tunnel(registry_name)
636
+ if not is_ready:
637
+ raise ValueError("CR VPC tunnel is not ready")
638
+
639
+ if "_" in name:
640
+ raise ValueError("Function or Application name cannot contain '_'.")
641
+
642
+ # Generate default gateway names with timestamp if not provided
643
+ if not gateway_name:
644
+ gateway_name = f"{name}-gw-{formatted_timestamp()}"
645
+
646
+ # Check for existing serverless gateways to reuse
647
+ existing_gateways = self.apig_client.list_gateways()
648
+ for gateway_instance in existing_gateways.items:
649
+ if (
650
+ gateway_instance.type == "serverless"
651
+ and gateway_instance.name != gateway_name
652
+ ):
653
+ logger.warning(
654
+ f"You have at least one serverless gateway {gateway_instance.name}, but not {gateway_name}. Using {gateway_instance.name} instead."
655
+ )
656
+ gateway_name = gateway_instance.name
657
+ break
658
+
659
+ # Set default gateway service and upstream names
660
+ if not gateway_service_name:
661
+ gateway_service_name = f"{name}-gw-svr-{formatted_timestamp()}"
662
+ if not gateway_upstream_name:
663
+ gateway_upstream_name = f"{name}-gw-us-{formatted_timestamp()}"
664
+
665
+ function_name = f"{name}-fn"
666
+
667
+ # Log deployment start with image information
668
+ logger.info(
669
+ f"Start to create VeFaaS function {function_name} with image {image}. Gateway: {gateway_name}, Gateway Service: {gateway_service_name}, Gateway Upstream: {gateway_upstream_name}."
670
+ )
671
+
672
+ # Create function using container image method
673
+ function_name, function_id = self._create_image_function(function_name, image)
674
+ logger.info(f"VeFaaS function {function_name} with ID {function_id} created.")
675
+
676
+ # Create application using existing application creation logic
677
+ logger.info(f"Start to create VeFaaS application {name}.")
678
+ app_id = self._create_application(
679
+ name,
680
+ function_name,
681
+ gateway_name,
682
+ gateway_upstream_name,
683
+ gateway_service_name,
684
+ )
685
+
686
+ # Release application and get deployment URL
687
+ logger.info(f"VeFaaS application {name} with ID {app_id} created.")
688
+ logger.info(f"Start to release VeFaaS application {app_id}.")
689
+ # Release application with retry
690
+ max_attempts = 5
691
+ attempt = 0
692
+ while True:
693
+ try:
694
+ url = self._release_application(app_id)
695
+ logger.info(f"VeFaaS application {name} with ID {app_id} released.")
696
+ break
697
+ except Exception:
698
+ attempt += 1
699
+ if attempt < max_attempts:
700
+ wait_time = 30 * attempt
701
+ logger.info(
702
+ f"Image sync still in progress. Waiting {wait_time} seconds before retry {attempt}/{max_attempts}."
703
+ )
704
+ time.sleep(wait_time)
705
+ else:
706
+ raise
707
+
708
+ logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.")
709
+
710
+ return url, app_id, function_id
711
+
712
+ def _get_application_logs(self, app_id: str) -> list[str]:
713
+ response = _ = ve_request(
714
+ request_body={"Id": app_id, "Limit": 99999, "RevisionNumber": 1},
715
+ action="GetApplicationRevisionLog",
716
+ ak=self.ak,
717
+ sk=self.sk,
718
+ service="vefaas",
719
+ version="2021-03-03",
720
+ region="cn-beijing",
721
+ host="open.volcengineapi.com",
722
+ )
723
+
724
+ try:
725
+ logs = response["Result"]["LogLines"]
726
+ return logs
727
+ except Exception as _:
728
+ raise ValueError(f"Get application log failed. Response: {response}")
@@ -65,12 +65,15 @@ class VePromptPilot:
65
65
  api_key=self.api_key,
66
66
  ): # stream chunks of optimized prompt
67
67
  # Process each chunk as it arrives
68
- optimized_prompt += chunk.data.content
68
+ optimized_prompt += chunk.data.content if chunk.data else ""
69
69
  # print(chunk.data.content, end="", flush=True)
70
70
  if chunk.event == "usage":
71
- usage = chunk.data.usage
71
+ usage = chunk.data.usage if chunk.data else 0
72
72
  optimized_prompt = optimized_prompt.replace("\\n", "\n")
73
73
  print(f"Optimized prompt for agent {agent.name}:\n{optimized_prompt}")
74
- logger.info(f"Token usage: {usage['total_tokens']}")
74
+ if usage:
75
+ logger.info(f"Token usage: {usage['total_tokens']}")
76
+ else:
77
+ logger.warning("No usage data.")
75
78
 
76
79
  return optimized_prompt
@@ -0,0 +1,13 @@
1
+ # Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
@@ -0,0 +1,117 @@
1
+ # Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import hashlib
16
+ import json
17
+ from typing import Any, Literal
18
+
19
+ import httpx
20
+ from volcengine.ApiInfo import ApiInfo
21
+ from volcengine.auth.SignerV4 import SignerV4
22
+ from volcengine.tls.const import (
23
+ APPLICATION_JSON,
24
+ CONTENT_MD5,
25
+ CONTENT_TYPE,
26
+ DATA,
27
+ WEB_TRACKS,
28
+ )
29
+ from volcengine.tls.TLSService import TLSService
30
+
31
+ from veadk.utils.logger import get_logger
32
+
33
+ logger = get_logger(__name__)
34
+
35
+ HEADER_API_VERSION = "x-tls-apiversion"
36
+ API_VERSION_V_0_3_0 = "0.3.0"
37
+
38
+ API_INFO = {
39
+ "CreateProject": ApiInfo("POST", "/CreateProject", {}, {}, {}),
40
+ "DescribeProjects": ApiInfo("GET", "/DescribeProjects", {}, {}, {}),
41
+ "CreateTraceInstance": ApiInfo("POST", "/CreateTraceInstance", {}, {}, {}),
42
+ "DescribeTraceInstances": ApiInfo("GET", "/DescribeTraceInstances", {}, {}, {}),
43
+ "DescribeTraceInstance": ApiInfo("GET", "/DescribeTraceInstance", {}, {}, {}),
44
+ }
45
+
46
+
47
+ def __prepare_request(
48
+ client: TLSService,
49
+ api: str,
50
+ params: dict | None = None,
51
+ body: Any | None = None,
52
+ request_headers: dict | None = None,
53
+ ):
54
+ if params is None:
55
+ params = {}
56
+ if body is None:
57
+ body = {}
58
+
59
+ request = client.prepare_request(API_INFO[api], params)
60
+
61
+ if request_headers is None:
62
+ request_headers = {CONTENT_TYPE: APPLICATION_JSON}
63
+ request.headers.update(request_headers)
64
+
65
+ if "json" in request.headers[CONTENT_TYPE] and api != WEB_TRACKS:
66
+ request.body = json.dumps(body)
67
+ else:
68
+ request.body = body[DATA]
69
+
70
+ if len(request.body) != 0:
71
+ if isinstance(request.body, str):
72
+ request.headers[CONTENT_MD5] = hashlib.md5(
73
+ request.body.encode("utf-8")
74
+ ).hexdigest()
75
+ else:
76
+ request.headers[CONTENT_MD5] = hashlib.md5(request.body).hexdigest()
77
+
78
+ SignerV4.sign(request, client.service_info.credentials)
79
+
80
+ return request
81
+
82
+
83
+ def ve_tls_request(
84
+ client: TLSService,
85
+ api: str,
86
+ params: dict | None = None,
87
+ body: dict | None = None,
88
+ request_headers: dict | None = None,
89
+ method: Literal["POST", "GET", "PUT", "DELETE"] = "POST",
90
+ ):
91
+ """Customize a standard HTTP request to the Volcengine TLS API"""
92
+
93
+ if request_headers is None:
94
+ request_headers = {HEADER_API_VERSION: API_VERSION_V_0_3_0}
95
+ elif HEADER_API_VERSION not in request_headers:
96
+ request_headers[HEADER_API_VERSION] = API_VERSION_V_0_3_0
97
+ if CONTENT_TYPE not in request_headers:
98
+ request_headers[CONTENT_TYPE] = APPLICATION_JSON
99
+ request = __prepare_request(client, api, params, body, request_headers)
100
+
101
+ url = request.build()
102
+
103
+ with httpx.Client() as session:
104
+ while True:
105
+ try:
106
+ response = session.request(
107
+ method=method,
108
+ url=url,
109
+ headers=request.headers,
110
+ data=request.body, # type: ignore
111
+ timeout=60,
112
+ )
113
+ return response.json()
114
+ except Exception as e:
115
+ logger.error(
116
+ f"Error occurred while making {method} request to {url}: {e}. Response: {response}"
117
+ )