diff options
27 files changed, 135 insertions, 454 deletions
| diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index 6e920ab4..85f65dc3 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -8,7 +8,7 @@ from ..server.ide_protocol import AbstractIdeProtocolServer  from ..libs.util.queue import AsyncSubscriptionQueue  from ..models.main import ContinueBaseModel  from .main import Policy, History, FullState, Step, HistoryNode -from ..libs.steps.core.core import ReversibleStep, ManualEditStep, UserInputStep +from ..steps.core.core import ReversibleStep, ManualEditStep, UserInputStep  from ..libs.util.telemetry import capture_event  from .sdk import ContinueSDK  import asyncio diff --git a/continuedev/src/continuedev/core/policy.py b/continuedev/src/continuedev/core/policy.py index 6e264bab..f7fcf21a 100644 --- a/continuedev/src/continuedev/core/policy.py +++ b/continuedev/src/continuedev/core/policy.py @@ -1,13 +1,13 @@  from typing import List, Tuple, Type -from ..libs.steps.steps_on_startup import StepsOnStartupStep -from ..libs.steps.draft.dlt import CreatePipelineStep +from ..steps.steps_on_startup import StepsOnStartupStep +from ..recipes.CreatePipelineRecipe.main import CreatePipelineRecipe  from .main import Step, Validator, History, Policy  from .observation import Observation, TracebackObservation, UserInputObservation -from ..libs.steps.main import EditHighlightedCodeStep, SolveTracebackStep, RunCodeStep, FasterEditHighlightedCodeStep, StarCoderEditHighlightedCodeStep, MessageStep, EmptyStep -from ..libs.steps.nate import WritePytestsStep, CreateTableStep +from ..steps.main import EditHighlightedCodeStep, SolveTracebackStep, RunCodeStep, FasterEditHighlightedCodeStep, StarCoderEditHighlightedCodeStep, MessageStep, EmptyStep +from ..recipes.WritePytestsRecipe.main import WritePytestsRecipe  # from ..libs.steps.chroma import AnswerQuestionChroma, EditFileChroma -from ..libs.steps.continue_step import ContinueStepStep +from ..recipes.ContinueRecipeRecipe.main import ContinueStepStep  class DemoPolicy(Policy): @@ -22,11 +22,9 @@ class DemoPolicy(Policy):          if observation is not None and isinstance(observation, UserInputObservation):              # This could be defined with ObservationTypePolicy. Ergonomics not right though.              if " test" in observation.user_input.lower(): -                return WritePytestsStep(instructions=observation.user_input) +                return WritePytestsRecipe(instructions=observation.user_input)              elif "/dlt" in observation.user_input.lower() or " dlt" in observation.user_input.lower(): -                return CreatePipelineStep() -            elif "/table" in observation.user_input: -                return CreateTableStep(sql_str=" ".join(observation.user_input.split(" ")[1:])) +                return CreatePipelineRecipe()              # elif "/ask" in observation.user_input:              #     return AnswerQuestionChroma(question=" ".join(observation.user_input.split(" ")[1:]))              # elif "/edit" in observation.user_input: diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py index af7754cc..5d0f03fe 100644 --- a/continuedev/src/continuedev/core/sdk.py +++ b/continuedev/src/continuedev/core/sdk.py @@ -10,7 +10,7 @@ from ..libs.llm.openai import OpenAI  from .observation import Observation  from ..server.ide_protocol import AbstractIdeProtocolServer  from .main import History, Step -from ..libs.steps.core.core import * +from ..steps.core.core import *  from .env import get_env_var, make_sure_env_exists diff --git a/continuedev/src/continuedev/libs/steps/nate.py b/continuedev/src/continuedev/libs/steps/nate.py deleted file mode 100644 index 2f84e9d7..00000000 --- a/continuedev/src/continuedev/libs/steps/nate.py +++ /dev/null @@ -1,214 +0,0 @@ -from textwrap import dedent -import time -from typing import Coroutine, Union - -from ...models.filesystem import RangeInFile -from ...models.filesystem_edit import AddDirectory, AddFile -from ...core.observation import Observation, TextObservation -from ...core.main import Step, ContinueSDK -from .main import RunCommandStep -from .core.core import WaitForUserConfirmationStep, EditCodeStep, EditFileStep -import os - - -class WritePytestsStep(Step): -    for_filepath: Union[str, None] = None -    instructions: str = "Write unit tests for this file." - -    async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]: -        if self.for_filepath is None: -            self.for_filepath = (await sdk.ide.getOpenFiles())[0] - -        filename = os.path.basename(self.for_filepath) -        dirname = os.path.dirname(self.for_filepath) - -        path_dir = os.path.join(dirname, "tests") -        if not os.path.exists(path_dir): -            await sdk.apply_filesystem_edit(AddDirectory(path=path_dir)) - -        path = os.path.join(path_dir, f"test_{filename}") -        if os.path.exists(path): -            return None - -        for_file_contents = await sdk.ide.readFile(self.for_filepath) - -        prompt = dedent(f"""This is the file you will write unit tests for: - -```python -{for_file_contents} -``` - -Here are additional instructions: - -"{self.instructions}" - -Here is a complete set of pytest unit tests: - -        """) -        # tests = (await sdk.models.gpt35()).complete(prompt) -        tests = ''' -import pytest - -from ..calculator import Calculator - - -@pytest.fixture -def calculator(): -    return Calculator() - - -def test_add(calculator): -    assert calculator.add(2, 3) == 5 -    assert calculator.add(10, -2) == 8 -    assert calculator.add(0, 0) == 0 - - -def test_sub(calculator): -    assert calculator.sub(2, 3) == -1 -    assert calculator.sub(10, -2) == 12 -    assert calculator.sub(0, 0) == 0 - - -def test_mul(calculator): -    assert calculator.mul(2, 3) == 6 -    assert calculator.mul(10, -2) == -20 -    assert calculator.mul(0, 0) == 0 - - -def test_div(calculator): -    assert calculator.div(2, 3) == 0.6666666666666666 -    assert calculator.div(10, -2) == -5 -    assert calculator.div(0, 1) == 0 - - -def test_exp(calculator): -    assert calculator.exp(2, 3) == 8 -    assert calculator.exp(10, -2) == 0.01 -    assert calculator.exp(0, 0) == 1 -''' -        time.sleep(3.5) -        await sdk.apply_filesystem_edit(AddFile(filepath=path, content=tests)) - -        return None - - -class CreatePyplot(Step): -    # Wish there was a way to add import, specify dependency -    name: str = "Create a pyplot" - -    async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]: -        code = dedent("""import matplotlib.pyplot as plt -import numpy as np - -{instructions} - -plt.xlabel("{x_label}") -plt.ylabel("{y_label}") -plt.title("{title}") -plt.show() -        """) - - -class ImplementAbstractMethodStep(Step): -    name: str = "Implement abstract method for all subclasses" -    method_name: str = "def walk(self, path: str) -> List[str]" -    class_name: str = "FileSystem" - -    async def run(self, sdk: ContinueSDK): -        await sdk.run_step(WaitForUserConfirmationStep(prompt="Detected new abstract method. Implement in all subclasses?")) -        implementations = [] -        for filepath in ["/Users/natesesti/Desktop/continue/extension/examples/python/filesystem/real.py", "/Users/natesesti/Desktop/continue/extension/examples/python/filesystem/virtual.py"]: -            contents = await sdk.ide.readFile(filepath) -            implementations.append( -                RangeInFile.from_entire_file(filepath, contents)) - -        for implementation in implementations: -            await sdk.run_step(EditCodeStep( -                range_in_files=[implementation], -                prompt=f"{{code}}\nRewrite the class, implementing the method `{self.method_name}`.\n", -            )) - - -class CreateTableStep(Step): -    sql_str: str -    name: str = "Create a table" -    hide = True - -    async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]: -        # Write the TypeORM entity -        entity_name = "Order" -        orm_entity = '''import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; - -@Entity() -export class Order { -  @PrimaryGeneratedColumn() -  order_id: number; - -  @Column() -  customer_id: number; - -  @Column() -  order_date: Date; - -  @Column() -  order_total: number; - -  @Column() -  shipping_address: string; - -  @Column() -  billing_address: string; - -  @Column() -  payment_method: string; - -  @Column() -  order_status: string; - -  @Column() -  tracking_number: string; -}''' -        time.sleep(2) -        # orm_entity = (await sdk.models.gpt35()).complete( -        #     f"{self.sql_str}\n\nWrite a TypeORM entity called {entity_name} for this table, importing as necessary:") -        # (await sdk.models.gpt35()).complete("What is the name of the entity?") -        await sdk.apply_filesystem_edit(AddFile(filepath=f"/Users/natesesti/Desktop/continue/extension/examples/python/MyProject/src/entity/{entity_name}.ts", content=orm_entity)) -        await sdk.ide.setFileOpen(f"/Users/natesesti/Desktop/continue/extension/examples/python/MyProject/src/entity/{entity_name}.ts", True) - -        # Add entity to data-source.ts -        await sdk.run_step(EditFileStep( -            filepath=f"/Users/natesesti/Desktop/continue/extension/examples/python/MyProject/src/data-source.ts", -            prompt=f"{{code}}\nAdd the {entity_name} entity:\n", -        )) - -        # Generate blank migration for the entity -        obs: TextObservation = await sdk.run_step(RunCommandStep( -            cmd=f"npx typeorm migration:create ./src/migration/Create{entity_name}Table" -        )) -        migration_filepath = obs.text.split(" ")[1] - -        # Wait for user input -        await sdk.run_step(WaitForUserConfirmationStep(prompt="Fill in the migration?")) - -        # Fill in the migration -        await sdk.run_step(EditFileStep( -            filepath=migration_filepath, -            prompt=f"{{code}}\nThis is the table that was created:\n{self.sql_str}\n\nFill in the migration for the table:\n", -        )) - -        # Run the migration -        command_step = RunCommandStep( -            cmd=f"""sqlite3 database.sqlite 'CREATE TABLE orders ( -  order_id SERIAL PRIMARY KEY, -  customer_id INTEGER, -  order_date DATE, -  order_total NUMERIC, -  shipping_address TEXT, -  billing_address TEXT, -  payment_method TEXT, -  order_status TEXT, -  tracking_number TEXT -);'""" -        ) -        command_step._description = "npx typeorm-ts-node-commonjs migration:run -d ./src/data-source.ts" -        await sdk.run_step(command_step) diff --git a/continuedev/src/continuedev/libs/steps/ty.py b/continuedev/src/continuedev/libs/steps/ty.py deleted file mode 100644 index 9dde7c86..00000000 --- a/continuedev/src/continuedev/libs/steps/ty.py +++ /dev/null @@ -1,155 +0,0 @@ -import subprocess -from ...models.main import Position, Range -from ...models.filesystem import RangeInFile -from ...models.filesystem_edit import AddDirectory, AddFile, FileEdit -from ...core.observation import DictObservation -from ...core.main import History, Step, Policy -from ...core.sdk import ContinueSDK -from .main import RunCommandStep -from ..steps.core.core import EditCodeStep, WaitForUserConfirmationStep, WaitForUserInputStep - -source_name = "weather_api" - - -class SetupPipelineStep(Step): - -    name = "Setup Pipeline" - -    api_description: str  # e.g. "I want to load data from the weatherapi.com API" - -    async def run(self, sdk: ContinueSDK): -        # source_name = (await sdk.models.gpt35()).complete( -        #     f"Write a snake_case name for the data source described by {self.api_description}: ").strip() -        filename = f'/Users/natesesti/Desktop/continue/extension/examples/python/{source_name}.py' - -        # running commands to get started when creating a new dlt pipeline -        process = subprocess.Popen( -            '/bin/bash', stdin=subprocess.PIPE, stdout=subprocess.PIPE) -        out, err = process.communicate(f''' -        cd /Users/natesesti/Desktop/continue/extension/examples/python && python3 -m venv env && source env/bin/activate && pip install dlt && dlt init {source_name} duckdb -Y -pip install -r requirements.txt && pip install dlt[duckdb]'''.encode()) -        process = subprocess.Popen( -            '/bin/bash', stdin=subprocess.PIPE, stdout=subprocess.PIPE) -        out, err = process.communicate( -            f'''cd /Users/natesesti/Desktop/continue/extension/examples/python && source env/bin/activate && pip install -r requirements.txt'''.encode()) -        # await sdk.run_step( -        #     RunCommandStep(cmd="cd /Users/natesesti/Desktop/continue/extension/examples/python") >> -        #     RunCommandStep(cmd=f'python3 -m venv env') >> -        #     RunCommandStep(cmd=f'source env/bin/activate') >> -        #     RunCommandStep(cmd=f'pip install dlt') >> -        #     RunCommandStep(cmd=f'dlt init {source_name} duckdb') >> -        #     RunCommandStep(cmd=f'pip install -r requirements') -        # ) - -        # editing the resource function to call the requested API -        await sdk.ide.setFileOpen(filename) -        contents = await sdk.ide.readFile(filename) -        await sdk.run_step(EditCodeStep( -            range_in_files=[RangeInFile.from_entire_file(filename, contents)], -            prompt=f'{{code}}\n\nRewrite the entire file, editing the resource function to call the API described by this: {self.api_description}' -        )) - -        # wait for user to put API key in secrets.toml -        await sdk.ide.setFileOpen("/Users/natesesti/Desktop/continue/extension/examples/python/.dlt/secrets.toml") -        await sdk.run_step(WaitForUserConfirmationStep(prompt=f"Please add the API key to the `secrets.toml` file and then press `Continue`")) -        return DictObservation(values={"source_name": source_name}) - - -class ValidatePipelineStep(Step): - -    name = "Validate Pipeline" - -    async def run(self, sdk: ContinueSDK): -        # source_name = sdk.history.last_observation()["source_name"] -        filename = f'/Users/natesesti/Desktop/continue/extension/examples/python/{source_name}.py' - -        # test that the API call works -        await sdk.run_step(RunCommandStep(cmd=f'env/bin/python3 weather_api.py')) -        # TODO: validate that the response code is 200 (i.e. successful) else loop - -        # remove exit() from the main main function -        await sdk.ide.setFileOpen(filename) -        contents = await sdk.ide.readFile(filename) -        new_contents = contents.replace('exit()', '') -        await sdk.apply_filesystem_edit(FileEdit(filepath=filename, range=Range.from_entire_file(contents), replacement=new_contents)) -        await sdk.ide.saveFile(filename) -        # await sdk.run_step(EditCodeStep( -        #     range_in_files=[RangeInFile.from_entire_file(filename)], -        #     prompt=f'Remove exit() from the main function' -        # )) - -        # test that dlt loads the data into the DuckDB instance -        await sdk.run_step(RunCommandStep(cmd=f'env/bin/python3 weather_api.py')) -        # TODO: validate that `dlt` outputted success via print(load_info) else loop - -        # write Python code in `query.py` that queries the DuckDB instance to validate it worked -        query_filename = '/Users/natesesti/Desktop/continue/extension/examples/python/query.py' - -        names_query_code = ''' -        import duckdb - -        # Connect to the DuckDB instance -        con = duckdb.connect('weather.duckdb') - -        # Query the schema_name.table_name -        result = conn.execute("SELECT table_schema || '.' || table_name FROM information_schema.tables WHERE table_schema NOT IN ('information_schema', 'pg_catalog')").fetchall() - -        # Print the schema_name.table_name(s) to stdout -        for r in result: -            print(r[0]) -        ''' -        # await sdk.apply_filesystem_edit(FileEdit.from_insertion( -        #     filepath=query_filename, -        #     position=Position(line=0, character=0), -        #     content=names_query_code -        # )) -        # await sdk.run_step(RunCommandStep(cmd=f'env/bin/python3 query.py')) -        # TODO: replace with code that grabs all non-dlt `schema_name.table_name`s outputted by previous query -        table_name = "weather_api.weather_api_resource" -        tables_query_code = f''' -import duckdb - -# connect to DuckDB instance -conn = duckdb.connect(database="weather.duckdb") - -# get table names -rows = conn.execute("SELECT * FROM {table_name};").fetchall() - -# print table names -for row in rows: -    print(row) -        ''' -        await sdk.apply_filesystem_edit(AddFile(filepath=query_filename, content=tables_query_code)) -        await sdk.ide.setFileOpen(query_filename) -        # await sdk.apply_filesystem_edit(FileEdit(filepath=query_filename, replacement=tables_query_code, -        #                                          range=Range.from_entire_file(content=names_query_code))) -        await sdk.run_step(RunCommandStep(cmd=f'env/bin/python3 query.py')) - - -class CreatePipelinePolicy(Policy): - -    _current_state: str = "init" - -    def next(self, history: History = History.from_empty()) -> "Step": -        if self._current_state == "init": -            self._current_state = "setup" -            return WaitForUserInputStep(prompt="What API do you want to load data from?") -        elif self._current_state == "setup": -            self._current_state = "validate" -            return SetupPipelineStep() -        elif self._current_state == "validate": -            self._current_state = "done" -            return ValidatePipelineStep() -        else: -            return None - - -class CreatePipelineStep(Step): - -    async def run(self, sdk: ContinueSDK): -        await sdk.run_step( -            WaitForUserInputStep(prompt="What API do you want to load data from?") >> -            SetupPipelineStep(api_description="Load data from the WeatherAPI.com API") >> -            ValidatePipelineStep() -        ) diff --git a/continuedev/src/continuedev/recipes/ContinueRecipeRecipe/README.md b/continuedev/src/continuedev/recipes/ContinueRecipeRecipe/README.md new file mode 100644 index 00000000..df66104f --- /dev/null +++ b/continuedev/src/continuedev/recipes/ContinueRecipeRecipe/README.md @@ -0,0 +1,7 @@ +# ContinueRecipeRecipe + +A recipe for building recipes! + +## How to use this recipe + +This recipe takes a single input, a description of the recipe to be built. diff --git a/continuedev/src/continuedev/libs/steps/continue_step.py b/continuedev/src/continuedev/recipes/ContinueRecipeRecipe/main.py index 253bb490..953fb0c2 100644 --- a/continuedev/src/continuedev/libs/steps/continue_step.py +++ b/continuedev/src/continuedev/recipes/ContinueRecipeRecipe/main.py @@ -1,6 +1,6 @@  from textwrap import dedent  from ...models.filesystem import RangeInFile -from .main import EditHighlightedCodeStep +from ...steps.main import EditHighlightedCodeStep  from ...core.main import Step  from ...core.sdk import ContinueSDK diff --git a/continuedev/src/continuedev/libs/steps/react_posthog.py b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/README.md index e69de29b..e69de29b 100644 --- a/continuedev/src/continuedev/libs/steps/react_posthog.py +++ b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/README.md diff --git a/continuedev/src/continuedev/recipes/CreatePipelineRecipe/main.py b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/main.py new file mode 100644 index 00000000..c0699cae --- /dev/null +++ b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/main.py @@ -0,0 +1,33 @@ +from textwrap import dedent + +from ...core.main import Step +from ...core.sdk import ContinueSDK +from ...steps.core.core import WaitForUserInputStep +from ...steps.main import MessageStep +from .steps import SetupPipelineStep, ValidatePipelineStep + + +class CreatePipelineRecipe(Step): +    hide: bool = True + +    async def run(self, sdk: ContinueSDK): +        await sdk.run_step( +            MessageStep(message=dedent("""\ +                This recipe will walk you through the process of creating a dlt pipeline for your chosen data source. With the help of Continue, you will: +                - Create a Python virtual environment with dlt installed +                - Run `dlt init` to generate a pipeline template +                - Write the code to call the API +                - Add any required API keys to the `secrets.toml` file +                - Test that the API call works +                - Load the data into a local DuckDB instance +                - Write a query to view the data""")) >> +            WaitForUserInputStep(prompt="What API do you want to load data from?") >> +            SetupPipelineStep(api_description="WeatherAPI.com API") >> +            MessageStep(message=dedent("""\ +                This step will validate that your dlt pipeline is working as expected: +                - Test that the API call works +                - Load the data into a local DuckDB instance +                - Write a query to view the data +                """)) >> +            ValidatePipelineStep() +        ) diff --git a/continuedev/src/continuedev/libs/steps/draft/dlt.py b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/steps.py index 9cec5014..b480223a 100644 --- a/continuedev/src/continuedev/libs/steps/draft/dlt.py +++ b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/steps.py @@ -1,13 +1,10 @@  from textwrap import dedent -from ....core.sdk import Models - -from ....core.observation import DictObservation -from ....models.filesystem_edit import AddFile -from ....core.main import Step -from ....core.sdk import ContinueSDK -from ..core.core import WaitForUserInputStep -from ..main import MessageStep +from ...core.sdk import Models +from ...core.observation import DictObservation +from ...models.filesystem_edit import AddFile +from ...core.main import Step +from ...core.sdk import ContinueSDK  class SetupPipelineStep(Step): @@ -86,29 +83,3 @@ class ValidatePipelineStep(Step):          query_filename = (await sdk.ide.getWorkspaceDirectory()) + "/query.py"          await sdk.apply_filesystem_edit(AddFile(filepath=query_filename, content=tables_query_code))          await sdk.run('env/bin/python3 query.py') - - -class CreatePipelineStep(Step): -    hide: bool = True - -    async def run(self, sdk: ContinueSDK): -        await sdk.run_step( -            MessageStep(message=dedent("""\ -                This recipe will walk you through the process of creating a dlt pipeline for your chosen data source. With the help of Continue, you will: -                - Create a Python virtual environment with dlt installed -                - Run `dlt init` to generate a pipeline template -                - Write the code to call the API -                - Add any required API keys to the `secrets.toml` file -                - Test that the API call works -                - Load the data into a local DuckDB instance -                - Write a query to view the data""")) >> -            WaitForUserInputStep(prompt="What API do you want to load data from?") >> -            SetupPipelineStep(api_description="WeatherAPI.com API") >> -            MessageStep(message=dedent("""\ -                This step will validate that your dlt pipeline is working as expected: -                - Test that the API call works -                - Load the data into a local DuckDB instance -                - Write a query to view the data -                """)) >> -            ValidatePipelineStep() -        ) diff --git a/continuedev/src/continuedev/recipes/README.md b/continuedev/src/continuedev/recipes/README.md new file mode 100644 index 00000000..5e01cc97 --- /dev/null +++ b/continuedev/src/continuedev/recipes/README.md @@ -0,0 +1,9 @@ +# This is a collaborative collection of Continue recipes + +Recipes here will automatically be made available in the [Continue VS Code extension](https://marketplace.visualstudio.com/items?itemName=Continue.continue). + +The `recipes` folder contains all recipes, each with the same structure. **If you wish to create your own recipe, please do the following:** + +1. Create a new subfolder in `recipes`, with the name of your recipe (for example `MyNewRecipe`). +2. Make 2 files in this folder: 1) a `README.md` describing your recipe and how to use it and 2) a `main.py` including a single class with the name of your recipe (e.g. `MyNewRecipe`). +3. Write any utility code other than the main recipe class in a separate file, which you can import in `main.py`. Particularly if you decide to break the recipe into multiple sub-steps, try to keep these separate. diff --git a/continuedev/src/continuedev/recipes/TemplateRecipe/README.md b/continuedev/src/continuedev/recipes/TemplateRecipe/README.md new file mode 100644 index 00000000..91d1123b --- /dev/null +++ b/continuedev/src/continuedev/recipes/TemplateRecipe/README.md @@ -0,0 +1,7 @@ +# TemplateRecipe + +This folder is a template that you can copy to create your own recipe. + +## How to use this recipe + +Explain here what users should know when using your recipe. What inputs does it have and what actions will it perform? diff --git a/continuedev/src/continuedev/recipes/TemplateRecipe/main.py b/continuedev/src/continuedev/recipes/TemplateRecipe/main.py new file mode 100644 index 00000000..94675725 --- /dev/null +++ b/continuedev/src/continuedev/recipes/TemplateRecipe/main.py @@ -0,0 +1,27 @@ +from typing import Coroutine +from continuedev.core import Step, ContinueSDK, Observation, Models + + +class TemplateRecipe(Step): +    """ +    A simple recipe that appends a print statement to the currently open file. +    Use this as a template to create your own! +    """ + +    # Paremeters for the recipe +    name: str + +    # A title for the recipe, to be displayed in the GUI +    title = "Template Recipe" + +    # A description of what the recipe accomplished, to be displayed in the GUI +    async def describe(self, models: Models) -> Coroutine[str, None, None]: +        return f"Appended a statement to print `Hello, {self.name}!` at the end of the file." + +    # The code executed when the recipe is run +    async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]: +        open_files = await sdk.ide.getOpenFiles() +        await sdk.edit_file( +            filename=open_files[0], +            prompt=f"Append a statement to print `Hello, {self.name}!` at the end of the file." +        ) diff --git a/continuedev/src/continuedev/recipes/WritePytestsRecipe/README.md b/continuedev/src/continuedev/recipes/WritePytestsRecipe/README.md new file mode 100644 index 00000000..5ce33ecb --- /dev/null +++ b/continuedev/src/continuedev/recipes/WritePytestsRecipe/README.md @@ -0,0 +1,7 @@ +# CreatePytestsRecipe + +A recipe for writing unit tests in Pytest. + +# How to use this recipe + +Call this recipe with a python file open that you would like to test. It will create tests in a `tests/` folder adjacent to the file with the test file given the same name prepended by `test_`. diff --git a/continuedev/src/continuedev/libs/steps/pytest.py b/continuedev/src/continuedev/recipes/WritePytestsRecipe/main.py index 2e83ae2d..a35055f3 100644 --- a/continuedev/src/continuedev/libs/steps/pytest.py +++ b/continuedev/src/continuedev/recipes/WritePytestsRecipe/main.py @@ -4,7 +4,7 @@ from ...core.main import Step, ContinueSDK  import os -class WritePytestsStep(Step): +class WritePytestsRecipe(Step):      for_filepath: str      async def run(self, sdk: ContinueSDK): diff --git a/continuedev/src/continuedev/server/session_manager.py b/continuedev/src/continuedev/server/session_manager.py index 5598e140..0dbfaf38 100644 --- a/continuedev/src/continuedev/server/session_manager.py +++ b/continuedev/src/continuedev/server/session_manager.py @@ -6,7 +6,6 @@ from ..models.filesystem_edit import FileEditWithFullContents  from ..core.policy import DemoPolicy  from ..core.main import FullState  from ..core.autopilot import Autopilot -from ..libs.steps.nate import ImplementAbstractMethodStep  from .ide_protocol import AbstractIdeProtocolServer  import asyncio  import nest_asyncio @@ -34,11 +33,6 @@ class DemoAutopilot(Autopilot):              self._manual_edits_buffer.append(edit)              # Note that you're storing a lot of unecessary data here. Can compress into EditDiffs on the spot, and merge.              # self._manual_edits_buffer = merge_file_edit(self._manual_edits_buffer, edit) -            # FOR DEMO PURPOSES -            if edit.fileEdit.filepath.endswith("filesystem.py") and "List" in self.cumulative_edit_string and ":" in edit.fileEdit.replacement: -                self.cumulative_edit_string = "" -                asyncio.create_task(self.run_from_step( -                    ImplementAbstractMethodStep()))  class SessionManager: diff --git a/continuedev/src/continuedev/libs/steps/__init__.py b/continuedev/src/continuedev/steps/__init__.py index 8b137891..8b137891 100644 --- a/continuedev/src/continuedev/libs/steps/__init__.py +++ b/continuedev/src/continuedev/steps/__init__.py diff --git a/continuedev/src/continuedev/libs/steps/chroma.py b/continuedev/src/continuedev/steps/chroma.py index 39424c5c..59a8b6e0 100644 --- a/continuedev/src/continuedev/libs/steps/chroma.py +++ b/continuedev/src/continuedev/steps/chroma.py @@ -1,9 +1,9 @@  from textwrap import dedent  from typing import Coroutine, Union -from ...core.observation import Observation, TextObservation -from ...core.main import Step, ContinueSDK +from ..core.observation import Observation, TextObservation +from ..core.main import Step, ContinueSDK  from .core.core import EditFileStep -from ..chroma.query import query_codebase_index +from ..libs.chroma.query import query_codebase_index  from .core.core import EditFileStep diff --git a/continuedev/src/continuedev/libs/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 9a5d54f0..e54a9a21 100644 --- a/continuedev/src/continuedev/libs/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -2,12 +2,12 @@  import subprocess  from textwrap import dedent  from typing import Coroutine, List, Union -from ...llm.prompt_utils import MarkdownStyleEncoderDecoder +from ...libs.llm.prompt_utils import MarkdownStyleEncoderDecoder -from ....models.filesystem_edit import EditDiff, FileEditWithFullContents, FileSystemEdit -from ....models.filesystem import FileSystem, RangeInFile, RangeInFileWithContents -from ....core.observation import Observation, TextObservation, TracebackObservation, UserInputObservation -from ....core.main import Step, SequentialStep +from ...models.filesystem_edit import EditDiff, FileEditWithFullContents, FileSystemEdit +from ...models.filesystem import FileSystem, RangeInFile, RangeInFileWithContents +from ...core.observation import Observation, TextObservation, TracebackObservation, UserInputObservation +from ...core.main import Step, SequentialStep  class ContinueSDK: diff --git a/continuedev/src/continuedev/libs/steps/draft/abstract_method.py b/continuedev/src/continuedev/steps/draft/abstract_method.py index f3131c4b..f3131c4b 100644 --- a/continuedev/src/continuedev/libs/steps/draft/abstract_method.py +++ b/continuedev/src/continuedev/steps/draft/abstract_method.py diff --git a/continuedev/src/continuedev/libs/steps/migration.py b/continuedev/src/continuedev/steps/draft/migration.py index 7b70422d..ea538bb7 100644 --- a/continuedev/src/continuedev/libs/steps/migration.py +++ b/continuedev/src/continuedev/steps/draft/migration.py @@ -1,8 +1,7 @@  # When an edit is made to an existing class or a new sqlalchemy class is created,  # this should be kicked off. -from ...models.filesystem import RangeInFile -from .main import EditCodeStep, RunCommandStep +from ..main import EditCodeStep, RunCommandStep  from ...core.main import Step diff --git a/continuedev/src/continuedev/libs/steps/draft/redux.py b/continuedev/src/continuedev/steps/draft/redux.py index efaa9ba4..17506316 100644 --- a/continuedev/src/continuedev/libs/steps/draft/redux.py +++ b/continuedev/src/continuedev/steps/draft/redux.py @@ -1,5 +1,5 @@ -from ....core.main import Step -from ....core.sdk import ContinueSDK +from ...core.main import Step +from ...core.sdk import ContinueSDK  from ..core.core import EditFileStep diff --git a/continuedev/src/continuedev/libs/steps/draft/typeorm.py b/continuedev/src/continuedev/steps/draft/typeorm.py index d06a6fb4..153c855f 100644 --- a/continuedev/src/continuedev/libs/steps/draft/typeorm.py +++ b/continuedev/src/continuedev/steps/draft/typeorm.py @@ -1,6 +1,6 @@  from textwrap import dedent -from ....core.main import Step -from ....core.sdk import ContinueSDK +from ...core.main import Step +from ...core.sdk import ContinueSDK  class CreateTableStep(Step): diff --git a/continuedev/src/continuedev/libs/steps/main.py b/continuedev/src/continuedev/steps/main.py index 73ad3352..8588ec92 100644 --- a/continuedev/src/continuedev/libs/steps/main.py +++ b/continuedev/src/continuedev/steps/main.py @@ -2,17 +2,17 @@ from typing import Coroutine, List, Union  from pydantic import BaseModel -from ..util.traceback_parsers import parse_python_traceback -from ..llm import LLM -from ...models.main import Traceback, Range -from ...models.filesystem_edit import EditDiff, FileEdit -from ...models.filesystem import RangeInFile, RangeInFileWithContents -from ...core.observation import Observation, TextObservation, TracebackObservation -from ..llm.prompt_utils import MarkdownStyleEncoderDecoder +from ..libs.util.traceback_parsers import parse_python_traceback +from ..libs.llm import LLM +from ..models.main import Traceback, Range +from ..models.filesystem_edit import EditDiff, FileEdit +from ..models.filesystem import RangeInFile, RangeInFileWithContents +from ..core.observation import Observation, TextObservation, TracebackObservation +from ..libs.llm.prompt_utils import MarkdownStyleEncoderDecoder  from textwrap import dedent -from ...core.main import Step -from ...core.sdk import ContinueSDK, Models -from ...core.observation import Observation +from ..core.main import Step +from ..core.sdk import ContinueSDK, Models +from ..core.observation import Observation  import subprocess  from .core.core import EditCodeStep diff --git a/continuedev/src/continuedev/libs/steps/steps_on_startup.py b/continuedev/src/continuedev/steps/steps_on_startup.py index fd1eb8f0..cd40ff56 100644 --- a/continuedev/src/continuedev/libs/steps/steps_on_startup.py +++ b/continuedev/src/continuedev/steps/steps_on_startup.py @@ -1,13 +1,11 @@ - - -from ...core.main import ContinueSDK, Models, Step +from ..core.main import ContinueSDK, Models, Step  from .main import UserInputStep -from .draft.dlt import CreatePipelineStep +from ..recipes.CreatePipelineRecipe.main import CreatePipelineRecipe  step_name_to_step_class = {      "UserInputStep": UserInputStep, -    "CreatePipelineStep": CreatePipelineStep +    "CreatePipelineRecipe": CreatePipelineRecipe  } diff --git a/docs/docs/concepts/step.md b/docs/docs/concepts/step.md index 1758fdd8..1e1a0a65 100644 --- a/docs/docs/concepts/step.md +++ b/docs/docs/concepts/step.md @@ -60,10 +60,10 @@ Create and run an alembic migration  - `edited_file`:
 -### WritePytestsStep
 +### WritePytestsRecipe
  Write unit tests for this file.
  #### Parameters
 -- for_filepath (required): the path of the file that unit tests should be created for
\ No newline at end of file +- for_filepath (required): the path of the file that unit tests should be created for
 diff --git a/docs/docs/walkthroughs/create-a-recipe.md b/docs/docs/walkthroughs/create-a-recipe.md index 0cf1892e..12dd3167 100644 --- a/docs/docs/walkthroughs/create-a-recipe.md +++ b/docs/docs/walkthroughs/create-a-recipe.md @@ -67,7 +67,7 @@ class CreatePytestsStep(Step):          code = await sdk.ide.readFile(self.input_file_path)
          sdk.run_step(CreateDirStep(output_dir_path))
 -        sdk.run_step(WritePytestsStep(code, output_file_prefix, output_dir_path))
 +        sdk.run_step(WritePytestsRecipe(code, output_file_prefix, output_dir_path))
  ```
  ### Adjust for different OS
 | 
