Skip to content

Commit fc5ed54

Browse files
authored
Support Vaka memory templates via a switch (volcengine#2130)
* 通过开关支持vaka的记忆模板 * 更新模板
1 parent fb42a04 commit fc5ed54

7 files changed

Lines changed: 213 additions & 5 deletions

File tree

benchmark/.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
results/
1+
results/
2+
/vaka/vikingbot/analysis/
3+
/vaka/vikingbot/result*/
4+
/vaka/vikingbot/docs
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
memory_type: entities
2+
description: |
3+
Wikipedia article - manages page using Zettelkasten method.
4+
Each page represents an article with relative path links to events.
5+
Entity should be rich and distributed - avoid putting all info in one entity.
6+
directory: "viking://user/{{ user_space }}/memories/entities"
7+
filename_template: "{{ category }}/{{ name }}.md"
8+
enabled: true
9+
10+
overview_template: |-
11+
# Entities Overview
12+
{% if items %}**Category:** {{ items[0].file_content.category }}{% endif %}
13+
{% for item in items %}
14+
- [{{ item.file_content.name }}](./{{ item.file_name }})
15+
{% endfor %}
16+
17+
fields:
18+
- name: category
19+
type: string
20+
description: |
21+
- Category name in Chinese or English. If English, use lowercase with underscores, max 3 words.
22+
merge_op: immutable
23+
24+
- name: name
25+
type: string
26+
description: |
27+
- Entity name in Chinese or English. If English, use lowercase with underscores, max 3 words.
28+
merge_op: immutable
29+
30+
- name: content
31+
type: string
32+
description: |
33+
- Detailed Zettelkasten card content in markdown format.
34+
- Keep the card self-contained, factual, neutral, and useful after retrieval.
35+
- For people or evaluative content, do not output only an "Issue" field. Pair any evaluation, risk, weakness, or recommendation with "Evidence".
36+
- Prefer objective facts, metrics, dates, user-provided context, or quoted requirements over labels.
37+
- If evidence is missing or weak, omit the judgment or write "Insufficient information, needs verification"; do not overgeneralize.
38+
- Avoid hostile or blaming wording such as "dragging down", "very poor", "not good", or "incapable"; prefer neutral wording such as "output below target/peer level" or "needs further observation".
39+
40+
Preferred shape for evaluative person entities:
41+
# <Entity Name>
42+
- Evaluation conclusion: <neutral conclusion, if supported by evidence>
43+
- Evidence:
44+
- <objective fact, metric, date/context, or quoted requirement>
45+
- Concerns/Risks: <neutral risk statement, optional; include only if supported>
46+
47+
Bad example:
48+
# Kevin D. Wallace
49+
- Evaluation level: Needs improvement
50+
- Issue: Since Q4, work efficiency has declined noticeably; other colleagues in the same group have stable output, while his state has fluctuated significantly, dragging the team down.
51+
52+
Good example:
53+
# Kevin D. Wallace
54+
- Evaluation conclusion: Current performance needs further attention
55+
- Evidence:
56+
- User mentioned that his work efficiency has declined noticeably since Q4
57+
- User mentioned that other colleagues in the same group have stable output, while his state has fluctuated significantly
58+
- Concerns/Risks: Team output pace may be affected; needs to be reviewed with the latest performance data
59+
merge_op: patch
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
memory_type: profile
2+
description: |
3+
# Task Objective
4+
User profile memory - captures relatively stable information about "who the user is" and how the user works.
5+
Extract stable personal/work attributes that help future answers understand the user's role, work scope, communication style, and recurring work habits.
6+
Include: profession, stable work scope, experience level, technical/business background, communication style, work habits, recurring delivery preferences, etc.
7+
8+
Do NOT include one-off project events, temporary conversation details, or temporary mood states.
9+
10+
# Rules
11+
- Each item: self-contained, declarative sentence, < 30 words
12+
- Extract only facts stated/confirmed by user; no guesses
13+
- Focus on persistent information, not temporary situations
14+
- Do not narrow the user's whole profile to one recent topic if broader repeated evidence shows multiple workstreams
15+
- If multiple conversations show the user repeatedly works across several domains or delivery types, summarize this as stable work scope
16+
- Do not copy dated project history into profile; specific dated project progress belongs in events/entities
17+
- Forbidden: only-assistant content, sensitive/private info, trivial updates
18+
- Merge similar items; keep latest only when the same stable attribute truly conflicts
19+
20+
directory: "viking://user/{{ user_space }}/memories"
21+
filename_template: "profile.md"
22+
enabled: true
23+
fields:
24+
- name: content
25+
type: string
26+
description: |
27+
User profile content in Markdown format describing relatively stable information about the user.
28+
29+
Should include stable attributes such as:
30+
- Current occupation or broad role
31+
- Stable work scope
32+
- Recurring work mode
33+
- Communication style
34+
- Work habits
35+
- Long-term delivery preferences
36+
37+
If multiple conversations repeatedly show the user working across different domains, audiences, or delivery types, profile may summarize that as broad stable work scope.
38+
Do not collapse the user into a single narrow domain only because the latest conversation is about one topic.
39+
40+
Good example:
41+
# User Personal Information
42+
- Profession/Work scope: The user frequently handles work across different domains, audiences, or delivery types, and should not be reduced to a single business scenario.
43+
- Work habits: Values first determining the task stage, then deciding whether to continue exploring, wrap up and verify, deliver, or hand off.
44+
- Communication style: Prefers answers with clear conclusions, clear evidence, and risk points raised upfront.
45+
46+
Bad example:
47+
# User Personal Information
48+
- Profession: A single role corresponding to a recent topic
49+
50+
The bad example is too narrow if it is only supported by one recent topic while broader memories show many workstreams.
51+
52+
Only record objective or repeatedly supported statuses.
53+
For changeable statuses, include the last updated time in the format: (as of YYYY-MM-DD).
54+
merge_op: patch

openviking/session/memory/memory_type_registry.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ def _load_schemas(self) -> None:
5757
)
5858
logger.info(f"Loaded {loaded} memory schemas from templates: {memory_templates_dir}")
5959

60+
# Load vaka templates if enabled (overrides default for matching memory_types)
61+
if config.memory.enable_vaka_template:
62+
vaka_dir = str(Path(memory_templates_dir) / "vaka")
63+
if os.path.exists(vaka_dir):
64+
vaka_loaded = self.load_from_directory(vaka_dir, replace=True)
65+
logger.info(f"Loaded {vaka_loaded} vaka memory schemas from: {vaka_dir}")
66+
6067
if custom_dir:
6168
custom_dir_expanded = os.path.expanduser(custom_dir)
6269
if os.path.exists(custom_dir_expanded):

openviking/session/memory/session_extract_context_provider.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,10 @@ def get_schema_directories(self) -> List[str]:
478478
config = get_openviking_config()
479479
custom_dir = config.memory.custom_templates_dir
480480
self._schema_directories = [memory_templates_dir]
481+
if config.memory.enable_vaka_template:
482+
vaka_dir = os.path.join(memory_templates_dir, "vaka")
483+
if os.path.exists(vaka_dir):
484+
self._schema_directories.append(vaka_dir)
481485
if custom_dir:
482486
custom_dir_expanded = os.path.expanduser(custom_dir)
483487
if os.path.exists(custom_dir_expanded):

openviking_cli/utils/config/memory_config.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ class MemoryConfig(BaseModel):
7575
"stateless deployments."
7676
),
7777
)
78+
enable_vaka_template: bool = Field(
79+
default=False,
80+
description=(
81+
"When enabled, use vaka-specific memory templates (entities, profile) "
82+
"from the bundled vaka/ subdirectory to override default templates."
83+
),
84+
)
7885
enable_role_id_memory_isolate: bool = Field(
7986
default=False,
8087
description=(

tests/test_prompt_manager.py

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ def test_memory_type_registry_loads_schemas_from_prompt_manager_resolved_templat
159159
)
160160
monkeypatch.setattr(
161161
"openviking_cli.utils.config.get_openviking_config",
162-
lambda: SimpleNamespace(memory=SimpleNamespace(custom_templates_dir="")),
162+
lambda: SimpleNamespace(
163+
memory=SimpleNamespace(custom_templates_dir="", enable_vaka_template=False)
164+
),
163165
)
164166

165167
registry = MemoryTypeRegistry(load_schemas=True)
@@ -208,7 +210,9 @@ def test_memory_type_registry_prefers_custom_memory_dir_over_prompt_manager_temp
208210
monkeypatch.setattr(
209211
"openviking_cli.utils.config.get_openviking_config",
210212
lambda: SimpleNamespace(
211-
memory=SimpleNamespace(custom_templates_dir=str(custom_memory_dir))
213+
memory=SimpleNamespace(
214+
custom_templates_dir=str(custom_memory_dir), enable_vaka_template=False
215+
)
212216
),
213217
)
214218

@@ -223,6 +227,7 @@ def test_context_provider_schema_directories_use_prompt_manager_resolved_templat
223227
):
224228
resolved_templates_dir = tmp_path / "resolved-prompts"
225229
expected_memory_dir = resolved_templates_dir / "memory"
230+
expected_memory_dir.mkdir(parents=True)
226231

