Skip to content

fix(reply): preserve sessions_send external routes#88803

Merged
steipete merged 10 commits into
openclaw:mainfrom
MonkeyLeeT:codex/sessions-send-external-route
Jun 1, 2026
Merged

fix(reply): preserve sessions_send external routes#88803
steipete merged 10 commits into
openclaw:mainfrom
MonkeyLeeT:codex/sessions-send-external-route

Conversation

@MonkeyLeeT

@MonkeyLeeT MonkeyLeeT commented May 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #88044.

  • preserve a target session's persisted external delivery context for internal sessions_send handoffs that enter through the internal webchat surface
  • carry persisted deliveryContext.threadId for inherited external routes so threaded transports stay on the stored thread
  • preserve that inherited external thread in restart-recovery and pending-final delivery contexts
  • keep sessions_send / agent-step handoffs on automatic source delivery instead of forcing message_tool_only, so the inherited routeReply path is the production path
  • keep ordinary webchat turns on their live webchat route, and keep the stale-thread guard for non-inherited routes

Behavior

Before this change, an agent-to-agent sessions_send turn could arrive as internal webchat and then fail to deliver a reply back to the existing Feishu session, even when the target session still had a valid external deliveryContext.

After this change, only sessions_send inter-session handoffs with a persisted deliverable external deliveryContext inherit that external route. If the persisted route has a threadId, dispatch and restart/pending-final recovery preserve it only for that inherited route case. Normal Control UI/webchat turns continue to use their live webchat route, ordinary routed replies still derive thread context from the active turn or thread-scoped session key, and sessions_send no longer requests message_tool_only suppression.

Compatibility / maintainer decision

This PR intentionally treats the target session's persisted external deliveryContext as authoritative for sessions_send inter-session replies that arrive through internal webchat. Maintainers should accept that compatibility behavior before merge: existing sessions with stale stored channel, target, account, or thread metadata can affect live delivery, but the same persisted route is the only durable source tying an internal handoff back to the user's original external conversation. If that persisted-route behavior is not desired, this PR should pause for a different product direction rather than land with a parallel fallback.

Verification

  • node --require ./node_modules/tsx/dist/preflight.cjs --import ./node_modules/tsx/dist/loader.mjs .artifacts/proof/sessions-send-feishu-route-proof.ts
  • node scripts/run-vitest.mjs src/auto-reply/reply/dispatch-from-config.test.ts src/auto-reply/reply/effective-reply-route.test.ts src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts src/agents/openclaw-tools.sessions.test.ts src/agents/tools/agent-step.test.ts
  • pnpm format:check src/auto-reply/reply/dispatch-from-config.ts src/auto-reply/reply/dispatch-from-config.test.ts src/auto-reply/reply/agent-runner.ts src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts
  • git diff --check

Focused regressions on b8fb236c56: sessions_send production gateway params and agent-step handoffs do not include sourceReplyDeliveryMode, inherited route resolution preserves deliveryContext.threadId="thread:om_123", dispatch passes that same thread id to routeReply, unthreaded inherited external routes do not borrow the live internal webchat thread, restart recovery and pending-final replay keep the inherited Feishu thread instead of the live internal webchat thread, and the stale-thread regression still proves ordinary/non-inherited routes do not resurrect a normalized stored thread id.

Real behavior proof

Behavior addressed: sessions_send replies can route through a target session's persisted external delivery context instead of being trapped as internal webchat; inherited external routes also preserve the persisted route thread when present, including restart-recovery and pending-final replay contexts.

Real environment tested: original issue #88044 reports a real OpenClaw 2026.5.27 Feishu/Lark setup with 7 agents, tools.agentToAgent.enabled=true, and tools.sessions.visibility="all". The after-fix proof ran on patched branch b8fb236c56 using that same route shape: target session key agent:B:feishu:B:direct:ou_xxx, persisted deliveryContext.channel="feishu", incoming InputProvenance.kind="inter_session", sourceTool="sessions_send", and live provider/surface/originating channel all webchat. To avoid live credentials in the PR, the proof registered a Feishu outbound adapter and exercised production sessions_send parameter construction, source-reply visibility policy, effective-route resolution, durable external-channel delivery, unthreaded inherited-route dispatch, and restart/pending-final recovery context persistence.

Exact steps or command run after this patch:

