Skip to content

Commit 064b206

Browse files
authored
Merge branch 'main' into fix-legacy-web-search-preserve-records-83287
2 parents a86899a + 6048cd4 commit 064b206

57 files changed

Lines changed: 1810 additions & 289 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/openclaw-npm-release.yml

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -511,10 +511,25 @@ jobs:
511511
preferred_name="openclaw-npm-preflight-${RELEASE_TAG}"
512512
rm -rf preflight-tarball
513513
mkdir -p preflight-tarball
514-
if gh run download "${PREFLIGHT_RUN_ID}" \
515-
--repo "${GITHUB_REPOSITORY}" \
516-
--name "${preferred_name}" \
517-
--dir preflight-tarball; then
514+
515+
download_named_artifact() {
516+
local artifact_name="$1"
517+
for attempt in 1 2 3; do
518+
if gh run download "${PREFLIGHT_RUN_ID}" \
519+
--repo "${GITHUB_REPOSITORY}" \
520+
--name "${artifact_name}" \
521+
--dir preflight-tarball; then
522+
return 0
523+
fi
524+
if [[ "$attempt" != "3" ]]; then
525+
echo "::warning::Artifact download for ${artifact_name} failed on attempt ${attempt}; retrying."
526+
sleep $((attempt * 10))
527+
fi
528+
done
529+
return 1
530+
}
531+
532+
if download_named_artifact "${preferred_name}"; then
518533
echo "Downloaded ${preferred_name}."
519534
return 0
520535
fi
@@ -530,10 +545,7 @@ jobs:
530545
exit 1
531546
fi
532547
fallback_name="${matches[0]}"
533-
gh run download "${PREFLIGHT_RUN_ID}" \
534-
--repo "${GITHUB_REPOSITORY}" \
535-
--name "${fallback_name}" \
536-
--dir preflight-tarball
548+
download_named_artifact "${fallback_name}"
537549
echo "Downloaded fallback preflight artifact ${fallback_name}."
538550
}
539551

.github/workflows/openclaw-release-publish.yml

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,25 @@ jobs:
153153
preflight_dir="${RUNNER_TEMP}/openclaw-npm-preflight-manifest"
154154
rm -rf "${preflight_dir}"
155155
mkdir -p "${preflight_dir}"
156-
if gh run download "${PREFLIGHT_RUN_ID}" \
157-
--repo "${GITHUB_REPOSITORY}" \
158-
--name "${preferred_name}" \
159-
--dir "${preflight_dir}"; then
156+
157+
download_named_artifact() {
158+
local artifact_name="$1"
159+
for attempt in 1 2 3; do
160+
if gh run download "${PREFLIGHT_RUN_ID}" \
161+
--repo "${GITHUB_REPOSITORY}" \
162+
--name "${artifact_name}" \
163+
--dir "${preflight_dir}"; then
164+
return 0
165+
fi
166+
if [[ "$attempt" != "3" ]]; then
167+
echo "::warning::Artifact download for ${artifact_name} failed on attempt ${attempt}; retrying."
168+
sleep $((attempt * 10))
169+
fi
170+
done
171+
return 1
172+
}
173+
174+
if download_named_artifact "${preferred_name}"; then
160175
echo "name=${preferred_name}" >> "$GITHUB_OUTPUT"
161176
exit 0
162177
fi
@@ -172,10 +187,7 @@ jobs:
172187
exit 1
173188
fi
174189
fallback_name="${matches[0]}"
175-
gh run download "${PREFLIGHT_RUN_ID}" \
176-
--repo "${GITHUB_REPOSITORY}" \
177-
--name "${fallback_name}" \
178-
--dir "${preflight_dir}"
190+
download_named_artifact "${fallback_name}"
179191
echo "name=${fallback_name}" >> "$GITHUB_OUTPUT"
180192
181193
- name: Download full release validation manifest
@@ -645,10 +657,14 @@ jobs:
645657
--workflow-ref "${CHILD_WORKFLOW_REF}"
646658
--full-release-validation-run "${FULL_RELEASE_VALIDATION_RUN_ID}"
647659
--plugin-npm-run "${plugin_npm_run_id}"
648-
--plugin-clawhub-run "${plugin_clawhub_run_id}"
649660
--openclaw-npm-run "${openclaw_npm_run_id}"
650661
--evidence-out "${evidence_path}"
651662
)
663+
if [[ "${WAIT_FOR_CLAWHUB}" == "true" ]]; then
664+
verify_args+=(--plugin-clawhub-run "${plugin_clawhub_run_id}")
665+
else
666+
verify_args+=(--skip-clawhub)
667+
fi
652668
if [[ -n "${PLUGINS// }" ]]; then
653669
verify_args+=(--plugins "${PLUGINS}")
654670
fi
@@ -671,11 +687,11 @@ jobs:
671687
echo "- Release SHA: \`${TARGET_SHA}\`"
672688
echo "- Plugin npm and ClawHub publish: dispatched in parallel"
673689
if [[ "${PUBLISH_OPENCLAW_NPM}" == "true" ]]; then
674-
echo "- OpenClaw npm publish: starts after plugin npm succeeds; final verification waits for ClawHub"
690+
echo "- OpenClaw npm publish: starts after plugin npm succeeds"
675691
else
676692
echo "- OpenClaw npm publish: skipped by input"
677693
fi
678-
if [[ "${WAIT_FOR_CLAWHUB}" == "true" || "${PUBLISH_OPENCLAW_NPM}" == "true" ]]; then
694+
if [[ "${WAIT_FOR_CLAWHUB}" == "true" ]]; then
679695
echo "- Workflow completion waits for ClawHub"
680696
else
681697
echo "- Workflow completion does not wait for ClawHub; monitor the dispatched ClawHub run separately"
@@ -717,7 +733,7 @@ jobs:
717733
718734
clawhub_result=""
719735
clawhub_pid=""
720-
if [[ "${WAIT_FOR_CLAWHUB}" == "true" || "${PUBLISH_OPENCLAW_NPM}" == "true" ]]; then
736+
if [[ "${WAIT_FOR_CLAWHUB}" == "true" ]]; then
721737
clawhub_result="$RUNNER_TEMP/clawhub-result.txt"
722738
wait_run_pid=""
723739
wait_for_run_background plugin-clawhub-release.yml "${plugin_clawhub_run_id}" "${clawhub_result}"

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ Docs: https://docs.openclaw.ai
1212
### Fixes
1313

