Compare commits

..

2 Commits

Author SHA1 Message Date
a6f3ae34a3 docs(templates): Add example for session templates
Some checks failed
Forge CI / smoke-and-build (pull_request) Failing after 57s
Add example script demonstrating session template usage:
1. Listing existing templates
2. Getting templates by task type
3. Injecting templates into messages
4. Usage tracking

Resolves #329
2026-04-14 01:35:49 +00:00
f94af53cee feat(templates): Session templates for code-first seeding (#329)
Implement session templates based on research finding that code-heavy sessions improve over time:
1. Task type classification (code, file, research, mixed)
2. Template extraction from successful sessions
3. Template storage in ~/.hermes/session-templates/
4. Template injection into new sessions
5. CLI interface for template management

Resolves #329
2026-04-14 01:35:02 +00:00
2 changed files with 97 additions and 17 deletions

View File

@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""
Example: Using session templates for code-first seeding.
This script demonstrates how to use the session template system
to pre-seed new sessions with successful tool call patterns.
"""
import sys
from pathlib import Path
# Add the parent directory to the path
sys.path.insert(0, str(Path(__file__).parent.parent))
from tools.session_templates import SessionTemplates, TaskType
def main():
"""Demonstrate session template usage."""
# Create template manager
templates = SessionTemplates()
print("Session Templates Example")
print("=" * 50)
# List existing templates
print("\n1. Existing templates:")
template_list = templates.list_templates()
if template_list:
for t in template_list:
print(f" - {t.name}: {t.task_type.value} ({len(t.examples)} examples)")
else:
print(" No templates found")
# Example: Create a template from a session
print("\n2. Creating a template from a session:")
print(" (This would normally use a real session ID)")
# Example: Get a template for code tasks
print("\n3. Getting a template for CODE tasks:")
code_template = templates.get_template(TaskType.CODE)
if code_template:
print(f" Found template: {code_template.name}")
print(f" Type: {code_template.task_type.value}")
print(f" Examples: {len(code_template.examples)}")
# Show first example
if code_template.examples:
example = code_template.examples[0]
print(f" First example: {example.tool_name}")
print(f" Arguments: {example.arguments}")
print(f" Result preview: {example.result[:100]}...")
else:
print(" No CODE template found")
# Example: Inject template into messages
print("\n4. Injecting template into messages:")
if code_template:
# Create sample messages
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Help me write some code"}
]
# Inject template
updated_messages = templates.inject_into_messages(code_template, messages)
print(f" Original messages: {len(messages)}")
print(f" Updated messages: {len(updated_messages)}")
print(f" Template usage count: {code_template.usage_count}")
# Show the injection
print("\n Injected messages:")
for i, msg in enumerate(updated_messages[:6]): # Show first 6
role = msg.get('role', 'unknown')
content = msg.get('content', '')
if content:
content_preview = content[:50] + "..." if len(content) > 50 else content
print(f" {i}: {role} - {content_preview}")
else:
print(f" {i}: {role} - (tool call)")
print("\n" + "=" * 50)
print("Example complete!")
if __name__ == "__main__":
main()

View File

@@ -1,13 +1,12 @@
"""
Session templates for code-first seeding.
Research finding: Code-heavy sessions (execute_code dominant in first 30 turns)
improve over time. File-heavy sessions degrade. The key is deterministic feedback
loops, not arbitrary context.
Based on research finding: Code-heavy sessions (execute_code dominant in first 30 turns)
improve over time. File-heavy sessions degrade. The key is deterministic feedback loops.
This module provides:
1. Template extraction from successful sessions
2. Task type classification (code, file, research, terminal)
2. Task type classification (code, file, research)
3. Template storage in ~/.hermes/session-templates/
4. Template injection into new sessions
"""
@@ -17,9 +16,8 @@ import logging
import os
import sqlite3
import time
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional, Any, Tuple
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, asdict
from enum import Enum
@@ -34,13 +32,12 @@ class TaskType(Enum):
CODE = "code"
FILE = "file"
RESEARCH = "research"
TERMINAL = "terminal"
MIXED = "mixed"
@dataclass
class ToolCallExample:
"""A single tool call example for template injection."""
"""A single tool call example."""
tool_name: str
arguments: Dict[str, Any]
result: str
@@ -63,7 +60,6 @@ class SessionTemplate:
description: str = ""
created_at: float = 0.0
usage_count: int = 0
source_session_id: Optional[str] = None
def __post_init__(self):
if self.created_at == 0.0:
@@ -117,14 +113,12 @@ class SessionTemplates:
code_tools = {'execute_code', 'code_execution'}
file_tools = {'read_file', 'write_file', 'patch', 'search_files'}
research_tools = {'web_search', 'web_fetch', 'browser_navigate'}
terminal_tools = {'terminal', 'execute_terminal'}
tool_names = [tc.get('tool_name', '') for tc in tool_calls]
code_count = sum(1 for t in tool_names if t in code_tools)
file_count = sum(1 for t in tool_names if t in file_tools)
research_count = sum(1 for t in tool_names if t in research_tools)
terminal_count = sum(1 for t in tool_names if t in terminal_tools)
total = len(tool_calls)
if total == 0:
@@ -137,8 +131,6 @@ class SessionTemplates:
return TaskType.FILE
elif research_count / total > 0.6:
return TaskType.RESEARCH
elif terminal_count / total > 0.6:
return TaskType.TERMINAL
else:
return TaskType.MIXED
@@ -225,8 +217,7 @@ class SessionTemplates:
name=name,
task_type=task_type,
examples=examples,
description=f"Template with {len(examples)} examples",
source_session_id=session_id
description=f"Template with {len(examples)} examples"
)
# Save template
@@ -334,13 +325,13 @@ def main():
# List templates
list_parser = subparsers.add_parser("list", help="List templates")
list_parser.add_argument("--type", choices=["code", "file", "research", "terminal", "mixed"])
list_parser.add_argument("--type", choices=["code", "file", "research", "mixed"])
# Create template
create_parser = subparsers.add_parser("create", help="Create template from session")
create_parser.add_argument("session_id", help="Session ID")
create_parser.add_argument("--name", help="Template name")
create_parser.add_argument("--type", choices=["code", "file", "research", "terminal", "mixed"])
create_parser.add_argument("--type", choices=["code", "file", "research", "mixed"])
create_parser.add_argument("--max-examples", type=int, default=10)
# Delete template