node --require ./node_modules/tsx/dist/preflight.cjs --import ./node_modules/tsx/dist/loader.mjs .artifacts/proof/sessions-send-feishu-route-proof.ts
node scripts/run-vitest.mjs src/auto-reply/reply/dispatch-from-config.test.ts src/auto-reply/reply/effective-reply-route.test.ts src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts src/agents/openclaw-tools.sessions.test.ts src/agents/tools/agent-step.test.ts
pnpm format:check src/auto-reply/reply/dispatch-from-config.ts src/auto-reply/reply/dispatch-from-config.test.ts src/auto-reply/reply/agent-runner.ts src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts
git diff --check

Evidence after fix:

{
  "head": "b8fb236c56",
  "productionSessionsSendAgentParams": {
    "sessionKey": "agent:B:feishu:B:direct:ou_xxx",
    "deliver": false,
    "channel": "webchat",
    "lane": "nested:agent:B:feishu:B:direct:ou_xxx",
    "inputProvenance": {
      "kind": "inter_session",
      "sourceTool": "sessions_send",
      "sourceChannel": "webchat"
    },
    "sourceReplyDeliveryMode": "absent"
  },
  "sourceReplyPolicy": {
    "sourceReplyDeliveryMode": "automatic",
    "suppressAutomaticSourceDelivery": false,
    "suppressDelivery": false
  },
  "persistedDeliveryContext": {
    "channel": "feishu",
    "to": "user:ou_123",
    "accountId": "work",
    "threadId": "thread:om_123"
  },
  "effectiveRoute": {
    "channel": "feishu",
    "to": "user:ou_123",
    "accountId": "work",
    "threadId": "thread:om_123",
    "inheritedExternalRoute": true
  },
  "unthreadedInheritedRoute": {
    "liveInternalWebchatThread": "internal-webchat-thread",
    "routeReplyThreadId": "undefined"
  },
  "recoveryContexts": {
    "liveInternalWebchatThread": "internal-webchat-thread",
    "restartRecoveryDeliveryContext": {
      "channel": "feishu",
      "to": "user:ou_123",
      "accountId": "work",
      "threadId": "thread:om_123"
    },
    "pendingFinalDeliveryContext": {
      "channel": "feishu",
      "to": "user:ou_123",
      "accountId": "work",
      "threadId": "thread:om_123"
    }
  },
  "feishuSends": [
    {
      "adapter": "registered feishu outbound.sendText",
      "to": "user:ou_123",
      "accountId": "work",
      "text": "QA-SESSIONS-SEND-FEISHU-PROOF",
      "threadId": "thread:om_123"
    }
  ],
  "observed": "PASS: sessions_send handoff keeps automatic delivery and uses persisted Feishu thread route"
}

Observed result after fix: the latest production sessions_send handoff no longer asks dispatch to suppress automatic source delivery, the visibility policy resolves to automatic, the same route shape from #88044 resolves the final reply route to Feishu with threadId="thread:om_123", durable delivery calls the registered Feishu outbound adapter with that target and proof marker, and restart/pending-final recovery stores the Feishu thread instead of the internal webchat thread.

What was not tested: a fresh live Feishu tenant run against this patched branch was not rerun; the live Feishu evidence remains the original issue's redacted runtime logs, paired here with latest-head production-parameter, route, durable-delivery, and recovery-context proof for the same persisted Feishu route shape.

@openclaw-barnacle openclaw-barnacle Bot added size: S triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels May 31, 2026
@clawsweeper

clawsweeper Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed May 31, 2026, 11:32 PM ET / 03:32 UTC.

Summary
The PR changes sessions_send/agent-step reply routing so internal webchat inter-session handoffs can inherit a target session’s persisted external delivery context and thread id, with focused route, dispatch, recovery, and agent-tool tests.

PR surface: Source +49, Tests +250. Total +299 across 8 files.

Reproducibility: yes. from source and the linked issue logs: current main resolves non-system webchat inter-session handoffs from live origin metadata and blocks ordinary internal webchat turns from routeReply, matching the reported lost Feishu replies. I did not run a fresh live Feishu reproduction in this read-only review.

Review metrics: none identified.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦐 gold shrimp
Patch quality: 🐚 platinum hermit
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted after-fix Feishu/Lark tenant proof, such as terminal logs, copied live output, or screenshots/video that show the reply reaching the original conversation and thread.
  • Confirm in the PR body whether maintainers should accept persisted external deliveryContext as the intended compatibility behavior for existing sessions.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body provides useful after-fix terminal output for the production route shape with a registered Feishu adapter, but not fresh live Feishu/Lark proof; the contributor should add redacted real transport proof and then update the PR body to trigger re-review, or ask a maintainer for @clawsweeper re-review.

