@fastpaca/cria 0.0.1 → 1.0.1

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 (140) hide show
  1. package/README.md +93 -106
  2. package/dist/ai-sdk/index.d.ts +43 -0
  3. package/dist/ai-sdk/index.d.ts.map +1 -0
  4. package/dist/ai-sdk/index.js +303 -0
  5. package/dist/ai-sdk/index.js.map +1 -0
  6. package/dist/ai-sdk/index.test.d.ts +2 -0
  7. package/dist/ai-sdk/index.test.d.ts.map +1 -0
  8. package/dist/ai-sdk/index.test.js +101 -0
  9. package/dist/ai-sdk/index.test.js.map +1 -0
  10. package/dist/anthropic/index.d.ts +74 -0
  11. package/dist/anthropic/index.d.ts.map +1 -0
  12. package/dist/anthropic/index.js +238 -0
  13. package/dist/anthropic/index.js.map +1 -0
  14. package/dist/anthropic/index.test.d.ts +2 -0
  15. package/dist/anthropic/index.test.d.ts.map +1 -0
  16. package/dist/anthropic/index.test.js +115 -0
  17. package/dist/anthropic/index.test.js.map +1 -0
  18. package/dist/components/additional.test.d.ts +2 -0
  19. package/dist/components/additional.test.d.ts.map +1 -0
  20. package/dist/components/additional.test.js +31 -0
  21. package/dist/components/additional.test.js.map +1 -0
  22. package/dist/components/index.d.ts +148 -0
  23. package/dist/components/index.d.ts.map +1 -0
  24. package/dist/components/index.js +184 -0
  25. package/dist/components/index.js.map +1 -0
  26. package/dist/components/summary.d.ts +91 -0
  27. package/dist/components/summary.d.ts.map +1 -0
  28. package/dist/components/summary.js +118 -0
  29. package/dist/components/summary.js.map +1 -0
  30. package/dist/components/summary.test.d.ts +2 -0
  31. package/dist/components/summary.test.d.ts.map +1 -0
  32. package/dist/components/summary.test.js +101 -0
  33. package/dist/components/summary.test.js.map +1 -0
  34. package/dist/components/vector-search.d.ts +70 -0
  35. package/dist/components/vector-search.d.ts.map +1 -0
  36. package/dist/components/vector-search.js +110 -0
  37. package/dist/components/vector-search.js.map +1 -0
  38. package/dist/components/vector-search.test.d.ts +2 -0
  39. package/dist/components/vector-search.test.d.ts.map +1 -0
  40. package/dist/components/vector-search.test.js +113 -0
  41. package/dist/components/vector-search.test.js.map +1 -0
  42. package/dist/index.d.ts +12 -5
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +9 -5
  45. package/dist/index.js.map +1 -1
  46. package/dist/instrumentation/otel.d.ts +19 -0
  47. package/dist/instrumentation/otel.d.ts.map +1 -0
  48. package/dist/instrumentation/otel.js +102 -0
  49. package/dist/instrumentation/otel.js.map +1 -0
  50. package/dist/instrumentation/otel.test.d.ts +2 -0
  51. package/dist/instrumentation/otel.test.d.ts.map +1 -0
  52. package/dist/instrumentation/otel.test.js +116 -0
  53. package/dist/instrumentation/otel.test.js.map +1 -0
  54. package/dist/jsx-dev-runtime.d.ts +2 -0
  55. package/dist/jsx-dev-runtime.d.ts.map +1 -0
  56. package/dist/jsx-dev-runtime.js +2 -0
  57. package/dist/jsx-dev-runtime.js.map +1 -0
  58. package/dist/jsx-runtime.d.ts +30 -8
  59. package/dist/jsx-runtime.d.ts.map +1 -1
  60. package/dist/jsx-runtime.js +13 -10
  61. package/dist/jsx-runtime.js.map +1 -1
  62. package/dist/memory/chroma/index.d.ts +59 -0
  63. package/dist/memory/chroma/index.d.ts.map +1 -0
  64. package/dist/memory/chroma/index.js +172 -0
  65. package/dist/memory/chroma/index.js.map +1 -0
  66. package/dist/memory/index.d.ts +4 -0
  67. package/dist/memory/index.d.ts.map +1 -0
  68. package/dist/memory/index.js +2 -0
  69. package/dist/memory/index.js.map +1 -0
  70. package/dist/memory/key-value.d.ts +71 -0
  71. package/dist/memory/key-value.d.ts.map +1 -0
  72. package/dist/memory/key-value.js +34 -0
  73. package/dist/memory/key-value.js.map +1 -0
  74. package/dist/memory/postgres.d.ts +71 -0
  75. package/dist/memory/postgres.d.ts.map +1 -0
  76. package/dist/memory/postgres.js +109 -0
  77. package/dist/memory/postgres.js.map +1 -0
  78. package/dist/memory/qdrant/index.d.ts +64 -0
  79. package/dist/memory/qdrant/index.d.ts.map +1 -0
  80. package/dist/memory/qdrant/index.js +136 -0
  81. package/dist/memory/qdrant/index.js.map +1 -0
  82. package/dist/memory/redis.d.ts +70 -0
  83. package/dist/memory/redis.d.ts.map +1 -0
  84. package/dist/memory/redis.js +100 -0
  85. package/dist/memory/redis.js.map +1 -0
  86. package/dist/memory/vector.d.ts +53 -0
  87. package/dist/memory/vector.d.ts.map +1 -0
  88. package/dist/memory/vector.js +2 -0
  89. package/dist/memory/vector.js.map +1 -0
  90. package/dist/openai/index.d.ts +46 -0
  91. package/dist/openai/index.d.ts.map +1 -0
  92. package/dist/openai/index.js +260 -0
  93. package/dist/openai/index.js.map +1 -0
  94. package/dist/openai/index.test.d.ts +2 -0
  95. package/dist/openai/index.test.d.ts.map +1 -0
  96. package/dist/openai/index.test.js +204 -0
  97. package/dist/openai/index.test.js.map +1 -0
  98. package/dist/providers/index.d.ts +2 -0
  99. package/dist/providers/index.d.ts.map +1 -0
  100. package/dist/providers/index.js +2 -0
  101. package/dist/providers/index.js.map +1 -0
  102. package/dist/providers/types.d.ts +2 -0
  103. package/dist/providers/types.d.ts.map +1 -0
  104. package/dist/providers/types.js +2 -0
  105. package/dist/providers/types.js.map +1 -0
  106. package/dist/render.d.ts +44 -40
  107. package/dist/render.d.ts.map +1 -1
  108. package/dist/render.js +162 -148
  109. package/dist/render.js.map +1 -1
  110. package/dist/render.test.js +146 -28
  111. package/dist/render.test.js.map +1 -1
  112. package/dist/renderers/markdown.d.ts +3 -0
  113. package/dist/renderers/markdown.d.ts.map +1 -0
  114. package/dist/renderers/markdown.js +43 -0
  115. package/dist/renderers/markdown.js.map +1 -0
  116. package/dist/renderers/shared.d.ts +82 -0
  117. package/dist/renderers/shared.d.ts.map +1 -0
  118. package/dist/renderers/shared.js +156 -0
  119. package/dist/renderers/shared.js.map +1 -0
  120. package/dist/snapshot.d.ts +47 -0
  121. package/dist/snapshot.d.ts.map +1 -0
  122. package/dist/snapshot.js +140 -0
  123. package/dist/snapshot.js.map +1 -0
  124. package/dist/snapshot.test.d.ts +2 -0
  125. package/dist/snapshot.test.d.ts.map +1 -0
  126. package/dist/snapshot.test.js +68 -0
  127. package/dist/snapshot.test.js.map +1 -0
  128. package/dist/tokenizers.d.ts +14 -0
  129. package/dist/tokenizers.d.ts.map +1 -0
  130. package/dist/tokenizers.js +45 -0
  131. package/dist/tokenizers.js.map +1 -0
  132. package/dist/types.d.ts +212 -84
  133. package/dist/types.d.ts.map +1 -1
  134. package/dist/types.js +109 -0
  135. package/dist/types.js.map +1 -1
  136. package/package.json +88 -3
  137. package/dist/components.d.ts +0 -78
  138. package/dist/components.d.ts.map +0 -1
  139. package/dist/components.js +0 -98
  140. package/dist/components.js.map +0 -1
