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

@maelstrom-co/planner-llm

v0.2.1

Published

Reference LLM planner for the Maelstrom engine planner seam: one structured-output chat() call per attempt, with a section-based prompt builder.

Readme

@maelstrom-co/planner-llm

license

📚 Full documentation: https://docs.maelstrom-ai.co/reference/planner-llm/readme/

The reference LLM planner for the Maelstrom engine's planner seam. llmPlanner(options) returns a Stage<LlmPlannerInput, PlannerCandidate> that asks one LLM for the whole candidate in a single structured-output chat() call per attempt, using a TanStack AI adapter. The package also exports the section-based prompt builder the planner uses.


Quickstart

import { geminiText } from '@tanstack/ai-gemini';
import {
  ChartRequestMessage,
  SessionId,
  isOk,
} from '@maelstrom-co/protocol';
import { createEngine } from '@maelstrom-co/engine';
import { llmPlanner } from '@maelstrom-co/planner-llm';

const engine = createEngine({
  planner: llmPlanner({ adapter: geminiText('gemini-2.0-flash') }),
});

const session = SessionId();

const message = ChartRequestMessage({
  sessionId: session,
  request: /* build ChartRequest */,
});

const result = await engine.handle(message);

if (isOk(result) && result.value.type === 'chart_response') {
  // result.value.response is the MaelstromResponse
  console.log(result.value.response.userMessage);
}

Options

interface LlmPlannerOptions {
  /** TanStack AI text adapter. Required. */
  adapter: AnyTextAdapter;
  /** Section-based prompt customization. */
  prompt?: PromptOptions;
  /** Provider-specific options forwarded verbatim to every `chat()` call. */
  modelOptions?: Record<string, unknown>;
}
import { geminiText } from '@tanstack/ai-gemini';
import { llmPlanner } from '@maelstrom-co/planner-llm';

const planner = llmPlanner({ adapter: geminiText('gemini-2.0-flash') });

adapter accepts any TanStack AI text adapter: Gemini, OpenAI, Anthropic, or a custom adapter implementing the same interface. modelOptions is forwarded verbatim to every chat() call, so provider-specific settings (temperature, safety settings, tool config) pass straight through.

llmPlanner(...) validates its options and builds the system prompts once at construction. A bad option, or a misconfigured system-prompt customizer, throws synchronously with Invalid LlmPlannerOptions: ... rather than surfacing later on the first request.


Prompt customization

prompt is section-based. SystemSection and UserSection enumerate the keys available on each side of the prompt. Each section accepts:

  • a string, to replace the default content outright,
  • null, to remove the section,
  • a function (defaultContent) => string, to transform the default content, or
  • { prepend?, append? }, to add text around the default content.

vars substitutes {{name}} placeholders in the prompt text (e.g. assistantName).

See the system prompt guide for a full walkthrough of section keys and customization patterns.

buildPrompt, buildSystemPrompt, and buildUserPrompt are exported for inspecting the exact prompt text a given configuration produces, useful for tests and dry runs.


Retry prompt

The engine's withRetry re-runs the planner with the previous attempt's diagnostics when healing recommends a retry. On that re-run, llmPlanner sends the original user prompt preceded by a structured feedback block summarizing what went wrong; the system prompt is unchanged.

The previous response had issues. Please re-issue the response addressing:

Layout drops:
- instance "calendar-main" at (0,10) size 4x3 exceeds chart bounds (12x8)

Skipped actions:
- Action "expand" on instance "panel-2" had unparseable params: {bad

Original request:
<original user prompt>

Composing

llmPlanner is one Stage, so it composes with the engine's stage combinators like any other. A common pattern is to try a cheaper or narrower planner first and fall back to llmPlanner when that planner defers:

import { pipeline, withFallback } from '@maelstrom-co/engine';
import { llmPlanner } from '@maelstrom-co/planner-llm';

const planner = withFallback(
  pipeline(selectVessels, arrangeLayout),
  llmPlanner({ adapter }),
);

See the engine README's Planners and stages section for the full combinator set.