Files
Dorod-Sky/skyvern/forge/forge_app.py

263 lines
12 KiB
Python

from __future__ import annotations
from typing import Awaitable, Callable
from anthropic import AsyncAnthropic, AsyncAnthropicBedrock
from fastapi import FastAPI
from openai import AsyncAzureOpenAI, AsyncOpenAI
from skyvern.config import Settings
from skyvern.forge.agent import ForgeAgent
from skyvern.forge.agent_functions import AgentFunction
from skyvern.forge.forge_openai_client import ForgeAsyncHttpxClientWrapper
from skyvern.forge.sdk.api.azure import AzureClientFactory
from skyvern.forge.sdk.api.custom_credential_client import CustomCredentialAPIClient
from skyvern.forge.sdk.api.llm.api_handler import LLMAPIHandler
from skyvern.forge.sdk.api.llm.api_handler_factory import LLMAPIHandlerFactory
from skyvern.forge.sdk.api.real_azure import RealAzureClientFactory
from skyvern.forge.sdk.artifact.manager import ArtifactManager
from skyvern.forge.sdk.artifact.storage.azure import AzureStorage
from skyvern.forge.sdk.artifact.storage.base import BaseStorage
from skyvern.forge.sdk.artifact.storage.factory import StorageFactory
from skyvern.forge.sdk.artifact.storage.s3 import S3Storage
from skyvern.forge.sdk.cache.base import BaseCache
from skyvern.forge.sdk.cache.factory import CacheFactory
from skyvern.forge.sdk.core.rate_limiter import NoopRateLimiter, RateLimiter
from skyvern.forge.sdk.db.agent_db import AgentDB
from skyvern.forge.sdk.experimentation.providers import BaseExperimentationProvider, NoOpExperimentationProvider
from skyvern.forge.sdk.schemas.credentials import CredentialVaultType
from skyvern.forge.sdk.schemas.organizations import AzureClientSecretCredential, Organization
from skyvern.forge.sdk.services.credential.azure_credential_vault_service import AzureCredentialVaultService
from skyvern.forge.sdk.services.credential.bitwarden_credential_service import BitwardenCredentialVaultService
from skyvern.forge.sdk.services.credential.credential_vault_service import CredentialVaultService
from skyvern.forge.sdk.services.credential.custom_credential_vault_service import CustomCredentialVaultService
from skyvern.forge.sdk.settings_manager import SettingsManager
from skyvern.forge.sdk.workflow.context_manager import WorkflowContextManager
from skyvern.forge.sdk.workflow.service import WorkflowService
from skyvern.services.browser_recording.service import BrowserSessionRecordingService
from skyvern.webeye.browser_manager import BrowserManager
from skyvern.webeye.default_persistent_sessions_manager import DefaultPersistentSessionsManager
from skyvern.webeye.persistent_sessions_manager import PersistentSessionsManager
from skyvern.webeye.real_browser_manager import RealBrowserManager
from skyvern.webeye.scraper.scraper import ScrapeExcludeFunc
class ForgeApp:
"""Container for shared Forge services"""
SETTINGS_MANAGER: Settings
DATABASE: AgentDB
REPLICA_DATABASE: AgentDB
STORAGE: BaseStorage
CACHE: BaseCache
ARTIFACT_MANAGER: ArtifactManager
BROWSER_MANAGER: BrowserManager
EXPERIMENTATION_PROVIDER: BaseExperimentationProvider
RATE_LIMITER: RateLimiter
LLM_API_HANDLER: LLMAPIHandler
OPENAI_CLIENT: AsyncOpenAI | AsyncAzureOpenAI
ANTHROPIC_CLIENT: AsyncAnthropic | AsyncAnthropicBedrock
UI_TARS_CLIENT: AsyncOpenAI | None
AZURE_CLIENT_FACTORY: AzureClientFactory
SECONDARY_LLM_API_HANDLER: LLMAPIHandler
SELECT_AGENT_LLM_API_HANDLER: LLMAPIHandler
NORMAL_SELECT_AGENT_LLM_API_HANDLER: LLMAPIHandler
CUSTOM_SELECT_AGENT_LLM_API_HANDLER: LLMAPIHandler
SINGLE_CLICK_AGENT_LLM_API_HANDLER: LLMAPIHandler
SINGLE_INPUT_AGENT_LLM_API_HANDLER: LLMAPIHandler
PARSE_SELECT_LLM_API_HANDLER: LLMAPIHandler
EXTRACTION_LLM_API_HANDLER: LLMAPIHandler
CHECK_USER_GOAL_LLM_API_HANDLER: LLMAPIHandler
AUTO_COMPLETION_LLM_API_HANDLER: LLMAPIHandler
SVG_CSS_CONVERTER_LLM_API_HANDLER: LLMAPIHandler | None
SCRIPT_GENERATION_LLM_API_HANDLER: LLMAPIHandler
WORKFLOW_CONTEXT_MANAGER: WorkflowContextManager
WORKFLOW_SERVICE: WorkflowService
AGENT_FUNCTION: AgentFunction
PERSISTENT_SESSIONS_MANAGER: PersistentSessionsManager
BROWSER_SESSION_RECORDING_SERVICE: BrowserSessionRecordingService
BITWARDEN_CREDENTIAL_VAULT_SERVICE: BitwardenCredentialVaultService
AZURE_CREDENTIAL_VAULT_SERVICE: AzureCredentialVaultService | None
CUSTOM_CREDENTIAL_VAULT_SERVICE: CustomCredentialVaultService | None
CREDENTIAL_VAULT_SERVICES: dict[str, CredentialVaultService | None]
scrape_exclude: ScrapeExcludeFunc | None
authentication_function: Callable[[str], Awaitable[Organization]] | None
authenticate_user_function: Callable[[str], Awaitable[str | None]] | None
setup_api_app: Callable[[FastAPI], None] | None
api_app_startup_event: Callable[[FastAPI], Awaitable[None]] | None
api_app_shutdown_event: Callable[[], Awaitable[None]] | None
agent: ForgeAgent
def create_forge_app() -> ForgeApp:
"""Create and initialize a ForgeApp instance with all services"""
settings: Settings = SettingsManager.get_settings()
app = ForgeApp()
app.SETTINGS_MANAGER = settings
app.DATABASE = AgentDB(settings.DATABASE_STRING, debug_enabled=settings.DEBUG_MODE)
if settings.DATABASE_REPLICA_STRING and settings.DATABASE_REPLICA_STRING != settings.DATABASE_STRING:
app.REPLICA_DATABASE = AgentDB(settings.DATABASE_REPLICA_STRING, debug_enabled=settings.DEBUG_MODE)
else:
app.REPLICA_DATABASE = app.DATABASE
if settings.SKYVERN_STORAGE_TYPE == "s3":
StorageFactory.set_storage(S3Storage())
elif settings.SKYVERN_STORAGE_TYPE == "azureblob":
StorageFactory.set_storage(AzureStorage())
app.STORAGE = StorageFactory.get_storage()
app.CACHE = CacheFactory.get_cache()
if settings.NOTIFICATION_REGISTRY_TYPE == "redis":
from redis.asyncio import from_url as redis_from_url
from skyvern.forge.sdk.notification.factory import NotificationRegistryFactory
from skyvern.forge.sdk.notification.redis import RedisNotificationRegistry
from skyvern.forge.sdk.redis.factory import RedisClientFactory
redis_url = settings.NOTIFICATION_REDIS_URL or settings.REDIS_URL
redis_client = redis_from_url(redis_url, decode_responses=True)
RedisClientFactory.set_client(redis_client)
NotificationRegistryFactory.set_registry(RedisNotificationRegistry(redis_client))
app.ARTIFACT_MANAGER = ArtifactManager()
app.BROWSER_MANAGER = RealBrowserManager()
app.EXPERIMENTATION_PROVIDER = NoOpExperimentationProvider()
app.RATE_LIMITER = NoopRateLimiter()
app.LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(settings.LLM_KEY)
app.OPENAI_CLIENT = AsyncOpenAI(
api_key=settings.OPENAI_API_KEY or "",
http_client=ForgeAsyncHttpxClientWrapper(),
)
if settings.ENABLE_AZURE_CUA:
app.OPENAI_CLIENT = AsyncAzureOpenAI(
api_key=settings.AZURE_CUA_API_KEY,
api_version=settings.AZURE_CUA_API_VERSION,
azure_endpoint=settings.AZURE_CUA_ENDPOINT,
azure_deployment=settings.AZURE_CUA_DEPLOYMENT,
)
app.ANTHROPIC_CLIENT = AsyncAnthropic(api_key=settings.ANTHROPIC_API_KEY)
if settings.ENABLE_BEDROCK_ANTHROPIC:
app.ANTHROPIC_CLIENT = AsyncAnthropicBedrock()
app.UI_TARS_CLIENT = None
if settings.ENABLE_VOLCENGINE:
app.UI_TARS_CLIENT = AsyncOpenAI(
api_key=settings.VOLCENGINE_API_KEY,
base_url=settings.VOLCENGINE_API_BASE,
http_client=ForgeAsyncHttpxClientWrapper(),
)
app.SECONDARY_LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(
settings.SECONDARY_LLM_KEY if settings.SECONDARY_LLM_KEY else settings.LLM_KEY
)
app.SELECT_AGENT_LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(
settings.SELECT_AGENT_LLM_KEY or settings.SECONDARY_LLM_KEY or settings.LLM_KEY
)
app.NORMAL_SELECT_AGENT_LLM_API_HANDLER = (
LLMAPIHandlerFactory.get_llm_api_handler(settings.NORMAL_SELECT_AGENT_LLM_KEY)
if settings.NORMAL_SELECT_AGENT_LLM_KEY
else app.SECONDARY_LLM_API_HANDLER
)
app.CUSTOM_SELECT_AGENT_LLM_API_HANDLER = (
LLMAPIHandlerFactory.get_llm_api_handler(settings.CUSTOM_SELECT_AGENT_LLM_KEY)
if settings.CUSTOM_SELECT_AGENT_LLM_KEY
else app.SECONDARY_LLM_API_HANDLER
)
app.SINGLE_CLICK_AGENT_LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(
settings.SINGLE_CLICK_AGENT_LLM_KEY or settings.SECONDARY_LLM_KEY or settings.LLM_KEY
)
app.SINGLE_INPUT_AGENT_LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(
settings.SINGLE_INPUT_AGENT_LLM_KEY or settings.SECONDARY_LLM_KEY or settings.LLM_KEY
)
app.PARSE_SELECT_LLM_API_HANDLER = (
LLMAPIHandlerFactory.get_llm_api_handler(settings.PARSE_SELECT_LLM_KEY)
if settings.PARSE_SELECT_LLM_KEY
else app.SECONDARY_LLM_API_HANDLER
)
app.EXTRACTION_LLM_API_HANDLER = (
LLMAPIHandlerFactory.get_llm_api_handler(settings.EXTRACTION_LLM_KEY)
if settings.EXTRACTION_LLM_KEY
else app.LLM_API_HANDLER
)
app.CHECK_USER_GOAL_LLM_API_HANDLER = (
LLMAPIHandlerFactory.get_llm_api_handler(settings.CHECK_USER_GOAL_LLM_KEY)
if settings.CHECK_USER_GOAL_LLM_KEY
else app.SECONDARY_LLM_API_HANDLER
)
app.AUTO_COMPLETION_LLM_API_HANDLER = (
LLMAPIHandlerFactory.get_llm_api_handler(settings.AUTO_COMPLETION_LLM_KEY)
if settings.AUTO_COMPLETION_LLM_KEY
else app.SECONDARY_LLM_API_HANDLER
)
app.SVG_CSS_CONVERTER_LLM_API_HANDLER = app.SECONDARY_LLM_API_HANDLER if settings.SECONDARY_LLM_KEY else None
app.SCRIPT_GENERATION_LLM_API_HANDLER = (
LLMAPIHandlerFactory.get_llm_api_handler(settings.SCRIPT_GENERATION_LLM_KEY)
if settings.SCRIPT_GENERATION_LLM_KEY
else app.SECONDARY_LLM_API_HANDLER
)
app.WORKFLOW_CONTEXT_MANAGER = WorkflowContextManager()
app.WORKFLOW_SERVICE = WorkflowService()
app.AGENT_FUNCTION = AgentFunction()
app.PERSISTENT_SESSIONS_MANAGER = DefaultPersistentSessionsManager(database=app.DATABASE)
app.BROWSER_SESSION_RECORDING_SERVICE = BrowserSessionRecordingService()
app.AZURE_CLIENT_FACTORY = RealAzureClientFactory()
app.BITWARDEN_CREDENTIAL_VAULT_SERVICE = BitwardenCredentialVaultService()
# Azure Credential Vault Service
# If running a workload on Azure and using workload identity (the common case for AKS or Azure VMs),
# use DefaultAzureCredential when a client secret is not provided.
# If explicit credentials are configured use ClientSecretCredential instead.
if settings.AZURE_CREDENTIAL_VAULT:
if settings.AZURE_CLIENT_SECRET:
# Explicit client secret authentication
azure_vault_client = app.AZURE_CLIENT_FACTORY.create_from_client_secret(
AzureClientSecretCredential(
tenant_id=settings.AZURE_TENANT_ID, # type: ignore
client_id=settings.AZURE_CLIENT_ID, # type: ignore
client_secret=settings.AZURE_CLIENT_SECRET, # type: ignore
)
)
else:
# Workload Identity / DefaultAzureCredential
azure_vault_client = app.AZURE_CLIENT_FACTORY.create_default()
app.AZURE_CREDENTIAL_VAULT_SERVICE = AzureCredentialVaultService(
azure_vault_client,
vault_name=settings.AZURE_CREDENTIAL_VAULT, # type: ignore[arg-type]
)
else:
app.AZURE_CREDENTIAL_VAULT_SERVICE = None
app.CUSTOM_CREDENTIAL_VAULT_SERVICE = (
CustomCredentialVaultService(
CustomCredentialAPIClient(
api_base_url=settings.CUSTOM_CREDENTIAL_API_BASE_URL, # type: ignore
api_token=settings.CUSTOM_CREDENTIAL_API_TOKEN, # type: ignore
)
)
if settings.CUSTOM_CREDENTIAL_API_BASE_URL and settings.CUSTOM_CREDENTIAL_API_TOKEN
else CustomCredentialVaultService() # Create service without client for organization-based configuration
)
app.CREDENTIAL_VAULT_SERVICES = {
CredentialVaultType.BITWARDEN: app.BITWARDEN_CREDENTIAL_VAULT_SERVICE,
CredentialVaultType.AZURE_VAULT: app.AZURE_CREDENTIAL_VAULT_SERVICE,
CredentialVaultType.CUSTOM: app.CUSTOM_CREDENTIAL_VAULT_SERVICE,
}
app.scrape_exclude = None
app.authentication_function = None
app.authenticate_user_function = None
app.setup_api_app = None
app.api_app_startup_event = None
app.api_app_shutdown_event = None
app.agent = ForgeAgent()
return app