Skip to content

port: upstream v2026.3.24 선별 포팅 (7건)#13

Merged
planfit-alan merged 9 commits intomainfrom
cherry-pick/upstream-manual-port-2026-03-26
Mar 26, 2026
Merged

port: upstream v2026.3.24 선별 포팅 (7건)#13
planfit-alan merged 9 commits intomainfrom
cherry-pick/upstream-manual-port-2026-03-26

Conversation

@planfit-alan
Copy link
Copy Markdown
Collaborator

upstream v2026.3.24에서 7건 수동 포팅

planfit-alan and others added 9 commits March 26, 2026 17:37
)

- Add before_dispatch hook allowing plugins to intercept messages before model dispatch
- Extract sendFinalPayload helper to unify TTS + routing logic
- Preserve delivery semantics (TTS, routed delivery) when hook handles message
- Use canonical hook metadata (normalized conversation id, sender id, channel)

Upstream commits:
- a10d587: fix: preserve before_dispatch delivery semantics (openclaw#50444)
- b497f3c: fix: normalize before_dispatch conversation id

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
 partial)

- Add deliveryContext field to SystemEvent for routing preservation
- Wake interrupted session via heartbeat after restart (requestHeartbeatNow)
- Add retry logic for outbound delivery (2 attempts with 750ms delay)
- Preserve threadId routing through wake path
- Always enqueue wake even when delivery fails

Partial port of upstream 1c9f62f:
- Core: system-events deliveryContext, restart sentinel wake
- Deferred: heartbeat-runner turnSource integration, targets.ts routing updates
  (complex changes, requires more analysis)

Upstream commit:
- 1c9f62f: fix(gateway): restart sentinel wakes session after restart (openclaw#53940)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add resolveFreshestSessionStoreMatchFromStoreKeys to prefer newest updatedAt
- Add resolveFreshestSessionEntryFromStoreKeys wrapper
- Use in sessions.preview for duplicate row handling

Handles case-insensitive and legacy alias keys by sorting duplicates
by updatedAt timestamp and returning the freshest entry.

Upstream commits:
- f48571b: fix: prefer freshest duplicate rows in session loads
- 40f820f: fix: prefer freshest duplicate session rows in reads

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove enqueueDelivery/ackDelivery/failDelivery usage from
server-restart-sentinel.ts as delivery-queue.ts is not yet ported
to our codebase. Keep retry logic but use agentCommand directly.

Resolves build failure.
Wrap individual channel startup in try-catch so one broken channel
(e.g. WhatsApp missing runtime) doesn't block other channels
(e.g. Discord) from starting.

Changes:
- Add try-catch in startChannels loop
- Log per-channel startup errors
- Continue starting remaining channels after failure

Upstream commit:
- 30e80fb: fix: isolate channel startup failures (openclaw#54215)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Implement runBeforeDispatch directly using getHooksForName
- Remove GroupName check (not in our MsgContext)
- Fix TypeScript build errors

Resolves build failures after before_dispatch hook port.
Scope rate-limit cooldowns per model so one 429 no longer blocks every
model on the same auth profile. Replace exponential 1min→1h escalation
with stepped 30s/1min/5min ladder.

Key changes:
- Add cooldownReason and cooldownModel to ProfileUsageStats type
- Implement stepped backoff: 30s → 1min → 5min (was: 1min → 5min → 25min → 60min)
- Add model-aware cooldown bypass in isProfileInCooldown()
- Track model scope when marking auth profile failures
- Pass modelId through markAuthProfileFailure and related calls
- Update isProfileInCooldown calls in model-fallback and pi-embedded-runner to pass forModel

Upstream ref: 8440122
Surface rate limit and overload errors that occur mid-turn (after tool
calls) instead of silently returning an empty response.

Only applies when the assistant produced no valid (non-error) reply text,
so tool-level rate-limit messages don't override a successful turn.

Changes:
- Add isReasoning field to EmbeddedPiRunResult payload type
- Detect mid-turn rate limits in agent-runner-execution.ts when there's
  no valid content (checking for text/media, excluding errors/reasoning)
- Import isRateLimitErrorMessage and isOverloadedErrorMessage
- Replace empty responses with user-facing rate limit message

Note: Skipped upstream's incomplete turn detection in run.ts (detecting
stopReason=toolUse with no payloads) as it requires deep understanding
of our specific agent loop structure and could cause false positives.
The agent-runner-execution.ts check catches the issue at final output.

Upstream ref: 4ae4d1f (partial port)
…artial)

Changes:
- Add hasInternalHookListeners() to check for listeners before cloning
- Add session:patch hook with structuredClone to isolate payload
- Add SessionPatchHookEvent and isSessionPatchEvent() type guard
- Only clone and dispatch when listeners are registered (performance)

Why structuredClone:
Fire-and-forget hooks cannot mutate objects used by the response path.
Deep cloning sessionEntry, patch, and cfg prevents plugin corruption.

Skip model default reasoning guards (6c04ce3, b91374e):
Those patches require agentEntry.reasoningDefault and
modelState.resolveDefaultReasoningLevel() which haven't been ported yet.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@planfit-alan planfit-alan marked this pull request as ready for review March 26, 2026 09:09
@planfit-alan planfit-alan merged commit c614a95 into main Mar 26, 2026
7 of 13 checks passed
@planfit-alan planfit-alan deleted the cherry-pick/upstream-manual-port-2026-03-26 branch March 26, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant