@fastpaca/cria 0.0.1 → 1.1.3

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.
Files changed (113) hide show
  1. package/README.md +118 -121
  2. package/dist/ai-sdk/index.d.ts +68 -0
  3. package/dist/ai-sdk/index.d.ts.map +1 -0
  4. package/dist/ai-sdk/index.js +375 -0
  5. package/dist/ai-sdk/index.js.map +1 -0
  6. package/dist/anthropic/index.d.ts +102 -0
  7. package/dist/anthropic/index.d.ts.map +1 -0
  8. package/dist/anthropic/index.js +281 -0
  9. package/dist/anthropic/index.js.map +1 -0
  10. package/dist/components/index.d.ts +147 -0
  11. package/dist/components/index.d.ts.map +1 -0
  12. package/dist/components/index.js +181 -0
  13. package/dist/components/index.js.map +1 -0
  14. package/dist/components/summary.d.ts +90 -0
  15. package/dist/components/summary.d.ts.map +1 -0
  16. package/dist/components/summary.js +118 -0
  17. package/dist/components/summary.js.map +1 -0
  18. package/dist/components/vector-search.d.ts +70 -0
  19. package/dist/components/vector-search.d.ts.map +1 -0
  20. package/dist/components/vector-search.js +110 -0
  21. package/dist/components/vector-search.js.map +1 -0
  22. package/dist/dsl.d.ts +201 -0
  23. package/dist/dsl.d.ts.map +1 -0
  24. package/dist/dsl.js +320 -0
  25. package/dist/dsl.js.map +1 -0
  26. package/dist/index.d.ts +20 -19
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +18 -19
  29. package/dist/index.js.map +1 -1
  30. package/dist/instrumentation/otel.d.ts +19 -0
  31. package/dist/instrumentation/otel.d.ts.map +1 -0
  32. package/dist/instrumentation/otel.js +102 -0
  33. package/dist/instrumentation/otel.js.map +1 -0
  34. package/dist/jsx/index.d.ts +6 -0
  35. package/dist/jsx/index.d.ts.map +1 -0
  36. package/dist/jsx/index.js +7 -0
  37. package/dist/jsx/index.js.map +1 -0
  38. package/dist/jsx/jsx-dev-runtime.d.ts +2 -0
  39. package/dist/jsx/jsx-dev-runtime.d.ts.map +1 -0
  40. package/dist/jsx/jsx-dev-runtime.js +3 -0
  41. package/dist/jsx/jsx-dev-runtime.js.map +1 -0
  42. package/dist/jsx/jsx-runtime.d.ts +40 -0
  43. package/dist/jsx/jsx-runtime.d.ts.map +1 -0
  44. package/dist/{jsx-runtime.js → jsx/jsx-runtime.js} +14 -14
  45. package/dist/jsx/jsx-runtime.js.map +1 -0
  46. package/dist/memory/chroma/index.d.ts +59 -0
  47. package/dist/memory/chroma/index.d.ts.map +1 -0
  48. package/dist/memory/chroma/index.js +172 -0
  49. package/dist/memory/chroma/index.js.map +1 -0
  50. package/dist/memory/index.d.ts +4 -0
  51. package/dist/memory/index.d.ts.map +1 -0
  52. package/dist/memory/index.js +2 -0
  53. package/dist/memory/index.js.map +1 -0
  54. package/dist/memory/key-value.d.ts +71 -0
  55. package/dist/memory/key-value.d.ts.map +1 -0
  56. package/dist/memory/key-value.js +34 -0
  57. package/dist/memory/key-value.js.map +1 -0
  58. package/dist/memory/postgres.d.ts +71 -0
  59. package/dist/memory/postgres.d.ts.map +1 -0
  60. package/dist/memory/postgres.js +124 -0
  61. package/dist/memory/postgres.js.map +1 -0
  62. package/dist/memory/qdrant/index.d.ts +64 -0
  63. package/dist/memory/qdrant/index.d.ts.map +1 -0
  64. package/dist/memory/qdrant/index.js +136 -0
  65. package/dist/memory/qdrant/index.js.map +1 -0
  66. package/dist/memory/redis.d.ts +70 -0
  67. package/dist/memory/redis.d.ts.map +1 -0
  68. package/dist/memory/redis.js +127 -0
  69. package/dist/memory/redis.js.map +1 -0
  70. package/dist/memory/vector.d.ts +53 -0
  71. package/dist/memory/vector.d.ts.map +1 -0
  72. package/dist/memory/vector.js +2 -0
  73. package/dist/memory/vector.js.map +1 -0
  74. package/dist/openai/index.d.ts +73 -0
  75. package/dist/openai/index.d.ts.map +1 -0
  76. package/dist/openai/index.js +306 -0
  77. package/dist/openai/index.js.map +1 -0
  78. package/dist/render.d.ts +44 -40
  79. package/dist/render.d.ts.map +1 -1
  80. package/dist/render.js +174 -148
  81. package/dist/render.js.map +1 -1
  82. package/dist/renderers/markdown.d.ts +3 -0
  83. package/dist/renderers/markdown.d.ts.map +1 -0
  84. package/dist/renderers/markdown.js +43 -0
  85. package/dist/renderers/markdown.js.map +1 -0
  86. package/dist/renderers/shared.d.ts +82 -0
  87. package/dist/renderers/shared.d.ts.map +1 -0
  88. package/dist/renderers/shared.js +156 -0
  89. package/dist/renderers/shared.js.map +1 -0
  90. package/dist/snapshot.d.ts +47 -0
  91. package/dist/snapshot.d.ts.map +1 -0
  92. package/dist/snapshot.js +144 -0
  93. package/dist/snapshot.js.map +1 -0
  94. package/dist/tokenizers.d.ts +14 -0
  95. package/dist/tokenizers.d.ts.map +1 -0
  96. package/dist/tokenizers.js +45 -0
  97. package/dist/tokenizers.js.map +1 -0
  98. package/dist/types.d.ts +221 -85
  99. package/dist/types.d.ts.map +1 -1
  100. package/dist/types.js +116 -2
  101. package/dist/types.js.map +1 -1
  102. package/package.json +111 -5
  103. package/dist/components.d.ts +0 -78
  104. package/dist/components.d.ts.map +0 -1
  105. package/dist/components.js +0 -98
  106. package/dist/components.js.map +0 -1
  107. package/dist/jsx-runtime.d.ts +0 -18
  108. package/dist/jsx-runtime.d.ts.map +0 -1
  109. package/dist/jsx-runtime.js.map +0 -1
  110. package/dist/render.test.d.ts +0 -2
  111. package/dist/render.test.d.ts.map +0 -1
  112. package/dist/render.test.js +0 -49
  113. package/dist/render.test.js.map +0 -1
