@deepagents/context 0.37.0 → 0.38.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/index.d.ts CHANGED
@@ -11,8 +11,10 @@ export * from './lib/fragments/domain.ts';
11
11
  export * from './lib/fragments/message/user.ts';
12
12
  export * from './lib/fragments/reasoning.ts';
13
13
  export * from './lib/fragments/reminders/classifier.ts';
14
+ export * from './lib/fragments/reminders/combinators.ts';
14
15
  export * from './lib/fragments/reminders/content-predicates.ts';
15
- export * from './lib/fragments/reminders/temporal-reminder.ts';
16
+ export * from './lib/fragments/reminders/temporal/index.ts';
17
+ export * from './lib/fragments/reminders/turn-predicates.ts';
16
18
  export * from './lib/fragments/socratic.ts';
17
19
  export * from './lib/fragments/user.ts';
18
20
  export * from './lib/guardrail.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yCAAyC,CAAC;AACxD,cAAc,iDAAiD,CAAC;AAChE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,8CAA8C,CAAC;AAC7D,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC;AAChC,cAAc,sCAAsC,CAAC;AACrD,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yCAAyC,CAAC;AACxD,cAAc,0CAA0C,CAAC;AACzD,cAAc,iDAAiD,CAAC;AAChE,cAAc,6CAA6C,CAAC;AAC5D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,8CAA8C,CAAC;AAC7D,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC;AAChC,cAAc,sCAAsC,CAAC;AACrD,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -1118,118 +1118,9 @@ function extractPlainText(message2) {
1118
1118
  }
1119
1119
 
1120
1120
  // packages/context/src/lib/fragments/message/user.ts
1121
- function everyNTurns(n) {
1122
- return ({ turn }) => turn % n === 0;
1123
- }
1124
- function once() {
1125
- return ({ turn }) => turn === 1;
1126
- }
1127
- function firstN(n) {
1128
- return ({ turn }) => turn <= n;
1129
- }
1130
- function afterTurn(n) {
1131
- return ({ turn }) => turn > n;
1132
- }
1133
- function and(...predicates) {
1134
- return async (ctx) => {
1135
- for (const it of predicates) {
1136
- if (!await it(ctx)) return false;
1137
- }
1138
- return true;
1139
- };
1140
- }
1141
- function or(...predicates) {
1142
- return async (ctx) => {
1143
- for (const it of predicates) {
1144
- if (await it(ctx)) return true;
1145
- }
1146
- return false;
1147
- };
1148
- }
1149
- function not(predicate) {
1150
- return async (ctx) => !await predicate(ctx);
1151
- }
1152
- function contentIncludes(keywords) {
1153
- const lower = keywords.map((k) => k.toLowerCase());
1154
- return (ctx) => {
1155
- const text = ctx.content.toLowerCase();
1156
- return lower.some((kw) => text.includes(kw));
1157
- };
1158
- }
1159
- function contentPattern(pattern) {
1160
- return (ctx) => {
1161
- pattern.lastIndex = 0;
1162
- return pattern.test(ctx.content);
1163
- };
1164
- }
1165
- function toDateParts(date, tz) {
1166
- const parts = new Intl.DateTimeFormat("en-CA", {
1167
- timeZone: tz,
1168
- year: "numeric",
1169
- month: "2-digit",
1170
- day: "2-digit",
1171
- hour: "2-digit",
1172
- hourCycle: "h23"
1173
- }).formatToParts(date);
1174
- const get = (type) => parts.find((p) => p.type === type).value;
1175
- return {
1176
- year: get("year"),
1177
- month: get("month"),
1178
- day: get("day"),
1179
- hour: get("hour")
1180
- };
1181
- }
1182
- function temporalChanged(ctx, tz, getKey) {
1183
- if (ctx.lastMessageAt === void 0) return true;
1184
- const nowParts = toDateParts(/* @__PURE__ */ new Date(), tz);
1185
- const prevParts = toDateParts(new Date(ctx.lastMessageAt), tz);
1186
- return getKey(nowParts) !== getKey(prevParts);
1187
- }
1188
- function getSeason(month) {
1189
- if (month >= 2 && month <= 4) return "Spring";
1190
- if (month >= 5 && month <= 7) return "Summer";
1191
- if (month >= 8 && month <= 10) return "Fall";
1192
- return "Winter";
1193
- }
1194
- function isoWeekKey(parts) {
1195
- const d = new Date(
1196
- Date.UTC(
1197
- parseInt(parts.year),
1198
- parseInt(parts.month) - 1,
1199
- parseInt(parts.day)
1200
- )
1201
- );
1202
- d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
1203
- const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
1204
- const weekNo = Math.ceil(
1205
- ((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7
1206
- );
1207
- return `${d.getUTCFullYear()}-W${String(weekNo).padStart(2, "0")}`;
1208
- }
1209
- function dayChanged(tz = "UTC") {
1210
- return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}-${p.day}`);
1211
- }
1212
- function hourChanged(tz = "UTC") {
1213
- return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}-${p.day}-${p.hour}`);
1214
- }
1215
- function monthChanged(tz = "UTC") {
1216
- return (ctx) => temporalChanged(ctx, tz, (p) => `${p.year}-${p.month}`);
1217
- }
1218
- function yearChanged(tz = "UTC") {
1219
- return (ctx) => temporalChanged(ctx, tz, (p) => p.year);
1220
- }
1221
- function seasonChanged(tz = "UTC") {
1222
- return (ctx) => temporalChanged(ctx, tz, (p) => getSeason(parseInt(p.month) - 1));
1223
- }
1224
- function weekChanged(tz = "UTC") {
1225
- return (ctx) => temporalChanged(ctx, tz, isoWeekKey);
1226
- }
1227
1121
  function isConditionalReminder(fragment2) {
1228
1122
  return fragment2.name === "reminder" && !!fragment2.metadata?.reminder;
1229
1123
  }
