Skip to content

Character-truncation helper (s.slice(0, max-1) + "…") is duplicated in 4 modules #90

Description

@Deepam02

Problem

The same "truncate a string to N chars with an ellipsis" logic is reimplemented in four places, each as a local helper or inline expression:

  • packages/agentctx/src/profile/detect.ts:299clip(body):
    return body.length <= BODY_MAX_CHARS ? body : `${body.slice(0, BODY_MAX_CHARS - 1)}…`;
  • packages/agentctx/src/extract/ingest.ts:221clampTitle(text) (collapses whitespace first, then the same truncation):
    return oneLine.length <= TITLE_MAX_CHARS ? oneLine : `${oneLine.slice(0, TITLE_MAX_CHARS - 1)}…`;
  • packages/agentctx/src/hooks/post-tool-use.ts:208clamp(text, max):
    return text.length <= max ? text : `${text.slice(0, max - 1)}…`;
  • packages/agentctx/src/hooks/pre-compact.ts:33 — inlined:
    lastPrompt.length > PROMPT_EXCERPT_MAX_CHARS ? `${lastPrompt.slice(0, PROMPT_EXCERPT_MAX_CHARS)}…` : lastPrompt

Note these aren't even fully consistent: three reserve a char for the ellipsis (max - 1) so the result length stays ≤ max, but the pre-compact.ts copy slices at max and then appends , yielding max + 1 chars. (This is distinct from the token-based truncateToTokens in hooks/tokens.ts, which should stay as-is.)

What done looks like

  • A single shared char-truncation helper, e.g. truncateChars(text: string, maxChars: number): string, in a dependency-free util module.
  • clip, clamp, and the pre-compact.ts inline expression call it; clampTitle keeps its whitespace-collapse step and then calls it.
  • All four sites produce a result of length ≤ maxChars (fixing the off-by-one in pre-compact.ts).
  • npm run check stays green; a small unit test covers the boundary (exact length, length+1).

Scope: a small, self-contained refactor with no architectural impact.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions