Skip to content

Commit c6b9ad3

Browse files
authored
Merge pull request #64 from devchat-ai/type-annotation
Improve IDE services with type annotation and casting & Add two interfaces
2 parents 82d3fd5 + ef1c9ef commit c6b9ad3

9 files changed

Lines changed: 135 additions & 58 deletions

File tree

ask-code/ask-code.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
sys.path.append(os.path.join(os.path.dirname(__file__), "..", "libs"))
77
sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "libs"))
88

9-
from ide_services import get_lsp_brige_port # noqa: E402
9+
from ide_services import IDEService # noqa: E402
1010

1111

1212
def query(question, lsp_brige_port):
@@ -59,7 +59,7 @@ def main():
5959
print("Usage: python index_and_query.py query [question] [port]")
6060
sys.exit(1)
6161

62-
port = get_lsp_brige_port()
62+
port = IDEService().get_lsp_brige_port()
6363

6464
question = sys.argv[2]
6565
query(question, port)

commit/commit.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
sys.path.append(os.path.dirname(__file__))
1010

1111
from chatmark import Checkbox, Form, TextEditor # noqa: E402
12-
from ide_services.services import log_info
12+
from ide_services import IDEService # noqa: E402
1313
from llm_api import chat_completion_stream # noqa: E402
1414

