Commit Graph

382 Commits

Author SHA1 Message Date
Vincent Koc
e53c068d78 fix: repair skills and memory watcher refresh paths 2026-04-26 11:21:21 -07:00
Peter Steinberger
9a529ca78b chore: update dependencies 2026-04-26 10:54:58 +01:00
Peter Steinberger
27aedcfd56 style: format repository 2026-04-26 05:47:12 +01:00
Peter Steinberger
650dc59b6f fix: skip checkpoint transcripts in memory dreaming 2026-04-26 01:30:50 +01:00
pash-openai
edb618c6c4 Manage the Codex app-server binary in OpenClaw (#71808)
* Manage Codex app-server binary

* Use plugin deps for Codex app-server binary

* Stabilize media model registry test

* Exclude checkpoint transcripts from memory ingestion
2026-04-25 16:51:14 -07:00
Peter Steinberger
956cb1c7db fix: keep local embedding batches from flooding providers 2026-04-26 00:11:35 +01:00
Peter Steinberger
f1b1c3dc99 chore: update workspace dependencies 2026-04-25 22:48:44 +01:00
Ted Li
8e83e52213 fix(memory-core): skip stale dreaming recall sources (#71695)
* fix(memory-core): skip stale dreaming recall sources

* fix(memory-core): parallelize live recall filtering
2026-04-25 17:10:38 -04:00
Mara 🌿
4038f734f7 fix(memory-core): add runtime cron service fallback for dreaming reconciliation (#71694)
* fix(memory-core): add runtime cron service fallback for dreaming reconciliation

When the cron service is unavailable during gateway_start (e.g., due to
a startup timing race or deferred initialization), the startupCronSource
is captured as null and never refreshed. All subsequent runtime
reconciliation attempts fail with 'cron service unavailable', even when
the cron service is fully operational.

This adds a fallback path in the runtime reconciliation that attempts to
obtain the cron service from the plugin API runtime when the startup
capture was null. This handles the case where the cron service becomes
available after the initial startup event.

Fixes #67362

* fix(memory-core): hold gateway context for runtime cron resolution

The previous attempt tried to access api.runtime.cron which doesn't exist
on the PluginRuntime type. The cron service is only accessible through
PluginHookGatewayContext.getCron().

This fix stores the gateway context from the gateway_start event and uses
it to retry cron resolution at runtime when the initial capture was null.
This handles the race condition where the cron service isn't available
during gateway_start (250ms deferred init) but is ready later.

Also refreshes the startupCron capture when the runtime retry succeeds,
so subsequent reconciliation calls resolve immediately.

Addresses review feedback on #71694
2026-04-25 17:07:45 -04:00
Peter Steinberger
7fcefd56b7 chore: bump version to 2026.4.25 2026-04-25 10:31:52 +01:00
Vincent Koc
9895ecead3 fix(memory): keep llama runtime optional (#71425)
* fix(memory): keep llama runtime optional

* fix(memory): harden optional llama runtime guard
2026-04-25 00:09:12 -07:00
Alex Fries
66e66f19c6 feat(memory-core): expose hybrid search component scores
Expose raw `vectorScore` and `textScore` alongside the combined hybrid memory search `score`.

- Preserve vector/text component scores from `mergeHybridResults` output.
- Add optional component-score fields to both memory host SDK type surfaces.
- Extend hybrid merge tests for vector-only, text-only, and overlapping result cases.
- Document that component scores remain raw retrieval diagnostics while temporal decay/MMR only adjust or reorder the combined ranking `score`.

Closes #68166.

Maintainer verification:
- `pnpm test extensions/memory-core/src/memory/hybrid.test.ts`
- `pnpm check:changed`
- Fresh GitHub checks passed.

Co-authored-by: Alex Fries <alex@engramlabs.io>
2026-04-25 01:46:03 -05:00
Michiel van den Donker
2c716f5677 fix: enforce memory search session visibility (#70761) (thanks @nefainl)
* [EV-001] memory-core: filter memory_search session hits by visibility

- Move session visibility + listSpawnedSessionKeys to plugin-sdk; sync test
  hook with sessions-resolution __testing.setDepsForTest
- Extract loadCombinedSessionStoreForGateway to config/sessions; re-export
  from gateway session-utils
- Add session-transcript-hit stem resolver for builtin + QMD paths
- Post-filter memory_search results before citations/recall; fail closed when
  requester session key missing; optional corpus=sessions
- Tests: stem extraction, visibility filter smoke, existing suites green

* chore: sync plugin-sdk exports for session-transcript-hit and session-visibility

Run pnpm plugin-sdk:sync-exports so package.json exports match
scripts/lib/plugin-sdk-entrypoints.json. Fixes contract tests and
lint:plugins:plugin-sdk-subpaths-exported for memory-core imports.

* fix(EV-001): cross-agent session memory hits + hoist combined store load

- resolveTranscriptStemToSessionKeys: stop filtering by requester agentId so
  keys from other agents reach createSessionVisibilityGuard (a2a + visibility=all).
- Re-export loadCombinedSessionStoreForGateway from session-transcript-hit;
  filterMemorySearchHitsBySessionVisibility loads the combined store once per pass.
- Drop unused agentId from filter params; extend tests (Greptile/Codex review).

* fix(memory_search): honor corpus=sessions before maxResults cap

Pass sources into MemoryIndexManager.search so FTS/vector queries add
source IN (...) before ranking and top-N slice (Codex: non-session hits
could fill the window).

QMD path: oversample fetch limit for single-source recall, filter by
source, then diversify/clamp to the requested maxResults.

Wire corpus=sessions from tools; extend MemorySearchManager opts and
wrappers.

* fix(memory_search): apply corpus=memory source filter like sessions

Pass sources: ["memory"] into manager.search so maxResults applies only
within the memory index; post-filter for defense in depth. Document
corpus=memory in the tool description.

* fix: scope qmd session memory search

* fix: enforce memory search session visibility (#70761) (thanks @nefainl)

---------

Co-authored-by: NefAI <info@nefai.nl>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-25 09:30:21 +05:30
Peter Steinberger
0764f86e18 test(memory): keep embedding provider selection isolated 2026-04-25 04:17:27 +01:00
Peter Steinberger
f70e439699 fix(amazon-bedrock): skip auto memory embeddings without credentials (#71245)
Co-authored-by: bitloi <raphaelaloi.eth@gmail.com>
2026-04-25 02:47:52 +01:00
Peter Steinberger
27c61ed0d4 chore(deps): update workspace dependencies 2026-04-24 16:55:08 +01:00
Patrick Erichsen
aca92b2906 memory/dreaming: decouple managed cron from heartbeat (#70737)
* Revert "fix(memory/dreaming): surface blocked status when heartbeat is disabled for main (#69875)"

This reverts commit 529577e045.

Making way for the dreaming-vs-heartbeat decoupling from Josh's
josh/dreaming-isolated-cron-fix branch, which moves the managed dreaming
cron to isolated agent turns (sessionTarget: "isolated") so dreaming no
longer requires heartbeat to fire. Once the cron no longer rides the
heartbeat path, the blocked-reason observability has nothing left to
report — removing it cleanly here before the cherry-picks land.

* openclaw-3ba.1: move managed dreaming cron to isolated agent turns

* openclaw-46d: claim cron runs before embedded attempts

* openclaw-575: disable managed dreaming cron delivery

* openclaw-575: accept wrapped dreaming cron tokens

* openclaw-ccd: filter cron and wrapper transcript noise from dreaming corpus

* openclaw-cd9: filter archived, cron, and heartbeat transcript noise from dreaming corpus

* openclaw-cd9: suppress role-label reflection tags in rem dreaming

* openclaw-b49: stop narrative timeouts from blocking dreaming cron

* openclaw-b49: keep managed dreaming cron out of diary subagents

* openclaw-ff9: restore cron dream diary generation without serial waits

* openclaw-ff9: run dreaming narratives with lightweight isolated subagent lanes

* openclaw-ff9: detach cron dream diary generation from run completion

* openclaw-ff9: defer cron diary task startup until after cron completion

* doctor/cron: migrate stale managed dreaming jobs to isolated agent turns

After the dreaming cron moved off the heartbeat path to sessionTarget:
"isolated" + payload.kind: "agentTurn" (see the preceding memory-core
changes), users with existing ~/.openclaw/cron/jobs.json entries in the
old sessionTarget: "main" + payload.kind: "systemEvent" shape still
carry stale jobs until the gateway restart reconcile rewrites them.

Add a dreaming-specific cron migration to the existing
maybeRepairLegacyCronStore doctor path so "openclaw doctor" (and
"openclaw doctor --fix") rewrites those jobs without needing a gateway
restart. Match lives in a new doctor-cron-dreaming-payload-migration
helper alongside the existing legacy-delivery and store-migration files.

The matching uses the memory-core managed-job name and description tag
plus the short-term-promotion payload token. Constants are mirrored
from extensions/memory-core/src/dreaming.ts and commented so a future
rename in memory-core is a visible drift point here too.

* memory/dreaming: tighten cron-token match to known wrapper, not substring

The previous match relaxed the line check from 'trimmed line equals token'
to 'line contains token anywhere as a substring' to accept the
`[cron:<id>] <token>` wrapper that isolated-cron turns add. Substring
matching also let any user message embedding the token mid-sentence
trigger the dream-promotion hook, and was flagged by both Greptile and
Aisle on PR #70737.

Replace it with strip-the-known-prefix-then-exact-match: keep the
`[cron:<id>]` wrapper case working, reject every other variant. Add
focused unit coverage that the bare token, the wrapped token, and bare
multiline cases match while embedded / code-fenced / arbitrarily-wrapped
variants do not.

* memory/dreaming: drop assistant followup only on assistant-side signals

Per PR #70737 review (aisle-research-bot, Medium): the previous logic
suppressed the next assistant message whenever the prior user message
matched a 'generated prompt' pattern (`[cron:...]`,
`System (untrusted): ...`, heartbeat prompts, exec-completion events).
Real users can type those same patterns, which let a user exfiltrate
real assistant replies from the dreaming corpus by prefixing their own
prompt — the assistant's reply would be silently dropped.

Remove the cross-message coupling. Assistant-side machinery (silent
replies, system wrappers) is already dropped by sanitizeSessionText,
which is the right layer for that filter. Add an explicit assistant-side
HEARTBEAT_TOKEN check to keep the legitimate `HEARTBEAT_OK` ack drop
working without depending on the prior user message. Add a regression
test exercising the spoofing scenario.

* doctor/cron: assert mirrored dreaming constants stay in sync

Per PR #70737 review (greptile-apps): the doctor migration mirrors three
constants (MANAGED_DREAMING_CRON_NAME, MANAGED_DREAMING_CRON_TAG,
DREAMING_SYSTEM_EVENT_TEXT) from extensions/memory-core/src/dreaming.ts.
A future rename in either file would silently break the migration.

Add a vitest unit that reads both files and asserts the literals match.
Manually verified the assertion fires with a clear error when one side
diverges. Adds no runtime cost; sits in the regular test pipeline.

* fix(memory): stabilize dreaming CI checks

* memory/dreaming: skip eager narrative session cleanup when detached

Per PR #70737 review (chatgpt-codex-connector, P2): runDreamingSweepPhases
called deleteNarrativeSessionBestEffort synchronously right after each
phase. Once narrative generation moved to detached mode (queued via
queueMicrotask), the eager cleanup races the writer: the session is
deleted before the queued subagent run reads it, silently dropping cron
diary entries.

Skip the eager cleanup branch when params.detachNarratives is true.
generateAndAppendDreamNarrative still runs its own deleteSession in the
finally{} block, so the cleanup intent is preserved without the race.
Heartbeat-driven (non-detached) runs keep the original eager-cleanup
behavior.

* fix(plugin-sdk): restore heartbeat-summary re-export

Per PR #70737 review (chatgpt-codex-connector, P1): the revert of
PR #69875 dropped the `heartbeat-summary` re-export from
`openclaw/plugin-sdk/infra-runtime`. That subpath shipped publicly two
days earlier, so removing it is technically a breaking change to a
public SDK surface — third-party plugins importing
`isHeartbeatEnabledForAgent` / `resolveHeartbeatIntervalMs` from this
path would fail with no replacement contract introduced.

Restore the re-export. Costs nothing to keep; the helpers are already
public via `../infra/heartbeat-summary.ts`. SDK additions are by
default backwards-compatible (CLAUDE.md), so removing within days of
introduction violates that intent.

* changelog: note dreaming decoupling from heartbeat

Refs PR #70737.

---------

Co-authored-by: Josh Lehman <josh@martian.engineering>
2026-04-23 22:23:19 -07:00
Patrick Erichsen
4d7c4b3298 fix(memory-core): harden singleton cache recovery (#70925)
* fix memory cache singleton hardening

* refactor(memory-core): simplify singleton cache repair

Co-authored-by: BirdSong <88885494+fire-mirror@users.noreply.github.com>

---------

Co-authored-by: BirdSong <88885494+fire-mirror@users.noreply.github.com>
2026-04-23 21:21:04 -07:00
Peter Steinberger
1616510996 perf: narrow memory core test imports 2026-04-24 03:46:18 +01:00
Matt Znoj Assist
e069d03945 fix(memory-core): declare local memoryEmbeddingProviders contract (#70873)
Fix standalone memory CLI resolution for the built-in local embedding provider by declaring the memory-core capability contract.\n\nFixes #70836.\nThanks @mattznojassist.
2026-04-24 03:09:49 +01:00
Peter Steinberger
ededff4bc3 fix(memory): recreate stale qmd collections 2026-04-23 23:00:55 +01:00
Mariano
10a9acbf29 fix: keep root memory uppercase (#70621)
Thanks @mbelinky.
2026-04-23 16:10:36 +01:00
Peter Steinberger
4ad8ed2cbe refactor: type config schemas as typebox-compatible 2026-04-23 05:22:16 +01:00
Peter Steinberger
b2472d6560 build: migrate schema deps to typebox 2026-04-23 04:59:42 +01:00
Peter Steinberger
9660cb705b fix(memory): preserve KNN filter limits (#69680) (thanks @aalekh-sarvam) 2026-04-23 04:01:47 +01:00
aalekh-sarvam
7cd051d7f7 fix(memory): use sqlite-vec KNN for searchVector (190x speedup)
Replace full-table scan via vec_distance_cosine() + ORDER BY LIMIT with
sqlite-vec's native MATCH + k = ? KNN operator. Keep vec_distance_cosine()
in the SELECT so score = 1 - dist preserves the existing cosine [0,1]
semantics the downstream merge pipeline depends on.

Fixes #69666.

Benchmark on 10,827 chunks, 4096-dim embeddings:
- Before (full scan):  ~8490 ms/query
- After  (KNN + join): ~50 ms/query

No behavioral changes: returned ids and ordering are identical to the
previous query on all tested queries. The LIMIT ? binding is replaced by
k = ? which caps sqlite-vec's candidate set to the same count.
2026-04-23 04:01:47 +01:00
Vincent Koc
0f0d399c71 fix(hooks): stop memory-core runtime config fallback 2026-04-22 13:57:10 -07:00
Vincent Koc
eae0039aa4 fix(hooks): use live memory-core config during dreaming runs 2026-04-22 13:10:19 -07:00
Vincent Koc
1ebd8e0bb6 fix(hooks): use live config for memory dreaming runtime 2026-04-22 12:47:57 -07:00
Vincent Koc
c09591b086 test(memory): drop stale dreaming hook doubles 2026-04-22 11:53:00 -07:00
Vincent Koc
6d003cbcee fix(hooks): expose typed gateway startup context 2026-04-22 11:22:51 -07:00
Sanjay Santhanam
a37321ad5f fix(memory-core): suppress startup "cron service unavailable" warning (closes #69939)
memory-core registers a gateway:startup hook that runs reconcileManagedDreamingCron() before deps.cron is attached to the startup event (the startup hook is deferred via a 250ms setTimeout in server.impl).

Downgrade the first startup-time "cron service unavailable" warning to a debug log, and rely on the existing runtime reconciliation path to warn if the cron service truly stays unavailable after boot. The managed dreaming cron job itself runs correctly — this was a log-noise regression, not a functional failure.

Signed-off-by: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com>
2026-04-22 04:50:25 +01:00
Patrick Erichsen
529577e045 fix(memory/dreaming): surface blocked status when heartbeat is disabled for main (#69875)
* fix(memory/dreaming): surface blocked status in memory status when heartbeat disabled for main

Replace the hand-rolled heartbeat-rules logic in resolveDreamingBlockedReason
with the shared resolveHeartbeatSummaryForAgent helper, promoted from core to
the plugin-sdk via infra-runtime. Collapses the two disabled-reason branches
into a single message that points at a new Troubleshooting section in the
dreaming docs, so the silent-failure mode described in openclaw/openclaw#69843
becomes legible without the extension re-encoding heartbeat-enablement rules.

Refs openclaw/openclaw#69843, openclaw/openclaw#46046.

* refactor(memory/dreaming): share resolveDreamingBlockedReason across cli and /dreaming surfaces

- Move resolveDreamingBlockedReason from cli.runtime.ts into dreaming.ts as an exported helper and pin its heartbeat check to DEFAULT_AGENT_ID (now exported from plugin-sdk/routing) so the status-line check agrees with the cron's hardcoded sessionTarget even when the configured default agent is not main.
- Render the blocked reason from formatStatus in dreaming-command.ts directly under the enabled line, so /dreaming status, /dreaming on, /dreaming off, and bare /dreaming all flag that the cron is blocked instead of implying dreaming is healthy.
- Tighten the blocked-reason text to lead with user impact ('dreaming is enabled but will not run because heartbeat is disabled for main'), so operators immediately understand the config is toggled on but nothing is actually running.
- Tighten the dreaming Troubleshooting copy to name main explicitly and mention both surfaces.
- Add tests locking the new behavior across cli.test.ts (default-agent=ops still reports blocked for main) and dreaming-command.test.ts (/dreaming status ordering, /dreaming on surfacing, healthy-heartbeat omission).

Refs openclaw/openclaw#69843, openclaw/openclaw#46046.

* fix(memory/dreaming): check heartbeat for the resolved default agent, not the literal 'main'

sessionTarget: 'main' is a cron session-type enum variant meaning 'the default agent's main session', not an agent id (see src/cron/service/jobs.ts). buildManagedDreamingCronJob does not set agentId, and cron runtime resolves the missing agentId through resolveDefaultAgentId(cfg) before enqueuing or waking. The previous pin to DEFAULT_AGENT_ID could produce a false 'blocked' reading when a configured default agent is not 'main' and its heartbeat is fine, and could miss a real block when the default agent is not 'main' and that agent's heartbeat is actually off.

Switch resolveDreamingBlockedReason to resolveDefaultAgentId(cfg) and interpolate the resolved agent id into the message so the blocked line names the agent whose heartbeat is the blocker. Introduce a narrow local CRON_SESSION_TARGET_MAIN constant for the cron session-type enum variant (used by the sessionTarget type and value) so the remaining 'main' literal is semantically distinct from any agent id. Revert the DEFAULT_AGENT_ID export addition on plugin-sdk/routing; memory-core no longer needs it. Update the Troubleshooting doc wording and the cli test that was locking the wrong behaviour.

Refs openclaw/openclaw#69843, openclaw/openclaw#46046.

* fix(memory/dreaming): align blocked check with server-cron wake's defaults-only heartbeat

resolveDreamingBlockedReason was using resolveHeartbeatSummaryForAgent, which merges agents.defaults.heartbeat with agents.list[].heartbeat. The managed dreaming cron leaves job.agentId and job.sessionKey unset, so server-cron's wake wrapper cannot look up a per-agent entry and calls runHeartbeatOnce with agents.defaults.heartbeat only. Using the summary helper would disagree with the actual wake when the default agent overrides heartbeat.every differently from the defaults (either direction — false blocked when the override would run, or false healthy when defaults block).

Mirror the wake path explicitly: rule-1 enablement via isHeartbeatEnabledForAgent against the default agent, rule-3 interval via resolveHeartbeatIntervalMs with defaults-only heartbeat config. Comment points at server-cron so a future cleanup of that latent override-propagation gap sees the coupling.

Refs openclaw/openclaw#69843.
2026-04-21 18:51:43 -07:00
Bek
dfe0e49c8a fix(qmd): Dedup in-flight manager creation so only one full QMD manager arms per agent/config at a time, eliminating the concurrent exportSessions() collisions that triggered path changed during write errors (#65226)
Fixes concurrent manager creation races that caused SafeOpenErrors during session export.

Deduplicates in-flight manager creation so only one full QMD manager arms per agent/config at a time, eliminating the concurrent exportSessions() collisions that triggered path changed during write errors
Resolves and snapshots runtime inputs before cache reuse, replacing stale managers atomically when workspace/config changes, and aborting queued export work promptly on close()
2026-04-21 18:22:21 -04:00
Peter Steinberger
8150c363b5 fix: stabilize memory dreaming QA 2026-04-21 03:12:42 +01:00
chiyouYCH
2055e75f9f fix(memory-core): prevent dreaming-narrative session leaks (#66358) (#67023)
Merged via squash.

Prepared head SHA: 51f72b200c
Co-authored-by: chiyouYCH <26790612+chiyouYCH@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-20 15:41:11 -07:00
Peter Steinberger
f1a544ef6d perf: avoid sort-for-single selection 2026-04-20 23:20:31 +01:00
Peter Steinberger
512dc4f2b1 test: share memory session search setup 2026-04-20 21:14:46 +01:00
Peter Steinberger
1148f245c8 build(deps): declare extension runtime dependencies 2026-04-20 16:07:14 +01:00
Peter Steinberger
8116e638f3 chore: release 2026.4.20 2026-04-20 13:16:40 +01:00
Peter Steinberger
ac8f0c9c0d chore: prepare 2026.4.19-beta.1 release 2026-04-19 02:09:43 +01:00
Peter Steinberger
b3a97df754 refactor: cache reply and visibility runtimes 2026-04-18 20:54:30 +01:00
Peter Steinberger
df525b90f2 chore(lint): enable unnecessary type parameter rule 2026-04-18 18:31:13 +01:00
Peter Steinberger
3f2e73b723 chore(release): bump version to 2026.4.18 2026-04-18 15:46:33 +01:00
Ayaan Zaidi
26f7198eda fix(memory-core): preserve vector dims on readonly recovery 2026-04-17 11:22:56 +05:30
Rubén Cuevas
7b0e950e09 fix: dedupe degraded sqlite-vec warnings (#67898) (thanks @rubencu)
* Agents: dedupe bootstrap truncation warnings

* Memory: dedupe sqlite-vec degradation warnings

* Memory: align degraded vector warning

* test(memory-core): remove stale vector warning arg

* fix(memory-core): reset degraded warning on vector reset

* fix(memory-core): preserve warning latch across reindex rollback

* fix: dedupe degraded sqlite-vec warnings (#67898) (thanks @rubencu)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-17 11:09:14 +05:30
Peter Steinberger
77e6e4cf87 refactor: move memory embeddings into provider plugins 2026-04-17 02:57:18 +01:00
Peter Steinberger
0dc4c4076c chore: bump version to 2026.4.16 2026-04-17 00:45:04 +01:00
mjamiv
8c392f0019 fix(dreaming): default storage.mode to "separate" so phase blocks stop polluting daily memory files (#66412)
Merged via squash.

Prepared head SHA: 4b1c8ac4ec
Co-authored-by: mjamiv <142179942+mjamiv@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-15 13:49:18 -07:00
Josh Lehman
a1b01f0281 fix(memory-core): skip dreaming transcript ingestion via session store (#67315)
Merged via squash.

Prepared head SHA: 87c09b2a75
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-15 13:09:07 -07:00