npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tool-history-guard

v0.1.1

Published

Tiny validator and safe fixer for AI agent tool-call history.

Readme

tool-history-guard

tool-history-guard is a tiny TypeScript library that validates and safely repairs broken AI tool-call history before you send it to a model API.

This library is built for a common failure mode in agent systems: retries, resume flows, interrupts, and bad message assembly can leave tool-call and tool-result messages out of sync. The result is often a hard API error. This package gives you a focused preflight check without pulling in an agent framework.

What it solves

  • Detects missing tool results
  • Detects orphan tool results
  • Detects result ordering problems
  • Detects duplicate tool results for the same call id
  • Detects malformed tool_call_id / tool_use_id references
  • Applies a few safe structural fixes when enabled

The default adapter understands common OpenAI-style and Anthropic-style message shapes. The API is intentionally small so custom adapters can be added later.

Installation

npm install tool-history-guard

For local development in this repo:

npm install
npm test

Usage

import { fixToolHistory, validateToolHistory } from "tool-history-guard";

const messages = [
  { role: "user", content: "Look up the weather in Dubai." },
  {
    role: "assistant",
    content: "",
    tool_calls: [{ id: "call_1", type: "function", function: { name: "weather" } }],
  },
  {
    role: "tool",
    tool_call_id: "call_1",
    content: "{\"tempC\":31}",
  },
];

const validation = validateToolHistory(messages);
console.log(validation.valid);

const fixed = fixToolHistory(messages, {
  removeOrphanToolResults: true,
});
console.log(fixed.fixedMessages);

Example input / output

1. Valid history

const messages = [
  { role: "user", content: "Search the docs." },
  {
    role: "assistant",
    tool_calls: [{ id: "call_1", type: "function", function: { name: "search" } }],
  },
  { role: "tool", tool_call_id: "call_1", content: "{\"hits\":3}" },
];

validateToolHistory(messages);
// {
//   valid: true,
//   errors: [],
//   warnings: []
// }

2. Orphan tool result

const messages = [
  { role: "tool", tool_call_id: "missing_call", content: "{\"ok\":true}" },
];

validateToolHistory(messages);
// valid === false
// errors[0].code === "tool_result_without_call"

3. Missing tool result

const messages = [
  {
    role: "assistant",
    tool_calls: [{ id: "call_2", type: "function", function: { name: "search" } }],
  },
];

validateToolHistory(messages);
// valid === false
// errors[0].code === "tool_call_without_result"

4. Duplicated tool result

const messages = [
  {
    role: "assistant",
    tool_calls: [{ id: "call_3", type: "function", function: { name: "search" } }],
  },
  { role: "tool", tool_call_id: "call_3", content: "{\"ok\":true}" },
  { role: "tool", tool_call_id: "call_3", content: "{\"ok\":true}" },
];

fixToolHistory(messages);
// valid === true
// warnings include "applied_dedupe_tool_result"

5. Reordered fixed result

const messages = [
  { role: "tool", tool_call_id: "call_4", content: "{\"ok\":true}" },
  {
    role: "assistant",
    tool_calls: [{ id: "call_4", type: "function", function: { name: "search" } }],
  },
];

fixToolHistory(messages);
// fixedMessages[0].role === "assistant"
// fixedMessages[1].role === "tool"

API

validateToolHistory(messages, options?)

Validates message history and returns:

{
  valid: boolean;
  errors: ValidationIssue[];
  warnings: ValidationIssue[];
}

fixToolHistory(messages, options?)

Runs the same validation and applies a small set of safe fixes:

  • Reorder an adjacent misplaced tool result when it clearly matches the next assistant tool-call message
  • Remove an orphan tool-result message when removeOrphanToolResults: true
  • Dedupe identical adjacent tool-result messages

Returns:

{
  valid: boolean;
  errors: ValidationIssue[];
  warnings: ValidationIssue[];
  fixedMessages: Message[];
}

Options

{
  adapter?: HistoryAdapter;
  reorderAdjacentToolResults?: boolean; // default: true
  dedupeToolResults?: boolean; // default: true
  removeOrphanToolResults?: boolean; // default: false
}

Custom adapters

If your stack uses a different message format, pass a small adapter:

import type { HistoryAdapter } from "tool-history-guard";

const adapter: HistoryAdapter = {
  getToolCalls(message) {
    return [];
  },
  getToolResults(message) {
    return [];
  },
};

Limitations

  • The default fixer only performs message-level repairs. It does not rewrite mixed-content messages.
  • It does not invent missing tool results or patch malformed ids.
  • It assumes tool call ids are unique within the history.
  • Duplicate result auto-fix is intentionally conservative and only removes identical adjacent duplicates.
  • Validation focuses on structural correctness, not tool schema correctness or business logic.

Future ideas

  • Provider-specific adapters for stricter OpenAI, Anthropic, and Gemini validation
  • Optional duplicate tool-call id detection
  • More fix strategies for batched tool-result containers
  • A debug formatter for compact issue reports

Author

Arman Aslanyan
LinkedIn: https://www.linkedin.com/in/arman-aslanyan/

Development

npm install
npm run build
npm test