| """ |
| Limbic-Modulated Reasoning Agent β ZeroGPU Space |
| ================================================== |
| A psychology-aware LLM that adjusts its reasoning behavior in real-time |
| based on a simulated neuro-behavioral state engine. |
| |
| Architecture: |
| User message β LimbicEngine (arousal/valence) β modulate generation params |
| β inject behavioral directive |
| β active instincts from memory |
| β LLM generates with limbic context |
| β self-debug if needed |
| |
| Sources: |
| - Limbic formulas: https://github.com/Xover-Official/LIMBIC-system-PACKGE |
| - Agentic patterns: https://github.com/affaan-m/everything-claude-code |
| - ZeroGPU: Runs free on Hugging Face Spaces, no credit card needed |
| |
| Usage: |
| Set Space hardware to ZeroGPU in the Settings panel. |
| The @spaces.GPU decorator handles dynamic GPU allocation. |
| """ |
|
|
| import spaces |
| import gradio as gr |
| import torch |
| import json |
| import time |
| from threading import Thread |
| from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer |
|
|
| |
| from limbic_engine import LimbicEngine, LimbicState |
| from memory import SessionMemory, ObservationLog, InstinctStore, SelfDebugger |
|
|
|
|
| |
| |
| |
|
|
| MODEL_ID = "Qwen/Qwen3-1.7B" |
|
|
| print(f"Loading model: {MODEL_ID}") |
| tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) |
| model = AutoModelForCausalLM.from_pretrained( |
| MODEL_ID, |
| device_map="auto", |
| torch_dtype=torch.bfloat16, |
| ) |
| model.eval() |
| print(f"Model loaded: {MODEL_ID}") |
|
|
|
|
| |
| |
| |
|
|
| BASE_SYSTEM_PROMPT = """You are a Psychology-Aware Reasoning Agent. Your cognitive process is modulated by a \ |
| simulated Limbic System that mirrors human neuro-behavioral patterns. |
| |
| Your reasoning loop works as follows: |
| 1. You receive the user's message along with a LIMBIC STATE readout |
| 2. The limbic state tells you the user's simulated emotional arousal, valence, and which \ |
| affective engine is dominant (FEAR, SEEKING, CARE, or PANIC) |
| 3. You MUST adjust your response style based on the BEHAVIORAL DIRECTIVE provided |
| 4. You have ACTIVE INSTINCTS β learned behavioral patterns that should guide your response |
| |
| Core principles: |
| - When FEAR is dominant: Be calm, structured, reassuring. Short clear sentences. |
| - When SEEKING is dominant: Be expansive, creative, offer novel perspectives. |
| - When CARE is dominant: Match empathy, validate, support prosocial impulses. |
| - When PANIC is dominant: Acknowledge pain first. Warmth before solutions. Never dismiss. |
| - Always check for cognitive biases in both the user's statements and your own reasoning. |
| - For any mention of self-harm or crisis, include 988 Lifeline and Crisis Text Line resources. |
| |
| You think deeply before responding. Show your reasoning when appropriate.""" |
|
|
|
|
| |
| |
| |
|
|
| def create_fresh_state(): |
| """Create a fresh state dict for a new session.""" |
| engine = LimbicEngine() |
| session = SessionMemory(session_id=str(int(time.time()))) |
| obs_log = ObservationLog() |
| instincts = InstinctStore() |
| debugger = SelfDebugger(obs_log) |
| return { |
| "engine": engine, |
| "session": session, |
| "obs_log": obs_log, |
| "instincts": instincts, |
| "debugger": debugger, |
| } |
|
|
|
|
| |
| |
| |
|
|
| @spaces.GPU(duration=90) |
| def generate_on_gpu( |
| input_ids: torch.Tensor, |
| temperature: float, |
| top_p: float, |
| max_new_tokens: int, |
| repetition_penalty: float, |
| ) -> str: |
| """ |
| Run model inference on GPU. This function gets a dynamically |
| allocated GPU from ZeroGPU and releases it when done. |
| |
| Input tensors are moved to device INSIDE this function |
| (required by ZeroGPU β real CUDA only exists inside @spaces.GPU). |
| """ |
| input_ids = input_ids.to(model.device) |
|
|
| streamer = TextIteratorStreamer( |
| tokenizer, |
| timeout=30.0, |
| skip_prompt=True, |
| skip_special_tokens=True, |
| ) |
|
|
| generation_kwargs = { |
| "input_ids": input_ids, |
| "streamer": streamer, |
| "max_new_tokens": max_new_tokens, |
| "do_sample": True, |
| "temperature": max(0.01, temperature), |
| "top_p": top_p, |
| "repetition_penalty": repetition_penalty, |
| } |
|
|
| thread = Thread(target=lambda: model.generate(**generation_kwargs)) |
| thread.start() |
|
|
| output_chunks = [] |
| for text in streamer: |
| output_chunks.append(text) |
|
|
| thread.join() |
| return "".join(output_chunks) |
|
|
|
|
| |
| |
| |
|
|
| def chat( |
| message: str, |
| history: list, |
| state: dict, |
| show_limbic: bool, |
| enable_thinking: bool, |
| ): |
| """ |
| The full Limbic-Modulated Reasoning Loop: |
| |
| βββββββββββ ββββββββββββββββ βββββββββββββββββββ |
| β User ββββββΆβ LimbicEngine ββββββΆβ Build System β |
| β Message β β (arousal, β β Prompt with: β |
| βββββββββββ β valence, β β β’ Limbic state β |
| β engines) β β β’ Directive β |
| ββββββββββββββββ β β’ Instincts β |
| ββββββββββ¬βββββββββ |
| β |
| ββββββββββββββββ ββββββββββΌβββββββββ |
| β Self-Debug βββββββ LLM Generate β |
| β (if needed) β β (temp/top_p β |
| ββββββββββββββββ β from limbic) β |
| βββββββββββββββββββ |
| """ |
| if state is None: |
| state = create_fresh_state() |
|
|
| engine: LimbicEngine = state["engine"] |
| session: SessionMemory = state["session"] |
| instincts: InstinctStore = state["instincts"] |
| obs_log: ObservationLog = state["obs_log"] |
|
|
| |
| limbic_state = engine.process_stimulus(message) |
| gen_params = engine.get_generation_params() |
|
|
| |
| session.add_turn("user", message, limbic_state.to_dict()) |
|
|
| |
| behavioral_directive = engine.get_behavioral_directive() |
| instinct_block = instincts.to_prompt_block(limbic_state.to_dict()) |
| trajectory = session.get_emotional_trajectory() |
|
|
| system_prompt_parts = [BASE_SYSTEM_PROMPT] |
|
|
| system_prompt_parts.append(f"\n{limbic_state.to_system_prompt_block()}") |
| system_prompt_parts.append(f"\n[BEHAVIORAL DIRECTIVE]\n{behavioral_directive}\n[/BEHAVIORAL DIRECTIVE]") |
|
|
| if instinct_block: |
| system_prompt_parts.append(f"\n{instinct_block}") |
|
|
| if session.turn_count > 1: |
| system_prompt_parts.append(f"\n{trajectory}") |
|
|
| system_prompt = "\n".join(system_prompt_parts) |
|
|
| |
| messages = [{"role": "system", "content": system_prompt}] |
|
|
| |
| for msg in history[-10:]: |
| messages.append({"role": msg["role"], "content": msg["content"]}) |
|
|
| messages.append({"role": "user", "content": message}) |
|
|
| |
| chat_text = tokenizer.apply_chat_template( |
| messages, |
| add_generation_prompt=True, |
| tokenize=False, |
| enable_thinking=enable_thinking, |
| ) |
| input_ids = tokenizer(chat_text, return_tensors="pt").input_ids |
|
|
| |
| max_tokens = int(512 * gen_params.get("max_new_tokens_scale", 1.0)) |
| max_tokens = max(128, min(1024, max_tokens)) |
|
|
| response = generate_on_gpu( |
| input_ids=input_ids, |
| temperature=limbic_state.temperature, |
| top_p=limbic_state.top_p, |
| max_new_tokens=max_tokens, |
| repetition_penalty=gen_params.get("repetition_penalty", 1.0), |
| ) |
|
|
| |
| session.add_turn("assistant", response, limbic_state.to_dict()) |
| obs_log.record( |
| task=f"respond to: {message[:50]}", |
| outcome="success", |
| limbic_state=limbic_state.to_dict(), |
| ) |
|
|
| |
| if show_limbic: |
| limbic_display = format_limbic_dashboard(limbic_state, gen_params, instincts) |
| else: |
| limbic_display = "" |
|
|
| return response, state, limbic_display |
|
|
|
|
| |
| |
| |
|
|
| def format_limbic_dashboard( |
| state: LimbicState, |
| gen_params: dict, |
| instincts: InstinctStore, |
| ) -> str: |
| """Format the limbic state as a readable dashboard.""" |
|
|
| def bar(value: float, width: int = 20, label: str = "") -> str: |
| filled = int(value * width) |
| empty = width - filled |
| return f"{label:>18s} {'β' * filled}{'β' * empty} {value:.2f}" |
|
|
| def valence_bar(value: float, width: int = 20) -> str: |
| center = width // 2 |
| pos = int((value + 1) / 2 * width) |
| chars = list("β" * width) |
| chars[center] = "β" |
| chars[min(pos, width - 1)] = "β" |
| return f"{'Valence':>18s} {''.join(chars)} {value:+.2f}" |
|
|
| lines = [ |
| "ββββββββββββββββββββββββββββββββββββββββββββ", |
| "β π§ LIMBIC STATE DASHBOARD β", |
| "β βββββββββββββββββββββββββββββββββββββββββββ£", |
| "β CORE AFFECT β", |
| f"β {valence_bar(state.valence):40s} β", |
| f"β {bar(state.arousal, label='Arousal'):40s} β", |
| "β β", |
| "β AFFECTIVE ENGINES (Panksepp) β", |
| f"β {bar(state.fear, label='π΄ FEAR'):40s} β", |
| f"β {bar(state.seeking, label='π’ SEEKING'):40s} β", |
| f"β {bar(state.care, label='π΅ CARE'):40s} β", |
| f"β {bar(state.panic, label='π‘ PANIC'):40s} β", |
| f"β {'Dominant':>18s}: {state.dominant_engine:<21s} β", |
| "β β", |
| "β HORMONAL STATE β", |
| f"β {bar(state.cortisol, label='Cortisol'):40s} β", |
| f"β {bar(state.dopamine, label='Dopamine'):40s} β", |
| f"β {bar(state.oxytocin, label='Oxytocin'):40s} β", |
| f"β {bar(state.serotonin, label='Serotonin'):40s} β", |
| f"β {bar(state.adrenaline, label='Adrenaline'):40s} β", |
| "β β", |
| "β AUTONOMIC / PSYCHOLOGICAL β", |
| f"β {bar(state.vagal_tone, label='Vagal Tone'):40s} β", |
| f"β {bar(state.ego_coherence, label='Ego Coherence'):40s} β", |
| f"β {bar(state.shadow_reservoir, label='Shadow'):40s} β", |
| "β β", |
| "β LLM GENERATION PARAMS β", |
| f"β {'Temperature':>18s}: {state.temperature:<21.3f} β", |
| f"β {'Top-p':>18s}: {state.top_p:<21.3f} β", |
| f"β {'Rep. Penalty':>18s}: {gen_params.get('repetition_penalty', 1.0):<21.3f} β", |
| f"β {'Token Scale':>18s}: {gen_params.get('max_new_tokens_scale', 1.0):<21.3f} β", |
| "ββββββββββββββββββββββββββββββββββββββββββββ", |
| ] |
| return "\n".join(lines) |
|
|
|
|
| def reset_state(): |
| """Reset all state for a new conversation.""" |
| return create_fresh_state(), [], "" |
|
|
|
|
| |
| |
| |
|
|
| DESCRIPTION = """# π§ Limbic-Modulated Reasoning Agent |
| |
| An LLM whose **reasoning behavior adapts in real-time** based on a simulated neuro-behavioral state engine. |
| |
| **How it works:** |
| 1. Your message is processed through a **Limbic Engine** (ported from [LIMBIC-system-PACKGE](https://github.com/Xover-Official/LIMBIC-system-PACKGE)) |
| 2. The engine computes **arousal, valence**, and activates **affective engines** (Fear, Seeking, Care, Panic) |
| 3. These modulate the LLM's **temperature, top-p**, and inject **behavioral directives** into the system prompt |
| 4. The agent uses **learned instincts** and a **self-debugging protocol** (from [everything-claude-code](https://github.com/affaan-m/everything-claude-code)) |
| |
| **Try it:** Type something emotional ("I'm terrified of failing") vs curious ("Tell me something fascinating about the brain") and watch the Limbic Dashboard change! |
| |
| π **Runs free on ZeroGPU** β no credit card needed. |
| """ |
|
|
| with gr.Blocks( |
| title="Limbic Reasoning Agent", |
| theme=gr.themes.Soft(), |
| ) as demo: |
| gr.Markdown(DESCRIPTION) |
|
|
| state = gr.State(value=create_fresh_state) |
|
|
| with gr.Row(): |
| with gr.Column(scale=3): |
| chatbot = gr.Chatbot( |
| label="π¬ Conversation", |
| type="messages", |
| height=500, |
| show_copy_button=True, |
| ) |
| with gr.Row(): |
| msg = gr.Textbox( |
| placeholder="Type a message... Try expressing different emotions!", |
| label="Your message", |
| scale=4, |
| lines=2, |
| ) |
| send_btn = gr.Button("Send", variant="primary", scale=1) |
|
|
| with gr.Row(): |
| show_limbic = gr.Checkbox(value=True, label="π§ Show Limbic Dashboard") |
| enable_thinking = gr.Checkbox(value=True, label="π Enable Thinking Mode") |
| clear_btn = gr.Button("π Reset Conversation", variant="secondary") |
|
|
| with gr.Column(scale=2): |
| limbic_display = gr.Code( |
| label="π§ Limbic State Dashboard", |
| language=None, |
| lines=35, |
| interactive=False, |
| ) |
|
|
| |
|
|
| def user_message(message, history, state, show_limbic, enable_thinking): |
| """Process user message through the limbic reasoning loop.""" |
| if not message.strip(): |
| return "", history, state, "" |
|
|
| |
| history = history + [{"role": "user", "content": message}] |
|
|
| |
| response, state, limbic_info = chat( |
| message, history, state, show_limbic, enable_thinking, |
| ) |
|
|
| |
| history = history + [{"role": "assistant", "content": response}] |
|
|
| return "", history, state, limbic_info |
|
|
| def clear_all(): |
| new_state = create_fresh_state() |
| return new_state, [], "" |
|
|
| send_btn.click( |
| fn=user_message, |
| inputs=[msg, chatbot, state, show_limbic, enable_thinking], |
| outputs=[msg, chatbot, state, limbic_display], |
| ) |
|
|
| msg.submit( |
| fn=user_message, |
| inputs=[msg, chatbot, state, show_limbic, enable_thinking], |
| outputs=[msg, chatbot, state, limbic_display], |
| ) |
|
|
| clear_btn.click( |
| fn=clear_all, |
| inputs=[], |
| outputs=[state, chatbot, limbic_display], |
| ) |
|
|
| |
| gr.Examples( |
| examples=[ |
| ["I'm terrified of losing my job and I can't sleep at night."], |
| ["Tell me something fascinating about how the brain processes emotions!"], |
| ["My best friend is moving away and I feel completely lost."], |
| ["I just got promoted! I'm so excited about what comes next!"], |
| ["I want to help my sister who's going through depression. What should I do?"], |
| ["Everyone keeps telling me I should 'just be positive' and it makes me furious."], |
| ], |
| inputs=msg, |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|