@deepagents/context 0.34.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
@@ -902,373 +902,6 @@ async function estimate(modelId, renderer, ...fragments) {
902
902
  // packages/context/src/lib/fragments/message/user.ts
903
903
  import { generateId as generateId2 } from "ai";
904
904
 
905
- // packages/context/src/lib/text.ts
906
- import { isTextUIPart } from "ai";
907
- function getTextParts(message2) {
908
- return message2.parts.filter(isTextUIPart).map((part) => part.text);
909
- }
910
- function extractPlainText(message2) {
911
- return getTextParts(message2).join(" ");
912
- }
913
-
914
- // packages/context/src/lib/fragments/message/user.ts
915
- function everyNTurns(n) {
916
- return ({ turn }) => turn % n === 0;
917
- }
918
- function once() {
919
- return ({ turn }) => turn === 1;
920
- }
921
- function firstN(n) {
922
- return ({ turn }) => turn <= n;
923
- }
924
- function afterTurn(n) {
925
- return ({ turn }) => turn > n;
926
- }
927
- function and(...predicates) {
928
- return (ctx) => predicates.every((p) => p(ctx));
929
- }
930
- function or(...predicates) {
931
- return (ctx) => predicates.some((p) => p(ctx));
932
- }
933
- function not(predicate) {
934
- return (ctx) => !predicate(ctx);
935
- }
936
- function contentIncludes(keywords) {
937
- const lower = keywords.map((k) => k.toLowerCase());
938
- return (ctx) => {
939
- const text = ctx.content.toLowerCase();
940
- return lower.some((kw) => text.includes(kw));
941
- };
942
- }
943
- function contentPattern(pattern) {
944
- return (ctx) => {
945
- pattern.lastIndex = 0;
946
- return pattern.test(ctx.content);
947
- };
948
- }
949
- function toDateParts(date, tz) {
950
- const parts = new Intl.DateTimeFormat("en-CA", {
951
- timeZone: tz,
952
- year: "numeric",
953
- month: "2-digit",
954
- day: "2-digit",
955
- hour: "2-digit",
956
- hourCycle: "h23"
957
- }).formatToParts(date);
958
- const get = (type) => parts.find((p) => p.type === type).value;
959
- return {
960
- year: get("year"),
961
- month: get("month"),
962
- day: get("day"),
963
- hour: get("hour")
964
- };
965
- }
966
- function temporalChanged(ctx, tz, getKey) {
967
- if (ctx.lastMessageAt === void 0) return true;
968
- const nowParts = toDateParts(/* @__PURE__ */ new Date(), tz);
969
- const prevParts = toDateParts(new Date(ctx.lastMessageAt), tz);
970
- return getKey(nowParts) !== getKey(prevParts);
971
- }
972
- function getSeason(month) {
973
- if (month >= 2 && month <= 4) return "Spring";
974
- if (month >= 5 && month <= 7) return "Summer";
975
- if (month >= 8 && month <= 10) return "Fall";
976
- return "Winter";
977
- }
978
- function isoWeekKey(parts) {
979
- const d = new Date(
980
- Date.UTC(
981
- parseInt(parts.year),
982
- parseInt(parts.month) - 1,
983
- parseInt(parts.day)
984
- )
985
- );
986
- d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
987
- const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
988
- const weekNo = Math.ceil(
989
- ((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7
990
- );
991
- return `${d.getUTCFullYear()}-W${String(weekNo).padStart(2, "0")}`;
992
- }
993
- function dayChanged(tz = "UTC") {
994
- return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}-${p.day}`);
995
- }
996
- function hourChanged(tz = "UTC") {
997
- return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}-${p.day}-${p.hour}`);
998
- }
999
- function monthChanged(tz = "UTC") {
1000
- return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}`);
1001
- }
1002
- function yearChanged(tz = "UTC") {
1003
- return (ctx) => temporalChanged(ctx, tz, (p) => p.year);
1004
- }
1005
- function seasonChanged(tz = "UTC") {
1006
- return (ctx) => temporalChanged(ctx, tz, (p) => getSeason(parseInt(p.month) - 1));
1007
- }
1008
- function weekChanged(tz = "UTC") {
1009
- return (ctx) => temporalChanged(ctx, tz, isoWeekKey);
1010
- }
1011
- function isConditionalReminder(fragment2) {
1012
- return fragment2.name === "reminder" && !!fragment2.metadata?.reminder;
1013
- }
1014
- function getConditionalReminder(fragment2) {
1015
- return fragment2.metadata.reminder;
1016
- }
1017
- var SYSTEM_REMINDER_OPEN_TAG = "<system-reminder>";
1018
- var SYSTEM_REMINDER_CLOSE_TAG = "</system-reminder>";
1019
- function getReminderRanges(metadata) {
1020
- return metadata?.reminders ?? [];
1021
- }
1022
- function stripTextByRanges(text, ranges) {
1023
- if (ranges.length === 0) {
1024
- return text;
1025
- }
1026
- const normalized = ranges.map((range) => ({
1027
- start: Math.max(0, Math.min(text.length, range.start)),
1028
- end: Math.max(0, Math.min(text.length, range.end))
1029
- })).filter((range) => range.end > range.start).sort((a, b) => a.start - b.start);
1030
- if (normalized.length === 0) {
1031
- return text;
1032
- }
1033
- let cursor = 0;
1034
- let output = "";
1035
- for (const range of normalized) {
1036
- if (range.start < cursor) {
1037
- if (range.end > cursor) {
1038
- cursor = range.end;
1039
- }
1040
- continue;
1041
- }
1042
- output += text.slice(cursor, range.start);
1043
- cursor = range.end;
1044
- }
1045
- output += text.slice(cursor);
1046
- return output.trimEnd();
1047
- }
1048
- function stripReminders(message2) {
1049
- const reminderRanges = getReminderRanges(
1050
- isRecord(message2.metadata) ? message2.metadata : void 0
1051
- );
1052
- const rangesByPartIndex = /* @__PURE__ */ new Map();
1053
- for (const range of reminderRanges) {
1054
- const partRanges = rangesByPartIndex.get(range.partIndex) ?? [];
1055
- partRanges.push({ start: range.start, end: range.end });
1056
- rangesByPartIndex.set(range.partIndex, partRanges);
1057
- }
1058
- const strippedParts = message2.parts.flatMap((part, partIndex) => {
1059
- const clonedPart = { ...part };
1060
- const ranges = rangesByPartIndex.get(partIndex);
1061
- if (clonedPart.type !== "text" || ranges === void 0) {
1062
- return [clonedPart];
1063
- }
1064
- const strippedText = stripTextByRanges(clonedPart.text, ranges);
1065
- if (strippedText.length === 0) {
1066
- return [];
1067
- }
1068
- return [{ ...clonedPart, text: strippedText }];
1069
- });
1070
- const nextMessage = {
1071
- ...message2,
1072
- parts: strippedParts
1073
- };
1074
- if (isRecord(message2.metadata)) {
1075
- const metadata = { ...message2.metadata };
1076
- delete metadata.reminders;
1077
- if (Object.keys(metadata).length > 0) {
1078
- nextMessage.metadata = metadata;
1079
- } else {
1080
- delete nextMessage.metadata;
1081
- }
1082
- }
1083
- return nextMessage;
1084
- }
1085
- function isRecord(value) {
1086
- return typeof value === "object" && value !== null && !Array.isArray(value);
1087
- }
1088
- function assertReminderText(text) {
1089
- if (text.trim().length === 0) {
1090
- throw new Error("Reminder text must not be empty");
1091
- }
1092
- }
1093
- function formatTaggedReminder(text) {
1094
- return `${SYSTEM_REMINDER_OPEN_TAG}${text}${SYSTEM_REMINDER_CLOSE_TAG}`;
1095
- }
1096
- function findLastTextPartIndex(message2) {
1097
- for (let i = message2.parts.length - 1; i >= 0; i--) {
1098
- if (message2.parts[i].type === "text") {
1099
- return i;
1100
- }
1101
- }
1102
- return void 0;
1103
- }
1104
- function ensureTextPart(message2) {
1105
- const existingIndex = findLastTextPartIndex(message2);
1106
- if (existingIndex !== void 0) {
1107
- return existingIndex;
1108
- }
1109
- const reminderPart = {
1110
- type: "text",
1111
- text: ""
1112
- };
1113
- message2.parts.push(reminderPart);
1114
- return message2.parts.length - 1;
1115
- }
1116
- function applyInlineReminder(message2, value) {
1117
- const partIndex = ensureTextPart(message2);
1118
- const textPart = message2.parts[partIndex];
1119
- if (textPart.type !== "text") {
1120
- throw new Error("Failed to resolve text part for inline reminder");
1121
- }
1122
- const reminderText = formatTaggedReminder(value);
1123
- const start = textPart.text.length;
1124
- const updatedText = `${textPart.text}${reminderText}`;
1125
- message2.parts[partIndex] = { ...textPart, text: updatedText };
1126
- return {
1127
- id: generateId2(),
1128
- text: value,
1129
- partIndex,
1130
- start,
1131
- end: start + reminderText.length,
1132
- mode: "inline"
1133
- };
1134
- }
1135
- function applyPartReminder(message2, value) {
1136
- const part = { type: "text", text: value };
1137
- message2.parts.push(part);
1138
- const partIndex = message2.parts.length - 1;
1139
- return {
1140
- id: generateId2(),
1141
- text: value,
1142
- partIndex,
1143
- start: 0,
1144
- end: value.length,
1145
- mode: "part"
1146
- };
1147
- }
1148
- function resolveReminderText(item, ctx) {
1149
- return resolveReminder(item, ctx)?.text ?? "";
1150
- }
1151
- function normalizeReminderResolution(value) {
1152
- if (typeof value === "string") {
1153
- return value.trim().length === 0 ? null : { text: value };
1154
- }
1155
- if (value.text.trim().length === 0) {
1156
- return null;
1157
- }
1158
- return value;
1159
- }
1160
- function resolveReminder(item, ctx) {
1161
- const resolvedText = typeof item.text === "function" ? item.text(ctx) : item.text;
1162
- const resolved = normalizeReminderResolution(resolvedText);
1163
- if (!resolved) {
1164
- return null;
1165
- }
1166
- const metadata = item.metadata || resolved.metadata ? {
1167
- ...item.metadata ?? {},
1168
- ...resolved.metadata ?? {}
1169
- } : void 0;
1170
- return metadata ? { ...resolved, metadata } : resolved;
1171
- }
1172
- function mergeMessageMetadata(message2, addedMetadata) {
1173
- if (Object.keys(addedMetadata).length === 0) {
1174
- return;
1175
- }
1176
- const metadata = isRecord(message2.metadata) ? { ...message2.metadata } : {};
1177
- message2.metadata = { ...metadata, ...addedMetadata };
1178
- }
1179
- function applyReminderToMessage(message2, item, ctx) {
1180
- const resolved = resolveReminder(item, ctx);
1181
- if (!resolved) {
1182
- return null;
1183
- }
1184
- if (resolved.metadata) {
1185
- mergeMessageMetadata(message2, resolved.metadata);
1186
- }
1187
- return item.asPart ? applyPartReminder(message2, resolved.text) : applyInlineReminder(message2, resolved.text);
1188
- }
1189
- function mergeReminderMetadata(message2, addedReminders) {
1190
- if (addedReminders.length === 0) return;
1191
- const metadata = isRecord(message2.metadata) ? { ...message2.metadata } : {};
1192
- const existing = Array.isArray(metadata.reminders) ? metadata.reminders : [];
1193
- metadata.reminders = [...existing, ...addedReminders];
1194
- message2.metadata = metadata;
1195
- }
1196
- function reminder(text, options) {
1197
- if (typeof text === "string") {
1198
- assertReminderText(text);
1199
- }
1200
- if (options && "when" in options && options.when) {
1201
- return {
1202
- name: "reminder",
1203
- metadata: {
1204
- reminder: {
1205
- text,
1206
- when: options.when,
1207
- asPart: options.asPart ?? false
1208
- }
1209
- }
1210
- };
1211
- }
1212
- return {
1213
- text,
1214
- asPart: options?.asPart ?? false
1215
- };
1216
- }
1217
- function user(content, ...reminders) {
1218
- const message2 = typeof content === "string" ? {
1219
- id: generateId2(),
1220
- role: "user",
1221
- parts: [{ type: "text", text: content }]
1222
- } : { ...content, role: "user", parts: [...content.parts] };
1223
- if (reminders.length > 0) {
1224
- const plainText = extractPlainText(message2);
1225
- const added = [];
1226
- for (const item of reminders) {
1227
- const meta = applyReminderToMessage(message2, item, {
1228
- content: plainText
1229
- });
1230
- if (meta) added.push(meta);
1231
- }
1232
- mergeReminderMetadata(message2, added);
1233
- }
1234
- return {
1235
- id: message2.id,
1236
- name: "user",
1237
- type: "message",
1238
- persist: true,
1239
- codec: {
1240
- decode() {
1241
- return message2;
1242
- },
1243
- encode() {
1244
- return message2;
1245
- }
1246
- }
1247
- };
1248
- }
1249
-
1250
- // packages/context/src/lib/guardrail.ts
1251
- function pass(part) {
1252
- return { type: "pass", part };
1253
- }
1254
- function fail(feedback) {
1255
- return { type: "fail", feedback };
1256
- }
1257
- function stop(part) {
1258
- return { type: "stop", part };
1259
- }
1260
- function runGuardrailChain(part, guardrails, context) {
1261
- let currentPart = part;
1262
- for (const guardrail2 of guardrails) {
1263
- const result = guardrail2.handle(currentPart, context);
1264
- if (result.type === "fail" || result.type === "stop") {
1265
- return result;
1266
- }
1267
- currentPart = result.part;
1268
- }
1269
- return pass(currentPart);
1270
- }
1271
-
1272
905
  // packages/context/src/lib/renderers/abstract.renderer.ts
1273
906
  import pluralize from "pluralize";
1274
907
  import { titlecase } from "stringcase";
@@ -2076,74 +1709,460 @@ ${nested}`);
2076
1709
  if (this.isPrimitive(data)) {
2077
1710
  return `${this.#pad(ctx.depth)}${fragment2.name}: ${this.#formatValue(data)}`;
2078
1711
  }
