Set granite4.1 as default model.
This commit is contained in:
parent
6db78809f4
commit
a83198303f
@ -5,7 +5,7 @@ load_dotenv()
|
|||||||
|
|
||||||
# LLM Configuration
|
# LLM Configuration
|
||||||
LLM_BASE_URL = os.getenv("LLM_BASE_URL", default="http://localhost:11434/v1")
|
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_API_KEY = os.getenv("LLM_API_KEY", default="ollama")
|
||||||
LLM_TIMEOUT = int(os.getenv("LLM_TIMEOUT", default="600"))
|
LLM_TIMEOUT = int(os.getenv("LLM_TIMEOUT", default="600"))
|
||||||
# Agent Configuration
|
# Agent Configuration
|
||||||
|
|||||||
148
hendrik.py
148
hendrik.py
@ -1,4 +1,4 @@
|
|||||||
import os, sys, json
|
import os, sys, json, tty, termios
|
||||||
import config
|
import config
|
||||||
from llm_client import LLMClient
|
from llm_client import LLMClient
|
||||||
from tools import coder
|
from tools import coder
|
||||||
@ -13,25 +13,79 @@ tools_definition = [
|
|||||||
gadget.tools_mapping( coder.schema_git_operation, coder.git_operation ),
|
gadget.tools_mapping( coder.schema_git_operation, coder.git_operation ),
|
||||||
]
|
]
|
||||||
|
|
||||||
TOOLS = [t["schema"] for t in tools_definition] # Schemas
|
TOOLS = gadget.tool_schemas(tools_definition)
|
||||||
TOOL_HANDLERS = {t["name"]: t["handler"] for t in tools_definition} # Map
|
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
|
def interactive_input():
|
||||||
2. write_file: Write content to a file (overwrites existing)
|
fd = sys.stdin.fileno()
|
||||||
3. edit_file: Replace text in a file
|
old = termios.tcgetattr(fd)
|
||||||
4. run_bash: Execute bash commands
|
|
||||||
5. search_code: Search for files (glob) or file contents (regex)
|
|
||||||
6. git_operation: Run git commands
|
|
||||||
|
|
||||||
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):
|
buffer = bytearray()
|
||||||
messages = [
|
try:
|
||||||
{"role": "system" , "content": SYSTEM_PROMPT },
|
tty.setraw(fd)
|
||||||
{"role": "user" , "content": user_query }
|
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):
|
for _ in range(config.AGENT_MAX_ITERATIONS):
|
||||||
response = llm_client.chat(messages, tools=TOOLS)
|
response = llm_client.chat(messages, tools=TOOLS)
|
||||||
if response.tool_calls:
|
if response.tool_calls:
|
||||||
@ -48,6 +102,8 @@ def agent_loop(user_query, llm_client):
|
|||||||
if not handler:
|
if not handler:
|
||||||
result = f"Tool {tool_name} not found"
|
result = f"Tool {tool_name} not found"
|
||||||
else:
|
else:
|
||||||
|
args_display = ", ".join(f"{k}={v!r}" for k, v in tool_args.items())
|
||||||
|
print(f" \u2192 {tool_name}({args_display})")
|
||||||
try:
|
try:
|
||||||
if tool_name == "search_code":
|
if tool_name == "search_code":
|
||||||
result = handler(
|
result = handler(
|
||||||
@ -67,23 +123,67 @@ def agent_loop(user_query, llm_client):
|
|||||||
"content": str(result)
|
"content": str(result)
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
return response.content
|
messages.append({"role": "assistant", "content": response.content})
|
||||||
return "Max iterations reached without final answer."
|
return response.content, messages
|
||||||
|
msg = "Max iterations reached without final answer."
|
||||||
|
messages.append({"role": "assistant", "content": msg})
|
||||||
|
return msg, messages
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
llm_client = LLMClient(base_url=config.LLM_BASE_URL, model=config.LLM_MODEL, api_key=config.LLM_API_KEY)
|
workspace = None
|
||||||
if len(sys.argv) > 1:
|
query_parts = []
|
||||||
user_query = " ".join(sys.argv[1:])
|
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:
|
else:
|
||||||
print("Enter your query (Ctrl+D to submit):")
|
query_parts.append(sys.argv[i])
|
||||||
user_query = sys.stdin.read().strip()
|
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:
|
if not user_query:
|
||||||
print("No query provided.")
|
print("No query provided.")
|
||||||
return
|
return
|
||||||
|
messages = [{"role": "system", "content": gadget.build_system_prompt(tools_definition)}]
|
||||||
print("Thinking...")
|
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("\nFinal Answer:")
|
||||||
print(final_answer)
|
print(final_answer)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
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):
|
def tools_mapping(schema, handler, name=None):
|
||||||
tool_name = name or schema["function"]["name"]
|
tool_name = name or schema["function"]["name"]
|
||||||
return {"name": tool_name, "schema": schema, "handler": handler}
|
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