Skip to content

Commit 6894a8d

Browse files
committed
feat:Added pre-commit hooks
1 parent 3786d79 commit 6894a8d

8 files changed

Lines changed: 82 additions & 51 deletions

File tree

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,9 @@ cython_debug/
182182
.abstra/
183183

184184
# Visual Studio Code
185-
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
185+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186186
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187-
# and can be added to the global gitignore or merged into this file. However, if you prefer,
187+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
188188
# you could uncomment the following to ignore the entire vscode folder
189189
# .vscode/
190190

.pre-commit-config.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v4.5.0
4+
hooks:
5+
- id: trailing-whitespace
6+
- id: end-of-file-fixer
7+
- id: check-yaml
8+
9+
- repo: https://github.com/astral-sh/ruff-pre-commit
10+
rev: v0.3.0
11+
hooks:
12+
- id: ruff
13+
args: [ --fix ]
14+
- id: ruff-format

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,4 @@ Distributed under the Apache 2.0 License. See `LICENSE` for more information.
7171

7272
## Attribution
7373

74-
- Lambda icon by [shohanur.rahman13](https://www.flaticon.com/authors/shohanur-rahman13) from [Flaticon](https://www.flaticon.com/free-icons/lambda)
74+
- Lambda icon by [shohanur.rahman13](https://www.flaticon.com/authors/shohanur-rahman13) from [Flaticon](https://www.flaticon.com/free-icons/lambda)

lambda/agent.py

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
import json
21
from .config import API_KEY, MODEL_NAME
32
from .tools import TOOL_EXECUTORS, TOOL_FUNCTIONS
43

54
try:
65
import google.generativeai as genai
76
except ImportError:
8-
print("Warning: google-generativeai package is not installed. Please `pip install google-generativeai`.")
7+
print(
8+
"Warning: google-generativeai package is not installed. Please `pip install google-generativeai`."
9+
)
10+
911

1012
class Agent:
1113
def __init__(self):
1214
# Configure Gemini API
1315
genai.configure(api_key=API_KEY)
1416
self.model_name = MODEL_NAME
15-
17+
1618
system_instruction = (
1719
"You are Lambda, a minimal and highly efficient AI coding agent. "
1820
"Your primary goal is to help the user by writing code, executing commands, "
@@ -21,14 +23,14 @@ def __init__(self):
2123
"something that requires these tools, you should use them autonomously. "
2224
"Be concise and professional."
2325
)
24-
26+
2527
# Initialize the generative model with the built tools and system instructions
2628
self.model = genai.GenerativeModel(
2729
model_name=self.model_name,
2830
system_instruction=system_instruction,
29-
tools=TOOL_FUNCTIONS
31+
tools=TOOL_FUNCTIONS,
3032
)
31-
33+
3234
# Gemini manages history cleanly through the ChatSession
3335
self.chat_session = self.model.start_chat()
3436

@@ -44,44 +46,48 @@ def chat(self, user_input: str) -> str:
4446
try:
4547
# 1. Check if the model returned a function_call in any part
4648
tool_calls = [
47-
part.function_call for part in response.parts if getattr(part, 'function_call', None)
49+
part.function_call
50+
for part in response.parts
51+
if getattr(part, "function_call", None)
4852
]
49-
53+
5054
# 2. If it did, act on each function call
5155
if tool_calls:
5256
tool_responses = []
53-
57+
5458
for function_call in tool_calls:
5559
function_name = function_call.name
56-
60+
5761
# Convert protobuf args to dict
58-
arguments = {key: value for key, value in function_call.args.items()}
62+
arguments = {
63+
key: value for key, value in function_call.args.items()
64+
}
5965
print(f"\\n[Lambda is executing: {function_name}({arguments})]")
60-
66+
6167
# 3. Execute the tool locally
6268
if function_name in TOOL_EXECUTORS:
6369
function_to_call = TOOL_EXECUTORS[function_name]
6470
# Call the function dynamically
6571
tool_result = function_to_call(**arguments)
6672
else:
6773
tool_result = f"Error: Tool {function_name} not found."
68-
74+
6975
# Format the result back into Gemini's expected Response format
70-
tool_responses.append({
71-
"function_response": {
72-
"name": function_name,
73-
"response": {"result": str(tool_result)}
76+
tool_responses.append(
77+
{
78+
"function_response": {
79+
"name": function_name,
80+
"response": {"result": str(tool_result)},
81+
}
7482
}
75-
})
83+
)
7684

77-
78-
# 4. Send ALL the tool responses back to the model
85+
# 4. Send ALL the tool responses back to the model
7986
# so it can continue reasoning based on the new information
8087
response = self.chat_session.send_message(tool_responses)
81-
continue # Start the loop over to see if it calls more tools
88+
continue # Start the loop over to see if it calls more tools
8289
else:
8390
# No more tool calls; the LLM has generated a final text response.
8491
return response.text
8592
except Exception as e:
8693
return f"An error occurred in the agent loop: {str(e)}"
87-

lambda/config.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import os
2-
import sys
32

43
try:
54
from dotenv import load_dotenv
5+
66
load_dotenv()
77
except ImportError:
8-
print("Warning: python-dotenv not installed. If you are using a .env file, it will not be loaded.")
8+
print(
9+
"Warning: python-dotenv not installed. If you are using a .env file, it will not be loaded."
10+
)
911

1012
# Default to using Gemini
11-
API_KEY = os.getenv("API_KEY") # You can name this GEMINI_API_KEY in your .env
13+
API_KEY = os.getenv("API_KEY") # You can name this GEMINI_API_KEY in your .env
1214
MODEL_NAME = os.getenv("MODEL_NAME", "gemini-3-flash-preview")
1315

1416
if not API_KEY:
1517
print("WARNING: API_KEY is not set in the environment or .env file.")
16-

lambda/main.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import sys
21
from .agent import Agent
32

3+
44
def main():
55
print(r"""
66
========================================================
7-
██╗ █████╗ ███╗ ███╗██████╗ ██████╗ █████╗
7+
██╗ █████╗ ███╗ ███╗██████╗ ██████╗ █████╗
88
██║ ██╔══██╗████╗ ████║██╔══██╗██╔══██╗██╔══██╗
99
██║ ███████║██╔████╔██║██████╔╝██║ ██║███████║
1010
██║ ██╔══██║██║╚██╔╝██║██╔══██╗██║ ██║██╔══██║
@@ -18,25 +18,26 @@ def main():
1818
agent = Agent()
1919
print("Lambda is ready! Type 'exit' or 'quit' to stop.")
2020
print("-" * 40)
21-
21+
2222
while True:
2323
try:
24-
user_input = input("\\nYou: ")
25-
if user_input.lower() in ['exit', 'quit']:
24+
user_input = input("\nYou: ")
25+
if user_input.lower() in ["exit", "quit"]:
2626
print("Goodbye!")
2727
break
28-
28+
2929
if not user_input.strip():
3030
continue
31-
31+
3232
response = agent.chat(user_input)
33-
print(f"\\nLambda: {response}")
34-
33+
print(f"\nLambda: {response}")
34+
3535
except KeyboardInterrupt:
36-
print("\\nGoodbye!")
36+
print("\nGoodbye!")
3737
break
3838
except Exception as e:
3939
print(f"Failed to initialize Lambda: {str(e)}")
4040

41+
4142
if __name__ == "__main__":
4243
main()

lambda/tools.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,43 @@
1-
import os
21
import subprocess
32

3+
44
def read_file(path: str) -> str:
55
"""Reads the contents of a file.
6-
6+
77
Args:
88
path: The absolute or relative path to the file.
99
"""
1010
try:
11-
with open(path, 'r', encoding='utf-8') as f:
11+
with open(path, "r", encoding="utf-8") as f:
1212
return f.read()
1313
except Exception as e:
1414
return f"Error reading file {path}: {str(e)}"
1515

16+
1617
def write_file(path: str, content: str) -> str:
1718
"""Writes content to a specific file path.
18-
19+
1920
Args:
2021
path: The path to the file to write.
2122
content: The text content to write to the file.
2223
"""
2324
try:
24-
with open(path, 'w', encoding='utf-8') as f:
25+
with open(path, "w", encoding="utf-8") as f:
2526
f.write(content)
2627
return f"Successfully wrote to {path}"
2728
except Exception as e:
2829
return f"Error writing to file {path}: {str(e)}"
2930

31+
3032
def run_command(command: str) -> str:
3133
"""Executes a shell command on the host system.
32-
34+
3335
Args:
3436
command: The shell command to execute.
3537
"""
3638
try:
3739
result = subprocess.run(
38-
command,
39-
shell=True,
40-
capture_output=True,
41-
text=True,
42-
timeout=30
40+
command, shell=True, capture_output=True, text=True, timeout=30
4341
)
4442
output = result.stdout + result.stderr
4543
return output if output else "Command executed successfully with no output."
@@ -48,6 +46,7 @@ def run_command(command: str) -> str:
4846
except Exception as e:
4947
return f"Error executing command: {str(e)}"
5048

49+
5150
# A dictionary mapping tool names to Python functions for dynamic execution
5251
TOOL_EXECUTORS = {
5352
"read_file": read_file,
@@ -56,4 +55,4 @@ def run_command(command: str) -> str:
5655
}
5756

5857
# The list of raw Python functions for the Gemini SDK to auto-generate schemas
59-
TOOL_FUNCTIONS = [read_file, write_file, run_command]
58+
TOOL_FUNCTIONS = [read_file, write_file, run_command]

requirements.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
annotated-types==0.7.0
22
certifi==2026.2.25
33
cffi==2.0.0
4+
cfgv==3.5.0
45
charset-normalizer==3.4.7
56
cryptography==46.0.7
7+
distlib==0.4.0
8+
filelock==3.25.2
69
google-ai-generativelanguage==0.6.15
710
google-api-core==2.30.2
811
google-api-python-client==2.193.0
@@ -13,7 +16,11 @@ googleapis-common-protos==1.74.0
1316
grpcio==1.80.0
1417
grpcio-status==1.71.2
1518
httplib2==0.31.2
19+
identify==2.6.18
1620
idna==3.11
21+
nodeenv==1.10.0
22+
platformdirs==4.9.6
23+
pre_commit==4.5.1
1724
proto-plus==1.27.2
1825
protobuf==5.29.6
1926
pyasn1==0.6.3
@@ -22,10 +29,13 @@ pycparser==3.0
2229
pydantic==2.12.5
2330
pydantic_core==2.41.5
2431
pyparsing==3.3.2
32+
python-discovery==1.2.2
2533
python-dotenv==1.2.2
34+
PyYAML==6.0.3
2635
requests==2.33.1
2736
tqdm==4.67.3
2837
typing-inspection==0.4.2
2938
typing_extensions==4.15.0
3039
uritemplate==4.2.0
3140
urllib3==2.6.3
41+
virtualenv==21.2.0

0 commit comments

Comments
 (0)