@anythingai/teleprompt 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/testing.d.ts CHANGED
@@ -1,26 +1,7 @@
1
- import { P as PromptContext, a as PromptSection } from './types--sRnfw6Q.js';
1
+ import { P as PromptContext, a as PromptSection } from './types-ow-XbrO7.js';
2
2
 
3
- /**
4
- * Create a minimal PromptContext for testing.
5
- * All fields have sensible defaults that can be overridden.
6
- *
7
- * @example
8
- * ```ts
9
- * const ctx = mockContext({ flags: { myFlag: true } });
10
- * const output = mySection.render(ctx);
11
- * ```
12
- */
13
- declare function mockContext<TFlags extends Record<string, boolean> = Record<string, boolean>, TVars extends Record<string, unknown> = Record<string, unknown>>(overrides?: Partial<PromptContext<TFlags, TVars>>): PromptContext<TFlags, TVars>;
14
- /**
15
- * Render a single section in isolation with a mock context.
16
- * Respects the section's `when` guard — returns `null` if excluded.
17
- *
18
- * @example
19
- * ```ts
20
- * const output = renderSection(mySection, { flags: { enabled: true } });
21
- * expect(output).toContain('expected text');
22
- * ```
23
- */
24
- declare function renderSection<TCtx extends PromptContext<Record<string, boolean>, Record<string, unknown>>>(section: PromptSection<TCtx>, contextOverrides?: Partial<TCtx>): string | null;
3
+ declare function mockContext<TFlags extends Record<string, boolean> = Record<string, boolean>, TVars extends object = Record<string, unknown>>(overrides?: Partial<PromptContext<TFlags, TVars>>): PromptContext<TFlags, TVars>;
4
+ /** Renders a section in isolation. Returns `null` if excluded by `when` guard. */
5
+ declare function renderSection<TCtx extends PromptContext>(section: PromptSection<TCtx>, contextOverrides?: Partial<TCtx>): string | null;
25
6
 
26
7
  export { mockContext, renderSection };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/testing.ts"],"sourcesContent":["import type { PromptContext, PromptSection } from './types';\n\n/**\n * Create a minimal PromptContext for testing.\n * All fields have sensible defaults that can be overridden.\n *\n * @example\n * ```ts\n * const ctx = mockContext({ flags: { myFlag: true } });\n * const output = mySection.render(ctx);\n * ```\n */\nexport function mockContext<\n TFlags extends Record<string, boolean> = Record<string, boolean>,\n TVars extends Record<string, unknown> = Record<string, unknown>,\n>(overrides?: Partial<PromptContext<TFlags, TVars>>): PromptContext<TFlags, TVars> {\n return {\n flags: {} as TFlags,\n vars: {} as TVars,\n ...overrides,\n };\n}\n\n/**\n * Render a single section in isolation with a mock context.\n * Respects the section's `when` guard — returns `null` if excluded.\n *\n * @example\n * ```ts\n * const output = renderSection(mySection, { flags: { enabled: true } });\n * expect(output).toContain('expected text');\n * ```\n */\nexport function renderSection<\n TCtx extends PromptContext<Record<string, boolean>, Record<string, unknown>>,\n>(section: PromptSection<TCtx>, contextOverrides?: Partial<TCtx>): string | null {\n const ctx = mockContext(contextOverrides) as TCtx;\n if (section.when && !section.when(ctx)) {\n return null;\n }\n return section.render(ctx);\n}\n"],"mappings":";AAYO,SAAS,YAGd,WAAiF;AACjF,SAAO;AAAA,IACL,OAAO,CAAC;AAAA,IACR,MAAM,CAAC;AAAA,IACP,GAAG;AAAA,EACL;AACF;AAYO,SAAS,cAEd,SAA8B,kBAAiD;AAC/E,QAAM,MAAM,YAAY,gBAAgB;AACxC,MAAI,QAAQ,QAAQ,CAAC,QAAQ,KAAK,GAAG,GAAG;AACtC,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,OAAO,GAAG;AAC3B;","names":[]}
