Get up to date with OpenClaw main#22
Conversation
Merged with gates skipped by maintainer request. Prepared head SHA: 663ac49
* Gateway/Control UI: preserve partial output on abort * fix: finalize abort partial handling and tests (openclaw#15026) (thanks @advaitpaliwal) --------- Co-authored-by: Tyler Yust <TYTYYUST@YAHOO.COM>
…tream_staging # Conflicts: # pnpm-lock.yaml # src/config/types.channels.ts # ui/src/ui/app-render.ts
Fix type errors: string error codes, approveHint on DmPolicy, MarkdownTableMode values, positional resolveTextChunkLimit args, remove env from ChannelAccountSnapshot, cast config objects with identityId past OpenClawConfig's ConvosConfig type. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
The formal models extracted constants ( This check is informational (not blocking merges yet). If this change is intentional, follow up by updating the formal models repo or regenerating the extracted artifacts there. |
Update to OpenClaw main by switching UI timestamps to
|
| private fun applyMainSessionKey(candidate: String?) { | ||
| val trimmed = candidate?.trim().orEmpty() | ||
| if (trimmed.isEmpty()) return | ||
| val trimmed = normalizeMainKey(candidate) ?: return |
There was a problem hiding this comment.
🟢 Low
android/NodeRuntime.kt:295 In applyMainSessionKey, normalizeMainKey returns a non‑null String, so ?: return is dead code and empty input now becomes "main" instead of skipping an update. Suggest restoring the early‑return for blank candidates (e.g., check candidate.isNullOrBlank() before calling) or making normalizeMainKey return null for blank input.
| val trimmed = normalizeMainKey(candidate) ?: return | |
| if (candidate.isNullOrBlank()) return | |
| val trimmed = normalizeMainKey(candidate) |
🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file apps/android/app/src/main/java/ai/openclaw/android/NodeRuntime.kt around line 295:
In `applyMainSessionKey`, `normalizeMainKey` returns a non‑null `String`, so `?: return` is dead code and empty input now becomes `"main"` instead of skipping an update. Suggest restoring the early‑return for blank candidates (e.g., check `candidate.isNullOrBlank()` before calling) or making `normalizeMainKey` return `null` for blank input.
| ]) | ||
| } | ||
|
|
||
| if let fallback = store.defaultCalendarForNewEvents { |
There was a problem hiding this comment.
🟡 Medium
Calendar/CalendarService.swift:120 Suggestion: Ensure calendars are writable. Check allowsContentModifications when resolving a calendar (including store.defaultCalendarForNewEvents); if read‑only, choose another calendar or return a clear error.
- if let fallback = store.defaultCalendarForNewEvents {
+ if let fallback = store.defaultCalendarForNewEvents, fallback.allowsContentModifications {🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file apps/ios/Sources/Calendar/CalendarService.swift around line 120:
Suggestion: Ensure calendars are writable. Check `allowsContentModifications` when resolving a calendar (including `store.defaultCalendarForNewEvents`); if read‑only, choose another calendar or return a clear error.
| switch { | ||
| case strings.EqualFold(tgtLang, "zh-CN"): | ||
| // Keep this prompt as stable as possible; it has lots of tuning baked into the wording. | ||
| return strings.TrimSpace(fmt.Sprintf(zhCNPromptTemplate, srcLabel, tgtLabel, glossaryBlock)) | ||
| case strings.EqualFold(tgtLang, "ja-JP"): | ||
| return strings.TrimSpace(fmt.Sprintf(jaJPPromptTemplate, srcLabel, tgtLabel, glossaryBlock)) |
There was a problem hiding this comment.
🟢 Low
docs-i18n/prompt.go:30 prettyLanguageLabel trims whitespace before matching, but translationPrompt doesn't trim tgtLang before EqualFold checks. Consider using the already-trimmed tgtLabel for template selection to ensure consistency.
| switch { | |
| case strings.EqualFold(tgtLang, "zh-CN"): | |
| // Keep this prompt as stable as possible; it has lots of tuning baked into the wording. | |
| return strings.TrimSpace(fmt.Sprintf(zhCNPromptTemplate, srcLabel, tgtLabel, glossaryBlock)) | |
| case strings.EqualFold(tgtLang, "ja-JP"): | |
| return strings.TrimSpace(fmt.Sprintf(jaJPPromptTemplate, srcLabel, tgtLabel, glossaryBlock)) | |
| switch { | |
| case strings.EqualFold(tgtLabel, "zh-CN") || strings.EqualFold(tgtLabel, "Simplified Chinese"): | |
| // Keep this prompt as stable as possible; it has lots of tuning baked into the wording. | |
| return strings.TrimSpace(fmt.Sprintf(zhCNPromptTemplate, srcLabel, tgtLabel, glossaryBlock)) | |
| case strings.EqualFold(tgtLabel, "ja-JP") || strings.EqualFold(tgtLabel, "Japanese"): | |
| return strings.TrimSpace(fmt.Sprintf(jaJPPromptTemplate, srcLabel, tgtLabel, glossaryBlock)) |
🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file scripts/docs-i18n/prompt.go around lines 30-35:
`prettyLanguageLabel` trims whitespace before matching, but `translationPrompt` doesn't trim `tgtLang` before `EqualFold` checks. Consider using the already-trimmed `tgtLabel` for template selection to ensure consistency.
| if !trimmedToken.isEmpty { | ||
| GatewaySettingsStore.saveGatewayToken(trimmedToken, instanceId: instanceId) | ||
| } | ||
| GatewaySettingsStore.saveGatewayPassword(trimmedPassword, instanceId: instanceId) |
There was a problem hiding this comment.
🟡 Medium
Onboarding/GatewayOnboardingView.swift:220 Password is saved unconditionally, even when empty, which could overwrite a previously stored password. Consider adding an !trimmedPassword.isEmpty check like the token handling above.
| if !trimmedToken.isEmpty { | |
| GatewaySettingsStore.saveGatewayToken(trimmedToken, instanceId: instanceId) | |
| } | |
| GatewaySettingsStore.saveGatewayPassword(trimmedPassword, instanceId: instanceId) | |
| if !trimmedToken.isEmpty { | |
| GatewaySettingsStore.saveGatewayToken(trimmedToken, instanceId: instanceId) | |
| } | |
| if !trimmedPassword.isEmpty { | |
| GatewaySettingsStore.saveGatewayPassword(trimmedPassword, instanceId: instanceId) | |
| } |
🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file apps/ios/Sources/Onboarding/GatewayOnboardingView.swift around lines 220-223:
Password is saved unconditionally, even when empty, which could overwrite a previously stored password. Consider adding an `!trimmedPassword.isEmpty` check like the token handling above.
| if let port = self.manualPortValue(), !(1...65535).contains(port) { | ||
| self.connectStatusText = "Failed: invalid port" | ||
| return | ||
| } |
There was a problem hiding this comment.
🟡 Medium
Onboarding/GatewayOnboardingView.swift:204 Port handling allows empty or non‑numeric input to fall through as 0. Suggest requiring a present, numeric port and validating 1…65535; if non‑empty but unparsable or out of range, show an error and avoid using 0.
| if let port = self.manualPortValue(), !(1...65535).contains(port) { | |
| self.connectStatusText = "Failed: invalid port" | |
| return | |
| } | |
| let port = self.manualPortValue() ?? 0 | |
| guard (1...65535).contains(port) else { | |
| self.connectStatusText = "Failed: invalid port" | |
| return | |
| } |
🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file apps/ios/Sources/Onboarding/GatewayOnboardingView.swift around lines 204-207:
Port handling allows empty or non‑numeric input to fall through as `0`. Suggest requiring a present, numeric port and validating 1…65535; if non‑empty but unparsable or out of range, show an error and avoid using `0`.
|
|
||
| private var isGatewayConnected: Bool { | ||
| let status = self.appModel.gatewayStatusText.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() | ||
| if status.contains("connected") { return true } |
There was a problem hiding this comment.
🟢 Low
Settings/SettingsTab.swift:458 status.contains("connected") also matches "disconnected". Suggest matching the exact state (e.g., guard against "disconnected" or use a word/prefix check), or rely on a boolean connection flag instead of substring matching.
| if status.contains("connected") { return true } | |
| if status.contains("connected") && !status.contains("disconnected") { return true } |
🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file apps/ios/Sources/Settings/SettingsTab.swift around line 458:
`status.contains("connected")` also matches "disconnected". Suggest matching the exact state (e.g., guard against "disconnected" or use a word/prefix check), or rely on a boolean connection flag instead of substring matching.
| } | ||
|
|
||
| private func applyURL(_ url: URL) { | ||
| guard let host = url.host, !host.isEmpty else { return } |
There was a problem hiding this comment.
🟢 Low
Onboarding/GatewayOnboardingView.swift:302 applyURL fails silently when url.host is missing, yet applySetupCode still sets "Setup code applied." Suggest returning a success flag (or error) from applyURL and only setting the success message on success; otherwise update setupStatusText to indicate an invalid URL.
🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file apps/ios/Sources/Onboarding/GatewayOnboardingView.swift around line 302:
`applyURL` fails silently when `url.host` is missing, yet `applySetupCode` still sets "Setup code applied." Suggest returning a success flag (or error) from `applyURL` and only setting the success message on success; otherwise update `setupStatusText` to indicate an invalid URL.
| ]) | ||
| } | ||
| await self.gateway.sendEvent(event: "agent.request", payloadJSON: json) | ||
| await self.nodeGateway.sendEvent(event: "agent.request", payloadJSON: json) |
There was a problem hiding this comment.
🟡 Medium
Model/NodeAppModel.swift:620 sendEvent silently returns when channel is nil, so this call may succeed without actually sending anything. Consider checking gateway connection state before calling, or having sendEvent throw when the channel is unavailable.
🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file apps/ios/Sources/Model/NodeAppModel.swift around line 620:
`sendEvent` silently returns when `channel` is `nil`, so this call may succeed without actually sending anything. Consider checking gateway connection state before calling, or having `sendEvent` throw when the channel is unavailable.
| fun setGatewayToken(value: String) { | ||
| prefs.edit { putString("gateway.manual.token", value) } | ||
| _gatewayToken.value = value | ||
| } |
There was a problem hiding this comment.
🟢 Low
android/SecurePrefs.kt:150 Consider trimming the value in setGatewayToken for consistency with setDisplayName, setManualHost, etc. Currently _gatewayToken.value stores untrimmed input, but loadGatewayToken() trims it at line 161.
| fun setGatewayToken(value: String) { | |
| prefs.edit { putString("gateway.manual.token", value) } | |
| _gatewayToken.value = value | |
| } | |
| fun setGatewayToken(value: String) { | |
| val trimmed = value.trim() | |
| prefs.edit { putString("gateway.manual.token", trimmed) } | |
| _gatewayToken.value = trimmed | |
| } |
🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file apps/android/app/src/main/java/ai/openclaw/android/SecurePrefs.kt around lines 150-153:
Consider trimming the `value` in `setGatewayToken` for consistency with `setDisplayName`, `setManualHost`, etc. Currently `_gatewayToken.value` stores untrimmed input, but `loadGatewayToken()` trims it at line 161.
| private func isBackgroundRestricted(_ command: String) -> Bool { | ||
| command.hasPrefix("canvas.") || command.hasPrefix("camera.") || command.hasPrefix("screen.") | ||
| command.hasPrefix("canvas.") || command.hasPrefix("camera.") || command.hasPrefix("screen.") || | ||
| command.hasPrefix("talk.") |
There was a problem hiding this comment.
🟢 Low
Model/NodeAppModel.swift:677 The error message in handleInvoke says "canvas/camera/screen commands require foreground" but now talk. is also restricted. Consider updating the error message to include "talk".
🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file apps/ios/Sources/Model/NodeAppModel.swift around line 677:
The error message in `handleInvoke` says "canvas/camera/screen commands require foreground" but now `talk.` is also restricted. Consider updating the error message to include "talk".

tl;dr