@cortexkit/pi-magic-context 0.46.1 → 0.47.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.
@@ -138,7 +138,7 @@ class Parser {
138
138
  } else
139
139
  break;
140
140
  }
141
- const expression = { steps, cap: 300 };
141
+ const expression = { steps };
142
142
  if (this.take(".each(")) {
143
143
  if (relative)
144
144
  return this.error();
@@ -205,9 +205,23 @@ function compiled(source) {
205
205
  function oneLine(value) {
206
206
  return value.replace(/[\r\n\u2028\u2029]+/g, " ");
207
207
  }
208
- function truncate(value, cap) {
208
+ function truncate(value, cap, legacyPreview = false) {
209
209
  const chars = Array.from(oneLine(value));
210
- return chars.length > cap ? `${chars.slice(0, cap).join("")}…` : chars.join("");
210
+ if (cap === undefined || chars.length <= cap)
211
+ return chars.join("");
212
+ if (legacyPreview)
213
+ return `${chars.slice(0, cap).join("")}…`;
214
+ let end = 0;
215
+ for (let i = 0;i < Math.min(cap, chars.length); i++) {
216
+ if (!".!?。!?".includes(chars[i]))
217
+ continue;
218
+ let next = i + 1;
219
+ while (next < chars.length && `"'”’)]`.includes(chars[next]))
220
+ next++;
221
+ if (next <= cap && ("。!?".includes(chars[i]) || next === chars.length || /[ \t]/.test(chars[next])))
222
+ end = next;
223
+ }
224
+ return `${end ? `${chars.slice(0, end).join("")} ` : ""}[… ${chars.length - end} more characters]`;
211
225
  }
212
226
  function scalar(value) {
213
227
  if (value === undefined)
@@ -224,10 +238,11 @@ function compactJson(value) {
224
238
  function field(value, key) {
225
239
  return value !== null && typeof value === "object" && !Array.isArray(value) && Object.hasOwn(value, key) ? value[key] : undefined;
226
240
  }
227
- function render(nodes, root) {
241
+ function render(nodes, root, legacyPreview) {
228
242
  return nodes.map((node) => {
229
243
  if (typeof node === "string")
230
244
  return node;
245
+ const cap = node.cap ?? (legacyPreview ? 300 : undefined);
231
246
  let value = root;
232
247
  let list = false;
233
248
  for (const step of node.steps) {
@@ -241,19 +256,19 @@ function render(nodes, root) {
241
256
  }
242
257
  }
243
258
  if (node.count)
244
- return truncate(Array.isArray(value) ? String(value.length) : "", node.cap);
259
+ return truncate(Array.isArray(value) ? String(value.length) : "", cap, legacyPreview);
245
260
  if (node.each || list || node.join !== undefined) {
246
261
  if (!Array.isArray(value))
247
262
  return "";
248
- const elements = value.slice(0, 10).map((item) => truncate(node.each ? render(node.each, item) : scalar(item), 300));
249
- if (value.length > 10)
263
+ const elements = value.slice(0, legacyPreview ? 10 : undefined).map((item) => truncate(node.each ? render(node.each, item, legacyPreview) : scalar(item), legacyPreview ? 300 : undefined, legacyPreview));
264
+ if (legacyPreview && value.length > 10)
250
265
  elements.push(`… +${value.length - 10} more`);
251
- return truncate(elements.join(node.join ?? (node.each ? "; " : ", ")), node.cap);
266
+ return truncate(elements.join(node.join ?? (node.each ? "; " : ", ")), cap, legacyPreview);
252
267
  }
253
- return truncate(scalar(value), node.cap);
268
+ return truncate(scalar(value), cap, legacyPreview);
254
269
  }).join("");
255
270
  }
256
- function renderToolTemplate(source, input, output) {
271
+ function renderToolTemplate(source, input, output, legacyPreview = false) {
257
272
  const nodes = compiled(source);
258
273
  if (!nodes)
259
274
  return null;
@@ -268,8 +283,8 @@ function renderToolTemplate(source, input, output) {
268
283
  }
269
284
  }
270
285
  const root = { input, output: structured };
271
- const bareOutputNodes = nodes.map((node) => typeof node !== "string" && node.steps.length === 1 && ("field" in node.steps[0]) && node.steps[0].field === "output" && !node.each && !node.count && node.join === undefined ? truncate(text ?? "", node.cap) : node);
272
- return truncate(render(bareOutputNodes, root), 1000);
286
+ const bareOutputNodes = nodes.map((node) => typeof node !== "string" && node.steps.length === 1 && ("field" in node.steps[0]) && node.steps[0].field === "output" && !node.each && !node.count && node.join === undefined ? truncate(text ?? "", node.cap ?? (legacyPreview ? 300 : undefined), legacyPreview) : node);
287
+ return truncate(render(bareOutputNodes, root, legacyPreview), legacyPreview ? 1000 : undefined, legacyPreview);
273
288
  }
274
289
 
275
290
  // ../plugin/src/shared/protected-tools-policy.ts
@@ -3,7 +3,7 @@ import {
3
3
  toolTemplateError,
4
4
  DEFAULT_PROTECTED_TOOLS,
5
5
  mergeProtectedTools
6
- } from "./index-phh7e055.js";
6
+ } from "./index-spk5vrhy.js";
7
7
  import {
8
8
  getHarness,
9
9
  getMagicContextStorageDir,
@@ -5309,7 +5309,7 @@ var HistorianConfigSchema = AgentMetadataSchema.extend({
5309
5309
  ctx.addIssue({ code: "custom", message: error });
5310
5310
  }),
5311
5311
  literal(false)
5312
- ])).optional().describe('Readable historian tool expansions, keyed by exact host tool name. Templates override built-in defaults; false disables an expansion. Supports ${input.path}, ${output.path}, bare ${output}, array [N], [*].field, .each("${field}"), .join("separator"), .count and final .truncate(N). Missing fields are empty; placeholders default to 300 characters, lists to 10 elements, expansions to 1000 characters. Valid in user and project config; affects historian/recomp and verbose ctx_expand only, never the wire or default ctx_expand transcript.'),
5312
+ ])).optional().describe('Readable historian tool expansions, keyed by exact host tool name. Templates override built-in defaults; false disables an expansion. Supports ${input.path}, ${output.path}, bare ${output}, array [N], [*].field, .each("${field}"), .join("separator"), .count and final .truncate(N). Missing fields are empty. Historian text and lists have no implicit caps; explicit .truncate(N) keeps complete sentences and marks omitted characters, or emits only the marker if no sentence fits. When the ctx_expand history-recovery tool is called in verbose mode, its tool-call previews retain their original built-in templates and limits (300 characters per placeholder, 10 list elements, 1000 characters per expansion). Valid in user and project config; never changes the wire or default ctx_expand transcript.'),
5313
5313
  opencode: OpenCodeHarnessBlockSchema.optional(),