1
+ {"version":3,"sources":["../src/testing.ts"],"sourcesContent":["import type { PromptContext, PromptSection } from './types';\n\nexport function mockContext<\n TFlags extends Record<string, boolean> = Record<string, boolean>,\n TVars extends object = Record<string, unknown>,\n>(overrides?: Partial<PromptContext<TFlags, TVars>>): PromptContext<TFlags, TVars> {\n return {\n flags: {} as TFlags,\n vars: {} as TVars,\n ...overrides,\n };\n}\n\n/** Renders a section in isolation. Returns `null` if excluded by `when` guard. */\nexport function renderSection<TCtx extends PromptContext>(\n section: PromptSection<TCtx>,\n contextOverrides?: Partial<TCtx>,\n): string | null {\n const ctx = mockContext(contextOverrides) as TCtx;\n if (section.when && !section.when(ctx)) {\n return null;\n }\n return section.render(ctx);\n}\n"],"mappings":";AAEO,SAAS,YAGd,WAAiF;AACjF,SAAO;AAAA,IACL,OAAO,CAAC;AAAA,IACR,MAAM,CAAC;AAAA,IACP,GAAG;AAAA,EACL;AACF;AAGO,SAAS,cACd,SACA,kBACe;AACf,QAAM,MAAM,YAAY,gBAAgB;AACxC,MAAI,QAAQ,QAAQ,CAAC,QAAQ,KAAK,GAAG,GAAG;AACtC,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,OAAO,GAAG;AAC3B;","names":[]}
@@ -0,0 +1,12 @@
1
+ interface PromptContext<TFlags extends Record<string, boolean> = Record<string, boolean>, TVars extends object = Record<string, unknown>> {
2
+ flags: TFlags;
3
+ vars: TVars;
4
+ }
5
+ interface PromptSection<TCtx extends PromptContext = PromptContext> {
6
+ id: string;
7
+ /** Return `false` to exclude this section from the output. */
8
+ when?: (ctx: TCtx) => boolean;
9
+ render: (ctx: TCtx) => string;
10
+ }
11
+
12
+ export type { PromptContext as P, PromptSection as a };
@@ -0,0 +1,12 @@
1
+ interface PromptContext<TFlags extends Record<string, boolean> = Record<string, boolean>, TVars extends object = Record<string, unknown>> {
2
+ flags: TFlags;
3
+ vars: TVars;
4
+ }
5
+ interface PromptSection<TCtx extends PromptContext = PromptContext> {
6
+ id: string;
7
+ /** Return `false` to exclude this section from the output. */
8
+ when?: (ctx: TCtx) => boolean;
9
+ render: (ctx: TCtx) => string;
10
+ }
11
+
12
+ export type { PromptContext as P, PromptSection as a };
package/llms.txt ADDED
@@ -0,0 +1,183 @@
1
+ # teleprompt
2
+
3
+ Composable, section-based LLM system prompts. Published as `@anythingai/teleprompt`.
4
+
5
+ ## Core Concepts
6
+
7
+ **Section** — a named unit of prompt content with an id and a render function. Return a string to include, `null` to exclude.
8
+
9
+ **PromptBuilder** — composes sections in order. Supports groups, mutual exclusion, forking, and removal.
10
+
11
+ **PromptContext** — typed object with `flags` (booleans) and `vars` (arbitrary data) passed to every section's render function.
12
+
13
+ ## Idiomatic Usage
14
+
15
+ ### Define a context type for your application
16
+
17
+ ```ts
18
+ import { type PromptContext } from "@anythingai/teleprompt";
19
+
20
+ type Flags = { webSearchEnabled: boolean; verbose: boolean };
21
+ type Vars = { userName: string; tasks: Task[] };
22
+ type Ctx = PromptContext<Flags, Vars>;
23
+ ```
24
+
25
+ ### Create sections with the `section()` helper
26
+
27
+ ```ts
28
+ import { section } from "@anythingai/teleprompt";
29
+
30
+ // Static — no context needed, works in any builder
31
+ const guidelines = section("guidelines", () => `Be concise and direct.`);
32
+
33
+ // Dynamic — reads from context
34
+ const identity = section("identity", (ctx: Ctx) =>
35
+ `You are ${ctx.vars.userName}'s assistant.`
36
+ );
37
+
38
+ // Conditional — return null to exclude
39
+ const webSearch = section("web-search", (ctx: Ctx) => {
40
+ if (!ctx.flags.webSearchEnabled) return null;
41
+ return "You have access to web search.";
42
+ });
43
+ ```
44
+
45
+ ### Compose with PromptBuilder
46
+
47
+ ```ts
48
+ import { PromptBuilder } from "@anythingai/teleprompt";
49
+
50
+ const builder = new PromptBuilder<Ctx>()
51
+ .use(identity)
52
+ .use(guidelines)
53
+ .use(webSearch)
54
+ .group("tools", (b) => b.use(bashTool).use(gitTool))
55
+ .useOneOf(hasTasks, noTasks);
56
+
57
+ const prompt = builder.build(ctx);
58
+ const xmlPrompt = builder.build(ctx, { format: "xml" });
59
+ ```
60
+
61
+ ### Fork for variants
62
+
63
+ ```ts
64
+ const base = new PromptBuilder<Ctx>().use(identity).use(guidelines).use(tone);
65
+
66
+ const supportAgent = base.fork().use(escalationPolicy);
67
+ const codeAgent = base.fork().without(tone).use(codingRules);
68
+ ```
69
+
70
+ ## Patterns and Rationale
71
+
72
+ ### Use null returns for conditional sections, not the `when` guard
73
+
74
+ The `section()` helper colocates the condition with the content it guards, making sections self-contained and easier to reason about. The `when` field exists on the raw PromptSection interface for programmatic use cases, but `section()` with null returns is the standard path because it keeps each section's logic in one place.
75
+
76
+ ```ts
77
+ // Preferred — condition and content together
78
+ const verbose = section("verbose", (ctx: Ctx) => {
79
+ if (!ctx.flags.verbose) return null;
80
+ return "Show detailed explanations.";
81
+ });
82
+
83
+ // Avoid — splits the condition from the content it controls
84
+ const verbose: PromptSection<Ctx> = {
85
+ id: "verbose",
86
+ when: (ctx) => ctx.flags.verbose,
87
+ render: () => "Show detailed explanations.",
88
+ };
89
+ ```
90
+
91
+ ### Keep sections small and focused
92
+
93
+ Each section should own one concern. This makes sections independently reusable across builder variants (via `fork`, `without`, `use`) and gives `buildWithMeta` meaningful granularity — you can see exactly which capabilities were included or excluded. A monolithic section that concatenates everything defeats both of these.
94
+
95
+ ```ts
96
+ // Preferred — each concern is a composable unit
97
+ const identity = section("identity", (ctx: Ctx) => `You are ${ctx.vars.userName}'s assistant.`);
98
+ const guidelines = section("guidelines", () => "# Guidelines\n- Be concise.");
99
+ const webSearch = section("web-search", (ctx: Ctx) => {
100
+ if (!ctx.flags.webSearchEnabled) return null;
101
+ return "You can search the web.";
102
+ });
103
+ ```
104
+
105
+ ### Return null rather than empty string for absent content
106
+
107
+ Returning `null` from `section()` signals intentional exclusion — the section is tracked as "excluded" in `buildWithMeta`, which is useful for debugging and observability. An empty string is ambiguous (is it a bug or intentional?) and still occupies a slot in the output.
108
+
109
+ ```ts
110
+ // Preferred — null signals intentional absence, tracked in metadata
111
+ const tools = section("tools", (ctx: Ctx) => {
112
+ if (!ctx.flags.webSearchEnabled) return null;
113
+ return "You can search the web.";
114
+ });
115
+
116
+ // Avoid — empty string is ambiguous and not tracked as excluded
117
+ const tools = section("tools", (ctx: Ctx) =>
118
+ ctx.flags.webSearchEnabled ? "You can search the web." : ""
119
+ );
120
+ ```
121
+
122
+ ### Let the builder handle composition
123
+
124
+ The builder manages section ordering, format wrapping (text vs XML), joining, and metadata tracking. Calling `render` directly on sections bypasses all of this — you lose format support, metadata, and the ability to fork or modify the composition.
125
+
126
+ ```ts
127
+ // Preferred — builder handles joining, format, and metadata
128
+ const prompt = new PromptBuilder<Ctx>().use(identity).use(guidelines).build(ctx);
129
+
130
+ // Avoid — bypasses composition, forking, and metadata tracking
131
+ const prompt = identity.render(ctx) + "\n\n" + guidelines.render(ctx);
132
+ ```
133
+
134
+ ## API Reference
135
+
136
+ ### `section(id, render)`
137
+
138
+ Creates a PromptSection. `render` receives context, returns `string | null`.
139
+
140
+ ### `PromptBuilder<TCtx>`
141
+
142
+ - `.use(section)` — append or replace by id
143
+ - `.useOneOf(...sections)` — first non-empty render wins
144
+ - `.group(id, configure)` — named group (XML wrapper in xml format, transparent in text)
145
+ - `.without(id | section)` — remove by id, searches recursively
146
+ - `.has(id | section)` — check existence
147
+ - `.ids()` — list all section ids
148
+ - `.fork()` — independent deep copy
149
+ - `.build(ctx)` — render to string (text format)
150
+ - `.build(ctx, { format: "xml" })` — render with XML tags
151
+ - `.buildWithMeta(ctx)` — returns `{ prompt, included, excluded }`
152
+
153
+ ### `PromptContext<TFlags, TVars>`
154
+
155
+ ```ts
156
+ interface PromptContext<
157
+ TFlags extends Record<string, boolean>,
158
+ TVars extends object,
159
+ > {
160
+ flags: TFlags;
161
+ vars: TVars;
162
+ }
163
+ ```
164
+
165
+ Both type parameters default to open records, so `new PromptBuilder()` works without a type argument for simple cases.
166
+
167
+ ## Testing
168
+
169
+ ```ts
170
+ import { mockContext, renderSection } from "@anythingai/teleprompt/testing";
171
+
172
+ // Render a single section in isolation
173
+ const output = renderSection(webSearch, { flags: { webSearchEnabled: true } });
174
+
175
+ // Assert on builder metadata
176
+ const { included, excluded } = builder.buildWithMeta(ctx);
177
+ ```
178
+
179
+ ## Output Formats
180
+
181
+ **text** (default) — sections joined with `\n\n`, groups are transparent.
182
+
183
+ **xml** — each section wrapped in `<id>...</id>`, groups wrap children in `<id>...</id>`. Recommended for Claude and Gemini which handle XML-structured prompts well.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anythingai/teleprompt",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Composable, declarative prompt builder for LLM system prompts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -29,19 +29,12 @@
29
29
  }
30
30
  }
31
31
  },
32
- "files": ["dist", "README.md", "LICENSE"],
33
- "scripts": {
34
- "build": "tsup",
35
- "check": "pnpm lint && pnpm typecheck && pnpm test && pnpm publint && pnpm attw",
36
- "lint": "biome check .",
37
- "lint:fix": "biome check --write .",
38
- "typecheck": "tsc --noEmit",
39
- "test": "vitest run",
40
- "test:watch": "vitest",
41
- "publint": "publint",
42
- "attw": "attw --pack . --profile node16",
43
- "prepublishOnly": "pnpm check && pnpm build"
44
- },
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "LICENSE",
36
+ "llms.txt"
37
+ ],
45
38
  "keywords": [
46
39
  "prompt",
47
40
  "llm",
@@ -56,13 +49,9 @@
56
49
  "type": "git",
57
50
  "url": "https://github.com/Create-Inc/teleprompt.git"
58
51
  },
59
- "packageManager": "pnpm@10.30.0+sha512.2b5753de015d480eeb88f5b5b61e0051f05b4301808a82ec8b840c9d2adf7748eb352c83f5c1593ca703ff1017295bc3fdd3119abb9686efc96b9fcb18200937",
60
52
  "engines": {
61
53
  "node": ">=20"
62
54
  },
63
- "pnpm": {
64
- "onlyBuiltDependencies": ["@biomejs/biome", "esbuild"]
65
- },
66
55
  "devDependencies": {
67
56
  "@arethetypeswrong/cli": "^0.17.0",
68
57
  "@biomejs/biome": "^1.9.0",
@@ -71,5 +60,16 @@
71
60
  "tsx": "^4.21.0",
72
61
  "typescript": "^5.7.0",
73
62
  "vitest": "^3.0.0"
63
+ },
64
+ "scripts": {
65
+ "build": "tsup",
66
+ "check": "pnpm lint && pnpm typecheck && pnpm test && pnpm publint && pnpm attw",
67
+ "lint": "biome check .",
68
+ "lint:fix": "biome check --write .",
69
+ "typecheck": "tsc --noEmit",
70
+ "test": "vitest run",
71
+ "test:watch": "vitest",
72
+ "publint": "publint",
73
+ "attw": "attw --pack . --profile node16"
74
74
  }
75
- }
75
+ }
@@ -1,34 +0,0 @@
1
- /**
2
- * The context passed to every section's `when` and `render` functions.
3
- *
4
- * @typeParam TFlags - Shape of the boolean flags object
5
- * @typeParam TVars - Shape of the runtime variables object
6
- */
7
- interface PromptContext<TFlags extends Record<string, boolean> = Record<string, boolean>, TVars extends Record<string, unknown> = Record<string, unknown>> {
8
- /** Boolean flags that control which sections are included and how they render */
9
- flags: TFlags;
10
- /** Runtime data sections can read from (model, mode, integrations, etc.) */
11
- vars: TVars;
12
- }
13
- /**
14
- * A single composable unit of prompt content.
15
- *
16
- * @typeParam TCtx - The prompt context type this section operates on
17
- */
18
- interface PromptSection<TCtx extends PromptContext = PromptContext> {
19
- /** Unique identifier. Used by `use()`, `without()`, and `buildWithMeta()`. */
20
- id: string;
21
- /**
22
- * Guard function. Return `false` to exclude this section from the output.
23
- * If omitted, the section is always included.
24
- */
25
- when?: (ctx: TCtx) => boolean;
26
- /**
27
- * Render the section content. Receives the full prompt context.
28
- * Return an empty string to include nothing (different from `when: false`
29
- * which removes the section entirely including any separator).
30
- */
31
- render: (ctx: TCtx) => string;
32
- }
33
-
34
- export type { PromptContext as P, PromptSection as a };
@@ -1,34 +0,0 @@
1
- /**
2
- * The context passed to every section's `when` and `render` functions.
3
- *
4
- * @typeParam TFlags - Shape of the boolean flags object
5
- * @typeParam TVars - Shape of the runtime variables object
6
- */
7
- interface PromptContext<TFlags extends Record<string, boolean> = Record<string, boolean>, TVars extends Record<string, unknown> = Record<string, unknown>> {
8
- /** Boolean flags that control which sections are included and how they render */
9
- flags: TFlags;
10
- /** Runtime data sections can read from (model, mode, integrations, etc.) */
11
- vars: TVars;
12
- }
13
- /**
14
- * A single composable unit of prompt content.
15
- *
16
- * @typeParam TCtx - The prompt context type this section operates on
17
- */
18
- interface PromptSection<TCtx extends PromptContext = PromptContext> {
19
- /** Unique identifier. Used by `use()`, `without()`, and `buildWithMeta()`. */
20
- id: string;
21
- /**
22
- * Guard function. Return `false` to exclude this section from the output.
23
- * If omitted, the section is always included.
24
- */
25
- when?: (ctx: TCtx) => boolean;
26
- /**
27
- * Render the section content. Receives the full prompt context.
28
- * Return an empty string to include nothing (different from `when: false`
29
- * which removes the section entirely including any separator).
30
- */
31
- render: (ctx: TCtx) => string;
32
- }
33
-
34
- export type { PromptContext as P, PromptSection as a };