@@ -0,0 +1,140 @@
1
+ import { sha256 } from "@noble/hashes/sha256";
2
+ import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils";
3
+ import { markdownRenderer } from "./renderers/markdown";
4
+ /**
5
+ * Create a deterministic snapshot of a fitted prompt tree.
6
+ *
7
+ * - Keeps the tree structure (no flattening) and mirrors PromptElement shape.
8
+ * - Adds per-node token counts (using renderer.tokenString) and stable hashes.
9
+ * - Excludes strategy/context from the snapshot; this is for observability only.
10
+ */
11
+ export function createSnapshot(element, { tokenizer, renderer = markdownRenderer }) {
12
+ const root = snapshotElement(element, tokenizer, renderer);
13
+ return {
14
+ root,
15
+ totalTokens: root.tokens,
16
+ hash: root.hash,
17
+ };
18
+ }
19
+ export function createSnapshotHooks({ tokenizer, renderer, onSnapshot, }) {
20
+ return {
21
+ onFitComplete: async (event) => {
22
+ if (!event.result) {
23
+ return;
24
+ }
25
+ const snapshot = createSnapshot(event.result, {
26
+ tokenizer,
27
+ ...(renderer && { renderer }),
28
+ });
29
+ await onSnapshot(snapshot);
30
+ },
31
+ };
32
+ }
33
+ export function diffSnapshots(before, after) {
34
+ const added = [];
35
+ const removed = [];
36
+ const changed = [];
37
+ compareNodes(before.root, after.root, [], added, removed, changed);
38
+ return { added, removed, changed };
39
+ }
40
+ function compareNodes(before, after, path, added, removed, changed) {
41
+ if (handlePrimitives(before, after, path, added, removed, changed)) {
42
+ return;
43
+ }
44
+ const beforeElement = before;
45
+ const afterElement = after;
46
+ recordElementChange(beforeElement, afterElement, path, changed);
47
+ compareChildren(beforeElement, afterElement, path, added, removed, changed);
48
+ }
49
+ function handlePrimitives(before, after, path, added, removed, changed) {
50
+ if (typeof before === "string" && typeof after === "string") {
51
+ if (before !== after) {
52
+ changed.push({ path, before, after });
53
+ }
54
+ return true;
55
+ }
56
+ if (typeof before === "string") {
57
+ removed.push({ path, node: before });
58
+ added.push({ path, node: after });
59
+ return true;
60
+ }
61
+ if (typeof after === "string") {
62
+ removed.push({ path, node: before });
63
+ added.push({ path, node: after });
64
+ return true;
65
+ }
66
+ return false;
67
+ }
68
+ function recordElementChange(before, after, path, changed) {
69
+ const identityChanged = elementIdentity(before) !== elementIdentity(after);
70
+ const contentChanged = before.hash !== after.hash || before.tokens !== after.tokens;
71
+ if (identityChanged || contentChanged) {
72
+ changed.push({ path, before, after });
73
+ }
74
+ }
75
+ function compareChildren(before, after, path, added, removed, changed) {
76
+ const maxChildren = Math.max(before.children.length, after.children.length);
77
+ for (let i = 0; i < maxChildren; i++) {
78
+ const beforeChild = before.children[i];
79
+ const afterChild = after.children[i];
80
+ const childPath = [...path, i];
81
+ if (beforeChild === undefined && afterChild !== undefined) {
82
+ added.push({ path: childPath, node: afterChild });
83
+ continue;
84
+ }
85
+ if (beforeChild !== undefined && afterChild === undefined) {
86
+ removed.push({ path: childPath, node: beforeChild });
87
+ continue;
88
+ }
89
+ if (beforeChild !== undefined && afterChild !== undefined) {
90
+ compareNodes(beforeChild, afterChild, childPath, added, removed, changed);
91
+ }
92
+ }
93
+ }
94
+ function elementIdentity(element) {
95
+ return element.id ?? `${element.kind ?? "region"}:${element.priority}`;
96
+ }
97
+ function snapshotElement(element, tokenizer, renderer) {
98
+ const childSnapshots = element.children.map((child) => typeof child === "string"
99
+ ? child
100
+ : snapshotElement(child, tokenizer, renderer));
101
+ const contentProjection = renderer.tokenString(element);
102
+ const tokens = tokenizer(contentProjection);
103
+ const childHashes = childSnapshots.map((child) => typeof child === "string" ? hashString(child) : child.hash);
104
+ const hasToolId = element.kind === "tool-call" || element.kind === "tool-result";
105
+ const hash = hashElement({
106
+ kind: element.kind,
107
+ priority: element.priority,
108
+ role: element.kind === "message" ? element.role : undefined,
109
+ text: element.kind === "reasoning" ? element.text : undefined,
110
+ toolCallId: hasToolId ? element.toolCallId : undefined,
111
+ toolName: hasToolId ? element.toolName : undefined,
112
+ id: element.id,
113
+ tokens,
114
+ childHashes,
115
+ });
116
+ return {
117
+ ...element,
118
+ children: childSnapshots,
119
+ tokens,
120
+ hash,
121
+ };
122
+ }
123
+ function hashElement(input) {
124
+ const payload = {
125
+ kind: input.kind ?? "region",
126
+ priority: input.priority,
127
+ role: input.role,
128
+ text: input.text,
129
+ toolCallId: input.toolCallId,
130
+ toolName: input.toolName,
131
+ id: input.id,
132
+ tokens: input.tokens,
133
+ children: input.childHashes,
134
+ };
135
+ return hashString(JSON.stringify(payload));
136
+ }
137
+ function hashString(value) {
138
+ return bytesToHex(sha256(utf8ToBytes(value)));
139
+ }
140
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=snapshot.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.test.d.ts","sourceRoot":"","sources":["../src/snapshot.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@fastpaca/cria/jsx-runtime";
2
+ import { describe, expect, test } from "vitest";
3
+ import { Omit, Region } from "./components";
4
+ import { render } from "./render";
5
+ import { createSnapshot, createSnapshotHooks, diffSnapshots } from "./snapshot";
6
+ const tokenizer = (text) => text.length;
7
+ const buildBaseTree = () => (_jsxs(Region, { priority: 0, children: ["Intro", _jsx(Region, { priority: 1, children: "Keep" }), _jsx(Omit, { priority: 2, children: "Drop" })] }));
8
+ const buildChangedTree = () => (_jsxs(Region, { priority: 0, children: ["Intro updated", _jsx(Region, { priority: 1, children: "Keep" }), _jsx(Region, { priority: 2, children: "Replace" })] }));
9
+ describe("createSnapshot", () => {
10
+ test("produces deterministic snapshots for the same input", async () => {
11
+ const element = await buildBaseTree();
12
+ const first = await createSnapshot(element, { tokenizer });
13
+ const second = await createSnapshot(element, { tokenizer });
14
+ expect(first.hash).toBe(second.hash);
15
+ expect(first.root).toEqual(second.root);
16
+ expect(first.totalTokens).toBe(second.totalTokens);
17
+ });
18
+ test("hash changes when structural content changes", async () => {
19
+ const base = await createSnapshot(await buildBaseTree(), { tokenizer });
20
+ const changed = await createSnapshot(await buildChangedTree(), {
21
+ tokenizer,
22
+ });
23
+ expect(base.hash).not.toBe(changed.hash);
24
+ });
25
+ });
26
+ describe("diffSnapshots", () => {
27
+ test("reports changed nodes and no false adds/removals when shapes align", async () => {
28
+ const base = await createSnapshot(await buildBaseTree(), { tokenizer });
29
+ const changed = await createSnapshot(await buildChangedTree(), {
30
+ tokenizer,
31
+ });
32
+ const diff = diffSnapshots(base, changed);
33
+ const changedPaths = diff.changed
34
+ .map((entry) => entry.path.join("."))
35
+ .sort();
36
+ expect(diff.added).toHaveLength(0);
37
+ expect(diff.removed).toHaveLength(0);
38
+ expect(changedPaths).toEqual(["", "0", "2", "2.0"]);
39
+ });
40
+ });
41
+ describe("createSnapshotHooks", () => {
42
+ test("invokes callback with snapshot on fit complete", async () => {
43
+ const snapshots = [];
44
+ const element = (_jsxs(Region, { priority: 0, children: ["A", _jsx(Omit, { priority: 1, children: "BBBB" })] }));
45
+ const hooks = createSnapshotHooks({
46
+ tokenizer,
47
+ onSnapshot: (snapshot) => {
48
+ snapshots.push(snapshot.hash);
49
+ },
50
+ });
51
+ const result = await render(element, { tokenizer, budget: 1, hooks });
52
+ expect(result).toBe("A");
53
+ expect(snapshots).toHaveLength(1);
54
+ });
55
+ test("propagates errors from snapshot creation", async () => {
56
+ const element = _jsx(Region, { priority: 0, children: "Hi" });
57
+ const hooks = createSnapshotHooks({
58
+ tokenizer: () => {
59
+ throw new Error("tokenizer failed");
60
+ },
61
+ onSnapshot: () => {
62
+ throw new Error("callback failed");
63
+ },
64
+ });
65
+ await expect(render(element, { tokenizer, budget: 10, hooks })).rejects.toThrow("tokenizer failed");
66
+ });
67
+ });
68
+ //# sourceMappingURL=snapshot.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.test.js","sourceRoot":"","sources":["../src/snapshot.test.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { Tokenizer } from "./types";
2
+ /**
3
+ * Rough heuristic tokenizer: ~4 characters per token.
4
+ *
5
+ * Suitable as a default estimate when no model-specific tokenizer is available.
6
+ * For accurate budgeting, pass a model-aware tokenizer (e.g. tiktoken).
7
+ */
8
+ export declare const approximateTokenizer: Tokenizer;
9
+ /**
10
+ * Best-effort tokenizer using tiktoken. Falls back to approximate if the encoding
11
+ * is unavailable.
12
+ */
13
+ export declare function tiktokenTokenizer(modelHint?: string): Tokenizer;
14
+ //# sourceMappingURL=tokenizers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizers.d.ts","sourceRoot":"","sources":["../src/tokenizers.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,SACP,CAAC;AA6B7B;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAO/D"}
@@ -0,0 +1,45 @@
1
+ import { encodingForModel, getEncoding, } from "js-tiktoken";
2
+ /**
3
+ * Rough heuristic tokenizer: ~4 characters per token.
4
+ *
5
+ * Suitable as a default estimate when no model-specific tokenizer is available.
6
+ * For accurate budgeting, pass a model-aware tokenizer (e.g. tiktoken).
7
+ */
8
+ export const approximateTokenizer = (text) => Math.ceil(text.length / 4);
9
+ const tiktokenCache = new Map();
10
+ function getTiktokenEncoder(modelHint) {
11
+ const cacheKey = modelHint ?? "cl100k_base";
12
+ const cached = tiktokenCache.get(cacheKey);
13
+ if (cached) {
14
+ return cached;
15
+ }
16
+ try {
17
+ const encoder = modelHint
18
+ ? encodingForModel(modelHint)
19
+ : getEncoding("cl100k_base");
20
+ tiktokenCache.set(cacheKey, encoder);
21
+ return encoder;
22
+ }
23
+ catch (error) {
24
+ // Fall through to allow approximate fallback
25
+ const debugEnv = process.env
26
+ .DEBUG;
27
+ if (debugEnv?.includes("cria:tokenizer")) {
28
+ // eslint-disable-next-line no-console
29
+ console.warn("Falling back to approximate tokenizer:", error);
30
+ }
31
+ return null;
32
+ }
33
+ }
34
+ /**
35
+ * Best-effort tokenizer using tiktoken. Falls back to approximate if the encoding
36
+ * is unavailable.
37
+ */
38
+ export function tiktokenTokenizer(modelHint) {
39
+ const encoder = getTiktokenEncoder(modelHint);
40
+ if (!encoder) {
41
+ return approximateTokenizer;
42
+ }
43
+ return (text) => encoder.encode(text).length;
44
+ }
45
+ //# sourceMappingURL=tokenizers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizers.js","sourceRoot":"","sources":["../src/tokenizers.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,WAAW,GAGZ,MAAM,aAAa,CAAC;AAGrB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAc,CAAC,IAAI,EAAE,EAAE,CACtD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAE7B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAoB,CAAC;AAElD,SAAS,kBAAkB,CAAC,SAAkB;IAC5C,MAAM,QAAQ,GAAG,SAAS,IAAI,aAAa,CAAC;IAC5C,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,SAAS;YACvB,CAAC,CAAC,gBAAgB,CAAC,SAA0B,CAAC;YAC9C,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;QAC/B,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrC,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,6CAA6C;QAC7C,MAAM,QAAQ,GAAI,OAAO,CAAC,GAA8C;aACrE,KAAK,CAAC;QACT,IAAI,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACzC,sCAAsC;YACtC,OAAO,CAAC,IAAI,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAkB;IAClD,MAAM,OAAO,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAED,OAAO,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACvD,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,126 +1,254 @@
1
+ import { z } from "zod";
1
2
  /**
2
- * What can be passed as children to a Cria component.
3
+ * Message role used by semantic `kind: "message"` regions.
3
4
  *
4
- * Includes all JSX-compatible values: elements, strings, numbers, booleans,
5
- * null/undefined (ignored), and arrays (flattened). The jsx-runtime normalizes
6
- * these into `(PromptElement | string)[]` before storing in the element.
7
- *
8
- * @example
9
- * ```tsx
10
- * <Region>
11
- * {"Hello"}
12
- * {123}
13
- * {items.map(item => <Region>{item}</Region>)}
14
- * </Region>
15
- * ```
5
+ * This is intentionally compatible with common LLM SDKs (system/user/assistant/tool),
6
+ * while still allowing custom roles for bespoke targets.
7
+ */
8
+ export declare const PromptRoleSchema: z.ZodString;
9
+ export type PromptRole = z.infer<typeof PromptRoleSchema>;
10
+ /**
11
+ * A message in a completion request.
12
+ */
13
+ export interface CompletionMessage {
14
+ role: PromptRole;
15
+ content: string;
16
+ }
17
+ /**
18
+ * Request parameters for a completion.
19
+ */
20
+ export interface CompletionRequest {
21
+ /** Messages to send to the model */
22
+ messages: CompletionMessage[];
23
+ /** Optional system prompt (some providers handle this separately) */
24
+ system?: string;
25
+ }
26
+ /**
27
+ * Result from a completion request.
16
28
  */
