Skip to content
Back to skills

Hume Evi Langgraph

ASecurity

Integrate Hume EVI voice AI with LangGraph using interrupt/resume patterns. Use when building voice-based AI agents that need Twilio call handling, Hume EVI persona creation, transcript fetching with emotion extraction, and LangGraph state management across the call lifecycle. Covers dynamic Hume config creation, TwiML generation, webhook handling, chat_group event fetching, and emotion timeline extraction.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 11, 2026
ai-agentspythonapi

Works with

  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned November 11, 2026

npx -y skills add johnalbertini14-glitch/openclaw-skills --skill hume-evi-langgraph --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hume Evi Langgraph?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hume Evi Langgraph
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/johnalbertini14-glitch-hume-evi-langgraph/badge)](https://www.skillsdirectory.com/skills/johnalbertini14-glitch-hume-evi-langgraph)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hume-evi-langgraph
description: Integrate Hume EVI voice AI with LangGraph using interrupt/resume patterns. Use when building voice-based AI agents that need Twilio call handling, Hume EVI persona creation, transcript fetching with emotion extraction, and LangGraph state management across the call lifecycle. Covers dynamic Hume config creation, TwiML generation, webhook handling, chat_group event fetching, and emotion timeline extraction.
---

# Hume EVI + LangGraph Integration

## Architecture

Single LangGraph StateGraph with interrupt/resume:

```
receive_call → verify_pin → select_persona → create_hume_config → generate_twiml
    → await_call_end [INTERRUPT] → fetch_transcript → analyze → coach → store → END
```

The interrupt boundary separates pre-call (synchronous) from post-call (webhook-triggered).

## Critical Patterns

### 1. Interrupt/Resume for Async Calls

```python
from langgraph.types import interrupt, Command

def await_call_end(state):
    resume_data = interrupt({"reason": "waiting_for_webhook"})
    return {**state, "chat_id": resume_data["chat_id"]}

# In webhook handler:
graph.invoke(Command(resume={"chat_id": "xxx"}), config)
```

### 2. Hume Config Creation

Create dynamic EVI configs per call. Set temperature low (0.6) to prevent default enthusiasm:

```python
request_body = {
    "evi_version": "3",
    "name": f"Session-{persona_name}-{timestamp}",
    "prompt": {"text": voice_prompt},
    "voice": {"provider": "HUME_AI", "name": "KORA"},  # or "ITO" for male
    "language_model": {
        "model_provider": "OPEN_AI",
        "model_resource": "gpt-4o-mini",
        "temperature": 0.6,  # CRITICAL: default is too warm/eager
    },
    "event_messages": {"on_new_chat": {"enabled": True, "text": first_message}},
    "webhooks": [{"events": ["chat_ended"], "url": webhook_url}],
}
resp = httpx.post("https://api.hume.ai/v0/evi/configs", json=request_body, headers=headers)
```

### 3. TwiML Redirect (not Stream)

```python
twiml = f'''<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say voice="Polly.Matthew">Connecting now.</Say>
    <Redirect>https://api.hume.ai/v0/evi/twilio?config_id={config_id}&amp;api_key={api_key}</Redirect>
</Response>'''
```

Use `&amp;` not `&` — this is inside XML.

### 4. Transcript Fetching (⚠️ Known Bug Zone)

Hume's `/chats/{id}/events` returns 404. Must use chat_groups:

```python
# Step 1: Get chat_group_id
chat_resp = httpx.get(f"https://api.hume.ai/v0/evi/chats/{chat_id}", headers=headers)
chat_group_id = chat_resp.json().get("chat_group_id")

# Step 2: Fetch events via chat_group
events_resp = httpx.get(
    f"https://api.hume.ai/v0/evi/chat_groups/{chat_group_id}/events",
    headers=headers, params={"page_size": 100}
)
events = events_resp.json().get("events_page", [])
```

Field names are **snake_case**: `message_text`, `emotion_features` (not `messageText`).

### 5. Emotion Extraction

```python
for msg in messages:
    ef = msg.get("emotion_features")  # dict of ~48 emotions with float scores
    if ef and msg.get("role") == "USER":  # USER = the human caller
        top = sorted(ef.items(), key=lambda x: x[1], reverse=True)[:5]
        emotion_timeline.append({"turn": n, "text": text, "top_emotions": dict(top)})
```

### 6. Webhook Session Resolution

Hume `chat_ended` webhook does NOT include `call_sid`. Use config_id mapping:

```python
config_to_thread: dict[str, str] = {}  # hume_config_id → langgraph_thread_id

# On config creation:
config_to_thread[config_id] = thread_id

# On webhook:
thread_id = config_to_thread.pop(body["config_id"])
```

## Prevention Rules

See `references/bug-prevention.md` for the full bug registry and prevention checklist.

Files in this skill

  • SKILL.md3.6 KB
  • _meta.json319 B
  • references/bug-prevention.md2.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in ai-agents →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.