@deepagents/context 0.33.0 → 0.35.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/browser.js CHANGED
@@ -900,366 +900,7 @@ async function estimate(modelId, renderer, ...fragments) {
900
900
  }
901
901
 
902
902
  // packages/context/src/lib/fragments/message/user.ts
903
- import { generateId as generateId2, isTextUIPart } from "ai";
904
- function everyNTurns(n) {
905
- return ({ turn }) => turn % n === 0;
906
- }
907
- function once() {
908
- return ({ turn }) => turn === 1;
909
- }
910
- function firstN(n) {
911
- return ({ turn }) => turn <= n;
912
- }
913
- function afterTurn(n) {
914
- return ({ turn }) => turn > n;
915
- }
916
- function and(...predicates) {
917
- return (ctx) => predicates.every((p) => p(ctx));
918
- }
919
- function or(...predicates) {
920
- return (ctx) => predicates.some((p) => p(ctx));
921
- }
922
- function not(predicate) {
923
- return (ctx) => !predicate(ctx);
924
- }
925
- function contentIncludes(keywords) {
926
- const lower = keywords.map((k) => k.toLowerCase());
927
- return (ctx) => {
928
- const text = ctx.content.toLowerCase();
929
- return lower.some((kw) => text.includes(kw));
930
- };
931
- }
932
- function contentPattern(pattern) {
933
- return (ctx) => {
934
- pattern.lastIndex = 0;
935
- return pattern.test(ctx.content);
936
- };
937
- }
938
- function toDateParts(date, tz) {
939
- const parts = new Intl.DateTimeFormat("en-CA", {
940
- timeZone: tz,
941
- year: "numeric",
942
- month: "2-digit",
943
- day: "2-digit",
944
- hour: "2-digit",
945
- hourCycle: "h23"
946
- }).formatToParts(date);
947
- const get = (type) => parts.find((p) => p.type === type).value;
948
- return {
949
- year: get("year"),
950
- month: get("month"),
951
- day: get("day"),
952
- hour: get("hour")
953
- };
954
- }
955
- function temporalChanged(ctx, tz, getKey) {
956
- if (ctx.lastMessageAt === void 0) return true;
957
- const nowParts = toDateParts(/* @__PURE__ */ new Date(), tz);
958
- const prevParts = toDateParts(new Date(ctx.lastMessageAt), tz);
959
- return getKey(nowParts) !== getKey(prevParts);
960
- }
961
- function getSeason(month) {
962
- if (month >= 2 && month <= 4) return "Spring";
963
- if (month >= 5 && month <= 7) return "Summer";
964
- if (month >= 8 && month <= 10) return "Fall";
965
- return "Winter";
966
- }
967
- function isoWeekKey(parts) {
968
- const d = new Date(
969
- Date.UTC(
970
- parseInt(parts.year),
971
- parseInt(parts.month) - 1,
972
- parseInt(parts.day)
973
- )
974
- );
975
- d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
976
- const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
977
- const weekNo = Math.ceil(
978
- ((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7
979
- );
980
- return `${d.getUTCFullYear()}-W${String(weekNo).padStart(2, "0")}`;
981
- }
982
- function dayChanged(tz = "UTC") {
983
- return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}-${p.day}`);
984
- }
985
- function hourChanged(tz = "UTC") {
986
- return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}-${p.day}-${p.hour}`);
987
- }
988
- function monthChanged(tz = "UTC") {
989
- return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}`);
990
- }
991
- function yearChanged(tz = "UTC") {
992
- return (ctx) => temporalChanged(ctx, tz, (p) => p.year);
993
- }
994
- function seasonChanged(tz = "UTC") {
995
- return (ctx) => temporalChanged(ctx, tz, (p) => getSeason(parseInt(p.month) - 1));
996
- }
997
- function weekChanged(tz = "UTC") {
998
- return (ctx) => temporalChanged(ctx, tz, isoWeekKey);
999
- }
1000
- function isConditionalReminder(fragment2) {
1001
- return fragment2.name === "reminder" && !!fragment2.metadata?.reminder;
1002
- }
1003
- function getConditionalReminder(fragment2) {
1004
- return fragment2.metadata.reminder;
1005
- }
1006
- var SYSTEM_REMINDER_OPEN_TAG = "<system-reminder>";
1007
- var SYSTEM_REMINDER_CLOSE_TAG = "</system-reminder>";
1008
- function getReminderRanges(metadata) {
1009
- return metadata?.reminders ?? [];
1010
- }
1011
- function stripTextByRanges(text, ranges) {
1012
- if (ranges.length === 0) {
1013
- return text;
1014
- }
1015
- const normalized = ranges.map((range) => ({
1016
- start: Math.max(0, Math.min(text.length, range.start)),
1017
- end: Math.max(0, Math.min(text.length, range.end))
1018
- })).filter((range) => range.end > range.start).sort((a, b) => a.start - b.start);
1019
- if (normalized.length === 0) {
1020
- return text;
1021
- }
1022
- let cursor = 0;
1023
- let output = "";
1024
- for (const range of normalized) {
1025
- if (range.start < cursor) {
1026
- if (range.end > cursor) {
1027
- cursor = range.end;
1028
- }
1029
- continue;
1030
- }
1031
- output += text.slice(cursor, range.start);
1032
- cursor = range.end;
1033
- }
1034
- output += text.slice(cursor);
1035
- return output.trimEnd();
1036
- }
1037
- function stripReminders(message2) {
1038
- const reminderRanges = getReminderRanges(
1039
- isRecord(message2.metadata) ? message2.metadata : void 0
1040
- );
1041
- const rangesByPartIndex = /* @__PURE__ */ new Map();
1042
- for (const range of reminderRanges) {
1043
- const partRanges = rangesByPartIndex.get(range.partIndex) ?? [];
1044
- partRanges.push({ start: range.start, end: range.end });
1045
- rangesByPartIndex.set(range.partIndex, partRanges);
1046
- }
1047
- const strippedParts = message2.parts.flatMap((part, partIndex) => {
1048
- const clonedPart = { ...part };
1049
- const ranges = rangesByPartIndex.get(partIndex);
1050
- if (clonedPart.type !== "text" || ranges === void 0) {
1051
- return [clonedPart];
1052
- }
1053
- const strippedText = stripTextByRanges(clonedPart.text, ranges);
1054
- if (strippedText.length === 0) {
1055
- return [];
1056
- }
1057
- return [{ ...clonedPart, text: strippedText }];
1058
- });
1059
- const nextMessage = {
1060
- ...message2,
1061
- parts: strippedParts
1062
- };
1063
- if (isRecord(message2.metadata)) {
1064
- const metadata = { ...message2.metadata };
1065
- delete metadata.reminders;
1066
- if (Object.keys(metadata).length > 0) {
1067
- nextMessage.metadata = metadata;
1068
- } else {
1069
- delete nextMessage.metadata;
1070
- }
1071
- }
1072
- return nextMessage;
1073
- }
1074
- function extractPlainText(message2) {
1075
- return message2.parts.filter(isTextUIPart).map((part) => part.text).join(" ");
1076
- }
1077
- function isRecord(value) {
1078
- return typeof value === "object" && value !== null && !Array.isArray(value);
1079
- }
1080
- function assertReminderText(text) {
1081
- if (text.trim().length === 0) {
1082
- throw new Error("Reminder text must not be empty");
1083
- }
1084
- }
1085
- function formatTaggedReminder(text) {
1086
- return `${SYSTEM_REMINDER_OPEN_TAG}${text}${SYSTEM_REMINDER_CLOSE_TAG}`;
1087
- }
1088
- function findLastTextPartIndex(message2) {
1089
- for (let i = message2.parts.length - 1; i >= 0; i--) {
1090
- if (message2.parts[i].type === "text") {
1091
- return i;
1092
- }
1093
- }
1094
- return void 0;
1095
- }
1096
- function ensureTextPart(message2) {
1097
- const existingIndex = findLastTextPartIndex(message2);
1098
- if (existingIndex !== void 0) {
1099
- return existingIndex;
1100
- }
1101
- const reminderPart = {
1102
- type: "text",
1103
- text: ""
1104
- };
1105
- message2.parts.push(reminderPart);
1106
- return message2.parts.length - 1;
1107
- }
1108
- function applyInlineReminder(message2, value) {
1109
- const partIndex = ensureTextPart(message2);
1110
- const textPart = message2.parts[partIndex];
1111
- if (textPart.type !== "text") {
1112
- throw new Error("Failed to resolve text part for inline reminder");
1113
- }
1114
- const reminderText = formatTaggedReminder(value);
1115
- const start = textPart.text.length;
1116
- const updatedText = `${textPart.text}${reminderText}`;
1117
- message2.parts[partIndex] = { ...textPart, text: updatedText };
1118
- return {
1119
- id: generateId2(),
1120
- text: value,
1121
- partIndex,
1122
- start,
1123
- end: start + reminderText.length,
1124
- mode: "inline"
1125
- };
1126
- }
1127
- function applyPartReminder(message2, value) {
1128
- const part = { type: "text", text: value };
1129
- message2.parts.push(part);
1130
- const partIndex = message2.parts.length - 1;
1131
- return {
1132
- id: generateId2(),
1133
- text: value,
1134
- partIndex,
1135
- start: 0,
1136
- end: value.length,
1137
- mode: "part"
1138
- };
1139
- }
1140
- function resolveReminderText(item, ctx) {
1141
- return resolveReminder(item, ctx)?.text ?? "";
1142
- }
1143
- function normalizeReminderResolution(value) {
1144
- if (typeof value === "string") {
1145
- return value.trim().length === 0 ? null : { text: value };
1146
- }
1147
- if (value.text.trim().length === 0) {
1148
- return null;
1149
- }
1150
- return value;
1151
- }
1152
- function resolveReminder(item, ctx) {
1153
- const resolvedText = typeof item.text === "function" ? item.text(ctx) : item.text;
1154
- const resolved = normalizeReminderResolution(resolvedText);
1155
- if (!resolved) {
1156
- return null;
1157
- }
1158
- const metadata = item.metadata || resolved.metadata ? {
1159
- ...item.metadata ?? {},
1160
- ...resolved.metadata ?? {}
1161
- } : void 0;
1162
- return metadata ? { ...resolved, metadata } : resolved;
1163
- }
1164
- function mergeMessageMetadata(message2, addedMetadata) {
1165
- if (Object.keys(addedMetadata).length === 0) {
1166
- return;
1167
- }
1168
- const metadata = isRecord(message2.metadata) ? { ...message2.metadata } : {};
1169
- message2.metadata = { ...metadata, ...addedMetadata };
1170
- }
1171
- function applyReminderToMessage(message2, item, ctx) {
1172
- const resolved = resolveReminder(item, ctx);
1173
- if (!resolved) {
1174
- return null;
1175
- }
1176
- if (resolved.metadata) {
1177
- mergeMessageMetadata(message2, resolved.metadata);
1178
- }
1179
- return item.asPart ? applyPartReminder(message2, resolved.text) : applyInlineReminder(message2, resolved.text);
1180
- }
1181
- function mergeReminderMetadata(message2, addedReminders) {
1182
- if (addedReminders.length === 0) return;
1183
- const metadata = isRecord(message2.metadata) ? { ...message2.metadata } : {};
1184
- const existing = Array.isArray(metadata.reminders) ? metadata.reminders : [];
1185
- metadata.reminders = [...existing, ...addedReminders];
1186
- message2.metadata = metadata;
1187
- }
1188
- function reminder(text, options) {
1189
- if (typeof text === "string") {
1190
- assertReminderText(text);
1191
- }
1192
- if (options && "when" in options && options.when) {
1193
- return {
1194
- name: "reminder",
1195
- metadata: {
1196
- reminder: {
1197
- text,
1198
- when: options.when,
1199
- asPart: options.asPart ?? false
1200
- }
1201
- }
1202
- };
1203
- }
1204
- return {
1205
- text,
1206
- asPart: options?.asPart ?? false
1207
- };
1208
- }
1209
- function user(content, ...reminders) {
1210
- const message2 = typeof content === "string" ? {
1211
- id: generateId2(),
1212
- role: "user",
1213
- parts: [{ type: "text", text: content }]
1214
- } : { ...content, role: "user", parts: [...content.parts] };
1215
- if (reminders.length > 0) {
1216
- const plainText = extractPlainText(message2);
1217
- const added = [];
1218
- for (const item of reminders) {
1219
- const meta = applyReminderToMessage(message2, item, {
1220
- content: plainText
1221
- });
1222
- if (meta) added.push(meta);
1223
- }
1224
- mergeReminderMetadata(message2, added);
1225
- }
1226
- return {
1227
- id: message2.id,
1228
- name: "user",
1229
- type: "message",
1230
- persist: true,
1231
- codec: {
1232
- decode() {
1233
- return message2;
1234
- },
1235
- encode() {
1236
- return message2;
1237
- }
1238
- }
1239
- };
1240
- }
1241
-
1242
- // packages/context/src/lib/guardrail.ts
1243
- function pass(part) {
1244
- return { type: "pass", part };
1245
- }
1246
- function fail(feedback) {
1247
- return { type: "fail", feedback };
1248
- }
1249
- function stop(part) {
1250
- return { type: "stop", part };
1251
- }
1252
- function runGuardrailChain(part, guardrails, context) {
1253
- let currentPart = part;
1254
- for (const guardrail2 of guardrails) {
1255
- const result = guardrail2.handle(currentPart, context);
1256
- if (result.type === "fail" || result.type === "stop") {
1257
- return result;
1258
- }
1259
- currentPart = result.part;
1260
- }
1261
- return pass(currentPart);
1262
- }
903
+ import { generateId as generateId2 } from "ai";
1263
904
 
1264
905
  // packages/context/src/lib/renderers/abstract.renderer.ts
1265
906
  import pluralize from "pluralize";
@@ -2068,74 +1709,460 @@ ${nested}`);
2068
1709
  if (this.isPrimitive(data)) {
2069
1710
  return `${this.#pad(ctx.depth)}${fragment2.name}: ${this.#formatValue(data)}`;
2070
1711
  }
