Skip to content

fix(commands): preserve multiline args after slash command head#79174

Closed
hclsys wants to merge 1 commit into
openclaw:mainfrom
hclsys:fix/normalize-command-body-multiline-args-79155
Closed

fix(commands): preserve multiline args after slash command head#79174
hclsys wants to merge 1 commit into
openclaw:mainfrom
hclsys:fix/normalize-command-body-multiline-args-79155

Conversation

@hclsys

@hclsys hclsys commented May 8, 2026

Copy link
Copy Markdown

Problem

`normalizeCommandBody()` truncated everything after the first newline when normalizing a slash command, so a message like:

```text
/some-command
first line of payload
second line of payload
```

only delivered `first line of payload` as args. The remaining lines were silently dropped before downstream command/skill handling.

Root cause

`src/auto-reply/commands-registry-normalize.ts`:
```typescript
const newline = trimmed.indexOf("\n");
const singleLine = newline === -1 ? trimmed : trimmed.slice(0, newline).trim();
// multiline tail was never re-attached — lost at every return path
```

Fix

Capture `multilineTail = trimmed.slice(newline)` before normalization, then re-attach it to the final resolved output at every return path. The command head (first line) is still normalized for alias expansion and bot-mention stripping; the tail passes through verbatim.

Real behavior proof

Behavior or issue addressed: `normalizeCommandBody()` drops multiline args after the slash command head — payload lines 2+ were silently discarded before command dispatch.

Real environment tested: local OpenClaw source checkout on PR branch (`fix/normalize-command-body-multiline-args-79155`), Node 24, running vitest against the changed normalization function.

Exact steps or command run after this patch:
```bash
cd /tmp/openclaw_src
git checkout fix/normalize-command-body-multiline-args-79155
pnpm vitest run src/auto-reply/commands-registry.test.ts
```

Evidence after fix: copied terminal output:
```
Test Files 1 passed (1)
Tests 27 passed (27)
Start at 09:09:14
Duration 412ms
```

The regression test added in this PR asserts:
```typescript
expect(normalizeCommandBody("/btw\nfirst line\nsecond line")).toBe(
"/btw\nfirst line\nsecond line",
);
```
Before this patch, the output was `"/btw"` only (tail dropped). After, the full multiline payload is returned.

Observed result after fix: `normalizeCommandBody("/btw\nfirst line\nsecond line")` returns `"/btw\nfirst line\nsecond line"`. Bot-mention stripping also preserves the tail correctly.

What was not tested: live message delivery through a real channel adapter (Telegram, Discord, Slack) with actual multiline input. The fix is proven at the central normalization function used by all command dispatch paths.

Fixes #79155

@openclaw-barnacle openclaw-barnacle Bot added triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. size: XS 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 8, 2026
@clawsweeper

clawsweeper Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Summary
The PR preserves the multiline tail after the first slash-command line in normalizeCommandBody(), adds normalizer regression tests, and adds an Unreleased changelog entry.

Reproducibility: yes. source-reproducible: current main slices command text at the first newline, while the downstream skill invocation parser can accept multiline args if the tail is preserved. I did not run tests because this was a read-only review.

Real behavior proof
Needs real behavior proof before merge: The PR body supplies copied Vitest output only and explicitly says real channel delivery was not tested. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, ask a maintainer to comment @clawsweeper re-review.

Next step before merge
Contributor real behavior proof is the merge blocker; automation could fix the changelog line, but it cannot supply after-fix proof from the contributor's setup.

Security
Cleared: The diff only touches command normalization, a focused test, and changelog text; it adds no dependency, workflow, secret, permission, or package-resolution risk.

Review findings

  • [P3] Update and move the changelog entry — CHANGELOG.md:11
Review details

Best possible solution:

Land the shared normalizer fix after real command or skill dispatch proof is added, the changelog entry references this PR with contributor credit, and CI is green.

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

Yes, source-reproducible: current main slices command text at the first newline, while the downstream skill invocation parser can accept multiline args if the tail is preserved. I did not run tests because this was a read-only review.

Is this the best way to solve the issue?

Yes. Preserving and reattaching the newline tail in the shared normalizer is the narrow maintainable fix, but merge should wait for real dispatch proof and the changelog correction.

Full review comments:

  • [P3] Update and move the changelog entry — CHANGELOG.md:11
    The added entry references the linked issue rather than this PR, omits the required Thanks @hclsys credit, and is inserted above existing entries. The PR changelog gate requires a PR-linked added line at the end of the active section with contributor attribution for eligible human contributors.
    Confidence: 0.9

Overall correctness: patch is correct
Overall confidence: 0.88

Acceptance criteria:

  • pnpm test src/auto-reply/commands-registry.test.ts
  • Real gateway/channel or command-dispatch proof showing multiline args reach a command or skill handler

What I checked:

Likely related people:

  • steipete: Commit history shows Peter Steinberger added the central command normalizer and skill command base while packaging plugin SDK alias wrappers. (role: introduced command/skill command surface; confidence: medium; commits: 4862d349257a; files: src/auto-reply/commands-registry-normalize.ts, src/auto-reply/skill-commands-base.ts, src/plugin-sdk/command-surface.ts)
  • vincentkoc: Current blame in this checkout attributes the affected normalizer, parser, and adjacent tests to Vincent Koc's recent repository snapshot commit; this is routing context, not fault assignment. (role: recent current-line maintainer; confidence: medium; commits: 0fca66549794; files: src/auto-reply/commands-registry-normalize.ts, src/auto-reply/skill-commands-base.ts, src/auto-reply/commands-registry.test.ts)

Remaining risk / open question:

  • The PR body lacks after-fix proof from a real gateway, channel, or command/skill dispatch path showing multiline args reaching a handler.
  • The new regression coverage is focused on the normalizer only, so runtime integration behavior remains unproven until the contributor supplies proof.

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

…claw#79155)

normalizeCommandBody() discarded everything after the first newline
when normalizing a command like:

  /some-command
  line 1
  line 2

Root cause: singleLine = trimmed.slice(0, newline) dropped the tail
before alias expansion and token dispatch.

Fix: capture multilineTail = trimmed.slice(newline) before normalization,
then re-attach it to the final resolved head at all return paths:
- exact alias match
- unregistered token fallback
- no-args token (acceptsArgs=false) fallback
- resolved canonical + args return

The command head (first line) is still normalized for alias expansion
and bot-mention stripping. The tail passes through verbatim so callers
receive the full multiline payload.

27/27 commands-registry tests pass, including new regression test.

Fixes openclaw#79155
@hclsys

This comment was marked as low quality.

@hclsys

This comment was marked as low quality.

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

Labels

proof: supplied External PR includes structured after-fix real behavior proof. size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression: multiline slash skill arguments are truncated after first newline

1 participant