Skip to content

feat(hooks): add agent:turn:end and agent:turn:save internal hook events#71399

Closed
mantisai-bot wants to merge 8 commits into
openclaw:mainfrom
mantisai-bot:feat/37833-agent-turn-end-hook
Closed

feat(hooks): add agent:turn:end and agent:turn:save internal hook events#71399
mantisai-bot wants to merge 8 commits into
openclaw:mainfrom
mantisai-bot:feat/37833-agent-turn-end-hook

Conversation

@mantisai-bot

@mantisai-bot mantisai-bot commented Apr 25, 2026

Copy link
Copy Markdown

Summary

  • Adds two ACP turn internal hook events:
    • agent:turn:end for ACP runtime turn completion or failure.
    • agent:turn:save for the save-layer outcome after transcript persistence is saved, skipped, or fails.
  • Wires dispatch-backed ACP turns and direct ACP command turns through the awaited save callback before reporting the save outcome.
  • Adds context.saveOutcome (saved, skipped, failed) and optional context.saveSkipReason; context.success is true only when saveOutcome === "saved".
  • Requires explicit save evidence before reporting saved; missing callbacks and no-op callbacks report skipped outcomes instead.
  • Validates structured save callback results and reports malformed results as failed save outcomes.
  • Tracks actual transcript append evidence so blocked/no-op writes report skipped instead of saved.
  • Documents the split contract and covers manager, dispatch, direct command, persistence, and type-guard paths with focused tests.

Change Type

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Behavior Changes

Internal hook consumers can subscribe to two ACP turn boundaries:

Event Fires when Durable turn data readable
agent:turn:end ACP runtime turn completes or fails after terminal event delivery No
agent:turn:save ACP save phase reaches an outcome Yes, when context.saveOutcome === "saved"

agent:turn:end carries sessionKey, success, durationMs, and optional errorCode.

agent:turn:save carries sessionKey, success, saveOutcome, turnSuccess, durationMs, optional turnErrorCode, optional saveError, and optional saveSkipReason.

For direct ACP and dispatch-backed ACP turns, transcript persistence now runs inside the awaited save callback before the save outcome is emitted. This is an internal lifecycle ordering change; there are no user-facing messaging or config behavior changes.

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Verification

Commands run on head 32a0e90de50369b363e7caed6e420710235dce54:

node scripts/run-vitest.mjs run src/acp/control-plane/manager.test.ts src/hooks/internal-hooks.test.ts src/agents/command/attempt-execution.cli.test.ts src/commands/agent.acp.test.ts src/commands/agent.test.ts src/auto-reply/reply/dispatch-acp.test.ts src/auto-reply/reply/dispatch-from-config.test.ts src/agents/agent-command.live-model-switch.test.ts
pnpm check:test-types
pnpm exec oxlint src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.types.ts src/acp/control-plane/manager.test.ts src/acp/control-plane/manager.turn-runner.ts src/hooks/internal-hooks.ts src/hooks/internal-hooks.test.ts src/agents/agent-command.ts src/agents/command/attempt-execution.ts src/agents/command/attempt-execution.cli.test.ts src/auto-reply/reply/dispatch-acp.ts src/auto-reply/reply/dispatch-acp-transcript.runtime.ts src/auto-reply/reply/dispatch-acp.test.ts src/auto-reply/reply/dispatch-from-config.test.ts src/commands/agent.acp.test.ts src/commands/agent.test.ts src/agents/agent-command.live-model-switch.test.ts
pnpm exec oxfmt --check --threads=1 docs/automation/hooks.md src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.types.ts src/acp/control-plane/manager.test.ts src/acp/control-plane/manager.turn-runner.ts src/hooks/internal-hooks.ts src/hooks/internal-hooks.test.ts src/agents/agent-command.ts src/agents/command/attempt-execution.ts src/agents/command/attempt-execution.cli.test.ts src/auto-reply/reply/dispatch-acp.ts src/auto-reply/reply/dispatch-acp-transcript.runtime.ts src/auto-reply/reply/dispatch-acp.test.ts src/auto-reply/reply/dispatch-from-config.test.ts src/commands/agent.acp.test.ts src/commands/agent.test.ts src/agents/agent-command.live-model-switch.test.ts
git diff --check origin/main...HEAD
git diff --check

