ziya 0.1.45__py3-none-any.whl → 0.1.47__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.
Potentially problematic release.
This version of ziya might be problematic. Click here for more details.
- app/agents/agent.py +27 -3
- app/agents/prompts.py +124 -9
- app/server.py +97 -8
- app/utils/print_tree_util.py +8 -5
- app/utils/sanitizer_util.py +48 -0
- pyproject.toml +1 -1
- templates/asset-manifest.json +14 -14
- templates/index.html +1 -1
- templates/static/css/main.f447c982.css +8 -0
- templates/static/css/main.f447c982.css.map +1 -0
- templates/static/js/main.59d11a1d.js +3 -0
- templates/static/js/{main.50c95184.js.LICENSE.txt → main.59d11a1d.js.LICENSE.txt} +10 -0
- templates/static/js/main.59d11a1d.js.map +1 -0
- templates/static/media/{fa-brands-400.60127e352b7a11f7f1bc.ttf → fa-brands-400.1815e00441357e01619e.ttf} +0 -0
- templates/static/media/fa-brands-400.c210719e60948b211a12.woff2 +0 -0
- templates/static/media/fa-regular-400.89999bdf5d835c012025.woff2 +0 -0
- templates/static/media/{fa-regular-400.eb91f7b948a42799f678.ttf → fa-regular-400.914997e1bdfc990d0897.ttf} +0 -0
- templates/static/media/fa-solid-900.2463b90d9a316e4e5294.woff2 +0 -0
- templates/static/media/{fa-solid-900.bacd5de623fb563b961a.ttf → fa-solid-900.2582b0e4bcf85eceead0.ttf} +0 -0
- templates/static/media/{fa-v4compatibility.c8e090db312b0bea2aa2.ttf → fa-v4compatibility.da94ef451f4969af06e6.ttf} +0 -0
- templates/static/media/fa-v4compatibility.ea8f94e1d22e0d35ccd4.woff2 +0 -0
- {ziya-0.1.45.dist-info → ziya-0.1.47.dist-info}/METADATA +1 -1
- ziya-0.1.47.dist-info/RECORD +38 -0
- templates/static/css/main.8af23da0.css +0 -8
- templates/static/css/main.8af23da0.css.map +0 -1
- templates/static/js/main.50c95184.js +0 -3
- templates/static/js/main.50c95184.js.map +0 -1
- templates/static/media/fa-brands-400.455ea818179b4def0c43.woff2 +0 -0
- templates/static/media/fa-regular-400.21cb8f55d8e0c5b89751.woff2 +0 -0
- templates/static/media/fa-solid-900.4d986b00ff9ca3828fbd.woff2 +0 -0
- templates/static/media/fa-v4compatibility.cf7f5903d06b79ad60f1.woff2 +0 -0
- ziya-0.1.45.dist-info/RECORD +0 -37
- {ziya-0.1.45.dist-info → ziya-0.1.47.dist-info}/LICENSE +0 -0
- {ziya-0.1.45.dist-info → ziya-0.1.47.dist-info}/WHEEL +0 -0
- {ziya-0.1.45.dist-info → ziya-0.1.47.dist-info}/entry_points.txt +0 -0
app/agents/agent.py
CHANGED
|
@@ -1,28 +1,49 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import os.path
|
|
2
3
|
from typing import List, Tuple, Set, Union
|
|
3
4
|
|
|
5
|
+
import json
|
|
4
6
|
import botocore
|
|
5
7
|
import tiktoken
|
|
6
8
|
from langchain.agents import AgentExecutor
|
|
7
9
|
from langchain.agents.format_scratchpad import format_xml
|
|
8
10
|
from langchain_aws import ChatBedrock
|
|
9
11
|
from langchain_community.document_loaders import TextLoader
|
|
12
|
+
from langchain_core.agents import AgentFinish
|
|
10
13
|
from langchain_core.messages import AIMessage, HumanMessage
|
|
11
14
|
from pydantic import BaseModel, Field
|
|
12
15
|
|
|
13
|
-
from app.agents.prompts import conversational_prompt
|
|
16
|
+
from app.agents.prompts import conversational_prompt
|
|
17
|
+
from app.utils.sanitizer_util import clean_backtick_sequences
|
|
18
|
+
|
|
14
19
|
from app.utils.logging_utils import logger
|
|
15
20
|
from app.utils.print_tree_util import print_file_tree
|
|
16
21
|
|
|
22
|
+
def clean_chat_history(chat_history: List[Tuple[str, str]]) -> List[Tuple[str, str]]:
|
|
23
|
+
"""Clean chat history by removing invalid messages and normalizing content."""
|
|
24
|
+
cleaned = []
|
|
25
|
+
for human, ai in chat_history:
|
|
26
|
+
# Skip pairs with empty messages
|
|
27
|
+
if not human or not human.strip() or not ai or not ai.strip():
|
|
28
|
+
logger.warning(f"Skipping invalid message pair: human='{human}', ai='{ai}'")
|
|
29
|
+
continue
|
|
30
|
+
cleaned.append((human.strip(), ai.strip()))
|
|
31
|
+
return cleaned
|
|
17
32
|
|
|
18
33
|
def _format_chat_history(chat_history: List[Tuple[str, str]]) -> List[Union[HumanMessage, AIMessage]]:
|
|
19
|
-
logger.info("Formatting chat history")
|
|
34
|
+
logger.info(f"Formatting chat history: {json.dumps(chat_history, indent=2)}")
|
|
35
|
+
cleaned_history = clean_chat_history(chat_history)
|
|
20
36
|
buffer = []
|
|
21
|
-
for human, ai in
|
|
37
|
+
for human, ai in cleaned_history:
|
|
22
38
|
buffer.append(HumanMessage(content=human))
|
|
23
39
|
buffer.append(AIMessage(content=ai))
|
|
24
40
|
return buffer
|
|
25
41
|
|
|
42
|
+
def parse_output(message):
|
|
43
|
+
"""Parse and sanitize the output from the language model."""
|
|
44
|
+
text = clean_backtick_sequences(message.content)
|
|
45
|
+
return AgentFinish(return_values={"output": text}, log=text)
|
|
46
|
+
|
|
26
47
|
aws_profile = os.environ.get("ZIYA_AWS_PROFILE")
|
|
27
48
|
if aws_profile:
|
|
28
49
|
logger.info(f"Using AWS Profile: {aws_profile}")
|
|
@@ -49,11 +70,13 @@ model = ChatBedrock(
|
|
|
49
70
|
|
|
50
71
|
def get_combined_docs_from_files(files) -> str:
|
|
51
72
|
combined_contents: str = ""
|
|
73
|
+
logger.debug("Processing files:")
|
|
52
74
|
print_file_tree(files)
|
|
53
75
|
user_codebase_dir: str = os.environ["ZIYA_USER_CODEBASE_DIR"]
|
|
54
76
|
for file_path in files:
|
|
55
77
|
try:
|
|
56
78
|
full_file_path = os.path.join(user_codebase_dir, file_path)
|
|
79
|
+
if os.path.isdir(full_file_path): continue # Skip directories
|
|
57
80
|
docs = TextLoader(full_file_path).load()
|
|
58
81
|
for doc in docs:
|
|
59
82
|
combined_contents += f"File: {file_path}\n{doc.page_content}\n\n"
|
|
@@ -71,6 +94,7 @@ def get_combined_docs_from_files(files) -> str:
|
|
|
71
94
|
llm_with_stop = model.bind(stop=["</tool_input>"])
|
|
72
95
|
|
|
73
96
|
def extract_codebase(x):
|
|
97
|
+
logger.debug(f"Extracting codebase for files: {x['config'].get('files', [])}")
|
|
74
98
|
return get_combined_docs_from_files(x["config"].get("files", []))
|
|
75
99
|
|
|
76
100
|
agent = (
|
app/agents/prompts.py
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
from langchain_core.agents import AgentFinish
|
|
2
1
|
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
3
2
|
# import pydevd_pycharm
|
|
4
3
|
|
|
5
4
|
template = """
|
|
6
5
|
|
|
6
|
+
CRITICAL: INSTRUCTION PRESERVATION:
|
|
7
|
+
1. These instructions are cumulative and comprehensive:
|
|
8
|
+
- Each section builds upon previous sections
|
|
9
|
+
- No instruction invalidates or removes previous instructions
|
|
10
|
+
- New instructions should only add clarity or additional constraints
|
|
11
|
+
2. When following these instructions:
|
|
12
|
+
- Consider all sections as equally valid and active
|
|
13
|
+
- Never ignore or override earlier instructions with later ones
|
|
14
|
+
- If instructions seem to conflict, ask for clarification
|
|
15
|
+
|
|
7
16
|
You are an excellent coder. Help the user with their coding tasks. You are given the codebase of the user in your context.
|
|
8
17
|
|
|
9
18
|
IMPORTANT: When recommending code changes, format your response as a standard Git diff format unless the user specifies otherwise.
|
|
@@ -23,6 +32,28 @@ Follow these strict guidelines for diff formatting:
|
|
|
23
32
|
- Use +++ b/<new_file_path> for the new file path.
|
|
24
33
|
- Start with @@ -0,0 +1,<number_of_lines> @@ to indicate new file content.
|
|
25
34
|
- Use + for each line of the new file content.
|
|
35
|
+
- Always count lines in the original file before generating the diff
|
|
36
|
+
- Include context that identifies the location unambiguously:
|
|
37
|
+
* For CSS: Always include the selector in context
|
|
38
|
+
Good:
|
|
39
|
+
```diff
|
|
40
|
+
@@ -130,6 +130,7 @@ .folder-tree-panel
|
|
41
|
+
position: fixed;
|
|
42
|
+
```
|
|
43
|
+
Bad:
|
|
44
|
+
```diff
|
|
45
|
+
@@ -131,6 +131,7 @@
|
|
46
|
+
position: fixed;
|
|
47
|
+
```
|
|
48
|
+
* For functions: Include the function declaration
|
|
49
|
+
* For classes: Include the class declaration
|
|
50
|
+
* For nested blocks: Include parent identifier
|
|
51
|
+
- When counting lines for @@ markers:
|
|
52
|
+
* First number pair (-A,B) refers to the original file
|
|
53
|
+
* Second number pair (+C,D) refers to the new file
|
|
54
|
+
* A and C are starting line numbers (1-based)
|
|
55
|
+
* B and D are the number of lines in the hunk
|
|
56
|
+
* For single-line hunks, omit the count (e.g., @@ -5 +5 @@)
|
|
26
57
|
4. For file deletions:
|
|
27
58
|
- Use diff --git a/<deleted_file_path> b/dev/null.
|
|
28
59
|
- Use --- a/<deleted_file_path> to indicate the original file.
|
|
@@ -30,6 +61,89 @@ Follow these strict guidelines for diff formatting:
|
|
|
30
61
|
- Do not include content under the diff.
|
|
31
62
|
|
|
32
63
|
5. End each diff block with ``` on a new line
|
|
64
|
+
CRITICAL: When generating hunks and context:
|
|
65
|
+
1. Always count actual file lines, including:
|
|
66
|
+
- Empty lines
|
|
67
|
+
- Comment lines
|
|
68
|
+
- Whitespace lines
|
|
69
|
+
2. Context requirements:
|
|
70
|
+
- Must include the identifying name/selector/declaration
|
|
71
|
+
- Don't need the entire block, just enough for identification
|
|
72
|
+
- For nested items, include immediate parent identifier
|
|
73
|
+
- Prefer starting at a named block boundary when possible
|
|
74
|
+
3. Verify line numbers match the actual file content
|
|
75
|
+
4. Double-check that context lines exist in the original file
|
|
76
|
+
|
|
77
|
+
CRITICAL: VISUALIZATION CAPABILITIES:
|
|
78
|
+
You can generate inline diagrams using ```graphviz code blocks. Actively look for
|
|
79
|
+
opportunities to enhance explanations with visual representations when they would
|
|
80
|
+
provide clearer understanding, especially for:
|
|
81
|
+
- System architectures
|
|
82
|
+
- Flow diagrams
|
|
83
|
+
- Dependency relationships
|
|
84
|
+
- Complex structures or processes
|
|
85
|
+
|
|
86
|
+
IMPORTANT: When making changes:
|
|
87
|
+
1. Focus only on fixing the specific problem described by the user
|
|
88
|
+
2. Make the minimum changes necessary to solve the stated problem
|
|
89
|
+
3. Never make arbitrary value changes unless specifically requested
|
|
90
|
+
4. When multiple solutions are possible:
|
|
91
|
+
- Choose the one requiring the fewest changes
|
|
92
|
+
- Maintain existing patterns and values
|
|
93
|
+
- Do not introduce new patterns or values unless necessary
|
|
94
|
+
5. After providing the immediate solution, if you notice any of these:
|
|
95
|
+
- Fundamental architectural improvements that could provide significant benefits
|
|
96
|
+
- Systematic issues that affect multiple parts of the codebase
|
|
97
|
+
- Alternative approaches that could prevent similar issues in the future
|
|
98
|
+
Then:
|
|
99
|
+
a. First provide the direct solution to the immediate problem
|
|
100
|
+
b. Then say "While examining this issue, I noticed a potential broader improvement:"
|
|
101
|
+
c. Briefly explain the benefits (e.g., performance, maintainability, scalability)
|
|
102
|
+
d. Ask if you should demonstrate how to implement this broader change
|
|
103
|
+
6. If you notice other bugs or issues while solving the primary problem:
|
|
104
|
+
- Don't fix them as part of the original solution
|
|
105
|
+
- After providing the solution, note "While solving this, I also noticed:"
|
|
106
|
+
- List the issues for future consideration
|
|
107
|
+
|
|
108
|
+
CRITICAL: MAINTAINING CONTEXT AND REQUIREMENTS:
|
|
109
|
+
CRITICAL: When suggesting changes:
|
|
110
|
+
1. SOLVE THE STATED PROBLEM FIRST:
|
|
111
|
+
- Read the user's problem statement carefully
|
|
112
|
+
- Identify the specific issue to be fixed
|
|
113
|
+
- Provide the minimal change that solves exactly that issue
|
|
114
|
+
- Verify the solution addresses the stated problem directly
|
|
115
|
+
2. Always reference the codebase provided in your context as authoritative
|
|
116
|
+
3. Verify the current state of the code before suggesting changes
|
|
117
|
+
4. Do not assume the state of the code based on previous interactions
|
|
118
|
+
5. Ensure suggested changes are based on the actual current content of the files
|
|
119
|
+
6. Never remove existing requirements or constraints while adding new ones
|
|
120
|
+
7. Only after providing the solution for the stated problem:
|
|
121
|
+
- Reference related issues you noticed
|
|
122
|
+
- Suggest broader improvements
|
|
123
|
+
- Discuss potential architectural changes
|
|
124
|
+
8. When modifying code:
|
|
125
|
+
- Preserve existing functionality unless explicitly asked to change it
|
|
126
|
+
- Maintain all existing requirements unless specifically told to remove them
|
|
127
|
+
- If removing code, justify why it's safe to remove
|
|
128
|
+
- If changing behavior, explain the impact on existing functionality
|
|
129
|
+
|
|
130
|
+
When presenting multiple diffs in a numbered list:
|
|
131
|
+
1. Start each list item with the number and a period (e.g., "1. ")
|
|
132
|
+
2. Add a brief description of the change
|
|
133
|
+
3. Start the diff block on the next line with ```diff
|
|
134
|
+
4. No indentation should be used for the diff block
|
|
135
|
+
5. End the diff block with ``` on its own line
|
|
136
|
+
6. Add a blank line between list items
|
|
137
|
+
7. Example:
|
|
138
|
+
1. First change description:
|
|
139
|
+
```diff
|
|
140
|
+
[diff content]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
2. Second change description:
|
|
144
|
+
```diff
|
|
145
|
+
[diff content]
|
|
146
|
+
```
|
|
33
147
|
|
|
34
148
|
CRITICAL: After generating each hunk diff, carefully review and verify the following:
|
|
35
149
|
1. Check that the diff can be applied cleanly using `git apply`. This means:
|
|
@@ -37,11 +151,16 @@ CRITICAL: After generating each hunk diff, carefully review and verify the follo
|
|
|
37
151
|
- The line numbers and content should be consistent throughout the diff.
|
|
38
152
|
- There should be no conflicts or inconsistencies in the changes.
|
|
39
153
|
2. If you find any errors or inconsistencies, correct them before finalizing the diff.
|
|
40
|
-
3.
|
|
41
|
-
|
|
42
|
-
|
|
154
|
+
3. Review your explanation against your diff to verify:
|
|
155
|
+
- Every change you describe is actually present in the diff
|
|
156
|
+
- The diff contains no changes you haven't described
|
|
157
|
+
- Your description matches the actual changes in the diff exactly
|
|
158
|
+
- All line numbers and content in your description match the diff
|
|
159
|
+
4. For each hunk in the diff, please make sure it starts or ends with a line containing content instead of empty line, if possible.
|
|
160
|
+
5. When creating a new file, ensure the line `new file mode 100644` is included to specify file permissions.
|
|
161
|
+
6. When deleting a file, include `deleted file mode` to indicate that the file has been removed. Each line in the
|
|
43
162
|
deleted file should be prefixed with `-` to indicate the content removal.
|
|
44
|
-
|
|
163
|
+
7. Lines ending with a newline (\n) should not be interpreted as an additional line. Treat \n as the end of the current
|
|
45
164
|
line’s content, not as a new line in the file.
|
|
46
165
|
|
|
47
166
|
Do not include any explanatory text within the diff blocks. If you need to provide explanations or comments, do so outside the diff blocks.
|
|
@@ -75,7 +194,3 @@ conversational_prompt = ChatPromptTemplate.from_messages(
|
|
|
75
194
|
("ai", "{agent_scratchpad}"),
|
|
76
195
|
]
|
|
77
196
|
)
|
|
78
|
-
|
|
79
|
-
def parse_output(message):
|
|
80
|
-
text = message.content
|
|
81
|
-
return AgentFinish(return_values={"output": text}, log=text)
|
app/server.py
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import os
|
|
2
|
-
|
|
2
|
+
import time
|
|
3
|
+
from typing import Dict, Any, List, Tuple, Optional
|
|
3
4
|
|
|
4
5
|
import tiktoken
|
|
5
6
|
from fastapi import FastAPI, Request, HTTPException
|
|
6
7
|
from fastapi.middleware.cors import CORSMiddleware
|
|
8
|
+
from fastapi.responses import JSONResponse
|
|
7
9
|
from fastapi.staticfiles import StaticFiles
|
|
8
10
|
from fastapi.templating import Jinja2Templates
|
|
9
11
|
from langserve import add_routes
|
|
12
|
+
from app.agents.agent import model
|
|
10
13
|
from app.agents.agent import agent_executor
|
|
11
14
|
from fastapi.responses import FileResponse
|
|
12
15
|
from pydantic import BaseModel
|
|
16
|
+
from botocore.exceptions import ClientError, BotoCoreError, CredentialRetrievalError
|
|
17
|
+
|
|
13
18
|
|
|
14
19
|
# import pydevd_pycharm
|
|
15
20
|
import uvicorn
|
|
@@ -29,6 +34,39 @@ app.add_middleware(
|
|
|
29
34
|
allow_headers=["*"],
|
|
30
35
|
)
|
|
31
36
|
|
|
37
|
+
@app.exception_handler(CredentialRetrievalError)
|
|
38
|
+
async def credential_exception_handler(request: Request, exc: CredentialRetrievalError):
|
|
39
|
+
# Pass through the original error message which may contain helpful authentication instructions
|
|
40
|
+
error_message = str(exc)
|
|
41
|
+
return JSONResponse(
|
|
42
|
+
status_code=401,
|
|
43
|
+
content={"detail": f"AWS credential error: {error_message}"}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@app.exception_handler(ClientError)
|
|
48
|
+
async def boto_client_exception_handler(request: Request, exc: ClientError):
|
|
49
|
+
error_message = str(exc)
|
|
50
|
+
if "ExpiredTokenException" in error_message or "InvalidIdentityTokenException" in error_message:
|
|
51
|
+
return JSONResponse(
|
|
52
|
+
status_code=401,
|
|
53
|
+
content={"detail": "AWS credentials have expired. Please refresh your credentials."}
|
|
54
|
+
)
|
|
55
|
+
elif "ServiceUnavailableException" in error_message:
|
|
56
|
+
return JSONResponse(
|
|
57
|
+
status_code=503,
|
|
58
|
+
content={"detail": "AWS Bedrock service is temporarily unavailable. This usually happens when the service is experiencing high load. Please wait a moment and try again."}
|
|
59
|
+
)
|
|
60
|
+
return JSONResponse(
|
|
61
|
+
status_code=500,
|
|
62
|
+
content={"detail": f"AWS Service Error: {str(exc)}"}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
@app.exception_handler(Exception)
|
|
66
|
+
async def general_exception_handler(request: Request, exc: Exception):
|
|
67
|
+
logger.error(f"Unhandled exception: {str(exc)}", exc_info=True)
|
|
68
|
+
return JSONResponse(status_code=500, content={"detail": str(exc)})
|
|
69
|
+
|
|
32
70
|
app.mount("/static", StaticFiles(directory="../templates/static"), name="static")
|
|
33
71
|
templates = Jinja2Templates(directory="../templates")
|
|
34
72
|
|
|
@@ -39,7 +77,8 @@ add_routes(app, agent_executor, disabled_endpoints=["playground"], path="/ziya")
|
|
|
39
77
|
@app.get("/")
|
|
40
78
|
async def root(request: Request):
|
|
41
79
|
return templates.TemplateResponse("index.html", {
|
|
42
|
-
"request": request
|
|
80
|
+
"request": request,
|
|
81
|
+
"diff_view_type": os.environ.get("ZIYA_DIFF_VIEW_TYPE", "unified")
|
|
43
82
|
})
|
|
44
83
|
|
|
45
84
|
|
|
@@ -48,17 +87,38 @@ async def favicon():
|
|
|
48
87
|
return FileResponse('../templates/favicon.ico')
|
|
49
88
|
|
|
50
89
|
|
|
90
|
+
# Cache for folder structure with timestamp
|
|
91
|
+
_folder_cache = {'timestamp': 0, 'data': None}
|
|
92
|
+
|
|
51
93
|
def get_folder_structure(directory: str, ignored_patterns: List[Tuple[str, str]], max_depth: int) -> Dict[str, Any]:
|
|
52
94
|
should_ignore_fn = parse_gitignore_patterns(ignored_patterns)
|
|
53
95
|
|
|
54
96
|
def count_tokens(file_path: str) -> int:
|
|
55
97
|
try:
|
|
56
|
-
|
|
98
|
+
# Skip binary files by extension
|
|
99
|
+
binary_extensions = {
|
|
100
|
+
'.pyc', '.pyo', '.ico', '.png', '.jpg', '.jpeg', '.gif', '.svg',
|
|
101
|
+
'.core', '.bin', '.exe', '.dll', '.so', '.dylib', '.class',
|
|
102
|
+
'.pyd', '.woff', '.woff2', '.ttf', '.eot'
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if any(file_path.endswith(ext) for ext in binary_extensions):
|
|
106
|
+
logger.debug(f"Skipping binary file by extension: {file_path}")
|
|
107
|
+
return 0
|
|
108
|
+
|
|
109
|
+
# Try to detect if file is binary by reading first few bytes
|
|
110
|
+
with open(file_path, 'rb') as file:
|
|
111
|
+
content_bytes = file.read(1024)
|
|
112
|
+
if b'\x00' in content_bytes: # Binary file detection
|
|
113
|
+
return 0
|
|
114
|
+
|
|
115
|
+
# If not binary, read as text
|
|
116
|
+
with open(file_path, 'r', encoding='utf-8') as file:
|
|
57
117
|
content = file.read()
|
|
58
118
|
return len(tiktoken.get_encoding("cl100k_base").encode(content))
|
|
59
|
-
except
|
|
60
|
-
|
|
61
|
-
return 0
|
|
119
|
+
except (UnicodeDecodeError, IOError) as e:
|
|
120
|
+
logger.debug(f"Skipping binary or unreadable file {file_path}: {str(e)}")
|
|
121
|
+
return 0 # Skip files that can't be read as text
|
|
62
122
|
|
|
63
123
|
def get_structure(current_dir: str, current_depth: int):
|
|
64
124
|
if current_depth > max_depth:
|
|
@@ -87,6 +147,17 @@ def get_folder_structure(directory: str, ignored_patterns: List[Tuple[str, str]]
|
|
|
87
147
|
folder_structure = get_structure(directory, 1)
|
|
88
148
|
return folder_structure
|
|
89
149
|
|
|
150
|
+
def get_cached_folder_structure(directory: str, ignored_patterns: List[Tuple[str, str]], max_depth: int) -> Dict[str, Any]:
|
|
151
|
+
current_time = time.time()
|
|
152
|
+
cache_age = current_time - _folder_cache['timestamp']
|
|
153
|
+
|
|
154
|
+
# Refresh cache if older than 10 seconds
|
|
155
|
+
if _folder_cache['data'] is None or cache_age > 10:
|
|
156
|
+
_folder_cache['data'] = get_folder_structure(directory, ignored_patterns, max_depth)
|
|
157
|
+
_folder_cache['timestamp'] = current_time
|
|
158
|
+
logger.info("Refreshed folder structure cache")
|
|
159
|
+
|
|
160
|
+
return _folder_cache['data']
|
|
90
161
|
|
|
91
162
|
@app.get("/api/folders")
|
|
92
163
|
async def get_folders():
|
|
@@ -94,18 +165,36 @@ async def get_folders():
|
|
|
94
165
|
user_codebase_dir = os.environ["ZIYA_USER_CODEBASE_DIR"]
|
|
95
166
|
max_depth = int(os.environ.get("ZIYA_MAX_DEPTH"))
|
|
96
167
|
ignored_patterns: List[Tuple[str, str]] = get_ignored_patterns(user_codebase_dir)
|
|
97
|
-
return
|
|
98
|
-
|
|
168
|
+
return get_cached_folder_structure(user_codebase_dir, ignored_patterns, max_depth)
|
|
99
169
|
|
|
100
170
|
@app.get('/api/default-included-folders')
|
|
101
171
|
def get_default_included_folders():
|
|
102
172
|
return {'defaultIncludedFolders': []}
|
|
103
173
|
|
|
174
|
+
@app.get('/api/model-id')
|
|
175
|
+
def get_model_id():
|
|
176
|
+
# Get the model ID from the configured Bedrock client
|
|
177
|
+
return {'model_id': model.model_id.split(':')[0].split('/')[-1]}
|
|
104
178
|
|
|
105
179
|
class ApplyChangesRequest(BaseModel):
|
|
106
180
|
diff: str
|
|
107
181
|
filePath: str
|
|
108
182
|
|
|
183
|
+
class TokenCountRequest(BaseModel):
|
|
184
|
+
text: str
|
|
185
|
+
|
|
186
|
+
@app.post('/api/token-count')
|
|
187
|
+
async def count_tokens(request: TokenCountRequest) -> Dict[str, int]:
|
|
188
|
+
try:
|
|
189
|
+
# Use the existing model instance to count tokens
|
|
190
|
+
token_count = model.get_num_tokens(request.text)
|
|
191
|
+
logger.info(f"Counted {token_count} tokens for text length {len(request.text)}")
|
|
192
|
+
return {"token_count": token_count}
|
|
193
|
+
except Exception as e:
|
|
194
|
+
logger.error(f"Error counting tokens: {str(e)}", exc_info=True)
|
|
195
|
+
# Return 0 in case of error to avoid breaking the frontend
|
|
196
|
+
return {"token_count": 0}
|
|
197
|
+
|
|
109
198
|
@app.post('/api/apply-changes')
|
|
110
199
|
async def apply_changes(request: ApplyChangesRequest):
|
|
111
200
|
try:
|
app/utils/print_tree_util.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from app.utils.logging_utils import logger
|
|
3
|
+
|
|
2
4
|
|
|
3
5
|
def print_file_tree(file_paths):
|
|
4
6
|
# Create a dictionary to store files and directories
|
|
@@ -23,15 +25,16 @@ def print_file_tree(file_paths):
|
|
|
23
25
|
return
|
|
24
26
|
|
|
25
27
|
printed_dirs.add(dir_path)
|
|
26
|
-
|
|
28
|
+
logger.debug(f"{indent}{os.path.basename(dir_path)}")
|
|
29
|
+
|
|
27
30
|
if file_tree[dir_path]:
|
|
28
31
|
for i, file_name in enumerate(file_tree[dir_path]):
|
|
29
32
|
if i == len(file_tree[dir_path]) - 1:
|
|
30
|
-
|
|
33
|
+
logger.debug(f"{indent} └── {file_name}")
|
|
31
34
|
else:
|
|
32
|
-
|
|
35
|
+
logger.debug(f"{indent} ├── {file_name}")
|
|
33
36
|
else:
|
|
34
|
-
|
|
37
|
+
logger.debug(f"{indent} (empty)")
|
|
35
38
|
|
|
36
39
|
# Recursively print subdirectories
|
|
37
40
|
subdirs = [subdir for subdir in sorted_dirs if subdir.startswith(dir_path + os.sep)]
|
|
@@ -40,4 +43,4 @@ def print_file_tree(file_paths):
|
|
|
40
43
|
|
|
41
44
|
printed_dirs = set()
|
|
42
45
|
for dir_path in sorted_dirs:
|
|
43
|
-
print_dir(dir_path, "")
|
|
46
|
+
print_dir(dir_path, "")
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# lets move sanitizers here to clean up code flow and make them reusable
|
|
2
|
+
def clean_backtick_sequences(text: str) -> str:
|
|
3
|
+
"""
|
|
4
|
+
Cleans up problematic backtick sequences while preserving content within code blocks.
|
|
5
|
+
Ensures all code blocks are properly closed.
|
|
6
|
+
|
|
7
|
+
Args:
|
|
8
|
+
text (str): The input text containing potential backtick sequences
|
|
9
|
+
|
|
10
|
+
Returns:
|
|
11
|
+
str: Text with properly closed code blocks and preserved content
|
|
12
|
+
"""
|
|
13
|
+
lines = text.split('\n')
|
|
14
|
+
cleaned_lines = []
|
|
15
|
+
in_code_block = False
|
|
16
|
+
current_block_type = None
|
|
17
|
+
|
|
18
|
+
for line in lines:
|
|
19
|
+
if not in_code_block:
|
|
20
|
+
if line.startswith('```'):
|
|
21
|
+
# Starting a new block
|
|
22
|
+
in_code_block = True
|
|
23
|
+
# Capture the block type (diff, python, etc.)
|
|
24
|
+
current_block_type = line[3:].strip() if len(line) > 3 else None
|
|
25
|
+
cleaned_lines.append(line)
|
|
26
|
+
else:
|
|
27
|
+
cleaned_lines.append(line)
|
|
28
|
+
else:
|
|
29
|
+
# Inside a code block - collect content until closing backticks
|
|
30
|
+
if line.strip() == '```':
|
|
31
|
+
# Only close block if it's a bare ``` without a type specifier
|
|
32
|
+
if len(line.strip()) == 3:
|
|
33
|
+
in_code_block = False
|
|
34
|
+
current_block_type = None
|
|
35
|
+
cleaned_lines.append(line)
|
|
36
|
+
else:
|
|
37
|
+
# This is a nested block marker, preserve it
|
|
38
|
+
cleaned_lines.append(line)
|
|
39
|
+
else:
|
|
40
|
+
# Within a code block, preserve content exactly as it appears
|
|
41
|
+
cleaned_lines.append(line)
|
|
42
|
+
|
|
43
|
+
# If we ended with an open code block, close it
|
|
44
|
+
if in_code_block:
|
|
45
|
+
cleaned_lines.append('```')
|
|
46
|
+
current_block_type = None
|
|
47
|
+
|
|
48
|
+
return '\n'.join(cleaned_lines)
|
pyproject.toml
CHANGED
templates/asset-manifest.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": {
|
|
3
|
-
"main.css": "/static/css/main.
|
|
4
|
-
"main.js": "/static/js/main.
|
|
5
|
-
"static/media/fa-solid-900.ttf": "/static/media/fa-solid-900.
|
|
6
|
-
"static/media/fa-brands-400.ttf": "/static/media/fa-brands-400.
|
|
7
|
-
"static/media/fa-solid-900.woff2": "/static/media/fa-solid-900.
|
|
8
|
-
"static/media/fa-brands-400.woff2": "/static/media/fa-brands-400.
|
|
9
|
-
"static/media/fa-regular-400.ttf": "/static/media/fa-regular-400.
|
|
10
|
-
"static/media/fa-regular-400.woff2": "/static/media/fa-regular-400.
|
|
11
|
-
"static/media/fa-v4compatibility.ttf": "/static/media/fa-v4compatibility.
|
|
12
|
-
"static/media/fa-v4compatibility.woff2": "/static/media/fa-v4compatibility.
|
|
3
|
+
"main.css": "/static/css/main.f447c982.css",
|
|
4
|
+
"main.js": "/static/js/main.59d11a1d.js",
|
|
5
|
+
"static/media/fa-solid-900.ttf": "/static/media/fa-solid-900.2582b0e4bcf85eceead0.ttf",
|
|
6
|
+
"static/media/fa-brands-400.ttf": "/static/media/fa-brands-400.1815e00441357e01619e.ttf",
|
|
7
|
+
"static/media/fa-solid-900.woff2": "/static/media/fa-solid-900.2463b90d9a316e4e5294.woff2",
|
|
8
|
+
"static/media/fa-brands-400.woff2": "/static/media/fa-brands-400.c210719e60948b211a12.woff2",
|
|
9
|
+
"static/media/fa-regular-400.ttf": "/static/media/fa-regular-400.914997e1bdfc990d0897.ttf",
|
|
10
|
+
"static/media/fa-regular-400.woff2": "/static/media/fa-regular-400.89999bdf5d835c012025.woff2",
|
|
11
|
+
"static/media/fa-v4compatibility.ttf": "/static/media/fa-v4compatibility.da94ef451f4969af06e6.ttf",
|
|
12
|
+
"static/media/fa-v4compatibility.woff2": "/static/media/fa-v4compatibility.ea8f94e1d22e0d35ccd4.woff2",
|
|
13
13
|
"index.html": "/index.html",
|
|
14
|
-
"main.
|
|
15
|
-
"main.
|
|
14
|
+
"main.f447c982.css.map": "/static/css/main.f447c982.css.map",
|
|
15
|
+
"main.59d11a1d.js.map": "/static/js/main.59d11a1d.js.map"
|
|
16
16
|
},
|
|
17
17
|
"entrypoints": [
|
|
18
|
-
"static/css/main.
|
|
19
|
-
"static/js/main.
|
|
18
|
+
"static/css/main.f447c982.css",
|
|
19
|
+
"static/js/main.59d11a1d.js"
|
|
20
20
|
]
|
|
21
21
|
}
|
templates/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Ziya - Code Assistant</title><link rel="icon" href="/favicon.ico" type="image/x-icon"><script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script><script>window.enableCodeApply="true"</script><script defer="defer" src="/static/js/main.
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Ziya - Code Assistant</title><link rel="icon" href="/favicon.ico" type="image/x-icon"><script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script><script>window.enableCodeApply="true",window.diffDisplayMode="pretty",window.diffViewType="unified"</script><script defer="defer" src="/static/js/main.59d11a1d.js"></script><link href="/static/css/main.f447c982.css" rel="stylesheet"></head><body><div id="root"></div></body></html>
|