feat(hooks): add ACP turn transcript save hook#89154
Conversation
|
Thanks for the contribution. ClawSweeper proposes closing this for now: the implementation may be reasonable, but passing review and proof does not establish that OpenClaw should add this product surface. Close as unconfirmed product direction: the branch appears technically coherent and current main lacks this ACP transcript-save hook, but it adds a new internal hook/API contract and ACP save-ordering semantics without maintainer sponsorship. Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. This is a proposal only until the separate default-off apply policy is enabled and all live maintainer-signal checks pass. A maintainer can sponsor the direction, request a narrower version, or apply Review detailsBest possible solution: Close unless a maintainer sponsors this hook contract; if sponsored, reopen or refresh with explicit event/order acceptance and green current-head validation. Do we have a high-confidence way to reproduce the issue? Not applicable: this is a feature/API PR, not a bug report; source inspection shows current main lacks the hook and the PR body includes terminal proof for the new behavior. Is this the best way to solve the issue? Unclear as a product direction: the implementation is coherent, but the new event contract and ACP save ordering need maintainer sponsorship before release. Security review: Security review cleared: No concrete security or supply-chain concern was found in the reviewed hook, transcript persistence, docs, test fixture, script, and incidental formatting changes. AGENTS.md: found and applied where relevant. What I checked:
Likely related people:
Codex review notes: model internal, reasoning high; reviewed against 99551c499b01. |
9db27aa to
2e6e45e
Compare
|
ClawSweeper: please re-review this head. The previous append-evidence finding was addressed by preserving the append API |
…outcome-hook # Conflicts: # extensions/memory-core/src/memory/manager-fts-state.test.ts # scripts/plugin-sdk-surface-report.mjs # src/agents/agent-command.live-model-switch.test.ts # src/agents/agent-command.ts # src/agents/command/attempt-execution.cli.test.ts # src/agents/command/attempt-execution.ts # src/agents/embedded-agent-runner/run/llm-idle-timeout.test.ts # src/commands/agent.acp.test.ts # src/commands/agent.test.ts # src/gateway/server-discovery-runtime.test.ts # src/gateway/session-utils.ts # src/proxy-capture/store.sqlite.test.ts # ui/src/ui/views/workboard.ts
…outcome-hook # Conflicts: # extensions/slack/src/monitor/send.runtime.ts # scripts/plugin-sdk-surface-report.mjs # src/agents/agent-tools.schema.test.ts # src/commands/onboard-channels.e2e.test.ts
…outcome-hook # Conflicts: # scripts/plugin-sdk-surface-report.mjs # test/scripts/plugin-sdk-surface-report.test.ts
|
@vincentkoc @steipete @osolmaz @Drickon ClawSweeper is proposing close here unless a maintainer sponsors the transcript-save hook contract or marks it for human review. From our side, we still think this hook adds meaningful functionality: it exposes whether ACP transcript persistence actually saved, skipped, or failed, which is useful for integrations and diagnostics that care about durable turn capture rather than just turn completion. What would you prefer we do with this PR?
Happy to rebase and clean up current-head CI once the direction is clear; the main question seems to be product/API ownership and ACP save-ordering acceptance rather than a concrete code blocker. |
|
This pull request has been automatically marked as stale due to inactivity. |
|
Closing this for now: it adds a new core hook/API surface plus transcript-save ordering semantics without maintainer sponsorship. The broader lifecycle-hook direction remains in #43454. Happy to reconsider a focused replacement if maintainers explicitly sponsor the event name, payload, ordering, and compatibility contract. Thanks for doing the split and proof work here. |
Summary
Adds a separate
agent:turn:transcript:saveinternal hook event for the ACP turn transcript save phase. This PR is scoped to transcript-save durability outcomes and does not include the siblingagent:turn:endlifecycle hook from #89152.Current implementation
agent:turn:transcript:saveevent typing, validation, and docs with explicitsaved,skipped, andfailedoutcomes.saveOutcome: savedonly when the transcript append path reports a fresh durable append; no callback, declined boundaries, idempotency replays, blocked writes, empty turns, and save failures become non-saved outcomes.appendedflag through the user-turn transcript wrapper so replay/no-op writes are not counted as save evidence.process.env, and noServer WebSocket test servers set an explicit preauthmaxPayload.Real behavior proof
agent:turn:transcript:saveonly after transcript persistence reportssaveOutcome: saved; also verifies idempotency replay is not counted as a fresh save./Users/mantis/Projects/openclaw-pr-turn-save, branchfeat/agent-turn-save-outcome-hook, head4a7985a37c89030d877f1145d344dacf9d3436cc.OPENCLAW_STATE_DIR, installed a managed internal hook withHOOK.md+handler.js, loaded it throughloadInternalHooks, ranAcpSessionManager.runTurnfrom source with anonBeforeTurnSaveHookthat calls the realpersistAcpTurnTranscript, then read both the hook log and transcript JSONL.agent:turn:transcript:saveevent withsuccess: trueandsaveOutcome: saved, and the corresponding transcript file contained the persisted user and assistant messages. The idempotency replay regression now returnssaveOutcome: skipped/saveSkipReason: no_transcript_writeand leaves the transcript at one user message.Validation
node scripts/test-projects.mjs 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— passed 5 Vitest shards in 33.76s.node scripts/test-projects.mjs src/gateway/server-discovery-runtime.test.ts src/gateway/server.plugin-node-capability-auth.test.ts src/gateway/server.preauth-hardening.test.ts— passed 1 Vitest shard in 41.59s.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/auto-reply/reply/dispatch-acp.ts src/auto-reply/reply/dispatch-acp.test.ts src/auto-reply/reply/dispatch-from-config.test.ts src/auto-reply/reply/dispatch-acp-transcript.runtime.ts src/agents/agent-command.ts src/agents/agent-command.live-model-switch.test.ts src/agents/command/attempt-execution.ts src/agents/command/attempt-execution.cli.test.ts src/commands/agent.acp.test.ts src/commands/agent.test.ts src/sessions/user-turn-transcript.ts— passed.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/auto-reply/reply/dispatch-acp.ts src/auto-reply/reply/dispatch-acp.test.ts src/auto-reply/reply/dispatch-from-config.test.ts src/auto-reply/reply/dispatch-acp-transcript.runtime.ts src/agents/agent-command.ts src/agents/agent-command.live-model-switch.test.ts src/agents/command/attempt-execution.ts src/agents/command/attempt-execution.cli.test.ts src/commands/agent.acp.test.ts src/commands/agent.test.ts src/sessions/user-turn-transcript.ts src/gateway/server-discovery-runtime.test.ts src/gateway/server.plugin-node-capability-auth.test.ts src/gateway/server.preauth-hardening.test.ts— passed.pnpm tsgo:core:test— passed.git diff --check origin/main...HEAD && git diff --check— passed.Related
Related #37833
Sibling to #89152
Split from #71399
Latest head refresh (2026-06-22)
Current head:
bbc4673b17f175529b491e534b600d79f2df2a8bMerged current
origin/main(3ff59df960) into the PR branch, resolved Plugin SDK surface report/test conflicts against the merged hook surface, and aligned the slash-command browser-import expectation with the current shared-registry import order.Validation on the current head:
node scripts/test-projects.mjs 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 exec vitest run ui/src/ui/chat/slash-commands.browser-import.test.ts test/scripts/plugin-sdk-surface-report.test.tsObserved results:
Limitations: the original source-built transcript-save proof harness was not present in this worktree during this refresh, so I did not rerun live transcript-save behavior proof on this head; the prior source-built proof remains from the earlier proof head.