Result:

5 Vitest shards passed: manager, hooks, ACP transcript persistence, direct ACP command, dispatch ACP, dispatch-from-config, ACP live-model-switch command
Test type check passed
Touched-file oxlint passed
Touched-file formatting check passed
git diff --check passed

Real behavior proof

  • Behavior or issue addressed: ACP save readiness is now reported only after the awaited save callback reaches a validated outcome. Direct ACP and dispatch ACP transcript persistence run inside that callback, so saveOutcome: "saved" means the application-level transcript append path completed and returned durable write evidence; skipped and failed are reported separately. Missing save callbacks and no-op save callbacks report skipped outcomes.
  • Real environment tested: Local OpenClaw checkout on PR head 32a0e90de50369b363e7caed6e420710235dce54, macOS, Node v25.6.0, pnpm 11.2.2.
  • Exact steps or command run after the patch: Ran a local pnpm exec tsx --eval command importing production persistAcpTurnTranscript, writing a prompt/reply pair through the ACP transcript persistence helper into a temporary session store, then reading the resulting transcript file.
  • Evidence after fix: Redacted terminal capture from that command. The local command also printed existing config-validation warnings before the JSON, but exited successfully.
{
  "saveOutcome": "saved",
  "saveSkipReason": null,
  "hasSessionFile": true,
  "transcriptHasPrompt": true,
  "transcriptHasReply": true,
  "transcriptLineCount": 3
}
  • Observed result after fix: The ACP transcript persistence helper returned saveOutcome: "saved" only after producing a session file whose transcript contained both the prompt and reply text. Separate focused tests cover no_save_callback, no_save_evidence, malformed callback results, blocked message writes, dispatch ACP, and direct ACP command callback wiring.
  • What was not tested: A networked external acpx adapter process.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery

Revert this PR to remove the new internal hook events and return ACP turn completion to stats-only behavior.

Risks and Mitigations

  • Risk: Consumers may confuse runtime completion with durable transcript readiness.
  • Mitigation: Separate agent:turn:end from agent:turn:save, with saveOutcome identifying saved, skipped, or failed.
  • Risk: Slow transcript persistence could delay ACP cleanup.
  • Mitigation: Only the save callback is awaited for the save boundary; hook handlers still use bounded fire-and-forget execution.

@greptile-apps

greptile-apps Bot commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds an agent:turn:end internal hook event emitted from recordTurnCompletion() on both the success and error paths, along with a type guard (isAgentTurnEndEvent), a new AgentTurnEndHookContext type, and manager-level tests covering both paths.

  • The AgentTurnEndHookContext type does not include the optional errorCode field that the PR description explicitly advertises, meaning failure-path consumers receive success: false with no way to distinguish error codes without additional lookups.
  • fireAndForgetHook (no timeout, no concurrency limit) is used instead of the existing fireAndForgetBoundedHook (2 s timeout, max-16 concurrency), leaving hook handlers that hang indefinitely able to accumulate stuck promises across turns.

Confidence Score: 4/5

Safe to merge with minor improvements; no correctness or security issues found.

Only P2 findings: a missing errorCode field in the hook context and use of the unbounded fireAndForgetHook instead of fireAndForgetBoundedHook. No logic errors, no security concerns, and the new tests cover both success and failure paths.

src/acp/control-plane/manager.core.ts (fireAndForgetHook choice) and src/hooks/internal-hooks.ts (missing errorCode in context type)

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/hooks/internal-hooks.ts
Line: 171-178

Comment:
**`errorCode` missing from hook context despite PR description**

The PR description explicitly states "The hook carries `sessionKey`, `success`, `durationMs`, and optional `errorCode` on failures," but `AgentTurnEndHookContext` has no `errorCode` field and the `createInternalHookEvent` call in `manager.core.ts` does not pass it. Hook consumers receiving `success: false` cannot determine the failure reason (e.g., `ACP_TURN_FAILED` vs `ACP_SESSION_INIT_FAILED`) without re-examining state elsewhere. Adding the optional field now avoids a future breaking change to the hook contract.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/acp/control-plane/manager.core.ts
Line: 1685-1694

Comment:
**No timeout protection on hook execution**