1230
- function getConditionalReminder(fragment2) {
1231
- return fragment2.metadata.reminder;
1232
- }
1233
1124
  var SYSTEM_REMINDER_OPEN_TAG = "<system-reminder>";
1234
1125
  var SYSTEM_REMINDER_CLOSE_TAG = "</system-reminder>";
1235
1126
  function getReminderRanges(metadata) {
@@ -1417,10 +1308,12 @@ function mergeReminderMetadata(message2, addedReminders) {
1417
1308
  message2.metadata = metadata;
1418
1309
  }
1419
1310
  function reminder(textOrFragment, options) {
1420
- const text = isFragment(textOrFragment) ? new XmlRenderer().render([textOrFragment]) : textOrFragment;
1311
+ const fromFragment2 = isFragment(textOrFragment);
1312
+ const text = fromFragment2 ? new XmlRenderer().render([textOrFragment]) : textOrFragment;
1421
1313
  if (typeof text === "string") {
1422
1314
  assertReminderText(text);
1423
1315
  }
1316
+ const asPart = options?.asPart ?? false;
1424
1317
  if (options && "when" in options && options.when) {
1425
1318
  return {
1426
1319
  name: "reminder",
@@ -1429,14 +1322,14 @@ function reminder(textOrFragment, options) {
1429
1322
  reminder: {
1430
1323
  text,
1431
1324
  when: options.when,
1432
- asPart: options.asPart ?? false
1325
+ asPart
1433
1326
  }
1434
1327
  }
1435
1328
  };
1436
1329
  }
1437
1330
  return {
1438
1331
  text,
1439
- asPart: options?.asPart ?? false
1332
+ asPart
1440
1333
  };
1441
1334
  }
1442
1335
  function user(content, ...reminders) {
@@ -3000,6 +2893,7 @@ var ContextEngine = class _ContextEngine {
3000
2893
  content: plainText,
3001
2894
  lastMessageAt,
3002
2895
  lastMessage,
2896
+ currentMessage: original,
3003
2897
  chat: this.#chatData,
3004
2898
  usage,
3005
2899
  branch: this.#branchName,
@@ -3007,7 +2901,9 @@ var ContextEngine = class _ContextEngine {
3007
2901
  messageCount,
3008
2902
  lastAssistantMessage
3009
2903
  };
3010
- const configs = conditionalReminders.map(getConditionalReminder);
2904
+ const configs = conditionalReminders.map(
2905
+ (it) => it.metadata.reminder
2906
+ );
3011
2907
  const whenResults = await Promise.all(
3012
2908
  configs.map((it) => it.when(whenCtx))
3013
2909
  );
@@ -4477,6 +4373,27 @@ var BM25Classifier = class {
4477
4373
  }
4478
4374
  };
4479
4375
 
4376
+ // packages/context/src/lib/fragments/reminders/combinators.ts
4377
+ function and(...predicates) {
4378
+ return async (ctx) => {
4379
+ for (const it of predicates) {
4380
+ if (!await it(ctx)) return false;
4381
+ }
4382
+ return true;
4383
+ };
4384
+ }
4385
+ function or(...predicates) {
4386
+ return async (ctx) => {
4387
+ for (const it of predicates) {
4388
+ if (await it(ctx)) return true;
4389
+ }
4390
+ return false;
4391
+ };
4392
+ }
4393
+ function not(predicate) {
4394
+ return async (ctx) => !await predicate(ctx);
4395
+ }
4396
+
4480
4397
  // packages/context/src/lib/fragments/reminders/content-predicates.ts
4481
4398
  function contentMatches(topics, options) {
4482
4399
  const classifier = new BM25Classifier(
@@ -4487,8 +4404,117 @@ function contentMatches(topics, options) {
4487
4404
  function classifies(classifier, options) {
4488
4405
  return (ctx) => classifier.match(ctx.content, options).length > 0;
4489
4406
  }
4407
+ function contentIncludes(keywords) {
4408
+ const lower = keywords.map((k) => k.toLowerCase());
4409
+ return (ctx) => {
4410
+ const text = ctx.content.toLowerCase();
4411
+ return lower.some((kw) => text.includes(kw));
4412
+ };
4413
+ }
4414
+ function contentPattern(pattern) {
4415
+ return (ctx) => {
4416
+ pattern.lastIndex = 0;
4417
+ return pattern.test(ctx.content);
4418
+ };
4419
+ }
4490
4420
 
4491
- // packages/context/src/lib/fragments/reminders/temporal-reminder.ts
4421
+ // packages/context/src/lib/fragments/reminders/temporal/predicates.ts
4422
+ var LOCALE_METADATA_KEY = "locale";
4423
+ function getLocaleFromMessage(message2) {
4424
+ if (!message2) return null;
4425
+ const metadata = isRecord(message2.metadata) ? message2.metadata : null;
4426
+ if (!metadata) return null;
4427
+ const locale = metadata[LOCALE_METADATA_KEY];
4428
+ if (!isRecord(locale)) return null;
4429
+ if (typeof locale.language !== "string" || typeof locale.timeZone !== "string") {
4430
+ return null;
4431
+ }
4432
+ return { language: locale.language, timeZone: locale.timeZone };
4433
+ }
4434
+ function resolveTz(options, ctx) {
4435
+ if (options?.tz) return options.tz;
4436
+ return getLocaleFromMessage(ctx.currentMessage)?.timeZone ?? getLocaleFromMessage(ctx.lastMessage)?.timeZone ?? "UTC";
4437
+ }
4438
+ function toDateParts(date, tz) {
4439
+ const parts = new Intl.DateTimeFormat("en-CA", {
4440
+ timeZone: tz,
4441
+ year: "numeric",
4442
+ month: "2-digit",
4443
+ day: "2-digit",
4444
+ hour: "2-digit",
4445
+ hourCycle: "h23"
4446
+ }).formatToParts(date);
4447
+ const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
4448
+ return {
4449
+ year: get("year"),
4450
+ month: get("month"),
4451
+ day: get("day"),
4452
+ hour: get("hour")
4453
+ };
4454
+ }
4455
+ function temporalChanged(ctx, tz, getKey) {
4456
+ if (ctx.lastMessageAt === void 0) return true;
4457
+ const nowParts = toDateParts(/* @__PURE__ */ new Date(), tz);
4458
+ const prevParts = toDateParts(new Date(ctx.lastMessageAt), tz);
4459
+ return getKey(nowParts) !== getKey(prevParts);
4460
+ }
4461
+ function getSeason(month) {
4462
+ if (month >= 2 && month <= 4) return "Spring";
4463
+ if (month >= 5 && month <= 7) return "Summer";
4464
+ if (month >= 8 && month <= 10) return "Fall";
4465
+ return "Winter";
4466
+ }
4467
+ function isoWeekKey(parts) {
4468
+ const d = new Date(
4469
+ Date.UTC(
4470
+ parseInt(parts.year),
4471
+ parseInt(parts.month) - 1,
4472
+ parseInt(parts.day)
4473
+ )
4474
+ );
4475
+ d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
4476
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
4477
+ const weekNo = Math.ceil(
4478
+ ((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7
4479
+ );
4480
+ return `${d.getUTCFullYear()}-W${String(weekNo).padStart(2, "0")}`;
4481
+ }
4482
+ function dayChanged(options) {
4483
+ return (ctx) => temporalChanged(
4484
+ ctx,
4485
+ resolveTz(options, ctx),
4486
+ (p) => `${p.year}-${p.month}-${p.day}`
4487
+ );
4488
+ }
4489
+ function hourChanged(options) {
4490
+ return (ctx) => temporalChanged(
4491
+ ctx,
4492
+ resolveTz(options, ctx),
4493
+ (p) => `${p.year}-${p.month}-${p.day}-${p.hour}`
4494
+ );
4495
+ }
4496
+ function monthChanged(options) {
4497
+ return (ctx) => temporalChanged(
4498
+ ctx,
4499
+ resolveTz(options, ctx),
4500
+ (p) => `${p.year}-${p.month}`
4501
+ );
4502
+ }
4503
+ function yearChanged(options) {
4504
+ return (ctx) => temporalChanged(ctx, resolveTz(options, ctx), (p) => p.year);
4505
+ }
4506
+ function seasonChanged(options) {
4507
+ return (ctx) => temporalChanged(
4508
+ ctx,
4509
+ resolveTz(options, ctx),
4510
+ (p) => getSeason(parseInt(p.month) - 1)
4511
+ );
4512
+ }
4513
+ function weekChanged(options) {
4514
+ return (ctx) => temporalChanged(ctx, resolveTz(options, ctx), isoWeekKey);
4515
+ }
4516
+
4517
+ // packages/context/src/lib/fragments/reminders/temporal/reminder.ts
4492
4518
  function formatDateKey(date, tz) {
4493
4519
  return date.toLocaleDateString("en-CA", { timeZone: tz });
4494
4520
  }
@@ -4538,9 +4564,9 @@ function formatDiff(changes) {
4538
4564
  `;
4539
4565
  }
4540
4566
  function dateReminder(options) {
4541
- const tz = options?.tz ?? "UTC";
4542
4567
  return reminder(
4543
4568
  (ctx) => {
4569
+ const tz = resolveTz(options, ctx);
4544
4570
  const now = /* @__PURE__ */ new Date();
4545
4571
  const currentDate = formatDateKey(now, tz);
4546
4572
  const currentDay = formatDayOfWeek(now, tz);
@@ -4555,13 +4581,13 @@ function dateReminder(options) {
4555
4581
  return `${diff}Date: ${currentDate}
4556
4582
  Day of Week: ${currentDay}`;
4557
4583
  },
4558
- { when: dayChanged(tz), asPart: true }
4584
+ { when: dayChanged(options), asPart: false }
4559
4585
  );
4560
4586
  }
4561
4587
  function timeReminder(options) {
4562
- const tz = options?.tz ?? "UTC";
4563
4588
  return reminder(
4564
4589
  (ctx) => {
4590
+ const tz = resolveTz(options, ctx);
4565
4591
  const now = /* @__PURE__ */ new Date();
4566
4592
  const currentTime = formatTime(now, tz);
4567
4593
  let diff = "";
@@ -4573,13 +4599,13 @@ function timeReminder(options) {
4573
4599
  }
4574
4600
  return `${diff}Time: ${currentTime}`;
4575
4601
  },
4576
- { when: hourChanged(tz), asPart: true }
4602
+ { when: hourChanged(options), asPart: false }
4577
4603
  );
4578
4604
  }
4579
4605
  function monthReminder(options) {
4580
- const tz = options?.tz ?? "UTC";
4581
4606
  return reminder(
4582
4607
  (ctx) => {
4608
+ const tz = resolveTz(options, ctx);
4583
4609
  const now = /* @__PURE__ */ new Date();
4584
4610
  const currentMonth = formatMonthName(now, tz);
4585
4611
  let diff = "";
@@ -4591,13 +4617,13 @@ function monthReminder(options) {
4591
4617
  }
4592
4618
  return `${diff}Month: ${currentMonth}`;
4593
4619
  },
4594
- { when: monthChanged(tz), asPart: true }
4620
+ { when: monthChanged(options), asPart: false }
4595
4621
  );
4596
4622
  }
4597
4623
  function yearReminder(options) {
4598
- const tz = options?.tz ?? "UTC";
4599
4624
  return reminder(
4600
4625
  (ctx) => {
4626
+ const tz = resolveTz(options, ctx);
4601
4627
  const now = /* @__PURE__ */ new Date();
4602
4628
  const currentYear = formatYear(now, tz);
4603
4629
  let diff = "";
@@ -4609,13 +4635,13 @@ function yearReminder(options) {
4609
4635
  }
4610
4636
  return `${diff}Year: ${currentYear}`;
4611
4637
  },
4612
- { when: yearChanged(tz), asPart: true }
4638
+ { when: yearChanged(options), asPart: false }
4613
4639
  );
4614
4640
  }
4615
4641
  function seasonReminder(options) {
4616
- const tz = options?.tz ?? "UTC";
4617
4642
  return reminder(
4618
4643
  (ctx) => {
4644
+ const tz = resolveTz(options, ctx);
4619
4645
  const now = /* @__PURE__ */ new Date();
4620
4646
  const currentSeason = getSeason(getMonthIndex(now, tz));
4621
4647
  let diff = "";
@@ -4627,61 +4653,56 @@ function seasonReminder(options) {
4627
4653
  }
4628
4654
  return `${diff}Season: ${currentSeason}`;
4629
4655
  },
4630
- { when: seasonChanged(tz), asPart: true }
4656
+ { when: seasonChanged(options), asPart: false }
4631
4657
  );
4632
4658
  }
4633
- var LOCALE_METADATA_KEY = "locale";
4634
- function getLocaleFromMessage(message2) {
4635
- if (!message2) return null;
4636
- const metadata = isRecord(message2.metadata) ? message2.metadata : null;
4637
- if (!metadata) return null;
4638
- const locale = metadata[LOCALE_METADATA_KEY];
4639
- if (!isRecord(locale)) return null;
4640
- if (typeof locale.language !== "string" || typeof locale.timeZone !== "string") {
4641
- return null;
4642
- }
4643
- return { language: locale.language, timeZone: locale.timeZone };
4644
- }
4645
- function localeReminder(options) {
4646
- const language = options?.language ?? "English (US)";
4647
- const timeZone = options?.timeZone ?? "UTC";
4659
+ function localeReminder() {
4648
4660
  const whenFn = (ctx) => {
4649
- const prev = getLocaleFromMessage(ctx.lastMessage);
4650
- if (!prev) return true;
4651
- return prev.language !== language || prev.timeZone !== timeZone;
4661
+ const current = getLocaleFromMessage(ctx.currentMessage);
4662
+ if (!current) return false;
4663
+ const last = getLocaleFromMessage(ctx.lastMessage);
4664
+ if (!last) return true;
4665
+ return current.language !== last.language || current.timeZone !== last.timeZone;
4652
4666
  };
4653
4667
  return reminder(
4654
4668
  (ctx) => {
4655
- const prev = getLocaleFromMessage(ctx.lastMessage);
4656
- let diff = "";
4657
- if (prev) {
4658
- diff = formatDiff([
4659
- diffLine("language", prev.language, language),
4660
- diffLine("timezone", prev.timeZone, timeZone)
4661
- ]);
4662
- }
4663
- return {
4664
- text: `${diff}Language: ${language}
4665
- Timezone: ${timeZone}`,
4666
- metadata: {
4667
- [LOCALE_METADATA_KEY]: { language, timeZone }
4668
- }
4669
- };
4669
+ const current = getLocaleFromMessage(ctx.currentMessage);
4670
+ if (!current) return "";
4671
+ const last = getLocaleFromMessage(ctx.lastMessage);
4672
+ const diff = last ? formatDiff([
4673
+ diffLine("language", last.language, current.language),
4674
+ diffLine("timezone", last.timeZone, current.timeZone)
4675
+ ]) : "";
4676
+ return `${diff}Language: ${current.language}
4677
+ Timezone: ${current.timeZone}`;
4670
4678
  },
4671
- { when: whenFn, asPart: true }
4679
+ { when: whenFn, asPart: false }
4672
4680
  );
4673
4681
  }
4674
4682
  function temporalReminder(options) {
4675
- const tz = options?.tz ?? "UTC";
4676
4683
  return [
4677
- dateReminder({ tz }),
4678
- timeReminder({ tz }),
4679
- monthReminder({ tz }),
4680
- yearReminder({ tz }),
4681
- seasonReminder({ tz })
4684
+ dateReminder(options),
4685
+ timeReminder(options),
4686
+ monthReminder(options),
4687
+ yearReminder(options),
4688
+ seasonReminder(options)
4682
4689
  ];
4683
4690
  }
4684
4691
 
4692
+ // packages/context/src/lib/fragments/reminders/turn-predicates.ts
4693
+ function everyNTurns(n) {
4694
+ return ({ turn }) => turn % n === 0;
4695
+ }
4696
+ function once() {
4697
+ return ({ turn }) => turn === 1;
4698
+ }
4699
+ function firstN(n) {
4700
+ return ({ turn }) => turn <= n;
4701
+ }
4702
+ function afterTurn(n) {
4703
+ return ({ turn }) => turn > n;
4704
+ }
4705
+
4685
4706
  // packages/context/src/lib/fragments/socratic.ts
4686
4707
  function socraticPrompting() {
4687
4708
  return [
@@ -6305,11 +6326,10 @@ function createShallowRouter(backend, ext, cwd) {
6305
6326
  executeCommand: async (raw) => {
6306
6327
  const preHook = ext.onBeforeBashCall ? (await ext.onBeforeBashCall({ command: raw })).command : raw;
6307
6328
  let transformed;
6308
- let tokens;
6329
+ let dispatch;
6309
6330
  try {
6310
6331
  transformed = ext.plugins.length > 0 ? transformer.transform(preHook).script : preHook;
6311
- const firstCmd = parse(transformed).statements[0]?.pipelines[0]?.commands[0];
6312
- tokens = firstCmd?.type === "SimpleCommand" ? tokenizeFirstCommand(transformed) : [];
6332
+ dispatch = extractDispatchTarget(parse(transformed), cwd);
6313
6333
  } catch (err) {
6314
6334
  return {
6315
6335
  stdout: "",
@@ -6318,12 +6338,12 @@ function createShallowRouter(backend, ext, cwd) {
6318
6338
  exitCode: 2
6319
6339
  };
6320
6340
  }
6321
- const [name, ...args] = tokens;
6341
+ const [name, ...args] = dispatch?.tokens ?? [];
6322
6342
  const cmd = name ? byName.get(name) : void 0;
6323
6343
  if (cmd) {
6324
6344
  return cmd.handler(args, {
6325
6345
  sandbox: backend,
6326
- cwd,
6346
+ cwd: dispatch?.cwd ?? cwd,
6327
6347
  env: ext.env,
6328
6348
  stdin: ""
6329
6349
  });
@@ -6332,20 +6352,49 @@ function createShallowRouter(backend, ext, cwd) {
6332
6352
  }
6333
6353
  };
6334
6354
  }
6335
- function tokenizeFirstCommand(commandLine) {
6336
- const ast = parse(commandLine);
6337
- const first = ast.statements[0]?.pipelines[0]?.commands[0];
6338
- if (!first || first.type !== "SimpleCommand") return [];
6339
- if (ast.statements.length > 1) return [];
6340
- if (ast.statements[0].pipelines.length > 1) return [];
6341
- if (ast.statements[0].pipelines[0].commands.length > 1) return [];
6342
- if (first.redirections.length > 0) return [];
6343
- const name = asStaticWordText(first.name);
6344
- if (!name) return [];
6355
+ function extractDispatchTarget(ast, defaultCwd) {
6356
+ if (ast.statements.length !== 1) return null;
6357
+ const statement = ast.statements[0];
6358
+ if (statement.background) return null;
6359
+ if (statement.operators.length === 0 && statement.pipelines.length === 1) {
6360
+ const tokens = tokenizeSimplePipeline(statement.pipelines[0]);
6361
+ return tokens ? { tokens, cwd: defaultCwd } : null;
6362
+ }
6363
+ if (statement.operators.length === 1 && statement.operators[0] === "&&" && statement.pipelines.length === 2) {
6364
+ const cd = simpleCommandFromPipeline(statement.pipelines[0]);
6365
+ const cdCwd = readCdTarget(cd);
6366
+ if (!cdCwd) return null;
6367
+ const tokens = tokenizeSimplePipeline(statement.pipelines[1]);
6368
+ return tokens ? { tokens, cwd: cdCwd } : null;
6369
+ }
6370
+ return null;
6371
+ }
6372
+ function simpleCommandFromPipeline(pipeline) {
6373
+ if (!pipeline) return null;
6374
+ if (pipeline.negated || pipeline.timed || pipeline.commands.length !== 1) {
6375
+ return null;
6376
+ }
6377
+ const command = pipeline.commands[0];
6378
+ return command?.type === "SimpleCommand" ? command : null;
6379
+ }
6380
+ function readCdTarget(command) {
6381
+ if (!command) return null;
6382
+ if (command.redirections.length > 0 || command.args.length !== 1) {
6383
+ return null;
6384
+ }
6385
+ const name = asStaticWordText(command.name);
6386
+ if (name !== "cd") return null;
6387
+ return asStaticWordText(command.args[0]);
6388
+ }
6389
+ function tokenizeSimplePipeline(pipeline) {
6390
+ const command = simpleCommandFromPipeline(pipeline);
6391
+ if (!command || command.redirections.length > 0) return null;
6392
+ const name = asStaticWordText(command.name);
6393
+ if (!name) return null;
6345
6394
  const args = [];
6346
- for (const arg of first.args) {
6395
+ for (const arg of command.args) {
6347
6396
  const text = asStaticWordText(arg);
6348
- if (text == null) return [];
6397
+ if (text == null) return null;
6349
6398
  args.push(text);
6350
6399
  }
6351
6400
  return [name, ...args];
@@ -8966,6 +9015,21 @@ var StreamManager = class {
8966
9015
  lastSeq: lastSeqRef.value
8967
9016
  });
8968
9017
  }
9018
+ if (currentStatus === "failed") {
9019
+ const stream = await store2.getStream(streamId);
9020
+ if (stream) {
9021
+ const errorText = stream.error || "Stream failed";
9022
+ this.#emitPolling({
9023
+ type: "watch:error-emitted",
9024
+ streamId,
9025
+ errorTextLength: errorText.length
9026
+ });
9027
+ controller.enqueue({
9028
+ type: "error",
9029
+ errorText
9030
+ });
9031
+ }
9032
+ }
8969
9033
  this.#emitPolling({
8970
9034
  type: "watch:closed",
8971
9035
  streamId,
@@ -9134,6 +9198,7 @@ export {
9134
9198
  DockerfileStrategy,
9135
9199
  DuplicateCommandError,
9136
9200
  InMemoryContextStore,
9201
+ LOCALE_METADATA_KEY,
9137
9202
  MarkdownRenderer,
9138
9203
  ModelsRegistry,
9139
9204
  MountPathError,
@@ -9208,8 +9273,8 @@ export {
9208
9273
  fragment,
9209
9274
  fromFragment,
9210
9275
  generateChatTitle,
9211
- getConditionalReminder,
9212
9276
  getFragmentData,
9277
+ getLocaleFromMessage,
9213
9278
  getModelsRegistry,
9214
9279
  getReminderRanges,
9215
9280
  getSeason,
@@ -9259,6 +9324,7 @@ export {
9259
9324
  resolveReminder,
9260
9325
  resolveReminderAsync,
9261
9326
  resolveReminderText,
9327
+ resolveTz,
9262
9328
  role,
9263
9329
  runGuardrailChain,
9264
9330
  runWithBashMeta,