From 4992615da5d702956fc9dd8f29d90cf1f4bad96f Mon Sep 17 00:00:00 2001 From: Diwank Singh Tomer Date: Fri, 4 Oct 2024 05:31:42 +0530 Subject: [PATCH 1/5] Update lint-and-format.yml --- .github/workflows/lint-and-format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-and-format.yml b/.github/workflows/lint-and-format.yml index 65e4983c4..ab74c7e9b 100644 --- a/.github/workflows/lint-and-format.yml +++ b/.github/workflows/lint-and-format.yml @@ -37,7 +37,7 @@ jobs: uses: actions/cache@v4 with: path: agents-api/.pytype - key: ${{ runner.os }}-agents-api-pytype-${{ hashFiles('agents-api/**/*.py') }} + key: ${{ runner.os }}-agents-api-pytype- restore-keys: | ${{ runner.os }}-agents-api-pytype- From 9c38da1a42c29da7218dac9696b1d67d9ced2538 Mon Sep 17 00:00:00 2001 From: Vivek Gurudutt K <127002789+VivekGuruduttK28@users.noreply.github.com> Date: Fri, 4 Oct 2024 05:40:54 +0530 Subject: [PATCH 2/5] Enhanced the error messages (#575) This PR is to fix the issue mentioned in #572 I have made the required changes in the files create_agent.py, create_or_update_agent.py and delete_agent.py. I have added descriptions to QueryException, ValidationError and TypeError. ---- > [!IMPORTANT] > Enhanced error messages for exceptions in agent-related files to provide detailed guidance on potential issues. > > - **Error Messages**: > - Enhanced error messages for `QueryException`, `ValidationError`, and `TypeError` in `create_agent.py`, `create_or_update_agent.py`, and `delete_agent.py`. > - `QueryException`: Now includes a detailed message about potential causes related to database query failures. > - `ValidationError`: Provides guidance on checking input data for missing or incorrect fields. > - `TypeError`: Describes type mismatch issues and suggests reviewing input data types. > > This description was created by [Ellipsis](https://www.ellipsis.dev?ref=julep-ai%2Fjulep&utm_source=github&utm_medium=referral) for 049d7eea196b74158e4fc4d83049656c7e7fa12e. It will automatically update as commits are pushed. Co-authored-by: Diwank Singh Tomer --- agents-api/agents_api/models/agent/create_agent.py | 6 +++--- .../agents_api/models/agent/create_or_update_agent.py | 6 +++--- agents-api/agents_api/models/agent/delete_agent.py | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/agents-api/agents_api/models/agent/create_agent.py b/agents-api/agents_api/models/agent/create_agent.py index 73be4ec77..546d0d441 100644 --- a/agents-api/agents_api/models/agent/create_agent.py +++ b/agents-api/agents_api/models/agent/create_agent.py @@ -32,9 +32,9 @@ in str(e): lambda *_: HTTPException( detail="developer not found", status_code=403 ), - QueryException: partialclass(HTTPException, status_code=400), - ValidationError: partialclass(HTTPException, status_code=400), - TypeError: partialclass(HTTPException, status_code=400), + QueryException: partialclass(HTTPException, status_code=400, detail="A database query failed to return the expected results. This might occur if the requested resource doesn't exist or your query parameters are incorrect."), + ValidationError: partialclass(HTTPException, status_code=400, detail="Input validation failed. Please check the provided data for missing or incorrect fields, and ensure it matches the required format."), + TypeError: partialclass(HTTPException, status_code=400, detail="A type mismatch occurred. This likely means the data provided is of an incorrect type (e.g., string instead of integer). Please review the input and try again."), } ) @wrap_in_class( diff --git a/agents-api/agents_api/models/agent/create_or_update_agent.py b/agents-api/agents_api/models/agent/create_or_update_agent.py index 156c8ae61..17e01fccb 100644 --- a/agents-api/agents_api/models/agent/create_or_update_agent.py +++ b/agents-api/agents_api/models/agent/create_or_update_agent.py @@ -27,9 +27,9 @@ @rewrap_exceptions( { - QueryException: partialclass(HTTPException, status_code=400), - ValidationError: partialclass(HTTPException, status_code=400), - TypeError: partialclass(HTTPException, status_code=400), + QueryException: partialclass(HTTPException, status_code=400,detail="A database query failed to return the expected results. This might occur if the requested resource doesn't exist or your query parameters are incorrect."), + ValidationError: partialclass(HTTPException, status_code=400,detail="Input validation failed. Please check the provided data for missing or incorrect fields, and ensure it matches the required format."), + TypeError: partialclass(HTTPException, status_code=400,detail="A type mismatch occurred. This likely means the data provided is of an incorrect type (e.g., string instead of integer). Please review the input and try again."), } ) @wrap_in_class( diff --git a/agents-api/agents_api/models/agent/delete_agent.py b/agents-api/agents_api/models/agent/delete_agent.py index 926007bdf..cb6b16718 100644 --- a/agents-api/agents_api/models/agent/delete_agent.py +++ b/agents-api/agents_api/models/agent/delete_agent.py @@ -32,9 +32,9 @@ in e.resp["display"]: lambda *_: HTTPException( detail="developer not found or doesnt own resource", status_code=404 ), - QueryException: partialclass(HTTPException, status_code=400), - ValidationError: partialclass(HTTPException, status_code=400), - TypeError: partialclass(HTTPException, status_code=400), + QueryException: partialclass(HTTPException, status_code=400,detail="A database query failed to return the expected results. This might occur if the requested resource doesn't exist or your query parameters are incorrect."), + ValidationError: partialclass(HTTPException, status_code=400,detail="Input validation failed. Please check the provided data for missing or incorrect fields, and ensure it matches the required format."), + TypeError: partialclass(HTTPException, status_code=400,detail="A type mismatch occurred. This likely means the data provided is of an incorrect type (e.g., string instead of integer). Please review the input and try again."), } ) @wrap_in_class( From 51f5e65cf7095c09219dbe60080898b530f36dac Mon Sep 17 00:00:00 2001 From: Diwank Singh Tomer Date: Thu, 3 Oct 2024 20:11:31 -0400 Subject: [PATCH 3/5] fix(agents-api): Remove unnecessary 'type' property from tool type definition (#574) Signed-off-by: Diwank Singh Tomer ---- > [!IMPORTANT] > Removed 'type' property from tool classes and added computed 'type' property using a function in `Tools.py`, `openapi_model.py`, and `tasks.py`. > > - **Behavior**: > - Removed `type` property from `CreateToolRequest`, `NamedToolChoice`, `PatchToolRequest`, `Tool`, and `UpdateToolRequest` in `Tools.py`. > - Added computed `type` property to `TaskTool`, `Tool`, `UpdateToolRequest`, and `PatchToolRequest` in `openapi_model.py`. > - Updated `task_to_spec()` in `tasks.py` to use computed `type` property. > - **Misc**: > - Removed `type` property from `Tool` and `NamedToolChoice` in `models.tsp`. > > This description was created by [Ellipsis](https://www.ellipsis.dev?ref=julep-ai%2Fjulep&utm_source=github&utm_medium=referral) for 289e87eff9a220b2c4430959f989cca471e36cf9. It will automatically update as commits are pushed. Signed-off-by: Diwank Singh Tomer --- agents-api/agents_api/autogen/Tools.py | 31 ------ .../agents_api/autogen/openapi_model.py | 97 +++++-------------- .../agents_api/common/protocol/tasks.py | 27 ++++-- typespec/tools/models.tsp | 14 --- 4 files changed, 40 insertions(+), 129 deletions(-) diff --git a/agents-api/agents_api/autogen/Tools.py b/agents-api/agents_api/autogen/Tools.py index c2d4199a2..8227e5759 100644 --- a/agents-api/agents_api/autogen/Tools.py +++ b/agents-api/agents_api/autogen/Tools.py @@ -33,10 +33,6 @@ class CreateToolRequest(BaseModel): model_config = ConfigDict( populate_by_name=True, ) - type: Literal["function", "integration", "system", "api_call"] = "function" - """ - Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now) - """ name: Annotated[str, Field(max_length=40, pattern="^[^\\W0-9]\\w*$")] """ Name of the tool (must be unique for this agent and a valid python identifier string ) @@ -168,10 +164,6 @@ class NamedToolChoice(BaseModel): model_config = ConfigDict( populate_by_name=True, ) - type: Literal["function", "integration", "system", "api_call"] - """ - Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now) - """ function: FunctionCallOption | None = None @@ -183,10 +175,6 @@ class PatchToolRequest(BaseModel): model_config = ConfigDict( populate_by_name=True, ) - type: Literal["function", "integration", "system", "api_call"] = "function" - """ - Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now) - """ name: Annotated[str | None, Field(None, max_length=40, pattern="^[^\\W0-9]\\w*$")] """ Name of the tool (must be unique for this agent and a valid python identifier string ) @@ -247,10 +235,6 @@ class Tool(BaseModel): model_config = ConfigDict( populate_by_name=True, ) - type: Literal["function", "integration", "system", "api_call"] = "function" - """ - Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now) - """ name: Annotated[str, Field(max_length=40, pattern="^[^\\W0-9]\\w*$")] """ Name of the tool (must be unique for this agent and a valid python identifier string ) @@ -291,10 +275,6 @@ class UpdateToolRequest(BaseModel): model_config = ConfigDict( populate_by_name=True, ) - type: Literal["function", "integration", "system", "api_call"] = "function" - """ - Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now) - """ name: Annotated[str, Field(max_length=40, pattern="^[^\\W0-9]\\w*$")] """ Name of the tool (must be unique for this agent and a valid python identifier string ) @@ -316,14 +296,3 @@ class ChosenFunctionCall(ChosenToolCall): """ The function to call """ - - -class NamedFunctionChoice(NamedToolChoice): - model_config = ConfigDict( - populate_by_name=True, - ) - type: Literal["function"] = "function" - function: FunctionCallOption - """ - The function to call - """ diff --git a/agents-api/agents_api/autogen/openapi_model.py b/agents-api/agents_api/autogen/openapi_model.py index bff2221eb..0d9390816 100644 --- a/agents-api/agents_api/autogen/openapi_model.py +++ b/agents-api/agents_api/autogen/openapi_model.py @@ -77,88 +77,35 @@ class InputChatMLMessage(Message): pass -# Custom types (not generated correctly) -# -------------------------------------- - -ChatMLContent = ( - list[ChatMLTextContentPart | ChatMLImageContentPart] - | Tool - | ChosenToolCall - | str - | ToolResponse - | list[ - list[ChatMLTextContentPart | ChatMLImageContentPart] - | Tool - | ChosenToolCall - | str - | ToolResponse - ] -) - -# Extract ChatMLRole -ChatMLRole = BaseEntry.model_fields["role"].annotation - -# Extract ChatMLSource -ChatMLSource = BaseEntry.model_fields["source"].annotation - -# Extract ExecutionStatus -ExecutionStatus = Execution.model_fields["status"].annotation - -# Extract TransitionType -TransitionType = Transition.model_fields["type"].annotation - -# Assertions to ensure consistency (optional, but recommended for runtime checks) -assert ChatMLRole == BaseEntry.model_fields["role"].annotation -assert ChatMLSource == BaseEntry.model_fields["source"].annotation -assert ExecutionStatus == Execution.model_fields["status"].annotation -assert TransitionType == Transition.model_fields["type"].annotation - - -# Create models -# ------------- +# Patches +# ------- -class CreateTransitionRequest(Transition): - # The following fields are optional in this +def type_property(self: BaseModel) -> str: + return ( + "function" + if self.function + else "integration" + if self.integration + else "system" + if self.system + else "api_call" + if self.api_call + else None + ) - id: UUID | None = None - execution_id: UUID | None = None - created_at: AwareDatetime | None = None - updated_at: AwareDatetime | None = None - metadata: dict[str, Any] | None = None - task_token: str | None = None +# Patch original Tool class to add 'type' property +TaskTool.type = computed_field(property(type_property)) -class CreateEntryRequest(BaseEntry): - timestamp: Annotated[ - float, Field(ge=0.0, default_factory=lambda: utcnow().timestamp()) - ] +# Patch original Tool class to add 'type' property +Tool.type = computed_field(property(type_property)) - @classmethod - def from_model_input( - cls: Type[Self], - model: str, - *, - role: ChatMLRole, - content: ChatMLContent, - name: str | None = None, - source: ChatMLSource, - **kwargs: dict, - ) -> Self: - tokenizer: dict = select_tokenizer(model=model) - token_count = token_counter( - model=model, messages=[{"role": role, "content": content, "name": name}] - ) +# Patch original UpdateToolRequest class to add 'type' property +UpdateToolRequest.type = computed_field(property(type_property)) - return cls( - role=role, - content=content, - name=name, - source=source, - tokenizer=tokenizer["type"], - token_count=token_count, - **kwargs, - ) +# Patch original PatchToolRequest class to add 'type' property +PatchToolRequest.type = computed_field(property(type_property)) # Patch Task Workflow Steps diff --git a/agents-api/agents_api/common/protocol/tasks.py b/agents-api/agents_api/common/protocol/tasks.py index 6892d7098..bbb5c28d3 100644 --- a/agents-api/agents_api/common/protocol/tasks.py +++ b/agents-api/agents_api/common/protocol/tasks.py @@ -218,19 +218,28 @@ def task_to_spec( task: Task | CreateTaskRequest | UpdateTaskRequest | PatchTaskRequest, **model_opts ) -> TaskSpecDef | PartialTaskSpecDef: task_data = task.model_dump(**model_opts) - main = task_data.pop("main") - workflows = [Workflow(name="main", steps=main)] + if "tools" in task_data: + del task_data["tools"] - for k in list(task_data.keys()): - if k in TaskSpec.model_fields.keys(): - continue + tools = [] + for tool in task.tools: + tool_spec = getattr(tool, tool.type) - steps = task_data.pop(k) - workflows.append(Workflow(name=k, steps=steps)) + tools.append( + TaskToolDef( + type=tool.type, + spec=tool_spec.model_dump(), + **tool.model_dump(exclude={"type"}), + ) + ) - tools = task_data.pop("tools", []) - tools = [TaskToolDef(spec=tool.pop(tool["type"]), **tool) for tool in tools] + workflows = [Workflow(name="main", steps=task_data.pop("main"))] + + for key, steps in list(task_data.items()): + if key not in TaskSpec.model_fields: + workflows.append(Workflow(name=key, steps=steps)) + del task_data[key] cls = PartialTaskSpecDef if isinstance(task, PatchTaskRequest) else TaskSpecDef diff --git a/typespec/tools/models.tsp b/typespec/tools/models.tsp index be0fb4f68..8a8cead44 100644 --- a/typespec/tools/models.tsp +++ b/typespec/tools/models.tsp @@ -74,9 +74,6 @@ model SystemDef { // TODO: We should use this model for all tools, not just functions and discriminate on the type model Tool { - /** Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now) */ - type: ToolType = ToolType.function; - /** Name of the tool (must be unique for this agent and a valid python identifier string )*/ name: validPythonIdentifier; @@ -95,24 +92,13 @@ model FunctionCallOption { name: string; } -@discriminator("type") model NamedToolChoice { - /** Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now) */ - type: ToolType; - function?: FunctionCallOption; integration?: never; // TODO: Implement system?: never; // TODO: Implement api_call?: never; // TODO: Implement } -model NamedFunctionChoice extends NamedToolChoice { - type: ToolType.function; - - /** The function to call */ - function: FunctionCallOption; -} - model ToolResponse { @key id: uuid; From 06813fbe4afde299420d6d285fc4ee3b4d9a6dbd Mon Sep 17 00:00:00 2001 From: JeevaRamanathan <64531160+JeevaRamanathan@users.noreply.github.com> Date: Fri, 4 Oct 2024 05:42:58 +0530 Subject: [PATCH 4/5] Enhanced error message in create, delete agent (#572) Related to #568 Enhanced HTTPException in `create_agent.py` and `delete_agent.py`. As this issue states, we aim to improve error messages throughout the agents-api. I believe this issue can accommodate multiple pull requests. Your suggestions are highly appreciated. ---- > [!IMPORTANT] > Enhanced error messages in `create_agent.py` and `delete_agent.py` for better clarity in `HTTPException` details. > > - **Error Messages**: > - In `create_agent.py`, updated `HTTPException` detail to "Developer not found. Please ensure the provided auth token (which refers to your developer_id) is valid and the developer has the necessary permissions to create an agent." > - In `delete_agent.py`, updated `HTTPException` detail to "The specified developer does not own the requested resource. Please verify the ownership or check if the developer ID is correct." > > This description was created by [Ellipsis](https://www.ellipsis.dev?ref=julep-ai%2Fjulep&utm_source=github&utm_medium=referral) for a085d4193ec0c36ba407f340c77e81834419dd69. It will automatically update as commits are pushed. Co-authored-by: Diwank Singh Tomer --- agents-api/agents_api/models/agent/create_agent.py | 3 ++- agents-api/agents_api/models/agent/delete_agent.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/agents-api/agents_api/models/agent/create_agent.py b/agents-api/agents_api/models/agent/create_agent.py index 546d0d441..c1451bb30 100644 --- a/agents-api/agents_api/models/agent/create_agent.py +++ b/agents-api/agents_api/models/agent/create_agent.py @@ -30,7 +30,8 @@ lambda e: isinstance(e, QueryException) and "asserted to return some results, but returned none" in str(e): lambda *_: HTTPException( - detail="developer not found", status_code=403 + detail="Developer not found. Please ensure the provided auth token (which refers to your developer_id) is valid and the developer has the necessary permissions to create an agent.", + status_code=403 ), QueryException: partialclass(HTTPException, status_code=400, detail="A database query failed to return the expected results. This might occur if the requested resource doesn't exist or your query parameters are incorrect."), ValidationError: partialclass(HTTPException, status_code=400, detail="Input validation failed. Please check the provided data for missing or incorrect fields, and ensure it matches the required format."), diff --git a/agents-api/agents_api/models/agent/delete_agent.py b/agents-api/agents_api/models/agent/delete_agent.py index cb6b16718..d8f710481 100644 --- a/agents-api/agents_api/models/agent/delete_agent.py +++ b/agents-api/agents_api/models/agent/delete_agent.py @@ -30,7 +30,8 @@ lambda e: isinstance(e, QueryException) and "Developer does not own resource" in e.resp["display"]: lambda *_: HTTPException( - detail="developer not found or doesnt own resource", status_code=404 + detail="The specified developer does not own the requested resource. Please verify the ownership or check if the developer ID is correct.", + status_code=404 ), QueryException: partialclass(HTTPException, status_code=400,detail="A database query failed to return the expected results. This might occur if the requested resource doesn't exist or your query parameters are incorrect."), ValidationError: partialclass(HTTPException, status_code=400,detail="Input validation failed. Please check the provided data for missing or incorrect fields, and ensure it matches the required format."), From c5ea3ba75e9e1ef86efee81c093f46565e98b00b Mon Sep 17 00:00:00 2001 From: Diwank Singh Tomer Date: Thu, 3 Oct 2024 20:38:48 -0400 Subject: [PATCH 5/5] feat(agents-api): Naive speed improvement to cozo queries by adding limit=1 to all relevant queries (#580) Signed-off-by: Diwank Singh Tomer ---- > [!IMPORTANT] > Improve CozoDB query performance by adding `:limit 1` to relevant queries and restructure CI/CD workflows for agents-api. > > - **Performance Improvement**: > - Add `:limit 1` to CozoDB queries in `get_agent.py`, `get_cached_response.py`, and `prepare_chat_context.py` among others to improve query performance. > - **CI/CD Workflow**: > - Rename `lint-and-format.yml` to `lint-agents-api-pr.yml` and remove typecheck and test steps. > - Add `test-agents-api-pr.yml` for running tests on pull requests. > - Add `typecheck-agents-api-pr.yml` for type-checking on pull requests. > > This description was created by [Ellipsis](https://www.ellipsis.dev?ref=julep-ai%2Fjulep&utm_source=github&utm_medium=referral) for 4cd6bb0379e5afe3fb9941a338a1d7ab89f8ca0d. It will automatically update as commits are pushed. --------- Signed-off-by: Diwank Singh Tomer --- ...-and-format.yml => lint-agents-api-pr.yml} | 18 ------ .github/workflows/test-agents-api-pr.yml | 48 ++++++++++++++++ .github/workflows/typecheck-agents-api-pr.yml | 56 +++++++++++++++++++ .../agents_api/models/agent/get_agent.py | 2 + .../models/chat/get_cached_response.py | 1 + .../models/chat/prepare_chat_context.py | 2 + .../models/developer/get_developer.py | 2 + .../agents_api/models/docs/embed_snippets.py | 1 + agents-api/agents_api/models/docs/get_doc.py | 2 + .../agents_api/models/entry/get_history.py | 4 +- .../execution/create_execution_transition.py | 2 + .../execution/get_execution_transition.py | 4 +- .../execution/get_paused_execution_token.py | 1 + .../execution/get_temporal_workflow_data.py | 2 + .../models/execution/lookup_temporal_data.py | 2 + .../execution/prepare_execution_input.py | 2 + .../models/execution/update_execution.py | 2 + .../agents_api/models/session/get_session.py | 5 +- .../models/session/prepare_session_data.py | 2 + .../agents_api/models/tools/create_tools.py | 1 + .../agents_api/models/tools/get_tool.py | 2 + .../tools/get_tool_args_from_metadata.py | 4 ++ agents-api/agents_api/models/user/get_user.py | 5 +- agents-api/agents_api/models/utils.py | 4 ++ 24 files changed, 152 insertions(+), 22 deletions(-) rename .github/workflows/{lint-and-format.yml => lint-agents-api-pr.yml} (76%) create mode 100644 .github/workflows/test-agents-api-pr.yml create mode 100644 .github/workflows/typecheck-agents-api-pr.yml diff --git a/.github/workflows/lint-and-format.yml b/.github/workflows/lint-agents-api-pr.yml similarity index 76% rename from .github/workflows/lint-and-format.yml rename to .github/workflows/lint-agents-api-pr.yml index ab74c7e9b..90fdd0a4b 100644 --- a/.github/workflows/lint-and-format.yml +++ b/.github/workflows/lint-agents-api-pr.yml @@ -33,35 +33,17 @@ jobs: restore-keys: | ${{ runner.os }}-agents-api-poetry- - - name: Cache pytype - uses: actions/cache@v4 - with: - path: agents-api/.pytype - key: ${{ runner.os }}-agents-api-pytype- - restore-keys: | - ${{ runner.os }}-agents-api-pytype- - - name: Install dependencies run: | cd agents-api poetry install - - name: Typecheck - run: | - cd agents-api - poetry run poe typecheck - - name: Lint and format run: | cd agents-api poetry run poe format poetry run poe lint - - name: Run tests - run: | - cd agents-api - poetry run poe test - - uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: "refactor: Lint agents-api (CI)" diff --git a/.github/workflows/test-agents-api-pr.yml b/.github/workflows/test-agents-api-pr.yml new file mode 100644 index 000000000..b0f815634 --- /dev/null +++ b/.github/workflows/test-agents-api-pr.yml @@ -0,0 +1,48 @@ +name: Test agents-api +run-name: ${{ github.actor }} is testing the code + +# TODO: Fix CI github actions +# SCRUM-26 + +on: [pull_request] + +jobs: + Test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install and configure Poetry + uses: snok/install-poetry@v1 + + - name: Configure Poetry to use .venv + run: | + cd agents-api + poetry config virtualenvs.in-project true + + - name: Cache Poetry virtualenv + uses: actions/cache@v4 + with: + path: agents-api/.venv + key: ${{ runner.os }}-agents-api-poetry-${{ hashFiles('agents-api/poetry.lock') }} + restore-keys: | + ${{ runner.os }}-agents-api-poetry- + + - name: Install dependencies + run: | + cd agents-api + poetry install + + - name: Run tests + run: | + cd agents-api + poetry run poe test --fail-limit 1 + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} diff --git a/.github/workflows/typecheck-agents-api-pr.yml b/.github/workflows/typecheck-agents-api-pr.yml new file mode 100644 index 000000000..513390883 --- /dev/null +++ b/.github/workflows/typecheck-agents-api-pr.yml @@ -0,0 +1,56 @@ +name: Typecheck agents-api +run-name: ${{ github.actor }} is typechecking the code + +# TODO: Fix CI github actions +# SCRUM-26 + +on: [pull_request] + +jobs: + Typecheck: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install and configure Poetry + uses: snok/install-poetry@v1 + + - name: Configure Poetry to use .venv + run: | + cd agents-api + poetry config virtualenvs.in-project true + + - name: Cache Poetry virtualenv + uses: actions/cache@v4 + with: + path: agents-api/.venv + key: ${{ runner.os }}-agents-api-poetry-${{ hashFiles('agents-api/poetry.lock') }} + restore-keys: | + ${{ runner.os }}-agents-api-poetry- + + - name: Cache pytype + uses: actions/cache@v4 + with: + path: agents-api/.pytype + key: ${{ runner.os }}-agents-api-pytype-${{ github.base_ref }} + restore-keys: | + ${{ runner.os }}-agents-api-pytype- + + - name: Install dependencies + run: | + cd agents-api + poetry install + + - name: Typecheck + run: | + cd agents-api + poetry run poe typecheck + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} diff --git a/agents-api/agents_api/models/agent/get_agent.py b/agents-api/agents_api/models/agent/get_agent.py index 956fa46a5..f8127751a 100644 --- a/agents-api/agents_api/models/agent/get_agent.py +++ b/agents-api/agents_api/models/agent/get_agent.py @@ -101,6 +101,8 @@ def get_agent(*, developer_id: UUID, agent_id: UUID) -> tuple[list[str], dict]: "min_p": min_p, "preset": preset, } + + :limit 1 """ queries = [ diff --git a/agents-api/agents_api/models/chat/get_cached_response.py b/agents-api/agents_api/models/chat/get_cached_response.py index 5440a6703..368c88567 100644 --- a/agents-api/agents_api/models/chat/get_cached_response.py +++ b/agents-api/agents_api/models/chat/get_cached_response.py @@ -9,6 +9,7 @@ def get_cached_response(key: str) -> tuple[str, dict]: query = """ input[key] <- [[$key]] ?[key, value] := input[key], *session_cache{key, value} + :limit 1 """ return (query, {"key": key}) diff --git a/agents-api/agents_api/models/chat/prepare_chat_context.py b/agents-api/agents_api/models/chat/prepare_chat_context.py index 4d521acb0..9be2d64aa 100644 --- a/agents-api/agents_api/models/chat/prepare_chat_context.py +++ b/agents-api/agents_api/models/chat/prepare_chat_context.py @@ -119,6 +119,8 @@ def prepare_chat_context( ?[{', '.join(session_data_fields)}, toolsets] := *_session_data_json {{ {', '.join(session_data_fields)} }}, *_toolsets_json {{ toolsets }} + + :limit 1 """ queries = [ diff --git a/agents-api/agents_api/models/developer/get_developer.py b/agents-api/agents_api/models/developer/get_developer.py index 31ade5334..0ae5421aa 100644 --- a/agents-api/agents_api/models/developer/get_developer.py +++ b/agents-api/agents_api/models/developer/get_developer.py @@ -67,6 +67,8 @@ def get_developer( created_at, updated_at, } + + :limit 1 """ return (query, {"developer_id": developer_id}) diff --git a/agents-api/agents_api/models/docs/embed_snippets.py b/agents-api/agents_api/models/docs/embed_snippets.py index e810d0379..993e76396 100644 --- a/agents-api/agents_api/models/docs/embed_snippets.py +++ b/agents-api/agents_api/models/docs/embed_snippets.py @@ -81,6 +81,7 @@ def embed_snippets( }}, index > {max(snippet_indices)} + :limit 1 :assert none """ diff --git a/agents-api/agents_api/models/docs/get_doc.py b/agents-api/agents_api/models/docs/get_doc.py index 4b3996c27..e81084985 100644 --- a/agents-api/agents_api/models/docs/get_doc.py +++ b/agents-api/agents_api/models/docs/get_doc.py @@ -87,6 +87,8 @@ def get_doc( metadata, }, snippets[snippet_data] + + :limit 1 """ queries = [ diff --git a/agents-api/agents_api/models/entry/get_history.py b/agents-api/agents_api/models/entry/get_history.py index 8918d357f..bd3c0397a 100644 --- a/agents-api/agents_api/models/entry/get_history.py +++ b/agents-api/agents_api/models/entry/get_history.py @@ -131,7 +131,9 @@ def get_history( session_relations[relations], session_id = to_uuid($session_id), created_at = now() - """ + + :limit 1 + """ queries = [ verify_developer_id_query(developer_id), diff --git a/agents-api/agents_api/models/execution/create_execution_transition.py b/agents-api/agents_api/models/execution/create_execution_transition.py index 42c6f1c22..f40395126 100644 --- a/agents-api/agents_api/models/execution/create_execution_transition.py +++ b/agents-api/agents_api/models/execution/create_execution_transition.py @@ -141,6 +141,8 @@ def create_execution_transition( found = length(prev_transitions), valid = if($next_type == "init", found == 0, found > 0), assert(valid, "Invalid transition"), + + :limit 1 """ # Prepare the insert query diff --git a/agents-api/agents_api/models/execution/get_execution_transition.py b/agents-api/agents_api/models/execution/get_execution_transition.py index d3ebf3783..e2b38789a 100644 --- a/agents-api/agents_api/models/execution/get_execution_transition.py +++ b/agents-api/agents_api/models/execution/get_execution_transition.py @@ -65,7 +65,9 @@ def get_execution_transition( is_null(next_tuple), null, {"workflow": next_tuple->0, "step": next_tuple->1}, - ), + ) + + :limit 1 """ get_query += filter diff --git a/agents-api/agents_api/models/execution/get_paused_execution_token.py b/agents-api/agents_api/models/execution/get_paused_execution_token.py index b4c9f9081..44eb8a4da 100644 --- a/agents-api/agents_api/models/execution/get_paused_execution_token.py +++ b/agents-api/agents_api/models/execution/get_paused_execution_token.py @@ -45,6 +45,7 @@ def get_paused_execution_token( execution_id = to_uuid($execution_id), status = "awaiting_input" + :limit 1 :assert some """ diff --git a/agents-api/agents_api/models/execution/get_temporal_workflow_data.py b/agents-api/agents_api/models/execution/get_temporal_workflow_data.py index bb0a462ef..8b1bf4604 100644 --- a/agents-api/agents_api/models/execution/get_temporal_workflow_data.py +++ b/agents-api/agents_api/models/execution/get_temporal_workflow_data.py @@ -45,6 +45,8 @@ def get_temporal_workflow_data( result_run_id, first_execution_run_id, } + + :limit 1 """ return ( diff --git a/agents-api/agents_api/models/execution/lookup_temporal_data.py b/agents-api/agents_api/models/execution/lookup_temporal_data.py index e3c369b94..35f09129b 100644 --- a/agents-api/agents_api/models/execution/lookup_temporal_data.py +++ b/agents-api/agents_api/models/execution/lookup_temporal_data.py @@ -43,6 +43,8 @@ def lookup_temporal_data( *temporal_executions_lookup { id, execution_id, run_id, first_execution_run_id, result_run_id } + + :limit 1 """ queries = [ diff --git a/agents-api/agents_api/models/execution/prepare_execution_input.py b/agents-api/agents_api/models/execution/prepare_execution_input.py index b763a7508..5f30e7f83 100644 --- a/agents-api/agents_api/models/execution/prepare_execution_input.py +++ b/agents-api/agents_api/models/execution/prepare_execution_input.py @@ -187,6 +187,8 @@ def prepare_execution_input( user = null, session = null, arguments = execution->"input" + + :limit 1 """ queries = [ diff --git a/agents-api/agents_api/models/execution/update_execution.py b/agents-api/agents_api/models/execution/update_execution.py index c2f40c7ff..4d0367ae4 100644 --- a/agents-api/agents_api/models/execution/update_execution.py +++ b/agents-api/agents_api/models/execution/update_execution.py @@ -82,6 +82,8 @@ def update_execution( ?[num] := valid_status[num], assert(num > 0, 'Invalid status') + + :limit 1 """ update_query = f""" diff --git a/agents-api/agents_api/models/session/get_session.py b/agents-api/agents_api/models/session/get_session.py index 2d8956eb7..45d971c3f 100644 --- a/agents-api/agents_api/models/session/get_session.py +++ b/agents-api/agents_api/models/session/get_session.py @@ -95,7 +95,10 @@ def get_session( token_budget, context_overflow, @ "END" - }, updated_at = to_int(validity) + }, + updated_at = to_int(validity) + + :limit 1 """ queries = [ diff --git a/agents-api/agents_api/models/session/prepare_session_data.py b/agents-api/agents_api/models/session/prepare_session_data.py index e8cfb7fc7..bbbd9c4cd 100644 --- a/agents-api/agents_api/models/session/prepare_session_data.py +++ b/agents-api/agents_api/models/session/prepare_session_data.py @@ -209,6 +209,8 @@ def prepare_session_data( session_data[session], user_data[users], agent_data[agents] + + :limit 1 """ queries = [ diff --git a/agents-api/agents_api/models/tools/create_tools.py b/agents-api/agents_api/models/tools/create_tools.py index dd8397797..87ea3a9cf 100644 --- a/agents-api/agents_api/models/tools/create_tools.py +++ b/agents-api/agents_api/models/tools/create_tools.py @@ -80,6 +80,7 @@ def create_tools( name, } + :limit 1 :assert none """ diff --git a/agents-api/agents_api/models/tools/get_tool.py b/agents-api/agents_api/models/tools/get_tool.py index 5ea009064..465fd2efe 100644 --- a/agents-api/agents_api/models/tools/get_tool.py +++ b/agents-api/agents_api/models/tools/get_tool.py @@ -68,6 +68,8 @@ def get_tool( updated_at, created_at, } + + :limit 1 """ queries = [ diff --git a/agents-api/agents_api/models/tools/get_tool_args_from_metadata.py b/agents-api/agents_api/models/tools/get_tool_args_from_metadata.py index ade296a29..2cdb92cb9 100644 --- a/agents-api/agents_api/models/tools/get_tool_args_from_metadata.py +++ b/agents-api/agents_api/models/tools/get_tool_args_from_metadata.py @@ -46,6 +46,8 @@ def tool_args_for_task( # Right values overwrite left values # See: https://docs.cozodb.org/en/latest/functions.html#Func.Vector.concat values = concat(agent_{arg_type}, task_{arg_type}), + + :limit 1 """ queries = [ @@ -88,6 +90,8 @@ def tool_args_for_session( # Right values overwrite left values # See: https://docs.cozodb.org/en/latest/functions.html#Func.Vector.concat values = concat(agent_{arg_type}, session_{arg_type}), + + :limit 1 """ queries = [ diff --git a/agents-api/agents_api/models/user/get_user.py b/agents-api/agents_api/models/user/get_user.py index cc7c6f970..2b4f59c83 100644 --- a/agents-api/agents_api/models/user/get_user.py +++ b/agents-api/agents_api/models/user/get_user.py @@ -67,7 +67,10 @@ def get_user( created_at, updated_at, metadata, - }""" + } + + :limit 1 + """ queries = [ verify_developer_id_query(developer_id), diff --git a/agents-api/agents_api/models/utils.py b/agents-api/agents_api/models/utils.py index c97d92451..c163642c0 100644 --- a/agents-api/agents_api/models/utils.py +++ b/agents-api/agents_api/models/utils.py @@ -127,6 +127,8 @@ def verify_developer_id_query(developer_id: UUID | str) -> str: matched[num], exists = num > 0, assert(exists, "Developer does not exist") + + :limit 1 """ @@ -162,6 +164,8 @@ def verify_developer_owns_resource_query( found[num], exists = num > 0, assert(exists, "Developer does not own resource {resource} with {resource_id_key} {resource_id_value}") + + :limit 1 """ rule = rule_head + rule_body + assertion