package/README.md CHANGED
@@ -1,15 +1,17 @@
1
1
  <h1 align="center">Cria</h1>
2
2
 
3
3
  <p align="center">
4
- Cria is a tiny library for building LLM prompts as reusable components.
4
+ <i>Your prompts deserve the same structure as your code.</i>
5
5
  </p>
6
6
 
7
7
  <p align="center">
8
- <i>Debug, view, and save your prompts easily. Swap out components without major rewrites and test your prompts.</i>
8
+ <b><i>Cria turns prompts into composable components with explicit roles and strategies, and works with your existing environment & frameworks.</i></b>
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
+ <a href="https://github.com/fastpaca/cria/actions/workflows/ci.yml"><img src="https://github.com/fastpaca/cria/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
12
13
  <a href="https://www.npmjs.com/package/@fastpaca/cria"><img src="https://img.shields.io/npm/v/@fastpaca/cria?logo=npm&logoColor=white" alt="npm"></a>
14
+ <a href="https://www.npmjs.com/package/@fastpaca/cria"><img src="https://img.shields.io/npm/dm/@fastpaca/cria" alt="Downloads"></a>
13
15
  <a href="https://opensource.org/license/mit"><img src="https://img.shields.io/badge/license-MIT-blue" alt="License"></a>
14
16
  </p>
15
17
 
@@ -19,147 +21,142 @@
19
21
  </a>
20
22
  </p>
21
23
 
