cecli-dev 0.93.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cecli/__init__.py +20 -0
- cecli/__main__.py +4 -0
- cecli/_version.py +34 -0
- cecli/args.py +1092 -0
- cecli/args_formatter.py +228 -0
- cecli/change_tracker.py +133 -0
- cecli/coders/__init__.py +38 -0
- cecli/coders/agent_coder.py +1872 -0
- cecli/coders/architect_coder.py +63 -0
- cecli/coders/ask_coder.py +8 -0
- cecli/coders/base_coder.py +3993 -0
- cecli/coders/chat_chunks.py +116 -0
- cecli/coders/context_coder.py +52 -0
- cecli/coders/copypaste_coder.py +269 -0
- cecli/coders/editblock_coder.py +656 -0
- cecli/coders/editblock_fenced_coder.py +9 -0
- cecli/coders/editblock_func_coder.py +140 -0
- cecli/coders/editor_diff_fenced_coder.py +8 -0
- cecli/coders/editor_editblock_coder.py +8 -0
- cecli/coders/editor_whole_coder.py +8 -0
- cecli/coders/help_coder.py +15 -0
- cecli/coders/patch_coder.py +705 -0
- cecli/coders/search_replace.py +757 -0
- cecli/coders/shell.py +37 -0
- cecli/coders/single_wholefile_func_coder.py +101 -0
- cecli/coders/udiff_coder.py +428 -0
- cecli/coders/udiff_simple.py +12 -0
- cecli/coders/wholefile_coder.py +143 -0
- cecli/coders/wholefile_func_coder.py +133 -0
- cecli/commands/__init__.py +192 -0
- cecli/commands/add.py +226 -0
- cecli/commands/agent.py +51 -0
- cecli/commands/architect.py +46 -0
- cecli/commands/ask.py +44 -0
- cecli/commands/chat_mode.py +0 -0
- cecli/commands/clear.py +37 -0
- cecli/commands/code.py +46 -0
- cecli/commands/command_prefix.py +44 -0
- cecli/commands/commit.py +52 -0
- cecli/commands/context.py +47 -0
- cecli/commands/context_blocks.py +124 -0
- cecli/commands/context_management.py +51 -0
- cecli/commands/copy.py +62 -0
- cecli/commands/copy_context.py +81 -0
- cecli/commands/core.py +287 -0
- cecli/commands/diff.py +68 -0
- cecli/commands/drop.py +217 -0
- cecli/commands/editor.py +78 -0
- cecli/commands/exit.py +55 -0
- cecli/commands/git.py +57 -0
- cecli/commands/help.py +140 -0
- cecli/commands/history_search.py +40 -0
- cecli/commands/lint.py +109 -0
- cecli/commands/list_sessions.py +56 -0
- cecli/commands/load.py +85 -0
- cecli/commands/load_session.py +48 -0
- cecli/commands/load_skill.py +68 -0
- cecli/commands/ls.py +75 -0
- cecli/commands/map.py +37 -0
- cecli/commands/map_refresh.py +35 -0
- cecli/commands/model.py +118 -0
- cecli/commands/models.py +41 -0
- cecli/commands/multiline_mode.py +38 -0
- cecli/commands/paste.py +91 -0
- cecli/commands/quit.py +32 -0
- cecli/commands/read_only.py +267 -0
- cecli/commands/read_only_stub.py +270 -0
- cecli/commands/reasoning_effort.py +70 -0
- cecli/commands/remove_skill.py +68 -0
- cecli/commands/report.py +40 -0
- cecli/commands/reset.py +88 -0
- cecli/commands/run.py +99 -0
- cecli/commands/save.py +49 -0
- cecli/commands/save_session.py +43 -0
- cecli/commands/settings.py +69 -0
- cecli/commands/test.py +58 -0
- cecli/commands/think_tokens.py +74 -0
- cecli/commands/tokens.py +207 -0
- cecli/commands/undo.py +145 -0
- cecli/commands/utils/__init__.py +0 -0
- cecli/commands/utils/base_command.py +131 -0
- cecli/commands/utils/helpers.py +142 -0
- cecli/commands/utils/registry.py +53 -0
- cecli/commands/utils/save_load_manager.py +98 -0
- cecli/commands/voice.py +78 -0
- cecli/commands/weak_model.py +123 -0
- cecli/commands/web.py +87 -0
- cecli/deprecated_args.py +185 -0
- cecli/diffs.py +129 -0
- cecli/dump.py +29 -0
- cecli/editor.py +147 -0
- cecli/exceptions.py +115 -0
- cecli/format_settings.py +26 -0
- cecli/help.py +119 -0
- cecli/help_pats.py +19 -0
- cecli/helpers/__init__.py +9 -0
- cecli/helpers/copypaste.py +123 -0
- cecli/helpers/coroutines.py +8 -0
- cecli/helpers/file_searcher.py +142 -0
- cecli/helpers/model_providers.py +552 -0
- cecli/helpers/plugin_manager.py +81 -0
- cecli/helpers/profiler.py +162 -0
- cecli/helpers/requests.py +77 -0
- cecli/helpers/similarity.py +98 -0
- cecli/helpers/skills.py +577 -0
- cecli/history.py +186 -0
- cecli/io.py +1782 -0
- cecli/linter.py +304 -0
- cecli/llm.py +101 -0
- cecli/main.py +1280 -0
- cecli/mcp/__init__.py +154 -0
- cecli/mcp/oauth.py +250 -0
- cecli/mcp/server.py +278 -0
- cecli/mdstream.py +243 -0
- cecli/models.py +1255 -0
- cecli/onboarding.py +301 -0
- cecli/prompts/__init__.py +0 -0
- cecli/prompts/agent.yml +71 -0
- cecli/prompts/architect.yml +35 -0
- cecli/prompts/ask.yml +31 -0
- cecli/prompts/base.yml +99 -0
- cecli/prompts/context.yml +60 -0
- cecli/prompts/copypaste.yml +5 -0
- cecli/prompts/editblock.yml +143 -0
- cecli/prompts/editblock_fenced.yml +106 -0
- cecli/prompts/editblock_func.yml +25 -0
- cecli/prompts/editor_diff_fenced.yml +115 -0
- cecli/prompts/editor_editblock.yml +121 -0
- cecli/prompts/editor_whole.yml +46 -0
- cecli/prompts/help.yml +37 -0
- cecli/prompts/patch.yml +110 -0
- cecli/prompts/single_wholefile_func.yml +24 -0
- cecli/prompts/udiff.yml +106 -0
- cecli/prompts/udiff_simple.yml +13 -0
- cecli/prompts/utils/__init__.py +0 -0
- cecli/prompts/utils/prompt_registry.py +167 -0
- cecli/prompts/utils/system.py +56 -0
- cecli/prompts/wholefile.yml +50 -0
- cecli/prompts/wholefile_func.yml +24 -0
- cecli/queries/tree-sitter-language-pack/README.md +7 -0
- cecli/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
- cecli/queries/tree-sitter-language-pack/c-tags.scm +12 -0
- cecli/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
- cecli/queries/tree-sitter-language-pack/clojure-tags.scm +12 -0
- cecli/queries/tree-sitter-language-pack/commonlisp-tags.scm +127 -0
- cecli/queries/tree-sitter-language-pack/cpp-tags.scm +18 -0
- cecli/queries/tree-sitter-language-pack/csharp-tags.scm +32 -0
- cecli/queries/tree-sitter-language-pack/d-tags.scm +26 -0
- cecli/queries/tree-sitter-language-pack/dart-tags.scm +97 -0
- cecli/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
- cecli/queries/tree-sitter-language-pack/elixir-tags.scm +59 -0
- cecli/queries/tree-sitter-language-pack/elm-tags.scm +22 -0
- cecli/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
- cecli/queries/tree-sitter-language-pack/go-tags.scm +49 -0
- cecli/queries/tree-sitter-language-pack/java-tags.scm +26 -0
- cecli/queries/tree-sitter-language-pack/javascript-tags.scm +96 -0
- cecli/queries/tree-sitter-language-pack/lua-tags.scm +39 -0
- cecli/queries/tree-sitter-language-pack/matlab-tags.scm +10 -0
- cecli/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
- cecli/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +101 -0
- cecli/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
- cecli/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
- cecli/queries/tree-sitter-language-pack/python-tags.scm +24 -0
- cecli/queries/tree-sitter-language-pack/r-tags.scm +27 -0
- cecli/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
- cecli/queries/tree-sitter-language-pack/ruby-tags.scm +69 -0
- cecli/queries/tree-sitter-language-pack/rust-tags.scm +63 -0
- cecli/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
- cecli/queries/tree-sitter-language-pack/swift-tags.scm +54 -0
- cecli/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
- cecli/queries/tree-sitter-languages/README.md +24 -0
- cecli/queries/tree-sitter-languages/c-tags.scm +12 -0
- cecli/queries/tree-sitter-languages/c_sharp-tags.scm +52 -0
- cecli/queries/tree-sitter-languages/cpp-tags.scm +18 -0
- cecli/queries/tree-sitter-languages/dart-tags.scm +92 -0
- cecli/queries/tree-sitter-languages/elisp-tags.scm +8 -0
- cecli/queries/tree-sitter-languages/elixir-tags.scm +59 -0
- cecli/queries/tree-sitter-languages/elm-tags.scm +22 -0
- cecli/queries/tree-sitter-languages/fortran-tags.scm +18 -0
- cecli/queries/tree-sitter-languages/go-tags.scm +36 -0
- cecli/queries/tree-sitter-languages/haskell-tags.scm +5 -0
- cecli/queries/tree-sitter-languages/hcl-tags.scm +77 -0
- cecli/queries/tree-sitter-languages/java-tags.scm +26 -0
- cecli/queries/tree-sitter-languages/javascript-tags.scm +96 -0
- cecli/queries/tree-sitter-languages/julia-tags.scm +60 -0
- cecli/queries/tree-sitter-languages/kotlin-tags.scm +30 -0
- cecli/queries/tree-sitter-languages/matlab-tags.scm +10 -0
- cecli/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
- cecli/queries/tree-sitter-languages/ocaml_interface-tags.scm +104 -0
- cecli/queries/tree-sitter-languages/php-tags.scm +32 -0
- cecli/queries/tree-sitter-languages/python-tags.scm +22 -0
- cecli/queries/tree-sitter-languages/ql-tags.scm +26 -0
- cecli/queries/tree-sitter-languages/ruby-tags.scm +69 -0
- cecli/queries/tree-sitter-languages/rust-tags.scm +63 -0
- cecli/queries/tree-sitter-languages/scala-tags.scm +64 -0
- cecli/queries/tree-sitter-languages/typescript-tags.scm +44 -0
- cecli/queries/tree-sitter-languages/zig-tags.scm +20 -0
- cecli/reasoning_tags.py +82 -0
- cecli/repo.py +626 -0
- cecli/repomap.py +1368 -0
- cecli/report.py +260 -0
- cecli/resources/__init__.py +3 -0
- cecli/resources/model-metadata.json +25751 -0
- cecli/resources/model-settings.yml +2394 -0
- cecli/resources/providers.json +67 -0
- cecli/run_cmd.py +143 -0
- cecli/scrape.py +295 -0
- cecli/sendchat.py +250 -0
- cecli/sessions.py +281 -0
- cecli/special.py +203 -0
- cecli/tools/__init__.py +72 -0
- cecli/tools/command.py +103 -0
- cecli/tools/command_interactive.py +113 -0
- cecli/tools/context_manager.py +175 -0
- cecli/tools/delete_block.py +154 -0
- cecli/tools/delete_line.py +120 -0
- cecli/tools/delete_lines.py +144 -0
- cecli/tools/extract_lines.py +281 -0
- cecli/tools/finished.py +35 -0
- cecli/tools/git_branch.py +132 -0
- cecli/tools/git_diff.py +49 -0
- cecli/tools/git_log.py +43 -0
- cecli/tools/git_remote.py +39 -0
- cecli/tools/git_show.py +37 -0
- cecli/tools/git_status.py +32 -0
- cecli/tools/grep.py +242 -0
- cecli/tools/indent_lines.py +195 -0
- cecli/tools/insert_block.py +263 -0
- cecli/tools/list_changes.py +71 -0
- cecli/tools/load_skill.py +51 -0
- cecli/tools/ls.py +77 -0
- cecli/tools/remove_skill.py +51 -0
- cecli/tools/replace_all.py +113 -0
- cecli/tools/replace_line.py +135 -0
- cecli/tools/replace_lines.py +180 -0
- cecli/tools/replace_text.py +186 -0
- cecli/tools/show_numbered_context.py +137 -0
- cecli/tools/thinking.py +52 -0
- cecli/tools/undo_change.py +82 -0
- cecli/tools/update_todo_list.py +148 -0
- cecli/tools/utils/base_tool.py +64 -0
- cecli/tools/utils/helpers.py +359 -0
- cecli/tools/utils/output.py +119 -0
- cecli/tools/utils/registry.py +145 -0
- cecli/tools/view_files_matching.py +138 -0
- cecli/tools/view_files_with_symbol.py +117 -0
- cecli/tui/__init__.py +83 -0
- cecli/tui/app.py +971 -0
- cecli/tui/io.py +566 -0
- cecli/tui/styles.tcss +117 -0
- cecli/tui/widgets/__init__.py +19 -0
- cecli/tui/widgets/completion_bar.py +331 -0
- cecli/tui/widgets/file_list.py +76 -0
- cecli/tui/widgets/footer.py +165 -0
- cecli/tui/widgets/input_area.py +320 -0
- cecli/tui/widgets/key_hints.py +16 -0
- cecli/tui/widgets/output.py +354 -0
- cecli/tui/widgets/status_bar.py +279 -0
- cecli/tui/worker.py +160 -0
- cecli/urls.py +16 -0
- cecli/utils.py +499 -0
- cecli/versioncheck.py +90 -0
- cecli/voice.py +90 -0
- cecli/waiting.py +38 -0
- cecli/watch.py +316 -0
- cecli/watch_prompts.py +12 -0
- cecli/website/Gemfile +8 -0
- cecli/website/_includes/blame.md +162 -0
- cecli/website/_includes/get-started.md +22 -0
- cecli/website/_includes/help-tip.md +5 -0
- cecli/website/_includes/help.md +24 -0
- cecli/website/_includes/install.md +5 -0
- cecli/website/_includes/keys.md +4 -0
- cecli/website/_includes/model-warnings.md +67 -0
- cecli/website/_includes/multi-line.md +22 -0
- cecli/website/_includes/python-m-aider.md +5 -0
- cecli/website/_includes/recording.css +228 -0
- cecli/website/_includes/recording.md +34 -0
- cecli/website/_includes/replit-pipx.md +9 -0
- cecli/website/_includes/works-best.md +1 -0
- cecli/website/_sass/custom/custom.scss +103 -0
- cecli/website/docs/config/adv-model-settings.md +2498 -0
- cecli/website/docs/config/agent-mode.md +320 -0
- cecli/website/docs/config/aider_conf.md +548 -0
- cecli/website/docs/config/api-keys.md +90 -0
- cecli/website/docs/config/custom-commands.md +187 -0
- cecli/website/docs/config/dotenv.md +493 -0
- cecli/website/docs/config/editor.md +127 -0
- cecli/website/docs/config/mcp.md +210 -0
- cecli/website/docs/config/model-aliases.md +173 -0
- cecli/website/docs/config/options.md +890 -0
- cecli/website/docs/config/reasoning.md +210 -0
- cecli/website/docs/config/skills.md +172 -0
- cecli/website/docs/config/tui.md +126 -0
- cecli/website/docs/config.md +44 -0
- cecli/website/docs/faq.md +379 -0
- cecli/website/docs/git.md +76 -0
- cecli/website/docs/index.md +47 -0
- cecli/website/docs/install/codespaces.md +39 -0
- cecli/website/docs/install/docker.md +48 -0
- cecli/website/docs/install/optional.md +100 -0
- cecli/website/docs/install/replit.md +8 -0
- cecli/website/docs/install.md +115 -0
- cecli/website/docs/languages.md +264 -0
- cecli/website/docs/legal/contributor-agreement.md +111 -0
- cecli/website/docs/legal/privacy.md +104 -0
- cecli/website/docs/llms/anthropic.md +77 -0
- cecli/website/docs/llms/azure.md +48 -0
- cecli/website/docs/llms/bedrock.md +132 -0
- cecli/website/docs/llms/cohere.md +34 -0
- cecli/website/docs/llms/deepseek.md +32 -0
- cecli/website/docs/llms/gemini.md +49 -0
- cecli/website/docs/llms/github.md +111 -0
- cecli/website/docs/llms/groq.md +36 -0
- cecli/website/docs/llms/lm-studio.md +39 -0
- cecli/website/docs/llms/ollama.md +75 -0
- cecli/website/docs/llms/openai-compat.md +39 -0
- cecli/website/docs/llms/openai.md +58 -0
- cecli/website/docs/llms/openrouter.md +78 -0
- cecli/website/docs/llms/other.md +117 -0
- cecli/website/docs/llms/vertex.md +50 -0
- cecli/website/docs/llms/warnings.md +10 -0
- cecli/website/docs/llms/xai.md +53 -0
- cecli/website/docs/llms.md +54 -0
- cecli/website/docs/more/analytics.md +127 -0
- cecli/website/docs/more/edit-formats.md +116 -0
- cecli/website/docs/more/infinite-output.md +192 -0
- cecli/website/docs/more-info.md +8 -0
- cecli/website/docs/recordings/auto-accept-architect.md +31 -0
- cecli/website/docs/recordings/dont-drop-original-read-files.md +35 -0
- cecli/website/docs/recordings/index.md +21 -0
- cecli/website/docs/recordings/model-accepts-settings.md +69 -0
- cecli/website/docs/recordings/tree-sitter-language-pack.md +80 -0
- cecli/website/docs/repomap.md +112 -0
- cecli/website/docs/scripting.md +100 -0
- cecli/website/docs/sessions.md +213 -0
- cecli/website/docs/troubleshooting/aider-not-found.md +24 -0
- cecli/website/docs/troubleshooting/edit-errors.md +76 -0
- cecli/website/docs/troubleshooting/imports.md +62 -0
- cecli/website/docs/troubleshooting/models-and-keys.md +54 -0
- cecli/website/docs/troubleshooting/support.md +79 -0
- cecli/website/docs/troubleshooting/token-limits.md +96 -0
- cecli/website/docs/troubleshooting/warnings.md +12 -0
- cecli/website/docs/troubleshooting.md +11 -0
- cecli/website/docs/usage/browser.md +57 -0
- cecli/website/docs/usage/caching.md +49 -0
- cecli/website/docs/usage/commands.md +133 -0
- cecli/website/docs/usage/conventions.md +119 -0
- cecli/website/docs/usage/copypaste.md +136 -0
- cecli/website/docs/usage/images-urls.md +48 -0
- cecli/website/docs/usage/lint-test.md +118 -0
- cecli/website/docs/usage/modes.md +211 -0
- cecli/website/docs/usage/not-code.md +179 -0
- cecli/website/docs/usage/notifications.md +87 -0
- cecli/website/docs/usage/tips.md +79 -0
- cecli/website/docs/usage/tutorials.md +30 -0
- cecli/website/docs/usage/voice.md +121 -0
- cecli/website/docs/usage/watch.md +294 -0
- cecli/website/docs/usage.md +102 -0
- cecli/website/share/index.md +101 -0
- cecli_dev-0.93.1.dist-info/METADATA +549 -0
- cecli_dev-0.93.1.dist-info/RECORD +366 -0
- cecli_dev-0.93.1.dist-info/WHEEL +5 -0
- cecli_dev-0.93.1.dist-info/entry_points.txt +4 -0
- cecli_dev-0.93.1.dist-info/licenses/LICENSE.txt +202 -0
- cecli_dev-0.93.1.dist-info/top_level.txt +1 -0
cecli/coders/shell.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
shell_cmd_prompt = """
|
|
2
|
+
4. *Concisely* suggest any shell commands the user might want to run in ```bash blocks.
|
|
3
|
+
|
|
4
|
+
Just suggest shell commands this way, not example code.
|
|
5
|
+
Only suggest complete shell commands that are ready to execute, without placeholders.
|
|
6
|
+
Only suggest at most a few shell commands at a time, not more than 1-3, one per line.
|
|
7
|
+
Do not suggest multi-line shell commands.
|
|
8
|
+
All shell commands will run from the root directory of the user's project.
|
|
9
|
+
|
|
10
|
+
Use the appropriate shell based on the user's system info:
|
|
11
|
+
{platform}
|
|
12
|
+
Examples of when to suggest shell commands:
|
|
13
|
+
|
|
14
|
+
- If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.
|
|
15
|
+
- If you changed a CLI program, suggest the command to run it to see the new behavior.
|
|
16
|
+
- If you added a test, suggest how to run it with the testing tool used by the project.
|
|
17
|
+
- Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.
|
|
18
|
+
- If your code changes add new dependencies, suggest the command to install them.
|
|
19
|
+
- Etc.
|
|
20
|
+
""" # noqa
|
|
21
|
+
|
|
22
|
+
no_shell_cmd_prompt = """
|
|
23
|
+
Keep in mind these details about the user's platform and environment:
|
|
24
|
+
{platform}
|
|
25
|
+
""" # noqa
|
|
26
|
+
|
|
27
|
+
shell_cmd_reminder = """
|
|
28
|
+
Examples of when to suggest shell commands:
|
|
29
|
+
|
|
30
|
+
- If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.
|
|
31
|
+
- If you changed a CLI program, suggest the command to run it to see the new behavior.
|
|
32
|
+
- If you added a test, suggest how to run it with the testing tool used by the project.
|
|
33
|
+
- Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.
|
|
34
|
+
- If your code changes add new dependencies, suggest the command to install them.
|
|
35
|
+
- Etc.
|
|
36
|
+
|
|
37
|
+
""" # noqa
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from cecli import diffs
|
|
2
|
+
|
|
3
|
+
from ..dump import dump # noqa: F401
|
|
4
|
+
from .base_coder import Coder
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class SingleWholeFileFunctionCoder(Coder):
|
|
8
|
+
edit_format = "func"
|
|
9
|
+
prompt_format = "single_wholefile_func"
|
|
10
|
+
|
|
11
|
+
functions = [
|
|
12
|
+
dict(
|
|
13
|
+
name="write_file",
|
|
14
|
+
description="write new content into the file",
|
|
15
|
+
# strict=True,
|
|
16
|
+
parameters=dict(
|
|
17
|
+
type="object",
|
|
18
|
+
properties=dict(
|
|
19
|
+
explanation=dict(
|
|
20
|
+
type="string",
|
|
21
|
+
description=(
|
|
22
|
+
"Step by step plan for the changes to be made to the code (future"
|
|
23
|
+
" tense, markdown format)"
|
|
24
|
+
),
|
|
25
|
+
),
|
|
26
|
+
content=dict(
|
|
27
|
+
type="string",
|
|
28
|
+
description="Content to write to the file",
|
|
29
|
+
),
|
|
30
|
+
),
|
|
31
|
+
required=["explanation", "content"],
|
|
32
|
+
additionalProperties=False,
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
def __init__(self, *args, **kwargs):
|
|
38
|
+
super().__init__(*args, **kwargs)
|
|
39
|
+
|
|
40
|
+
def add_assistant_reply_to_cur_messages(self, edited):
|
|
41
|
+
if edited:
|
|
42
|
+
self.cur_messages += [
|
|
43
|
+
dict(role="assistant", content=self.gpt_prompts.redacted_edit_message)
|
|
44
|
+
]
|
|
45
|
+
else:
|
|
46
|
+
self.cur_messages += [dict(role="assistant", content=self.partial_response_content)]
|
|
47
|
+
|
|
48
|
+
def render_incremental_response(self, final=False):
|
|
49
|
+
res = ""
|
|
50
|
+
if self.partial_response_content:
|
|
51
|
+
res += self.partial_response_content
|
|
52
|
+
|
|
53
|
+
args = self.parse_partial_args()
|
|
54
|
+
|
|
55
|
+
if not args:
|
|
56
|
+
return ""
|
|
57
|
+
|
|
58
|
+
for k, v in args.items():
|
|
59
|
+
res += "\n"
|
|
60
|
+
res += f"{k}:\n"
|
|
61
|
+
res += v
|
|
62
|
+
|
|
63
|
+
return res
|
|
64
|
+
|
|
65
|
+
def live_diffs(self, fname, content, final):
|
|
66
|
+
lines = content.splitlines(keepends=True)
|
|
67
|
+
|
|
68
|
+
# ending an existing block
|
|
69
|
+
full_path = self.abs_root_path(fname)
|
|
70
|
+
|
|
71
|
+
content = self.io.read_text(full_path)
|
|
72
|
+
if content is None:
|
|
73
|
+
orig_lines = []
|
|
74
|
+
else:
|
|
75
|
+
orig_lines = content.splitlines()
|
|
76
|
+
|
|
77
|
+
show_diff = diffs.diff_partial_update(
|
|
78
|
+
orig_lines,
|
|
79
|
+
lines,
|
|
80
|
+
final,
|
|
81
|
+
fname=fname,
|
|
82
|
+
).splitlines()
|
|
83
|
+
|
|
84
|
+
return "\n".join(show_diff)
|
|
85
|
+
|
|
86
|
+
def get_edits(self):
|
|
87
|
+
chat_files = self.get_inchat_relative_files()
|
|
88
|
+
assert len(chat_files) == 1, chat_files
|
|
89
|
+
|
|
90
|
+
args = self.parse_partial_args()
|
|
91
|
+
if not args:
|
|
92
|
+
return []
|
|
93
|
+
|
|
94
|
+
res = chat_files[0], args["content"]
|
|
95
|
+
dump(res)
|
|
96
|
+
return [res]
|
|
97
|
+
|
|
98
|
+
def apply_edits(self, edits):
|
|
99
|
+
for path, content in edits:
|
|
100
|
+
full_path = self.abs_root_path(path)
|
|
101
|
+
self.io.write_text(full_path, content)
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import difflib
|
|
2
|
+
from itertools import groupby
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from ..dump import dump # noqa: F401
|
|
6
|
+
from .base_coder import Coder
|
|
7
|
+
from .search_replace import (
|
|
8
|
+
SearchTextNotUnique,
|
|
9
|
+
all_preprocs,
|
|
10
|
+
diff_lines,
|
|
11
|
+
flexible_search_and_replace,
|
|
12
|
+
search_and_replace,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
no_match_error = """UnifiedDiffNoMatch: hunk failed to apply!
|
|
16
|
+
|
|
17
|
+
{path} does not contain lines that match the diff you provided!
|
|
18
|
+
Try again.
|
|
19
|
+
DO NOT skip blank lines, comments, docstrings, etc!
|
|
20
|
+
The diff needs to apply cleanly to the lines in {path}!
|
|
21
|
+
|
|
22
|
+
{path} does not contain these {num_lines} exact lines in a row:
|
|
23
|
+
```
|
|
24
|
+
{original}```
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
not_unique_error = """UnifiedDiffNotUnique: hunk failed to apply!
|
|
29
|
+
|
|
30
|
+
{path} contains multiple sets of lines that match the diff you provided!
|
|
31
|
+
Try again.
|
|
32
|
+
Use additional ` ` lines to provide context that uniquely indicates which code needs to be changed.
|
|
33
|
+
The diff needs to apply to a unique set of lines in {path}!
|
|
34
|
+
|
|
35
|
+
{path} contains multiple copies of these {num_lines} lines:
|
|
36
|
+
```
|
|
37
|
+
{original}```
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
other_hunks_applied = (
|
|
41
|
+
"Note: some hunks did apply successfully. See the updated source code shown above.\n\n"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class UnifiedDiffCoder(Coder):
|
|
46
|
+
"""A coder that uses unified diff format for code modifications."""
|
|
47
|
+
|
|
48
|
+
edit_format = "udiff"
|
|
49
|
+
prompt_format = "udiff"
|
|
50
|
+
|
|
51
|
+
def get_edits(self):
|
|
52
|
+
content = self.partial_response_content
|
|
53
|
+
|
|
54
|
+
# might raise ValueError for malformed ORIG/UPD blocks
|
|
55
|
+
raw_edits = list(find_diffs(content))
|
|
56
|
+
|
|
57
|
+
last_path = None
|
|
58
|
+
edits = []
|
|
59
|
+
for path, hunk in raw_edits:
|
|
60
|
+
if path:
|
|
61
|
+
last_path = path
|
|
62
|
+
else:
|
|
63
|
+
path = last_path
|
|
64
|
+
edits.append((path, hunk))
|
|
65
|
+
|
|
66
|
+
return edits
|
|
67
|
+
|
|
68
|
+
def apply_edits(self, edits):
|
|
69
|
+
seen = set()
|
|
70
|
+
uniq = []
|
|
71
|
+
for path, hunk in edits:
|
|
72
|
+
hunk = normalize_hunk(hunk)
|
|
73
|
+
if not hunk:
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
this = [path + "\n"] + hunk
|
|
77
|
+
this = "".join(this)
|
|
78
|
+
|
|
79
|
+
if this in seen:
|
|
80
|
+
continue
|
|
81
|
+
seen.add(this)
|
|
82
|
+
|
|
83
|
+
uniq.append((path, hunk))
|
|
84
|
+
|
|
85
|
+
errors = []
|
|
86
|
+
for path, hunk in uniq:
|
|
87
|
+
full_path = self.abs_root_path(path)
|
|
88
|
+
content = self.io.read_text(full_path)
|
|
89
|
+
|
|
90
|
+
original, _ = hunk_to_before_after(hunk)
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
content = do_replace(full_path, content, hunk)
|
|
94
|
+
except SearchTextNotUnique:
|
|
95
|
+
errors.append(
|
|
96
|
+
not_unique_error.format(
|
|
97
|
+
path=path, original=original, num_lines=len(original.splitlines())
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
if not content:
|
|
103
|
+
errors.append(
|
|
104
|
+
no_match_error.format(
|
|
105
|
+
path=path, original=original, num_lines=len(original.splitlines())
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
continue
|
|
109
|
+
|
|
110
|
+
# SUCCESS!
|
|
111
|
+
self.io.write_text(full_path, content)
|
|
112
|
+
|
|
113
|
+
if errors:
|
|
114
|
+
errors = "\n\n".join(errors)
|
|
115
|
+
if len(errors) < len(uniq):
|
|
116
|
+
errors += other_hunks_applied
|
|
117
|
+
raise ValueError(errors)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def do_replace(fname, content, hunk):
|
|
121
|
+
fname = Path(fname)
|
|
122
|
+
|
|
123
|
+
before_text, after_text = hunk_to_before_after(hunk)
|
|
124
|
+
|
|
125
|
+
# does it want to make a new file?
|
|
126
|
+
if not fname.exists() and not before_text.strip():
|
|
127
|
+
fname.touch()
|
|
128
|
+
content = ""
|
|
129
|
+
|
|
130
|
+
if content is None:
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
# TODO: handle inserting into new file
|
|
134
|
+
if not before_text.strip():
|
|
135
|
+
# append to existing file, or start a new file
|
|
136
|
+
new_content = content + after_text
|
|
137
|
+
return new_content
|
|
138
|
+
|
|
139
|
+
new_content = None
|
|
140
|
+
|
|
141
|
+
new_content = apply_hunk(content, hunk)
|
|
142
|
+
if new_content:
|
|
143
|
+
return new_content
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def collapse_repeats(s):
|
|
147
|
+
return "".join(k for k, g in groupby(s))
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def apply_hunk(content, hunk):
|
|
151
|
+
before_text, after_text = hunk_to_before_after(hunk)
|
|
152
|
+
|
|
153
|
+
res = directly_apply_hunk(content, hunk)
|
|
154
|
+
if res:
|
|
155
|
+
return res
|
|
156
|
+
|
|
157
|
+
hunk = make_new_lines_explicit(content, hunk)
|
|
158
|
+
|
|
159
|
+
# just consider space vs not-space
|
|
160
|
+
ops = "".join([line[0] for line in hunk])
|
|
161
|
+
ops = ops.replace("-", "x")
|
|
162
|
+
ops = ops.replace("+", "x")
|
|
163
|
+
ops = ops.replace("\n", " ")
|
|
164
|
+
|
|
165
|
+
cur_op = " "
|
|
166
|
+
section = []
|
|
167
|
+
sections = []
|
|
168
|
+
|
|
169
|
+
for i in range(len(ops)):
|
|
170
|
+
op = ops[i]
|
|
171
|
+
if op != cur_op:
|
|
172
|
+
sections.append(section)
|
|
173
|
+
section = []
|
|
174
|
+
cur_op = op
|
|
175
|
+
section.append(hunk[i])
|
|
176
|
+
|
|
177
|
+
sections.append(section)
|
|
178
|
+
if cur_op != " ":
|
|
179
|
+
sections.append([])
|
|
180
|
+
|
|
181
|
+
all_done = True
|
|
182
|
+
for i in range(2, len(sections), 2):
|
|
183
|
+
preceding_context = sections[i - 2]
|
|
184
|
+
changes = sections[i - 1]
|
|
185
|
+
following_context = sections[i]
|
|
186
|
+
|
|
187
|
+
res = apply_partial_hunk(content, preceding_context, changes, following_context)
|
|
188
|
+
if res:
|
|
189
|
+
content = res
|
|
190
|
+
else:
|
|
191
|
+
all_done = False
|
|
192
|
+
# FAILED!
|
|
193
|
+
# this_hunk = preceding_context + changes + following_context
|
|
194
|
+
break
|
|
195
|
+
|
|
196
|
+
if all_done:
|
|
197
|
+
return content
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def flexi_just_search_and_replace(texts):
|
|
201
|
+
strategies = [
|
|
202
|
+
(search_and_replace, all_preprocs),
|
|
203
|
+
]
|
|
204
|
+
|
|
205
|
+
return flexible_search_and_replace(texts, strategies)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def make_new_lines_explicit(content, hunk):
|
|
209
|
+
before, after = hunk_to_before_after(hunk)
|
|
210
|
+
|
|
211
|
+
diff = diff_lines(before, content)
|
|
212
|
+
|
|
213
|
+
back_diff = []
|
|
214
|
+
for line in diff:
|
|
215
|
+
if line[0] == "+":
|
|
216
|
+
continue
|
|
217
|
+
# if line[0] == "-":
|
|
218
|
+
# line = "+" + line[1:]
|
|
219
|
+
|
|
220
|
+
back_diff.append(line)
|
|
221
|
+
|
|
222
|
+
new_before = directly_apply_hunk(before, back_diff)
|
|
223
|
+
if not new_before:
|
|
224
|
+
return hunk
|
|
225
|
+
|
|
226
|
+
if len(new_before.strip()) < 10:
|
|
227
|
+
return hunk
|
|
228
|
+
|
|
229
|
+
before = before.splitlines(keepends=True)
|
|
230
|
+
new_before = new_before.splitlines(keepends=True)
|
|
231
|
+
after = after.splitlines(keepends=True)
|
|
232
|
+
|
|
233
|
+
if len(new_before) < len(before) * 0.66:
|
|
234
|
+
return hunk
|
|
235
|
+
|
|
236
|
+
new_hunk = difflib.unified_diff(new_before, after, n=max(len(new_before), len(after)))
|
|
237
|
+
new_hunk = list(new_hunk)[3:]
|
|
238
|
+
|
|
239
|
+
return new_hunk
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def cleanup_pure_whitespace_lines(lines):
|
|
243
|
+
res = [
|
|
244
|
+
line if line.strip() else line[-(len(line) - len(line.rstrip("\r\n")))] for line in lines
|
|
245
|
+
]
|
|
246
|
+
return res
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def normalize_hunk(hunk):
|
|
250
|
+
before, after = hunk_to_before_after(hunk, lines=True)
|
|
251
|
+
|
|
252
|
+
before = cleanup_pure_whitespace_lines(before)
|
|
253
|
+
after = cleanup_pure_whitespace_lines(after)
|
|
254
|
+
|
|
255
|
+
diff = difflib.unified_diff(before, after, n=max(len(before), len(after)))
|
|
256
|
+
diff = list(diff)[3:]
|
|
257
|
+
return diff
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def directly_apply_hunk(content, hunk):
|
|
261
|
+
before, after = hunk_to_before_after(hunk)
|
|
262
|
+
|
|
263
|
+
if not before:
|
|
264
|
+
return
|
|
265
|
+
|
|
266
|
+
before_lines, _ = hunk_to_before_after(hunk, lines=True)
|
|
267
|
+
before_lines = "".join([line.strip() for line in before_lines])
|
|
268
|
+
|
|
269
|
+
# Refuse to do a repeated search and replace on a tiny bit of non-whitespace context
|
|
270
|
+
if len(before_lines) < 10 and content.count(before) > 1:
|
|
271
|
+
return
|
|
272
|
+
|
|
273
|
+
try:
|
|
274
|
+
new_content = flexi_just_search_and_replace([before, after, content])
|
|
275
|
+
except SearchTextNotUnique:
|
|
276
|
+
new_content = None
|
|
277
|
+
|
|
278
|
+
return new_content
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def apply_partial_hunk(content, preceding_context, changes, following_context):
|
|
282
|
+
len_prec = len(preceding_context)
|
|
283
|
+
len_foll = len(following_context)
|
|
284
|
+
|
|
285
|
+
use_all = len_prec + len_foll
|
|
286
|
+
|
|
287
|
+
# if there is a - in the hunk, we can go all the way to `use=0`
|
|
288
|
+
for drop in range(use_all + 1):
|
|
289
|
+
use = use_all - drop
|
|
290
|
+
|
|
291
|
+
for use_prec in range(len_prec, -1, -1):
|
|
292
|
+
if use_prec > use:
|
|
293
|
+
continue
|
|
294
|
+
|
|
295
|
+
use_foll = use - use_prec
|
|
296
|
+
if use_foll > len_foll:
|
|
297
|
+
continue
|
|
298
|
+
|
|
299
|
+
if use_prec:
|
|
300
|
+
this_prec = preceding_context[-use_prec:]
|
|
301
|
+
else:
|
|
302
|
+
this_prec = []
|
|
303
|
+
|
|
304
|
+
this_foll = following_context[:use_foll]
|
|
305
|
+
|
|
306
|
+
res = directly_apply_hunk(content, this_prec + changes + this_foll)
|
|
307
|
+
if res:
|
|
308
|
+
return res
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def find_diffs(content):
|
|
312
|
+
# We can always fence with triple-quotes, because all the udiff content
|
|
313
|
+
# is prefixed with +/-/space.
|
|
314
|
+
|
|
315
|
+
if not content.endswith("\n"):
|
|
316
|
+
content = content + "\n"
|
|
317
|
+
|
|
318
|
+
lines = content.splitlines(keepends=True)
|
|
319
|
+
line_num = 0
|
|
320
|
+
edits = []
|
|
321
|
+
while line_num < len(lines):
|
|
322
|
+
while line_num < len(lines):
|
|
323
|
+
line = lines[line_num]
|
|
324
|
+
if line.startswith("```diff"):
|
|
325
|
+
line_num, these_edits = process_fenced_block(lines, line_num + 1)
|
|
326
|
+
edits += these_edits
|
|
327
|
+
break
|
|
328
|
+
line_num += 1
|
|
329
|
+
|
|
330
|
+
# For now, just take 1!
|
|
331
|
+
# edits = edits[:1]
|
|
332
|
+
|
|
333
|
+
return edits
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def process_fenced_block(lines, start_line_num):
|
|
337
|
+
for line_num in range(start_line_num, len(lines)):
|
|
338
|
+
line = lines[line_num]
|
|
339
|
+
if line.startswith("```"):
|
|
340
|
+
break
|
|
341
|
+
|
|
342
|
+
block = lines[start_line_num:line_num]
|
|
343
|
+
block.append("@@ @@")
|
|
344
|
+
|
|
345
|
+
if block[0].startswith("--- ") and block[1].startswith("+++ "):
|
|
346
|
+
# Extract the file path, considering that it might contain spaces
|
|
347
|
+
a_fname = block[0][4:].strip()
|
|
348
|
+
b_fname = block[1][4:].strip()
|
|
349
|
+
|
|
350
|
+
# Check if standard git diff prefixes are present (or /dev/null) and strip them
|
|
351
|
+
if (a_fname.startswith("a/") or a_fname == "/dev/null") and b_fname.startswith("b/"):
|
|
352
|
+
fname = b_fname[2:]
|
|
353
|
+
else:
|
|
354
|
+
# Otherwise, assume the path is as intended
|
|
355
|
+
fname = b_fname
|
|
356
|
+
|
|
357
|
+
block = block[2:]
|
|
358
|
+
else:
|
|
359
|
+
fname = None
|
|
360
|
+
|
|
361
|
+
edits = []
|
|
362
|
+
|
|
363
|
+
keeper = False
|
|
364
|
+
hunk = []
|
|
365
|
+
op = " "
|
|
366
|
+
for line in block:
|
|
367
|
+
hunk.append(line)
|
|
368
|
+
if len(line) < 2:
|
|
369
|
+
continue
|
|
370
|
+
|
|
371
|
+
if line.startswith("+++ ") and hunk[-2].startswith("--- "):
|
|
372
|
+
if hunk[-3] == "\n":
|
|
373
|
+
hunk = hunk[:-3]
|
|
374
|
+
else:
|
|
375
|
+
hunk = hunk[:-2]
|
|
376
|
+
|
|
377
|
+
edits.append((fname, hunk))
|
|
378
|
+
hunk = []
|
|
379
|
+
keeper = False
|
|
380
|
+
|
|
381
|
+
fname = line[4:].strip()
|
|
382
|
+
continue
|
|
383
|
+
|
|
384
|
+
op = line[0]
|
|
385
|
+
if op in "-+":
|
|
386
|
+
keeper = True
|
|
387
|
+
continue
|
|
388
|
+
if op != "@":
|
|
389
|
+
continue
|
|
390
|
+
if not keeper:
|
|
391
|
+
hunk = []
|
|
392
|
+
continue
|
|
393
|
+
|
|
394
|
+
hunk = hunk[:-1]
|
|
395
|
+
edits.append((fname, hunk))
|
|
396
|
+
hunk = []
|
|
397
|
+
keeper = False
|
|
398
|
+
|
|
399
|
+
return line_num + 1, edits
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def hunk_to_before_after(hunk, lines=False):
|
|
403
|
+
before = []
|
|
404
|
+
after = []
|
|
405
|
+
op = " "
|
|
406
|
+
for line in hunk:
|
|
407
|
+
if len(line) < 2:
|
|
408
|
+
op = " "
|
|
409
|
+
line = line
|
|
410
|
+
else:
|
|
411
|
+
op = line[0]
|
|
412
|
+
line = line[1:]
|
|
413
|
+
|
|
414
|
+
if op == " ":
|
|
415
|
+
before.append(line)
|
|
416
|
+
after.append(line)
|
|
417
|
+
elif op == "-":
|
|
418
|
+
before.append(line)
|
|
419
|
+
elif op == "+":
|
|
420
|
+
after.append(line)
|
|
421
|
+
|
|
422
|
+
if lines:
|
|
423
|
+
return before, after
|
|
424
|
+
|
|
425
|
+
before = "".join(before)
|
|
426
|
+
after = "".join(after)
|
|
427
|
+
|
|
428
|
+
return before, after
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .udiff_coder import UnifiedDiffCoder
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class UnifiedDiffSimpleCoder(UnifiedDiffCoder):
|
|
5
|
+
"""
|
|
6
|
+
A coder that uses unified diff format for code modifications.
|
|
7
|
+
This variant uses a simpler prompt that doesn't mention specific
|
|
8
|
+
diff rules like using `@@ ... @@` lines or avoiding line numbers.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
edit_format = "udiff-simple"
|
|
12
|
+
prompt_format = "udiff_simple"
|