-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode_review.py
More file actions
186 lines (143 loc) · 5.45 KB
/
Copy pathcode_review.py
File metadata and controls
186 lines (143 loc) · 5.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
"""
CodeSage AI -- Python Review Backend
====================================
Called by the VS Code extension as a child process.
Communication Protocol:
- Input: JSON via stdin -> { "code": str, "language": str, "fileName": str }
- Config: Environment variables ->
HF_API_KEY, CODESAGE_MODEL, CODESAGE_MAX_TOKENS, CODESAGE_TEMPERATURE,
CODESAGE_PROFILE, CODESAGE_SYSTEM_PROMPT, CODESAGE_STREAM
- Output (non-streaming): single JSON -> { "content", "model", "tokens_used" } or { "error" }
- Output (streaming): JSON lines -> { "type": "chunk", "content" } ... { "type": "done", ... }
Dependencies:
pip install huggingface_hub
"""
import sys
import os
import json
from huggingface_hub import InferenceClient
# Fallback system prompt used when CODESAGE_SYSTEM_PROMPT is not set.
FALLBACK_SYSTEM_PROMPT = """You are CodeSage AI, an expert code reviewer. Analyze the provided code and deliver a comprehensive, actionable review in markdown format.
## Code Quality Rating
Rate the code from A (excellent) to F (critical issues).
## Issues Found
List each issue with severity, line number, description, and fix.
## Improvements
Suggest improvements with code examples.
## Security
Flag any security concerns.
## Summary
Top 3 action items."""
def main():
"""Entry point: read request from stdin, call AI, write response to stdout."""
# Read configuration from environment
api_key = os.environ.get("HF_API_KEY")
if not api_key:
output_error("Missing API key. Run 'CodeSage: Set API Key' from the command palette.")
return
model = os.environ.get("CODESAGE_MODEL", "deepseek-ai/DeepSeek-R1")
max_tokens = int(os.environ.get("CODESAGE_MAX_TOKENS", "4096"))
temperature = float(os.environ.get("CODESAGE_TEMPERATURE", "0.3"))
system_prompt = os.environ.get("CODESAGE_SYSTEM_PROMPT", FALLBACK_SYSTEM_PROMPT)
stream_mode = os.environ.get("CODESAGE_STREAM", "false").lower() == "true"
# Read request from stdin
try:
raw_input = sys.stdin.read()
request = json.loads(raw_input)
except json.JSONDecodeError as e:
output_error(f"Invalid input format: {e}")
return
code = request.get("code", "")
language = request.get("language", "Unknown")
file_name = request.get("fileName", "unknown")
if not code.strip():
output_error("No code provided for review.")
return
# Initialize HuggingFace client
client = InferenceClient(
provider="together",
api_key=api_key,
)
# Build the prompt
base_name = os.path.basename(file_name)
user_prompt = f"Review this {language} code from `{base_name}`:\n\n```{language}\n{code}\n```"
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
]
# Call the AI model
try:
if stream_mode:
_stream_response(client, model, messages, max_tokens)
else:
_standard_response(client, model, messages, max_tokens)
except Exception as e:
output_error(f"AI request failed: {e}")
def _standard_response(client, model, messages, max_tokens):
"""Non-streaming: collect full response, output as single JSON."""
response = client.chat.completions.create(
model=model,
messages=messages,
max_tokens=max_tokens,
)
content = (
response.choices[0].message.content
if response.choices
else "No response received from the AI model."
)
tokens_used = 0
if hasattr(response, "usage") and response.usage:
tokens_used = getattr(response.usage, "total_tokens", 0)
output_result({
"content": content,
"model": model,
"tokens_used": tokens_used,
})
def _stream_response(client, model, messages, max_tokens):
"""Streaming: output JSON lines as chunks arrive."""
accumulated = []
try:
stream = client.chat.completions.create(
model=model,
messages=messages,
max_tokens=max_tokens,
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta and chunk.choices[0].delta.content:
text = chunk.choices[0].delta.content
accumulated.append(text)
output_chunk(text)
# Send final done message
full_content = "".join(accumulated)
output_done(full_content, model)
except Exception as e:
# If streaming fails partway, try to send what we have
if accumulated:
full_content = "".join(accumulated)
output_done(full_content, model)
else:
output_error(f"Streaming failed: {e}")
def output_result(data):
"""Write a successful result as JSON to stdout (non-streaming)."""
sys.stdout.write(json.dumps(data))
sys.stdout.flush()
def output_chunk(content):
"""Write a streaming chunk as a JSON line to stdout."""
sys.stdout.write(json.dumps({"type": "chunk", "content": content}) + "\n")
sys.stdout.flush()
def output_done(content, model):
"""Write the final streaming message as a JSON line to stdout."""
sys.stdout.write(json.dumps({
"type": "done",
"content": content,
"model": model,
"tokens_used": 0,
}) + "\n")
sys.stdout.flush()
def output_error(message):
"""Write an error as JSON to stdout."""
sys.stdout.write(json.dumps({"error": message}))
sys.stdout.flush()
if __name__ == "__main__":
main()