Skip to content

Commit 0313068

Browse files
nvidiaruvnet
andcommitted
merge: sync upstream main (59 commits) into dev
Upstream catch-up from volcengine/OpenViking main at a18d4b9. Auto-merged (24 files): README, bot/config, crates/ov_cli, session/session.py, session/compressor{,_v2}.py, session/memory_deduplicator.py, memory_extractor.py, schema_model_generator.py, utils/uri.py, storage/viking_fs.py, storage/transaction/lock_manager.py, storage/queuefs/semantic_processor.py, retrieve/hierarchical_retriever.py, server/routers/content.py, server/routers/search.py, core/directories.py, prompts/templates/memory/preferences.yaml, examples/openclaw-plugin/{index,text-utils}.ts, examples/ov.conf.example, openviking_cli/utils/config/{memory_config,open_viking_config}.py, docs/en/concepts/08-session.md. Hand-resolved conflicts (14 files): Memory subsystem: - entities.yaml: adopt upstream category field + event linking, keep our brain-hardening rules (canonical names, Aliases section, one-card-per-entity). Removed upstream's Caroline LoCoMo leak. - events.yaml: adopt upstream year/month/day folder template. - memory_updater.py: keep dev's two-function _apply_write/_apply_edit structure with collision-safe entity writes, port get_year/get_month/get_day helpers to ExtractContext for events.yaml template to work. - session_extract_context_provider.py: keep dev's [Keywords] bug fix (_derive_search_keywords) — upstream volcengine#1159 did not address this. - extract_loop.py: keep dev's small-model extraction path. Dev's hard_cap iteration extension is more sophisticated than upstream's version. Storage: - collection_schemas.py: combine dev's BGE-M3 truncation (30k chars) with upstream volcengine#1301 embed_compat async wrapper. - queuefs/semantic_dag.py: combine dev's old_summary hash comparison with upstream's defensive null check on cached summary. - queuefs/semantic_queue.py: keep dev's 300-second dedup window with _TrackedSemanticRequest dataclass. - utils/summarizer.py: take upstream — convergent fix, upstream is superset of our context_type centralization plus resource cover handling. Models: - openai_vlm.py: merge timeout signature (float | None = 60.0). Plugin (TypeScript): - config.ts: keep dev's profileInjection/recallFormat/alignment fields, add upstream's bypassSessionPatterns deprecation alias. - client.ts: merge addSessionMessage signature (sessionId, role, content, parts?, agentId?, createdAt?), keep dev's createSession(), combine body building with optional created_at. - context-engine.ts: keep dev's driftDetector + alignment, add upstream's isBypassedSession helper + bypass early-return in doCommit/afterTurn. Drop upstream's inline afterTurn commit block — dev routes through doCommitOVSession. Update addSessionMessage call to 6-arg form. - memory-ranking.ts: keep dev's multi-slot recall + tool-experience separation architecture. Deferred upstream changes: - volcengine#1221 agfs→ragfs Rust rewrite: new Rust crates land but Python code unchanged; pyagfs handles auto-fallback via RAGFS_IMPL env var. - volcengine#1159 memory_updater unified operations refactor: kept dev's separate write/edit function structure to avoid cascading schema changes through extract_loop and related files. Critical security + bug fixes preserved from upstream: - volcengine#1319 leaked token removed from settings.py - volcengine#1133 SSRF hardening on HTTP resource ingestion - volcengine#1297 sanitize and cap recall queries (wraps our plugin recall) - volcengine#1277 configurable embedding circuit breaker - volcengine#1279 trusted mode without API key restricted to localhost - volcengine#1211 PID lock recycle + ownership checks + compressor refs - volcengine#1182 task API ownership leakage fix in content.py - volcengine#1301 embedder async contention reduction - volcengine#1226 prevent VLM blocking startup hang in redo recovery - volcengine#769/volcengine#792 queuefs dedupe memory semantic parent enqueues Critical dev fixes preserved: - [Keywords] placeholder root-cause fix (brain-hardening plan phase 1) - Episodic memory v2 (retrieval scope, category boosts, archive filter) - Qwen-9B small-model extraction compatibility - Plugin recall refactor (tool-experience separation, multi-tier recall) - Context-type centralized inference (convergent with upstream fix) - BGE-M3 embedding input truncation - URI normalization + collision-safe entity writes Merged on dev-local2 safety branch. Next steps: build + test before fast-forwarding dev. Co-Authored-By: claude-flow <ruv@ruv.net>
2 parents c6c3942 + a18d4b9 commit 0313068

