* refactor(agents): route scheduler tool-name consumers through canonical identity
Introduce AUTOMATIONS_TOOL_NAME + isAutomationsToolName() in
src/agents/tools/automations-tool-name.ts as the single source of truth for
the scheduler agent tool's name, and convert every exact-name consumer:
factory descriptors, deferred-followup availability detection, add-counting,
policy deny lists, mutation classification, trusted media set, tool catalog
id, system-prompt tool order and tool-line map, sandbox deny defaults,
delegation capability map, MCP loopback probes, and local-model lean deny.
Behavior-neutral: the constant still resolves to "cron". Prepares the
rename in RFC openclaw/rfcs#50 so the flip is a one-line change with no
scattered literals.
* feat(agents): rename scheduler agent tool cron -> automations
Flip AUTOMATIONS_TOOL_NAME to "automations" and register the legacy name:
- TOOL_NAME_ALIASES gains cron -> automations, so persisted toolsAllow/
toolsDeny lists, tool groups, and creator allowlists written before the
rename keep matching through the same shipped mechanism as bash -> exec.
No doctor rewrite needed.
- isAutomationsToolName() accepts legacy names so saved transcripts keep
their mutation/replay-safety classification; MUTATING_TOOL_NAMES retains
the legacy entry for the same reason.
- Tool label, catalog label, and tool-search keywords follow the rename
("cron" kept as a search synonym).
- Regression tests cover old-name policy matching (allow and deny), legacy
transcript replay classification, and legacy creator allowlists
normalizing to the canonical id.
Model-facing description strings still say cron; those move in the
follow-up strings PR. Part of RFC openclaw/rfcs#50 Phase 1.
* test(agents): update creator-cap expectations for canonical automations id
The creator tool surface derives from normalized live tool names, so derived
toolsAllow outputs now emit "automations". Passthrough paths without a
creator cap keep storing user input verbatim; those expectations stay on the
legacy name as stored-data coverage.
* fix(gateway): canonicalize legacy cron tool calls and restore scheduler deny protection
Review follow-ups from ClawSweeper and Codex on the rename (RFC 0026):
- MCP loopback tools/call resolves legacy "cron" names to the published
automations tool without re-advertising the old name in tools/list.
- Gateway /tools/invoke canonicalizes legacy names before core-id checks and
exact-name dispatch, so pre-rename integrations keep working.
- Security fix: dangerous-tools deny lists (owner-only HTTP deny and
control-plane set) were keyed on the literal "cron", so the renamed tool
silently lost default-deny and owner-only protection on the HTTP invoke
surface. Lists now use the canonical constant, and the gateway.tools.allow
un-deny filter normalizes both sides so legacy allow entries still lift it.
- Voice high-impact confirmation list and MCP serve creator allowlist follow
the canonical name.
Existing cron-regression suite now proves the legacy path end to end:
default deny 404 for both names, legacy allow entry lifts the deny, and
non-owner protection holds.
* fix(agents): cover stdio MCP legacy calls, probe prompts, and prompt snapshots for the rename
- stdio MCP servers (openclaw-tools-serve / plugin tools handlers) resolve
legacy "cron" callTool names to the published canonical tool, matching
the HTTP loopback behavior; listTools stays canonical-only.
- Live probe prompts instruct harnesses to load/call the automations MCP
tool (mcp__openclaw__automations) instead of the retired name.
- Prompt snapshot fixture filter follows the canonical name (the renamed
tool had silently dropped out of the Codex dynamic-tools snapshots);
snapshots regenerated as a clean rename.
- Type-cast the new mcp-http handler test payloads for check-test-types.
* test(agents): update tool-surface expectations for the automations rename
CI-surfaced fallout in shards not covered by the focused local runs: tool
availability, agent-config filtering, coding-tools construction,
model-provider lean policy, and skill dispatch all assert the scheduler
tool's surface name. Mock fixtures and expectations follow the canonical
id; legacy-name coverage stays in the dedicated policy/creator-cap/invoke
regression suites.
* test(gateway): update tool-resolution exclude expectations for automations rename
* test(security): update trust-model audit expectations for automations rename
* docs(agents): declare cron a permanent scheduler-tool alias per owner decision
Maintainer decision (Omar): cron is not being retired anywhere — config keys,
RPC methods, schedule syntax, and the CLI token all keep it, and the tool
alias follows the same permanent contract as bash -> exec. No doctor rewrite
and no removal window; comments updated to state the contract instead of a
deprecation plan.
* chore(agents): regen prompt snapshots after rebase onto main
* fix(agents): teach canonical automations tool in fallback guidance and reuse the identity source
Review follow-ups: the structured-list fallback still taught models the cron
tool; the cron-scope test echoed its own stub; MCP serve allowlist and voice
confirmation hardcoded the name instead of the canonical constant.
* fix(mcp): place automations identity import outside the header comment
---------
Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
* perf(sqlite): cache synchronous prepared statements
* fix(sqlite): refresh cached statement metadata
* fix(sqlite): bound cached statement retention
* fix(sqlite): close statement cache lifecycle gaps
* test: suppress SQLite warning in retention child
* test(sqlite): make transcript-load counter statement-cache-aware and allowlist raw test SQL
* test(sessions): type the wrapped iterate against its overloaded signature
* test: share a statement-cache-aware SQLite execution counter across prepare-count tests
* fix(pr): validate head SHA with bash regex so fork-CI runners without ripgrep pass the artifacts-init guard
---------
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* refactor(prompt): plain inbound context labels with a provenance marker
Replaces trust-worded inbound context labels ("(untrusted metadata)",
"(untrusted, for context)") with plain labels plus a fixed provenance
marker suffix appended to every OpenClaw-injected context header.
Detection keys on the marker, not label text, so strippers stay correct
across UI, TUI, replay, /trace segmentation, memory recall, and the Swift
chat preprocessor. Drops sanitizeInboundSystemTags in favor of the marker
boundary plus trusted system-prompt narration.
Renames the untrusted-named plugin SDK context identifiers to
channel-provenance names, keeping deprecated aliases registered for
removal after 2026-09-08.
Adds `openclaw doctor --fix` migrations that rewrite legacy inbound
labels in stored SQLite transcripts and purge legacy envelope-
contaminated LanceDB recall rows.
* fix(ci): resolve gate failures for plain inbound context labels
- doctor sqlite readers: open read-only connections via openNodeSqliteDatabase
so the Kysely connection-boundary guardrail holds; unexport the now-internal
transcript snapshot type (Knip unused-export gate).
- compat registry: split the record table into registry-records.ts and
plugin-sdk-subpath-records.ts. The new compat record pushed registry.ts past
the 700-line oxlint cap; suppressions are disallowed, so follow the existing
sibling record-module pattern. Public exports and PluginCompatCode literals
unchanged.
- acp-runtime test: assert current finalization behavior (newline normalization
only). The bracket de-fang and System: rewrite it expected were removed with
sanitizeInboundSystemTags; forged system lines are neutralized at the
system-event queue, the single chokepoint feeding the System:-per-line render.
- regenerate docs_map and the plugin SDK API baseline manifest.
* fix(prompt): harden inbound context label migration and drop in-band sanitizer
Review follow-ups on the plain-label + provenance-marker change:
- Remove src/security/system-tags.ts. Rewriting inbound text to neutralize
look-alike `System:`/`[System]` markers corrupted legitimate user text and is
not a real injection boundary; role separation plus external-content wrapping
is. Explicit product decision, recorded at the system-event queue.
- Narrow the LanceDB legacy-row purge so it cannot delete benign memories. It
now requires a complete known legacy sentinel line, a legacy label followed by
a fenced JSON body, or the complete legacy external-content header. The prior
predicates matched ordinary prose such as `Notes (untrusted metadata):`, and
deletion is irreversible.
- Make explicit-empty canonical ChannelStructuredContext win over the deprecated
alias via a present/absent result instead of collapsing `[]` to undefined.
- Keep `\r?` in the active-memory doctor rule. It is the only rule spanning the
header's line break, migrated assistant rows skip newline normalization, and
without it the marked-header replace wins and the body strips to empty. Added
a CRLF regression test.
- Fix stale comments that described removed behavior, and cover the Swift
prose-block strip path.
Claude-Session: https://claude.ai/code/session_01WNzsPddQmxy9Y7jKD4wAxH
* feat(sessions): retain reset history in sqlite with physical disk budget
* fix(sessions): satisfy test-types, knip export scan, and docs map
* fix(sessions): align behavioral suites and flip proof with retained history, route-aware cleanup plans
Measured breakdown of check-prompt-snapshots in run 29557851276 (5m03s):
- 37s checkout + Node env setup
- 4m25s inside one `pnpm prompt:snapshots:check` process:
- ~35s tsx import of the generator graph
- ~3min first createOpenClawCodingTools call: the message-tool schema
build resolves the scenario channel plugin, the empty loaded registry
falls back to the bundled-channel jiti loader
(extensions/telegram/index.ts), and jiti re-transpiles the core source
graph (136.6s jiti self time in --cpu-prof; second generation call in
the same process takes 0.3s)
- ~1min more for the cold provider-plugin lookup in
normalizeAgentRuntimeTools; no provider plugin owns tool-schema hooks
for the `codex` harness provider, so the jiti load only rediscovers a
no-op
- <2s actual rendering + oxfmt + drift compare
Split axis decision: the planned 2-3 way scenario shard matrix cannot
lower the pole because the cost is a one-time per-process transpile;
every shard would pay the full ~4min again (jiti fsCache does not help:
a warm-cache rerun still took 200s). Fix the generator instead:
- Preload each scenario's channel plugin surface (channel-plugin-api.js,
resolved via the bundled-plugin public-surface resolver) through the
ambient tsx/vitest ESM graph, and pin exactly that channel in a scoped
loaded registry while the scenario's tools are built. Snapshot bytes
are unchanged: the loaded plugin object is the same export the bundled
jiti fallback materializes, and cross-channel action discovery still
sees no other loaded channels.
- Pass allowProviderRuntimePluginLoad=false to normalizeAgentRuntimeTools;
registry-only resolution returns the same undefined plugin instantly.
Coverage guard: test/scripts/prompt-snapshots.test.ts now generates the
snapshot files and asserts zero jiti plugin-loader calls (with the
offending transform targets in the failure message), so a future scenario
or channel that misses the preload fails the suite instead of silently
restoring the 4-minute lane.
Proof: `pnpm prompt:snapshots:check` passes byte-identical against the
committed fixtures in 54s wall / 35s CPU locally (was 354s wall / 306s
CPU); focused vitest suites (32 tests incl. new guard), tsgo core-test +
extensions-test lanes, scoped oxlint/oxfmt, and `git diff --check` are
green. Expected CI pole when the lane fires: ~5.1min -> ~1.5-2min.
* refactor: delete dead infra and config exports
* refactor: preserve live infra and config contracts
* refactor(config): remove obsolete file-store lifecycle APIs
* refactor(infra): finish current-main dead export cleanup
* fix(gateway): make hot reload transactional
Replace partial reload side effects with a deferred transaction that publishes config, secrets, auth, and subsystem state together, and drains in-flight reload work before shutdown.
Co-authored-by: LZY3538 <293718838+LZY3538@users.noreply.github.com>
* fix(auth): preserve state-only credential ownership
Keep derived runtime snapshots in place for main-store state mutations so order refreshes do not look like credential replacement.
* fix(gateway): close reload transaction gaps
* fix(gateway): close merged reload gaps
* chore: move reload note to PR context
* fix(gateway): exclude restart emission root
---------
Co-authored-by: LZY3538 <293718838+LZY3538@users.noreply.github.com>
Adds a core sessions_search agent tool backed by a SQLite FTS5 index that
lives next to the transcript rows in the per-agent database. Indexing is
transactional: user/assistant text is indexed inside the same write
transaction that persists the event, deletes drop index rows in the same
transaction, and branch rewinds mark the session dirty so the next search
rebuilds it from the same visible-path resolution sessions_history uses
(which also lazily backfills doctor-migrated databases). Search executes
gateway-side behind an additive sessions.search method with a bounded
session-key allowlist; visibility, sandbox restrictions, and snippet
redaction mirror sessions_history.
Closes#100978
* chore(types): add declaration files for scripts/lib and scripts/e2e modules
* chore(types): add declaration files for top-level script modules (a-m)
* chore(types): add declaration files for top-level script modules (n-z)
* test: use a non-secret-shaped gateway token fixture
* test: type ci workflow guard helpers for the root test lane
* chore(tooling): typecheck root test/** with a dedicated tsgo lane
- test/tsconfig/tsconfig.test.root.json: root-test program (strict unused checks,
fixtures excluded; two Docker E2E clients that import built dist/** stay out,
same rationale as the scripts/e2e exclusion in tsconfig.scripts.json)
- tsgo:test:root wired into tsgo:test, check:test-types, scripts/check.mjs, and
the ci.yml test-types shard, mirroring the tsgo:scripts lane (#104348)
- changed-lane routing: test/**/*.ts (excluding fixtures) and the lane tsconfig
now trigger 'typecheck test root' in check:changed; previously test/ paths ran
lint only, so harness type errors surfaced first in CI (#104287 envDir case)
- burn down all 1071 latent type errors in the program: precise param/local
types across test/scripts, test/vitest, test/e2e, and transitive scripts/e2e
program members; 205 sibling .d.mts declaration files for imported .mjs
modules (committed separately); zero any, zero ts-expect-error
- resolve the pre-existing testing star-export ambiguity in
scripts/e2e/parallels/common.ts with an explicit re-export
Closes#104388
* chore(types): correct declaration fidelity per structured review
- re-derive 51 .d.mts files from implementation data flow instead of
initializers: fix a wrong never return (runTestProjectsDelegation returns
the child), add encoding-sensitive exec/spawn overloads (plain-gh), restore
the full release profile union, make parsed paths string | null, add missing
parseArgs fields via help/non-help unions, add a missing sibling declaration
(budget-number-args), drop 15 unused lint directives
- precise install-record/tuple typing removes the type-aware oxlint
regressions the first declarations caused in scripts/e2e implementations
- route .mts declaration edits under test/ to the testRoot lane and reference
the test-root project from tsconfig.projects.json so tsgo:all covers it
(closes both review findings against the lane wiring)
* chore(scripts): keep telegram runner dist typing structural for the boundary guard
* chore(types): declare runtime pack and gateway readiness exports added on main
* test: pin the importTargetPlan form of the plugin-contract plan import
The guard expectation still referenced the raw await import( form that
7ae5996bb3 (#103975) replaced with the importTargetPlan fallback helper;
the assertion fails on current main.
* feat(tooling): add tsgo typecheck lane for scripts/**
* fix(scripts): burn down scripts type debt surfaced by the new lane
Typing-only except bugs the lane surfaced: gh-read timeout race,
Discord Headers spread dropping entries, undefined allowedHeadBranches
match, plugin-boundary matchAll crash. Deletes retired config keys from
fixtures/benches (prompt snapshots regenerated, config dump only) and
the orphaned non-runnable sync-moonshot-docs script. Adds full-surface
.d.mts declarations for existing .mjs boundaries.
Allow busy TUI sessions to forward prompts into the configured queue while
keeping queued-turn admission, cancellation, restart, and transcript ownership
consistent across the TUI, Gateway, and followup queue.
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
Summary:
- The branch adds `useAutoCleanupTempDirTracker()`, broadens the temp-dir warning reporter to flag new manual helper imports/usages, updates docs, and migrates two script tests to the new helper.
- PR surface: Tests +301, Docs +1, Other +248. Total +550 across 8 files.
- Reproducibility: not applicable. this is test/tooling cleanup, and the changed behavior is exercised through helper/reporter tests and CI evidence rather than a user reproduction path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: test: harden temp dir helper guard
- PR branch already contained follow-up commit before automerge: test: clarify auto cleanup temp dir helper name
- PR branch already contained follow-up commit before automerge: test: cover existing mkdtemp temp dir forms
- PR branch already contained follow-up commit before automerge: test: read staged temp helper source from index
Validation:
- ClawSweeper review passed for head 1fdd7d2a9a.
- Required merge gates passed before the squash merge.
Prepared head SHA: 1fdd7d2a9a
Review: https://github.com/openclaw/openclaw/pull/93209#issuecomment-4705653665
Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Approved-by: hxy91819