@anythingai/teleprompt

中文文档
0.3.0发布于 2026/03/26MITTypeScriptESM + CJS零依赖近 30 天下载 1.7万

Composable, declarative prompt builder for LLM system prompts

原始使用文档
文档目录10 节
  1. Quick Start
  2. Sections
  3. Context
  4. Forking
  5. XML Format
  6. Groups
  7. Mutually Exclusive Sections
  8. Builder API
  9. Testing
  10. License

teleprompt

Composable, section-based LLM system prompts.

Each section owns its content and conditional logic. Sections can be reused across prompt variants, conditionally included, and rendered as plain text or XML.

pnpm add @anythingai/teleprompt

Quick Start

import { PromptBuilder, section, type PromptContext } from '@anythingai/teleprompt';

// Define your context shape
type MyFlags = { webSearchEnabled: boolean };
type MyVars = { assistantName: string };
type MyContext = PromptContext<MyFlags, MyVars>;

// Static section — no context needed, no type parameter
const guidelines = section('guidelines', () => `# Guidelines
- Be concise and direct.
- Cite sources when making factual claims.
- Ask for clarification when a request is ambiguous.`);

// Dynamic section — uses context
const identity = section('identity', (ctx: MyContext) =>
  `You are ${ctx.vars.assistantName}, a helpful AI assistant.`
);

// Conditional section — return null to exclude
const webSearch = section('web-search', (ctx: MyContext) => {
  if (!ctx.flags.webSearchEnabled) return null;
  return `You have access to web search. Use it when the user asks about
current events or information that may have changed after your training cutoff.`;
});

// Compose and build
const prompt = new PromptBuilder<MyContext>()
  .use(identity)
  .use(guidelines)
  .use(webSearch)
  .build({
    flags: { webSearchEnabled: true },
    vars: { assistantName: 'Daniel' },
  });

Sections

section(id, render) takes an id and a render function. Return a string to include, null to exclude:

// Always included
const rules = section('rules', () => 'Be helpful and concise.');

// Conditional — null means excluded
const citation = section('citation', (ctx: MyContext) => {
  if (!ctx.flags.citationEnabled) return null;
  return 'Always include citations with links when referencing external sources.';
});

Sections render in the order you call .use(). To reorder, change the call order.

Static sections (no type parameter) work in any builder:

const disclaimer = section('disclaimer', () => 'Responses are not legal advice.');

// Works in any builder regardless of context type
new PromptBuilder<MyContext>().use(disclaimer)
new PromptBuilder<OtherContext>().use(disclaimer)

Context

Sections receive a typed context with boolean flags and arbitrary variables:

type MyFlags = {
  webSearchEnabled: boolean;
  citationEnabled: boolean;
};

type MyVars = {
  assistantName: string;
  language: string;
};

type MyContext = PromptContext<MyFlags, MyVars>;

PromptContext and PromptBuilder have defaults, so the type parameter is optional:

const builder = new PromptBuilder();

Build the context once and pass it to .build(ctx). Every section receives the same object.

Forking

Create variants from a shared base:

const base = new PromptBuilder<MyContext>()
  .use(identity)
  .use(guidelines)
  .use(tone);

// Customer support agent — adds escalation rules
const supportAgent = base.fork()
  .use(escalationPolicy)
  .use(ticketFormat);

// Code assistant — swaps guidelines, drops tone
const codeAssistant = base.fork()
  .without(guidelines)
  .without(tone)
  .use(codingGuidelines)
  .use(outputFormat);

Each fork is independent. Modifying one doesn't affect the others.

XML Format

Both Claude and Gemini recommend structuring prompts with XML tags. Pass { format: 'xml' } to .build() to wrap each section in <id> tags:

builder.build(ctx, { format: 'xml' })

The section id becomes the tag name. Content is left as-is inside the tags.

Groups

Group related sections together. In text mode, groups are transparent. In XML mode, they wrap children in tags:

const prompt = new PromptBuilder<MyContext>()
  .use(identity)
  .group('tools', b => b
    .use(webSearch)
    .use(calculator)
  )
  .use(guidelines)
  .build(ctx, { format: 'xml' });
<identity>
You are Daniel, a helpful AI assistant.
</identity>

<tools>
<web-search>
You have access to web search...
</web-search>

<calculator>
You can evaluate math expressions...
</calculator>
</tools>

<guidelines>
# Guidelines
...
</guidelines>

Groups can be nested:

builder.group('capabilities', b => b
  .group('tools', b => b
    .use(webSearch)
    .use(calculator)
  )
  .group('integrations', b => b
    .use(slack)
    .use(linear)
  )
)

Mutually Exclusive Sections

Use .useOneOf() when exactly one of several sections should render. The first candidate that returns a non-empty string wins:

const hasTasks = section('has-tasks', (ctx: MyContext) => {
  if (ctx.vars.tasks.length === 0) return null;
  return `## Active Tasks\n\n${ctx.vars.tasks.map(t => `- ${t.title}`).join('\n')}`;
});

const noTasks = section('no-tasks', () => '## Active Tasks\n\nNo tasks currently running.');

builder.useOneOf(hasTasks, noTasks);

Builder API

new PromptBuilder<MyContext>()
  .use(section)                      // append (replaces if same id)
  .useOneOf(sectionA, sectionB)      // first match wins
  .group('name', b => b.use(...))    // named group (XML wrapper)
  .without(section)                  // remove by object or string id
  .has(section)                      // check existence
  .ids()                             // list all section ids
  .fork()                            // independent copy
  .build(ctx)                        // render to string
  .build(ctx, { format: 'xml' })     // render with XML tags
  .buildWithMeta(ctx)                // render + { included, excluded }

Testing

import { mockContext, renderSection } from '@anythingai/teleprompt/testing';

// Render a section in isolation
const output = renderSection(webSearch, { flags: { webSearchEnabled: true } });
expect(output).toContain('web search');

// Assert on prompt structure
const { included, excluded } = builder.buildWithMeta(ctx);
expect(included).toContain('web-search');
expect(excluded).toContain('citation');

License

MIT

版本与发布记录

@anythingai/teleprompt 共发布 4 个版本,首次发布于 2026/02/20;过去 12 个月发布了 4 个版本。

版本发布日期距今
0.3.0latest2026/03/267 个月前
0.2.02026/02/288 个月前
0.1.12026/02/208 个月前
0.1.02026/02/208 个月前

关于 @anythingai/teleprompt 的常见问题

@anythingai/teleprompt 是什么?

Composable, declarative prompt builder for LLM system prompts

如何安装 @anythingai/teleprompt?

在项目目录运行 npm install @anythingai/teleprompt,或使用 pnpm add / yarn add / bun add。

@anythingai/teleprompt 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@anythingai/teleprompt 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@anythingai/teleprompt 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@anythingai/teleprompt 可以商用吗?

@anythingai/teleprompt 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@anythingai/teleprompt 的下载量有多少?

根据 npm 官方下载统计,@anythingai/teleprompt 在 2026/10/06 – 2026/11/04 这 30 天内被下载 17,141 次,日均约 571 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@anythingai/teleprompt 还在维护吗?

最新版本 0.3.0 发布于 2026/03/26(7 个月前);至今共发布 4 个版本,其中过去 12 个月发布了 4 个;首次发布于 2026/02/20。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。