22
- Most prompt construction is string concatenation. Append everything to some buffer, hope the important parts survive when you hit limits or want to save cost.
23
-
24
- Cria lets you declare what's expendable and what is not, and makes your prompts failure mode explicit.
25
-
26
- Cria treats memory layout as a first-class concern. You declare priorities upfront, and the library handles eviction when needed. Components let you test retrieval logic separately from system prompts, swap implementations without rewrites, and debug exactly which content got cut when quality degrades.
27
-
28
- ```tsx
29
- const prompt = (
30
- <Region priority={0}>
31
- You are a helpful assistant.
32
-
33
- {/* Only preserve 80k tokens of history */}
34
- <Truncate budget={80000} priority={2}>
35
- {conversationHistory}
36
- </Truncate>
37
-
38
- {/* Only preserve 20k tokens of tool calls. It gets dropped
39
- first in case we need to. */}
40
- <Truncate budget={20000} priority={3}>
41
- {toolCalls}
42
- </Truncate>
43
-
44
- {/* Skip examples in case we are bad on budget */}
45
- <Omit priority={3}>{examples}</Omit>
46
-
47
- {userMessage}
48
- </Region>
49
- );
50
-
51
- render(prompt, { tokenizer, budget: 128000 });
24
+ Cria is a lightweight prompt composition library for structured prompt engineering. Build prompts as components, keep behavior predictable, and reuse the same structure across providers. Runs on Node, Deno, Bun, and Edge; adapters require their SDKs.
25
+
26
+ ```ts
27
+ const messages = await cria
28
+ .prompt()
29
+ .system("You are a research assistant.")
30
+ .vectorSearch({ store, query: question, limit: 10 })
31
+ .provider(openai("gpt-5-nano"), p => p
32
+ .summary(conversation, { store: memory })
33
+ .last(conversation, { N: 20 })
34
+ )
35
+ .user(question)
36
+ .render({ budget: 200_000, renderer });
52
37
  ```
53
38
 
54
- Cria will drop lower priority sections or truncate them in case it hits your prompt limits.
55
- ## Features
39
+ See all **[-> Documentation](docs/README.md)** for more comprehensive overviews.
56
40
 
57
- - **Composable** Build prompts from reusable components. Test and optimize each part independently.
58
- - **Priority-based** — Declare what's sacred (priority 0) and what's expendable (priority 3). No more guessing what gets cut.
59
- - **Flexible strategies** — Truncate content progressively, omit entire sections, or write custom eviction logic.
60
- - **Tiny** — Zero dependencies.
41
+ ## Use Cria when you need...
61
42
 
62
- ## Getting Started
43
+ - **Need RAG?** Call `.vectorSearch({ store, query })`.
44
+ - **Need a summary for long conversations?** Use `.summary(...)`.
45
+ - **Need to cap history but keep structure?** Use `.last(...)`.
46
+ - **Need to drop optional context when the context window is full?** Use `.omit(...)`.
47
+ - **Using AI SDK?** Plug and play with `@fastpaca/cria/ai-sdk`!
48
+ - **Prefer TSX?** Import the optional JSX surface from `@fastpaca/cria/jsx`.
63
49
 
64
- ```bash
65
- npm install @fastpaca/cria
66
- ```
67
-
68
- Add to your `tsconfig.json`:
69
-
70
- ```json
71
- {
72
- "compilerOptions": {
73
- "jsx": "react-jsx",
74
- "jsxImportSource": "@fastpaca/cria"
75
- }
76
- }
77
- ```
50
+ ## Integrations
78
51
 
79
- ## Documentation
52
+ <details>
53
+ <summary><strong>OpenAI Chat Completions</strong></summary>
80
54
 
81
- ### Components
55
+ ```ts
56
+ import OpenAI from "openai";
57
+ import { chatCompletions } from "@fastpaca/cria/openai";
58
+ import { cria } from "@fastpaca/cria";
82
59
 
83
- **`<Region>`** The basic building block. Groups content with a priority level.
84
-
85
- ```jsx
86
- <Region>
87
- <Region priority={0}>System instructions</Region>
88
- <Region priority={2}>Retrieved context</Region>
89
- </Region>
60
+ const client = new OpenAI();
61
+ const messages = await cria
62
+ .prompt()
63
+ .system("You are helpful.")
64
+ .user(userQuestion)
65
+ .render({ budget, tokenizer, renderer: chatCompletions });
66
+ const response = await client.chat.completions.create({ model: "gpt-4o-mini", messages });
90
67
  ```
91
-
92
- **`<Truncate>`** — Progressively shortens content when over budget.
93
-
94
- ```jsx
95
- <Truncate budget={10000} from="start" priority={2}>
96
- {longConversation}
97
- </Truncate>
68
+ </details>
69
+
70
+ <details>
71
+ <summary><strong>OpenAI Responses</strong></summary>
72
+
73
+ ```ts
74
+ import OpenAI from "openai";
75
+ import { responses } from "@fastpaca/cria/openai";
76
+ import { cria } from "@fastpaca/cria";
77
+
78
+ const client = new OpenAI();
79
+ const input = await cria
80
+ .prompt()
81
+ .system("You are helpful.")
82
+ .user(userQuestion)
83
+ .render({ budget, tokenizer, renderer: responses });
84
+ const response = await client.responses.create({ model: "gpt-5-nano", input });
98
85
  ```
99
-
100
- **`<Omit>`** — Drops entirely when space is needed.
101
-
102
- ```jsx
103
- <Omit priority={3}>{optionalExamples}</Omit>
86
+ </details>
87
+
88
+ <details>
89
+ <summary><strong>Anthropic</strong></summary>
90
+
91
+ ```ts
92
+ import Anthropic from "@anthropic-ai/sdk";
93
+ import { anthropic } from "@fastpaca/cria/anthropic";
94
+ import { cria } from "@fastpaca/cria";
95
+
96
+ const client = new Anthropic();
97
+ const { system, messages } = await cria
98
+ .prompt()
99
+ .system("You are helpful.")
100
+ .user(userQuestion)
101
+ .render({ budget, tokenizer, renderer: anthropic });
102
+ const response = await client.messages.create({ model: "claude-haiku-4-5", system, messages });
104
103
  ```
