EXTENSION for TreeOS
llm-response-formatting
Post-processing layer between the LLM and the user. Hooks into two lifecycle events (beforeResponse and beforeToolCall) to clean up the messy, inconsistent output that language models produce. The goal is that every response reaching the user follows the same formatting conventions regardless of which model generated it. The beforeResponse hook runs a three-stage cleaning pipeline on every AI response. First, emoji stripping: a comprehensive regex covering emoticons, dingbats, transport symbols, flags, supplemental symbols, and variation selectors removes all emoji characters while preserving basic punctuation, arrows, math symbols, and currency signs. Second, whitespace normalization: runs of three or more consecutive newlines collapse to exactly two, preventing the excessive vertical spacing many models produce. Third, filler trimming: a pattern-matched removal of trailing pleasantries that LLMs append reflexively. Phrases like 'Let me know if you need anything else', 'Feel free to ask', 'Hope this helps', and 'Don't hesitate to reach out' are stripped from the end of responses. The beforeToolCall hook fixes tool name mismatches. Some models generate tool calls with underscores (navigate_tree) when the registered tool uses hyphens (navigate-tree). The hook first checks the exact name against the tool registry. If no match is found, it replaces underscores with hyphens and checks again. A successful match silently rewrites the tool name before it reaches MCP dispatch, preventing tool-not-found errors that would otherwise break the conversation flow. The fast path (exact name match) adds zero overhead to correctly-named tool calls.
v1.0.2 by TreeOS Site 0 downloads 3 files 130 lines 5.0 KB published 38d ago
treeos ext install llm-response-formatting
View changelog

Manifest

Requires

  • services: hooks
SHA256: 13147e537792249d7a2be2d3f76ae0a14499190bfb4e2abc96d5637dd47a5ef8

Dependents

1 package depend on this

PackageTypeRelationship
treeos v1.0.1osstandalone

Hooks

Listens To

  • beforeResponse
  • beforeToolCall

Source Code

1// formatting/clean.js
2// Deterministic post-processing for LLM output.
3
4// Emoji ranges: emoticons, dingbats, symbols, transport, flags, supplemental, etc.
5// Keeps basic punctuation, arrows, math symbols, and currency signs.
6const EMOJI_RE = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2702}-\u{27B0}\u{FE00}-\u{FE0F}\u{200D}\u{20E3}\u{E0020}-\u{E007F}]/gu;
7
8/**
9 * Strip emojis from text.
10 */
11export function stripEmojis(text) {
12  return text.replace(EMOJI_RE, "");
13}
14
15/**
16 * Collapse runs of 3+ newlines into 2.
17 */
18export function normalizeWhitespace(text) {
19  return text.replace(/\n{3,}/g, "\n\n");
20}
21
22/**
23 * Remove trailing filler phrases LLMs like to append.
24 * "Let me know if you need anything else!" etc.
25 */
26const FILLER_RE = /\n{1,2}(?:Let me know if (?:you (?:need|have|want|would like)|there(?:'s| is) anything)|Feel free to (?:ask|reach out|let me know)|Hope (?:this|that) helps|Happy to help|Don't hesitate to)[^\n]*$/i;
27
28export function trimFiller(text) {
29  return text.replace(FILLER_RE, "");
30}
31
32/**
33 * Full cleaning pipeline.
34 */
35export function clean(text) {
36  if (!text || typeof text !== "string") return text;
37  let result = text;
38  result = stripEmojis(result);
39  result = normalizeWhitespace(result);
40  result = trimFiller(result);
41  result = result.trim();
42  return result;
43}
44
1import log from "../../seed/log.js";
2import { clean } from "./clean.js";
3
4export async function init(core) {
5  // Clean AI responses (emojis, whitespace, filler)
6  core.hooks.register("beforeResponse", async (data) => {
7    if (data.content && typeof data.content === "string") {
8      data.content = clean(data.content);
9    }
10  }, "llm-response-formatting");
11
12  // Normalize tool names against registered tools.
13  // Some models generate tool calls with underscores (navigate_tree) instead
14  // of hyphens (navigate-tree), or with slight misspellings. This hook finds
15  // the closest matching registered tool name before it reaches MCP.
16  const { resolveTools } = await import("../../seed/tools.js");
17  const { getToolsForMode } = await import("../../seed/modes/registry.js");
18
19  core.hooks.register("beforeToolCall", async (data) => {
20    if (!data.toolName) return;
21    // Try the name as-is first (fast path)
22    const exact = resolveTools([data.toolName]);
23    if (exact.length > 0) return;
24
25    // Try replacing underscores with hyphens
26    const hyphenated = data.toolName.replace(/_/g, "-");
27    const hyphenMatch = resolveTools([hyphenated]);
28    if (hyphenMatch.length > 0) {
29      log.debug("Formatting", `Tool name normalized: ${data.toolName} -> ${hyphenated}`);
30      data.toolName = hyphenated;
31    }
32  }, "llm-response-formatting");
33
34  log.verbose("Formatting", "Response cleaning + tool name normalization active");
35
36  return {};
37}
38
1export default {
2  name: "llm-response-formatting",
3  version: "1.0.2",
4  builtFor: "TreeOS",
5  description:
6    "Post-processing layer between the LLM and the user. Hooks into two lifecycle events " +
7    "(beforeResponse and beforeToolCall) to clean up the messy, inconsistent output that " +
8    "language models produce. The goal is that every response reaching the user follows the " +
9    "same formatting conventions regardless of which model generated it.\n\n" +
10    "The beforeResponse hook runs a three-stage cleaning pipeline on every AI response. First, " +
11    "emoji stripping: a comprehensive regex covering emoticons, dingbats, transport symbols, " +
12    "flags, supplemental symbols, and variation selectors removes all emoji characters while " +
13    "preserving basic punctuation, arrows, math symbols, and currency signs. Second, whitespace " +
14    "normalization: runs of three or more consecutive newlines collapse to exactly two, preventing " +
15    "the excessive vertical spacing many models produce. Third, filler trimming: a pattern-matched " +
16    "removal of trailing pleasantries that LLMs append reflexively. Phrases like 'Let me know if " +
17    "you need anything else', 'Feel free to ask', 'Hope this helps', and 'Don't hesitate to " +
18    "reach out' are stripped from the end of responses.\n\n" +
19    "The beforeToolCall hook fixes tool name mismatches. Some models generate tool calls with " +
20    "underscores (navigate_tree) when the registered tool uses hyphens (navigate-tree). The hook " +
21    "first checks the exact name against the tool registry. If no match is found, it replaces " +
22    "underscores with hyphens and checks again. A successful match silently rewrites the tool " +
23    "name before it reaches MCP dispatch, preventing tool-not-found errors that would otherwise " +
24    "break the conversation flow. The fast path (exact name match) adds zero overhead to " +
25    "correctly-named tool calls.",
26
27  needs: {
28    services: ["hooks"],
29  },
30
31  optional: {},
32
33  provides: {
34    models: {},
35    routes: false,
36    tools: false,
37    jobs: false,
38    orchestrator: false,
39    energyActions: {},
40    sessionTypes: {},
41
42    hooks: {
43      fires: [],
44      listens: ["beforeResponse", "beforeToolCall"],
45    },
46  },
47};
48

Versions

Version Published Downloads
1.0.2 38d ago 0
1.0.0 48d ago 0
0 stars
0 flags
React from the CLI: treeos ext star llm-response-formatting

Comments

Loading comments...

Post comments from the CLI: treeos ext comment llm-response-formatting "your comment"
Max 3 comments per extension. One star and one flag per user.