* fix(openclaw): restore peer_role routing
The plugin refactor stopped applying peer_role to message attribution and data-plane actor headers, causing assistant mode to tag user messages and route every request as the agent. Restore role-aware routing across context and tool flows.
* fix(openclaw): close peer routing isolation gaps
* fix(openclaw): separate message peers from actor scope
Treat failed session archives as terminal skipped state so later commits can continue, and replace OpenClaw's fixed auto-commit token threshold with a context-window ratio while tolerating the deprecated config key.
Co-authored-by: LinQiang391 <linqiang391@users.noreply.github.com>
Drop dead exports/helpers with no callers (sysEnv, waitForHealth, estimateTokens, etc.) and remove redundant conditions and stale comments.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(plugin): canonicalize tool message format for OpenClaw Responses API
The OpenClaw Responses API replay path only recognizes `toolCall` blocks
(with `arguments` field), but the OpenViking context engine plugin was
emitting `toolUse` blocks (with `input` field) from its assembled context.
This mismatch caused `toolResult` orphan errors on subsequent turns after
tool use.
Changes:
- convertToAgentMessages: emit toolCall+arguments instead of
toolUse+input, matching the OpenClaw canonical format
- Add canonicalizeAgentMessages() to normalize legacy/variant block
formats (toolUse, functionCall, tool_call) into toolCall before
sanitizeToolUseResultPairing
- Add canonicalizeAssistantBlock() for per-block normalization with
id/name/arguments field mapping
- messageDigest: update type guard from toolUse to toolCall
This preserves backward compatibility on input (old toolUse blocks are
still accepted and normalized) while ensuring output always matches the
current OpenClaw Responses API contract.
* fix(plugin): address review feedback on PR #1632
- Remove 'unknown' fallback for toolResult.toolName in canonicalizeAgentMessages();
preserve undefined to let downstream normalizeToolResultName() backfill from paired toolCall
- Remove 'unknown' fallback for tool_name in convertToAgentMessages() structured path;
only set toolName on toolResult when the value exists
- Only include toolName on toolResult when present (not always)
- Update test expectations: toolUse → toolCall, input → arguments
- Update README/README_CN: describe canonical output format with backward-compat note
---------
Co-authored-by: Moss <moss@openclaw.ai>
When a stored message has only tool-type parts and no text parts, the
else-branch of convertToAgentMessages was pushing { role, content: "" }.
Strict providers (ZAI/GLM) reject requests containing empty-content
messages with 400. Fix: skip the push when texts is empty; preserve any
collected toolResults. Adds a regression test covering the issue-1485
scenario.
Fixes#1485
Co-authored-by: yeyitech <yeyitech@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Codex <codex@local.invalid>
Propagate toolCallId through the pipeline and reconstruct
toolUse+toolResult pairs from user-role tool parts stored in OV.
Add mergeConsecutiveAssistants to handle adjacent assistant messages.
Made-with: Cursor
Extract flat message assembly into 4-layer partition architecture as foundation for progressive compression (L1-L5). Add allocateContextBudget with Archive 15%/8K cap, Session as remainder, Reserved 15%/20K floor. Add buildArchiveMemory with over-budget trim protection. Switch estimatedTokens from backend value to client-side roughEstimate. Enhance diag with partition-level metrics.
Made-with: Cursor
* fix(ragfs): localfs write should respect WriteFlag to truncate file
The localfs write implementation was ignoring the WriteFlag parameter and
not truncating the file when WriteFlag::Create or WriteFlag::Truncate was
specified. This caused files to be appended instead of overwritten when
writing empty content.
Root cause: The _flags parameter was declared but never used. When opening
an existing file, .truncate(true) was not called.
Fix: Use OpenOptions::new().truncate(should_truncate) based on the flags.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(session): clear messages.jsonl after commit and improve memory extraction
- Add workaround to delete messages.jsonl before writing to work around
RAGFS localfs not truncating files (now fixed in ragfs)
- Add _get_latest_archive_last_msg_time to filter messages for memory
extraction by timestamp
- Fix memory extraction to only process new messages after last archive
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* update
* fix(openclaw): add HEARTBEAT filtering in sanitizeUserTextForCapture
过滤 HEARTBEAT 健康检查消息,避免 HEARTBEAT.md 和 HEARTBEAT_OK
进入 session 存档。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* revert: restore logger.warn instead of warnOrInfo
Reverting to use logger.warn directly. The warnOrInfo wrapper was
unnecessary as logger always has warn method.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(session): remove RAGFS truncate workaround
The ragfs localfs write now respects WriteFlag to truncate files,
so the workaround to delete messages.jsonl before writing is no
longer needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(openclaw): unify addSessionMessage with parts API
- Remove old addSessionMessage (string content)
- Keep addSessionMessage but accept parts array
- Update index.ts and context-engine.ts to use new format
- Update tests to check parts structure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(openclaw): use optional chaining for logger.warn
TypeScript strict mode requires handling possibly undefined warn method.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(openclaw): log trace_id from commit results
Add trace_id to CommitSessionResult type and log it for all
commitSession calls (afterTurn, commitOVSession, compact).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(openclaw): add tool_input to tool parts
- Add toolInput field to ExtractedMessage type
- Extract tool_input from msg.toolInput in extractNewTurnMessages
- Pass tool_input when constructing tool parts for addSessionMessage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(openclaw): lookup toolInput from preceding toolUse messages
When extracting toolResult messages, look up the corresponding toolInput
from the preceding assistant messages' toolUse blocks using toolCallId/
toolUseId as the key.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(openclaw): add more field name variations for toolInput/toolCallId
Support additional field names: arguments, toolInput, tool_call_id
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(openclaw): lookup toolInput from preceding toolCall messages
- Scan all messages to find toolCall/toolUse/tool_call blocks
- Extract tool input from arguments/input/toolInput fields
- Match toolResult with toolCall using toolCallId/toolUseId
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Update docs, tests, and example integrations to reflect accepted + task_id
session commits with task polling for completed results.
Also fix the local PR-Agent model provider prefix in .pr_agent.toml.
Return the latest archive through pre_archive_abstracts and drop the
separate latest_archive_id field so session context consumers only need
one archive index path.
* fix(openclaw-plugin): fix compact result mapping
* fix(openclaw-plugin): align compact result fields
* fix(openclaw-plugin): mark unknown tokensBefore as -1
* feat(session): make commit two-phase with async memory extraction
Session commit now returns immediately after archiving messages (Phase 1).
Summary generation and memory extraction (Phase 2) run in the background
via asyncio.create_task(), returning a task_id for polling progress.
- Add get_task() API across all client layers for querying background task status
- get_session() auto-creates session if it does not exist
- Remove wait parameter and telemetry from commit endpoint
- Add .done completion marker to archive directories
- Update docs (EN/ZH) and tests for new two-phase flow
* feat(session): add .meta.json persistence and auto_create control for get_session
SessionService.get() now defaults to auto_create=False, raising NotFoundError
for missing sessions. A new SessionMeta dataclass tracks created_at, updated_at,
message_count, commit_count, memories_extracted (by category), last_commit_at,
and cumulative llm_token_usage. Meta is persisted to .meta.json and updated on
add_message, commit Phase 1 (message clear), and commit Phase 2 completion
(token usage, memory counts via bind_telemetry). All client layers
(local/async/sync/HTTP) and API docs updated accordingly.
* fix: remove session vectorize
* support commit for openclaw-plugin
Made-with: Cursor
* feat(openclaw-plugin): archive-aware context assembler with lazy-read optimization
- Implement get_context_for_assemble with token-budget-aware archive trimming
- Write .meta.json during commit for pre-stored token counts
- Lazy-read archives from newest to oldest, skip old archives when budget exhausted
- Backward-compatible: fall back to reading overview for old archives without .meta.json
- Pass agentId through getContextForAssemble in client.ts
- Use sessionKey from OpenClaw in assemble to match afterTurn session resolution
- Emit non-error toolResult for pending/running tools instead of synthetic error
- Log warning and mark stats on ls(history) failure instead of silent swallow
* refactor(openclaw-plugin): unify OV session identity to sessionId
Made-with: Cursor
* feat(openclaw-plugin): add memory chain integration test script
Made-with: Cursor
* add test and desc of openclaw-plugin
* change commit to async
---------
Co-authored-by: qin-ctx <qinhaojie.exe@bytedance.com>
Co-authored-by: wlff123 <wulf234@163.com>
Co-authored-by: Eurekaxun <eurekaxun@163.com>
Co-authored-by: lin-qiang123 <1667704220@qq.com>
* feat(session): make commit two-phase with async memory extraction
Session commit now returns immediately after archiving messages (Phase 1).
Summary generation and memory extraction (Phase 2) run in the background
via asyncio.create_task(), returning a task_id for polling progress.
- Add get_task() API across all client layers for querying background task status
- get_session() auto-creates session if it does not exist
- Remove wait parameter and telemetry from commit endpoint
- Add .done completion marker to archive directories
- Update docs (EN/ZH) and tests for new two-phase flow
* feat(session): add .meta.json persistence and auto_create control for get_session
SessionService.get() now defaults to auto_create=False, raising NotFoundError
for missing sessions. A new SessionMeta dataclass tracks created_at, updated_at,
message_count, commit_count, memories_extracted (by category), last_commit_at,
and cumulative llm_token_usage. Meta is persisted to .meta.json and updated on
add_message, commit Phase 1 (message clear), and commit Phase 2 completion
(token usage, memory counts via bind_telemetry). All client layers
(local/async/sync/HTTP) and API docs updated accordingly.
* fix: remove session vectorize
* support commit for openclaw-plugin (#902)
Made-with: Cursor
* fix: reuse latest archive overview in session context
Thread the latest completed archive overview into archive summary generation and memory extraction, and simplify search context assembly to current messages plus the latest archive overview.
Co-Authored-By: Claude Opus 4.6
* refactor: session overview
---------
Co-authored-by: AutoCoder <wulf234@163.com>
* feat(openclaw-context-plugin): migrate OpenViking memory plugin to context engine
1. Rename the OpenClaw plugin from memory-openviking to openclaw-context-plugin and switch its kind from memory to context-engine.
2. Keep auto-recall and ingest-reply-assist on before_prompt_build to preserve the existing prompt injection behavior.
3. Move the canonical auto-capture flow from the old agent_end-style lifecycle to ContextEngine afterTurn.
4. Delegate compact handling to the legacy compact engine when it is available, so existing compaction behavior can still be reused.
5. Preserve the OpenViking tools and local process management while updating setup helpers, installers, docs, and OpenClaw config paths to plugins.slots.contextEngine.
Co-authored-by: GPT-5.4 <noreply@openai.com>
* refactor(openclaw-context-plugin): rename plugin id to context-openviking
- rename the runtime plugin id, package name, install destination, and OpenClaw config keys from openclaw-context-plugin to context-openviking
- keep the source directory at examples/openclaw-context-plugin unchanged while updating docs, installers, and setup helpers to use the new runtime name
- remove unused sys imports from the demo scripts so ruff check stays green
---------
Co-authored-by: GPT-5.4 <noreply@openai.com>