105
-
106
- ### Priority Levels
107
-
108
- Lower number = higher importance.
109
-
110
- | Priority | Use for |
111
- |----------|---------|
112
- | 0 | System prompt, safety rules |
113
- | 1 | Current user message, tool outputs |
114
- | 2 | Conversation history, retrieved docs |
115
- | 3 | Examples, optional context |
116
-
117
- ### Tokenizer
118
-
119
- Pass any function that counts tokens:
120
-
121
- ```tsx
122
- import { encoding_for_model } from "tiktoken";
123
-
124
- const enc = encoding_for_model("gpt-4");
125
- const tokenizer = (text: string) => enc.encode(text).length;
126
-
127
- render(prompt, { tokenizer, budget: 128000 });
104
+ </details>
105
+
106
+ <details>
107
+ <summary><strong>Vercel AI SDK</strong></summary>
108
+
109
+ ```ts
110
+ import { renderer } from "@fastpaca/cria/ai-sdk";
111
+ import { cria } from "@fastpaca/cria";
112
+ import { generateText } from "ai";
113
+
114
+ const messages = await cria
115
+ .prompt()
116
+ .system("You are helpful.")
117
+ .user(userQuestion)
118
+ .render({ budget, tokenizer, renderer });
119
+ const { text } = await generateText({ model, messages });
128
120
  ```
121
+ </details>
129
122
 
130
- ### Custom Strategies
123
+ ## Roadmap
131
124
 
132
- Write your own eviction logic:
125
+ **Done**
133
126
 
134
- ```tsx
135
- import type { Strategy } from "@fastpaca/cria";
127
+ - [x] Fluent DSL and priority-based eviction
128
+ - [x] Components: Region, Message, Truncate, Omit, Last, Summary, VectorSearch, ToolCall, ToolResult, Reasoning, Examples, CodeBlock, Separator
129
+ - [x] Renderers: OpenAI (Chat Completions + Responses), Anthropic, AI SDK
130
+ - [x] AI SDK helpers: Messages component, DEFAULT_PRIORITIES
131
+ - [x] Memory: InMemoryStore, Redis, Postgres, Chroma, Qdrant
132
+ - [x] Observability: render hooks, validation schemas, snapshots, OpenTelemetry
133
+ - [x] Tokenizer helpers
136
134
 
137
- const summarize: Strategy = ({ target, tokenizer }) => {
138
- const summary = createSummary(target.content);
139
- return [{ ...target, content: summary, tokens: tokenizer(summary) }];
140
- };
135
+ **Planned**
141
136
 
142
- <Region priority={2} strategy={summarize}>{document}</Region>
143
- ```
137
+ - [ ] Next.js adapter
138
+ - [ ] GenAI semantic conventions for OpenTelemetry
139
+ - [ ] Visualization tool
140
+ - [ ] Prompt eval / testing functionality
144
141
 
145
- ### Error Handling
142
+ ## Contributing
146
143
 
147
- ```tsx
148
- import { FitError } from "@fastpaca/cria";
144
+ - Issues and PRs are welcome.
145
+ - Keep changes small and focused.
146
+ - If you add a feature, include a short example or doc note.
147
+ - Prefer DSL-based examples in contributions; JSX lives under `@fastpaca/cria/jsx` as optional sugar.
149
148
 
