From 4ace5fa67acf88f08a58d8f94e91341afa711c92 Mon Sep 17 00:00:00 2001 From: Julep Developers Date: Sun, 22 Sep 2024 17:13:08 +0000 Subject: [PATCH 1/3] fix: Remove unnecessary docker compose dependencies --- agents-api/docker-compose.yml | 3 --- scheduler/docker-compose.yml | 2 -- 2 files changed, 5 deletions(-) diff --git a/agents-api/docker-compose.yml b/agents-api/docker-compose.yml index 84aae7e7c..0770ded61 100644 --- a/agents-api/docker-compose.yml +++ b/agents-api/docker-compose.yml @@ -72,9 +72,6 @@ services: build: context: . dockerfile: Dockerfile.worker - depends_on: - temporal: - condition: service_started develop: watch: diff --git a/scheduler/docker-compose.yml b/scheduler/docker-compose.yml index 090b0d7be..e0f86ec9d 100644 --- a/scheduler/docker-compose.yml +++ b/scheduler/docker-compose.yml @@ -62,8 +62,6 @@ services: image: temporalio/ui:latest profiles: - temporal-ui - depends_on: - - temporal environment: - TEMPORAL_ADDRESS=${TEMPORAL_ADDRESS:-temporal:7233} - TEMPORAL_CORS_ORIGINS=${TEMPORAL_CORS_ORIGINS:-http://localhost:3000} From d633c7712b0d6be50c2a67214cf27e55961a11bb Mon Sep 17 00:00:00 2001 From: Diwank Singh Tomer Date: Sun, 22 Sep 2024 20:00:37 -0400 Subject: [PATCH 2/3] fix: Fix litellm config for voyage-3 Signed-off-by: Diwank Singh Tomer --- llm-proxy/litellm-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llm-proxy/litellm-config.yaml b/llm-proxy/litellm-config.yaml index 91d2a2c09..733cd0ec4 100644 --- a/llm-proxy/litellm-config.yaml +++ b/llm-proxy/litellm-config.yaml @@ -87,7 +87,7 @@ model_list: - model_name: voyage-3 litellm_params: - model: "voyage/voyage-large-2" + model: "voyage/voyage-3" api_key: os.environ/VOYAGE_API_KEY tags: ["paid"] From ecc95ea0e6a36cf1b34e5cd8fff25fa336fe58ad Mon Sep 17 00:00:00 2001 From: Hamada Salhab Date: Mon, 23 Sep 2024 14:20:14 +0300 Subject: [PATCH 3/3] Implement ToolCallStep & Fix transition after PromptStep (#513) > [!IMPORTANT] > Implement `ToolCallStep` and fix transition logic after `PromptStep` in workflow execution. > > - **ToolCallStep Implementation**: > - Implements `tool_call_step()` in `tool_call_step.py` to handle tool calls, including generating a call ID and validating tool names. > - Updates `STEP_TO_ACTIVITY` in `task_execution/__init__.py` to map `ToolCallStep` to `tool_call_step()`. > - **PromptStep Transition Fix**: > - Updates transition logic in `task_execution/__init__.py` to handle tool calls after a `PromptStep`. > - Removes unused code related to tool calls in `PromptStep` handling. > - **State Machine Update**: > - Updates `valid_transitions` in `tasks.py` to allow 'wait' to 'step' transition. > > This description was created by [Ellipsis](https://www.ellipsis.dev?ref=julep-ai%2Fjulep&utm_source=github&utm_medium=referral) for 5ab9e3a59ab8f000d371cdfed07b6a0364c88a21. It will automatically update as commits are pushed. --- .../activities/task_steps/prompt_step.py | 1 - .../activities/task_steps/tool_call_step.py | 45 +++++++++++++++---- .../agents_api/common/protocol/tasks.py | 2 +- .../workflows/task_execution/__init__.py | 36 +++++---------- 4 files changed, 50 insertions(+), 34 deletions(-) diff --git a/agents-api/agents_api/activities/task_steps/prompt_step.py b/agents-api/agents_api/activities/task_steps/prompt_step.py index d04dc99a6..3eecc2b55 100644 --- a/agents-api/agents_api/activities/task_steps/prompt_step.py +++ b/agents-api/agents_api/activities/task_steps/prompt_step.py @@ -22,7 +22,6 @@ async def prompt_step(context: StepContext) -> StepOutcome: context_data, skip_vars=["developer_id"], ) - # Get settings and run llm agent_default_settings: dict = ( context.execution_input.agent.default_settings.model_dump() diff --git a/agents-api/agents_api/activities/task_steps/tool_call_step.py b/agents-api/agents_api/activities/task_steps/tool_call_step.py index 85a119deb..a576bbbeb 100644 --- a/agents-api/agents_api/activities/task_steps/tool_call_step.py +++ b/agents-api/agents_api/activities/task_steps/tool_call_step.py @@ -1,20 +1,49 @@ +import base64 +import secrets + from beartype import beartype from temporalio import activity +from ...activities.task_steps import base_evaluate +from ...autogen.openapi_model import ToolCallStep from ...common.protocol.tasks import ( StepContext, + StepOutcome, ) +def generate_call_id(): + # Generate 18 random bytes (which will result in 24 base64 characters) + random_bytes = secrets.token_bytes(18) + # Encode to base64 and remove padding + base64_string = base64.urlsafe_b64encode(random_bytes).decode("ascii").rstrip("=") + # Add the "call_" prefix + return f"call_{base64_string}" + + @activity.defn @beartype -async def tool_call_step(context: StepContext) -> dict: - raise NotImplementedError() - # assert isinstance(context.current_step, ToolCallStep) +async def tool_call_step(context: StepContext) -> StepOutcome: + assert isinstance(context.current_step, ToolCallStep) + + tool_type, tool_name = context.current_step.tool.split(".") + arguments = await base_evaluate( + context.current_step.arguments, context.model_dump() + ) + + tools = context.execution_input.tools + + assert tool_name in [tool.name for tool in tools], f"Tool {tool_name} not found" + + call_id = generate_call_id() - # context.current_step.tool_id - # context.current_step.arguments - # # get tool by id - # # call tool + tool_call = { + tool_type: { + "arguments": arguments, + "name": tool_name, + }, + "id": call_id, + "type": tool_type, + } - # return {} + return StepOutcome(output=tool_call) diff --git a/agents-api/agents_api/common/protocol/tasks.py b/agents-api/agents_api/common/protocol/tasks.py index 81a04bb4a..e50b5c2ea 100644 --- a/agents-api/agents_api/common/protocol/tasks.py +++ b/agents-api/agents_api/common/protocol/tasks.py @@ -72,7 +72,7 @@ "error": [], "cancelled": [], # Intermediate states - "wait": ["resume", "cancelled", "finish", "finish_branch"], + "wait": ["resume", "step", "cancelled", "finish", "finish_branch"], "resume": [ "wait", "error", diff --git a/agents-api/agents_api/workflows/task_execution/__init__.py b/agents-api/agents_api/workflows/task_execution/__init__.py index 2ff45e55c..d1f13585f 100644 --- a/agents-api/agents_api/workflows/task_execution/__init__.py +++ b/agents-api/agents_api/workflows/task_execution/__init__.py @@ -81,7 +81,7 @@ # Mapping of step types to their corresponding activities STEP_TO_ACTIVITY = { PromptStep: task_steps.prompt_step, - # ToolCallStep: tool_call_step, + ToolCallStep: task_steps.tool_call_step, WaitForInputStep: task_steps.wait_for_input_step, SwitchStep: task_steps.switch_step, LogStep: task_steps.log_step, @@ -389,10 +389,7 @@ async def run( state = PartialTransition(type="resume", output=result) - case PromptStep(), StepOutcome( - output=response - ): # FIXME: if not response.choices[0].tool_calls: - # SCRUM-15 + case PromptStep(), StepOutcome(output=response): workflow.logger.debug(f"Prompt step: Received response: {response}") if response["choices"][0]["finish_reason"] != "tool_calls": workflow.logger.debug("Prompt step: Received response") @@ -421,19 +418,6 @@ async def run( ) state = PartialTransition(output=new_response.output, type="resume") - # case PromptStep(), StepOutcome( - # output=response - # ): # FIXME: if response.choices[0].tool_calls: - # # SCRUM-15 - # workflow.logger.debug("Prompt step: Received response") - # - # ## First, enter a wait-for-input step and ask developer to run the tool calls - # ## Then, continue the workflow with the input received from the developer - # ## This will be a dict with the tool call name as key and the tool call arguments as value - # ## The prompt is run again with the tool call arguments as input - # ## And the result is returned - # ## If model asks for more tool calls, repeat the process - case SetStep(), StepOutcome(output=evaluated_output): workflow.logger.info("Set step: Updating user state") self.update_user_state(evaluated_output) @@ -466,11 +450,15 @@ async def run( workflow.logger.error("ParallelStep not yet implemented") raise ApplicationError("Not implemented") - case ToolCallStep(), _: - # FIXME: Implement ToolCallStep - # SCRUM-16 - workflow.logger.error("ToolCallStep not yet implemented") - raise ApplicationError("Not implemented") + case ToolCallStep(), StepOutcome(output=tool_call): + # Enter a wait-for-input step to ask the developer to run the tool calls + tool_call_response = await workflow.execute_activity( + task_steps.raise_complete_async, + args=[context, tool_call], + schedule_to_close_timeout=timedelta(days=31), + ) + + state = PartialTransition(output=tool_call_response, type="resume") case _: workflow.logger.error( @@ -502,7 +490,7 @@ async def run( # Continue as a child workflow return await continue_as_child( - context, + context.execution_input, start=final_state.next, previous_inputs=previous_inputs + [final_state.output], user_state=self.user_state,