Script - credential / secret integration (#3279)
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
"""remove unique constraints for workflow and script cache_key_value
|
||||||
|
|
||||||
|
Revision ID: 1bba8a38ddc7
|
||||||
|
Revises: f148f36edc09
|
||||||
|
Create Date: 2025-08-23 01:51:56.114060+00:00
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = "1bba8a38ddc7"
|
||||||
|
down_revision: Union[str, None] = "f148f36edc09"
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_constraint(op.f("uc_workflow_permanent_id_cache_key_value"), "workflow_scripts", type_="unique")
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_unique_constraint(
|
||||||
|
op.f("uc_workflow_permanent_id_cache_key_value"),
|
||||||
|
"workflow_scripts",
|
||||||
|
["workflow_permanent_id", "cache_key_value"],
|
||||||
|
postgresql_nulls_not_distinct=False,
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
@@ -24,6 +24,7 @@ import libcst as cst
|
|||||||
import structlog
|
import structlog
|
||||||
from libcst import Attribute, Call, Dict, DictElement, FunctionDef, Name, Param
|
from libcst import Attribute, Call, Dict, DictElement, FunctionDef, Name, Param
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.core.script_generations.constants import SCRIPT_TASK_BLOCKS
|
from skyvern.core.script_generations.constants import SCRIPT_TASK_BLOCKS
|
||||||
from skyvern.core.script_generations.generate_workflow_parameters import (
|
from skyvern.core.script_generations.generate_workflow_parameters import (
|
||||||
generate_workflow_parameters_schema,
|
generate_workflow_parameters_schema,
|
||||||
@@ -102,7 +103,7 @@ def _value(value: Any) -> cst.BaseExpression:
|
|||||||
return cst.SimpleString(repr(str(value)))
|
return cst.SimpleString(repr(str(value)))
|
||||||
|
|
||||||
|
|
||||||
def _prompt_value(prompt_text: str) -> cst.BaseExpression:
|
def _render_value(prompt_text: str) -> cst.BaseExpression:
|
||||||
"""Create a prompt value with template rendering logic if needed."""
|
"""Create a prompt value with template rendering logic if needed."""
|
||||||
if "{{" in prompt_text and "}}" in prompt_text:
|
if "{{" in prompt_text and "}}" in prompt_text:
|
||||||
# Generate code for: render_template(prompt_text)
|
# Generate code for: render_template(prompt_text)
|
||||||
@@ -443,33 +444,7 @@ def _build_generated_model_from_schema(schema_code: str) -> cst.ClassDef | None:
|
|||||||
|
|
||||||
def _build_run_task_statement(block_title: str, block: dict[str, Any]) -> cst.SimpleStatementLine:
|
def _build_run_task_statement(block_title: str, block: dict[str, Any]) -> cst.SimpleStatementLine:
|
||||||
"""Build a skyvern.run_task statement."""
|
"""Build a skyvern.run_task statement."""
|
||||||
args = [
|
args = __build_base_task_statement(block_title, block)
|
||||||
cst.Arg(
|
|
||||||
keyword=cst.Name("prompt"),
|
|
||||||
value=_prompt_value(block.get("navigation_goal", "")),
|
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
|
||||||
indent=True,
|
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
cst.Arg(
|
|
||||||
keyword=cst.Name("max_steps"),
|
|
||||||
value=_value(block.get("max_steps_per_run", 30)),
|
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
|
||||||
indent=True,
|
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
cst.Arg(
|
|
||||||
keyword=cst.Name("cache_key"),
|
|
||||||
value=_value(block_title),
|
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
|
||||||
indent=True,
|
|
||||||
),
|
|
||||||
comma=cst.Comma(),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
call = cst.Call(
|
call = cst.Call(
|
||||||
func=cst.Attribute(value=cst.Name("skyvern"), attr=cst.Name("run_task")),
|
func=cst.Attribute(value=cst.Name("skyvern"), attr=cst.Name("run_task")),
|
||||||
args=args,
|
args=args,
|
||||||
@@ -487,7 +462,7 @@ def _build_download_statement(block_title: str, block: dict[str, Any]) -> cst.Si
|
|||||||
args = [
|
args = [
|
||||||
cst.Arg(
|
cst.Arg(
|
||||||
keyword=cst.Name("prompt"),
|
keyword=cst.Name("prompt"),
|
||||||
value=_prompt_value(block.get("navigation_goal", "")),
|
value=_render_value(block.get("navigation_goal", "")),
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
indent=True,
|
indent=True,
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
@@ -503,7 +478,7 @@ def _build_download_statement(block_title: str, block: dict[str, Any]) -> cst.Si
|
|||||||
),
|
),
|
||||||
cst.Arg(
|
cst.Arg(
|
||||||
keyword=cst.Name("download_suffix"),
|
keyword=cst.Name("download_suffix"),
|
||||||
value=_value(block.get("download_suffix", "")),
|
value=_render_value(block.get("download_suffix", "")),
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
indent=True,
|
indent=True,
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
@@ -536,15 +511,7 @@ def _build_action_statement(block_title: str, block: dict[str, Any]) -> cst.Simp
|
|||||||
args = [
|
args = [
|
||||||
cst.Arg(
|
cst.Arg(
|
||||||
keyword=cst.Name("prompt"),
|
keyword=cst.Name("prompt"),
|
||||||
value=_prompt_value(block.get("navigation_goal", "")),
|
value=_render_value(block.get("navigation_goal", "")),
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
|
||||||
indent=True,
|
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
cst.Arg(
|
|
||||||
keyword=cst.Name("max_steps"),
|
|
||||||
value=_value(block.get("max_steps_per_run", 30)),
|
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
indent=True,
|
indent=True,
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
@@ -574,49 +541,7 @@ def _build_action_statement(block_title: str, block: dict[str, Any]) -> cst.Simp
|
|||||||
|
|
||||||
def _build_login_statement(block_title: str, block: dict[str, Any]) -> cst.SimpleStatementLine:
|
def _build_login_statement(block_title: str, block: dict[str, Any]) -> cst.SimpleStatementLine:
|
||||||
"""Build a skyvern.login statement."""
|
"""Build a skyvern.login statement."""
|
||||||
args = [
|
args = __build_base_task_statement(block_title, block)
|
||||||
cst.Arg(
|
|
||||||
keyword=cst.Name("title"),
|
|
||||||
value=_value(block_title),
|
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
|
||||||
indent=True,
|
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
cst.Arg(
|
|
||||||
keyword=cst.Name("prompt"),
|
|
||||||
value=_prompt_value(block.get("navigation_goal", "")),
|
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
|
||||||
indent=True,
|
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
cst.Arg(
|
|
||||||
keyword=cst.Name("totp_identifier"),
|
|
||||||
value=_value(block.get("totp_identifier", "")),
|
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
|
||||||
indent=True,
|
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
cst.Arg(
|
|
||||||
keyword=cst.Name("webhook_callback_url"),
|
|
||||||
value=_value(block.get("webhook_callback_url", "")),
|
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
|
||||||
indent=True,
|
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
cst.Arg(
|
|
||||||
keyword=cst.Name("cache_key"),
|
|
||||||
value=_value(block_title),
|
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
|
||||||
indent=True,
|
|
||||||
),
|
|
||||||
comma=cst.Comma(),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
call = cst.Call(
|
call = cst.Call(
|
||||||
func=cst.Attribute(value=cst.Name("skyvern"), attr=cst.Name("login")),
|
func=cst.Attribute(value=cst.Name("skyvern"), attr=cst.Name("login")),
|
||||||
args=args,
|
args=args,
|
||||||
@@ -634,7 +559,7 @@ def _build_extract_statement(block_title: str, block: dict[str, Any]) -> cst.Sim
|
|||||||
args = [
|
args = [
|
||||||
cst.Arg(
|
cst.Arg(
|
||||||
keyword=cst.Name("prompt"),
|
keyword=cst.Name("prompt"),
|
||||||
value=_value(block.get("data_extraction_goal", "")),
|
value=_render_value(block.get("data_extraction_goal", "")),
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
indent=True,
|
indent=True,
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
@@ -667,7 +592,7 @@ def _build_navigate_statement(block_title: str, block: dict[str, Any]) -> cst.Si
|
|||||||
args = [
|
args = [
|
||||||
cst.Arg(
|
cst.Arg(
|
||||||
keyword=cst.Name("prompt"),
|
keyword=cst.Name("prompt"),
|
||||||
value=_prompt_value(block.get("navigation_goal", "")),
|
value=_render_value(block.get("navigation_goal", "")),
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
indent=True,
|
indent=True,
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
@@ -683,7 +608,7 @@ def _build_navigate_statement(block_title: str, block: dict[str, Any]) -> cst.Si
|
|||||||
),
|
),
|
||||||
cst.Arg(
|
cst.Arg(
|
||||||
keyword=cst.Name("max_steps"),
|
keyword=cst.Name("max_steps"),
|
||||||
value=_value(block.get("max_steps_per_run", 30)),
|
value=_value(block.get("max_steps_per_run", settings.MAX_STEPS_PER_RUN)),
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
indent=True,
|
indent=True,
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
@@ -773,7 +698,7 @@ def _build_validate_statement(block: dict[str, Any]) -> cst.SimpleStatementLine:
|
|||||||
args = [
|
args = [
|
||||||
cst.Arg(
|
cst.Arg(
|
||||||
keyword=cst.Name("prompt"),
|
keyword=cst.Name("prompt"),
|
||||||
value=_prompt_value(block.get("navigation_goal", "")),
|
value=_render_value(block.get("navigation_goal", "")),
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
indent=True,
|
indent=True,
|
||||||
),
|
),
|
||||||
@@ -823,7 +748,7 @@ def _build_for_loop_statement(block_title: str, block: dict[str, Any]) -> cst.Si
|
|||||||
args = [
|
args = [
|
||||||
cst.Arg(
|
cst.Arg(
|
||||||
keyword=cst.Name("prompt"),
|
keyword=cst.Name("prompt"),
|
||||||
value=_prompt_value(block.get("navigation_goal", "")),
|
value=_render_value(block.get("navigation_goal", "")),
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
indent=True,
|
indent=True,
|
||||||
last_line=cst.SimpleWhitespace(INDENT),
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
@@ -831,7 +756,7 @@ def _build_for_loop_statement(block_title: str, block: dict[str, Any]) -> cst.Si
|
|||||||
),
|
),
|
||||||
cst.Arg(
|
cst.Arg(
|
||||||
keyword=cst.Name("max_steps"),
|
keyword=cst.Name("max_steps"),
|
||||||
value=_value(block.get("max_steps_per_run", 30)),
|
value=_value(block.get("max_steps_per_run", settings.MAX_STEPS_PER_RUN)),
|
||||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
indent=True,
|
indent=True,
|
||||||
),
|
),
|
||||||
@@ -876,6 +801,74 @@ def _build_goto_statement(block: dict[str, Any]) -> cst.SimpleStatementLine:
|
|||||||
return cst.SimpleStatementLine([cst.Expr(cst.Await(call))])
|
return cst.SimpleStatementLine([cst.Expr(cst.Await(call))])
|
||||||
|
|
||||||
|
|
||||||
|
def __build_base_task_statement(block_title: str, block: dict[str, Any]) -> list[cst.Arg]:
|
||||||
|
args = [
|
||||||
|
cst.Arg(
|
||||||
|
keyword=cst.Name("prompt"),
|
||||||
|
value=_render_value(block.get("navigation_goal", "")),
|
||||||
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
|
indent=True,
|
||||||
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
if block.get("url"):
|
||||||
|
args.append(
|
||||||
|
cst.Arg(
|
||||||
|
keyword=cst.Name("url"),
|
||||||
|
value=_render_value(block.get("url", "")),
|
||||||
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
|
indent=True,
|
||||||
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if block.get("max_steps_per_run"):
|
||||||
|
args.append(
|
||||||
|
cst.Arg(
|
||||||
|
keyword=cst.Name("max_steps"),
|
||||||
|
value=_render_value(block.get("max_steps_per_run", settings.MAX_STEPS_PER_RUN)),
|
||||||
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
|
indent=True,
|
||||||
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if block.get("totp_identifier"):
|
||||||
|
args.append(
|
||||||
|
cst.Arg(
|
||||||
|
keyword=cst.Name("totp_identifier"),
|
||||||
|
value=_render_value(block.get("totp_identifier", "")),
|
||||||
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
|
indent=True,
|
||||||
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if block.get("totp_verification_url"):
|
||||||
|
args.append(
|
||||||
|
cst.Arg(
|
||||||
|
keyword=cst.Name("totp_url"),
|
||||||
|
value=_render_value(block.get("totp_verification_url", "")),
|
||||||
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
|
indent=True,
|
||||||
|
last_line=cst.SimpleWhitespace(INDENT),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
args.append(
|
||||||
|
cst.Arg(
|
||||||
|
keyword=cst.Name("cache_key"),
|
||||||
|
value=_value(block_title),
|
||||||
|
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||||
|
indent=True,
|
||||||
|
),
|
||||||
|
comma=cst.Comma(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------- #
|
# --------------------------------------------------------------------- #
|
||||||
# 4. function builders #
|
# 4. function builders #
|
||||||
# --------------------------------------------------------------------- #
|
# --------------------------------------------------------------------- #
|
||||||
|
|||||||
@@ -4,11 +4,26 @@ from pydantic import BaseModel
|
|||||||
|
|
||||||
from skyvern.core.script_generations.script_run_context_manager import script_run_context_manager
|
from skyvern.core.script_generations.script_run_context_manager import script_run_context_manager
|
||||||
from skyvern.core.script_generations.skyvern_page import RunContext, SkyvernPage
|
from skyvern.core.script_generations.skyvern_page import RunContext, SkyvernPage
|
||||||
|
from skyvern.forge import app
|
||||||
|
from skyvern.forge.sdk.core import skyvern_context
|
||||||
|
from skyvern.forge.sdk.workflow.models.parameter import WorkflowParameterType
|
||||||
|
|
||||||
|
|
||||||
async def setup(
|
async def setup(
|
||||||
parameters: dict[str, Any], generated_parameter_cls: type[BaseModel] | None = None
|
parameters: dict[str, Any], generated_parameter_cls: type[BaseModel] | None = None
|
||||||
) -> tuple[SkyvernPage, RunContext]:
|
) -> tuple[SkyvernPage, RunContext]:
|
||||||
|
# transform any secrets/credential parameters. For example, if there's only one credential in the parameters: {"cred_12345": "cred_12345"},
|
||||||
|
# it should be transformed to {"cred_12345": {"username": "secret_5fBoa_username", "password": "secret_5fBoa_password"}}
|
||||||
|
# context comes from app.WORKFLOW_CONTEXT_MANAGER.get_workflow_run_context(workflow_run_id)
|
||||||
|
context = skyvern_context.current()
|
||||||
|
if context and context.organization_id and context.workflow_run_id:
|
||||||
|
workflow_run_context = app.WORKFLOW_CONTEXT_MANAGER.get_workflow_run_context(context.workflow_run_id)
|
||||||
|
parameters_in_workflow_context = workflow_run_context.parameters
|
||||||
|
for key in parameters:
|
||||||
|
if key in parameters_in_workflow_context:
|
||||||
|
parameter = parameters_in_workflow_context[key]
|
||||||
|
if parameter.workflow_parameter_type == WorkflowParameterType.CREDENTIAL_ID:
|
||||||
|
parameters[key] = workflow_run_context.values[key]
|
||||||
skyvern_page = await SkyvernPage.create()
|
skyvern_page = await SkyvernPage.create()
|
||||||
run_context = RunContext(
|
run_context = RunContext(
|
||||||
parameters=parameters,
|
parameters=parameters,
|
||||||
|
|||||||
@@ -329,6 +329,11 @@ class SkyvernPage:
|
|||||||
If the prompt generation or parsing fails for any reason we fall back to
|
If the prompt generation or parsing fails for any reason we fall back to
|
||||||
inputting the originally supplied ``text``.
|
inputting the originally supplied ``text``.
|
||||||
"""
|
"""
|
||||||
|
# format the text with the actual value of the parameter if it's a secret when running a workflow
|
||||||
|
context = skyvern_context.current()
|
||||||
|
if context and context.workflow_run_id:
|
||||||
|
text = await _get_actual_value_of_parameter_if_secret(context.workflow_run_id, text)
|
||||||
|
|
||||||
locator = self.page.locator(f"xpath={xpath}")
|
locator = self.page.locator(f"xpath={xpath}")
|
||||||
await handler_utils.input_sequentially(locator, text, timeout=timeout)
|
await handler_utils.input_sequentially(locator, text, timeout=timeout)
|
||||||
|
|
||||||
@@ -500,3 +505,16 @@ class RunContext:
|
|||||||
self.page = page
|
self.page = page
|
||||||
self.trace: list[ActionCall] = []
|
self.trace: list[ActionCall] = []
|
||||||
self.prompt: str | None = None
|
self.prompt: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
async def _get_actual_value_of_parameter_if_secret(workflow_run_id: str, parameter: str) -> Any:
|
||||||
|
"""
|
||||||
|
Get the actual value of a parameter if it's a secret. If it's not a secret, return the parameter value as is.
|
||||||
|
|
||||||
|
Just return the parameter value if the task isn't a workflow's task.
|
||||||
|
|
||||||
|
This is only used for InputTextAction, UploadFileAction, and ClickAction (if it has a file_url).
|
||||||
|
"""
|
||||||
|
workflow_run_context = app.WORKFLOW_CONTEXT_MANAGER.get_workflow_run_context(workflow_run_id)
|
||||||
|
secret_value = workflow_run_context.get_original_secret_value_or_none(parameter)
|
||||||
|
return secret_value if secret_value is not None else parameter
|
||||||
|
|||||||
@@ -3930,7 +3930,7 @@ class AgentDB:
|
|||||||
.where(WorkflowScriptModel.deleted_at.is_(None))
|
.where(WorkflowScriptModel.deleted_at.is_(None))
|
||||||
)
|
)
|
||||||
|
|
||||||
if cache_key:
|
if cache_key is not None:
|
||||||
ws_script_ids_subquery = ws_script_ids_subquery.where(WorkflowScriptModel.cache_key == cache_key)
|
ws_script_ids_subquery = ws_script_ids_subquery.where(WorkflowScriptModel.cache_key == cache_key)
|
||||||
|
|
||||||
# Latest version per script_id within the org and not deleted
|
# Latest version per script_id within the org and not deleted
|
||||||
|
|||||||
@@ -840,11 +840,6 @@ class ScriptFileModel(Base):
|
|||||||
class WorkflowScriptModel(Base):
|
class WorkflowScriptModel(Base):
|
||||||
__tablename__ = "workflow_scripts"
|
__tablename__ = "workflow_scripts"
|
||||||
__table_args__ = (
|
__table_args__ = (
|
||||||
UniqueConstraint(
|
|
||||||
"workflow_permanent_id",
|
|
||||||
"cache_key_value",
|
|
||||||
name="uc_workflow_permanent_id_cache_key_value",
|
|
||||||
),
|
|
||||||
Index("idx_workflow_scripts_org_created", "organization_id", "created_at"),
|
Index("idx_workflow_scripts_org_created", "organization_id", "created_at"),
|
||||||
Index("idx_workflow_scripts_workflow_permanent_id", "workflow_permanent_id"),
|
Index("idx_workflow_scripts_workflow_permanent_id", "workflow_permanent_id"),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -617,6 +617,10 @@ class WorkflowService:
|
|||||||
WorkflowRunStatus.timed_out,
|
WorkflowRunStatus.timed_out,
|
||||||
):
|
):
|
||||||
workflow_run = await self.mark_workflow_run_as_completed(workflow_run_id=workflow_run.workflow_run_id)
|
workflow_run = await self.mark_workflow_run_as_completed(workflow_run_id=workflow_run.workflow_run_id)
|
||||||
|
# generate script for workflow if the workflow.generate_script is True AND there's no script cached for the workflow
|
||||||
|
# only generate script if the workflow run is completed
|
||||||
|
if workflow.generate_script:
|
||||||
|
await self.generate_script_for_workflow(workflow=workflow, workflow_run=workflow_run)
|
||||||
else:
|
else:
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"Workflow run is already timed_out, canceled, failed, or terminated, not marking as completed",
|
"Workflow run is already timed_out, canceled, failed, or terminated, not marking as completed",
|
||||||
@@ -642,16 +646,6 @@ class WorkflowService:
|
|||||||
organization_id=organization_id,
|
organization_id=organization_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
# generate script for workflow if the workflow.generate_script is True AND there's no script cached for the workflow
|
|
||||||
if workflow.generate_script:
|
|
||||||
LOG.info(
|
|
||||||
"Generating script for workflow",
|
|
||||||
workflow_run_id=workflow_run_id,
|
|
||||||
workflow_id=workflow.workflow_id,
|
|
||||||
workflow_name=workflow.title,
|
|
||||||
)
|
|
||||||
await self.generate_script_for_workflow(workflow=workflow, workflow_run=workflow_run)
|
|
||||||
|
|
||||||
return workflow_run
|
return workflow_run
|
||||||
|
|
||||||
async def create_workflow(
|
async def create_workflow(
|
||||||
@@ -2349,6 +2343,7 @@ class WorkflowService:
|
|||||||
"""
|
"""
|
||||||
Execute the related workflow script instead of running the workflow blocks.
|
Execute the related workflow script instead of running the workflow blocks.
|
||||||
"""
|
"""
|
||||||
|
LOG.info("Start to execute workflow script", workflow_run_id=workflow_run.workflow_run_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Render the cache_key_value to find the right script
|
# Render the cache_key_value to find the right script
|
||||||
@@ -2400,7 +2395,7 @@ class WorkflowService:
|
|||||||
workflow_run: WorkflowRun,
|
workflow_run: WorkflowRun,
|
||||||
) -> None:
|
) -> None:
|
||||||
cache_key = workflow.cache_key
|
cache_key = workflow.cache_key
|
||||||
rendered_cache_key_value = "default"
|
rendered_cache_key_value = ""
|
||||||
# 1) Build cache_key_value from workflow run parameters via jinja
|
# 1) Build cache_key_value from workflow run parameters via jinja
|
||||||
if cache_key:
|
if cache_key:
|
||||||
parameter_tuples = await app.DATABASE.get_workflow_run_parameters(
|
parameter_tuples = await app.DATABASE.get_workflow_run_parameters(
|
||||||
|
|||||||
@@ -250,11 +250,11 @@ async def _create_workflow_block_run_and_task(
|
|||||||
Create a workflow block run and optionally a task if workflow_run_id is available in context.
|
Create a workflow block run and optionally a task if workflow_run_id is available in context.
|
||||||
Returns (workflow_run_block_id, task_id) tuple.
|
Returns (workflow_run_block_id, task_id) tuple.
|
||||||
"""
|
"""
|
||||||
context = skyvern_context.ensure_context()
|
context = skyvern_context.current()
|
||||||
|
if not context or not context.workflow_run_id or not context.organization_id:
|
||||||
|
return None, None
|
||||||
workflow_run_id = context.workflow_run_id
|
workflow_run_id = context.workflow_run_id
|
||||||
organization_id = context.organization_id
|
organization_id = context.organization_id
|
||||||
if not context or not workflow_run_id or not organization_id:
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Create workflow run block with appropriate parameters based on block type
|
# Create workflow run block with appropriate parameters based on block type
|
||||||
|
|||||||
Reference in New Issue
Block a user