From 285e66ea016c6c526ba3f24295aa2a81358f01d6 Mon Sep 17 00:00:00 2001 From: Dita Aji Pratama Date: Sun, 27 Sep 2026 06:44:25 +0700 Subject: [PATCH] smart instruction --- hendrik.py | 29 +----- .../costapy/costapy-template-create.md | 95 +++++++++++++++++++ instruction/costapy/costapy.md | 6 ++ instruction/test/test.md | 1 + tools/smart.py | 48 ++++++++++ tools/smart_rp.py | 48 ++++++++++ 6 files changed, 203 insertions(+), 24 deletions(-) create mode 100644 instruction/costapy/costapy-template-create.md create mode 100644 instruction/costapy/costapy.md create mode 100644 instruction/test/test.md create mode 100644 tools/smart.py create mode 100644 tools/smart_rp.py diff --git a/hendrik.py b/hendrik.py index e7ba382..83503bd 100644 --- a/hendrik.py +++ b/hendrik.py @@ -3,7 +3,8 @@ import os, sys, threading, time, signal import config from lib import gadget, personality, moop, ragroleplay as ragroleplay_lib -from tools import coder, carrack, ragroleplay as ragroleplay_tools, vision, imagegen +from modules import argsparser +from tools import coder, carrack, ragroleplay as ragroleplay_tools, vision, imagegen, smart, smart_rp from services.llm_client import LLMClient from services.xmpp_client import XMPPClient @@ -11,8 +12,6 @@ from services.telegram_client import TelegramClient from interfaces.tui import HendrikTUI -from modules import argsparser - tools_definition = [ # Coder Tools gadget.tools_mapping( schema = coder.schema_read_file, handler = coder.read_file ), @@ -30,7 +29,9 @@ tools_definition = [ gadget.tools_mapping( schema = vision.schema_describe_image, handler = vision.describe_image ), # Image Generation Tools gadget.tools_mapping( schema = imagegen.schema_generate_image, handler = imagegen.generate_image ), - + # Instruction Tools + gadget.tools_mapping( schema = smart.schema_instruction_use, handler = smart.instruction_use ), # snippet + gadget.tools_mapping( schema = smart_rp.schema_rp_instruction_use, handler = smart_rp.rp_instruction_use ), # roleplay # Rag Roleplay Tools gadget.tools_mapping( schema = ragroleplay_tools.schema_users_store, handler = ragroleplay_tools.users_store ), gadget.tools_mapping( schema = ragroleplay_tools.schema_user_load, handler = ragroleplay_tools.user_load ), # s_load @@ -45,26 +46,6 @@ tools_definition = [ gadget.tools_mapping( schema = ragroleplay_tools.schema_memories_update, handler = ragroleplay_tools.memories_update ), gadget.tools_mapping( schema = ragroleplay_tools.schema_memories_delete, handler = ragroleplay_tools.memories_delete ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_worlds_store, handler = ragroleplay_tools.worlds_store ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_worlds_filter, handler = ragroleplay_tools.worlds_filter ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_worlds_update, handler = ragroleplay_tools.worlds_update ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_worlds_delete, handler = ragroleplay_tools.worlds_delete ), - - gadget.tools_mapping( schema = ragroleplay_tools.schema_objects_store, handler = ragroleplay_tools.objects_store ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_objects_filter, handler = ragroleplay_tools.objects_filter ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_objects_update, handler = ragroleplay_tools.objects_update ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_objects_delete, handler = ragroleplay_tools.objects_delete ), - - gadget.tools_mapping( schema = ragroleplay_tools.schema_outfits_store, handler = ragroleplay_tools.outfits_store ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_outfits_filter, handler = ragroleplay_tools.outfits_filter ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_outfits_update, handler = ragroleplay_tools.outfits_update ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_outfits_delete, handler = ragroleplay_tools.outfits_delete ), - - gadget.tools_mapping( schema = ragroleplay_tools.schema_todos_store, handler = ragroleplay_tools.todos_store ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_todos_filter, handler = ragroleplay_tools.todos_filter ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_todos_update, handler = ragroleplay_tools.todos_update ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_todos_delete, handler = ragroleplay_tools.todos_delete ), - gadget.tools_mapping( schema = ragroleplay_tools.schema_end_session, handler = ragroleplay_tools.end_session ), ] diff --git a/instruction/costapy/costapy-template-create.md b/instruction/costapy/costapy-template-create.md new file mode 100644 index 0000000..97ff861 --- /dev/null +++ b/instruction/costapy/costapy-template-create.md @@ -0,0 +1,95 @@ +# CostaPy / Template / Create + +Here is the guide about how to create a template for costapy. + +What you need to prepare: +- template name +- static file and directory +- raw HTML template +- part or component that you want to create + +## Create a directory +- make a directory with your template name `mkdir learn` +- go to a template directory `cd learn` +- then `learn` is your template directory + +## Routing a static file + +create `static` directory inside the template directory. + +create `main.py` inside the template directory and add a static list +```python +static = [ + { + "route" : "/templates/learn/css/", + "root" : "./templates/learn/static/css" + } +] +``` + +then you can manage your file on there. For example, put `style.css` on `static/css`. + +## Separate the part or component from the raw HTML template + +create `html` directory inside the template directory. and place your raw `index.html` in here. + +create `main.py` inside the template directory and set the template parts or components +```python +from core import html + +def main(dir, page): + html_template = html.main.get_html("templates/learn/html") + html_page = html.main.get_html(dir) + return { + "index" : html_template [ "index.html" ], + "navbar" : html_template [ "navbar.html" ], + "footer" : html_template [ "footer.html" ], + "container" : html_page [f"{page}.html" ] + } +``` + +adjust and separate the code into a modular file. For example, here I separate `navbar` and `footer` into a modular file. Use python mako template. + +`index.html` +```python + + + + + + + ${title} + + + +
+

${header}

+
+ ${navbar} +
+ ${container} +
+ ${footer} + + +``` + +`navbar.html` +```python + +``` + +`footer.html` +```python + +``` diff --git a/instruction/costapy/costapy.md b/instruction/costapy/costapy.md new file mode 100644 index 0000000..266662a --- /dev/null +++ b/instruction/costapy/costapy.md @@ -0,0 +1,6 @@ +# CostaPy + +Here is the instruction list that you can call. + +Templating +- `costapy-template-create.md` Create a template diff --git a/instruction/test/test.md b/instruction/test/test.md new file mode 100644 index 0000000..903b846 --- /dev/null +++ b/instruction/test/test.md @@ -0,0 +1 @@ +Katakan "Whoop! Whoop!" di tiap awal respon dan katakan "Brrrr.." di tiap akhir respon. diff --git a/tools/smart.py b/tools/smart.py new file mode 100644 index 0000000..13a15db --- /dev/null +++ b/tools/smart.py @@ -0,0 +1,48 @@ +import os +from scripts import loggorilla + +schema_instruction_use = { + "type": "function", + "function": { + "name": "instruction_use", + "description": "Reads a specific instruction file from the 'instruction' directory and returns its content. This is typically used to load specific guidelines or system prompt extensions.", + "parameters": { + "type": "object", + "properties": { + "directory": { + "type": "string", + "description": "The subdirectory within the 'instruction' folder (e.g., 'test', 'costapy', 'costapy/template')." + }, + "filename": { + "type": "string", + "description": "The name of the instruction file to read (e.g., 'test.md', 'costapy.md')." + } + }, + "required": ["directory", "filename"] + } + } +} + +def instruction_use(directory, filename): + loggorilla.fyinf("tools.smart", f"Calling instruction_use with directory='{directory}', filename='{filename}'") + current_file_dir = os.path.dirname(os.path.abspath(__file__)) + project_root = os.path.dirname(current_file_dir) + base_dir = os.path.join(project_root, "instruction") + safe_directory = directory.lstrip('/').replace('..', '') + safe_filename = os.path.basename(filename) + file_path = os.path.join(base_dir, safe_directory, safe_filename) + + if not os.path.exists(file_path): + res = f"Error: Instruction file not found at {file_path}" + loggorilla.fyinf("tools.smart", f"File not found: {res}") + return res + + try: + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + loggorilla.fyinf("tools.smart", f"Successfully read file. Content snippet: {content[:100]}...") + return content + except Exception as e: + res = f"Error reading file: {str(e)}" + loggorilla.fyinf("tools.smart", f"Exception occurred: {res}") + return res diff --git a/tools/smart_rp.py b/tools/smart_rp.py new file mode 100644 index 0000000..7b48ef8 --- /dev/null +++ b/tools/smart_rp.py @@ -0,0 +1,48 @@ +import os +from scripts import loggorilla + +schema_rp_instruction_use = { + "type": "function", + "function": { + "name": "rp_instruction_use", + "description": "CRITICAL ROLEPLAY VALIDATION TOOL: Use this tool ONLY when the character is interacting with a specific object, outfit, or location mentioned in the instruction files. This tool MUST be called to fetch the authoritative description before describing the item to ensure narrative consistency and prevent hallucination. DO NOT use if the character is not interacting with a specific listed item.", + "parameters": { + "type": "object", + "properties": { + "directory": { + "type": "string", + "description": "The subdirectory within the 'instruction' folder (e.g., 'rp/item', 'rp/armor', 'rp/world', 'gameplay')." + }, + "filename": { + "type": "string", + "description": "The name of the instruction file to read (e.g., 'rules.md', 'iron-sword.md')." + } + }, + "required": ["directory", "filename"] + } + } +} + +def rp_instruction_use(directory, filename): + loggorilla.fyinf("tools.smart_rp", f"Calling rp_instruction_use with directory='{directory}', filename='{filename}'") + current_file_dir = os.path.dirname(os.path.abspath(__file__)) + project_root = os.path.dirname(current_file_dir) + base_dir = os.path.join(project_root, "instruction") + safe_directory = directory.lstrip('/').replace('..', '') + safe_filename = os.path.basename(filename) + file_path = os.path.join(base_dir, safe_directory, safe_filename) + + if not os.path.exists(file_path): + res = f"Error: Roleplay instruction file not found at {file_path}" + loggorilla.fyinf("tools.smart_rp", f"File not found: {res}") + return res + + try: + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + loggorilla.fyinf("tools.smart_rp", f"Successfully read RP file. Content snippet: {content[:100]}...") + return content + except Exception as e: + res = f"Error reading RP file: {str(e)}" + loggorilla.fyinf("tools.smart_rp", f"Exception occurred: {res}") + return res