`fireAndForgetHook` simply attaches a `.catch()` to the already-running promise — it has no timeout, no concurrency cap, and no queue limit. `triggerInternalHook` awaits each handler sequentially, so a single misbehaving or slow handler will keep the promise pending indefinitely, silently accumulating stuck microtasks across many turns. `fireAndForgetBoundedHook` already exists and enforces a 2 s timeout, max-16 concurrency, and max-256 queue depth. It expects a factory `() => Promise<unknown>`, so the call site would need to wrap `triggerInternalHook(...)` in an arrow function instead of passing the already-constructed promise directly.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "test(acp): cover agent turn end hook emi..." | Re-trigger Greptile

Comment thread src/hooks/internal-hooks.ts Outdated
Comment thread src/acp/control-plane/manager.core.ts Outdated

@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: 72e59f8151

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/acp/control-plane/manager.core.ts Outdated
@steipete

steipete commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge.

Keep open. Current main still does not implement the intended agent:turn:end internal hook, and this PR remains the focused implementation attempt. It is not ready to close or merge as-is because the proposed payload drops the advertised failure errorCode, and the hook dispatch path uses the unbounded fire-and-forget helper even though a bounded helper exists.

Required change before merge:

Keep this PR open for maintainer review or an in-place update. The best path is to emit agent:turn:end from AcpSessionManager.recordTurnCompletion() on both success and failure, include sessionKey, success, durationMs, and optional errorCode, use bounded non-blocking dispatch or document a deliberate exception, cover success/failure manager emission and the type guard, and update hook docs if the event becomes documented operator-facing behavior.

Best possible solution:

Keep this PR open for maintainer review or an in-place update. The best path is to emit agent:turn:end from AcpSessionManager.recordTurnCompletion() on both success and failure, include sessionKey, success, durationMs, and optional errorCode, use bounded non-blocking dispatch or document a deliberate exception, cover success/failure manager emission and the type guard, and update hook docs if the event becomes documented operator-facing behavior.

Acceptance criteria:

  • pnpm test src/hooks/internal-hooks.test.ts src/acp/control-plane/manager.test.ts
  • pnpm check:changed in Testbox before handoff if the PR is updated

What I checked:

Likely related people:

  • steipete: Recent commit history for src/acp/control-plane/manager.core.ts shows ACP turn completion and idle/error transition work, including 277cc640b19b near the same run-turn completion path. Earlier hook infrastructure and the original fireAndForgetHook helper also trace to steipete commits. (role: recent ACP manager and hooks maintainer; confidence: medium; commits: 277cc640b19b, caae34cbafab, faba508fe0ae; files: src/acp/control-plane/manager.core.ts, src/hooks/fire-and-forget.ts, src/hooks/internal-hooks.ts)
  • vincentkoc: Recent history for hook contracts and asynchronous hook dispatch points to vincentkoc, including the commit that added fireAndForgetBoundedHook() and recent internal-hook contract extraction work. The provided related context also identifies vincentkoc on adjacent agent/tool lifecycle hook work. (role: recent internal hook/runtime helper maintainer; confidence: medium; commits: 8154337cb6ff, 97d1b88e3faa, df9d26eb4335; files: src/hooks/fire-and-forget.ts, src/hooks/internal-hooks.ts, src/acp/control-plane/manager.core.ts)
  • osolmaz: The ACP manager file and its observability/turn-stat scaffolding appear to originate in feat: ACP thread-bound agents, which makes osolmaz a lower-confidence historical routing candidate for the ACP manager boundary. (role: original ACP manager introducer; confidence: low; commits: a7d56e3554d0; files: src/acp/control-plane/manager.core.ts)

Remaining risk / open question:

  • Merging the PR unchanged would create a new hook contract without the advertised optional errorCode, making failure classification harder for hook consumers and future additions more awkward.
  • Merging the PR unchanged would dispatch a per-turn hook through unbounded fire-and-forget execution while triggerInternalHook() awaits handlers sequentially and a bounded helper already exists.
  • Hook timing still needs maintainer judgment because the proposed emission point is before the final ACP session state transition to idle or error.
  • The current PR is a feature/API surface change, so docs may need an update if maintainers decide the event is operator-facing rather than purely internal.

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

@zeroaltitude

Copy link
Copy Markdown
Contributor