17
- export type PromptChildren = PromptElement | string | number | boolean | null | undefined | readonly PromptChildren[];
29
+ export interface CompletionResult {
30
+ /** The generated text response */
31
+ text: string;
32
+ }
18
33
  /**
19
- * The core IR node type. All Cria components return a PromptElement.
34
+ * A model provider that can generate completions.
20
35
  *
21
- * This is the normalized representation after JSX transformation.
22
- * The render pipeline traverses this tree to produce fragments for fitting.
36
+ * This abstraction allows Cria components to call AI models without
37
+ * being coupled to a specific SDK.
38
+ */
39
+ export interface ModelProvider {
40
+ /** Provider identifier for debugging */
41
+ name: string;
42
+ /**
43
+ * Tokenizer for this provider's model.
44
+ *
45
+ * Used for budget fitting when the caller doesn't pass a tokenizer directly.
46
+ * Providers should supply an estimate that matches the chosen model; callers
47
+ * can still override via render options.
48
+ */
49
+ tokenizer?: Tokenizer;
50
+ /**
51
+ * Generate a completion from the model.
52
+ */
53
+ completion(request: CompletionRequest): MaybePromise<CompletionResult>;
54
+ }
55
+ /**
56
+ * Context that can be provided through the component tree.
23
57
  *
24
- * @property priority - Lower number = higher importance (kept longer during fitting)
25
- * @property strategy - Optional function to reduce this region when over budget
26
- * @property id - Optional stable identifier for caching/debugging
27
- * @property children - Normalized array of child elements and text
58
+ * Provider components (like `<AISDKProvider>`) inject context that
59
+ * child components can access during rendering and strategy execution.
60
+ */
61
+ export interface CriaContext {
62
+ /** Model provider for AI-powered operations */
63
+ provider?: ModelProvider | undefined;
64
+ }
65
+ export type MaybePromise<T> = T | Promise<T>;
66
+ /**
67
+ * A function that counts tokens in a string.
68
+ * Cria doesn't bundle a tokenizer. You provide one.
28
69
  *
29
70
  * @example
30
- * ```tsx
31
- * // Created via JSX:
32
- * <Region priority={0}>System prompt</Region>
71
+ * ```typescript
72
+ * import { encoding_for_model } from "tiktoken";
33
73
  *
34
- * // Produces:
35
- * { priority: 0, children: ["System prompt"] }
74
+ * const enc = encoding_for_model("gpt-4");
75
+ * const tokenizer: Tokenizer = (text) => enc.encode(text).length;
36
76
  * ```
37
77
  */
