fix(session): wire auto-commit threshold into add_messages - #2936
fix(session): wire auto-commit threshold into add_messages#2936lg320531124 wants to merge 301 commits into
Conversation
|
CI note: the The failure is identical across all currently-open PRs (#2874, #2936, #2937, #2938) and reproduces on #2874 which predates my other work:
This PR is pure-Python (touches only Evidence that maintainers are not blocking on this flake: #2934 was merged today (2026-07-02 01:07 UTC) with the same Local unit tests for this PR pass (see PR body). Happy to help root-cause the maturin/upstream flake separately if useful — just let me know. |
cb4773a to
71722c9
Compare
Co-authored-by: ZaynJarvis <31875147+ZaynJarvis@users.noreply.github.com>
Co-authored-by: Yuanqing Zhao <2604121+yuanqingz@users.noreply.github.com>
Add multimodal image vectorization and image query support across the server, SDKs, and CLI.
* fix(memory): avoid nesting rendered links * fix(memory): cover spaces in link targets Reviewer (@fujiajie666) noted that _RELATIVE_LINK_RE rejected whitespace inside link targets, so an existing link like [Frank Ocean](entities/frank ocean.md) was not detected as a link span, causing the next render to wrap the inner 'Frank' and produce a nested broken link. - Loosen _RELATIVE_LINK_RE to \[^)]+\ so the target may contain spaces (and \%20\ percent-encoded forms) when matching. - Percent-encode spaces in generated link targets in render_links so the emitted markdown is portable across renderers. Tests cover: skip inside existing literal-space link, encode spaces in new targets, skip when existing target is %20-encoded, strip_links on both literal-space and %20-encoded targets, full round-trip, and idempotency on re-render. --------- Co-authored-by: AITree69 <292109083+AITree69@users.noreply.github.com>
中文:对 HTTP/HTTPS URL 使用 urlparse(url).path 提取扩展名,确保 video.mp4?signature=... 命中 UnderstandingAPI fast path。新增带签名视频 URL 的 ParserRouter 回归测试。 English: Parse HTTP/HTTPS URL paths before checking extensions so signed video URLs hit the UnderstandingAPI fast path. Add a ParserRouter regression test for signed video URLs. Co-authored-by: chenpengfei <chenpengfei@bytedance.com>
Disable recursive submodule fetching and avoid exposing remote Git errors to resource API callers.
Co-authored-by: huangruiteng <huangruiteng@bytedance.com>
…olcengine#3104) Commit 4d34025 added the required `sender_name` parameter to `BaseChannel._handle_message()` and updated `feishu.py`, but `slack.py` and `email.py` were not updated in the same change. This caused a `TypeError` on every inbound message in both channels. Because Slack SDK swallows exceptions in asyncio listener callbacks, the error was silent — the bot received events, added emoji reactions, but never called the LLM or sent any reply. Fix: pass `sender_name=sender_id` in SlackChannel and `sender_name=sender` in EmailChannel. Co-authored-by: scott.kim <scott@ScottMacBookPro.local> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…gine#3114) * fix(vectordb): only write content field for VikingDB backends * fix: update doc
Regenerate uv.lock metadata to match pyproject.toml after two upstream deps changes that left the lock unreconciled: - b596e26 (volcengine#2965): bump litellm pin <1.89.3 -> <1.90.3 - 47da6ce (volcengine#3037): merge bot-* extras into a single [bot] extra Metadata-only diff (13 insertions / 66 deletions) — no resolved package versions or hashes change. Confirmed by a clean `uv sync` leaving uv.lock unmodified. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Updates the requirements on [litellm](https://github.com/BerriAI/litellm) to permit the latest version. - [Release notes](https://github.com/BerriAI/litellm/releases) - [Commits](BerriAI/litellm@v1.83.14.rc.1...v1.91.1) --- updated-dependencies: - dependency-name: litellm dependency-version: 1.91.1 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
) Manual-dispatch workflow that builds mcp-server-openviking-controlplane (MCP server + ov-cp CLI) from an explicit ref of an external source repo (default volcengine/mcp-server, subdirectory server/mcp_server_openviking_controlplane) and publishes it to TestPyPI/PyPI via the existing trusted-publishing environments. Requires a one-time pending-publisher registration on (Test)PyPI binding the project name to this repo + workflow file + environment.
* feat: add Cursor and TRAE memory integrations * fix: install Cursor plugin from shared command * refactor: share Cursor and TRAE integration runtime * fix: migrate legacy OpenViking MCP entry * docs: simplify Cursor and TRAE setup guides * fix: harden Cursor and TRAE memory integrations * refactor: standardize Cursor and TRAE integrations * refactor: clarify Cursor and TRAE hook entrypoints * fix: address Cursor and TRAE integration review
…engine#3092) * perf(cuvs): fast-path cached native filter routes * perf(cuvs): parallelize auto filter preflight * perf(cuvs): add search route telemetry * test(cuvs): use a valid telemetry vector dimension * perf(cuvs): reuse native filter preflight results * perf(cuvs): allow concurrent snapshot searches * perf(cuvs): coalesce optional background rebuilds * perf(cuvs): coordinate per-GPU build admission * perf(cuvs): add opt-in float16 search * build(cuvs): support vector benchmark harnesses * perf(cuvs): bound concurrent GPU searches * perf(cuvs): avoid partial background rebuilds * fix(cuvs): address rebuild and telemetry review feedback * fix(cuvs): defer rebuild until index initialization --------- Co-authored-by: Yuanqing Zhao <2604121+yuanqingz@users.noreply.github.com>
…olcengine#3119) * bot opt config\api check * 优化vikingbot的启动链路 * 美化颜色 * docs: add VikingBot gateway routing diagram * fix(bot): harden gateway auth and proxy routing
* session: prefer self for missing peer memory * fix * session: split message peer id scope * Revert "session: split message peer id scope" This reverts commit 853f1c6. * session: include all message peer ids in scope
* docs: fix stale commands, paths, and provider claims Sweep findings: D-03, D-04, D-05, D-06, D-07, D-08, D-09. Align setup and API examples with current configuration and CLI behavior. (cherry picked from commit 2b21ee5) * fix(review): correct crypto output flag Addresses blocking review finding on volcengine#3401. (cherry picked from commit 85bb502) * docs(ov): finish stale CLI path cleanup Complete the volcengine#3401 salvage by updating the API-writing templates and the remaining encryption guide examples to the Rust CLI surface. * fix(ov): make local content operations race-safe Salvage the safe-I/O portions of OpenViking#3414: reject unsupported local watch requests before upload, atomically create download targets, and write snapshot output before reporting JSON success. Add focused regression coverage. * fix(ov): validate timeout and node-limit inputs Salvage and complete OpenViking#3414 by validating every timeout and node-limit surface consistently while preserving config commands as a repair path for invalid persisted values. * fix(ov): allow explicit help before language setup Salvage OpenViking#3416 with a narrower contract: only clap-recognized -h/--help requests bypass first-run language selection. Bare command groups, legacy -help, and option values keep the existing gate. * docs(ov): align session and snapshot command examples Salvage OpenViking#3419 by correcting positional session and snapshot examples, documenting the canonical observer filesystem command, and keeping fs as a compatible alias. * fix(ov): honor configured output defaults safely Salvage and complete OpenViking#3424 with CLI-over-config precedence, runtime validation for normal commands, and a table fallback that leaves config repair commands usable. Also clarify the Python-client versus Rust-CLI upload-mode controls. * fix(ov): preserve zero node-limit semantics * ci: skip embedding-dependent resource test without secrets * fix(cli): validate compile timeout consistently --------- Co-authored-by: zhiheng.liu <zhiheng.liu@bytedance.com>
…ne#3685) * refactor(langchain): extract standalone integration package * fix(langchain): preserve optional legacy imports * fix(langchain): guard legacy submodule imports
* feat(ragfs): add structured lock tracing logs * feat(ragfs): add log async writer * fix(ragfs): add CRITICAL trans && add rust hook to receive rotate log file
…#3548) * fix(server): stop exporting raw query strings and buffering zip responses in observability Sweep findings: B-03, B-13. Prevent query secrets from reaching traces and keep ZIP responses streaming. (cherry picked from commit d8ac3dc) * fix(session): tolerate missing/corrupt archive in Phase-2 replay (NotFoundError / _ArchiveMessagesCorruptError) on a missing or corrupt archive messages.jsonl instead of returning []. That PR added skip-on- missing tolerance to the read path (_get_uncovered_archive_messages) and to resume_queued_commit, but not to the Phase-2 commit replay path (_prepare_phase2_archive_messages), which calls _read_archive_messages unguarded while rolling earlier failed archives into the current commit. Consequence: a terminally-failed earlier archive whose messages.jsonl is missing/corrupt (legacy "no messages" terminal data, or produced by volcengine#3417's own archive_read terminal path) makes every subsequent commit's Phase-2 extraction raise -> caught by _run_memory_extraction's except -> the current archive is terminal-failed too. Because the poisoned archive is only removed from replay once "covered" (which requires a later archive to complete), and no later archive can ever complete, the session's memory extraction is permanently poisoned. Raw messages are safe, but extraction is stuck. Fix: wrap the replay-loop _read_archive_messages call in the same tolerance _get_uncovered_archive_messages already uses -- skip + warn on not-found (_is_storage_not_found) and on _ArchiveMessagesCorruptError, re-raise real storage failures. The skipped archive stays in covered_failed so the current archive's .done marks it covered, clearing the poison permanently. Adds a regression test asserting the replay skips a failed archive with a missing messages.jsonl (and marks it covered) instead of raising, and that a real storage failure still propagates. Follow-up to volcengine#3417. (cherry picked from commit 5b8ec9e) * fix(client): align client surfaces without leaking memory metadata Reconstructs the client-parity work from upstream PR volcengine#3439 on current main and strips reserved memory metadata before line slicing in both embedded and HTTP reads. Based-on: 48b411d Co-authored-by: zhiheng.liu <zhiheng.liu@bytedance.com> * fix(index): propagate semantic vectorization failures safely Reconstructs upstream PR volcengine#3437 on current main, carries enqueue failures through SemanticDagExecutor, and drains the attempt's embedding tracker before retry-visible failure propagation. Based-on: 02387de Co-authored-by: zhiheng.liu <zhiheng.liu@bytedance.com> * fix(core): close privacy and embedding failure gaps * fix(memory): strip repeated metadata trailers * fix(core): close public memory visibility gaps * ci: skip embedding-dependent resource test without secrets --------- Co-authored-by: zhiheng.liu <zhiheng.liu@bytedance.com>
* feat: add audio and video understanding via VLM * docs: design media resource guards * fix: bound media staging concurrency * fix: cap unknown-size media staging * test: stage media in routing fake * test: exercise media staging callbacks * test: trim media understanding coverage * chore: 清理实现计划文档 * fix: 修复多凭证切换问题 --------- Co-authored-by: Qin Haojie <qinhaojie.exe@bytedance.com>
…olcengine#3706) Route the query() random-sampling branch through search_by_vector with a client-generated random vector (config.embedding.dimension) so every backend behaves consistently, instead of each backend's server-side search_by_random. This also makes Qdrant/OpenGauss truly random rather than a deterministic scroll/scan. Drop the raise_on_error path entirely per request: query(), the Collection wrapper, and HttpCollection.search_by_random no longer take raise_on_error, and delete() no longer requests it. As a result, HTTP filter-based deletion id lookups now return empty on non-200 instead of raising. Co-authored-by: TRAE CLI <noreply@bytedance.com>
volcengine#3704) * feat(config): add enable_watch_scheduler toggle for read-only replicas Add a top-level `enable_watch_scheduler` config flag (default true) and gate `WatchScheduler.start()` on it in service initialization. Read-only replicas that share a writer's data must not run the periodic watch/refresh background loop: it would execute writes against shared storage (vectordb / backups) and race the writer when persisting watch task state, which has no cross-process lock. The scheduler instance is still created and wired for on-demand read paths; only its background loop is skipped. Defaults to true, so existing single-instance deployments are unaffected. * fix * fix
GET /api/v1/fs/attrs read search tags with a bare `uri` equality filter
and no level constraint. Over a path-typed `uri` field this does not pin
an exact node, and it merged tags across all levels, so a directory whose
tags live on its L0/L1 summary records could read back tags from an
unrelated record instead of its own.
Mirror how ContentWriteCoordinator.set_tags writes tags: a directory
carries them on its L0/L1 records and a file on its L2 record. Query with
And([Eq("uri", uri), In("level", levels)]) so Eq compiles to an exact
path match (-d=0) and the level set matches the node kind.
Co-authored-by: TRAE CLI <noreply@bytedance.com>
…ngs (volcengine#3695) * feat(agent-evolution): record trajectory mapping in snapshot commits * feat(agent-evolution): apply global switch immediately * fix(snapshot): hide memory fields in visible history * fix(agent-evolution): preserve batch snapshot provenance * feat(agent-evolution): scope runtime settings by account * fix(agent-evolution): serialize experience snapshot finalization
The bytes_row STRING type uses a uint16 length prefix, capping a single
field at 65535 bytes. Add a new TEXT field type (enum value 9) that mirrors
STRING semantics (utf-8 str round-trip) but uses a uint32 length prefix,
lifting the per-field limit to ~4GB.
TEXT is added only at the physical bytes_row layer, across all serializers
that must stay byte-identical: the C++ engine (bytes_row.h/.cpp), the abi3
boundary (abi3_engine_backend.cpp, decoding to str not bytes), the pure
Python fallback (store/bytes_row.py), and the engine API (_python_api.py).
Existing types and the CandidateData.fields field are untouched, so old
on-disk data stays readable without reindex.
Fields opt into the new type via metadata={"field_type": FieldType.text}.
Add TestTextFieldType covering >65535-byte round-trips, py<->cpp cross
read/write, binary consistency, and metadata-based declaration.
Co-authored-by: TRAE CLI <noreply@bytedance.com>
* feat(integrations): add ZCode memory plugin Add examples/zcode-memory-plugin — a thin ZCode lifecycle adapter that reuses the shared memory-plugin-shared runtime for recall, capture, commit, and MCP proxy. No memory logic is duplicated. Key design decisions (see docs/design/zcode-memory-plugin-design.md): - Vendor shared runtime into scripts/shared/ via sync.mjs (self-contained plugin) - 4 hook events only (SessionStart, UserPromptSubmit, PreToolUse, Stop) — ZCode does not support PreCompact/SessionEnd/SubagentStart/SubagentStop - Output schema: ZCode-canonical keys only (no Claude-Code 'decision: approve') - Config-driven install: hooks + MCP merged into ~/.zcode/cli/config.json - install.sh wiring: detection, TUI, validation, install, uninstall Verified locally: - 22/22 node:test cases pass (turns parser + hook output schema) - sync.test.mjs passes - install → uninstall cycle: hooks/MCP correctly written and cleaned - URI guard denies viking:// paths with MCP redirect - Capture writes to OV session with zc- prefix Closes volcengine#3127 Related: volcengine#3442, volcengine#3544 * chore: remove non-essential files from PR, add .scratch to .gitignore - Remove .scratch/ working notes (local ticket files, not codebase artifacts) - Remove package.json and .gitignore from plugin dir (TRAE/Cursor don't have them) - Add .scratch/ to root .gitignore * fix(zcode): use verified ZCode field names + rollout fallback for capture - Update zcode-turns.mjs to probe responseText/responsePreview (verified from ZCode reverse-engineering in volcengine#3127 by @quinn-zenith) instead of the TRAE-inferred last_assistant_message - Add rollout file fallback: when stdin payload lacks user content (the known ZCode limitation), read ~/.zcode/cli/rollout/model-io-sess-*.jsonl to extract the last user+assistant pair from request.messages+response - Fix concurrent session isolation: normalize sessionId→session_id in zcode-hook.mjs before resolveNativeSessionId to prevent cwd-fallback collision when two ZCode windows run in the same directory - Add 2 new test cases for rollout fallback (14 turns tests total, 24 total) - All 24 tests pass * fix(zcode): address maintainer review blockers (config safety, MCP ownership, turnId) Addresses 3 blockers from @huangruiteng's review (CHANGES_REQUESTED): 1. Config safety: distinguish ENOENT from parse errors — malformed config.json now aborts instead of overwriting. Use backup+tmp+rename for atomic writes. 2. MCP ownership: only replace/delete mcp.servers.openviking entries tagged as openviking-memory. User-managed entries with the same name are preserved on install and untouched on uninstall. 3. TurnId-based dedup: rollout entries carry monotonic turnId — now used as the primary dedup key (capturedTurnIds set) instead of stableHash. extractUnseenRolloutTurns scans ALL unseen entries since lastTurnId, not just the last row — recovers missed turns after hook failure. Fail-closed when no turns are found. Also updates DESIGN.md to reflect verified field names (responseText/ responsePreview) and the turnId contract. 27/27 tests pass (was 24). Added 3 new rollout tests: incremental capture with lastTurnId, multi-entry scan, turnId propagation. * docs(zcode): update stale field name references in design spec Update test case descriptions to match verified field names (responseText/responsePreview instead of last_assistant_message) and add rollout fallback + turnId test coverage descriptions. * fix(zcode): dedup key includes role + first-capture returns all turns Fix two bugs found in code review pass 2: 1. Assistant turns silently dropped: user and assistant from the same rollout entry shared a turnId, so dedup via capturedTurnIds dropped the assistant. Fix: dedup key is now ${turnId}:${role}, not turnId alone. Regression test added. 2. First-capture data loss: when no lastKnownTurnId was set, only the last rollout entry was returned, losing prior turns. Fix: first-time capture now returns ALL entries. Also: add backup step to config atomic write (copyFileSync before tmp+rename), fix line width in zcode-turns.mjs, add 2 lifecycle tests (missed Stop recovery, user+assistant same turnId). 29/29 tests pass (was 27). * test(zcode): add concurrent session isolation tests Two new test cases addressing maintainer criterion 4 (concurrent sessions): 1. Two sessions read their own rollout files — verifies session A cannot see session B's content and vice versa (sentinel-based assertion) 2. Independent lastTurnId state per session — verifies incremental capture progresses independently when one session has prior state and another is fresh 31/31 tests pass (was 29). * fix(zcode): correct rollout file path pattern (model-io-<sessionId>) The rollout path used model-io-sess-${sessionId} but ZCode filenames are model-io-<sessionId> where sessionId already includes the sess_ prefix. This caused the rollout fallback to always miss the file and return empty, defeating capture entirely in production. Verified on live two-session ZCode setup: - Session A (sess_8c6ce483): 2 messages, 2 commits - Session B (sess_74759710): 2 messages, 2 commits - No cross-contamination between sessions 31/31 tests pass. Updated all test rollout filename patterns. * docs(zcode): fix stale rollout path in comments and DESIGN.md Comments referenced model-io-sess-<sessionId> but actual pattern is model-io-<sessionId> (fixed in code already, comments were stale). --------- Co-authored-by: woshiguanxiaoliang <woshiguanxiaoliang@noreply.gitcode.com>
…engine#3710) * feat(config): make external parse concurrency configurable * refactor(config): move external parse concurrency to queue workers --------- Co-authored-by: chenpengfei <chenpengfei@bytedance.com>
Use ZCode rollout logs as the authoritative incremental source, advance capture state only for the acknowledged prefix, and persist host turn identity with the OpenViking turn_id contract. Detach Stop writes, package ZCode in the TOS marketplace artifact, add end-to-end regressions, and move the integration docs under community plugins. Co-authored-by: TRAE CLI <noreply@bytedance.com>
volcengine#3730) Surface the vector store's search_tags on each matched context (returned under the "tags" key to match the tags filter param) and remove the result fields the retrieval pipeline never populates (category, match_reason, relations, overview). Co-authored-by: TRAE CLI <noreply@bytedance.com>
…e#3727) * feat(agent-evolution): track experience trajectory lineage * fix(agent-evolution): return matched trajectory records * fix(agent-evolution): stabilize lineage pagination
… mode="context" (volcengine#3534) * feat(retrieval): assemble auto-recall context server-side via /search mode="context" Auto-recall assembly lived in every harness plugin: each one searched per memory type, read hits back one by one, and stitched a context block with its own budget and degradation rules. The implementations drifted, and the shared weaknesses showed up in production injections — roughly half of the entries degraded to a bare URI plus a score, character budgets distorted up to 6x on CJK text, and adjacent turns re-injected the same memories. This moves assembly into the server as one round trip. /find stays an unchanged stateless primitive. /search gains mode="context" (mode="list" is the default and byte-identical to before), and /recall becomes a thin preset over the same kernel with its v1 field names folded onto the new contract. New assembly kernel under openviking/retrieve/context_assembler/: - Token budgeting with a CJK-aware estimate replaces the character budget. - detail="auto" fills breadth-first then deepens: every candidate gets a readable floor, then overview, then full for high-scoring entries. An oversized tier falls back to the previous one instead of being truncated, bounded by max_tokens / candidates * 2 per entry. - Overview extraction dispatches by source: memory files use their leading Summary section, code files reuse code_outline signatures, long documents use a heading tree plus first paragraph. - Directory hits start at overview and read their .overview.md sidecar, since directories carry no stored abstract; their full tier stays capped at overview. v1 injected the sidecar as if it were a whole file. - Quotas generalize beyond memory types to resources and skills, with purpose presets supplying ratios when quotas are absent. - dedup_turns keeps a per-session ledger at {session_uri}/.recall_log.json so every harness inherits cross-turn dedup; exclude_uris remains as the stateless fallback. - Rendering flattens to one <memory uri=... type=... score=... detail=...> element per entry. Every tier carries its URI, so the model can always drill down through the MCP read tool. - Query expansion and digest rewriting are opt-in and fail closed: both have timeout fuses, and a failed rewrite still returns the unrewritten block. Retrieval failures are counted into stats rather than silently yielding an empty block. Plugins now send one context request, falling back to /recall and then to raw find on older deployments, and cache that outcome so only the first turn pays for the probe. The tri-state recallRewrite knob chooses between local host-CLI compression and the server digest, and client-side settings move to a plugin section in ovcli.conf. * refactor(retrieval): give context tiers a per-category default The tier ladder assumed `abstract` is a cheap summary. For memory files it is not: the memory writer stores the whole stripped body in that scalar because it doubles as the embedding text, so `abstract` costs the same as `full` and the ladder runs `uri < overview < abstract = full`. Two of the model's properties fell out of that: exempting `abstract` from the per-entry cap let a single entry eat several times the budget, and `detail` — which only ever set a ceiling — collapsed to two distinguishable behaviours across its four values, since `auto` already allowed `full` for memory. Tiers now come from a per-category constant table that treats the storage shape as a given: `events` starts at overview (the one memory type whose `# Summary` extraction is a real compression) and may deepen to full on leftover budget; every other category is served at `abstract`, which for memory already is the complete file at zero read cost and for resources and skills is the generated 256-char summary. The table carries the note to move `events` back to `abstract` once the writer stores a separate summary scalar. Falling out of that: prefetch now reads only the candidates whose planned tier needs a body rather than every candidate, `detail` becomes a real pin (start and ceiling) and additionally accepts a per-category map, and `full_score_threshold` is gone — leftover budget is spent in score order instead of behind an absolute threshold the observed score band cannot support. `auto` is still accepted on the wire as a synonym for "unset". Assembly fixes found alongside: - Removing the abstract cap exemption would turn an oversized abstract into a bare URI, so it now falls back to overview first — for memory that is a cheaper substitute, not a step up. - Rewrite timeouts were reported as failures on Python 3.10, where `asyncio.TimeoutError` is a separate class from the builtin. - `stats.rewrite_usage` read `token_tracker` off `VLMConfig`, which has no such attribute; usage was structurally always null. It now reads the model instance's tracker and reports only when the call count moved by exactly one, since that tracker is shared. - A single malformed ledger record made every deduped recall in that session fail, and the file was never rewritten, so it could not heal. Records are now coerced on read and dropped on the next write, along with records left ahead of the clock by an archive rotation. - Entries served as a bare URI no longer enter the dedup cooldown: they lost to budget pressure, not to the reader having already seen them. - The render envelope only neutralised a literal `</memory>`, so a body could forge a sibling entry with its own uri, type and score. - Flat-mode gathering re-derived the category from the URI, reading `viking://resources/backup/memories/events/log.md` as an event. - Cooled and excluded URIs are compensated with extra rows, so a fully cooled bucket falls through to the next-best hits instead of coming back empty. - `/recall` quotas overlay the v1 bucket defaults again; `{"events": 5}` had started dropping the other three buckets. - The MCP `recall` signature sent its own defaults as if the caller had, which resolved a different profile than `POST /recall`; an unknown `detail` value raised `KeyError` through the whole call instead of degrading. * feat(codex): inject profile context on session start Reuse the shared profile builder for startup, clear, and resume hooks while preserving archive injection and orphan-session status output. Co-authored-by: TRAE CLI <noreply@bytedance.com> * fix(retrieval): raise rewrite timeout default to 30s * docs(agents): document low-latency recall settings * fix(codex): prefer luna as recall compressor fallback * refactor(plugins): unify recall compression setting * feat(plugins): enable recall compression by default * docs(agents): use absolute links in image docs * fix(retrieval): address context assembly review feedback Co-authored-by: TRAE CLI <noreply@bytedance.com> * test: trim redundant context assembly coverage * fix(retrieval): address second-round context assembly review - Drop the backticked `/search` from the deprecated-recall row in both API overviews. The reference checker scans the whole row after the method cell for backticked paths, so it read the description as a route named `POST /search` and Build Docs failed on an unknown, undocumented route. - Accept ovcli.conf's full field set in both Python readers. The file's schema belongs to the Rust CLI, which writes `root_api_key`, `output`, `echo_command`, `show_progress` and `verbose` and ignores unknown keys; the two Python readers had drifted into stricter subsets, so the shipped example already failed to load in both. Adding the new `plugin` section to a working ovcli.conf would have broken `ov doctor` and every SDK client the same way. - Return 400 from `mode="context"` for a request `mode="list"` also rejects. Retrieval validates query and image_url before searching, and the gather fuse swallowed that rejection along with genuine scope failures, so a body of `{"mode":"context"}` came back 200 with an empty block instead of the documented parameter error. Runtime failures still degrade into `stats.retrieval_errors`. - Let a context request that asks for a server-side digest outlast the server's rewrite fuse. The plugin's ordinary 15s request timeout is shorter than the 30s fuse, so a rewrite that finished inside its own budget was aborted client-side, discarding the whole response — including the uncompressed block the server returns when a rewrite fails — and falling back to `/recall`. The deadline is only extended when the body actually requests a rewrite, and `OPENVIKING_RECALL_CONTEXT_TIMEOUT_MS` / `plugin.recallContextTimeoutMs` pins it. * chore(plugins): sync shared modules into the zcode snapshot * fix(retrieval): align context quotas and plugin defaults Restore cross-domain coding recall, reuse authoritative actor resource scopes, and make bucket quotas the sole width control in purpose mode. Keep plugin defaults server-owned while preserving explicit legacy limit settings through quota conversion. Co-authored-by: TRAE CLI <noreply@bytedance.com> * fix(retrieval): preserve recall compatibility Restore the deprecated recall threshold default, distinguish successful empty rewrites from compressor failures, and document legacy quota floors across coding-agent plugins. Co-authored-by: TRAE CLI <noreply@bytedance.com> --------- Co-authored-by: TRAE CLI <noreply@bytedance.com> Co-authored-by: qin-ctx <qinhaojie.exe@bytedance.com>
…hots (volcengine#3742) * feat(agent-evolution): aggregate trajectory outcomes by experience * fix(agent-evolution): snapshot only visible experience changes * docs(api): document agent evolution queries
…engine#3738) * fix(compile): resolve pickle error and merge skill_name changes * fix
…ngleton 、cluster 、 sentinel (volcengine#3741)
… recalls (volcengine#3746) * fix(retrieval): honor tier ceilings and stop cooling unserved recalls Follow-up to volcengine#3534, from its post-merge review round. - The abstract-to-overview substitute now applies only to categories whose stored abstract is the whole file body. A resource or skill whose abstract is missing (`processing_mode=vectors_only`) or over the per-entry cap read its body and returned an overview instead, which for a short file is the body almost verbatim — crossing the opt-in deepening boundary those categories are documented to have, and doing it even under an explicit `detail="abstract"`. They now degrade to a bare URI and their body is never read. - A digest reporting `no_relevant` blanks `rendered`, so the client injects nothing, yet those URIs still entered the dedup ledger and were cooled for `dedup_turns` turns. That contradicted the ledger's own bare-URI grace rule and held memories back from the later turn they were relevant to. - Flat retrieval reaches built-in memory types outside the four named ones (`cases`, `patterns`, `tools`, `trajectories`, skill-usage memories) and reported them as an undeclared `memories` category that no tier or penalty table covered, so other-peer hits skipped the score penalty and callers could not pin their tier. The catch-all is now a declared category with both; it stays out of `quotas`, whose buckets it would overlap. Skill-usage memories also stop being misread as the `skills` category. - ZCode, OpenCode and pi own an OV session id but did not forward it, so their recalls silently ran without query expansion or cross-turn dedup. - The context-request deadline covered only the server's 30s rewrite fuse, but the pipeline is serial: expansion, retrieval and budgeting all precede it. 45s covers both fuses and the work between them. - `plugin` config scope and the `/recall` successor example now match what the code actually does. * fix(retrieval): make the context deadline and expansion opt-out reachable Forwarding a session id turns on server-side query expansion, an LLM call with its own 5s fuse, but neither the deadline that was supposed to cover it nor the switch that turns it off reached the two harnesses this PR newly enabled it for. - `contextRequestTimeoutMs()` now derives the deadline from the request body rather than from `cfg` plus a rewrite flag. The body is what states which server stages will run: a session takes the expansion fuse, `rewrite` takes the digest fuse, and a bare retrieval takes neither and keeps the caller's own budget. Reading `cfg` alone could not tell those apart. - OpenCode pinned `timeoutMs: 5000` after spreading the helper's options and pi ignored them entirely, so the helper's deadline was dead code in both. Their own budgets are now defaults rather than ceilings. OpenCode's 5s in particular was shorter than the expansion fuse it had just enabled, so a legal request would have been aborted client-side and dropped back to the path with neither dedup nor expansion. - OpenCode and pi read `OPENVIKING_RECALL_QUERY_EXPANSION` (and `recallQueryExpansion` in their own config files) and set the `configured` flag the shared body builder requires, so the documented opt-out exists where the cost was introduced. - The integration overview no longer implies every harness reads the same environment knobs, and describes the deadline as per-stage rather than rewrite-only.
Resolve merge with main's add_messages/add_messages_async split: _maybe_auto_commit() now fires after both sync and async appends. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Problem
_auto_commit_threshold(default 8000) and thepending_tokenssignal were both maintained by_append_messagesbut never connected — the threshold param was dead code (assigned in__init__, never read anywhere).Only the offline ingest poller (
maybe_commit_on_thresholdinreplay.py, called frompoller.py:120) committed on threshold. In-process sessions — the HTTP/SDKadd_messagespath used by the Claude Code plugin and HTTP clients — never auto-committed.Result: real-time sessions accumulated messages without extraction. On a live deployment this shows up as a very low session→memory conversion rate (a 1210-session / 94-memory ratio was observed locally — ~7.8%, and far worse on sessions that never hit the poller path).
The CC plugin's
auto-capture.mjsdocstring even states the assumption:…but the Python side never honored it for the in-process path.
Fix
Add
_maybe_auto_commit()called at the end ofSession.add_messages:pending_tokens >= _auto_commit_threshold, firecommit_async(keep_recent_count=...)as a background task.add_messagesstays non-blocking; archive (Phase 1) and extraction (Phase 2) both run in the background.commit_async's path-lock + empty-messages early-return make a concurrent plugin-initiated commit a safe no-op.threshold <= 0disables (escape hatch).Why this is the root-cause fix
The signal (
pending_tokens, updated in_append_messages:895) and the trigger (_auto_commit_threshold) both already existed — only the wire between them was missing. This is the smallest possible fix at the shared function all callers route through (add_messages), rather than guarding each caller.Complementary to #2874 (rule-based tool-input compaction reduces storage per session); this PR makes extraction actually trigger on real-time sessions.
Tests
tests/unit/session/test_session_autocommit.py— 5 unit tests viaSession.__new__(no VikingFS/vectordb dependency):pending_tokens >= thresholdthreshold <= 0keep_recent_counttocommit_asyncpending_tokens == thresholdfires (>=)All 5 pass locally.
Checklist