@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 +441 -421
- package/dist/browser.js.map +4 -4
- package/dist/index.js +479 -447
- package/dist/index.js.map +4 -4
- package/dist/lib/agent.d.ts.map +1 -1
- package/dist/lib/engine.d.ts.map +1 -1
- package/dist/lib/fragments/message/user.d.ts +57 -13
- package/dist/lib/fragments/message/user.d.ts.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
2088
|
-
|
|
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
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
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
|
-
|
|
2101
|
-
|
|
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
|
-
|
|
2104
|
-
|
|
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
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
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
|
-
|
|
2115
|
-
return
|
|
2041
|
+
if (value.text.trim().length === 0) {
|
|
2042
|
+
return null;
|
|
2116
2043
|
}
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
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
|
-
|
|
2127
|
-
|
|
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
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
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
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|