1414
- CLI/message: include a stable top-level `messageId` in `openclaw message --json` output when channel sends return one. (#84191) Thanks @100menotu001.
15+
- Gateway/agents: use an agent's `identity.name` in Gateway agent summaries when `agents.list[].name` is unset, so configured agent labels remain visible in clients. (#84355; refs #57835) Thanks @luoyanglang.
1516
- Plugins/hooks: apply a default 30-second timeout to `before_compaction` and `after_compaction` hooks so a hung plugin handler no longer blocks compaction completion. (#84153)
1617
- Discord: preserve disabled presentation buttons when adapting and rendering Discord message controls. (#84188) Thanks @100menotu001.
18+
- Twitch: add a test-only client-manager registry reset helper so non-isolated Twitch tests can clear cached managers between cases. Fixes #83887. (#84244) Thanks @hclsys.
19+
- Cron: use structured embedded-run denial metadata for isolated scheduled tasks so blocked exec requests fail the job without treating ordinary assistant prose as a denial. (#84067) Thanks @abnershang.
20+
- Cron: keep recovered tool warnings diagnostic for successful scheduled runs so final cron output is delivered instead of being replaced by a post-processing warning. (#84045) Thanks @abnershang.
1721
- Plugins/perf: thread explicit plugin discovery results through `loadBundledCapabilityRuntimeRegistry`, `resolveBundledPluginSources`, and `listChannelCatalogEntries` so callers that already hold a discovery result skip redundant filesystem walks. Thanks @SebTardif.
1822
- harden update restart script creation [AI]. (#84088) Thanks @pgondhi987.
1923
- Docker: keep the bundled Codex plugin in official release image keep lists so the default OpenAI agent harness remains available after Docker pruning. Fixes #83613. (#83626) Thanks @YuanHanzhong.
@@ -29,6 +33,8 @@ Docs: https://docs.openclaw.ai
2933

3034
- Agents: include bounded trajectory queued-writer diagnostics in `pi-trajectory-flush` timeout warnings so flush stalls show pending writes, queued bytes, and append state. Fixes #82961. (#82962) Thanks @galiniliev.
3135
- Agents/subagents: recover stale completion announces by retrying unsupported transcript-wait wakes without transcript waiting and forcing a message-tool handoff when the requester run is already stale. Fixes #83699. (#83700) Thanks @galiniliev.
36+
- Agents/subagents: constrain wildcard subagent target allowlists to configured agents while preserving explicitly listed compatibility targets. Fixes #84040. (#84357) Thanks @joshavant.
37+
- Providers/Anthropic: route Anthropic model refs selected with Claude CLI auth through the Claude CLI runtime so shorthand refs such as `anthropic/opus-4.7` no longer fall back to embedded Anthropic billing. Fixes #84222. (#84374) Thanks @joshavant.
3238
- Agents: honor explicit `models.providers.<id>.timeoutSeconds` values above the default idle watchdog for cloud and self-hosted providers, so long first-token waits no longer fall back at ~120s when the provider timeout is higher. (#83979) Thanks @yujiawei.
3339
- Agents/subagents: skip stale embedded-run wake probes for dormant completion requesters, so late subagent completions go straight to requester-agent/direct handoff instead of producing `reason=no_active_run` queue noise. (#82964) Thanks @galiniliev.
3440
- CLI: retry config snapshot reads after a transient failure so one rejected read no longer poisons later commands in the same process. (#83931) Thanks @honor2030.
@@ -106,6 +112,7 @@ Docs: https://docs.openclaw.ai
106112
- Providers/DeepSeek: normalize MCP tool schemas with `anyOf`/`oneOf` unions before normal and compaction requests reach DeepSeek, preventing union-shaped parameters from being rejected. (#83766) Thanks @TurboTheTurtle.
107113
- Control UI: render live tool progress from session-scoped `session.tool` Gateway events so externally started runs show their tool cards in the active session. (#83734) Thanks @TurboTheTurtle.
108114
- Outbound: resolve send-capable channel plugins from the active runtime registry when the pinned startup registry only has setup metadata. (#83733) Thanks @TurboTheTurtle.
115+
- Discord: preserve streamed reply previews when recovered tool-warning finals are delivered before or after the assistant's final reply. (#84169) Thanks @neeravmakwana.
109116
- Control UI: keep the chat delete confirmation popover clamped inside the visible viewport on small screens. (#83804) Thanks @ThiagoCAltoe.
110117
- Browser: enforce current-tab URL allowlist checks for `/act` evaluate/batch actions and `/highlight` routes while leaving tab-management actions unblocked. (#78523)
111118
- CI: require real-behavior-proof verdict markers to come from the ClawSweeper GitHub App before accepting exact-head proof. (#83692)

docs/automation/cron-jobs.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Cron is the Gateway's built-in scheduler. It persists jobs, wakes the agent at t
5151
- Isolated cron runs best-effort close tracked browser tabs/processes for their `cron:<jobId>` session when the run completes, so detached browser automation does not leave orphaned processes behind.
5252
- Isolated cron runs that receive the narrow cron self-cleanup grant can still read scheduler status, a self-filtered list of their current job, and that job's run history, so status/heartbeat checks can inspect their own schedule without gaining broader cron mutation access.
5353
- Isolated cron runs also guard against stale acknowledgement replies. If the first result is just an interim status update (`on it`, `pulling everything together`, and similar hints) and no descendant subagent run is still responsible for the final answer, OpenClaw re-prompts once for the actual result before delivery.
54-
- Isolated cron runs prefer structured execution-denial metadata from the embedded run, then fall back to known final summary/output markers such as `SYSTEM_RUN_DENIED` and `INVALID_REQUEST`, so a blocked command is not reported as a green run.
54+
- Isolated cron runs use structured execution-denial metadata from the embedded run, including node-host `UNAVAILABLE` wrappers whose nested error message starts with `SYSTEM_RUN_DENIED` or `INVALID_REQUEST`, so a blocked command is not reported as a green run while ordinary assistant prose is not treated as a denial.
5555
- Isolated cron runs also treat run-level agent failures as job errors even when no reply payload is produced, so model/provider failures increment error counters and trigger failure notifications instead of clearing the job as successful.
5656
- When an isolated agent-turn job reaches `timeoutSeconds`, cron aborts the underlying agent run and gives it a short cleanup window. If the run does not drain, Gateway-owned cleanup force-clears that run's session ownership before cron records the timeout, so queued chat work is not left behind a stale processing session.
5757
- If an isolated agent-turn stalls before the runner starts or before the first model call, cron records a phase-specific timeout such as `setup timed out before runner start` or `stalled before first model call (last phase: context-engine)`. These watchdogs cover embedded providers and CLI-backed providers before their external CLI process is actually started, and are capped independently from long `timeoutSeconds` values so cold-start/auth/context failures surface quickly instead of waiting for the full job budget.

docs/cli/cron.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,9 @@ If an isolated cron run returns only the silent token (`NO_REPLY` or `no_reply`)
165165

166166
### Structured denials
167167

168-
Isolated cron runs prefer structured execution-denial metadata from the embedded run, then fall back to known denial markers in final output, such as `SYSTEM_RUN_DENIED`, `INVALID_REQUEST`, and approval-binding refusal phrases.
168+
Isolated cron runs use structured execution-denial metadata from the embedded run as the authoritative denial signal. They also honor node-host `UNAVAILABLE` wrappers when the nested structured error message starts with `SYSTEM_RUN_DENIED` or `INVALID_REQUEST`.
169+
170+
Cron does not classify final-output prose or approval-looking refusal phrases as denials unless the embedded run also provides structured denial metadata, so ordinary assistant text is not treated as a blocked command.
169171

170172
`cron list` and run history surface the denial reason instead of reporting a blocked command as `ok`.
171173

docs/gateway/config-agents.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ for provider examples and precedence.
10921092
- `runtime`: optional per-agent runtime descriptor. Use `type: "acp"` with `runtime.acp` defaults (`agent`, `backend`, `mode`, `cwd`) when the agent should default to ACP harness sessions.
10931093
- `identity.avatar`: workspace-relative path, `http(s)` URL, or `data:` URI.
10941094
- `identity` derives defaults: `ackReaction` from `emoji`, `mentionPatterns` from `name`/`emoji`.
1095-
- `subagents.allowAgents`: allowlist of agent ids for explicit `sessions_spawn.agentId` targets (`["*"]` = any; default: same agent only). Include the requester id when self-targeted `agentId` calls should be allowed.
1095+
- `subagents.allowAgents`: allowlist of agent ids for explicit `sessions_spawn.agentId` targets (`["*"]` = any configured target; default: same agent only). Include the requester id when self-targeted `agentId` calls should be allowed.
10961096
- Sandbox inheritance guard: if the requester session is sandboxed, `sessions_spawn` rejects targets that would run unsandboxed.
10971097
- `subagents.requireAgentId`: when true, block `sessions_spawn` calls that omit `agentId` (forces explicit profile selection; default: false).
10981098

docs/gateway/config-tools.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ Experimental built-in tool flags. Default off unless a strict-agentic GPT-5 auto
401401
```
402402

403403
- `model`: default model for spawned sub-agents. If omitted, sub-agents inherit the caller's model.
404-
- `allowAgents`: default allowlist of target agent ids for `sessions_spawn` when the requester agent does not set its own `subagents.allowAgents` (`["*"]` = any; default: same agent only).
404+
- `allowAgents`: default allowlist of target agent ids for `sessions_spawn` when the requester agent does not set its own `subagents.allowAgents` (`["*"]` = any configured target; default: same agent only).
405405
- `runTimeoutSeconds`: default timeout (seconds) for `sessions_spawn` when the tool call omits `runTimeoutSeconds`. `0` means no timeout.
406406
- `announceTimeoutMs`: per-call timeout (milliseconds) for gateway `agent` announce delivery attempts. Default: `120000`. Transient retries can make the total announce wait longer than one configured timeout.
407407
- Per-subagent tool policy: `tools.subagents.tools.allow` / `tools.subagents.tools.deny`.

docs/tools/subagents.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ See [Configuration reference](/gateway/configuration-reference) and
340340
### Allowlist
341341

342342
<ParamField path="agents.list[].subagents.allowAgents" type="string[]">
343-
List of agent ids that can be targeted via explicit `agentId` (`["*"]` allows any). Default: only the requester agent. If you set a list and still want the requester to spawn itself with `agentId`, include the requester id in the list.
343+
List of agent ids that can be targeted via explicit `agentId` (`["*"]` allows any configured target). Default: only the requester agent. If you set a list and still want the requester to spawn itself with `agentId`, include the requester id in the list.
344344
</ParamField>
345345
<ParamField path="agents.defaults.subagents.allowAgents" type="string[]">
346346
Default target-agent allowlist used when the requester agent does not set its own `subagents.allowAgents`.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
2+
import { CLAUDE_CLI_BACKEND_ID, CLAUDE_CLI_MODEL_ALIASES } from "./cli-constants.js";
3+
4+
const DEFAULT_CLAUDE_MODEL_BY_FAMILY: Record<string, string> = {
5+
opus: "claude-opus-4-7",
6+
sonnet: "claude-sonnet-4-6",
7+
};
8+
9+
export type ClaudeCliAnthropicModelRefs = {
10+
selectedRef: string;
11+
runtimeRefs: string[];
12+
rewriteRef?: string;
13+
};
14+
15+
function parseProviderModelRef(
16+
raw: string,
17+
defaultProvider: string,
18+
): { provider: string; model: string; explicitProvider: boolean } | null {
19+
const trimmed = raw.trim();
20+
if (!trimmed) {
21+
return null;
22+
}
23+
const slashIndex = trimmed.indexOf("/");
24+
if (slashIndex <= 0) {
25+
return { provider: defaultProvider, model: trimmed, explicitProvider: false };
26+
}
27+
const provider = trimmed.slice(0, slashIndex).trim();
28+
const model = trimmed.slice(slashIndex + 1).trim();
29+
if (!provider || !model) {
30+
return null;
31+
}
32+
return {
33+
provider: normalizeLowercaseStringOrEmpty(provider),
34+
model,
35+
explicitProvider: true,
36+
};
37+
}
38+
39+
function canonicalizeKnownClaudeCliModelId(modelId: string): string | null {
40+
const trimmed = modelId.trim();
41+
const normalized = normalizeLowercaseStringOrEmpty(trimmed);
42+
if (!normalized) {
43+
return null;
44+
}
45+
if (normalized.startsWith("claude-")) {
46+
return trimmed;
47+
}
48+
const defaultModel = DEFAULT_CLAUDE_MODEL_BY_FAMILY[normalized];
49+
if (defaultModel) {
50+
return defaultModel;
51+
}
52+
const family = CLAUDE_CLI_MODEL_ALIASES[normalized];
53+
if (!family) {
54+
return null;
55+
}
56+
const version = normalized.slice(`${family}-`.length);
57+
if (!version || version === normalized) {
58+
return null;
59+
}
60+
return `claude-${family}-${version.replaceAll(".", "-")}`;
61+
}
62+
63+
export function resolveClaudeCliAnthropicModelRefs(
64+
raw: string,
65+
): ClaudeCliAnthropicModelRefs | null {
66+
const parsed = parseProviderModelRef(raw, "anthropic");
67+
if (!parsed) {
68+
return null;
69+
}
70+
if (parsed.provider !== "anthropic" && parsed.provider !== CLAUDE_CLI_BACKEND_ID) {
71+
return null;
72+
}
73+
74+
const selectedRef = `anthropic/${parsed.model}`;
75+
const runtimeRefs = new Set<string>([selectedRef]);
76+
const canonicalModelId = canonicalizeKnownClaudeCliModelId(parsed.model);
77+
if (!parsed.explicitProvider && !canonicalModelId) {
78+
return null;
79+
}
80+
const rewriteRef =
81+
canonicalModelId || parsed.provider === CLAUDE_CLI_BACKEND_ID
82+
? `anthropic/${canonicalModelId ?? parsed.model}`
83+
: undefined;
84+
if (rewriteRef) {
85+
runtimeRefs.add(rewriteRef);
86+
}
87+
88+
return {
89+
selectedRef,
90+
runtimeRefs: [...runtimeRefs],
91+
...(rewriteRef ? { rewriteRef } : {}),
92+
};
93+
}
94+
95+
export function resolveKnownAnthropicModelRef(raw?: string): string | null {
96+
if (!raw) {
97+
return null;
98+
}
99+
const trimmed = raw.trim();
100+
if (!trimmed) {
101+
return null;
102+
}
103+
return resolveClaudeCliAnthropicModelRefs(trimmed)?.rewriteRef ?? trimmed;
104+
}

0 commit comments

Comments
 (0)