1515
diff_too_large_message_en = (
@@ -67,17 +67,19 @@ def read_prompt_from_file(filename):
6767
- FileNotFoundError: If the file does not exist.
6868
- Exception: If any other error occurs during file reading.
6969
"""
70+
s = IDEService()
7071
try:
7172
with open(filename, "r", encoding="utf-8") as file:
7273
return file.read().strip()
7374
except FileNotFoundError:
74-
log_info(
75+
s.ide_logging(
76+
"info",
7577
f"File {filename} not found. "
76-
"Please make sure it exists in the same directory as the script."
78+
"Please make sure it exists in the same directory as the script.",
7779
)
7880
sys.exit(1)
7981
except Exception as e:
80-
log_info(f"An error occurred while reading the file {filename}: {e}")
82+
s.ide_logging("info", f"An error occurred while reading the file {filename}: {e}")
8183
sys.exit(1)
8284

8385

libs/ide_services/__init__.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
1-
from .services import (
2-
get_lsp_brige_port,
3-
ide_language,
4-
ide_logging,
5-
install_python_env,
6-
update_slash_commands,
7-
)
1+
from .service import IDEService
82

93
__all__ = [
10-
"get_lsp_brige_port",
11-
"install_python_env",
12-
"update_slash_commands",
13-
"ide_language",
14-
"ide_logging",
4+
"IDEService",
155
]

libs/ide_services/service.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import os
2+
from functools import wraps
3+
from typing import List
4+
5+
import requests
6+
7+
from .types import Location, SymbolNode
8+
9+
BASE_SERVER_URL = os.environ.get("DEVCHAT_IDE_SERVICE_URL", "http://localhost:3000")
10+
11+
12+
def rpc_method(f):
13+
"""
14+
Decorator for Service methods
15+
"""
16+
17+
@wraps(f)
18+
def wrapper(self, *args, **kwargs):
19+
if os.environ.get("DEVCHAT_IDE_SERVICE_URL", "") == "":
20+
# maybe in a test, user don't want to mock services functions
21+
return
22+
23+
try:
24+
function_name = f.__name__
25+
url = f"{BASE_SERVER_URL}/{function_name}"
26+
27+
data = dict(zip(f.__code__.co_varnames[1:], args)) # Exclude "self"
28+
data.update(kwargs)
29+
headers = {"Content-Type": "application/json"}
30+
31+
response = requests.post(url, json=data, headers=headers)
32+
33+
if response.status_code != 200:
34+
raise Exception(f"Server error: {response.status_code}")
35+
36+
response_data = response.json()
37+
if "error" in response_data:
38+
raise Exception(f"Server returned an error: {response_data['error']}")
39+
40+
# Store the result in the _result attribute of the instance
41+
self._result = response_data.get("result", None)
42+
return f(self, *args, **kwargs)
43+
44+
except ConnectionError as err:
45+
# TODO
46+
raise err
47+
48+
return wrapper
49+
50+
51+
class IDEService:
52+
"""
53+
Client for IDE service
54+
55+
Usage:
56+
client = IDEService()
57+
res = client.ide_language()
58+
res = client.ide_logging("info", "some message")
59+
"""
60+
61+
def __init__(self):
62+
self._result = None
63+
64+
@rpc_method
65+
def get_lsp_brige_port(self) -> str:
66+
return self._result
67+
68+
@rpc_method
69+
def install_python_env(self, command_name: str, requirements_file: str) -> str:
70+
return self._result
71+
72+
@rpc_method
73+
def update_slash_commands(self) -> bool:
74+
return self._result
75+
76+
@rpc_method
77+
def ide_language(self) -> str:
78+
return self._result
79+
80+
@rpc_method
81+
def ide_logging(self, level: str, message: str) -> bool:
82+
"""
83+
level: "info" | "warn" | "error" | "debug"
84+
"""
85+
return self._result
86+
87+
@rpc_method
88+
def get_document_symbols(self, abspath: str) -> List[SymbolNode]:
89+
return [SymbolNode.parse_obj(node) for node in self._result]
90+
91+
@rpc_method
92+
def find_type_def_locations(self, abspath: str, line: int, character: int) -> List[Location]:
93+
return [Location.parse_obj(loc) for loc in self._result]

libs/ide_services/services.py

Lines changed: 0 additions & 34 deletions
This file was deleted.

libs/ide_services/types.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from typing import List
2+
3+
from pydantic import BaseModel
4+
5+
6+
class Position(BaseModel):
7+
line: int # 0-based
8+
character: int # 0-based
9+
10+
11+
class Range(BaseModel):
12+
start: Position
13+
end: Position
14+
15+
16+
class Location(BaseModel):
17+
abspath: str
18+
range: Range
19+
20+
21+
class SymbolNode(BaseModel):
22+
name: str
23+
kind: str
24+
range: Range
25+
children: List["SymbolNode"]

libs/llm_api/text_confirm.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88

99
from chatmark import Checkbox, Form, TextEditor # noqa: #402
10-
from ide_services.services import log_info # noqa: #402
1110

1211

1312
class MissEditConfirmFieldException(Exception):

libs/llm_api/tools_call.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
1010

1111
from chatmark import Checkbox, Form, Radio, TextEditor # noqa: #402
12-
from ide_services.services import log_info, log_warn # noqa: #402
12+
from ide_services import IDEService # noqa: #402
1313

1414

1515
class MissToolsFieldException(Exception):
@@ -191,9 +191,10 @@ def wrapper(*args, **kwargs):
191191
# call function
192192
functions = {tool.function_name: tool for tool in tools}
193193
for call in response["all_calls"]:
194-
log_info(
194+
IDEService().ide_logging(
195+
"info",
195196
f"try to call function tool: {call['function_name']} "
196-
f"with {call['parameters']}"
197+
f"with {call['parameters']}",
197198
)
198199
tool = functions[call["function_name"]]
199200
result = tool(**json.loads(call["parameters"]))

unit_tests/main.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from chatmark import Checkbox, Form, Step, TextEditor # noqa: E402
1111
from find_reference_tests import find_reference_tests
1212
from i18n import TUILanguage, get_translation
13-
from ide_services import ide_language # noqa: E402
13+
from ide_services import IDEService # noqa: E402
1414
from model import (
1515
FuncToTest,
1616
TokenBudgetExceededException,
@@ -214,7 +214,8 @@ def main(input: str):
214214
user_prompt = f"Help me write unit tests for the `{func_name}` function"
215215

216216
repo_root = os.getcwd()
217-
ide_lang = ide_language()
217+
ide_lang = IDEService().ide_language()
218+
218219
tui_lang = TUILanguage.from_str(ide_lang)
219220
_i = get_translation(tui_lang)
220221

0 commit comments

Comments
 (0)