2071
- if (isFragment(data)) {
2072
- const child = this.renderFragment(data, {
2073
- ...ctx,
2074
- depth: ctx.depth + 1
2075
- });
2076
- return `${this.#pad(ctx.depth)}${fragment2.name}:
2077
- ${child}`;
1712
+ if (isFragment(data)) {
1713
+ const child = this.renderFragment(data, {
1714
+ ...ctx,
1715
+ depth: ctx.depth + 1
1716
+ });
1717
+ return `${this.#pad(ctx.depth)}${fragment2.name}:
1718
+ ${child}`;
1719
+ }
1720
+ if (Array.isArray(data)) {
1721
+ return this.#renderArrayField(fragment2.name, data, ctx.depth);
1722
+ }
1723
+ if (isFragmentObject(data)) {
1724
+ const entries = this.#renderObjectEntries(data, ctx.depth + 1);
1725
+ if (!entries) {
1726
+ return `${this.#pad(ctx.depth)}${fragment2.name}:`;
1727
+ }
1728
+ return `${this.#pad(ctx.depth)}${fragment2.name}:
1729
+ ${entries}`;
1730
+ }
1731
+ return `${this.#pad(ctx.depth)}${fragment2.name}:`;
1732
+ }
1733
+ renderPrimitive(key, value, ctx) {
1734
+ return `${this.#pad(ctx.depth)}${key}: ${this.#formatValue(value)}`;
1735
+ }
1736
+ renderArray(key, items, ctx) {
1737
+ return this.#renderArrayField(key, items, ctx.depth);
1738
+ }
1739
+ renderObject(key, obj, ctx) {
1740
+ const entries = this.#renderObjectEntries(obj, ctx.depth + 1);
1741
+ if (!entries) {
1742
+ return `${this.#pad(ctx.depth)}${key}:`;
1743
+ }
1744
+ return `${this.#pad(ctx.depth)}${key}:
1745
+ ${entries}`;
1746
+ }
1747
+ #pad(depth) {
1748
+ return " ".repeat(depth);
1749
+ }
1750
+ #needsQuoting(value) {
1751
+ if (value === "") return true;
1752
+ if (value !== value.trim()) return true;
1753
+ if (["true", "false", "null"].includes(value.toLowerCase())) return true;
1754
+ if (/^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i.test(value)) return true;
1755
+ if (/[:\\"'[\]{}|,\t\n\r]/.test(value)) return true;
1756
+ if (value.startsWith("-")) return true;
1757
+ return false;
1758
+ }
1759
+ #escape(value) {
1760
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
1761
+ }
1762
+ #canonicalizeNumber(n) {
1763
+ if (!Number.isFinite(n)) return "null";
1764
+ if (Object.is(n, -0)) return "0";
1765
+ return String(n);
1766
+ }
1767
+ #formatValue(value) {
1768
+ if (value === null) return "null";
1769
+ if (typeof value === "boolean") return String(value);
1770
+ if (typeof value === "number") return this.#canonicalizeNumber(value);
1771
+ if (typeof value === "string") {
1772
+ if (this.#needsQuoting(value)) {
1773
+ return `"${this.#escape(value)}"`;
1774
+ }
1775
+ return value;
1776
+ }
1777
+ return `"${this.#escape(JSON.stringify(value))}"`;
1778
+ }
1779
+ };
1780
+
1781
+ // packages/context/src/lib/text.ts
1782
+ import { isTextUIPart } from "ai";
1783
+ function getTextParts(message2) {
1784
+ return message2.parts.filter(isTextUIPart).map((part) => part.text);
1785
+ }
1786
+ function extractPlainText(message2) {
1787
+ return getTextParts(message2).join(" ");
1788
+ }
1789
+
1790
+ // packages/context/src/lib/fragments/message/user.ts
1791
+ function everyNTurns(n) {
1792
+ return ({ turn }) => turn % n === 0;
1793
+ }
1794
+ function once() {
1795
+ return ({ turn }) => turn === 1;
1796
+ }
1797
+ function firstN(n) {
1798
+ return ({ turn }) => turn <= n;
1799
+ }
1800
+ function afterTurn(n) {
1801
+ return ({ turn }) => turn > n;
1802
+ }
1803
+ function and(...predicates) {
1804
+ return async (ctx) => {
1805
+ for (const it of predicates) {
1806
+ if (!await it(ctx)) return false;
1807
+ }
1808
+ return true;
1809
+ };
1810
+ }
1811
+ function or(...predicates) {
1812
+ return async (ctx) => {
1813
+ for (const it of predicates) {
1814
+ if (await it(ctx)) return true;
1815
+ }
1816
+ return false;
1817
+ };
1818
+ }
1819
+ function not(predicate) {
1820
+ return async (ctx) => !await predicate(ctx);
1821
+ }
1822
+ function contentIncludes(keywords) {
1823
+ const lower = keywords.map((k) => k.toLowerCase());
1824
+ return (ctx) => {
1825
+ const text = ctx.content.toLowerCase();
1826
+ return lower.some((kw) => text.includes(kw));
1827
+ };
1828
+ }
1829
+ function contentPattern(pattern) {
1830
+ return (ctx) => {
1831
+ pattern.lastIndex = 0;
1832
+ return pattern.test(ctx.content);
1833
+ };
1834
+ }
1835
+ function toDateParts(date, tz) {
1836
+ const parts = new Intl.DateTimeFormat("en-CA", {
1837
+ timeZone: tz,
1838
+ year: "numeric",
1839
+ month: "2-digit",
1840
+ day: "2-digit",
1841
+ hour: "2-digit",
1842
+ hourCycle: "h23"
1843
+ }).formatToParts(date);
1844
+ const get = (type) => parts.find((p) => p.type === type).value;
1845
+ return {
1846
+ year: get("year"),
1847
+ month: get("month"),
1848
+ day: get("day"),
1849
+ hour: get("hour")
1850
+ };
1851
+ }
1852
+ function temporalChanged(ctx, tz, getKey) {
1853
+ if (ctx.lastMessageAt === void 0) return true;
1854
+ const nowParts = toDateParts(/* @__PURE__ */ new Date(), tz);
1855
+ const prevParts = toDateParts(new Date(ctx.lastMessageAt), tz);
1856
+ return getKey(nowParts) !== getKey(prevParts);
1857
+ }
1858
+ function getSeason(month) {
1859
+ if (month >= 2 && month <= 4) return "Spring";
1860
+ if (month >= 5 && month <= 7) return "Summer";
1861
+ if (month >= 8 && month <= 10) return "Fall";
1862
+ return "Winter";
1863
+ }
1864
+ function isoWeekKey(parts) {
1865
+ const d = new Date(
1866
+ Date.UTC(
1867
+ parseInt(parts.year),
1868
+ parseInt(parts.month) - 1,
1869
+ parseInt(parts.day)
1870
+ )
1871
+ );
1872
+ d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
1873
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
1874
+ const weekNo = Math.ceil(
1875
+ ((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7
1876
+ );
1877
+ return `${d.getUTCFullYear()}-W${String(weekNo).padStart(2, "0")}`;
1878
+ }
1879
+ function dayChanged(tz = "UTC") {
1880
+ return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}-${p.day}`);
1881
+ }
1882
+ function hourChanged(tz = "UTC") {
1883
+ return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}-${p.day}-${p.hour}`);
1884
+ }
1885
+ function monthChanged(tz = "UTC") {
1886
+ return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}`);
1887
+ }
1888
+ function yearChanged(tz = "UTC") {
1889
+ return (ctx) => temporalChanged(ctx, tz, (p) => p.year);
1890
+ }
1891
+ function seasonChanged(tz = "UTC") {
1892
+ return (ctx) => temporalChanged(ctx, tz, (p) => getSeason(parseInt(p.month) - 1));
1893
+ }
1894
+ function weekChanged(tz = "UTC") {
1895
+ return (ctx) => temporalChanged(ctx, tz, isoWeekKey);
1896
+ }
1897
+ function isConditionalReminder(fragment2) {
1898
+ return fragment2.name === "reminder" && !!fragment2.metadata?.reminder;
1899
+ }
1900
+ function getConditionalReminder(fragment2) {
1901
+ return fragment2.metadata.reminder;
1902
+ }
1903
+ var SYSTEM_REMINDER_OPEN_TAG = "<system-reminder>";
1904
+ var SYSTEM_REMINDER_CLOSE_TAG = "</system-reminder>";
1905
+ function getReminderRanges(metadata) {
1906
+ return metadata?.reminders ?? [];
1907
+ }
1908
+ function stripTextByRanges(text, ranges) {
1909
+ if (ranges.length === 0) {
1910
+ return text;
1911
+ }
1912
+ const normalized = ranges.map((range) => ({
1913
+ start: Math.max(0, Math.min(text.length, range.start)),
1914
+ end: Math.max(0, Math.min(text.length, range.end))
1915
+ })).filter((range) => range.end > range.start).sort((a, b) => a.start - b.start);
1916
+ if (normalized.length === 0) {
1917
+ return text;
1918
+ }
1919
+ let cursor = 0;
1920
+ let output = "";
1921
+ for (const range of normalized) {
1922
+ if (range.start < cursor) {
1923
+ if (range.end > cursor) {
1924
+ cursor = range.end;
1925
+ }
1926
+ continue;
1927
+ }
1928
+ output += text.slice(cursor, range.start);
1929
+ cursor = range.end;
1930
+ }
1931
+ output += text.slice(cursor);
1932
+ return output.trimEnd();
1933
+ }
1934
+ function stripReminders(message2) {
1935
+ const reminderRanges = getReminderRanges(
1936
+ isRecord(message2.metadata) ? message2.metadata : void 0
1937
+ );
1938
+ const rangesByPartIndex = /* @__PURE__ */ new Map();
1939
+ for (const range of reminderRanges) {
1940
+ const partRanges = rangesByPartIndex.get(range.partIndex) ?? [];
1941
+ partRanges.push({ start: range.start, end: range.end });
1942
+ rangesByPartIndex.set(range.partIndex, partRanges);
1943
+ }
1944
+ const strippedParts = message2.parts.flatMap((part, partIndex) => {
1945
+ const clonedPart = { ...part };
1946
+ const ranges = rangesByPartIndex.get(partIndex);
1947
+ if (clonedPart.type !== "text" || ranges === void 0) {
1948
+ return [clonedPart];
1949
+ }
1950
+ const strippedText = stripTextByRanges(clonedPart.text, ranges);
1951
+ if (strippedText.length === 0) {
1952
+ return [];
2078
1953
  }
2079
- if (Array.isArray(data)) {
2080
- return this.#renderArrayField(fragment2.name, data, ctx.depth);
1954
+ return [{ ...clonedPart, text: strippedText }];
1955
+ });
1956
+ const nextMessage = {
1957
+ ...message2,
1958
+ parts: strippedParts
1959
+ };
1960
+ if (isRecord(message2.metadata)) {
1961
+ const metadata = { ...message2.metadata };
1962
+ delete metadata.reminders;
1963
+ if (Object.keys(metadata).length > 0) {
1964
+ nextMessage.metadata = metadata;
1965
+ } else {
1966
+ delete nextMessage.metadata;
2081
1967
  }
2082
- if (isFragmentObject(data)) {
2083
- const entries = this.#renderObjectEntries(data, ctx.depth + 1);
2084
- if (!entries) {
2085
- return `${this.#pad(ctx.depth)}${fragment2.name}:`;
2086
- }
2087
- return `${this.#pad(ctx.depth)}${fragment2.name}:
2088
- ${entries}`;
1968
+ }
1969
+ return nextMessage;
1970
+ }
1971
+ function isRecord(value) {
1972
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1973
+ }
1974
+ function assertReminderText(text) {
1975
+ if (text.trim().length === 0) {
1976
+ throw new Error("Reminder text must not be empty");
1977
+ }
1978
+ }
1979
+ function formatTaggedReminder(text) {
1980
+ return `${SYSTEM_REMINDER_OPEN_TAG}${text}${SYSTEM_REMINDER_CLOSE_TAG}`;
1981
+ }
1982
+ function findLastTextPartIndex(message2) {
1983
+ for (let i = message2.parts.length - 1; i >= 0; i--) {
1984
+ if (message2.parts[i].type === "text") {
1985
+ return i;
2089
1986
  }
2090
- return `${this.#pad(ctx.depth)}${fragment2.name}:`;
2091
1987
  }
2092
- renderPrimitive(key, value, ctx) {
2093
- return `${this.#pad(ctx.depth)}${key}: ${this.#formatValue(value)}`;
1988
+ return void 0;
1989
+ }
1990
+ function ensureTextPart(message2) {
1991
+ const existingIndex = findLastTextPartIndex(message2);
1992
+ if (existingIndex !== void 0) {
1993
+ return existingIndex;
2094
1994
  }
2095
- renderArray(key, items, ctx) {
2096
- return this.#renderArrayField(key, items, ctx.depth);
1995
+ const reminderPart = {
1996
+ type: "text",
1997
+ text: ""
1998
+ };
1999
+ message2.parts.push(reminderPart);
2000
+ return message2.parts.length - 1;
2001
+ }
2002
+ function applyInlineReminder(message2, value) {
2003
+ const partIndex = ensureTextPart(message2);
2004
+ const textPart = message2.parts[partIndex];
2005
+ if (textPart.type !== "text") {
2006
+ throw new Error("Failed to resolve text part for inline reminder");
2097
2007
  }
2098
- renderObject(key, obj, ctx) {
2099
- const entries = this.#renderObjectEntries(obj, ctx.depth + 1);
2100
- if (!entries) {
2101
- return `${this.#pad(ctx.depth)}${key}:`;
2102
- }
2103
- return `${this.#pad(ctx.depth)}${key}:
2104
- ${entries}`;
2008
+ const reminderText = formatTaggedReminder(value);
2009
+ const start = textPart.text.length;
2010
+ const updatedText = `${textPart.text}${reminderText}`;
2011
+ message2.parts[partIndex] = { ...textPart, text: updatedText };
2012
+ return {
2013
+ id: generateId2(),
2014
+ text: value,
2015
+ partIndex,
2016
+ start,
2017
+ end: start + reminderText.length,
2018
+ mode: "inline"
2019
+ };
2020
+ }
2021
+ function applyPartReminder(message2, value) {
2022
+ const part = { type: "text", text: value };
2023
+ message2.parts.push(part);
2024
+ const partIndex = message2.parts.length - 1;
2025
+ return {
2026
+ id: generateId2(),
2027
+ text: value,
2028
+ partIndex,
2029
+ start: 0,
2030
+ end: value.length,
2031
+ mode: "part"
2032
+ };
2033
+ }
2034
+ function resolveReminderText(item, ctx) {
2035
+ return resolveReminder(item, ctx)?.text ?? "";
2036
+ }
2037
+ function normalizeReminderResolution(value) {
2038
+ if (typeof value === "string") {
2039
+ return value.trim().length === 0 ? null : { text: value };
2105
2040
  }
2106
- #pad(depth) {
2107
- return " ".repeat(depth);
2041
+ if (value.text.trim().length === 0) {
2042
+ return null;
2108
2043
  }
2109
- #needsQuoting(value) {
2110
- if (value === "") return true;
2111
- if (value !== value.trim()) return true;
2112
- if (["true", "false", "null"].includes(value.toLowerCase())) return true;
2113
- if (/^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i.test(value)) return true;
2114
- if (/[:\\"'[\]{}|,\t\n\r]/.test(value)) return true;
2115
- if (value.startsWith("-")) return true;
2116
- return false;
2044
+ return value;
2045
+ }
2046
+ function resolveReminder(item, ctx) {
2047
+ const resolvedText = typeof item.text === "function" ? item.text(ctx) : item.text;
2048
+ const resolved = normalizeReminderResolution(resolvedText);
2049
+ if (!resolved) {
2050
+ return null;
2117
2051
  }
2118
- #escape(value) {
2119
- return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
2052
+ const metadata = item.metadata || resolved.metadata ? {
2053
+ ...item.metadata ?? {},
2054
+ ...resolved.metadata ?? {}
2055
+ } : void 0;
2056
+ return metadata ? { ...resolved, metadata } : resolved;
2057
+ }
2058
+ async function resolveReminderAsync(item, ctx) {
2059
+ const text = await (typeof item.text === "function" ? item.text(ctx) : item.text);
2060
+ const resolved = normalizeReminderResolution(text);
2061
+ if (!resolved) return null;
2062
+ const metadata = item.metadata || resolved.metadata ? { ...item.metadata ?? {}, ...resolved.metadata ?? {} } : void 0;
2063
+ return metadata ? { ...resolved, metadata } : resolved;
2064
+ }
2065
+ function mergeMessageMetadata(message2, addedMetadata) {
2066
+ if (Object.keys(addedMetadata).length === 0) {
2067
+ return;
2120
2068
  }
2121
- #canonicalizeNumber(n) {
2122
- if (!Number.isFinite(n)) return "null";
2123
- if (Object.is(n, -0)) return "0";
2124
- return String(n);
2069
+ const metadata = isRecord(message2.metadata) ? { ...message2.metadata } : {};
2070
+ message2.metadata = { ...metadata, ...addedMetadata };
2071
+ }
2072
+ function applyReminderToMessage(message2, item, ctx) {
2073
+ const resolved = resolveReminder(item, ctx);
2074
+ if (!resolved) {
2075
+ return null;
2125
2076
  }
2126
- #formatValue(value) {
2127
- if (value === null) return "null";
2128
- if (typeof value === "boolean") return String(value);
2129
- if (typeof value === "number") return this.#canonicalizeNumber(value);
2130
- if (typeof value === "string") {
2131
- if (this.#needsQuoting(value)) {
2132
- return `"${this.#escape(value)}"`;
2077
+ if (resolved.metadata) {
2078
+ mergeMessageMetadata(message2, resolved.metadata);
2079
+ }
2080
+ return item.asPart ? applyPartReminder(message2, resolved.text) : applyInlineReminder(message2, resolved.text);
2081
+ }
2082
+ function mergeReminderMetadata(message2, addedReminders) {
2083
+ if (addedReminders.length === 0) return;
2084
+ const metadata = isRecord(message2.metadata) ? { ...message2.metadata } : {};
2085
+ const existing = Array.isArray(metadata.reminders) ? metadata.reminders : [];
2086
+ metadata.reminders = [...existing, ...addedReminders];
2087
+ message2.metadata = metadata;
2088
+ }
2089
+ function reminder(textOrFragment, options) {
2090
+ const text = isFragment(textOrFragment) ? new XmlRenderer().render([textOrFragment]) : textOrFragment;
2091
+ if (typeof text === "string") {
2092
+ assertReminderText(text);
2093
+ }
2094
+ if (options && "when" in options && options.when) {
2095
+ return {
2096
+ name: "reminder",
2097
+ data: null,
2098
+ metadata: {
2099
+ reminder: {
2100
+ text,
2101
+ when: options.when,
2102
+ asPart: options.asPart ?? false
2103
+ }
2133
2104
  }
2134
- return value;
2105
+ };
2106
+ }
2107
+ return {
2108
+ text,
2109
+ asPart: options?.asPart ?? false
2110
+ };
2111
+ }
2112
+ function user(content, ...reminders) {
2113
+ const message2 = typeof content === "string" ? {
2114
+ id: generateId2(),
2115
+ role: "user",
2116
+ parts: [{ type: "text", text: content }]
2117
+ } : { ...content, role: "user", parts: [...content.parts] };
2118
+ if (reminders.length > 0) {
2119
+ const plainText = extractPlainText(message2);
2120
+ const added = [];
2121
+ for (const item of reminders) {
2122
+ const meta = applyReminderToMessage(message2, item, {
2123
+ content: plainText
2124
+ });
2125
+ if (meta) added.push(meta);
2135
2126
  }
2136
- return `"${this.#escape(JSON.stringify(value))}"`;
2127
+ mergeReminderMetadata(message2, added);
2137
2128
  }
2138
- };
2129
+ return {
2130
+ id: message2.id,
2131
+ name: "user",
2132
+ type: "message",
2133
+ persist: true,
2134
+ codec: {
2135
+ decode() {
2136
+ return message2;
2137
+ },
2138
+ encode() {
2139
+ return message2;
2140
+ }
2141
+ }
2142
+ };
2143
+ }
2144
+
2145
+ // packages/context/src/lib/guardrail.ts
2146
+ function pass(part) {
2147
+ return { type: "pass", part };
2148
+ }
2149
+ function fail(feedback) {
2150
+ return { type: "fail", feedback };
2151
+ }
2152
+ function stop(part) {
2153
+ return { type: "stop", part };
2154
+ }
2155
+ function runGuardrailChain(part, guardrails, context) {
2156
+ let currentPart = part;
2157
+ for (const guardrail2 of guardrails) {
2158
+ const result = guardrail2.handle(currentPart, context);
2159
+ if (result.type === "fail" || result.type === "stop") {
2160
+ return result;
2161
+ }
2162
+ currentPart = result.part;
2163
+ }
2164
+ return pass(currentPart);
2165
+ }
2139
2166
 
2140
2167
  // packages/context/src/lib/render.ts
2141
2168
  function render(tag, ...fragments) {
@@ -2320,7 +2347,6 @@ export {
2320
2347
  everyNTurns,
2321
2348
  example,
2322
2349
  explain,
2323
- extractPlainText,
2324
2350
  fail,
2325
2351
  firstN,
2326
2352
  fragment,
@@ -2359,6 +2385,7 @@ export {
2359
2385
  reminder,
2360
2386
  render,
2361
2387
  resolveReminder,
2388
+ resolveReminderAsync,
2362
2389
  resolveReminderText,
2363
2390
  role,
2364
2391
  runGuardrailChain,