Skip to content

Commit b889efa

Browse files
authored
Merge pull request #54 from vektori-ai/feat/pipecat-voice-integration
feat(pipecat): voice agent integration with persistent memory
2 parents f26c68b + 65877b0 commit b889efa

12 files changed

Lines changed: 1347 additions & 20 deletions

File tree

examples/agent_type_extraction.py

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
"""
2+
Vektori — Agent-type extraction customisation examples
3+
=======================================================
4+
5+
Shows how to tailor what Vektori extracts at L0 (facts) and L1 (episodes)
6+
for different agent personas. The same conversation is run through three
7+
differently-configured Vektori instances so you can see the effect.
8+
9+
Quick-start
10+
-----------
11+
export OPENAI_API_KEY=...
12+
python examples/agent_type_extraction.py
13+
14+
Levels of customisation
15+
-----------------------
16+
Level 1 — agent_type preset (zero effort):
17+
Vektori(agent_type="presales")
18+
19+
Level 2 — domain hints on top of a preset:
20+
Vektori(extraction_config=ExtractionConfig(
21+
agent_type="presales",
22+
focus_on=["ICP fit", "executive sponsor"],
23+
ignore=["pleasantries"],
24+
))
25+
26+
Level 3 — prompt suffix (low effort, precise control):
27+
Vektori(extraction_config=ExtractionConfig(
28+
agent_type="sales",
29+
facts_prompt_suffix="Always extract the exact dollar amount when pricing is mentioned.",
30+
))
31+
32+
Level 4 — full prompt override (escape hatch):
33+
Vektori(extraction_config=ExtractionConfig(
34+
custom_facts_prompt=MY_PROMPT_TEMPLATE,
35+
))
36+
"""
37+
38+
import asyncio
39+
import json
40+
41+
from vektori import ExtractionConfig, Vektori
42+
43+
# ---------------------------------------------------------------------------
44+
# A realistic pre-sales discovery call snippet
45+
# ---------------------------------------------------------------------------
46+
PRESALES_CONVERSATION = [
47+
{
48+
"role": "user",
49+
"content": (
50+
"We're a Series B fintech, around 200 engineers. "
51+
"Right now our AI agents lose context between sessions — support keeps "
52+
"repeating the same questions to customers. It's killing CSAT scores."
53+
),
54+
},
55+
{
56+
"role": "assistant",
57+
"content": (
58+
"That's a common friction point at your scale. What does your current "
59+
"session storage look like — are you on something like Redis, or more ad hoc?"
60+
),
61+
},
62+
{
63+
"role": "user",
64+
"content": (
65+
"Ad hoc, honestly. Each team rolls their own. Our CTO wants a unified "
66+
"memory layer by Q3 — we've got maybe a $60–80K budget for tooling this half. "
67+
"We tried Mem0 briefly but the graph retrieval wasn't granular enough."
68+
),
69+
},
70+
{
71+
"role": "assistant",
72+
"content": (
73+
"Got it. So you need something that preserves the full conversation story, "
74+
"not just entity triples — that's exactly what Vektori's three-layer graph "
75+
"is built for. Who else is involved in the decision besides your CTO?"
76+
),
77+
},
78+
{
79+
"role": "user",
80+
"content": (
81+
"Our VP Eng and the platform team lead, Aisha. She's the one who'd actually "
82+
"integrate it. They're both pretty hands-on technically."
83+
),
84+
},
85+
]
86+
87+
# ---------------------------------------------------------------------------
88+
# A sales closing call
89+
# ---------------------------------------------------------------------------
90+
SALES_CONVERSATION = [
91+
{
92+
"role": "user",
93+
"content": (
94+
"We reviewed the proposal. Legal flagged the data residency clause — "
95+
"they need EU hosting confirmed before we can sign."
96+
),
97+
},
98+
{
99+
"role": "assistant",
100+
"content": (
101+
"Understood. Our EU region is live on AWS eu-west-1 — I'll get that "
102+
"confirmed in writing by tomorrow. Are there any other open items?"
103+
),
104+
},
105+
{
106+
"role": "user",
107+
"content": (
108+
"Just that. We're looking at the $48K/year enterprise tier. "
109+
"If legal clears it this week we can sign by Friday the 18th."
110+
),
111+
},
112+
{
113+
"role": "assistant",
114+
"content": (
115+
"Perfect. I'll loop in our legal team tonight. I'll also prep the "
116+
"countersigned order form so it's ready to go the moment you get approval."
117+
),
118+
},
119+
]
120+
121+
122+
async def run_demo():
123+
print("=" * 70)
124+
print("Vektori ExtractionConfig demo")
125+
print("=" * 70)
126+
127+
# ------------------------------------------------------------------
128+
# Example 1: pre-sales preset — zero effort
129+
# ------------------------------------------------------------------
130+
print("\n[1] agent_type='presales' — built-in preset\n")
131+
132+
presales_v = Vektori(agent_type="presales")
133+
captured: list[dict] = []
134+
await presales_v.add(
135+
messages=PRESALES_CONVERSATION,
136+
session_id="demo-presales-001",
137+
user_id="demo-user",
138+
# _capture_out is an internal debug hook used in tests
139+
)
140+
# Give async extraction a moment to complete for the demo
141+
await asyncio.sleep(3)
142+
memory = await presales_v.search("budget and decision makers", user_id="demo-user")
143+
print("Facts retrieved (presales):")
144+
for f in memory.get("facts", []):
145+
print(f" • {f['text']}")
146+
await presales_v.close()
147+
148+
# ------------------------------------------------------------------
149+
# Example 2: sales preset + domain hints
150+
# ------------------------------------------------------------------
151+
print("\n[2] agent_type='sales' + focus_on=['contract value', 'close date']\n")
152+
153+
sales_v = Vektori(
154+
extraction_config=ExtractionConfig(
155+
agent_type="sales",
156+
focus_on=["contract value", "close date", "legal blockers"],
157+
)
158+
)
159+
await sales_v.add(
160+
messages=SALES_CONVERSATION,
161+
session_id="demo-sales-001",
162+
user_id="demo-sales-user",
163+
)
164+
await asyncio.sleep(3)
165+
memory = await sales_v.search("deal status and blockers", user_id="demo-sales-user")
166+
print("Facts retrieved (sales):")
167+
for f in memory.get("facts", []):
168+
print(f" • {f['text']}")
169+
await sales_v.close()
170+
171+
# ------------------------------------------------------------------
172+
# Example 3: same sales call, general (no preset) — shows the difference
173+
# ------------------------------------------------------------------
174+
print("\n[3] agent_type='general' — no domain bias (baseline)\n")
175+
176+
general_v = Vektori() # default, no agent_type
177+
await general_v.add(
178+
messages=SALES_CONVERSATION,
179+
session_id="demo-general-001",
180+
user_id="demo-general-user",
181+
)
182+
await asyncio.sleep(3)
183+
memory = await general_v.search("deal status and blockers", user_id="demo-general-user")
184+
print("Facts retrieved (general):")
185+
for f in memory.get("facts", []):
186+
print(f" • {f['text']}")
187+
await general_v.close()
188+
189+
print("\nDone.")
190+
191+
192+
if __name__ == "__main__":
193+
asyncio.run(run_demo())

0 commit comments

Comments
 (0)