File tree

455 files changed

+58940
-4883
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

455 files changed

+58940
-4883
lines changed

.github/workflows/_build.yml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,17 @@ jobs:
237237
mkdir -p openviking/bin
238238
cp target/${{ matrix.arch == 'aarch64' && 'aarch64-unknown-linux-gnu' || 'x86_64-unknown-linux-gnu' }}/release/ov openviking/bin/
239239
chmod +x openviking/bin/ov
240+
240241
- name: Clean workspace (force ignore dirty)
241242
shell: bash
242243
run: |
244+
# Back up pre-built artifacts before cleaning
245+
cp -a openviking/bin /tmp/_ov_bin || true
243246
git reset --hard HEAD
244247
git clean -fd
245248
rm -rf openviking/_version.py openviking.egg-info
249+
# Restore pre-built artifacts
250+
cp -a /tmp/_ov_bin openviking/bin || true
246251
# Ignore uv.lock changes to avoid dirty state in setuptools_scm
247252
git update-index --assume-unchanged uv.lock || true
248253
@@ -257,6 +262,8 @@ jobs:
257262
git status --ignored
258263
echo "=== Check openviking/_version.py ==="
259264
if [ -f openviking/_version.py ]; then cat openviking/_version.py; else echo "Not found"; fi
265+
echo "=== Verify pre-built artifacts survived clean ==="
266+
ls -la openviking/bin/ || true
260267
261268
- name: Build package (Wheel Only)
262269
run: uv build --wheel
@@ -276,11 +283,8 @@ jobs:
276283
- name: Repair wheels (Linux)
277284
run: |
278285
uv pip install auditwheel
279-
# Repair wheels and output to a temporary directory
280286
uv run auditwheel repair dist/*.whl -w dist_fixed
281-
# Remove original non-compliant wheels
282287
rm dist/*.whl
283-
# Move repaired wheels back to dist
284288
mv dist_fixed/*.whl dist/
285289
rmdir dist_fixed
286290
@@ -405,12 +409,17 @@ jobs:
405409
cp target/release/ov openviking/bin/
406410
chmod +x openviking/bin/ov
407411
fi
412+
408413
- name: Clean workspace (force ignore dirty)
409414
shell: bash
410415
run: |
416+
# Back up pre-built artifacts before cleaning
417+
cp -a openviking/bin /tmp/_ov_bin || true
411418
git reset --hard HEAD
412419
git clean -fd
413420
rm -rf openviking/_version.py openviking.egg-info
421+
# Restore pre-built artifacts
422+
cp -a /tmp/_ov_bin openviking/bin || true
414423
# Ignore uv.lock changes to avoid dirty state in setuptools_scm
415424
git update-index --assume-unchanged uv.lock || true
416425
@@ -425,6 +434,8 @@ jobs:
425434
git status --ignored
426435
echo "=== Check openviking/_version.py ==="
427436
if [ -f openviking/_version.py ]; then cat openviking/_version.py; else echo "Not found"; fi
437+
echo "=== Verify pre-built artifacts survived clean ==="
438+
ls -la openviking/bin/ || true
428439
429440
- name: Build package (Wheel Only)
430441
run: uv build --wheel

.github/workflows/api_test.yml

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: 03. API Integration Tests
1+
name: 06. API Integration Tests
22

33
on:
44
workflow_dispatch:
@@ -42,10 +42,12 @@ jobs:
4242
api-tests:
4343
name: API Integration Tests (${{ matrix.os }})
4444
runs-on: ${{ matrix.os }}
45+
timeout-minutes: 50
4546
strategy:
4647
fail-fast: false
48+
max-parallel: 2
4749
matrix:
48-
os: [ubuntu-24.04, ubuntu-24.04-arm, macos-14, macos-15-intel, windows-latest]
50+
os: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') && fromJSON('["ubuntu-24.04", "macos-14", "windows-latest"]') || fromJSON('["ubuntu-24.04"]') }}
4951

5052
steps:
5153
- uses: actions/checkout@v6
@@ -58,24 +60,17 @@ jobs:
5860
python-version: '3.10'
5961

6062
- name: Cache Go modules
61-
uses: actions/cache@v4
63+
uses: actions/cache@v5
64+
continue-on-error: true
6265
with:
6366
path: ~/go/pkg/mod
64-
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
67+
key: ${{ runner.os }}-go-${{ hashFiles('third_party/agfs/**/go.sum') }}
6568
restore-keys: |
6669
${{ runner.os }}-go-
6770
68-
- name: Cache C++ extensions
69-
uses: actions/cache@v4
70-
with:
71-
path: openviking/pyagfs
72-
key: ${{ runner.os }}-cpp-${{ hashFiles('**/CMakeLists.txt', '**/*.cpp', '**/*.h') }}
73-
restore-keys: |
74-
${{ runner.os }}-cpp-
75-
7671
- name: Cache Python dependencies (Unix)
7772
if: runner.os != 'Windows'
78-
uses: actions/cache@v4
73+
uses: actions/cache@v5
7974
with:
8075
path: ~/.cache/pip
8176
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt', '**/pyproject.toml') }}
@@ -84,7 +79,7 @@ jobs:
8479
8580
- name: Cache Python dependencies (Windows)
8681
if: runner.os == 'Windows'
87-
uses: actions/cache@v4
82+
uses: actions/cache@v5
8883
with:
8984
path: ~\AppData\Local\pip\Cache
9085
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt', '**/pyproject.toml') }}
@@ -94,7 +89,7 @@ jobs:
9489
- name: Set up Go
9590
uses: actions/setup-go@v6
9691
with:
97-
go-version: '1.22'
92+
go-version: '1.25.1'
9893