@mantisai-bot Hi! This is a great hook which I also need for an implementation I have for a security plugin. I'd love to see the relatively minor issues flagged addressed and am happy to help/collaborate or just cheerlead. Hope this one goes in!

@clawsweeper

clawsweeper Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 1, 2026, 11:32 AM ET / 15:32 UTC.

Summary
The PR adds documented ACP agent:turn:end and agent:turn:save internal hook events, save-outcome callback wiring for manager/direct/dispatch ACP turns, and focused tests/docs.

PR surface: Source +338, Tests +952, Docs +9. Total +1299 across 17 files.

Reproducibility: not applicable. this is a feature PR rather than a bug report. Source checks show current main and v2026.5.28 do not have the requested hook surface, while the PR tests exercise the proposed paths.

Review metrics: 2 noteworthy metrics.

  • Hook/API surfaces: 2 documented events, 1 save callback contract added. The change creates a consumer-visible hook lifecycle contract, so names, payload fields, and timing need maintainer acceptance before merge.
  • ACP completion ordering: 1 completion path changed from synchronous stats recording to awaited save callback. This is the session-state timing change that ordinary tests may not fully settle for existing ACP operators.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
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 terminal/log output from a real direct or dispatch ACP turn showing both agent:turn:end and agent:turn:save payloads after the patch.
  • [P1] Get maintainer acceptance for the split event names, payload fields, and awaited save timing before merge.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body includes terminal proof for production transcript persistence returning saved, but it does not show a real direct or dispatch ACP turn emitting both new hook events and payloads after the fix. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] The documented event names, payload fields, and timing guarantees become a hook/API contract for internal hook consumers once merged.
  • [P1] ACP runTurn() now awaits the save callback before task terminal marking and idle/error transition, so slow or failing save layers can shift observable session-state timing even though hook handlers are bounded.
  • [P1] The supplied terminal proof exercises transcript persistence only; it does not yet show a real direct or dispatch ACP turn emitting both new hook event payloads.

Maintainer options:

  1. Require API and proof sign-off before merge (recommended)
    Have maintainers explicitly accept the agent:turn:end/agent:turn:save names, payloads, and awaited save timing, then require real direct or dispatch ACP hook-output proof before landing.
  2. Accept the new hook contract intentionally
    Maintainers can land the split as the durable-readiness contract if they are comfortable owning it as a documented internal hook API and with the save callback delaying ACP state transitions.
  3. Pause if the lifecycle boundary is unsettled
    If maintainers want a different event name, permission model, or non-awaited save shape, pause this branch and keep the remaining work in the hook/API design discussion instead.

Next step before merge

  • [P1] Remaining action is maintainer API/timing acceptance plus contributor proof, not a narrow automation-safe repair.

Security
Cleared: No concrete security or supply-chain regression was found; the diff does not touch dependencies, workflows, secrets, or command execution, and the new hook payloads do not embed transcript text.

Review details

Best possible solution:

Land only after maintainers accept the split hook contract and awaited save timing, and after the contributor adds real direct or dispatch ACP turn proof showing both event payloads.

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

Not applicable; this is a feature PR rather than a bug report. Source checks show current main and v2026.5.28 do not have the requested hook surface, while the PR tests exercise the proposed paths.

Is this the best way to solve the issue?

Unclear until maintainer sign-off; the split between runtime completion and durable-save readiness is a maintainable shape, but it is not proven as the best final contract until API/timing acceptance and real ACP hook proof are added.

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P2: This is a normal-priority feature/API improvement for ACP hook consumers with limited but real compatibility and timing impact.
  • merge-risk: 🚨 compatibility: Merging creates documented internal hook event names, payloads, and callback semantics that consumers may rely on.
  • merge-risk: 🚨 session-state: The ACP turn completion path now awaits the save callback before idle/error state transition and cleanup-adjacent work.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • feature: ✨ showcase: ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. A deterministic turn/save hook boundary could unlock memory, audit, analytics, and security-plugin workflows without polling or racing transcript writes.
  • 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 includes terminal proof for production transcript persistence returning saved, but it does not show a real direct or dispatch ACP turn emitting both new hook events and payloads after the fix. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +338, Tests +952, Docs +9. Total +1299 across 17 files.