Risk before merge

  • [P1] Merging changes sessions_send final replies from internal-webchat handling to persisted external deliveryContext routing for target sessions; stale stored channel, target, account, or thread data can now affect live delivery for existing sessions.
  • [P1] The supplied after-fix proof is useful terminal output against the production route shape with a registered Feishu adapter, but it is not a fresh live Feishu/Lark tenant run on this branch.

Maintainer options:

  1. Require real transport proof before merge (recommended)
    Ask for redacted after-fix Feishu/Lark tenant proof, or equivalent real transport logs/screenshots, showing the routed reply reaches the original external conversation with the preserved thread.
  2. Accept the adapter proof deliberately
    A maintainer can choose to merge with the production-route adapter proof if they accept that it covers core routing but not the external Feishu service boundary.
  3. Pause if persisted-route delivery is not desired
    If maintainers do not want sessions_send replies to inherit target sessions’ stored external routes, this PR should pause for a different product direction rather than land a competing behavior.

Next step before merge

  • [P1] No automated repair lane is appropriate: I found no remaining concrete code defect, but the PR still needs contributor real-behavior proof or maintainer override plus compatibility acceptance.

Security
Cleared: The diff changes core reply routing and tests only; it does not add dependencies, CI/script execution, secrets handling, or new external code execution, and delivery still goes through existing routeReply/send-policy plumbing.

Review details

Best possible solution:

Land the narrow routing fix after maintainers accept the persisted-route compatibility behavior and either receive fresh real Feishu/Lark transport proof or explicitly override that proof gap.

Do we have a high-confidence way to reproduce the issue?

Yes, from source and the linked issue logs: current main resolves non-system webchat inter-session handoffs from live origin metadata and blocks ordinary internal webchat turns from routeReply, matching the reported lost Feishu replies. I did not run a fresh live Feishu reproduction in this read-only review.

Is this the best way to solve the issue?

Yes, the proposed code path is the best narrow owner-boundary fix I found: it extends effective route resolution, dispatch, and recovery contexts instead of adding channel-specific Feishu logic or parsing session keys alone. The remaining issue is proof and upgrade-safety acceptance, not a line-level code defect.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against ebcdb637bb77.

Label changes

Label changes:

  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body provides useful after-fix terminal output for the production route shape with a registered Feishu adapter, but not fresh live Feishu/Lark proof; the contributor should add redacted real transport proof and then update the PR body to trigger re-review, or ask a maintainer for @clawsweeper re-review.
  • remove status: ⏳ waiting on author: Current PR status label is status: 📣 needs proof.

Label justifications:

  • P1: The PR addresses lost user-visible replies in multi-agent Feishu/Lark sessions_send workflows, which is a broken agent/channel workflow affecting real users.
  • merge-risk: 🚨 compatibility: The diff changes how existing persisted session delivery context is used during sessions_send, so upgrades can route replies differently for already-stored sessions.
  • merge-risk: 🚨 message-delivery: The changed route selection can determine whether replies go to Feishu/Lark, an internal webchat route, a stored thread, or no valid provider target.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body provides useful after-fix terminal output for the production route shape with a registered Feishu adapter, but not fresh live Feishu/Lark proof; the contributor should add redacted real transport proof and then update the PR body to trigger re-review, or ask a maintainer for @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +49, Tests +250. Total +299 across 8 files.

View PR surface stats
Area Files Added Removed Net
Source 3 63 14 +49
Tests 5 250 0 +250
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 8 313 14 +299

What I checked:

  • Repository policy read: Read the full root AGENTS.md plus scoped src/agents/AGENTS.md and src/agents/tools/AGENTS.md; the review applied the compatibility-sensitive routing and real-behavior-proof guidance. (AGENTS.md:1, ebcdb637bb77)
  • Current main routes non-system replies from live origin metadata: On current main, resolveEffectiveReplyRoute returns OriginatingChannel/OriginatingTo for non-system providers, so a sessions_send handoff entering as internal webchat keeps the webchat route instead of consulting persisted external delivery context. (src/auto-reply/reply/effective-reply-route.ts:28, ebcdb637bb77)
  • Current main blocks routeReply for ordinary internal webchat turns: Current dispatch treats internal webchat turns without ExplicitDeliverRoute as non-routable, and passes only the active-turn/thread-scoped thread id into routeReply. (src/auto-reply/reply/dispatch-from-config.ts:1403, ebcdb637bb77)
  • PR head inherits persisted external route only for sessions_send internal webchat handoffs: The PR adds a narrow sessions_send inter-session branch that requires an internal current surface, a non-webchat deliverable persisted channel, and a persisted target before returning inheritedExternalRoute with persisted account/thread context. (src/auto-reply/reply/effective-reply-route.ts:49, b8fb236c56c8)
  • PR head routes inherited sessions_send replies through routeReply: The PR treats inherited external routes as explicit delivery routes and passes the inherited route thread id as-is, avoiding fallback to the internal webchat thread for unthreaded persisted routes. (src/auto-reply/reply/dispatch-from-config.ts:1407, b8fb236c56c8)
  • PR head preserves inherited thread context for recovery: resolveReplyRunDeliveryContext now resolves the effective route first and preserves replyRoute.threadId for inherited sessions_send routes before normalizing restart and pending-final delivery context. (src/auto-reply/reply/agent-runner.ts:191, b8fb236c56c8)