9994
- name: Install system dependencies (Ubuntu)
10095
if: runner.os == 'Linux'
@@ -109,7 +104,7 @@ jobs:
109104
- name: Install system dependencies (Windows)
110105
if: runner.os == 'Windows'
111106
run: |
112-
choco install cmake -y
107+
echo "cmake is pre-installed on Windows runner and will also be installed via pip"
113108
114109
- name: Install uv
115110
uses: astral-sh/setup-uv@v7
@@ -415,7 +410,8 @@ jobs:
415410
echo "Running basic tests only (no VLM/Embedding)"
416411
uv run python -m pytest . -v --html=api-test-report.html --self-contained-html \
417412
--ignore=retrieval/ --ignore=resources/test_pack.py --ignore=resources/test_wait_processed.py \
418-
--ignore=admin/ --ignore=skills/ --ignore=system/test_system_status.py --ignore=system/test_is_healthy.py --ignore=system/test_system_wait.py -k "not test_observer"
413+
--ignore=admin/ --ignore=skills/ --ignore=system/test_system_status.py --ignore=system/test_is_healthy.py --ignore=system/test_system_wait.py \
414+
--ignore=scenarios/ -k "not test_observer"
419415
fi
420416
continue-on-error: true
421417

@@ -433,7 +429,7 @@ jobs:
433429
uv run python -m pytest . -v --html=api-test-report.html --self-contained-html --ignore=filesystem/
434430
} else {
435431
Write-Host "Running basic tests only (no VLM/Embedding, Windows: skipping filesystem tests)"
436-
uv run python -m pytest . -v --html=api-test-report.html --self-contained-html --ignore=retrieval/ --ignore=resources/test_pack.py --ignore=resources/test_wait_processed.py --ignore=admin/ --ignore=skills/ --ignore=system/test_system_status.py --ignore=system/test_is_healthy.py --ignore=system/test_system_wait.py --ignore=filesystem/ -k "not test_observer"
432+
uv run python -m pytest . -v --html=api-test-report.html --self-contained-html --ignore=retrieval/ --ignore=resources/test_pack.py --ignore=resources/test_wait_processed.py --ignore=admin/ --ignore=skills/ --ignore=system/test_system_status.py --ignore=system/test_is_healthy.py --ignore=system/test_system_wait.py --ignore=filesystem/ --ignore=scenarios/ -k "not test_observer"
437433
}
438434
continue-on-error: true
439435

.github/workflows/build-docker-image.yml

Lines changed: 100 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ on:
88
required: true
99
type: string
1010
push:
11+
branches: [ main ]
1112
tags: [ "v*.*.*" ]
1213

1314
env:
@@ -52,41 +53,79 @@ jobs:
5253
username: ${{ github.actor }}
5354
password: ${{ secrets.GITHUB_TOKEN }}
5455