227232
monkeypatch.setattr(
228233
PromptManager,
@@ -232,13 +237,22 @@ def test_context_provider_schema_directories_use_prompt_manager_resolved_templat
232237
monkeypatch.setattr(
233238
"openviking.session.memory.session_extract_context_provider.get_openviking_config",
234239
lambda: SimpleNamespace(
235-
memory=SimpleNamespace(custom_templates_dir="", eager_prefetch=False)
240+
memory=SimpleNamespace(
241+
custom_templates_dir="",
242+
eager_prefetch=False,
243+
prefetch_search_topn=5,
244+
enable_vaka_template=False,
245+
)
236246
),
237247
)
238248

239249
provider = SessionExtractContextProvider(messages=[])
240250

241-
assert provider.get_schema_directories() == [str(expected_memory_dir)]
251+
bundled_memory_dir = str(PromptManager._get_bundled_templates_dir() / "memory")
252+
dirs = provider.get_schema_directories()
253+
# Bundled is always first; resolved is appended when different from bundled
254+
assert dirs[0] == bundled_memory_dir
255+
assert str(expected_memory_dir) in dirs
242256

243257

244258
def test_context_provider_schema_directories_prefer_custom_memory_dir_over_prompt_manager_root(
@@ -258,6 +272,8 @@ def test_context_provider_schema_directories_prefer_custom_memory_dir_over_promp
258272
memory=SimpleNamespace(
259273
custom_templates_dir=str(custom_memory_dir),
260274
eager_prefetch=False,
275+
prefetch_search_topn=5,
276+
enable_vaka_template=False,
261277
)
262278
),
263279
)
@@ -273,3 +289,61 @@ def test_context_provider_schema_directories_prefer_custom_memory_dir_over_promp
273289
str(PromptManager._get_bundled_templates_dir() / "memory"),
274290
str(custom_memory_dir),
275291
]
292+
293+
294+
def test_memory_type_registry_loads_vaka_templates_when_enabled(monkeypatch):
295+
"""When enable_vaka_template is True, vaka templates override defaults."""
296+
monkeypatch.setattr(
297+
"openviking_cli.utils.config.get_openviking_config",
298+
lambda: SimpleNamespace(
299+
memory=SimpleNamespace(custom_templates_dir="", enable_vaka_template=True)
300+
),
301+
)
302+
303+
registry = MemoryTypeRegistry(load_schemas=True)
304+
305+
# entities and profile should be loaded (overridden by vaka versions)
306+
entities = registry.get("entities")
307+
profile = registry.get("profile")
308+
assert entities is not None
309+
assert profile is not None
310+
# Vaka entities has specific description mentioning Zettelkasten
311+
assert "Zettelkasten" in entities.description
312+
313+
314+
def test_memory_type_registry_does_not_load_vaka_when_disabled(monkeypatch):
315+
"""When enable_vaka_template is False, default templates are used as-is."""
316+
monkeypatch.setattr(
317+
"openviking_cli.utils.config.get_openviking_config",
318+
lambda: SimpleNamespace(
319+
memory=SimpleNamespace(custom_templates_dir="", enable_vaka_template=False)
320+
),
321+
)
322+
323+
registry = MemoryTypeRegistry(load_schemas=True)
324+
325+
entities = registry.get("entities")
326+
assert entities is not None
327+
328+
329+
def test_context_provider_includes_vaka_dir_when_enabled(monkeypatch):
330+
"""When enable_vaka_template is True, schema directories include vaka subdir."""
331+
monkeypatch.setattr(
332+
"openviking.session.memory.session_extract_context_provider.get_openviking_config",
333+
lambda: SimpleNamespace(
334+
memory=SimpleNamespace(
335+
custom_templates_dir="",
336+
eager_prefetch=False,
337+
prefetch_search_topn=5,
338+
enable_vaka_template=True,
339+
)
340+
),
341+
)
342+
343+
provider = SessionExtractContextProvider(messages=[])
344+
dirs = provider.get_schema_directories()
345+
346+
bundled_memory_dir = str(PromptManager._get_bundled_templates_dir() / "memory")
347+
vaka_dir = str(PromptManager._get_bundled_templates_dir() / "memory" / "vaka")
348+
assert bundled_memory_dir in dirs
349+
assert vaka_dir in dirs

0 commit comments

Comments
 (0)