-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbehavior_engine.py
More file actions
106 lines (92 loc) · 4.48 KB
/
behavior_engine.py
File metadata and controls
106 lines (92 loc) · 4.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from logging_setup import get_logger
logger = get_logger(__name__)
from logging_setup import get_logger
logger = get_logger(__name__)
import json
class BehaviorState:
"""A simple data class to hold the properties of a single behavioral state."""
def __init__(self, state_data: dict):
self.id = state_data.get("id", "0,0")
self.name = state_data.get("name", "Unknown")
self.expressiveness = state_data.get("expressiveness", 0.5)
self.pacing = state_data.get("pacing", "normal")
self.tone_bias = state_data.get("tone_bias", "neutral")
self.memory_strictness = state_data.get("memory_strictness", "medium")
def __str__(self):
return f"[{self.id}] {self.name}"
def get_instructions(self) -> str:
"""Generates a string of instructions for the LLM based on the state's metadata."""
return (
f"Current Behavior State: {self.name} ({self.id}).\n"
f"- Expressiveness Level: {self.expressiveness * 100}%\n"
f"- Conversational Pacing: {self.pacing}\n"
f"- Dominant Tone: {self.tone_bias}\n"
f"- Adherence to Memory: {self.memory_strictness}"
)
class BehaviorStateMachine:
"""
Manages the 5x4 grid of behavioral states for the JL Engine.
"""
def __init__(self, config_path: str):
try:
with open(config_path, 'r') as f:
config = json.load(f)
self.states = [[BehaviorState(s) for s in row] for row in config["states"]]
self.trigger_mappings = config["trigger_mappings"]
self.rows = config["grid_dimensions"]["rows"]
self.columns = config["grid_dimensions"]["columns"]
except (FileNotFoundError, json.JSONDecodeError, KeyError) as e:
print(f"FATAL: Could not load behavior states from {config_path}: {e}")
self.states = [[BehaviorState({}) for _ in range(4)] for _ in range(5)]
self.trigger_mappings = {}
self.rows = 5
self.columns = 4
# Default state is Engaged-Disciplined
self.current_row = 2
self.current_col = 0
def get_current_state(self) -> BehaviorState:
"""Returns the current BehaviorState object."""
return self.states[self.current_row][self.current_col]
def set_state_by_coords(self, row: int, col: int):
"""Sets the machine to a specific state using grid coordinates."""
self.current_row = max(0, min(row, self.rows - 1))
self.current_col = max(0, min(col, self.columns - 1))
print(f"[Behavior Engine] State set to: {self.get_current_state()}")
def set_state_by_label(self, label: str):
"""
Sets the machine to the first state matching the given name or id.
Returns True if a match is found, else False.
"""
if not label:
return False
label_lower = label.lower()
for r, row in enumerate(self.states):
for c, state in enumerate(row):
if state.name.lower() == label_lower or state.id.lower() == label_lower:
self.set_state_by_coords(r, c)
return True
print(f"[Behavior Engine] WARN: No state found matching '{label}'.")
return False
def transition_by_trigger(self, trigger: str | None, gait: str):
"""
Sets the state based on a user trigger, influenced by the current gait.
"""
if trigger and trigger in self.trigger_mappings:
target_row, target_col = self.trigger_mappings[trigger]
# --- Gait Influence Hook ---
# High-energy gaits can push the state towards higher intensity (rows).
if gait in ["trot", "gallop"]:
target_row = min(self.rows - 1, target_row + 1) # Increase intensity by 1
elif gait == "sprint":
target_row = min(self.rows - 1, target_row + 2) # Increase intensity by 2
elif gait == "idle":
target_row = max(0, target_row - 1) # Decrease intensity by 1
self.set_state_by_coords(target_row, target_col)
else:
# If no trigger, default to a neutral state
self.set_state_by_coords(2, 1)
def apply_state_to_memory(self, memory_manager: object):
"""Hook for influencing the memory system."""
current_state = self.get_current_state()
strictness = current_state.memory_strictness
print(f"[Behavior Engine] Memory hook called. Strictness level: '{strictness}'")