56+
- name: Log in to Docker Hub
57+
uses: docker/login-action@v4
58+
with:
59+
username: ${{ secrets.DOCKERHUB_USERNAME }}
60+
password: ${{ secrets.DOCKERHUB_TOKEN }}
61+
5562
- name: Extract metadata (tags, labels) for Docker
5663
id: meta
5764
uses: docker/metadata-action@v6
5865
with:
59-
images: ${{ env.REGISTRY }}/${{ steps.image-name.outputs.image }}
66+
images: |
67+
${{ env.REGISTRY }}/${{ steps.image-name.outputs.image }}
68+
docker.io/${{ secrets.DOCKERHUB_USERNAME }}/openviking
6069
tags: |
6170
type=raw,value=${{ github.event.inputs.version }},enable=${{ github.event_name == 'workflow_dispatch' }}
6271
type=ref,event=tag,enable=${{ github.ref_type == 'tag' }}
72+
type=raw,value=latest,enable=${{ github.ref_type == 'tag' }}
73+
type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }}
6374
6475
- name: Set up Docker Buildx
6576
uses: docker/setup-buildx-action@v4
6677

67-
- name: Build and push Docker image
68-
id: push
78+
- name: Build and push Docker image to GHCR
79+
id: push-ghcr
80+
uses: docker/build-push-action@v7
81+
with:
82+
context: .
83+
platforms: ${{ matrix.platform }}
84+
outputs: |
85+
type=image,name=${{ env.REGISTRY }}/${{ steps.image-name.outputs.image }},push-by-digest=true,name-canonical=true,push=true
86+
labels: ${{ steps.meta.outputs.labels }}
87+
build-args: |
88+
# fallback to 0.0.0 if no version is provided
89+
OPENVIKING_VERSION=${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.version) || (github.ref_type == 'tag' && github.ref_name) || '0.0.0' }}
90+
91+
- name: Build and push Docker image to Docker Hub
92+
id: push-dockerhub
6993
uses: docker/build-push-action@v7
7094
with:
7195
context: .
7296
platforms: ${{ matrix.platform }}
73-
outputs: type=image,name=${{ env.REGISTRY }}/${{ steps.image-name.outputs.image }},push-by-digest=true,name-canonical=true,push=true
97+
outputs: |
98+
type=image,name=docker.io/${{ secrets.DOCKERHUB_USERNAME }}/openviking,push-by-digest=true,name-canonical=true,push=true
7499
labels: ${{ steps.meta.outputs.labels }}
75100
build-args: |
76101
# fallback to 0.0.0 if no version is provided
77102
OPENVIKING_VERSION=${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.version) || (github.ref_type == 'tag' && github.ref_name) || '0.0.0' }}
78103
79-
- name: Export image digest
104+
- name: Export GHCR image digest
80105
run: |
81-
mkdir -p /tmp/digests
82-
digest="${{ steps.push.outputs.digest }}"
83-
touch "/tmp/digests/${digest#sha256:}"
106+
mkdir -p /tmp/digests-ghcr
107+
ghcr_digest="${{ steps.push-ghcr.outputs.digest }}"
108+
touch "/tmp/digests-ghcr/${ghcr_digest#sha256:}"
84109
85-
- name: Upload image digest
110+
- name: Upload GHCR image digest
86111
uses: actions/upload-artifact@v7
87112
with:
88-
name: docker-digests-${{ matrix.arch }}
89-
path: /tmp/digests/*
113+
name: docker-digests-ghcr-${{ matrix.arch }}
114+
path: /tmp/digests-ghcr/*
115+
if-no-files-found: error
116+
retention-days: 1
117+
118+
- name: Export Docker Hub image digest
119+
run: |
120+
mkdir -p /tmp/digests-dockerhub
121+
dockerhub_digest="${{ steps.push-dockerhub.outputs.digest }}"
122+
touch "/tmp/digests-dockerhub/${dockerhub_digest#sha256:}"
123+
124+
- name: Upload Docker Hub image digest
125+
uses: actions/upload-artifact@v7
126+
with:
127+
name: docker-digests-dockerhub-${{ matrix.arch }}
128+
path: /tmp/digests-dockerhub/*
90129
if-no-files-found: error
91130
retention-days: 1
92131

@@ -117,43 +156,81 @@ jobs:
117156
username: ${{ github.actor }}
118157
password: ${{ secrets.GITHUB_TOKEN }}
119158

159+
- name: Log in to Docker Hub
160+
uses: docker/login-action@v4
161+
with:
162+
username: ${{ secrets.DOCKERHUB_USERNAME }}
163+
password: ${{ secrets.DOCKERHUB_TOKEN }}
164+
120165
- name: Extract metadata (tags, labels) for Docker
121166
id: meta
122167
uses: docker/metadata-action@v6
123168
with:
124-
images: ${{ env.REGISTRY }}/${{ steps.image-name.outputs.image }}
169+
images: |
170+
${{ env.REGISTRY }}/${{ steps.image-name.outputs.image }}
171+
docker.io/${{ secrets.DOCKERHUB_USERNAME }}/openviking
125172
tags: |
126173
type=raw,value=${{ github.event.inputs.version }},enable=${{ github.event_name == 'workflow_dispatch' }}
127174
type=ref,event=tag,enable=${{ github.ref_type == 'tag' }}
175+
type=raw,value=latest,enable=${{ github.ref_type == 'tag' }}
176+
type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }}
128177
129178
- name: Set up Docker Buildx
130179
uses: docker/setup-buildx-action@v4
131180

132-
- name: Download image digests
181+
- name: Download GHCR image digests
133182
uses: actions/download-artifact@v8
134183
with:
135-
pattern: docker-digests-*
136-
path: /tmp/digests
184+
pattern: docker-digests-ghcr-*
185+
path: /tmp/digests-ghcr
186+
merge-multiple: true
187+
188+
- name: Download Docker Hub image digests
189+
uses: actions/download-artifact@v8
190+
with:
191+
pattern: docker-digests-dockerhub-*
192+
path: /tmp/digests-dockerhub
137193
merge-multiple: true
138194

139195
- name: Create multi-arch manifests
140196
env:
141197
SOURCE_TAGS: ${{ steps.meta.outputs.tags }}
142198
run: |
143-
image_refs=()
144-
for digest_file in /tmp/digests/*; do
199+
# Collect image references for both registries
200+
ghcr_image_refs=()
201+
dockerhub_image_refs=()
202+
for digest_file in /tmp/digests-ghcr/*; do
203+
[ -e "$digest_file" ] || continue
204+
digest="sha256:$(basename "$digest_file")"
205+
ghcr_image_refs+=("${{ env.REGISTRY }}/${{ steps.image-name.outputs.image }}@${digest}")
206+
done
207+
for digest_file in /tmp/digests-dockerhub/*; do
145208
[ -e "$digest_file" ] || continue
146-
image_refs+=("${{ env.REGISTRY }}/${{ steps.image-name.outputs.image }}@sha256:$(basename "$digest_file")")
209+
digest="sha256:$(basename "$digest_file")"
210+
dockerhub_image_refs+=("docker.io/${{ secrets.DOCKERHUB_USERNAME }}/openviking@${digest}")
147211
done
148212
149-
[ ${#image_refs[@]} -gt 0 ] || {
150-
echo "No image digests found" >&2
213+
[ ${#ghcr_image_refs[@]} -gt 0 ] || {
214+
echo "No GHCR image digests found" >&2
215+
exit 1
216+
}
217+
[ ${#dockerhub_image_refs[@]} -gt 0 ] || {
218+
echo "No Docker Hub image digests found" >&2
151219
exit 1
152220
}
153221
222+
# Create manifests for all tags
154223
while IFS= read -r tag; do
155224
[ -n "$tag" ] || continue
156-
docker buildx imagetools create \
157-
--tag "$tag" \
158-
"${image_refs[@]}"
225+
226+
# Determine which registry this tag belongs to
227+
if [[ "$tag" == ghcr.io/* ]]; then
228+
docker buildx imagetools create \
229+
--tag "$tag" \
230+
"${ghcr_image_refs[@]}"
231+
elif [[ "$tag" == docker.io/* ]]; then
232+
docker buildx imagetools create \
233+
--tag "$tag" \
234+
"${dockerhub_image_refs[@]}"
235+
fi
159236
done <<< "$SOURCE_TAGS"

.github/workflows/ci.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,5 @@ permissions:
2323
security-events: write
2424

2525
jobs:
26-
test-full:
27-
uses: ./.github/workflows/_test_full.yml
28-
2926
security-scan:
3027
uses: ./.github/workflows/_codeql.yml

0 commit comments

Comments
 (0)