@a1hvdy/cc-openclaw 0.32.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -122,6 +122,62 @@ function truncateResult(s) {
122
122
  }
123
123
  return cut ? out.replace(/\s+$/, '') + '\n…' : out;
124
124
  }
125
+ /**
126
+ * v0.33.0 C6 — OpenClaw 2026.5.22 WebChat-style tool deduplication.
127
+ * Detect when a tool's result text appears nearly verbatim in the assistant's
128
+ * final answer. Returns true if >80% of the tool result chars appear in the
129
+ * assistant text (threshold chosen to catch real duplicates while tolerating
130
+ * minor formatting differences).
131
+ */
132
+ function isToolResultDuplicate(toolResult, assistantText) {
133
+ if (!toolResult || !assistantText)
134
+ return false;
135
+ const toolChars = toolResult.trim().length;
136
+ if (toolChars < 50)
137
+ return false; // Skip short results (not worth summarizing)
138
+ // Normalize both strings: lowercase, collapse whitespace
139
+ const normTool = toolResult.toLowerCase().replace(/\s+/g, ' ').trim();
140
+ const normAsst = assistantText.toLowerCase().replace(/\s+/g, ' ').trim();
141
+ // Check if assistant text contains most of the tool result
142
+ if (normAsst.includes(normTool))
143
+ return true;
144
+ // Fuzzy check: count how many 10-char chunks from tool result appear in assistant text
145
+ const chunkSize = 10;
146
+ const chunks = [];
147
+ for (let i = 0; i <= normTool.length - chunkSize; i += chunkSize) {
148
+ chunks.push(normTool.slice(i, i + chunkSize));
149
+ }
150
+ const matchedChunks = chunks.filter(c => normAsst.includes(c)).length;
151
+ const matchRatio = matchedChunks / Math.max(chunks.length, 1);
152
+ return matchRatio > 0.8; // 80% of tool result appears in assistant text
153
+ }
154
+ /**
155
+ * v0.33.0 C6 — Summarize a tool result when it duplicates the assistant's answer.
156
+ * Returns a short summary like "✓ 247 chars" or "✓ message sent" instead of the
157
+ * full verbose output. Keeps cards clean when the assistant already shows the content.
158
+ */
159
+ function summarizeToolResult(tc, resultText) {
160
+ const name = tc.name.toLowerCase();
161
+ const chars = resultText.trim().length;
162
+ // Tool-specific summaries
163
+ if (name === 'bash' || name === 'exec') {
164
+ return `✓ ${chars} chars output`;
165
+ }
166
+ if (name === 'read') {
167
+ return `✓ ${chars} chars read`;
168
+ }
169
+ if (name === 'write' || name === 'edit' || name === 'multiedit') {
170
+ return `✓ file updated`;
171
+ }
172
+ if (name.includes('message') || name.includes('send')) {
173
+ return `✓ message sent`;
174
+ }
175
+ if (name.includes('search') || name.includes('fetch')) {
176
+ return `✓ ${chars} chars fetched`;
177
+ }
178
+ // Generic fallback
179
+ return `✓ ${chars} chars`;
180
+ }
125
181
  /**
126
182
  * v0.27.4 M2 — CLI-parity gap #3: render a compact file diff for Edit / Write /
127
183
  * MultiEdit from the tool INPUT (the result payload is only "File updated", so
@@ -393,11 +449,25 @@ export function renderTurn(turn, meta) {
393
449
  // the "File updated" result; other tools keep the result preview.
394
450
  const diffText = toolDiffBlock(tc);
395
451
  const resultText = toolResultText(tc);
396
- const block = diffText
397
- ? pre(diffText, 'diff') // v0.27.5 M1 Telegram colors -/+ lines red/green
398
- : resultText
399
- ? pre(truncateResult(resultText), langForTool(tc)) // v0.27.5 M2 — lang-highlight output
400
- : '';
452
+ // v0.33.0 C6 — WebChat-style deduplication: if the tool result duplicates
453
+ // the assistant's answer, show a short summary instead of the full output.
454
+ // Keeps cards clean when the assistant already presents the same content.
455
+ let block = '';
456
+ if (diffText) {
457
+ block = pre(diffText, 'diff'); // v0.27.5 M1 — Telegram colors -/+ lines red/green
458
+ }
459
+ else if (resultText) {
460
+ const isDupe = isToolResultDuplicate(resultText, turn.assistantText);
461
+ if (isDupe) {
462
+ // Summarize duplicate output (e.g., "✓ 247 chars" instead of full text)
463
+ const summary = summarizeToolResult(tc, resultText);
464
+ block = code(summary); // Short inline summary, not a <pre> block
465
+ }
466
+ else {
467
+ // Show full result with truncation
468
+ block = pre(truncateResult(resultText), langForTool(tc)); // v0.27.5 M2 — lang-highlight output
469
+ }
470
+ }
401
471
  const withBlock = block ? `${line}\n${block}` : line;
402
472
  // Prefer line+block; if that bursts the cap, fall back to the line alone
403
473
  // (the result preview is the droppable part, the activity line is not).
@@ -0,0 +1,74 @@
1
+ /**
2
+ * drift-detector — snapshots the parsed Config to disk on a healthy boot;
3
+ * compares on subsequent boots and returns a delta list.
4
+ *
5
+ * Primary purpose: detect keys pruned by `openclaw doctor --fix`
6
+ * (OF5 — feedback_cc_openclaw_provider_timeout.md).
7
+ *
8
+ * Snapshot path: ~/.openclaw/workspace/memory/cc-openclaw-config-snapshot.json
9
+ * The file is written atomically (write-then-rename is not available in pure
10
+ * Node ESM without extra deps; we write directly since the worst case is a
11
+ * corrupted snapshot — non-fatal; falls back to empty baseline).
12
+ */
13
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
14
+ import { homedir } from 'os';
15
+ import { join, dirname } from 'path';
16
+ const SNAPSHOT_PATH = join(homedir(), '.openclaw', 'workspace', 'memory', 'cc-openclaw-config-snapshot.json');
17
+ // ── Internal helpers ──────────────────────────────────────────────────────────
18
+ function flattenConfig(obj, prefix = '') {
19
+ if (obj === null || typeof obj !== 'object') {
20
+ return { [prefix]: obj };
21
+ }
22
+ const result = {};
23
+ for (const [k, v] of Object.entries(obj)) {
24
+ const key = prefix ? `${prefix}.${k}` : k;
25
+ if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
26
+ Object.assign(result, flattenConfig(v, key));
27
+ }
28
+ else {
29
+ result[key] = v;
30
+ }
31
+ }
32
+ return result;
33
+ }
34
+ function readSnapshot() {
35
+ if (!existsSync(SNAPSHOT_PATH))
36
+ return {};
37
+ try {
38
+ const raw = readFileSync(SNAPSHOT_PATH, 'utf8');
39
+ return JSON.parse(raw);
40
+ }
41
+ catch {
42
+ return {};
43
+ }
44
+ }
45
+ // ── Public API ────────────────────────────────────────────────────────────────
46
+ /**
47
+ * Compare current config against the on-disk snapshot.
48
+ * Returns an array of changed paths (empty = no drift).
49
+ */
50
+ export function detectDrift(current) {
51
+ const previous = readSnapshot();
52
+ const flat = flattenConfig(current);
53
+ const deltas = [];
54
+ for (const [path, value] of Object.entries(flat)) {
55
+ if (path in previous && JSON.stringify(previous[path]) !== JSON.stringify(value)) {
56
+ deltas.push({ path, previous: previous[path], current: value });
57
+ }
58
+ }
59
+ return deltas;
60
+ }
61
+ /**
62
+ * Persist current config as the baseline snapshot for future drift detection.
63
+ * Called at the end of a successful boot (after phase 7 / ready state).
64
+ */
65
+ export function saveSnapshot(current) {
66
+ try {
67
+ mkdirSync(dirname(SNAPSHOT_PATH), { recursive: true });
68
+ const flat = flattenConfig(current);
69
+ writeFileSync(SNAPSHOT_PATH, JSON.stringify(flat, null, 2), 'utf8');
70
+ }
71
+ catch {
72
+ // Non-fatal: drift detection degrades to "no baseline" on next boot.
73
+ }
74
+ }
package/dist/src/index.js CHANGED
@@ -20,7 +20,7 @@ import { registerCwdPatch, registerSyspromptStrip, registerThinkConflictResolver
20
20
  import { register as registerTelegramMirror } from './channels/telegram-mirror/index.js';
21
21
  import { register as registerMcpBridge } from './mcp/index.js';
22
22
  export const PLUGIN_ID = 'cc-openclaw';
23
- export const VERSION = '0.1.0';
23
+ export const VERSION = '0.33.0';
24
24
  /**
25
25
  * Listener-activation flag — gates all sub-module register() calls.
26
26
  *
@@ -92,6 +92,12 @@ function parseEnvelope(raw) {
92
92
  * win when present (interactive sessions); otherwise we derive a name from the
93
93
  * enveloped user prompts (headless cco sessions). cwd is taken from the first
94
94
  * entry that records it.
95
+ *
96
+ * v0.33.0 C5 — OpenClaw 2026.5.22 session workflow optimization: instead of
97
+ * reading the entire file, read only the first ~100 lines (for title/cwd) and
98
+ * last ~100 lines (for last-prompt/desc). This makes /sessions listing ~10×
99
+ * faster for long sessions (e.g., 1000+ line files) while extracting the same
100
+ * metadata. Typical savings: 50KB file → read 10KB instead of 50KB.
95
101
  */
96
102
  function extractMeta(filePath, sizeBytes) {
97
103
  let title = '';
@@ -101,9 +107,28 @@ function extractMeta(filePath, sizeBytes) {
101
107
  let lastUser = '';
102
108
  if (sizeBytes > MAX_PARSE_BYTES)
103
109
  return { title, desc, cwd };
110
+ // v0.33.0 C5 — Optimized read: first + last chunks only (not entire file)
111
+ const CHUNK_LINES = 100; // Read first/last N lines for metadata
104
112
  let content;
105
113
  try {
106
- content = readFileSync(filePath, 'utf8');
114
+ if (sizeBytes < 50_000) {
115
+ // Small files: read entire content (faster than chunked I/O)
116
+ content = readFileSync(filePath, 'utf8');
117
+ }
118
+ else {
119
+ // Large files: read first ~100 and last ~100 lines only
120
+ const fullContent = readFileSync(filePath, 'utf8');
121
+ const lines = fullContent.split('\n');
122
+ if (lines.length <= CHUNK_LINES * 2) {
123
+ content = fullContent; // File has ≤200 lines, use full content
124
+ }
125
+ else {
126
+ // Extract first 100 + last 100 lines, skip middle
127
+ const firstChunk = lines.slice(0, CHUNK_LINES).join('\n');
128
+ const lastChunk = lines.slice(-CHUNK_LINES).join('\n');
129
+ content = `${firstChunk}\n${lastChunk}`;
130
+ }
131
+ }
107
132
  }
108
133
  catch {
109
134
  return { title, desc, cwd };
@@ -0,0 +1,10 @@
1
+ export * from './register-guard.js';
2
+ export { registerOnce } from './register-guard.js';
3
+ export { stripSysprompt, isStripEnabled } from './sysprompt-strip.js';
4
+ export { isCacheParityEnabled, hashPrompt, recordAttachment, readRegistry, REGISTRY_PATH, } from './cache-parity.js';
5
+ // Engine routing — originally `./route-flag.js`; collapsed into
6
+ // `./config-service.js` at Cluster A step 8. Same API, same semantics,
7
+ // single source of truth.
8
+ export { selectEngine, isCcOpenclawEnabled, captureSessionRoute, ACTIVE_FLAG_ENV, ROUTE_FLAG_ENV, } from './config-service.js';
9
+ export { isTestMode, TEST_MODE_ENV, _setTestModeForTests } from './test-mode.js';
10
+ export { getAggressiveStripEnabled, getCacheParityEnabled, getLogLevel, isLogLevelDebug, } from './config.js';
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Stale PID-keyed file cleanup — for status/sentinel files named `<pid>.json`
3
+ * in a tee directory, removes entries whose PID is no longer alive.
4
+ *
5
+ * Extracted from `live-card.ts` 2026-05-14. Pure-function utility with a
6
+ * dir-parameter shape so future callers (other PID-keyed sentinel patterns)
7
+ * can reuse without duplicating the kill(pid, 0) liveness probe.
8
+ *
9
+ * The original file-extension was `.json`; expose it as a parameter so this
10
+ * is forward-compatible with `.sock`, `.lock`, etc.
11
+ */
12
+ import { readdirSync, unlinkSync } from 'node:fs';
13
+ /**
14
+ * Remove `<pid><ext>` files in `dir` whose PID no longer exists.
15
+ * Silent on missing directory. Per-file errors are swallowed — this is
16
+ * best-effort cleanup, not a correctness guarantee.
17
+ */
18
+ export function cleanStalePidFiles(dir, ext = '.json') {
19
+ try {
20
+ const files = readdirSync(dir);
21
+ for (const file of files) {
22
+ if (!file.endsWith(ext))
23
+ continue;
24
+ const pid = parseInt(file.replace(ext, ''), 10);
25
+ if (isNaN(pid))
26
+ continue;
27
+ try {
28
+ process.kill(pid, 0);
29
+ }
30
+ catch {
31
+ try {
32
+ unlinkSync(`${dir}/${file}`);
33
+ }
34
+ catch { /* ignore */ }
35
+ }
36
+ }
37
+ }
38
+ catch { /* directory doesn't exist — nothing to clean */ }
39
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * SnapshotWriter — periodic full-state snapshot of the SessionRegistry.
3
+ *
4
+ * Snapshot file: ~/.openclaw/workspace/memory/cc-openclaw-session-snapshot.json
5
+ * Written every N minutes from phase 7 (schedule-jobs).
6
+ * Phase E wires SessionRegistry.snapshot() → SnapshotWriter.write().
7
+ * Stub body in Phase D.
8
+ */
9
+ import { mkdirSync, writeFileSync } from 'fs';
10
+ import { homedir } from 'os';
11
+ import { join, dirname } from 'path';
12
+ const SNAPSHOT_PATH = join(homedir(), '.openclaw', 'workspace', 'memory', 'cc-openclaw-session-snapshot.json');
13
+ export class SnapshotWriter {
14
+ path;
15
+ constructor(path = SNAPSHOT_PATH) {
16
+ this.path = path;
17
+ }
18
+ /**
19
+ * Write the full session state array as a JSON file.
20
+ * Phase E: write to a temp file then rename for atomicity.
21
+ */
22
+ async write(states) {
23
+ try {
24
+ mkdirSync(dirname(this.path), { recursive: true });
25
+ writeFileSync(this.path, JSON.stringify(states, null, 2), 'utf8');
26
+ }
27
+ catch {
28
+ // Non-fatal stub; Phase E promotes to logged error.
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * WalWriter — append-only JSONL writer for the session registry WAL.
3
+ *
4
+ * WAL file location: ~/.openclaw/workspace/memory/cc-openclaw-session-wal.jsonl
5
+ * Phase E wires this into SessionRegistry.set() / delete().
6
+ * Stub body in Phase D — compiles and exports the class with the correct interface.
7
+ */
8
+ import { mkdirSync, appendFileSync } from 'fs';
9
+ import { homedir } from 'os';
10
+ import { join, dirname } from 'path';
11
+ const WAL_PATH = join(homedir(), '.openclaw', 'workspace', 'memory', 'cc-openclaw-session-wal.jsonl');
12
+ export class WalWriter {
13
+ path;
14
+ constructor(path = WAL_PATH) {
15
+ this.path = path;
16
+ }
17
+ /**
18
+ * Append a JSON-serializable record as a single JSONL line.
19
+ * Creates parent directories if absent. Non-atomic in Phase D stub;
20
+ * Phase E adds write-then-rename for crash safety.
21
+ */
22
+ append(record) {
23
+ try {
24
+ mkdirSync(dirname(this.path), { recursive: true });
25
+ appendFileSync(this.path, JSON.stringify(record) + '\n', 'utf8');
26
+ }
27
+ catch {
28
+ // Non-fatal in Phase D; Phase E promotes to logged error.
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Cluster A — Type-seams barrel.
3
+ *
4
+ * Single import surface for all typed boundaries introduced in Cluster A.
5
+ * Subsequent clusters import from `cc-openclaw/types` (this barrel)
6
+ * rather than reaching into individual modules.
7
+ *
8
+ * This file is intentionally pure re-exports — no logic, no side effects.
9
+ */
10
+ export * from './runtime-config.js';
11
+ export * from './route.js';
12
+ export * from './sse.js';
13
+ export * from './session.js';
14
+ export * from './upstream.js';
15
+ export * from './tool-bridge.js';
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Cluster A — Session boundary types.
3
+ *
4
+ * Re-exports the session vocabulary already established in the root
5
+ * `src/types.ts` module. New aliases (`SessionStartConfig`, `SessionMeta`)
6
+ * preview Cluster B's `SessionService` boundary without yet introducing
7
+ * a new shape — they're typed wrappers over today's `SessionConfig` /
8
+ * `ActiveSession`.
9
+ *
10
+ * `SessionName` is the branded type that Cluster D's `SessionRegistry`
11
+ * will use to enforce the `'openai-'` prefix routing discriminant
12
+ * (cwd-patch.ts:489 gates CWD redirect, tools restoration, CLAUDE.md
13
+ * injection on this prefix).
14
+ *
15
+ * NOT consumed yet — Cluster A first commit establishes the vocabulary.
16
+ */
17
+ export const sessionNameFromKey = (key) => `openai-${key}`;
18
+ export const isOpenAiBridgeName = (name) => name.startsWith('openai-');
19
+ export const stripOpenAiPrefix = (name) => name.replace(/^openai-/, '');
package/mcp-tools.json CHANGED
@@ -1 +1 @@
1
- [{"type":"function","function":{"name":"browser","description":"Control the browser via OpenClaw's browser control server (status/start/stop/profiles/tabs/open/snapshot/screenshot/actions). Browser choice: omit profile by default for the isolated OpenClaw-managed browser (`openclaw`). For the logged-in user browser, use profile=\"user\". A supported Chromium-based browser (v144+) must be running on the selected host or browser node. Use only when existing logins/cookies matter and the user is present. For profile=\"user\" or other existing-session profiles, omit timeoutMs on act:type, evaluate, hover, scrollIntoView, drag, select, and fill; that driver rejects per-call timeout overrides for those actions. When a node-hosted browser proxy is available, the tool may auto-route to it. Pin a node with node=<id|name> or target=\"node\". When using refs from snapshot (e.g. e12), keep the same tab: prefer passing targetId from the snapshot response into subsequent actions (act/click/type/etc). For tab operations, targetId also accepts tabId handles (t1) and labels from action=tabs. For multi-step browser work, login checks, stale refs, duplicate tabs, or Google Meet flows, use the bundled browser-automation skill when it is available. For stable, self-resolving refs across calls, use snapshot with refs=\"aria\" (Playwright aria-ref ids). Default refs=\"role\" are role+name-based. Use snapshot+act for UI automation. Avoid act:wait by default; use only in exceptional cases when no reliable UI state exists. target selects browser location (sandbox|host|node). Default: host. Host target allowed.","parameters":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["doctor","status","start","stop","profiles","tabs","open","focus","close","snapshot","screenshot","navigate","console","pdf","upload","dialog","act"]},"target":{"type":"string","enum":["sandbox","host","node"]},"node":{"type":"string"},"profile":{"type":"string"},"targetUrl":{"type":"string"},"url":{"type":"string"},"targetId":{"type":"string"},"label":{"type":"string"},"limit":{"type":"number"},"maxChars":{"type":"number"},"mode":{"type":"string","enum":["efficient"]},"snapshotFormat":{"type":"string","enum":["aria","ai"]},"refs":{"type":"string","enum":["role","aria"]},"interactive":{"type":"boolean"},"compact":{"type":"boolean"},"depth":{"type":"number"},"selector":{"type":"string"},"frame":{"type":"string"},"labels":{"type":"boolean"},"urls":{"type":"boolean"},"fullPage":{"type":"boolean"},"ref":{"type":"string"},"element":{"type":"string"},"type":{"type":"string","enum":["png","jpeg"]},"level":{"type":"string"},"paths":{"type":"array","items":{"type":"string"}},"inputRef":{"type":"string"},"timeoutMs":{"type":"number"},"accept":{"type":"boolean"},"promptText":{"type":"string"},"kind":{"type":"string","enum":["click","clickCoords","type","press","hover","drag","select","fill","resize","wait","evaluate","close"]},"doubleClick":{"type":"boolean"},"button":{"type":"string"},"modifiers":{"type":"array","items":{"type":"string"}},"x":{"type":"number"},"y":{"type":"number"},"text":{"type":"string"},"submit":{"type":"boolean"},"slowly":{"type":"boolean"},"key":{"type":"string"},"delayMs":{"type":"number"},"startRef":{"type":"string"},"endRef":{"type":"string"},"values":{"type":"array","items":{"type":"string"}},"fields":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"width":{"type":"number"},"height":{"type":"number"},"timeMs":{"type":"number"},"textGone":{"type":"string"},"loadState":{"type":"string"},"fn":{"type":"string"},"request":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["click","clickCoords","type","press","hover","drag","select","fill","resize","wait","evaluate","close"]},"targetId":{"type":"string"},"ref":{"type":"string"},"doubleClick":{"type":"boolean"},"button":{"type":"string"},"modifiers":{"type":"array","items":{"type":"string"}},"x":{"type":"number"},"y":{"type":"number"},"text":{"type":"string"},"submit":{"type":"boolean"},"slowly":{"type":"boolean"},"key":{"type":"string"},"delayMs":{"type":"number"},"startRef":{"type":"string"},"endRef":{"type":"string"},"values":{"type":"array","items":{"type":"string"}},"fields":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"width":{"type":"number"},"height":{"type":"number"},"timeMs":{"type":"number"},"selector":{"type":"string"},"url":{"type":"string"},"loadState":{"type":"string"},"textGone":{"type":"string"},"timeoutMs":{"type":"number"},"fn":{"type":"string"}}}}}}},{"type":"function","function":{"name":"cron","description":"Manage Gateway cron jobs (status/list/get/add/update/remove/run/runs) and send wake events. Use this for reminders, \"check back later\" requests, delayed follow-ups, and recurring tasks. Do not emulate scheduling with exec sleep or process polling.\n\nMain-session cron jobs enqueue system events for heartbeat handling. Isolated cron jobs create background task runs that appear in `openclaw tasks`.\n\nACTIONS:\n- status: Check cron scheduler status\n- list: List jobs (use includeDisabled:true to include disabled; agentId filters by agent, auto-filled from session)\n- get: Get one job by id (requires jobId)\n- add: Create job (requires job object, see schema below)\n- update: Modify job (requires jobId + patch object)\n- remove: Delete job (requires jobId)\n- run: Trigger job immediately (requires jobId)\n- runs: Get job run history (requires jobId)\n- wake: Send wake event (requires text, optional mode)\n\nJOB SCHEMA (for add action):\n{\n \"name\": \"string (optional)\",\n \"schedule\": { ... }, // Required: when to run\n \"payload\": { ... }, // Required: what to execute\n \"delivery\": { ... }, // Optional: announce summary (isolated/current/session:xxx only) or webhook POST\n \"sessionTarget\": \"main\" | \"isolated\" | \"current\" | \"session:<custom-id>\", // Optional, defaults based on context\n \"enabled\": true | false // Optional, default true\n}\n\nSESSION TARGET OPTIONS:\n- \"main\": Run in the main session (requires payload.kind=\"systemEvent\")\n- \"isolated\": Run in an ephemeral isolated session (requires payload.kind=\"agentTurn\")\n- \"current\": Bind to the current session where the cron is created (resolved at creation time)\n- \"session:<custom-id>\": Run in a persistent named session (e.g., \"session:project-alpha-daily\")\n\nDEFAULT BEHAVIOR (unchanged for backward compatibility):\n- payload.kind=\"systemEvent\" → defaults to \"main\"\n- payload.kind=\"agentTurn\" → defaults to \"isolated\"\nTo use current session binding, explicitly set sessionTarget=\"current\".\n\nSCHEDULE TYPES (schedule.kind):\n- \"at\": One-shot at absolute time\n { \"kind\": \"at\", \"at\": \"<ISO-8601 timestamp>\" }\n- \"every\": Recurring interval\n { \"kind\": \"every\", \"everyMs\": <interval-ms>, \"anchorMs\": <optional-start-ms> }\n- \"cron\": Cron expression evaluated in the supplied timezone, or the Gateway host local timezone when tz is omitted\n { \"kind\": \"cron\", \"expr\": \"<cron-expression>\", \"tz\": \"<optional-IANA-timezone>\" }\n Write expr in the selected timezone's local wall-clock time; do not convert the requested local time to UTC first.\n If tz is omitted, do not assume UTC; the Gateway host local timezone is used.\n Example: \"Remind me every day at 6pm Shanghai time\" -> { \"kind\": \"cron\", \"expr\": \"0 18 * * *\", \"tz\": \"Asia/Shanghai\" }\n\nFor schedule.kind=\"at\", ISO timestamps without an explicit timezone are treated as UTC.\n\nPAYLOAD TYPES (payload.kind):\n- \"systemEvent\": Injects text as system event into session\n { \"kind\": \"systemEvent\", \"text\": \"<message>\" }\n- \"agentTurn\": Runs agent with message (isolated sessions only)\n { \"kind\": \"agentTurn\", \"message\": \"<prompt>\", \"model\": \"<optional>\", \"thinking\": \"<optional>\", \"timeoutSeconds\": <optional, 0 means no timeout> }\n\nDELIVERY (top-level):\n { \"mode\": \"none|announce|webhook\", \"channel\": \"<optional>\", \"to\": \"<optional>\", \"threadId\": \"<optional>\", \"bestEffort\": <optional-bool> }\n - Default for isolated agentTurn jobs (when delivery omitted): \"announce\"\n - announce: send to chat channel (optional channel/to target)\n - threadId: chat thread/topic id for channels that support threaded delivery\n - webhook: send finished-run event as HTTP POST to delivery.to (URL required)\n - If the task needs to send to a specific chat/recipient, set announce delivery.channel/to; do not call messaging tools inside the run.\n\nCRITICAL CONSTRAINTS:\n- sessionTarget=\"main\" REQUIRES payload.kind=\"systemEvent\"\n- sessionTarget=\"isolated\" | \"current\" | \"session:xxx\" REQUIRES payload.kind=\"agentTurn\"\n- For webhook callbacks, use delivery.mode=\"webhook\" with delivery.to set to a URL.\nDefault: prefer isolated agentTurn jobs unless the user explicitly wants current-session binding.\n\nRESTRICTED CRON RUNS:\n- Some isolated cron runs receive a narrow cron grant for self-cleanup. In that mode, read-only status and list are for self-introspection only, get/runs are allowed for the current job only, and mutation actions remain limited to removing the current cron job.\n\nWAKE MODES (for wake action):\n- \"next-heartbeat\" (default): Wake on next heartbeat\n- \"now\": Wake immediately\n\nUse jobId as the canonical identifier; id is accepted for compatibility. Use contextMessages (0-10) to add previous messages as context to the job text.","parameters":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["status","list","get","add","update","remove","run","runs","wake"]},"gatewayUrl":{"type":"string"},"gatewayToken":{"type":"string"},"timeoutMs":{"type":"number"},"includeDisabled":{"type":"boolean"},"job":{"type":"object","properties":{"name":{"type":"string","description":"Job name"},"schedule":{"type":"object","properties":{"kind":{"type":"string","enum":["at","every","cron"],"description":"Schedule type"},"at":{"type":"string","description":"ISO-8601 timestamp (kind=at)"},"everyMs":{"type":"number","description":"Interval in milliseconds (kind=every)"},"anchorMs":{"type":"number","description":"Optional start anchor in milliseconds (kind=every)"},"expr":{"type":"string","description":"Cron expression (kind=cron) written in the supplied tz's local wall-clock time, or the Gateway host local timezone when tz is omitted; do not convert the requested local time to UTC first. Example: 6pm Shanghai daily is \"0 18 * * *\" with tz \"Asia/Shanghai\"."},"tz":{"type":"string","description":"IANA timezone for interpreting cron wall-clock fields (kind=cron), e.g. \"Asia/Shanghai\"; if omitted, cron uses the Gateway host local timezone."},"staggerMs":{"type":"number","description":"Random jitter in ms (kind=cron)"}},"additionalProperties":true},"sessionTarget":{"type":"string","description":"Session target: \"main\", \"isolated\", \"current\", or \"session:<id>\""},"wakeMode":{"type":"string","enum":["now","next-heartbeat"],"description":"When to wake the session"},"payload":{"type":"object","properties":{"kind":{"type":"string","enum":["systemEvent","agentTurn"],"description":"Payload type"},"text":{"type":"string","description":"Message text (kind=systemEvent)"},"message":{"type":"string","description":"Agent prompt (kind=agentTurn)"},"model":{"type":"string","description":"Model override"},"thinking":{"type":"string","description":"Thinking level override"},"timeoutSeconds":{"type":"number"},"lightContext":{"type":"boolean"},"allowUnsafeExternalContent":{"type":"boolean"},"fallbacks":{"type":"array","items":{"type":"string"},"description":"Fallback model ids"},"toolsAllow":{"type":"array","items":{"type":"string"},"description":"Allowed tool ids"}},"additionalProperties":true},"delivery":{"type":"object","properties":{"mode":{"type":"string","enum":["none","announce","webhook"],"description":"Delivery mode"},"channel":{"type":"string","description":"Delivery channel"},"to":{"type":"string","description":"Delivery target"},"threadId":{"anyOf":[{"type":"string"},{"type":"number"}],"description":"Thread/topic id for channels that support threaded delivery"},"bestEffort":{"type":"boolean"},"accountId":{"type":"string","description":"Account target for delivery"},"failureDestination":{"type":"object","properties":{"channel":{"type":"string"},"to":{"type":"string"},"accountId":{"type":"string"},"mode":{"type":"string","enum":["announce","webhook"]}},"additionalProperties":true}},"additionalProperties":true},"agentId":{"type":"string","description":"Agent id, or null to keep it unset"},"description":{"type":"string","description":"Human-readable description"},"enabled":{"type":"boolean"},"deleteAfterRun":{"type":"boolean","description":"Delete after first execution"},"sessionKey":{"type":"string","description":"Explicit session key, or null to clear it"},"failureAlert":{"type":"object","properties":{"after":{"type":"number","description":"Failures before alerting"},"channel":{"type":"string","description":"Alert channel"},"to":{"type":"string","description":"Alert target"},"cooldownMs":{"type":"number","description":"Cooldown between alerts in ms"},"includeSkipped":{"type":"boolean","description":"Count consecutive skipped runs toward alerting"},"mode":{"type":"string","enum":["announce","webhook"]},"accountId":{"type":"string"}},"additionalProperties":true,"description":"Failure alert config object, or the boolean value false to disable alerts for this job"}},"additionalProperties":true},"jobId":{"type":"string"},"id":{"type":"string"},"patch":{"type":"object","properties":{"name":{"type":"string","description":"Job name"},"schedule":{"type":"object","properties":{"kind":{"type":"string","enum":["at","every","cron"],"description":"Schedule type"},"at":{"type":"string","description":"ISO-8601 timestamp (kind=at)"},"everyMs":{"type":"number","description":"Interval in milliseconds (kind=every)"},"anchorMs":{"type":"number","description":"Optional start anchor in milliseconds (kind=every)"},"expr":{"type":"string","description":"Cron expression (kind=cron) written in the supplied tz's local wall-clock time, or the Gateway host local timezone when tz is omitted; do not convert the requested local time to UTC first. Example: 6pm Shanghai daily is \"0 18 * * *\" with tz \"Asia/Shanghai\"."},"tz":{"type":"string","description":"IANA timezone for interpreting cron wall-clock fields (kind=cron), e.g. \"Asia/Shanghai\"; if omitted, cron uses the Gateway host local timezone."},"staggerMs":{"type":"number","description":"Random jitter in ms (kind=cron)"}},"additionalProperties":true},"sessionTarget":{"type":"string","description":"Session target"},"wakeMode":{"type":"string","enum":["now","next-heartbeat"]},"payload":{"type":"object","properties":{"kind":{"type":"string","enum":["systemEvent","agentTurn"],"description":"Payload type"},"text":{"type":"string","description":"Message text (kind=systemEvent)"},"message":{"type":"string","description":"Agent prompt (kind=agentTurn)"},"model":{"type":"string","description":"Model override"},"thinking":{"type":"string","description":"Thinking level override"},"timeoutSeconds":{"type":"number"},"lightContext":{"type":"boolean"},"allowUnsafeExternalContent":{"type":"boolean"},"fallbacks":{"type":"array","items":{"type":"string"},"description":"Fallback model ids"},"toolsAllow":{"type":"array","items":{"type":"string"},"description":"Allowed tool ids, or null to clear"}},"additionalProperties":true},"delivery":{"type":"object","properties":{"mode":{"type":"string","enum":["none","announce","webhook"],"description":"Delivery mode"},"channel":{"type":"string","description":"Delivery channel"},"to":{"type":"string","description":"Delivery target"},"threadId":{"anyOf":[{"type":"string"},{"type":"number"}],"description":"Thread/topic id for channels that support threaded delivery"},"bestEffort":{"type":"boolean"},"accountId":{"type":"string","description":"Account target for delivery"},"failureDestination":{"type":"object","properties":{"channel":{"type":"string"},"to":{"type":"string"},"accountId":{"type":"string"},"mode":{"type":"string","enum":["announce","webhook"]}},"additionalProperties":true}},"additionalProperties":true},"description":{"type":"string"},"enabled":{"type":"boolean"},"deleteAfterRun":{"type":"boolean"},"agentId":{"type":"string","description":"Agent id, or null to clear it"},"sessionKey":{"type":"string","description":"Explicit session key, or null to clear it"},"failureAlert":{"type":"object","properties":{"after":{"type":"number","description":"Failures before alerting"},"channel":{"type":"string","description":"Alert channel"},"to":{"type":"string","description":"Alert target"},"cooldownMs":{"type":"number","description":"Cooldown between alerts in ms"},"includeSkipped":{"type":"boolean","description":"Count consecutive skipped runs toward alerting"},"mode":{"type":"string","enum":["announce","webhook"]},"accountId":{"type":"string"}},"additionalProperties":true,"description":"Failure alert config object, or the boolean value false to disable alerts for this job"}},"additionalProperties":true},"text":{"type":"string"},"mode":{"type":"string","enum":["now","next-heartbeat"]},"runMode":{"type":"string","enum":["due","force"]},"contextMessages":{"type":"number","minimum":0,"maximum":10},"agentId":{"type":"string","description":"Filter by agent id (list action)"}},"additionalProperties":true}}},{"type":"function","function":{"name":"edit","description":"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.","parameters":{"type":"object","required":["path","edits"],"properties":{"path":{"type":"string","description":"Path to the file to edit (relative or absolute)"},"edits":{"type":"array","items":{"type":"object","required":["oldText","newText"],"properties":{"oldText":{"type":"string","description":"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call."},"newText":{"type":"string","description":"Replacement text for this targeted edit."}},"additionalProperties":false},"description":"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead."}},"additionalProperties":false}}},{"type":"function","function":{"name":"exec","description":"Execute shell commands with background continuation for work that starts now. Use yieldMs/background to continue later via process tool. For long-running work started now, rely on automatic completion wake when it is enabled and the command emits output or fails; otherwise use process to confirm completion. Use process whenever you need logs, status, input, or intervention. Do not use exec sleep or delay loops for reminders or deferred follow-ups; use cron instead. Use pty=true for TTY-required commands (terminal UIs, coding agents).","parameters":{"type":"object","required":["command"],"properties":{"command":{"type":"string","description":"Shell command to execute"},"workdir":{"type":"string","description":"Working directory (defaults to cwd)"},"env":{"type":"object","patternProperties":{"^.*$":{"type":"string"}}},"yieldMs":{"type":"number","description":"Milliseconds to wait before backgrounding (default 10000)"},"background":{"type":"boolean","description":"Run in background immediately"},"timeout":{"type":"number","description":"Timeout in seconds (optional, kills process on expiry)"},"pty":{"type":"boolean","description":"Run in a pseudo-terminal (PTY) when available (TTY-required CLIs, coding agents)"},"elevated":{"type":"boolean","description":"Run on the host with elevated permissions (if allowed)"},"host":{"type":"string","enum":["auto","sandbox","gateway","node"],"description":"Exec host/target (auto|sandbox|gateway|node)."},"security":{"type":"string","description":"Ignored for normal calls; exec security is set by tools.exec.security and host approvals."},"ask":{"type":"string","description":"Exec ask mode (off|on-miss|always)."},"node":{"type":"string","description":"Node id/name for host=node."}}}}},{"type":"function","function":{"name":"image","description":"Analyze one or more images with a vision model. Use image for a single path/URL, or images for multiple (up to 20). Only use this tool when images were NOT already provided in the user's message. Images mentioned in the prompt are automatically visible to you.","parameters":{"type":"object","properties":{"prompt":{"type":"string"},"image":{"type":"string","description":"Single image path or URL."},"images":{"type":"array","items":{"type":"string"},"description":"Multiple image paths or URLs (up to maxImages, default 20)."},"model":{"type":"string"},"maxBytesMb":{"type":"number"},"maxImages":{"type":"number"}}}}},{"type":"function","function":{"name":"image_generate","description":"Generate new images or edit reference images with the configured or inferred image-generation model. For transparent backgrounds, use outputFormat=\"png\" or \"webp\" and background=\"transparent\"; OpenAI also accepts openai.background and OpenClaw routes the default OpenAI image model to gpt-image-1.5 for that mode. Set agents.defaults.imageGenerationModel.primary to pick a provider/model. Providers declare their own auth/readiness; use action=\"list\" to inspect registered providers, models, readiness, and auth hints. Generated images are delivered automatically from the tool result as MEDIA paths.","parameters":{"type":"object","properties":{"action":{"type":"string","description":"Optional action: \"generate\" (default) or \"list\" to inspect available providers/models."},"prompt":{"type":"string","description":"Image generation prompt."},"image":{"type":"string","description":"Optional reference image path or URL for edit mode."},"images":{"type":"array","items":{"type":"string"},"description":"Optional reference images for edit mode (up to 5)."},"model":{"type":"string","description":"Optional provider/model override, e.g. openai/gpt-image-2; use openai/gpt-image-1.5 for transparent OpenAI backgrounds."},"filename":{"type":"string","description":"Optional output filename hint. OpenClaw preserves the basename and saves under its managed media directory."},"size":{"type":"string","description":"Optional size hint like 1024x1024, 1536x1024, 1024x1536, 2048x2048, or 3840x2160."},"aspectRatio":{"type":"string","description":"Optional aspect ratio hint: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, or 21:9."},"resolution":{"type":"string","description":"Optional resolution hint: 1K, 2K, or 4K. Useful for Google edit/generation flows."},"quality":{"type":"string","enum":["low","medium","high","auto"],"description":"Optional quality hint: low, medium, high, or auto when the provider supports it."},"outputFormat":{"type":"string","enum":["png","jpeg","webp"],"description":"Optional output format hint: png, jpeg, or webp when the provider supports it."},"background":{"type":"string","enum":["transparent","opaque","auto"],"description":"Optional background hint: transparent, opaque, or auto when the provider supports it. For transparent output use outputFormat png or webp."},"openai":{"type":"object","properties":{"background":{"type":"string","enum":["transparent","opaque","auto"],"description":"OpenAI-only background hint: transparent, opaque, or auto. For transparent output use outputFormat png or webp; OpenClaw routes the default OpenAI image model to gpt-image-1.5 for this mode."},"moderation":{"type":"string","enum":["low","auto"],"description":"OpenAI-only moderation hint: low or auto."},"outputCompression":{"type":"number","description":"OpenAI-only compression level for jpeg/webp outputFormat, 0-100.","minimum":0,"maximum":100},"user":{"type":"string","description":"OpenAI-only stable end-user identifier for abuse monitoring."}}},"count":{"type":"number","description":"Optional number of images to request (1-4).","minimum":1,"maximum":4},"timeoutMs":{"type":"number","description":"Optional provider request timeout in milliseconds.","minimum":1}}}}},{"type":"function","function":{"name":"lcm_describe","description":"Look up metadata and content for an LCM item by ID. Use this to inspect summaries (sum_xxx) or stored files (file_xxx) from compacted conversation history. Returns summary content, lineage, token counts, and file exploration results.","parameters":{"type":"object","required":["id"],"properties":{"id":{"description":"The LCM ID to look up. Use sum_xxx for summaries, file_xxx for files.","type":"string"},"conversationId":{"description":"Conversation ID to scope describe lookups to. If omitted, uses the current session conversation.","type":"number"},"allConversations":{"description":"Set true to explicitly allow lookups across all conversations. Ignored when conversationId is provided.","type":"boolean"},"tokenCap":{"description":"Optional budget cap used for subtree manifest budget-fit annotations.","minimum":1,"type":"number"}}}}},{"type":"function","function":{"name":"lcm_expand","description":"Expand compacted conversation summaries from LCM (Lossless Context Management). Traverses the summary DAG to retrieve children and source messages. Use this to drill into previously-compacted context when you need detail that was summarised away. Provide either summaryIds (direct expansion) or query (grep-first, then expand top matches). Returns a compact text payload plus cited IDs in tool output for follow-up.","parameters":{"type":"object","properties":{"summaryIds":{"description":"Summary IDs to expand (sum_xxx format). Required if query is not provided.","type":"array","items":{"type":"string"}},"query":{"description":"Text query to grep for matching summaries before expanding. If provided, summaryIds is ignored and the top grep results are expanded.","type":"string"},"maxDepth":{"description":"Max traversal depth per summary (default: 3).","minimum":1,"type":"number"},"tokenCap":{"description":"Max tokens across the entire expansion result.","minimum":1,"type":"number"},"includeMessages":{"description":"Whether to include raw source messages at leaf level (default: false).","type":"boolean"},"conversationId":{"description":"Conversation ID to scope the expansion to. If omitted, uses the current session's conversation.","type":"number"},"allConversations":{"description":"Set true to explicitly allow cross-conversation expansion. Ignored when conversationId is provided.","type":"boolean"}}}}},{"type":"function","function":{"name":"lcm_expand_query","description":"Answer a focused natural-language question using delegated LCM expansion. Find candidate summaries (by IDs or a short FTS5 query that follows the same full-text rules as lcm_grep), expand them in a delegated sub-agent, and return a compact prompt-focused answer. Tool output includes cited summary IDs for follow-up.","parameters":{"type":"object","required":["prompt"],"properties":{"summaryIds":{"description":"Summary IDs to expand (sum_xxx). Required when query is not provided.","type":"array","items":{"type":"string"}},"query":{"description":"FTS5 query used to find summaries via the same full-text search path as lcm_grep before expansion. Use 1-3 distinctive terms or a quoted phrase; FTS5 defaults to AND matching, so extra terms make matches stricter. Required when summaryIds is not provided.","type":"string"},"prompt":{"description":"Natural-language question or task to answer using expanded context. Put the answer request here, not in query.","type":"string"},"conversationId":{"description":"Conversation ID to scope expansion to. If omitted, uses the current session conversation.","type":"number"},"allConversations":{"description":"Set true to explicitly allow cross-conversation lookup. Ignored when conversationId is provided.","type":"boolean"},"maxTokens":{"description":"Maximum answer tokens to target (default: 2000).","minimum":1,"type":"number"},"tokenCap":{"description":"Expansion retrieval token budget across all delegated lcm_expand calls for this query.","minimum":1,"type":"number"}}}}},{"type":"function","function":{"name":"lcm_grep","description":"Search compacted conversation history using regex or full-text search. Searches across messages and/or summaries stored by LCM. Use this to find specific content that may have been compacted away from active context. In full_text mode, queries use FTS5 AND semantics by default, so keep them short and focused; quoted phrases stay intact and optional sort modes can prioritize relevance for older topics. Returns matching snippets with their summary/message IDs for follow-up with lcm_expand or lcm_describe.","parameters":{"type":"object","required":["pattern"],"properties":{"pattern":{"description":"Search pattern. Interpreted as regex when mode is \"regex\", or as an FTS5 text query when mode is \"full_text\". In full_text mode, FTS5 defaults to AND matching, so prefer 1-3 distinctive terms or one quoted multi-word phrase instead of padding with synonyms or extra keywords.","type":"string"},"mode":{"description":"Search mode: \"regex\" for regular expression matching, \"full_text\" for text search. Default: \"regex\".","enum":["regex","full_text"],"type":"string"},"scope":{"description":"What to search: \"messages\" for raw messages, \"summaries\" for compacted summaries, \"both\" for all. Default: \"both\".","enum":["messages","summaries","both"],"type":"string"},"conversationId":{"description":"Conversation ID to search within. If omitted, defaults to the current session conversation.","type":"number"},"allConversations":{"description":"Set true to explicitly search across all conversations. Ignored when conversationId is provided.","type":"boolean"},"since":{"description":"Only return matches created at or after this ISO timestamp.","type":"string"},"before":{"description":"Only return matches created before this ISO timestamp.","type":"string"},"limit":{"description":"Maximum number of results to return (default: 50).","minimum":1,"maximum":200,"type":"number"},"sort":{"description":"Sort order: \"recency\" (newest first, default), \"relevance\" (best FTS5 match first, full_text mode only), or \"hybrid\" (full_text mode only; balances relevance with recency). Applied before limit is enforced.","enum":["recency","relevance","hybrid"],"type":"string"}}}}},{"type":"function","function":{"name":"memory_get","description":"Safe exact excerpt read from MEMORY.md or memory/*.md. Defaults to a bounded excerpt when lines are omitted, includes truncation/continuation info when more content exists, and `corpus=wiki` reads from registered compiled-wiki supplements.","parameters":{"type":"object","properties":{"path":{"type":"string"},"from":{"type":"number"},"lines":{"type":"number"},"corpus":{"type":"string","enum":["memory","wiki","all"]}},"required":["path"],"additionalProperties":false}}},{"type":"function","function":{"name":"memory_search","description":"Mandatory recall step: semantically search MEMORY.md + memory/*.md (and optional session transcripts) before answering questions about prior work, decisions, dates, people, preferences, or todos. Optional `corpus=wiki` or `corpus=all` also searches registered compiled-wiki supplements. `corpus=memory` restricts hits to indexed memory files (excludes session transcript chunks from ranking). `corpus=sessions` restricts hits to indexed session transcripts (same visibility rules as session history tools). If response has disabled=true, memory retrieval is unavailable and should be surfaced to the user.","parameters":{"type":"object","properties":{"query":{"type":"string"},"maxResults":{"type":"number"},"minScore":{"type":"number"},"corpus":{"type":"string","enum":["memory","wiki","all","sessions"]}},"required":["query"],"additionalProperties":false}}},{"type":"function","function":{"name":"music_generate","description":"Generate music using configured providers. Generated tracks are saved under OpenClaw-managed media storage and delivered automatically as attachments.","parameters":{"type":"object","properties":{"action":{"type":"string","description":"Optional action: \"generate\" (default), \"status\" to inspect the active session task, or \"list\" to inspect available providers/models."},"prompt":{"type":"string","description":"Music generation prompt."},"lyrics":{"type":"string","description":"Optional lyrics to guide sung output when the provider supports it."},"instrumental":{"type":"boolean","description":"Optional toggle for instrumental-only output when the provider supports it."},"image":{"type":"string","description":"Optional single reference image path or URL."},"images":{"type":"array","items":{"type":"string"},"description":"Optional reference images (up to 10)."},"model":{"type":"string","description":"Optional provider/model override, e.g. google/lyria-3-pro-preview."},"durationSeconds":{"type":"number","description":"Optional target duration in seconds when the provider supports duration hints.","minimum":1},"timeoutMs":{"type":"number","description":"Optional provider request timeout in milliseconds. Values below 10000ms are raised to 10000ms.","minimum":1},"format":{"type":"string","description":"Optional output format hint: \"mp3\" or \"wav\" when the provider supports it."},"filename":{"type":"string","description":"Optional output filename hint. OpenClaw preserves the basename and saves under its managed media directory."}}}}},{"type":"function","function":{"name":"process","description":"Manage running exec sessions for commands already started: list, poll, log, write, send-keys, submit, paste, kill. Use poll/log when you need status, logs, quiet-success confirmation, or completion confirmation when automatic completion wake is unavailable. Use poll/log also for input-wait hints. Use write/send-keys/submit/paste/kill for input or intervention. Do not use process polling to emulate timers or reminders; use cron for scheduled follow-ups.","parameters":{"type":"object","required":["action"],"properties":{"action":{"type":"string","description":"Process action (list|poll|log|write|send-keys|submit|paste|kill|clear|remove)"},"sessionId":{"type":"string","description":"Session id for actions other than list"},"data":{"type":"string","description":"Data to write for write"},"keys":{"type":"array","items":{"type":"string"},"description":"Key tokens to send for send-keys"},"hex":{"type":"array","items":{"type":"string"},"description":"Hex bytes to send for send-keys"},"literal":{"type":"string","description":"Literal string for send-keys"},"text":{"type":"string","description":"Text to paste for paste"},"bracketed":{"type":"boolean","description":"Wrap paste in bracketed mode"},"eof":{"type":"boolean","description":"Close stdin after write"},"offset":{"type":"number","description":"Log offset"},"limit":{"type":"number","description":"Log length"},"timeout":{"type":"number","description":"For poll: wait up to this many milliseconds before returning; max 30000 ms, higher values are clamped to 30000","minimum":0}}}}},{"type":"function","function":{"name":"read","description":"Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to 2000 lines or 50KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.","parameters":{"type":"object","required":["path"],"properties":{"path":{"type":"string","description":"Path to the file to read (relative or absolute)"},"offset":{"type":"number","description":"Line number to start reading from (1-indexed)"},"limit":{"type":"number","description":"Maximum number of lines to read"}}}}},{"type":"function","function":{"name":"session_status","description":"Show a /status-equivalent session status card for the current or another visible session, including usage, time, cost when available, and linked background task context. Use `sessionKey=\"current\"` for the current session; do not use UI/client labels such as `openclaw-tui` as session keys. Optional `model` sets a per-session model override; `model=default` resets overrides. Use this for questions like what model is active or how a session is configured.","parameters":{"type":"object","properties":{"sessionKey":{"type":"string"},"model":{"type":"string"}}}}},{"type":"function","function":{"name":"sessions_history","description":"Fetch sanitized message history for a visible session. Supports limits and optional tool messages; use this to inspect another session before replying, debugging, or resuming work.","parameters":{"type":"object","required":["sessionKey"],"properties":{"sessionKey":{"type":"string"},"limit":{"type":"number","minimum":1},"includeTools":{"type":"boolean"}}}}},{"type":"function","function":{"name":"sessions_list","description":"List visible sessions with optional filters for kind, label, agentId, search, recent activity, derived titles, and last-message previews. Use this to discover a target session before calling sessions_history or sessions_send.","parameters":{"type":"object","properties":{"kinds":{"type":"array","items":{"type":"string"}},"limit":{"type":"number","minimum":1},"activeMinutes":{"type":"number","minimum":1},"messageLimit":{"type":"number","minimum":0},"label":{"type":"string","minLength":1},"agentId":{"type":"string","minLength":1,"maxLength":64},"search":{"type":"string","minLength":1},"includeDerivedTitles":{"type":"boolean"},"includeLastMessage":{"type":"boolean"}}}}},{"type":"function","function":{"name":"sessions_send","description":"Send a message into another visible session by sessionKey or label. Thread-scoped chat sessions are rejected; target the parent channel session for inter-agent coordination. Use this to delegate follow-up work to an existing session; waits for the target run and returns the updated assistant reply when available.","parameters":{"type":"object","required":["message"],"properties":{"sessionKey":{"type":"string"},"label":{"type":"string","minLength":1,"maxLength":512},"agentId":{"type":"string","minLength":1,"maxLength":64},"message":{"type":"string"},"timeoutSeconds":{"type":"number","minimum":0}}}}},{"type":"function","function":{"name":"sessions_spawn","description":"Spawn a clean isolated session by default with the native subagent runtime. `mode=\"run\"` is one-shot background work. Subagents inherit the parent workspace directory automatically. For native subagents only, set `context=\"fork\"` when the child needs the current transcript context; otherwise omit it or use `context=\"isolated\"`. Use this when the work should happen in a fresh child session instead of the current one.","parameters":{"type":"object","required":["task"],"properties":{"task":{"type":"string"},"taskName":{"type":"string","description":"Stable optional alias for later subagents targeting. Use lowercase letters, digits, and underscores, starting with a letter."},"label":{"type":"string"},"runtime":{"type":"string","enum":["subagent"]},"agentId":{"type":"string"},"model":{"type":"string"},"thinking":{"type":"string"},"cwd":{"type":"string"},"runTimeoutSeconds":{"type":"number","minimum":0},"timeoutSeconds":{"type":"number","minimum":0},"mode":{"type":"string","enum":["run"]},"cleanup":{"type":"string","enum":["delete","keep"]},"sandbox":{"type":"string","enum":["inherit","require"]},"context":{"type":"string","enum":["isolated","fork"],"description":"Native subagent context mode. Omit or use \"isolated\" for a clean child session; use \"fork\" only when the child needs the requester transcript context."},"lightContext":{"type":"boolean","description":"When true, spawned subagent runs use lightweight bootstrap context. Only applies to runtime='subagent'."},"attachments":{"type":"array","items":{"type":"object","required":["name","content"],"properties":{"name":{"type":"string"},"content":{"type":"string"},"encoding":{"type":"string","enum":["utf8","base64"]},"mimeType":{"type":"string"}}},"maxItems":50},"attachAs":{"type":"object","properties":{"mountPath":{"type":"string"}}}}}}},{"type":"function","function":{"name":"sessions_yield","description":"End your current turn. Use after spawning subagents to receive their results as the next message.","parameters":{"type":"object","properties":{"message":{"type":"string"}}}}},{"type":"function","function":{"name":"subagents","description":"On-demand list, kill, or steer spawned sub-agents for this requester session. If sessions_yield is available, use it to wait for completion events; do not poll this tool in wait loops.","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","kill","steer"]},"target":{"type":"string"},"message":{"type":"string"},"recentMinutes":{"type":"number","minimum":1}}}}},{"type":"function","function":{"name":"update_plan","description":"Update the current structured work plan for this run. Use this for non-trivial multi-step work so the plan stays current while execution continues. Keep steps short, mark at most one step as `in_progress`, and skip this tool for simple one-step tasks.","parameters":{"type":"object","required":["plan"],"properties":{"explanation":{"type":"string","description":"Optional short note explaining what changed in the plan."},"plan":{"type":"array","items":{"type":"object","required":["step","status"],"properties":{"step":{"type":"string","description":"Short plan step."},"status":{"type":"string","enum":["pending","in_progress","completed"],"description":"One of \"pending\", \"in_progress\", or \"completed\"."}},"additionalProperties":true},"minItems":1,"description":"Ordered list of plan steps. At most one step may be in_progress."}}}}},{"type":"function","function":{"name":"video_generate","description":"Generate videos using configured providers. Generated videos are saved under OpenClaw-managed media storage and delivered automatically as attachments. Duration requests may be rounded to the nearest provider-supported value.","parameters":{"type":"object","properties":{"action":{"type":"string","description":"Optional action: \"generate\" (default), \"status\" to inspect the active session task, or \"list\" to inspect available providers/models."},"prompt":{"type":"string","description":"Video generation prompt."},"image":{"type":"string","description":"Optional single reference image path or URL."},"images":{"type":"array","items":{"type":"string"},"description":"Optional reference images (up to 9)."},"imageRoles":{"type":"array","items":{"type":"string"},"description":"Optional semantic roles for the combined reference image list, parallel by index. The list is `image` (if provided) followed by each entry in `images`, in order, after de-duplication. Canonical values: \"first_frame\", \"last_frame\", \"reference_image\". Providers may accept additional role strings. Must not have more entries than the combined image list; use an empty string to leave a position unset."},"video":{"type":"string","description":"Optional single reference video path or URL."},"videos":{"type":"array","items":{"type":"string"},"description":"Optional reference videos (up to 4)."},"videoRoles":{"type":"array","items":{"type":"string"},"description":"Optional semantic roles for the combined reference video list, parallel by index. The list is `video` (if provided) followed by each entry in `videos`, in order, after de-duplication. Canonical value: \"reference_video\". Providers may accept additional role strings. Must not have more entries than the combined video list; use an empty string to leave a position unset."},"audioRef":{"type":"string","description":"Optional single reference audio path or URL (e.g. background music)."},"audioRefs":{"type":"array","items":{"type":"string"},"description":"Optional reference audios (up to 3)."},"audioRoles":{"type":"array","items":{"type":"string"},"description":"Optional semantic roles for the combined reference audio list, parallel by index. The list is `audioRef` (if provided) followed by each entry in `audioRefs`, in order, after de-duplication. Canonical value: \"reference_audio\". Providers may accept additional role strings. Must not have more entries than the combined audio list; use an empty string to leave a position unset."},"model":{"type":"string","description":"Optional provider/model override, e.g. qwen/wan2.6-t2v."},"filename":{"type":"string","description":"Optional output filename hint. OpenClaw preserves the basename and saves under its managed media directory."},"size":{"type":"string","description":"Optional size hint like 1280x720 or 1920x1080 when the provider supports it."},"aspectRatio":{"type":"string","description":"Optional aspect ratio hint such as 1:1, 16:9, 9:16, \"adaptive\", or a provider-specific value. OpenClaw normalizes or ignores unsupported values per provider."},"resolution":{"type":"string","description":"Optional resolution hint such as 480P, 720P, 768P, 1080P, 4K, or a provider-specific value. OpenClaw normalizes or ignores unsupported values per provider."},"durationSeconds":{"type":"number","description":"Optional target duration in seconds. OpenClaw may round this to the nearest provider-supported duration.","minimum":1},"audio":{"type":"boolean","description":"Optional audio toggle when the provider supports generated audio."},"watermark":{"type":"boolean","description":"Optional watermark toggle when the provider supports it."},"providerOptions":{"type":"object","patternProperties":{"^.*$":{}},"description":"Optional provider-specific options as a JSON object, e.g. `{\"seed\": 42, \"draft\": true}`. Each provider declares its own accepted keys and primitive types (number/boolean/string) via its capabilities; unknown keys or type mismatches skip the candidate during fallback and never silently reach the wrong provider. Run `video_generate action=list` to see which keys each provider accepts."},"timeoutMs":{"type":"number","description":"Optional provider request timeout in milliseconds.","minimum":1}}}}},{"type":"function","function":{"name":"web_fetch","description":"Fetch and extract readable content from a URL (HTML → markdown/text). Use for lightweight page access without browser automation.","parameters":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"HTTP or HTTPS URL to fetch."},"extractMode":{"type":"string","enum":["markdown","text"],"description":"Extraction mode (\"markdown\" or \"text\").","default":"markdown"},"maxChars":{"type":"number","description":"Maximum characters to return (truncates when exceeded).","minimum":100}}}}},{"type":"function","function":{"name":"wiki_apply","description":"Apply narrow wiki mutations for syntheses and page metadata without freeform markdown surgery.","parameters":{"type":"object","required":["op"],"properties":{"op":{"anyOf":[{"type":"string","const":"create_synthesis"},{"type":"string","const":"update_metadata"}]},"title":{"type":"string","minLength":1},"body":{"type":"string","minLength":1},"lookup":{"type":"string","minLength":1},"sourceIds":{"type":"array","items":{"type":"string","minLength":1}},"claims":{"type":"array","items":{"type":"object","required":["text"],"properties":{"id":{"type":"string","minLength":1},"text":{"type":"string","minLength":1},"status":{"type":"string","minLength":1},"confidence":{"type":"number","minimum":0,"maximum":1},"evidence":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","minLength":1},"sourceId":{"type":"string","minLength":1},"path":{"type":"string","minLength":1},"lines":{"type":"string","minLength":1},"weight":{"type":"number","minimum":0},"note":{"type":"string","minLength":1},"confidence":{"type":"number","minimum":0,"maximum":1},"privacyTier":{"type":"string","minLength":1},"updatedAt":{"type":"string","minLength":1}},"additionalProperties":false}},"updatedAt":{"type":"string","minLength":1}},"additionalProperties":false}},"contradictions":{"type":"array","items":{"type":"string","minLength":1}},"questions":{"type":"array","items":{"type":"string","minLength":1}},"confidence":{"anyOf":[{"type":"number","minimum":0,"maximum":1},{"type":"null"}]},"status":{"type":"string","minLength":1}},"additionalProperties":false}}},{"type":"function","function":{"name":"wiki_get","description":"Read a wiki page by id or relative path, or fall back to the active memory corpus when shared search is enabled.","parameters":{"type":"object","required":["lookup"],"properties":{"lookup":{"type":"string","minLength":1},"fromLine":{"type":"number","minimum":1},"lineCount":{"type":"number","minimum":1},"backend":{"anyOf":[{"type":"string","const":"shared"},{"type":"string","const":"local"}]},"corpus":{"anyOf":[{"type":"string","const":"wiki"},{"type":"string","const":"memory"},{"type":"string","const":"all"}]}},"additionalProperties":false}}},{"type":"function","function":{"name":"wiki_lint","description":"Lint the wiki vault and surface structural issues, provenance gaps, contradictions, and open questions.","parameters":{"type":"object","properties":{},"additionalProperties":false}}},{"type":"function","function":{"name":"wiki_search","description":"Search wiki pages and, when shared search is enabled, the active memory corpus by title, path, id, or body text.","parameters":{"type":"object","required":["query"],"properties":{"query":{"type":"string","minLength":1},"maxResults":{"type":"number","minimum":1},"backend":{"anyOf":[{"type":"string","const":"shared"},{"type":"string","const":"local"}]},"corpus":{"anyOf":[{"type":"string","const":"wiki"},{"type":"string","const":"memory"},{"type":"string","const":"all"}]},"mode":{"anyOf":[{"type":"string","const":"auto"},{"type":"string","const":"find-person"},{"type":"string","const":"route-question"},{"type":"string","const":"source-evidence"},{"type":"string","const":"raw-claim"}]}},"additionalProperties":false}}},{"type":"function","function":{"name":"wiki_status","description":"Inspect the current memory wiki vault mode, health, and Obsidian CLI availability.","parameters":{"type":"object","properties":{},"additionalProperties":false}}},{"type":"function","function":{"name":"write","description":"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.","parameters":{"type":"object","required":["path","content"],"properties":{"path":{"type":"string","description":"Path to the file to write (relative or absolute)"},"content":{"type":"string","description":"Content to write to the file"}}}}}]
1
+ [{"type":"function","function":{"name":"browser","description":"Control the browser via OpenClaw's browser control server (status/start/stop/profiles/tabs/open/snapshot/screenshot/actions). Browser choice: omit profile by default for the isolated OpenClaw-managed browser (`openclaw`). For the logged-in user browser, use profile=\"user\". A supported Chromium-based browser (v144+) must be running on the selected host or browser node. Use only when existing logins/cookies matter and the user is present. For profile=\"user\" or other existing-session profiles, omit timeoutMs on act:type, evaluate, hover, scrollIntoView, drag, select, and fill; that driver rejects per-call timeout overrides for those actions. When a node-hosted browser proxy is available, the tool may auto-route to it. Pin a node with node=<id|name> or target=\"node\". When using refs from snapshot (e.g. e12), keep the same tab: prefer passing targetId from the snapshot response into subsequent actions (act/click/type/etc). For tab operations, targetId also accepts tabId handles (t1) and labels from action=tabs. For multi-step browser work, login checks, stale refs, duplicate tabs, or Google Meet flows, use the bundled browser-automation skill when it is available. For stable, self-resolving refs across calls, use snapshot with refs=\"aria\" (Playwright aria-ref ids). Default refs=\"role\" are role+name-based. Use snapshot+act for UI automation. Avoid act:wait by default; use only in exceptional cases when no reliable UI state exists. target selects browser location (sandbox|host|node). Default: host. Host target allowed.","parameters":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["doctor","status","start","stop","profiles","tabs","open","focus","close","snapshot","screenshot","navigate","console","pdf","upload","dialog","act"]},"target":{"type":"string","enum":["sandbox","host","node"]},"node":{"type":"string"},"profile":{"type":"string"},"targetUrl":{"type":"string"},"url":{"type":"string"},"targetId":{"type":"string"},"label":{"type":"string"},"limit":{"type":"number"},"maxChars":{"type":"number"},"mode":{"type":"string","enum":["efficient"]},"snapshotFormat":{"type":"string","enum":["aria","ai"]},"refs":{"type":"string","enum":["role","aria"]},"interactive":{"type":"boolean"},"compact":{"type":"boolean"},"depth":{"type":"number"},"selector":{"type":"string"},"frame":{"type":"string"},"labels":{"type":"boolean"},"urls":{"type":"boolean"},"fullPage":{"type":"boolean"},"ref":{"type":"string"},"element":{"type":"string"},"type":{"type":"string","enum":["png","jpeg"]},"level":{"type":"string"},"paths":{"type":"array","items":{"type":"string"}},"inputRef":{"type":"string"},"timeoutMs":{"type":"number"},"dialogId":{"type":"string"},"accept":{"type":"boolean"},"promptText":{"type":"string"},"kind":{"type":"string","enum":["click","clickCoords","type","press","hover","drag","select","fill","resize","wait","evaluate","close"]},"doubleClick":{"type":"boolean"},"button":{"type":"string"},"modifiers":{"type":"array","items":{"type":"string"}},"x":{"type":"number"},"y":{"type":"number"},"text":{"type":"string"},"submit":{"type":"boolean"},"slowly":{"type":"boolean"},"key":{"type":"string"},"delayMs":{"type":"number"},"startRef":{"type":"string"},"endRef":{"type":"string"},"values":{"type":"array","items":{"type":"string"}},"fields":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"width":{"type":"number"},"height":{"type":"number"},"timeMs":{"type":"number"},"textGone":{"type":"string"},"loadState":{"type":"string"},"fn":{"type":"string"},"request":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["click","clickCoords","type","press","hover","drag","select","fill","resize","wait","evaluate","close"]},"targetId":{"type":"string"},"ref":{"type":"string"},"doubleClick":{"type":"boolean"},"button":{"type":"string"},"modifiers":{"type":"array","items":{"type":"string"}},"x":{"type":"number"},"y":{"type":"number"},"text":{"type":"string"},"submit":{"type":"boolean"},"slowly":{"type":"boolean"},"key":{"type":"string"},"delayMs":{"type":"number"},"startRef":{"type":"string"},"endRef":{"type":"string"},"values":{"type":"array","items":{"type":"string"}},"fields":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"width":{"type":"number"},"height":{"type":"number"},"timeMs":{"type":"number"},"selector":{"type":"string"},"url":{"type":"string"},"loadState":{"type":"string"},"textGone":{"type":"string"},"timeoutMs":{"type":"number"},"fn":{"type":"string"}}}}}}},{"type":"function","function":{"name":"cron","description":"Manage Gateway cron jobs and wake events: reminders, check-back-later, delayed follow-ups, recurring work. Do not emulate scheduling with exec sleep/process polling.\n\nMain cron => system events for heartbeat. Isolated cron => background task in `openclaw tasks`.\n\nACTIONS:\n- status: scheduler status\n- list: jobs; includeDisabled true includes disabled; agentId filter auto-filled from session\n- get: one job; needs jobId\n- add: create job; needs job object\n- update: patch job; needs jobId + patch\n- remove: delete job; needs jobId\n- run: trigger now; needs jobId\n- runs: run history; needs jobId\n- wake: send wake event; needs text, optional mode\n\nJOB SCHEMA (for add action):\n{\n \"name\": \"string\",\n \"schedule\": { ... }, // required\n \"payload\": { ... }, // required\n \"delivery\": { ... }, // optional announce for isolated/current/session, webhook for any target\n \"sessionTarget\": \"main\" | \"isolated\" | \"current\" | \"session:<id>\",\n \"enabled\": true | false // default true\n}\n\nSESSION TARGET OPTIONS:\n- \"main\": main session; requires payload.kind=\"systemEvent\"\n- \"isolated\": ephemeral isolated session; requires payload.kind=\"agentTurn\"\n- \"current\": bind current session at creation\n- \"session:<id>\": persistent named session\n\nDEFAULTS:\n- payload.kind=\"systemEvent\" → defaults to \"main\"\n- payload.kind=\"agentTurn\" → defaults to \"isolated\"\nCurrent binding needs sessionTarget=\"current\".\n\nSCHEDULE TYPES (schedule.kind):\n- \"at\": one-shot absolute time\n { \"kind\": \"at\", \"at\": \"<ISO-8601 timestamp>\" }\n- \"every\": recurring interval\n { \"kind\": \"every\", \"everyMs\": <ms>, \"anchorMs\": <optional-ms> }\n- \"cron\": expr in supplied timezone, or Gateway host local timezone when tz omitted\n { \"kind\": \"cron\", \"expr\": \"<cron-expression>\", \"tz\": \"<optional-IANA-timezone>\" }\n Write expr in local wall-clock time; do not convert the requested local time to UTC first.\n tz omitted => Gateway host local timezone, not UTC.\n Example 6pm Shanghai daily: { \"kind\": \"cron\", \"expr\": \"0 18 * * *\", \"tz\": \"Asia/Shanghai\" }\n\nFor \"at\", ISO timestamps without timezone are UTC.\n\nPAYLOAD TYPES (payload.kind):\n- \"systemEvent\": inject text as system event\n { \"kind\": \"systemEvent\", \"text\": \"<message>\" }\n- \"agentTurn\": run agent with prompt; isolated/current/session only\n { \"kind\": \"agentTurn\", \"message\": \"<prompt>\", \"model\": \"<optional>\", \"thinking\": \"<optional>\", \"timeoutSeconds\": <optional, 0=no timeout> }\n\nDELIVERY (top-level):\n { \"mode\": \"none|announce|webhook\", \"channel\": \"<optional>\", \"to\": \"<optional>\", \"threadId\": \"<optional>\", \"bestEffort\": <optional-bool> }\n - isolated agentTurn default when omitted: \"announce\"\n - announce: send to chat channel; isolated/current/session only; optional channel/to\n - threadId: chat thread/topic id\n - webhook: POST finished-run event to delivery.to URL\n - Specific chat/recipient: set announce delivery.channel/to; do not call messaging tools inside run.\n\nCRITICAL CONSTRAINTS:\n- sessionTarget=\"main\" REQUIRES payload.kind=\"systemEvent\"\n- sessionTarget=\"isolated\" | \"current\" | \"session:xxx\" REQUIRES payload.kind=\"agentTurn\"\n- Webhook: delivery.mode=\"webhook\" and delivery.to URL.\nDefault: prefer isolated agentTurn jobs unless the user explicitly wants current-session binding.\n\nRESTRICTED CRON RUNS:\n- Some isolated cron runs get narrow self-cleanup grant: status/list self-only, get/runs current job only, mutation only remove current job.\n\nWAKE MODES (for wake action):\n- \"next-heartbeat\" default: wake next heartbeat\n- \"now\": wake immediately\n\nUse jobId canonical; id accepted compat. contextMessages (0-10) adds previous messages as job context.","parameters":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["status","list","get","add","update","remove","run","runs","wake"]},"gatewayUrl":{"type":"string"},"gatewayToken":{"type":"string"},"timeoutMs":{"type":"number"},"includeDisabled":{"type":"boolean"},"job":{"type":"object","properties":{"name":{"type":"string","description":"Job name"},"schedule":{"type":"object","properties":{"kind":{"type":"string","enum":["at","every","cron"],"description":"Schedule kind"},"at":{"type":"string","description":"ISO-8601 time (kind=at)"},"everyMs":{"type":"number","description":"Interval ms (kind=every)"},"anchorMs":{"type":"number","description":"Start anchor ms (kind=every)"},"expr":{"type":"string","description":"Cron expr in tz wall-clock time; do not convert to UTC. Omitted tz => Gateway host local timezone. Example 6pm Shanghai daily: expr \"0 18 * * *\", tz \"Asia/Shanghai\"."},"tz":{"type":"string","description":"IANA timezone for cron wall-clock fields, e.g. \"Asia/Shanghai\"; omitted => Gateway host local timezone."},"staggerMs":{"type":"number","description":"Jitter ms (kind=cron)"}},"additionalProperties":true},"sessionTarget":{"type":"string","description":"main | isolated | current | session:<id>"},"wakeMode":{"type":"string","enum":["now","next-heartbeat"],"description":"Wake timing"},"payload":{"type":"object","properties":{"kind":{"type":"string","enum":["systemEvent","agentTurn"],"description":"Payload kind"},"text":{"type":"string","description":"systemEvent text"},"message":{"type":"string","description":"agentTurn prompt"},"model":{"type":"string","description":"Model override"},"thinking":{"type":"string","description":"Thinking override"},"timeoutSeconds":{"type":"number"},"lightContext":{"type":"boolean"},"allowUnsafeExternalContent":{"type":"boolean"},"fallbacks":{"type":"array","items":{"type":"string"},"description":"Fallback models"},"toolsAllow":{"type":"array","items":{"type":"string"},"description":"Allowed tools"}},"additionalProperties":true},"delivery":{"type":"object","properties":{"mode":{"type":"string","enum":["none","announce","webhook"],"description":"Delivery mode"},"channel":{"type":"string","description":"Delivery channel"},"to":{"type":"string","description":"Delivery target"},"threadId":{"anyOf":[{"type":"string"},{"type":"number"}],"description":"Thread/topic id"},"bestEffort":{"type":"boolean"},"accountId":{"type":"string","description":"Delivery account"},"failureDestination":{"type":"object","properties":{"channel":{"type":"string"},"to":{"type":"string"},"accountId":{"type":"string"},"mode":{"type":"string","enum":["announce","webhook"]}},"additionalProperties":true}},"additionalProperties":true},"agentId":{"type":"string","description":"Agent id, or null to keep it unset"},"description":{"type":"string","description":"Human description"},"enabled":{"type":"boolean"},"deleteAfterRun":{"type":"boolean","description":"Delete after first run"},"sessionKey":{"type":"string","description":"Explicit session key, or null to clear it"},"failureAlert":{"type":"object","properties":{"after":{"type":"number","description":"Failures before alert"},"channel":{"type":"string","description":"Alert channel"},"to":{"type":"string","description":"Alert target"},"cooldownMs":{"type":"number","description":"Alert cooldown ms"},"includeSkipped":{"type":"boolean","description":"Skipped runs count toward alert"},"mode":{"type":"string","enum":["announce","webhook"]},"accountId":{"type":"string"}},"additionalProperties":true,"description":"Failure alert object; false disables alerts"}},"additionalProperties":true},"jobId":{"type":"string"},"id":{"type":"string"},"patch":{"type":"object","properties":{"name":{"type":"string","description":"Job name"},"schedule":{"type":"object","properties":{"kind":{"type":"string","enum":["at","every","cron"],"description":"Schedule kind"},"at":{"type":"string","description":"ISO-8601 time (kind=at)"},"everyMs":{"type":"number","description":"Interval ms (kind=every)"},"anchorMs":{"type":"number","description":"Start anchor ms (kind=every)"},"expr":{"type":"string","description":"Cron expr in tz wall-clock time; do not convert to UTC. Omitted tz => Gateway host local timezone. Example 6pm Shanghai daily: expr \"0 18 * * *\", tz \"Asia/Shanghai\"."},"tz":{"type":"string","description":"IANA timezone for cron wall-clock fields, e.g. \"Asia/Shanghai\"; omitted => Gateway host local timezone."},"staggerMs":{"type":"number","description":"Jitter ms (kind=cron)"}},"additionalProperties":true},"sessionTarget":{"type":"string","description":"Session target"},"wakeMode":{"type":"string","enum":["now","next-heartbeat"]},"payload":{"type":"object","properties":{"kind":{"type":"string","enum":["systemEvent","agentTurn"],"description":"Payload kind"},"text":{"type":"string","description":"systemEvent text"},"message":{"type":"string","description":"agentTurn prompt"},"model":{"type":"string","description":"Model override"},"thinking":{"type":"string","description":"Thinking override"},"timeoutSeconds":{"type":"number"},"lightContext":{"type":"boolean"},"allowUnsafeExternalContent":{"type":"boolean"},"fallbacks":{"type":"array","items":{"type":"string"},"description":"Fallback models"},"toolsAllow":{"type":"array","items":{"type":"string"},"description":"Allowed tool ids, or null to clear"}},"additionalProperties":true},"delivery":{"type":"object","properties":{"mode":{"type":"string","enum":["none","announce","webhook"],"description":"Delivery mode"},"channel":{"type":"string","description":"Delivery channel"},"to":{"type":"string","description":"Delivery target"},"threadId":{"anyOf":[{"type":"string"},{"type":"number"}],"description":"Thread/topic id"},"bestEffort":{"type":"boolean"},"accountId":{"type":"string","description":"Delivery account"},"failureDestination":{"type":"object","properties":{"channel":{"type":"string"},"to":{"type":"string"},"accountId":{"type":"string"},"mode":{"type":"string","enum":["announce","webhook"]}},"additionalProperties":true}},"additionalProperties":true},"description":{"type":"string"},"enabled":{"type":"boolean"},"deleteAfterRun":{"type":"boolean"},"agentId":{"type":"string","description":"Agent id, or null to clear it"},"sessionKey":{"type":"string","description":"Explicit session key, or null to clear it"},"failureAlert":{"type":"object","properties":{"after":{"type":"number","description":"Failures before alert"},"channel":{"type":"string","description":"Alert channel"},"to":{"type":"string","description":"Alert target"},"cooldownMs":{"type":"number","description":"Alert cooldown ms"},"includeSkipped":{"type":"boolean","description":"Skipped runs count toward alert"},"mode":{"type":"string","enum":["announce","webhook"]},"accountId":{"type":"string"}},"additionalProperties":true,"description":"Failure alert object; false disables alerts"}},"additionalProperties":true},"text":{"type":"string"},"mode":{"type":"string","enum":["now","next-heartbeat"]},"runMode":{"type":"string","enum":["due","force"]},"contextMessages":{"type":"number","minimum":0,"maximum":10},"agentId":{"type":"string","description":"List filter: agent id"}},"additionalProperties":true}}},{"type":"function","function":{"name":"edit","description":"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.","parameters":{"type":"object","required":["path","edits"],"properties":{"path":{"type":"string","description":"Path to the file to edit (relative or absolute)"},"edits":{"type":"array","items":{"type":"object","required":["oldText","newText"],"properties":{"oldText":{"type":"string","description":"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call."},"newText":{"type":"string","description":"Replacement text for this targeted edit."}},"additionalProperties":false},"description":"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead."}},"additionalProperties":false}}},{"type":"function","function":{"name":"exec","description":"Execute shell commands with background continuation for work that starts now. Use yieldMs/background to continue later via process tool. For long-running work started now, rely on automatic completion wake when it is enabled and the command emits output or fails; otherwise use process to confirm completion. Use process whenever you need logs, status, input, or intervention. Do not use exec sleep or delay loops for reminders or deferred follow-ups; use cron instead. Use pty=true for TTY-required commands (terminal UIs, coding agents).","parameters":{"type":"object","required":["command"],"properties":{"command":{"type":"string","description":"Shell command to execute"},"workdir":{"type":"string","description":"Working directory (defaults to cwd)"},"env":{"type":"object","patternProperties":{"^.*$":{"type":"string"}}},"yieldMs":{"type":"number","description":"Milliseconds to wait before backgrounding (default 10000)"},"background":{"type":"boolean","description":"Run in background immediately"},"timeout":{"type":"number","description":"Timeout in seconds (optional, kills process on expiry)"},"pty":{"type":"boolean","description":"Run in a pseudo-terminal (PTY) when available (TTY-required CLIs, coding agents)"},"elevated":{"type":"boolean","description":"Run on the host with elevated permissions (if allowed)"},"host":{"type":"string","enum":["auto","sandbox","gateway","node"],"description":"Exec host/target (auto|sandbox|gateway|node)."},"security":{"type":"string","description":"Ignored for normal calls; exec security is set by tools.exec.security and host approvals."},"ask":{"type":"string","description":"Exec ask mode (off|on-miss|always)."},"node":{"type":"string","description":"Node id/name for host=node."}}}}},{"type":"function","function":{"name":"gbrain__gbrain_list_tools","description":"Discover the FULL gbrain toolset (~64 advanced tools beyond search/query/get_page). No arg → all tool names + one-line descriptions. Pass {name} → that tool's full input schema (call this to learn a tool's params before invoking gbrain_tool).","parameters":{"type":"object","properties":{"name":{"type":"string","description":"optional: a tool name to get its full schema"}},"required":[]}}},{"type":"function","function":{"name":"gbrain__gbrain_tool","description":"Escape hatch: invoke ANY gbrain tool by name when the 3 common tools are not enough — e.g. traverse_graph, get_backlinks, list_pages, find_experts, find_trajectory, find_anomalies, get_recent_salience, recall, add_link, put_page, submit_agent, run_doctor. Discover names/params with gbrain_list_tools first.","parameters":{"type":"object","properties":{"name":{"type":"string","description":"the gbrain tool name"},"arguments":{"type":"object","description":"arguments object for that tool"}},"required":["name"]}}},{"type":"function","function":{"name":"gbrain__get_page","description":"Read a brain page by its slug (path-like id).","parameters":{"type":"object","properties":{"slug":{"type":"string"}},"required":["slug"]}}},{"type":"function","function":{"name":"gbrain__query","description":"Hybrid semantic search of the personal brain (vector + keyword). Best for natural-language questions about past work, decisions, configs.","parameters":{"type":"object","properties":{"query":{"type":"string","description":"the question"},"limit":{"type":"number"}},"required":["query"]}}},{"type":"function","function":{"name":"gbrain__search","description":"Keyword search the personal knowledge brain. Returns matching pages. Use for exact terms/names.","parameters":{"type":"object","properties":{"query":{"type":"string","description":"search terms"},"limit":{"type":"number"}},"required":["query"]}}},{"type":"function","function":{"name":"image","description":"Analyze images with vision model. Use image for one path/URL, images for max 20. Only use this tool when images were NOT already provided; prompt images already visible.","parameters":{"type":"object","properties":{"prompt":{"type":"string"},"image":{"type":"string","description":"One image path/URL."},"images":{"type":"array","items":{"type":"string"},"description":"Image paths/URLs; maxImages default 20."},"model":{"type":"string"},"maxBytesMb":{"type":"number"},"maxImages":{"type":"number"}}}}},{"type":"function","function":{"name":"image_generate","description":"Create/edit images. Session chats: background task; do not call image_generate again for same request; wait completion, then send attachments via message tool. Transparent: outputFormat=\"png\" or \"webp\" + background=\"transparent\"; OpenAI also supports openai.background and routes default model to gpt-image-1.5. Use action=\"list\" for providers/models/readiness/auth, \"status\" for active task.","parameters":{"type":"object","properties":{"action":{"type":"string","description":"\"generate\" default, \"status\" active task, \"list\" providers/models."},"prompt":{"type":"string","description":"Image prompt."},"image":{"type":"string","description":"Reference image path/URL for edit."},"images":{"type":"array","items":{"type":"string"},"description":"Reference images for edit; max 5."},"model":{"type":"string","description":"Provider/model override, e.g. openai/gpt-image-2; transparent OpenAI: openai/gpt-image-1.5."},"filename":{"type":"string","description":"Output filename hint; basename preserved in managed media dir."},"size":{"type":"string","description":"Size hint: 1024x1024, 1536x1024, 1024x1536, 2048x2048, 3840x2160."},"aspectRatio":{"type":"string","description":"Aspect ratio: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9."},"resolution":{"type":"string","description":"Resolution: 1K, 2K, 4K; useful for Google."},"quality":{"type":"string","enum":["low","medium","high","auto"],"description":"Quality: low, medium, high, auto."},"outputFormat":{"type":"string","enum":["png","jpeg","webp"],"description":"Output format: png, jpeg, webp."},"background":{"type":"string","enum":["transparent","opaque","auto"],"description":"Background: transparent, opaque, auto. Transparent needs png/webp output."},"openai":{"type":"object","properties":{"background":{"type":"string","enum":["transparent","opaque","auto"],"description":"OpenAI background: transparent, opaque, auto. Transparent needs png/webp; default model routes to gpt-image-1.5."},"moderation":{"type":"string","enum":["low","auto"],"description":"OpenAI moderation: low, auto."},"outputCompression":{"type":"number","description":"OpenAI jpeg/webp compression 0-100.","minimum":0,"maximum":100},"user":{"type":"string","description":"OpenAI stable end-user id."}}},"count":{"type":"number","description":"Image count 1-4.","minimum":1,"maximum":4},"timeoutMs":{"type":"number","description":"Provider timeout ms.","minimum":1}}}}},{"type":"function","function":{"name":"lcm_describe","description":"Look up metadata and content for an LCM item by ID. Use this to inspect summaries (sum_xxx) or stored files (file_xxx) from compacted conversation history. Returns summary content, lineage, token counts, and file exploration results.","parameters":{"type":"object","required":["id"],"properties":{"id":{"description":"The LCM ID to look up. Use sum_xxx for summaries, file_xxx for files.","type":"string"},"conversationId":{"description":"Conversation ID to scope describe lookups to. If omitted, uses the current session conversation.","type":"number"},"allConversations":{"description":"Set true to explicitly allow lookups across all conversations. Ignored when conversationId is provided.","type":"boolean"},"tokenCap":{"description":"Optional budget cap used for subtree manifest budget-fit annotations.","minimum":1,"type":"number"}}}}},{"type":"function","function":{"name":"lcm_expand","description":"Expand compacted conversation summaries from LCM (Lossless Context Management). Traverses the summary DAG to retrieve children and source messages. Use this to drill into previously-compacted context when you need detail that was summarised away. Provide either summaryIds (direct expansion) or query (grep-first, then expand top matches). Returns a compact text payload plus cited IDs in tool output for follow-up.","parameters":{"type":"object","properties":{"summaryIds":{"description":"Summary IDs to expand (sum_xxx format). Required if query is not provided.","type":"array","items":{"type":"string"}},"query":{"description":"Text query to grep for matching summaries before expanding. If provided, summaryIds is ignored and the top grep results are expanded.","type":"string"},"maxDepth":{"description":"Max traversal depth per summary (default: 3).","minimum":1,"type":"number"},"tokenCap":{"description":"Max tokens across the entire expansion result.","minimum":1,"type":"number"},"includeMessages":{"description":"Whether to include raw source messages at leaf level (default: false).","type":"boolean"},"conversationId":{"description":"Conversation ID to scope the expansion to. If omitted, uses the current session's conversation.","type":"number"},"allConversations":{"description":"Set true to explicitly allow cross-conversation expansion. Ignored when conversationId is provided.","type":"boolean"}}}}},{"type":"function","function":{"name":"lcm_expand_query","description":"Answer a focused natural-language question using delegated LCM expansion. Find candidate summaries (by IDs or a short FTS5 query that follows the same full-text rules as lcm_grep), expand them in a delegated sub-agent, and return a compact prompt-focused answer. Tool output includes cited summary IDs for follow-up.","parameters":{"type":"object","required":["prompt"],"properties":{"summaryIds":{"description":"Summary IDs to expand (sum_xxx). Required when query is not provided.","type":"array","items":{"type":"string"}},"query":{"description":"FTS5 query used to find summaries via the same full-text search path as lcm_grep before expansion. Use 1-3 distinctive terms or a quoted phrase; FTS5 defaults to AND matching, so extra terms make matches stricter. Required when summaryIds is not provided.","type":"string"},"prompt":{"description":"Natural-language question or task to answer using expanded context. Put the answer request here, not in query.","type":"string"},"conversationId":{"description":"Conversation ID to scope expansion to. If omitted, uses the current session conversation.","type":"number"},"allConversations":{"description":"Set true to explicitly allow cross-conversation lookup. Ignored when conversationId is provided.","type":"boolean"},"maxTokens":{"description":"Maximum answer tokens to target (default: 2000).","minimum":1,"type":"number"},"tokenCap":{"description":"Expansion retrieval token budget across all delegated lcm_expand calls for this query.","minimum":1,"type":"number"}}}}},{"type":"function","function":{"name":"lcm_grep","description":"Search compacted conversation history using regex or full-text search. Searches across messages and/or summaries stored by LCM. Use this to find specific content that may have been compacted away from active context. In full_text mode, queries use FTS5 AND semantics by default, so keep them short and focused; quoted phrases stay intact and optional sort modes can prioritize relevance for older topics. Returns matching snippets with their summary/message IDs for follow-up with lcm_expand or lcm_describe.","parameters":{"type":"object","required":["pattern"],"properties":{"pattern":{"description":"Search pattern. Interpreted as regex when mode is \"regex\", or as an FTS5 text query when mode is \"full_text\". In full_text mode, FTS5 defaults to AND matching, so prefer 1-3 distinctive terms or one quoted multi-word phrase instead of padding with synonyms or extra keywords.","type":"string"},"mode":{"description":"Search mode: \"regex\" for regular expression matching, \"full_text\" for text search. Default: \"regex\".","enum":["regex","full_text"],"type":"string"},"scope":{"description":"What to search: \"messages\" for raw messages, \"summaries\" for compacted summaries, \"both\" for all. Default: \"both\".","enum":["messages","summaries","both"],"type":"string"},"conversationId":{"description":"Conversation ID to search within. If omitted, defaults to the current session conversation.","type":"number"},"allConversations":{"description":"Set true to explicitly search across all conversations. Ignored when conversationId is provided.","type":"boolean"},"since":{"description":"Only return matches created at or after this ISO timestamp.","type":"string"},"before":{"description":"Only return matches created before this ISO timestamp.","type":"string"},"limit":{"description":"Maximum number of results to return (default: 50).","minimum":1,"maximum":200,"type":"number"},"sort":{"description":"Sort order: \"recency\" (newest first, default), \"relevance\" (best FTS5 match first, full_text mode only), or \"hybrid\" (full_text mode only; balances relevance with recency). Applied before limit is enforced.","enum":["recency","relevance","hybrid"],"type":"string"}}}}},{"type":"function","function":{"name":"memory_get","description":"Safe exact excerpt read from MEMORY.md or memory/*.md. Defaults to a bounded excerpt when lines are omitted, includes truncation/continuation info when more content exists, and `corpus=wiki` reads from registered compiled-wiki supplements.","parameters":{"type":"object","properties":{"path":{"type":"string"},"from":{"type":"number"},"lines":{"type":"number"},"corpus":{"type":"string","enum":["memory","wiki","all"]}},"required":["path"],"additionalProperties":false}}},{"type":"function","function":{"name":"memory_search","description":"Mandatory recall step: semantically search MEMORY.md + memory/*.md (and optional session transcripts) before answering questions about prior work, decisions, dates, people, preferences, or todos. Optional `corpus=wiki` or `corpus=all` also searches registered compiled-wiki supplements. `corpus=memory` restricts hits to indexed memory files (excludes session transcript chunks from ranking). `corpus=sessions` restricts hits to indexed session transcripts (same visibility rules as session history tools). If response has disabled=true, memory retrieval is unavailable and should be surfaced to the user.","parameters":{"type":"object","properties":{"query":{"type":"string"},"maxResults":{"type":"number"},"minScore":{"type":"number"},"corpus":{"type":"string","enum":["memory","wiki","all","sessions"]}},"required":["query"],"additionalProperties":false}}},{"type":"function","function":{"name":"music_generate","description":"Create audio/music for song, jingle, beat, loop, soundtrack, anthem, instrumental requests. If user asks make/generate/create song/music, call music_generate; do not just write lyrics unless lyrics/text only. Prompt gets style/genre/mood/tempo/instruments/purpose. lyrics only exact sung words. Session chats: background task; do not call again for same request; wait completion, send attachments via message tool. \"status\" checks active task.","parameters":{"type":"object","properties":{"action":{"type":"string","description":"\"generate\" default, \"status\" active task, \"list\" providers/models."},"prompt":{"type":"string","description":"Music prompt: style, genre, mood, purpose."},"lyrics":{"type":"string","description":"Exact sung lyrics only when the user supplies lyrics or asks for vocal words. For song/style requests, use prompt instead."},"instrumental":{"type":"boolean","description":"Instrumental-only toggle."},"image":{"type":"string","description":"Reference image path/URL."},"images":{"type":"array","items":{"type":"string"},"description":"Reference images; max 10."},"model":{"type":"string","description":"Provider/model override, e.g. google/lyria-3-pro-preview."},"durationSeconds":{"type":"number","description":"Target seconds; provider may clamp.","minimum":1},"format":{"type":"string","description":"Output format: mp3, wav."},"filename":{"type":"string","description":"Output filename hint; basename preserved in managed media dir."}}}}},{"type":"function","function":{"name":"process","description":"Manage running exec sessions for commands already started: list, poll, log, write, send-keys, submit, paste, kill. Use poll/log when you need status, logs, quiet-success confirmation, or completion confirmation when automatic completion wake is unavailable. Use poll/log also for input-wait hints. Use write/send-keys/submit/paste/kill for input or intervention. Do not use process polling to emulate timers or reminders; use cron for scheduled follow-ups.","parameters":{"type":"object","required":["action"],"properties":{"action":{"type":"string","description":"Process action (list|poll|log|write|send-keys|submit|paste|kill|clear|remove)"},"sessionId":{"type":"string","description":"Session id for actions other than list"},"data":{"type":"string","description":"Data to write for write"},"keys":{"type":"array","items":{"type":"string"},"description":"Key tokens to send for send-keys"},"hex":{"type":"array","items":{"type":"string"},"description":"Hex bytes to send for send-keys"},"literal":{"type":"string","description":"Literal string for send-keys"},"text":{"type":"string","description":"Text to paste for paste"},"bracketed":{"type":"boolean","description":"Wrap paste in bracketed mode"},"eof":{"type":"boolean","description":"Close stdin after write"},"offset":{"type":"number","description":"Log offset"},"limit":{"type":"number","description":"Log length"},"timeout":{"type":"number","description":"For poll: wait up to this many milliseconds before returning; max 30000 ms, higher values are clamped to 30000","minimum":0}}}}},{"type":"function","function":{"name":"read","description":"Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to 2000 lines or 50KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.","parameters":{"type":"object","required":["path"],"properties":{"path":{"type":"string","description":"Path to the file to read (relative or absolute)"},"offset":{"type":"number","description":"Line number to start reading from (1-indexed)"},"limit":{"type":"number","description":"Maximum number of lines to read"}}}}},{"type":"function","function":{"name":"session_status","description":"Show /status-like card for current/visible session: model, usage, time, cost, tasks. Use `sessionKey=\"current\"` for current session; UI labels like `openclaw-tui` are not keys. `model` sets session override; `model=default` resets. Use for active model/session config questions.","parameters":{"type":"object","properties":{"sessionKey":{"type":"string"},"model":{"type":"string"}}}}},{"type":"function","function":{"name":"sessions_history","description":"Fetch sanitized history for visible session. Use before replying, debugging, resuming; supports limits/tool messages.","parameters":{"type":"object","required":["sessionKey"],"properties":{"sessionKey":{"type":"string"},"limit":{"type":"number","minimum":1},"includeTools":{"type":"boolean"}}}}},{"type":"function","function":{"name":"sessions_list","description":"List visible sessions; filter by kind, label, agentId, search, activity. Use before sessions_history or sessions_send target selection.","parameters":{"type":"object","properties":{"kinds":{"type":"array","items":{"type":"string"}},"limit":{"type":"number","minimum":1},"activeMinutes":{"type":"number","minimum":1},"messageLimit":{"type":"number","minimum":0},"label":{"type":"string","minLength":1},"agentId":{"type":"string","minLength":1,"maxLength":64},"search":{"type":"string","minLength":1},"includeDerivedTitles":{"type":"boolean"},"includeLastMessage":{"type":"boolean"}}}}},{"type":"function","function":{"name":"sessions_send","description":"Send message to visible session by sessionKey/label, or configured agent by agentId. Thread-scoped chats rejected; target parent channel session. Creates missing configured-agent main session; waits for reply when available.","parameters":{"type":"object","required":["message"],"properties":{"sessionKey":{"type":"string"},"label":{"type":"string","minLength":1,"maxLength":512},"agentId":{"type":"string","minLength":1,"maxLength":64},"message":{"type":"string"},"timeoutSeconds":{"type":"number","minimum":0}}}}},{"type":"function","function":{"name":"sessions_spawn","description":"Spawn clean child session; default `runtime=\"subagent\"`. `mode=\"run\"` one-shot background work. Subagents inherit parent workspace. Native subagents get task in first visible `[Subagent Task]` message. Native only: `context=\"fork\"` only when child needs current transcript; else omit or `isolated`. Use for fresh child-session work.","parameters":{"type":"object","required":["task"],"properties":{"task":{"type":"string"},"taskName":{"type":"string","description":"Stable alias for later targeting; lowercase letters/digits/underscores, starts letter."},"label":{"type":"string"},"runtime":{"type":"string","enum":["subagent"]},"agentId":{"type":"string"},"model":{"type":"string"},"thinking":{"type":"string"},"cwd":{"type":"string"},"runTimeoutSeconds":{"type":"number","minimum":0},"timeoutSeconds":{"type":"number","minimum":0},"mode":{"type":"string","enum":["run"]},"cleanup":{"type":"string","enum":["delete","keep"]},"sandbox":{"type":"string","enum":["inherit","require"]},"context":{"type":"string","enum":["isolated","fork"],"description":"Native context. Omit/\"isolated\" for clean child; \"fork\" only when child needs requester transcript."},"lightContext":{"type":"boolean","description":"Light bootstrap context; runtime=\"subagent\" only."},"attachments":{"type":"array","items":{"type":"object","required":["name","content"],"properties":{"name":{"type":"string"},"content":{"type":"string"},"encoding":{"type":"string","enum":["utf8","base64"]},"mimeType":{"type":"string"}}},"maxItems":50},"attachAs":{"type":"object","properties":{"mountPath":{"type":"string"}}}}}}},{"type":"function","function":{"name":"sessions_yield","description":"End current turn. Use after spawning subagents; results arrive as next message.","parameters":{"type":"object","properties":{"message":{"type":"string"}}}}},{"type":"function","function":{"name":"subagents","description":"List/kill/steer spawned subagents for requester session. If sessions_yield exists, use it for completion; do not poll wait loops.","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","kill","steer"]},"target":{"type":"string"},"message":{"type":"string"},"recentMinutes":{"type":"number","minimum":1}}}}},{"type":"function","function":{"name":"update_plan","description":"Update current run plan. Use for non-trivial multi-step work; keep plan current while executing. Short steps; max one `in_progress`; skip for simple one-step work.","parameters":{"type":"object","required":["plan"],"properties":{"explanation":{"type":"string","description":"Short note: what changed."},"plan":{"type":"array","items":{"type":"object","required":["step","status"],"properties":{"step":{"type":"string","description":"Short step."},"status":{"type":"string","enum":["pending","in_progress","completed"],"description":"pending | in_progress | completed."}},"additionalProperties":true},"minItems":1,"description":"Ordered steps; max one in_progress."}}}}},{"type":"function","function":{"name":"video_generate","description":"Create videos. Session chats: background task; do not call video_generate again for same request; wait completion, then send attachments via message tool. \"status\" checks active task. Duration may round to provider-supported value.","parameters":{"type":"object","properties":{"action":{"type":"string","description":"\"generate\" default, \"status\" active task, \"list\" providers/models."},"prompt":{"type":"string","description":"Video prompt."},"image":{"type":"string","description":"One reference image path/URL."},"images":{"type":"array","items":{"type":"string"},"description":"Reference images; max 9."},"imageRoles":{"type":"array","items":{"type":"string"},"description":"`image` + `images` roles by index after de-dupe. Values: first_frame, last_frame, reference_image; empty string leaves unset."},"video":{"type":"string","description":"One reference video path/URL."},"videos":{"type":"array","items":{"type":"string"},"description":"Reference videos; max 4."},"videoRoles":{"type":"array","items":{"type":"string"},"description":"`video` + `videos` roles by index after de-dupe. Value: reference_video; empty string leaves unset."},"model":{"type":"string","description":"Provider/model override, e.g. qwen/wan2.6-t2v."},"filename":{"type":"string","description":"Output filename hint; basename preserved in managed media dir."},"size":{"type":"string","description":"Size hint, e.g. 1280x720, 1920x1080."},"aspectRatio":{"type":"string","description":"Aspect ratio: 1:1, 16:9, 9:16, \"adaptive\", or provider value; unsupported normalized/ignored."},"resolution":{"type":"string","description":"Resolution: 480P, 720P, 768P, 1080P, 4K, or provider value; unsupported normalized/ignored."},"durationSeconds":{"type":"number","description":"Target seconds; may round to nearest supported duration.","minimum":1},"audio":{"type":"boolean","description":"Generated-audio toggle."},"watermark":{"type":"boolean","description":"Watermark toggle."},"providerOptions":{"type":"object","patternProperties":{"^.*$":{}},"description":"Provider JSON options, e.g. {\"seed\":42}. Keys/types must match provider capabilities; mismatch skips candidate. Use action=list for accepted keys."},"timeoutMs":{"type":"number","description":"Provider timeout ms.","minimum":1}}}}},{"type":"function","function":{"name":"web_fetch","description":"Fetch URL and extract readable markdown/text. Lightweight page access; no browser automation.","parameters":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"HTTP(S) URL."},"extractMode":{"type":"string","enum":["markdown","text"],"description":"Extract as markdown/text.","default":"markdown"},"maxChars":{"type":"number","description":"Max chars returned; truncates.","minimum":100}}}}},{"type":"function","function":{"name":"wiki_apply","description":"Apply narrow wiki mutations for syntheses and page metadata without freeform markdown surgery.","parameters":{"type":"object","required":["op"],"properties":{"op":{"anyOf":[{"type":"string","const":"create_synthesis"},{"type":"string","const":"update_metadata"}]},"title":{"type":"string","minLength":1},"body":{"type":"string","minLength":1},"lookup":{"type":"string","minLength":1},"sourceIds":{"type":"array","items":{"type":"string","minLength":1}},"claims":{"type":"array","items":{"type":"object","required":["text"],"properties":{"id":{"type":"string","minLength":1},"text":{"type":"string","minLength":1},"status":{"type":"string","minLength":1},"confidence":{"type":"number","minimum":0,"maximum":1},"evidence":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","minLength":1},"sourceId":{"type":"string","minLength":1},"path":{"type":"string","minLength":1},"lines":{"type":"string","minLength":1},"weight":{"type":"number","minimum":0},"note":{"type":"string","minLength":1},"confidence":{"type":"number","minimum":0,"maximum":1},"privacyTier":{"type":"string","minLength":1},"updatedAt":{"type":"string","minLength":1}},"additionalProperties":false}},"updatedAt":{"type":"string","minLength":1}},"additionalProperties":false}},"contradictions":{"type":"array","items":{"type":"string","minLength":1}},"questions":{"type":"array","items":{"type":"string","minLength":1}},"confidence":{"anyOf":[{"type":"number","minimum":0,"maximum":1},{"type":"null"}]},"status":{"type":"string","minLength":1}},"additionalProperties":false}}},{"type":"function","function":{"name":"wiki_get","description":"Read a wiki page by id or relative path, or fall back to the active memory corpus when shared search is enabled.","parameters":{"type":"object","required":["lookup"],"properties":{"lookup":{"type":"string","minLength":1},"fromLine":{"type":"number","minimum":1},"lineCount":{"type":"number","minimum":1},"backend":{"anyOf":[{"type":"string","const":"shared"},{"type":"string","const":"local"}]},"corpus":{"anyOf":[{"type":"string","const":"wiki"},{"type":"string","const":"memory"},{"type":"string","const":"all"}]}},"additionalProperties":false}}},{"type":"function","function":{"name":"wiki_lint","description":"Lint the wiki vault and surface structural issues, provenance gaps, contradictions, and open questions.","parameters":{"type":"object","properties":{},"additionalProperties":false}}},{"type":"function","function":{"name":"wiki_search","description":"Search wiki pages and, when shared search is enabled, the active memory corpus by title, path, id, or body text.","parameters":{"type":"object","required":["query"],"properties":{"query":{"type":"string","minLength":1},"maxResults":{"type":"number","minimum":1},"backend":{"anyOf":[{"type":"string","const":"shared"},{"type":"string","const":"local"}]},"corpus":{"anyOf":[{"type":"string","const":"wiki"},{"type":"string","const":"memory"},{"type":"string","const":"all"}]},"mode":{"anyOf":[{"type":"string","const":"auto"},{"type":"string","const":"find-person"},{"type":"string","const":"route-question"},{"type":"string","const":"source-evidence"},{"type":"string","const":"raw-claim"}]}},"additionalProperties":false}}},{"type":"function","function":{"name":"wiki_status","description":"Inspect the current memory wiki vault mode, health, and Obsidian CLI availability.","parameters":{"type":"object","properties":{},"additionalProperties":false}}},{"type":"function","function":{"name":"write","description":"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.","parameters":{"type":"object","required":["path","content"],"properties":{"path":{"type":"string","description":"Path to the file to write (relative or absolute)"},"content":{"type":"string","description":"Content to write to the file"}}}}}]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a1hvdy/cc-openclaw",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "description": "A1xAI's Anthropic CLI bridge plugin for OpenClaw",
5
5
  "author": "@a1cy",
6
6
  "license": "MIT",
@@ -43,15 +43,14 @@
43
43
  "lint": "eslint src tests",
44
44
  "lint:fix": "eslint src tests --fix",
45
45
  "format": "prettier -w .",
46
- "format:check": "prettier -c .",
47
- "prepublishOnly": "npm run build && npm test"
46
+ "format:check": "prettier -c ."
48
47
  },
49
48
  "dependencies": {
50
49
  "commander": "^12.1.0",
51
50
  "zod": "^3.23.0"
52
51
  },
53
52
  "peerDependencies": {
54
- "openclaw": ">=2026.3.0"
53
+ "openclaw": ">=2026.5.22"
55
54
  },
56
55
  "devDependencies": {
57
56
  "@eslint/js": "^9.15.0",