2079
- if (isFragment(data)) {
2080
- const child = this.renderFragment(data, {
2081
- ...ctx,
2082
- depth: ctx.depth + 1
2083
- });
2084
- return `${this.#pad(ctx.depth)}${fragment2.name}:
2085
- ${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 [];
2086
1953
  }
2087
- if (Array.isArray(data)) {
2088
- 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;
2089
1967
  }
2090
- if (isFragmentObject(data)) {
2091
- const entries = this.#renderObjectEntries(data, ctx.depth + 1);
2092
- if (!entries) {
2093
- return `${this.#pad(ctx.depth)}${fragment2.name}:`;
2094
- }
2095
- return `${this.#pad(ctx.depth)}${fragment2.name}:
2096
- ${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;
2097
1986
  }
2098
- return `${this.#pad(ctx.depth)}${fragment2.name}:`;
2099
1987
  }
2100
- renderPrimitive(key, value, ctx) {
2101
- 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;
2102
1994
  }
2103
- renderArray(key, items, ctx) {
2104
- 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");
2105
2007
  }
2106
- renderObject(key, obj, ctx) {
2107
- const entries = this.#renderObjectEntries(obj, ctx.depth + 1);
2108
- if (!entries) {
2109
- return `${this.#pad(ctx.depth)}${key}:`;
2110
- }
2111
- return `${this.#pad(ctx.depth)}${key}:
2112
- ${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 };
2113
2040
  }
2114
- #pad(depth) {
2115
- return " ".repeat(depth);
2041
+ if (value.text.trim().length === 0) {
2042
+ return null;
2116
2043
  }
2117
- #needsQuoting(value) {
2118
- if (value === "") return true;
2119
- if (value !== value.trim()) return true;
2120
- if (["true", "false", "null"].includes(value.toLowerCase())) return true;
2121
- if (/^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i.test(value)) return true;
2122
- if (/[:\\"'[\]{}|,\t\n\r]/.test(value)) return true;
2123
- if (value.startsWith("-")) return true;
2124
- 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;
2125
2051
  }
2126
- #escape(value) {
2127
- 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;
2128
2068
  }
2129
- #canonicalizeNumber(n) {
2130
- if (!Number.isFinite(n)) return "null";
2131
- if (Object.is(n, -0)) return "0";
2132
- 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;
2133
2076
  }
2134
- #formatValue(value) {
2135
- if (value === null) return "null";
2136
- if (typeof value === "boolean") return String(value);
2137
- if (typeof value === "number") return this.#canonicalizeNumber(value);
2138
- if (typeof value === "string") {
2139
- if (this.#needsQuoting(value)) {
2140
- 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
+ }
2141
2104
  }
2142
- 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);
2143
2126
  }
2144
- return `"${this.#escape(JSON.stringify(value))}"`;
2127
+ mergeReminderMetadata(message2, added);
2145
2128
  }
2146
- };
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
+ }
2147
2166
 
2148
2167
  // packages/context/src/lib/render.ts
2149
2168
  function render(tag, ...fragments) {
@@ -2366,6 +2385,7 @@ export {
2366
2385
  reminder,
2367
2386
  render,
2368
2387
  resolveReminder,
2388
+ resolveReminderAsync,
2369
2389
  resolveReminderText,
2370
2390
  role,
2371
2391
  runGuardrailChain,