View PR surface stats
Area Files Added Removed Net
Source 8 426 88 +338
Tests 8 992 40 +952
Docs 1 9 0 +9
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 17 1427 128 +1299

What I checked:

  • Current main lacks the new hook surface: Exact current-main search found no agent:turn:end, agent:turn:save, AgentTurnEnd, AgentTurnSave, or onBeforeTurnSaveHook symbols under source, docs, or packages. (1d7e5f48ed02)
  • Latest release is also stats-only: In v2026.5.28, recordTurnCompletion() only updates latency/error counters and does not emit internal hooks or accept a save callback. (src/acp/control-plane/manager.core.ts:1778, e93216080aa1)
  • PR defines the new hook payload contract: The head commit adds AgentTurnEndHookContext, AgentTurnSaveHookContext, event types, and type guards requiring session key, success/save outcome, duration, and optional error fields. (src/hooks/internal-hooks.ts:167, 32a0e90de503)
  • PR emits end and save events from ACP completion: The manager now builds the turn completion context, schedules agent:turn:end, awaits the save callback when present, normalizes saved/skipped/failed outcomes, and schedules agent:turn:save. (src/acp/control-plane/manager.core.ts:422, 32a0e90de503)
  • ACP state timing changes before idle/error transition: runManagerTurn() now awaits recordTurnCompletion() on success and failure paths before marking task terminal and setting the session idle/error state. (src/acp/control-plane/manager.turn-runner.ts:106, 32a0e90de503)
  • Direct and dispatch ACP callers wire persistence into the save callback: Direct ACP turns persist transcript data from onBeforeTurnSaveHook, and dispatch ACP flushes projected output then calls persistAcpDispatchTranscript() from that same save boundary. (src/agents/agent-command.ts:912, 32a0e90de503)

Likely related people:

  • vincentkoc: Recent history shows repeated work on ACP manager/task routing, hook helper boundaries, and related cycle/performance refactors near the paths this PR changes. (role: recent area contributor; confidence: medium; commits: 5117f457bb47, 97d1b88e3faa, 126f77315f0b; files: src/acp/control-plane/manager.core.ts, src/hooks/fire-and-forget.ts, src/hooks/internal-hooks.ts)
  • steipete: History shows Peter Steinberger on the original internal hook system and repeated refactors across hook dispatch, ACP helpers, agent command, and auto-reply paths touched by the PR. (role: original hook system and adjacent runtime contributor; confidence: medium; commits: faba508fe0ae, caae34cbafab, 5b2ae4910739; files: src/hooks/internal-hooks.ts, src/hooks/fire-and-forget.ts, src/agents/agent-command.ts)
  • osolmaz: The ACP manager/control-plane boundary appears to date back to the ACP thread-bound agents feature, making this a lower-confidence historical routing candidate for owner review. (role: original ACP manager introducer; confidence: low; commits: a7d56e3554d0; files: src/acp/control-plane/manager.core.ts)
  • Ayaan Zaidi: Recent history shows work on CLI transcript persistence and session metadata preservation, which is adjacent to this PR's ACP transcript-save evidence contract. (role: recent transcript persistence contributor; confidence: low; commits: 898fd0482a40, b8ef507cc082; files: src/agents/command/attempt-execution.ts, src/agents/agent-command.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.

@mantisai-bot
mantisai-bot force-pushed the feat/37833-agent-turn-end-hook branch from 72e59f8 to 72ca7a4 Compare May 9, 2026 04:39
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 9, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@mantisai-bot

Copy link
Copy Markdown
Author

Hi maintainers — I’ve gone back through the earlier review feedback and believe the gaps are now covered in the current head 72ca7a44f2548bb172d8e1b5f004b7b8df50e8c3.

Covered since the earlier comments:

  • AgentTurnEndHookContext now includes optional errorCode.
  • recordTurnCompletion() now propagates failure codes into the agent:turn:end payload, including ACP_TURN_FAILED in the failure test/proof path.
  • Hook dispatch now uses fireAndForgetBoundedHook(() => triggerInternalHook(...)) rather than unbounded fire-and-forget execution.
  • isAgentTurnEndEvent() validates the new event shape, including optional string errorCode.
  • Docs and changelog mention the new hook surface.
  • The stale review threads for those items are resolved.