5314
5314
  pi: PiHarnessBlockSchema.optional(),
5315
5315
  omp: OmpHarnessBlockSchema.optional(),
@@ -5461,7 +5461,11 @@ var MagicContextConfigSchema = object({
5461
5461
  }).catchall(number2().min(5000).max(2000000)).optional().describe("Absolute token thresholds per model. When matched, overrides execute_threshold_percentage for that model. Accepts `default` for all models or per-model keys. Values above 90% × context_limit are clamped with a warning log. Min 5_000, max 2_000_000."),
5462
5462
  protected_tokens: number2().int().min(PROTECTED_TOKENS_MIN).max(1e6).optional().describe("Positive integer token floor to protect from automatic reclaim (min: 4_000, max: 1_000_000). When omitted, the derived default is clamp(round(0.05 × usableSoft), min(16_000, round(0.08 × usableSoft)), 64_000)."),
5463
5463
  protected_tags: unknown().optional().describe("Deprecated: number of recent tags to protect. Ignored for behaviour; use protected_tokens instead.").meta({ deprecated: true }),
5464
- clear_reasoning_age: number2().min(10).default(50).describe("Clear reasoning/thinking blocks older than N tags (default: 50)"),
5464
+ clear_reasoning_age: unknown().optional().describe("Deprecated and ignored. Use keep_reasoning_tokens instead.").meta({ deprecated: true }),
5465
+ keep_reasoning_tokens: union([
5466
+ number2().int().min(0).max(1e6),
5467
+ object({ default: number2().int().min(0).max(1e6).optional() }).catchall(number2().int().min(0).max(1e6))
5468
+ ]).optional().describe("Reasoning tokens to keep on rebuilding passes. Number or per-model object; exact, shorter model keys, provider/*, then default. Omitted: fixed 10,000. 0 removes all eligible historical reasoning; newest and exempt steps always stay."),
5465
5469
  history_budget_percentage: number2().min(0.05).max(0.5).default(DEFAULT_HISTORY_BUDGET_PERCENTAGE).describe("Fraction of usable context (context_limit × execute_threshold) reserved for the session history block (default: 0.15)"),
5466
5470
  historian_timeout_ms: number2().min(60000).default(DEFAULT_HISTORIAN_TIMEOUT_MS).describe("Timeout for each historian prompt call in both TypeScript and Rust transform modes, in milliseconds (default: 600000)"),
5467
5471
  commit_cluster_trigger: object({