Likely related people:

  • Peter Steinberger: git shortlog shows the heaviest history across the touched reply-routing/session files, and recent commits such as 776c8e037ea84018082329aa6a005bcb8a5fd5bd adjusted routed reply runtime boundaries. (role: adjacent owner; confidence: high; commits: 776c8e037ea8, a25922a21f86; files: src/auto-reply/reply/dispatch-from-config.ts, src/auto-reply/reply/route-reply.ts, src/agents/tools/sessions-send-tool.ts)
  • Vincent Koc: Current-main blame on the central reply-routing files points to be1273182eb971f0bdfcdd807ab7b0939e4177ca, and 6c39616ecd473328533a807657dc8c5a01c16817 introduced the internal-webchat routing guard that this PR extends. (role: recent area contributor; confidence: high; commits: be1273182eb9, 6c39616ecd47; files: src/auto-reply/reply/effective-reply-route.ts, src/auto-reply/reply/dispatch-from-config.ts, src/auto-reply/reply/agent-runner.ts)
  • Accunza: Commit 8190cc4d218969bb25ad936213b5319ebfd78415 added the inter-session guard that preserves established external routes when sessions_send arrives as webchat. (role: introduced related invariant; confidence: medium; commits: 8190cc4d2189; files: src/auto-reply/reply/session-delivery.ts, src/auto-reply/reply/session.ts)
  • Andy Ye: Commit 921598442ace4243672d3740fbb3509407aa2f03 recently touched dispatch-from-config.ts to expose inbound reply metadata before dispatch, adjacent to the routing and hook context this PR changes. (role: recent adjacent contributor; confidence: medium; commits: 921598442ace; files: src/auto-reply/reply/dispatch-from-config.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels May 31, 2026
@MonkeyLeeT MonkeyLeeT changed the title [codex] fix(reply): preserve sessions_send external routes fix(reply): preserve sessions_send external routes May 31, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Updated the PR body with #88044's redacted real Feishu/journalctl evidence and kept the after-fix route/dispatch proof tied to the same runtime shape.

@clawsweeper

clawsweeper Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels May 31, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels May 31, 2026
@MonkeyLeeT

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Updated the PR body with patched-branch after-fix proof for the original #88044 route shape. The evidence shows a sessions_send inter-session handoff entering as internal webchat, resolving to the persisted Feishu delivery context, and reaching a registered Feishu outbound adapter with channel="feishu", to="user:ou_123", and accountId="work".

@clawsweeper

clawsweeper Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 1, 2026
@MonkeyLeeT
MonkeyLeeT marked this pull request as ready for review June 1, 2026 00:14

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e095bc4a32

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/auto-reply/reply/effective-reply-route.ts
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 1, 2026
@steipete steipete self-assigned this Jun 1, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 1, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 1, 2026
@MonkeyLeeT

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Addressed the inherited-route thread fallback finding in b8fb236c56.

  • dispatchReplyFromConfig now passes replyRoute.threadId as-is for inherited external routes, leaving it undefined when the persisted external route is unthreaded.
  • Added the requested regression where persisted Feishu deliveryContext has no thread while the live internal webchat context has MessageThreadId="internal-webchat-thread"; routeReply.threadId stays undefined.
  • Updated the PR body with latest-head proof and reran the focused dispatch/route/recovery/sessions tests, formatting check, and git diff --check.

@clawsweeper

clawsweeper Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b8fb236c56

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/auto-reply/reply/agent-runner.ts Outdated
Comment on lines +191 to +194
const replyRoute = resolveEffectiveReplyRoute({
ctx: params.sessionCtx,
entry: params.sessionEntry,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Authorize recovery against the inherited route

When a sessions_send handoff inherits an external route, this helper still runs resolveSourceReplyPolicy() before resolving replyRoute, so the send-policy check uses the live internal webchat channel from resolveSourceReplyPolicy rather than the external channel that dispatch will actually send to. In configs that deny webchat (or default-deny and allow the external channel), live dispatch can still route because dispatch-from-config.ts later checks policy with routeReplyChannel, but restart/pending-final context is never persisted here; a restart during final delivery would then lose the Feishu/Slack/etc. recovery target.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 1, 2026
@steipete
steipete force-pushed the codex/sessions-send-external-route branch from b8fb236 to 52a6b67 Compare June 1, 2026 03:35

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 52a6b67c59

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +412 to +416
params.originatingThreadId ??
resolveRoutedDeliveryThreadId({
ctx: params.ctx,
sessionKey: deliverySessionKey,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid inventing ACP route threads for inherited routes

When a sessions_send handoff inherits an external route that has no stored thread and the ACP hook owns delivery, originatingThreadId should remain absent; this fallback instead pulls MessageThreadId or the thread-scoped session key from the internal/webchat ACP context and sends it as the Feishu/Slack/etc. thread. That can route an otherwise unthreaded persisted external conversation into the wrong thread or fail provider validation, so the ACP routed-delivery path needs to preserve undefined for inherited external routes rather than deriving a source-context thread.

Useful? React with 👍 / 👎.

@steipete

steipete commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Maintainer pass on exact head 52a6b67c592d1cad578798023636997f8b9e6e76:

  • Rebasing/fixups: preserved the external sessions_send route, kept internal sessions_send/agent_step runs in message_tool_only source delivery mode, and threaded inherited route account/thread metadata through reply_dispatch/ACP only when the stored route has a trusted thread source.
  • Local proof: node scripts/run-vitest.mjs src/auto-reply/reply/effective-reply-route.test.ts src/auto-reply/reply/dispatch-from-config.test.ts src/auto-reply/reply/dispatch-acp-delivery.test.ts src/agents/tools/agent-step.test.ts src/agents/openclaw-tools.sessions.test.ts src/agents/tools/sessions.test.ts src/agents/tools/sessions-send-tool.a2a.test.ts passed.
  • Local proof: git diff --check origin/main...HEAD passed.
  • Local proof: .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main passed with no accepted/actionable findings.
  • GitHub proof: exact-head CI is clean, including check-lint, check-test-types, build-artifacts, checks-node-auto-reply-reply-dispatch, checks-node-auto-reply-reply-state-routing, and checks-node-agentic-agents-tools.

Known gap: no live Feishu end-to-end run was performed here; coverage is regression/unit plus CI for the affected dispatch/session surfaces.

@steipete
steipete merged commit 6cb06f5 into openclaw:main Jun 1, 2026
180 of 182 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 1, 2026
* fix(reply): preserve sessions_send external routes

* fix(reply): preserve inherited route thread ids

* fix(reply): keep sessions_send delivery single-owner

* fix(reply): satisfy dispatch route lint

* fix(reply): preserve inherited ACP route metadata

* test(reply): type inherited route event assertions

* test(ci): satisfy current lint rules

* fix(reply): avoid stale inherited route threads

* fix(reply): trust explicit inherited route threads

* fix(reply): require trusted route thread sources

---------

Co-authored-by: Peter Steinberger <[email protected]>
SYU8384 pushed a commit to SYU8384/openclaw that referenced this pull request Jun 3, 2026
* fix(reply): preserve sessions_send external routes

* fix(reply): preserve inherited route thread ids

* fix(reply): keep sessions_send delivery single-owner

* fix(reply): satisfy dispatch route lint

* fix(reply): preserve inherited ACP route metadata

* test(reply): type inherited route event assertions

* test(ci): satisfy current lint rules

* fix(reply): avoid stale inherited route threads

* fix(reply): trust explicit inherited route threads

* fix(reply): require trusted route thread sources

---------

Co-authored-by: Peter Steinberger <[email protected]>
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
* fix(reply): preserve sessions_send external routes

* fix(reply): preserve inherited route thread ids

* fix(reply): keep sessions_send delivery single-owner

* fix(reply): satisfy dispatch route lint

* fix(reply): preserve inherited ACP route metadata

* test(reply): type inherited route event assertions

* test(ci): satisfy current lint rules

* fix(reply): avoid stale inherited route threads

* fix(reply): trust explicit inherited route threads

* fix(reply): require trusted route thread sources

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling extensions: phone-control gateway Gateway runtime merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P1 High-priority user-facing bug, regression, or broken workflow. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: M status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Inter-session (agent-to-agent) messages route to webchat channel instead of original Feishu channel, causing lost replies

2 participants