150
- try {
151
- render(prompt, { tokenizer, budget: 1000 });
152
- } catch (e) {
153
- if (e instanceof FitError) {
154
- console.log(`Over budget by ${e.overBudgetBy} tokens`);
155
- }
156
- }
157
- ```
149
+ ## Support
158
150
 
159
- ## Contributing
151
+ - Open a GitHub issue for bugs or feature requests.
152
+ - For quick questions, include a minimal repro or snippet.
153
+
154
+ ## FAQ
160
155
 
161
- Contributions are welcome! Please feel free to submit a Pull Request.
156
+ - **Does this replace my LLM SDK?** No - Cria builds prompt structures. You still use your SDK to call the model.
157
+ - **How do I tune token budgets?** Pass `budget` to `render()` and set priorities on regions. Providers include tiktoken defaults; see [docs/tokenization.md](docs/tokenization.md) to bring your own.
158
+ - **Is this production-ready?** Not yet! It is a work in progress and you should test it out before you run this in production.
162
159
 
163
160
  ## License
164
161
 
165
- MIT © [Fastpaca](https://fastpaca.com)
162
+ MIT
@@ -0,0 +1,68 @@
1
+ import type { LanguageModel, ModelMessage, UIMessage } from "ai";
2
+ import type { CompletionRequest, CompletionResult, MaybePromise, ModelProvider, PromptChildren, PromptElement, PromptRenderer, Tokenizer } from "../types";
3
+ /**
4
+ * Priority configuration for message types when rendering prompts.
5
+ * Lower numbers = higher priority (less likely to be dropped).
6
+ */
7
+ export interface Priorities {
8
+ system: number;
9
+ user: number;
10
+ assistant: number;
11
+ toolCall: number;
12
+ toolResult: number;
13
+ reasoning: number;
14
+ }
15
+ export declare const DEFAULT_PRIORITIES: Priorities;
16
+ export interface MessagesProps {
17
+ messages: readonly UIMessage[];
18
+ includeReasoning?: boolean;
19
+ priorities?: Partial<Priorities>;
20
+ id?: string;
21
+ }
22
+ /**
23
+ * Converts AI SDK UIMessages into Cria prompt elements.
24
+ * Use this to include conversation history in your prompts.
25
+ */
26
+ export declare function Messages({ messages, includeReasoning, priorities, id, }: MessagesProps): PromptElement;
27
+ /**
28
+ * Renderer that outputs ModelMessage[] for use with the Vercel AI SDK.
29
+ * Pass this to render() to get messages compatible with generateText/streamText.
30
+ */
31
+ export declare const renderer: PromptRenderer<ModelMessage[]>;
32
+ interface AISDKProviderProps {
33
+ /** The language model to use (e.g. openai("gpt-4o"), anthropic("claude-sonnet-4-20250514")) */
34
+ model: LanguageModel;
35
+ /** Optional tokenizer to use for budgeting; defaults to an approximate counter */
36
+ tokenizer?: Tokenizer;
37
+ /** Child components that will have access to this provider */
38
+ children?: PromptChildren;
39
+ }
40
+ /**
41
+ * ModelProvider implementation that wraps an AI SDK LanguageModel.
42
+ * Use this with the DSL's `.provider()` method.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * import { cria } from "@fastpaca/cria";
47
+ * import { Provider } from "@fastpaca/cria/ai-sdk";
48
+ * import { openai } from "@ai-sdk/openai";
49
+ *
50
+ * const provider = new Provider(openai("gpt-4o"));
51
+ *
52
+ * const prompt = cria
53
+ * .prompt()
54
+ * .provider(provider, (p) =>
55
+ * p.summary(content, { id: "summary", store })
56
+ * )
57
+ * .build();
58
+ * ```
59
+ */
60
+ export declare class Provider implements ModelProvider {
61
+ readonly name = "ai-sdk";
62
+ private readonly model;
63
+ constructor(model: LanguageModel);
64
+ completion(request: CompletionRequest): Promise<CompletionResult>;
65
+ }
66
+ export declare function AISDKProvider({ model, tokenizer, children, }: AISDKProviderProps): MaybePromise<PromptElement>;
67
+ export {};
68
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EAEZ,SAAS,EACV,MAAM,IAAI,CAAC;AAmBZ,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EAEb,cAAc,EACd,aAAa,EACb,cAAc,EAEd,SAAS,EACV,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,kBAAkB,EAAE,UAOhC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,SAAS,SAAS,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,gBAAwB,EACxB,UAAU,EACV,EAAE,GACH,EAAE,aAAa,GAAG,aAAa,CAgB/B;AA0LD;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,cAAc,CAAC,YAAY,EAAE,CAKnD,CAAC;AAoMF,UAAU,kBAAkB;IAC1B,+FAA+F;IAC/F,KAAK,EAAE,aAAa,CAAC;IACrB,kFAAkF;IAClF,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AA4BD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,QAAS,YAAW,aAAa;IAC5C,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;gBAE1B,KAAK,EAAE,aAAa;IAI1B,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAkBxE;AAED,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,SAAS,EACT,QAAa,GACd,EAAE,kBAAkB,GAAG,YAAY,CAAC,aAAa,CAAC,CA+BlD"}