38
- export interface PromptElement {
78
+ export type Tokenizer = (text: string) => number;
79
+ export declare const PromptKindSchema: z.ZodUnion<[z.ZodObject<{
80
+ kind: z.ZodOptional<z.ZodUndefined>;
81
+ }, "strip", z.ZodTypeAny, {
82
+ kind?: undefined;
83
+ }, {
84
+ kind?: undefined;
85
+ }>, z.ZodObject<{
86
+ kind: z.ZodLiteral<"message">;
87
+ role: z.ZodString;
88
+ }, "strip", z.ZodTypeAny, {
89
+ kind: "message";
90
+ role: string;
91
+ }, {
92
+ kind: "message";
93
+ role: string;
94
+ }>, z.ZodObject<{
95
+ kind: z.ZodLiteral<"tool-call">;
96
+ toolCallId: z.ZodString;
97
+ toolName: z.ZodString;
98
+ input: z.ZodUnknown;
99
+ }, "strip", z.ZodTypeAny, {
100
+ kind: "tool-call";
101
+ toolCallId: string;
102
+ toolName: string;
103
+ input?: unknown;
104
+ }, {
105
+ kind: "tool-call";
106
+ toolCallId: string;
107
+ toolName: string;
108
+ input?: unknown;
109
+ }>, z.ZodObject<{
110
+ kind: z.ZodLiteral<"tool-result">;
111
+ toolCallId: z.ZodString;
112
+ toolName: z.ZodString;
113
+ output: z.ZodUnknown;
114
+ }, "strip", z.ZodTypeAny, {
115
+ kind: "tool-result";
116
+ toolCallId: string;
117
+ toolName: string;
118
+ output?: unknown;
119
+ }, {
120
+ kind: "tool-result";
121
+ toolCallId: string;
122
+ toolName: string;
123
+ output?: unknown;
124
+ }>, z.ZodObject<{
125
+ kind: z.ZodLiteral<"reasoning">;
126
+ text: z.ZodString;
127
+ }, "strip", z.ZodTypeAny, {
128
+ kind: "reasoning";
129
+ text: string;
130
+ }, {
131
+ kind: "reasoning";
132
+ text: string;
133
+ }>]>;
134
+ export type PromptKind = z.infer<typeof PromptKindSchema>;
135
+ export type PromptNodeKind = PromptKind["kind"];
136
+ export interface PromptElementBase {
39
137
  priority: number;
40
- strategy?: Strategy;
41
- id?: string;
42
- children: (PromptElement | string)[];
138
+ strategy?: Strategy | undefined;
139
+ id?: string | undefined;
140
+ context?: CriaContext | undefined;
141
+ children: PromptChildren;
43
142
  }
143
+ export type PromptElement = (PromptElementBase & {
144
+ kind?: undefined;
145
+ }) | (PromptElementBase & {
146
+ kind: "message";
147
+ role: PromptRole;
148
+ }) | (PromptElementBase & {
149
+ kind: "tool-call";
150
+ toolCallId: string;
151
+ toolName: string;
152
+ input: unknown;
153
+ }) | (PromptElementBase & {
154
+ kind: "tool-result";
155
+ toolCallId: string;
156
+ toolName: string;
157
+ output: unknown;
158
+ }) | (PromptElementBase & {
159
+ kind: "reasoning";
160
+ text: string;
161
+ });
162
+ export type PromptChild = string | PromptElement;
163
+ export type PromptChildren = PromptChild[];
164
+ export declare const PromptElementSchema: z.ZodType<PromptElement>;
165
+ export declare const PromptChildSchema: z.ZodType<PromptChild>;
166
+ export declare const PromptChildrenSchema: z.ZodType<PromptChildren>;
44
167
  /**
45
- * A flattened text fragment produced by the render pipeline.
168
+ * A renderer that converts a fitted prompt tree into an output format.
46
169
  *
47
- * The render step walks the PromptElement tree and emits an ordered list of
48
- * fragments. The fit loop then applies strategies to reduce token count.
170
+ * Renderers are used for two things:
171
+ * - **Token accounting / fitting** via `tokenString` (a stable string projection)
172
+ * - **Final output** via `render` (can be async, and can produce any type)
49
173
  *
50
- * @property content - The text content of this fragment
51
- * @property tokens - Token count (computed via the provided tokenizer)
52
- * @property priority - Inherited from the emitting element
53
- * @property regionId - Stable identifier (from element.id or auto-generated)
54
- * @property strategy - If present, this fragment can be reduced during fitting
55
- * @property index - Position in the fragment list (for stable ordering)
174
+ * @template TOutput - The produced output type (e.g. `string`, `ModelMessage[]`, etc.).
56
175
  */
57
- export interface PromptFragment {
58
- content: string;
59
- tokens: number;
60
- priority: number;
61
- regionId: string;
62
- strategy?: Strategy;
63
- index: number;
176
+ export interface PromptRenderer<TOutput> {
177
+ /** A short identifier for debugging/observability. */
178
+ name: string;
179
+ /**
180
+ * A deterministic string projection of the prompt tree used for token counting.
181
+ *
182
+ * Important properties:
183
+ * - **Pure / deterministic**: same tree => same string
184
+ * - **Cheap**: called frequently during fitting
185
+ * - **Representative**: should correlate with what `render()` produces (especially for string targets)
186
+ *
187
+ * For structured targets (e.g. AI SDK messages), this can be a markdown-ish projection
188
+ * that approximates the effective prompt content for token budgeting.
189
+ */
190
+ tokenString: (element: PromptElement) => string;
191
+ /**
192
+ * Render the fitted prompt tree to the target output.
193
+ *
194
+ * May be async (e.g. when a renderer needs to fetch/resolve attachments, or when
195
+ * strategies summarized content during fitting).
196
+ */
197
+ render: (element: PromptElement) => MaybePromise<TOutput>;
198
+ /**
199
+ * The “empty” value for this renderer.
200
+ *
201
+ * Used when the budget is <= 0, or when strategies remove the entire tree.
202
+ */
203
+ empty: () => TOutput;
64
204
  }
65
205
  /**
66
- * A strategy function that reduces a fragment when the prompt is over budget.
67
- *
68
- * Strategies are called during the fit loop, starting with the least important
69
- * priority (highest number). They receive context about the current state and
70
- * must return replacement fragments (or empty array to remove entirely).
71
- *
72
- * Strategies must be:
73
- * - **Pure**: Don't mutate the input fragments
74
- * - **Deterministic**: Same input = same output
75
- * - **Idempotent**: Applying twice has no additional effect
76
- *
77
- * @example
78
- * ```typescript
79
- * // A strategy that removes the fragment entirely
80
- * const omitStrategy: Strategy = () => [];
206
+ * Canonical normalized child node type stored in the IR.
81
207
  *
82
- * // A strategy that truncates from the end
83
- * const truncateStrategy: Strategy = ({ target, tokenizer }) => {
84
- * let content = target.content.slice(0, 100);
85
- * return [{ ...target, content, tokens: tokenizer(content) }];
86
- * };
87
- * ```
208
+ * This is the only type you’ll find inside `PromptElement.children` after JSX normalization.
88
209
  */
89
- export type Strategy = (input: StrategyInput) => PromptFragment[];
210
+ export type JsonValue = null | string | number | boolean | JsonValue[] | {
211
+ [key: string]: JsonValue;
212
+ };
213
+ export declare const JsonValueSchema: z.ZodType<JsonValue>;
214
+ export type StrategyResult = PromptElement | null;
90
215
  /**
91
216
  * Context passed to strategy functions during the fit loop.
92
217
  *
93
- * @property fragments - All current fragments (readonly, don't mutate)
94
- * @property target - The specific fragment this strategy should reduce
218
+ * @property target - The specific region to reduce
95
219
  * @property budget - The total token budget we're trying to fit within
96
220
  * @property tokenizer - Function to count tokens in a string
97
- * @property totalTokens - Current total token count across all fragments
221
+ * @property tokenString - Renderer-provided projection used for token counting
222
+ * @property totalTokens - Current total token count for the prompt
98
223
  * @property iteration - Which iteration of the fit loop (for debugging)
224
+ * @property context - Inherited context from ancestor provider components
99
225
  */
100
226
  export interface StrategyInput {
101
- fragments: readonly PromptFragment[];
102
- target: PromptFragment;
227
+ target: PromptElement;
103
228
  budget: number;
104
229
  tokenizer: Tokenizer;
230
+ tokenString: (element: PromptElement) => string;
105
231
  totalTokens: number;
106
232
  iteration: number;
233
+ /** Context inherited from ancestor provider components */
234
+ context: CriaContext;
107
235
  }
108
236
  /**
109
- * A function that counts tokens in a string.
237
+ * A Strategy function that rewrites a region subtree when the prompt is over budget.
110
238
  *
111
- * Cria doesn't bundle a tokenizer—you provide one. Common choices:
112
- * - `tiktoken` for OpenAI models (cl100k_base for GPT-4)
113
- * - Simple approximation: `text => Math.ceil(text.length / 4)`
239
+ * Strategies are applied during fitting, starting from the least important
240
+ * priority (highest number). Strategies run **bottom-up** (post-order) so nested
241
+ * regions get a chance to shrink before their parents.
114
242
  *
115
- * @example
116
- * ```typescript
117
- * import { encoding_for_model } from "tiktoken";
243
+ * Strategies must be:
244
+ * - **Pure**: don't mutate the input element
245
+ * - **Deterministic**
246
+ * - **Idempotent**
118
247
  *
119
- * const enc = encoding_for_model("gpt-4");
120
- * const tokenizer: Tokenizer = (text) => enc.encode(text).length;
121
- * ```
248
+ * Strategies have full ownership of their subtree: they can replace the element
249
+ * and/or rewrite any children.
122
250
  */
123
- export type Tokenizer = (text: string) => number;
251
+ export type Strategy = (input: StrategyInput) => MaybePromise<StrategyResult>;
124
252
  /**
125
253
  * Error thrown when the prompt cannot be fit within the budget.
126
254
  *