Set granite4.1 as default model.
This commit is contained in:
parent
6db78809f4
commit
a83198303f
@ -5,7 +5,7 @@ load_dotenv()
|
||||
|
||||
# LLM Configuration
|
||||
LLM_BASE_URL = os.getenv("LLM_BASE_URL", default="http://localhost:11434/v1")
|
||||
LLM_MODEL = os.getenv("LLM_MODEL", default="deepseek-r1:8b")
|
||||
LLM_MODEL = os.getenv("LLM_MODEL", default="granite4.1:8b")
|
||||
LLM_API_KEY = os.getenv("LLM_API_KEY", default="ollama")
|
||||
LLM_TIMEOUT = int(os.getenv("LLM_TIMEOUT", default="600"))
|
||||
# Agent Configuration
|
||||
|
||||
148
hendrik.py
148
hendrik.py
@ -1,4 +1,4 @@
|
||||
import os, sys, json
|
||||
import os, sys, json, tty, termios
|
||||
import config
|
||||
from llm_client import LLMClient
|
||||
from tools import coder
|
||||
@ -13,25 +13,79 @@ tools_definition = [
|
||||
gadget.tools_mapping( coder.schema_git_operation, coder.git_operation ),
|
||||
]
|
||||
|
||||
TOOLS = [t["schema"] for t in tools_definition] # Schemas
|
||||
TOOL_HANDLERS = {t["name"]: t["handler"] for t in tools_definition} # Map
|
||||
TOOLS = gadget.tool_schemas(tools_definition)
|
||||
TOOL_HANDLERS = gadget.tool_handlers(tools_definition)
|
||||
|
||||
SYSTEM_PROMPT = """You are a coding agent that assists with software engineering tasks. You have access to the following tools:
|
||||
|
||||
1. read_file: Read file contents with line numbers
|
||||
2. write_file: Write content to a file (overwrites existing)
|
||||
3. edit_file: Replace text in a file
|
||||
4. run_bash: Execute bash commands
|
||||
5. search_code: Search for files (glob) or file contents (regex)
|
||||
6. git_operation: Run git commands
|
||||
def interactive_input():
|
||||
fd = sys.stdin.fileno()
|
||||
old = termios.tcgetattr(fd)
|
||||
|
||||
Use tools by returning tool calls when needed. After receiving tool results, continue your reasoning. When you have the final answer, return it as plain text without tool calls."""
|
||||
print()
|
||||
print("\u2500" * 50)
|
||||
print("Hendrik AI Agent - Interactive Mode")
|
||||
print("\u2500" * 50)
|
||||
print(f"Workspace: {os.getcwd()}")
|
||||
print("\u2500" * 50)
|
||||
print("[Ctrl+W] Change workspace | :workspace <dir> | [Ctrl+D] Submit")
|
||||
print("\u2500" * 50)
|
||||
|
||||
def agent_loop(user_query, llm_client):
|
||||
messages = [
|
||||
{"role": "system" , "content": SYSTEM_PROMPT },
|
||||
{"role": "user" , "content": user_query }
|
||||
]
|
||||
buffer = bytearray()
|
||||
try:
|
||||
tty.setraw(fd)
|
||||
while True:
|
||||
ch = os.read(fd, 1)
|
||||
if ch == b'\x03': # Ctrl+C → exit
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
||||
print("\r\nExiting.")
|
||||
sys.exit(0)
|
||||
elif ch == b'\x04': # Ctrl+D → submit
|
||||
break
|
||||
elif ch == b'\x17': # Ctrl+W → change workspace
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
||||
print("\r\n", end="")
|
||||
ws = input("Workspace directory: ").strip()
|
||||
if ws:
|
||||
resolved = os.path.abspath(ws)
|
||||
if not os.path.isdir(resolved):
|
||||
print(f"Error: '{resolved}' is not a valid directory")
|
||||
else:
|
||||
os.chdir(resolved)
|
||||
print(f"\u2192 Workspace changed to {os.getcwd()}")
|
||||
return interactive_input()
|
||||
elif ch in (b'\r', b'\n'): # Enter
|
||||
buffer.extend(b'\n')
|
||||
sys.stdout.buffer.write(b'\r\n')
|
||||
sys.stdout.flush()
|
||||
elif ch == b'\x7f': # Backspace
|
||||
if buffer:
|
||||
buffer.pop()
|
||||
sys.stdout.buffer.write(b'\b \b')
|
||||
sys.stdout.flush()
|
||||
elif ch >= b' ': # Printable characters
|
||||
buffer.extend(ch)
|
||||
sys.stdout.buffer.write(ch)
|
||||
sys.stdout.flush()
|
||||
finally:
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
||||
|
||||
full_query = buffer.decode('utf-8', errors='replace').strip()
|
||||
|
||||
if full_query.startswith(':workspace '):
|
||||
ws = full_query[11:].strip()
|
||||
resolved = os.path.abspath(ws)
|
||||
if not os.path.isdir(resolved):
|
||||
print(f"Error: '{resolved}' is not a valid directory")
|
||||
return interactive_input()
|
||||
os.chdir(resolved)
|
||||
print(f"\u2192 Workspace changed to {os.getcwd()}")
|
||||
return interactive_input()
|
||||
|
||||
return full_query
|
||||
|
||||
|
||||
def agent_loop(user_query, messages, llm_client):
|
||||
messages.append({"role": "user", "content": user_query})
|
||||
for _ in range(config.AGENT_MAX_ITERATIONS):
|
||||
response = llm_client.chat(messages, tools=TOOLS)
|
||||
if response.tool_calls:
|
||||
@ -48,6 +102,8 @@ def agent_loop(user_query, llm_client):
|
||||
if not handler:
|
||||
result = f"Tool {tool_name} not found"
|
||||
else:
|
||||
args_display = ", ".join(f"{k}={v!r}" for k, v in tool_args.items())
|
||||
print(f" \u2192 {tool_name}({args_display})")
|
||||
try:
|
||||
if tool_name == "search_code":
|
||||
result = handler(
|
||||
@ -67,23 +123,67 @@ def agent_loop(user_query, llm_client):
|
||||
"content": str(result)
|
||||
})
|
||||
else:
|
||||
return response.content
|
||||
return "Max iterations reached without final answer."
|
||||
messages.append({"role": "assistant", "content": response.content})
|
||||
return response.content, messages
|
||||
msg = "Max iterations reached without final answer."
|
||||
messages.append({"role": "assistant", "content": msg})
|
||||
return msg, messages
|
||||
|
||||
|
||||
def main():
|
||||
llm_client = LLMClient(base_url=config.LLM_BASE_URL, model=config.LLM_MODEL, api_key=config.LLM_API_KEY)
|
||||
if len(sys.argv) > 1:
|
||||
user_query = " ".join(sys.argv[1:])
|
||||
workspace = None
|
||||
query_parts = []
|
||||
i = 1
|
||||
while i < len(sys.argv):
|
||||
if sys.argv[i] in ('-w', '--workspace') and i + 1 < len(sys.argv):
|
||||
workspace = sys.argv[i + 1]
|
||||
i += 2
|
||||
else:
|
||||
print("Enter your query (Ctrl+D to submit):")
|
||||
user_query = sys.stdin.read().strip()
|
||||
query_parts.append(sys.argv[i])
|
||||
i += 1
|
||||
|
||||
if workspace:
|
||||
resolved = os.path.abspath(workspace)
|
||||
if not os.path.isdir(resolved):
|
||||
print(f"Error: '{resolved}' is not a valid directory")
|
||||
sys.exit(1)
|
||||
os.chdir(resolved)
|
||||
|
||||
llm_client = LLMClient(
|
||||
base_url=config.LLM_BASE_URL,
|
||||
model=config.LLM_MODEL,
|
||||
api_key=config.LLM_API_KEY
|
||||
)
|
||||
|
||||
messages = None
|
||||
|
||||
if query_parts:
|
||||
user_query = ' '.join(query_parts)
|
||||
if not user_query:
|
||||
print("No query provided.")
|
||||
return
|
||||
messages = [{"role": "system", "content": gadget.build_system_prompt(tools_definition)}]
|
||||
print("Thinking...")
|
||||
final_answer = agent_loop(user_query, llm_client)
|
||||
final_answer, messages = agent_loop(user_query, messages, llm_client)
|
||||
print("\nFinal Answer:")
|
||||
print(final_answer)
|
||||
return
|
||||
|
||||
while True:
|
||||
user_query = interactive_input()
|
||||
if not user_query:
|
||||
break
|
||||
if user_query.lower() in ('/exit', '/quit'):
|
||||
break
|
||||
|
||||
if messages is None:
|
||||
messages = [{"role": "system", "content": gadget.build_system_prompt(tools_definition)}]
|
||||
|
||||
print("Thinking...")
|
||||
final_answer, messages = agent_loop(user_query, messages, llm_client)
|
||||
print("\nFinal Answer:")
|
||||
print(final_answer)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
Buatkan aku permainan menebak angka dadu dengan python dengan nama `dice.py`.
|
||||
Pemain dapat melihat angka dadu di awal permainan.
|
||||
Pemain akan menebak apakah angka selanjutnya lebih rendah atau lebih tinggi.
|
||||
Jika tebakan pemain benar maka score bertambah 10. Jika salah maka score di reset jadi 0.
|
||||
Tampilkan info `Score` dan `Dice`. Input hanya ada `low`, `high`, dan `quit`.
|
||||
Permainan akan terus berlanjut sampai pemain keluar dari permainan.
|
||||
@ -1,4 +1,37 @@
|
||||
import os
|
||||
|
||||
|
||||
def tools_mapping(schema, handler, name=None):
|
||||
tool_name = name or schema["function"]["name"]
|
||||
return {"name": tool_name, "schema": schema, "handler": handler}
|
||||
|
||||
|
||||
def tool_schemas(tools_definition):
|
||||
return [t["schema"] for t in tools_definition]
|
||||
|
||||
|
||||
def tool_handlers(tools_definition):
|
||||
return {t["name"]: t["handler"] for t in tools_definition}
|
||||
|
||||
|
||||
def build_system_prompt(tools_definition):
|
||||
lines = [
|
||||
"You are a coding agent that assists with software engineering tasks. "
|
||||
"You have access to the following tools:",
|
||||
""
|
||||
]
|
||||
for i, tool in enumerate(tools_definition, 1):
|
||||
name = tool["name"]
|
||||
desc = tool["schema"]["function"]["description"]
|
||||
lines.append(f"{i}. {name}: {desc}")
|
||||
lines.extend([
|
||||
"",
|
||||
"Use tools by returning tool calls when needed. After receiving tool "
|
||||
"results, continue your reasoning. When you have the final answer, "
|
||||
"return it as plain text without tool calls.",
|
||||
"",
|
||||
f"Your workspace directory is: {os.getcwd()}. "
|
||||
"All file operations are relative to this directory."
|
||||
])
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user