docs/en/concepts/06-extraction.md
OpenViking uses a three-layer async architecture for document parsing and context extraction.
Input File → Parser → TreeBuilder → SemanticQueue → Vector Index
↓ ↓ ↓
Parse & Move Files L0/L1 Generation
Convert Queue Semantic (LLM Async)
(No LLM)
Design Principle: Parsing and semantics are separated. Parser doesn't call LLM; semantic generation is async.
Parser handles document format conversion and structuring, creating file structure in temp directory.
| Format | Parser | Extensions | Status |
|---|---|---|---|
| Markdown | MarkdownParser | .md, .markdown | Supported |
| Plain text | TextParser | .txt | Supported |
| PDFParser | Supported | ||
| HTML | HTMLParser | .html, .htm | Supported |
| Code | CodeRepositoryParser | .py, .js, .go, etc. | Respects .gitignore and ignores common non-code directories |
| Image | ImageParser | .png, .jpg, etc. | |
| Video | VideoParser | .mp4, .avi, etc. | |
| Audio | AudioParser | .mp3, .wav, etc. |
# 1. Parse file
parse_result = registry.parse("/path/to/doc.md")
# 2. Returns temp directory URI
parse_result.temp_dir_path # viking://temp/abc123
If document_tokens <= 1024:
→ Save as single file
Else:
→ Split by headers
→ Section < 512 tokens → Merge
→ Section > 1024 tokens → Create subdirectory
ParseResult(
temp_dir_path: str, # Temp directory URI
source_format: str, # pdf/markdown/html
parser_name: str, # Parser name
parse_time: float, # Duration (seconds)
meta: Dict, # Metadata
)
TreeBuilder moves temp directory to AGFS and queues semantic processing.
building_tree = tree_builder.finalize_from_temp(
temp_dir_path="viking://temp/abc123",
scope="resources", # resources/user
)
| scope | Base URI |
|---|---|
| resources | viking://resources |
| user | viking://user |
SemanticQueue handles async L0/L1 generation and vectorization.
SemanticMsg(
id: str, # UUID
uri: str, # Directory URI
context_type: str, # resource/memory/skill
status: str, # pending/processing/completed
)
Leaf directories → Parent directories → Root
| Parameter | Default | Description |
|---|---|---|
max_concurrent_llm | 10 | Concurrent LLM calls |
max_images_per_call | 10 | Max images per VLM call |
max_sections_per_call | 20 | Max sections per VLM call |
For code files, OpenViking uses a fixed skeleton extraction route. This route is built into the code summary pipeline and is not selected or tuned by per-language parser settings.
The skeleton can include imports, classes, methods, functions, and other language-level symbols. Exact output depends on the maintained query or generic parser result for that language, but the route itself is fixed.
Code skeleton extraction follows this fixed order:
tags.scm query when one exists for the language.tags.scm exists, use tree-sitter-language-pack.process().semantic.code_summary only as fallback when the extraction route produces no useful skeleton.This routing applies to short and long code files alike.
| Phase | Resource | Memory | Skill |
|---|---|---|---|
| Parser | Common flow | Common flow | Common flow |
| Base URI | viking://resources | viking://user/memories | viking://user/skills |
| TreeBuilder scope | resources | user | user |
| SemanticMsg type | resource | memory | skill |
# Add resource
await client.add_resource(
"/path/to/doc.pdf",
reason="API documentation"
)
# Flow: Parser → TreeBuilder(scope=resources) → SemanticQueue
# Add skill
await client.add_skill({
"name": "search-web",
"content": "# search-web\\n..."
})
# Flow: Direct write to viking://user/skills/{name}/ → SemanticQueue
# Memory auto-extracted from session
await session.commit()
# Flow: SessionCompressorV2 → ExtractLoop → MemoryUpdater → SemanticQueue