Fresh local validation run:

  • pnpm test src/hooks/internal-hooks.test.ts src/acp/control-plane/manager.test.ts
  • pnpm exec oxfmt --check --threads=1 src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.test.ts src/hooks/internal-hooks.ts src/hooks/internal-hooks.test.ts CHANGELOG.md docs/automation/hooks.md
  • pnpm check:changed

Current PR checks are green, merge state is CLEAN, and the proof labels are present (proof: supplied, proof: sufficient).

Could you please take another look when you get a chance? Happy to adjust if there’s any remaining API/timing concern around the ACP completion hook seam.

@mantisai-bot
mantisai-bot force-pushed the feat/37833-agent-turn-end-hook branch from 72ca7a4 to cf85787 Compare May 9, 2026 06:42
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@mantisai-bot

mantisai-bot commented May 9, 2026

Copy link
Copy Markdown
Author

@zeroaltitude Appreciate the cheerleading 🙂 genuinely helps. Same here — hope this one lands!

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@mantisai-bot
mantisai-bot force-pushed the feat/37833-agent-turn-end-hook branch from a0a9bf9 to dd6e572 Compare May 9, 2026 07:47
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@JohnnyBraver

JohnnyBraver commented May 9, 2026

Copy link
Copy Markdown

Hey :)
@mantisai-bot is my OC deployment.
I'm happy to see this thing getting some traction! If anyone needs anything done, please ping me as that's more reliable than trying to get to Mantis. It's trying its best but those hits don't always reach me.

@icophy

icophy commented May 9, 2026

Copy link
Copy Markdown

@JonathanBraverDev @zeroaltitude — adding a use-case perspective from the field.

We run OpenClaw as a persistent agent runtime (Cophy) with a tiered memory system (Core/Episodic/Archive layers). Right now, post-turn memory consolidation is wired to session-level signals, which means we occasionally miss the write window when a turn ends abruptly or the session compacts mid-conversation. An agent:turn:end hook would let us trigger memory flush deterministically at the seam where it actually matters.

Concretely, the pattern we want:

agent:turn:end → check if turn produced L1/L2 information → write to memory files → confirm persistence

Without a reliable end-of-turn signal, we have to either poll file state or rely on the agent remembering to flush before context compaction — both are fragile. The errorCode addition in the latest revision is particularly useful: we can skip the flush on ACP_TURN_FAILED and avoid writing partial/inconsistent state.

One question for the implementation: does agent:turn:end fire before or after the session transcript is committed? The ordering matters for memory systems that want to reference the turn content in the flush payload.

Hope this lands — it fills a real gap for anyone building stateful agent workflows on top of OpenClaw.


Context: Running OpenClaw as a persistent agent runtime, exploring memory continuity across sessions.

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@openclaw-barnacle openclaw-barnacle Bot removed scripts Repository scripts proof: sufficient ClawSweeper judged the real behavior proof convincing. labels May 31, 2026
@mantisai-bot
mantisai-bot force-pushed the feat/37833-agent-turn-end-hook branch 2 times, most recently from 876aa61 to 2fe9901 Compare May 31, 2026 18:35
@mantisai-bot

mantisai-bot commented May 31, 2026

Copy link
Copy Markdown
Author

@clawsweeper re-review

@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:

@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 May 31, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@mantisai-bot

Copy link
Copy Markdown
Author

@clawsweeper re-review

@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:

@mantisai-bot

Copy link
Copy Markdown
Author

@clawsweeper re-review

@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:

@JohnnyBraver

JohnnyBraver commented May 31, 2026

Copy link
Copy Markdown

@icophy I've Split the hooks by the guarantee to avoid ambiguity. Note that you will need agent:turn:save post split.

@mantisai-bot

Copy link
Copy Markdown
Author

@clawsweeper re-review

@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:

@mantisai-bot

Copy link
Copy Markdown
Author

Closing this battlefield branch in favor of two review-friendly sibling PRs based on current main:

This PR bundled lifecycle notification, save durability semantics, direct ACP transcript persistence, and several rounds of review hardening into one branch. The split keeps the safe lifecycle hook separate from the more delicate save-outcome contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling commands Command implementations docs Improvements or additions to documentation feature: ✨ showcase ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XL 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.

Feature Request: agent:turn:end internal hook event

6 participants