@cydm/pie 2.4.0 → 2.5.1

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.
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  createAskUserCapability
4
- } from "../../../chunks/chunk-FKUEIYFQ.js";
4
+ } from "../../../chunks/chunk-REP6QANY.js";
5
5
  import "../../../chunks/chunk-ZKHMNEXL.js";
6
6
  import "../../../chunks/chunk-YRXXRLMQ.js";
7
7
  import "../../../chunks/chunk-XXGYUYXI.js";
@@ -136,7 +136,42 @@ function spawnHerdrReport(binPath, args, timeoutMs = REPORT_TIMEOUT_MS) {
136
136
  } catch {
137
137
  }
138
138
  }
139
- function attachHerdrReporter(host, herdr, transport = (args) => spawnHerdrReport(herdr.binPath, args), sequencer = createReportSequencer()) {
139
+ var KILL_GRACE_MS = 1e3;
140
+ async function runHerdrReportBounded(binPath, args, timeoutMs = REPORT_TIMEOUT_MS) {
141
+ let child;
142
+ try {
143
+ child = spawn(binPath, args, { detached: true, stdio: "ignore" });
144
+ } catch {
145
+ return { outcome: "spawn-error", exitCode: null };
146
+ }
147
+ return await new Promise((resolve) => {
148
+ let killTimer;
149
+ let settled = false;
150
+ const finish = (outcome, exitCode) => {
151
+ if (settled) return;
152
+ settled = true;
153
+ clearTimeout(timer);
154
+ if (killTimer) clearTimeout(killTimer);
155
+ resolve({ outcome, exitCode });
156
+ };
157
+ const timer = setTimeout(() => {
158
+ try {
159
+ child.kill("SIGTERM");
160
+ } catch {
161
+ }
162
+ killTimer = setTimeout(() => {
163
+ try {
164
+ if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
165
+ } catch {
166
+ }
167
+ killTimer = setTimeout(() => finish("escalated", child.exitCode), 250);
168
+ }, KILL_GRACE_MS);
169
+ }, timeoutMs);
170
+ child.on("error", () => finish("spawn-error", null));
171
+ child.on("exit", (code) => finish("exited", code));
172
+ });
173
+ }
174
+ function attachHerdrReporter(host, herdr, transport = (args) => spawnHerdrReport(herdr.binPath, args), sequencer = createReportSequencer(), shutdownTransport = (args) => runHerdrReportBounded(herdr.binPath, args)) {
140
175
  const nextSeq = sequencer;
141
176
  let agentActive = false;
142
177
  const blockingToolCalls = /* @__PURE__ */ new Map();
@@ -238,10 +273,10 @@ function attachHerdrReporter(host, herdr, transport = (args) => spawnHerdrReport
238
273
  }
239
274
  publishState();
240
275
  });
241
- host.registerCleanup?.((reason) => {
276
+ host.registerCleanup?.(async (reason) => {
242
277
  if (reason !== "shutdown") return;
243
278
  if (!heldPane) return;
244
- report(
279
+ await shutdownTransport(
245
280
  buildReleaseReportArgs({
246
281
  paneId: herdr.paneId,
247
282
  source: SOURCE_ID,
@@ -267,6 +302,7 @@ export {
267
302
  createReportSequencer,
268
303
  herdrAgentStateExtension as default,
269
304
  readHerdrEnvironment,
305
+ runHerdrReportBounded,
270
306
  spawnHerdrReport,
271
307
  summarizeAskUserQuestion
272
308
  };
@@ -24724,11 +24724,13 @@ var McpServerManager = class {
24724
24724
  };
24725
24725
  for (const tools of Object.values(this.readCacheFile())) {
24726
24726
  for (const tool of tools) {
24727
- if (!this.definitions.has(tool.server)) continue;
24727
+ const definition = this.definitions.get(tool.server);
24728
+ if (!definition || definition.disabled) continue;
24728
24729
  claim2(tool, false);
24729
24730
  }
24730
24731
  }
24731
24732
  for (const runtime of this.runtimes.values()) {
24733
+ if (runtime.definition.disabled) continue;
24732
24734
  for (const tool of runtime.tools ?? []) claim2(tool, true);
24733
24735
  }
24734
24736
  for (const name of conflicts) {
@@ -24849,6 +24851,20 @@ ${tail}` : "")
24849
24851
  error: `MCP call "${prefixedName}" was cancelled before the request was sent; nothing was executed.`
24850
24852
  };
24851
24853
  }
24854
+ const postConnectCatalog = this.loadCatalog();
24855
+ if (this.conflictedNames.has(prefixedName)) {
24856
+ return {
24857
+ delivery: "not_sent",
24858
+ error: `MCP tool name "${prefixedName}" became claimed by more than one server during connection. Rename one of the servers so every tool name is unambiguous; the call was NOT sent.`
24859
+ };
24860
+ }
24861
+ const postDescriptor = postConnectCatalog.find((tool) => tool.prefixedName === prefixedName);
24862
+ if (postDescriptor && (postDescriptor.server !== server || postDescriptor.tool !== toolName)) {
24863
+ return {
24864
+ delivery: "not_sent",
24865
+ error: `MCP tool "${prefixedName}" resolved to ${postDescriptor.server}/${postDescriptor.tool} after connecting; refusing to send the stale target ${server}/${toolName}. Retry the call.`
24866
+ };
24867
+ }
24852
24868
  try {
24853
24869
  const result = await withTimeout(
24854
24870
  client.callTool({ name: toolName, arguments: args }, void 0, signal !== void 0 ? { signal } : void 0),
@@ -25266,19 +25282,26 @@ function mcpAdapter(ctx) {
25266
25282
  ctx.log
25267
25283
  );
25268
25284
  async function reloadManager() {
25269
- await manager.dispose().catch(() => void 0);
25285
+ let replacement;
25270
25286
  try {
25271
- manager = new McpServerManager(
25272
- resolveMcpAdapterConfig(ctx.cwd, configDir).servers,
25273
- metadataCacheDir,
25274
- ctx.log
25275
- );
25287
+ const resolved = resolveMcpAdapterConfig(ctx.cwd, configDir);
25288
+ if (resolved.problems.length > 0) {
25289
+ const message = `config layers failed to parse: ${resolved.problems.join("; ")}`;
25290
+ ctx.log(`mcp: config reload failed, keeping the previous manager: ${message}`);
25291
+ if (ctx.hasUI) ctx.ui.notify(`MCP adapter config error (previous servers kept): ${message}`, "error");
25292
+ return { ok: false, error: message };
25293
+ }
25294
+ replacement = new McpServerManager(resolved.servers, metadataCacheDir, ctx.log);
25276
25295
  } catch (error2) {
25277
25296
  const message = error2 instanceof Error ? error2.message : String(error2);
25278
- ctx.log(`mcp: config reload failed: ${message}`);
25279
- if (ctx.hasUI) ctx.ui.notify(`MCP adapter config error: ${message}`, "error");
25280
- manager = new McpServerManager([], metadataCacheDir, ctx.log);
25297
+ ctx.log(`mcp: config reload failed, keeping the previous manager: ${message}`);
25298
+ if (ctx.hasUI) ctx.ui.notify(`MCP adapter config error (previous servers kept): ${message}`, "error");
25299
+ return { ok: false, error: message };
25281
25300
  }
25301
+ const previous = manager;
25302
+ manager = replacement;
25303
+ await previous.dispose().catch(() => void 0);
25304
+ return { ok: true };
25282
25305
  }
25283
25306
  ctx.registerCleanup?.(() => manager.dispose().catch(() => void 0));
25284
25307
  function readProjectOverride() {
@@ -25359,6 +25382,7 @@ function mcpAdapter(ctx) {
25359
25382
  }
25360
25383
  const overrides = readProjectOverride().mcpServers;
25361
25384
  const forceEnabled = overrides?.[definition.name]?.disabled === false;
25385
+ const previousOverride = overrides?.[definition.name]?.disabled;
25362
25386
  const filePath = writeProjectOverride(
25363
25387
  definition.name,
25364
25388
  // enable must lift a source-level disabled:true with an explicit
@@ -25367,8 +25391,24 @@ function mcpAdapter(ctx) {
25367
25391
  // existing force-enable on repeated enable commands too.
25368
25392
  sub === "disable" ? true : definition.disabled || forceEnabled ? false : null
25369
25393
  );
25370
- await reloadManager();
25371
- const effectiveDisabled = manager.getDefinition(definition.name)?.disabled ?? false;
25394
+ const reload = await reloadManager();
25395
+ if (!reload.ok) {
25396
+ writeProjectOverride(definition.name, previousOverride === void 0 ? null : previousOverride);
25397
+ commandCtx.ui.notify(
25398
+ `MCP server "${definition.name}" NOT ${sub === "disable" ? "disabled" : "enabled"}: config reload failed (${reload.error}); previous servers kept and the override was rolled back.`,
25399
+ "error"
25400
+ );
25401
+ return;
25402
+ }
25403
+ const reloaded = manager.getDefinition(definition.name);
25404
+ if (!reloaded) {
25405
+ commandCtx.ui.notify(
25406
+ `MCP server "${definition.name}" disappeared from the reloaded config (wrote ${filePath}); check project/global config merges.`,
25407
+ "error"
25408
+ );
25409
+ return;
25410
+ }
25411
+ const effectiveDisabled = reloaded.disabled;
25372
25412
  const stateLabel = effectiveDisabled ? "disabled" : sub === "disable" ? "still enabled" : "enabled";
25373
25413
  commandCtx.ui.notify(
25374
25414
  `MCP server "${definition.name}" ${stateLabel} (wrote ${filePath}). ` + (eagerRegistered.length > 0 ? "Restart or /reload to resync direct tools." : "Effective immediately."),
@@ -7,7 +7,7 @@ import {
7
7
  isPlanModeSafeCommand,
8
8
  markCompletedPlanSteps,
9
9
  restoreExecutionState
10
- } from "../../../chunks/chunk-FKUEIYFQ.js";
10
+ } from "../../../chunks/chunk-REP6QANY.js";
11
11
  import "../../../chunks/chunk-ZKHMNEXL.js";
12
12
  import "../../../chunks/chunk-YRXXRLMQ.js";
13
13
  import {
@@ -1,11 +1,11 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  createCliHostCapabilities
4
- } from "../../../chunks/chunk-XVUV3IM2.js";
4
+ } from "../../../chunks/chunk-N2MK46AE.js";
5
5
  import {
6
6
  createSharedFileSystemTools,
7
7
  createSubagentCapability
8
- } from "../../../chunks/chunk-FKUEIYFQ.js";
8
+ } from "../../../chunks/chunk-REP6QANY.js";
9
9
  import "../../../chunks/chunk-ZKHMNEXL.js";
10
10
  import "../../../chunks/chunk-YRXXRLMQ.js";
11
11
  import "../../../chunks/chunk-5353DEEC.js";
@@ -38,6 +38,7 @@ function subagentExtension(ctx) {
38
38
  notify: ctx.hasUI ? (message, type) => ctx.ui.notify(message, type === "success" ? "info" : type) : void 0,
39
39
  debugLog: (module, message, data) => ctx.log(`[subagent:${module}] ${message}${data !== void 0 ? ` ${JSON.stringify(data)}` : ""}`),
40
40
  resolveModelClass: (modelClass) => ctx.resolveModelClass?.(modelClass),
41
+ resolveModelRef: (modelRef) => ctx.resolveModelRef?.(modelRef),
41
42
  createRuntimeTools: () => {
42
43
  const parentRuntimeTools = ctx.getRuntimeTools();
43
44
  if (Array.isArray(parentRuntimeTools) && parentRuntimeTools.length > 0) {
@@ -8,7 +8,7 @@ import {
8
8
  executeManageTodoList,
9
9
  executionStateToTodos,
10
10
  restoreExecutionState
11
- } from "../../../chunks/chunk-FKUEIYFQ.js";
11
+ } from "../../../chunks/chunk-REP6QANY.js";
12
12
  import "../../../chunks/chunk-ZKHMNEXL.js";
13
13
  import "../../../chunks/chunk-YRXXRLMQ.js";
14
14
  import "../../../chunks/chunk-XXGYUYXI.js";
@@ -8,7 +8,7 @@ import {
8
8
  createSharedWebSearchTool,
9
9
  interpretShellExit,
10
10
  requestInteraction
11
- } from "./chunk-FKUEIYFQ.js";
11
+ } from "./chunk-REP6QANY.js";
12
12
  import {
13
13
  getBuiltinDir,
14
14
  getConfigDir
@@ -543,9 +543,24 @@ function createBashTool(defaultCwd, options) {
543
543
  totalNewlines += data.reduce((count, byte) => count + (byte === 10 ? 1 : 0), 0);
544
544
  if (headBytes >= maxHeadBytes) return;
545
545
  const prefix = data.subarray(0, maxHeadBytes - headBytes);
546
- headChunks.push(prefix);
546
+ headChunks.push(Buffer.from(prefix));
547
547
  headBytes += prefix.length;
548
548
  };
549
+ const appendRollingChunk = (data) => {
550
+ const owned = Buffer.from(data);
551
+ chunks.push(owned);
552
+ chunksBytes += owned.length;
553
+ while (chunksBytes > maxChunksBytes && chunks.length > 1) {
554
+ const removed = chunks.shift();
555
+ chunksBytes -= removed.length;
556
+ }
557
+ if (chunks.length === 1 && chunksBytes > maxChunksBytes) {
558
+ const only = chunks[0];
559
+ const tail = only.subarray(only.length - maxChunksBytes);
560
+ chunks[0] = Buffer.from(tail);
561
+ chunksBytes = tail.length;
562
+ }
563
+ };
549
564
  let timedOut = false;
550
565
  let processExited = false;
551
566
  let exitCode = null;
@@ -641,12 +656,7 @@ function createBashTool(defaultCwd, options) {
641
656
  return;
642
657
  }
643
658
  }
644
- chunks.push(data);
645
- chunksBytes += data.length;
646
- while (chunksBytes > maxChunksBytes && chunks.length > 1) {
647
- const removed = chunks.shift();
648
- chunksBytes -= removed.length;
649
- }
659
+ appendRollingChunk(data);
650
660
  if (onUpdate) {
651
661
  const fullBuffer = Buffer.concat(chunks);
652
662
  const fullText = fullBuffer.toString("utf-8");
@@ -700,12 +710,7 @@ function createBashTool(defaultCwd, options) {
700
710
  return;
701
711
  }
702
712
  }
703
- chunks.push(data);
704
- chunksBytes += data.length;
705
- while (chunksBytes > maxChunksBytes && chunks.length > 1) {
706
- const removed = chunks.shift();
707
- chunksBytes -= removed.length;
708
- }
713
+ appendRollingChunk(data);
709
714
  });
710
715
  const finishExecution = async (code, sig, stdioIncomplete = false) => {
711
716
  if (settled) return;
@@ -1322,6 +1322,8 @@ function formatSkillSummariesForPrompt(skills) {
1322
1322
 
1323
1323
  // ../../packages/shared-headless-capabilities/src/subagent.ts
1324
1324
  var DEFAULT_SUBAGENT_TIMEOUT_SECONDS = 1200;
1325
+ var DEFAULT_SUBAGENT_THINKING_LEVEL = "medium";
1326
+ var SUBAGENT_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
1325
1327
  function formatSkillsForPrompt(skills) {
1326
1328
  return formatSkillSummariesForPrompt(skills);
1327
1329
  }
@@ -1411,21 +1413,28 @@ function filterToolsForSubagent(runtimeTools, parentTools, plan) {
1411
1413
  }
1412
1414
  return filtered;
1413
1415
  }
1414
- function buildSubagentPlan(deps, task, name, priority, timeoutSeconds) {
1416
+ function buildSubagentPlan(deps, task, name, priority, timeoutSeconds, modelOverride, thinkingLevel = DEFAULT_SUBAGENT_THINKING_LEVEL) {
1415
1417
  const complexity = inferComplexity(task, priority);
1416
1418
  const modelClass = selectModelClass(complexity, priority);
1417
- const modelResolution = deps.resolveModelClass?.(modelClass);
1419
+ const overrideResolution = modelOverride ? deps.resolveModelRef?.(modelOverride) ?? { model: void 0, fallbackReason: `model override "${modelOverride}" is not supported by this host` } : void 0;
1420
+ const overridePair = overrideResolution?.model && overrideResolution?.apiKey ? { model: overrideResolution.model, apiKey: overrideResolution.apiKey } : void 0;
1421
+ const modelResolution = overridePair ? void 0 : deps.resolveModelClass?.(modelClass);
1418
1422
  const resolvedPair = modelResolution?.model && modelResolution?.apiKey ? { model: modelResolution.model, apiKey: modelResolution.apiKey } : void 0;
1419
- const model = resolvedPair?.model ?? deps.model;
1420
- const apiKey = resolvedPair?.apiKey ?? deps.apiKey;
1423
+ const model = overridePair?.model ?? resolvedPair?.model ?? deps.model;
1424
+ const apiKey = overridePair?.apiKey ?? resolvedPair?.apiKey ?? deps.apiKey;
1425
+ const overrideMissReason = overrideResolution?.fallbackReason ?? `model override "${modelOverride}" could not be resolved`;
1426
+ const modelFallbackReason = modelOverride ? overridePair ? void 0 : modelResolution?.fallbackReason ? `${overrideMissReason}; ${modelResolution.fallbackReason}` : overrideMissReason : modelResolution?.fallbackReason;
1421
1427
  const partialPlan = {
1422
1428
  task,
1423
1429
  name,
1424
1430
  priority,
1425
1431
  complexity,
1426
1432
  modelClass,
1433
+ modelOverride,
1434
+ modelOverrideApplied: Boolean(overridePair),
1435
+ thinkingLevel,
1427
1436
  modelId: `${model?.provider ? `${model.provider}/` : ""}${model?.id ?? "unknown"}`,
1428
- modelFallbackReason: modelResolution?.fallbackReason,
1437
+ modelFallbackReason,
1429
1438
  toolsExcluded: [],
1430
1439
  timeoutSeconds,
1431
1440
  outputContract: "Return a concise answer with evidence, uncertainty, and any parent follow-up needed."
@@ -1438,13 +1447,14 @@ function buildSubagentPlan(deps, task, name, priority, timeoutSeconds) {
1438
1447
  };
1439
1448
  return { plan, tools: filteredTools, apiKey, model };
1440
1449
  }
1441
- function createAgentInstance(deps, systemPrompt, tools, model, apiKey) {
1450
+ function createAgentInstance(deps, systemPrompt, tools, model, apiKey, thinkingLevel) {
1442
1451
  if (deps.createAgent) {
1443
1452
  return deps.createAgent({
1444
1453
  systemPrompt,
1445
1454
  model,
1446
1455
  tools,
1447
- apiKey
1456
+ apiKey,
1457
+ thinkingLevel
1448
1458
  });
1449
1459
  }
1450
1460
  return new Agent({
@@ -1452,7 +1462,7 @@ function createAgentInstance(deps, systemPrompt, tools, model, apiKey) {
1452
1462
  systemPrompt,
1453
1463
  model,
1454
1464
  tools,
1455
- thinkingLevel: "off"
1465
+ thinkingLevel
1456
1466
  },
1457
1467
  apiKey
1458
1468
  });
@@ -1501,7 +1511,7 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal) {
1501
1511
  deps.debugLog?.("run", "runSubagentWithProgress START", { taskName: task.name, yoloMode: deps.yoloMode });
1502
1512
  try {
1503
1513
  reportProgress({ message: `[${task.name}] Starting...`, increment: 5 });
1504
- const { plan, tools, apiKey, model } = buildSubagentPlan(deps, task.task, task.name, task.priority, task.timeoutSeconds);
1514
+ const { plan, tools, apiKey, model } = buildSubagentPlan(deps, task.task, task.name, task.priority, task.timeoutSeconds, task.modelOverride, task.thinkingLevel);
1505
1515
  task.plan = plan;
1506
1516
  task.needsParentWrite = needsParentWrite(task.task);
1507
1517
  for (const excluded of plan.toolsExcluded) {
@@ -1521,7 +1531,7 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal) {
1521
1531
  if (signal?.aborted) {
1522
1532
  throw new Error("Subagent aborted by parent");
1523
1533
  }
1524
- deps.log(`[Subagent ${task.name}] Plan: ${plan.complexity}/${plan.modelClass}, ${tools.length} tools`);
1534
+ deps.log(`[Subagent ${task.name}] Plan: ${plan.complexity}/${plan.modelClass}${plan.modelOverride ? `, model=${plan.modelOverrideApplied ? plan.modelOverride : "override failed"}` : ""}, ${tools.length} tools`);
1525
1535
  deps.debugLog?.("plan", "SubagentPlan", plan);
1526
1536
  const systemPrompt = `You are a specialized subagent focused on one bounded task.
1527
1537
 
@@ -1538,7 +1548,7 @@ Output:
1538
1548
  - Parent follow-up needed, if any
1539
1549
 
1540
1550
  ${formatSkillsForPrompt(deps.skills ?? [])}`;
1541
- const subagent = createAgentInstance(deps, systemPrompt, tools, model, apiKey);
1551
+ const subagent = createAgentInstance(deps, systemPrompt, tools, model, apiKey, plan.thinkingLevel);
1542
1552
  let assistantTurns = 0;
1543
1553
  let toolCalls = 0;
1544
1554
  let rejectTimeout = () => void 0;
@@ -1660,6 +1670,12 @@ function buildParallelResult(tasks, totalDuration) {
1660
1670
  resultText += `**${task.name}** (${statusLabel}`;
1661
1671
  if (task.plan) {
1662
1672
  resultText += `, ${task.plan.complexity}/${task.plan.modelClass}`;
1673
+ if (task.plan.thinkingLevel !== DEFAULT_SUBAGENT_THINKING_LEVEL) {
1674
+ resultText += `, thinking=${task.plan.thinkingLevel}`;
1675
+ }
1676
+ if (task.plan.modelOverride) {
1677
+ resultText += task.plan.modelOverrideApplied ? `, model=${task.plan.modelOverride}` : `, model=${task.plan.modelOverride} (unresolved, fell back)`;
1678
+ }
1663
1679
  }
1664
1680
  if (task.details) {
1665
1681
  resultText += `, ${task.details.durationMs}ms, ${task.details.toolCalls} tools`;
@@ -1699,7 +1715,7 @@ function normalizeTaskDefs(args) {
1699
1715
  return { error: "Invalid spawn_subagents_parallel arguments: tasks must be a non-empty array." };
1700
1716
  }
1701
1717
  const normalized = [];
1702
- const allowedFields = [...TASK_FIELD_ALIASES, "name", "priority", "timeout"];
1718
+ const allowedFields = [...TASK_FIELD_ALIASES, "name", "priority", "timeout", "model", "thinkingLevel"];
1703
1719
  for (const [index, def] of taskDefs.entries()) {
1704
1720
  if (!def || typeof def !== "object") {
1705
1721
  return { error: `Invalid task #${index + 1}: expected an object with the objective in "task" (aliases "description"/"prompt"/"objective" accepted).` };
@@ -1722,11 +1738,20 @@ function normalizeTaskDefs(args) {
1722
1738
  return { error: `Invalid task #${index + 1}: timeout must be a positive number of seconds.` };
1723
1739
  }
1724
1740
  const priority = def.priority === "thorough" ? "thorough" : "fast";
1741
+ const modelOverride = typeof def.model === "string" ? def.model.trim() : void 0;
1742
+ if (def.model !== void 0 && !modelOverride) {
1743
+ return { error: `Invalid task #${index + 1}: "model" must be a non-empty model reference such as "provider/model-id".` };
1744
+ }
1745
+ if (def.thinkingLevel !== void 0 && (typeof def.thinkingLevel !== "string" || !SUBAGENT_THINKING_LEVELS.includes(def.thinkingLevel))) {
1746
+ return { error: `Invalid task #${index + 1}: "thinkingLevel" must be one of ${SUBAGENT_THINKING_LEVELS.map((level) => `"${level}"`).join(", ")}.` };
1747
+ }
1725
1748
  normalized.push({
1726
1749
  name: typeof def.name === "string" && def.name.trim() ? def.name.trim() : void 0,
1727
1750
  task,
1728
1751
  priority,
1729
- timeoutSeconds
1752
+ timeoutSeconds,
1753
+ modelOverride,
1754
+ thinkingLevel: def.thinkingLevel
1730
1755
  });
1731
1756
  }
1732
1757
  return normalized;
@@ -1770,7 +1795,11 @@ function createSubagentCapability(deps) {
1770
1795
  Use this for independent investigation, search, review, or triage work. Provide each task as a plain objective. Pie chooses the model class automatically. Use timeout only for unusually long tasks.
1771
1796
 
1772
1797
  Arguments shape (each tasks[] item puts the objective in "task" \u2014 "description"/"prompt"/"objective" are accepted as aliases):
1773
- { "tasks": [{ "task": "<objective text>", "name": "<optional short label>", "priority": "fast" | "thorough", "timeout": 600 }] }`,
1798
+ { "tasks": [{ "task": "<objective text>", "name": "<optional short label>", "priority": "fast" | "thorough", "model": "<optional explicit model override>", "thinkingLevel": "<optional off|minimal|low|medium|high|xhigh, default medium>", "timeout": 600 }] }
1799
+
1800
+ "model" overrides the automatic model-class selection for that task when the user explicitly asks for a specific model (e.g. "anthropic/claude-..."). Prefer "provider/model-id"; a bare model id works only when it is unambiguous across providers. When the override cannot be resolved, the task falls back to automatic selection and reports why.
1801
+
1802
+ "thinkingLevel" defaults to "medium"; set it only when the user asks (e.g. "xhigh" for deep review) or for cheap lookup tasks ("off"). Non-reasoning models ignore it.`,
1774
1803
  parameters: Type.Object({
1775
1804
  tasks: Type.Array(
1776
1805
  Type.Object(
@@ -1781,9 +1810,11 @@ Arguments shape (each tasks[] item puts the objective in "task" \u2014 "descript
1781
1810
  objective: Type.Optional(Type.String({ description: "Alias for task." })),
1782
1811
  name: Type.Optional(Type.String({ description: "Short name for this subagent, shown in progress updates." })),
1783
1812
  priority: Type.Optional(Type.Union([Type.Literal("fast"), Type.Literal("thorough")], { description: "fast uses lower-cost defaults; thorough raises model class when needed." })),
1813
+ model: Type.Optional(Type.String({ description: 'Explicit model override for this task, e.g. "provider/model-id". Only set when the user explicitly requests a specific model; otherwise Pie picks the model class automatically.' })),
1814
+ thinkingLevel: Type.Optional(Type.Union([Type.Literal("off"), Type.Literal("minimal"), Type.Literal("low"), Type.Literal("medium"), Type.Literal("high"), Type.Literal("xhigh")], { description: `Reasoning level for this task. Default: "medium". Only override when the user asks (e.g. "xhigh" for deep review tasks, "off" for cheap lookups). Ignored by non-reasoning models.` })),
1784
1815
  timeout: Type.Optional(Type.Number({ description: "Timeout in seconds. Default: 1200s (20 minutes). For longer tasks, explicitly set a higher value, e.g. 3600." }))
1785
1816
  },
1786
- { additionalProperties: false, description: "Objective goes in 'task' (or an accepted alias); plus optional name/priority/timeout." }
1817
+ { additionalProperties: false, description: "Objective goes in 'task' (or an accepted alias); plus optional name/priority/model/thinkingLevel/timeout." }
1787
1818
  ),
1788
1819
  { description: "Array of tasks to run in parallel; at least one of task/description/prompt/objective must be a non-empty string per item.", minItems: 1, maxItems: 10 }
1789
1820
  )
@@ -1816,6 +1847,8 @@ Arguments shape (each tasks[] item puts the objective in "task" \u2014 "descript
1816
1847
  task: def.task,
1817
1848
  priority: def.priority,
1818
1849
  timeoutSeconds: def.timeoutSeconds,
1850
+ modelOverride: def.modelOverride,
1851
+ thinkingLevel: def.thinkingLevel,
1819
1852
  evidence: [],
1820
1853
  confidenceSignals: [],
1821
1854
  uncertainty: "medium",
@@ -1866,6 +1899,8 @@ Arguments shape (each tasks[] item puts the objective in "task" \u2014 "descript
1866
1899
  task: task.task,
1867
1900
  timeoutSeconds: task.timeoutSeconds,
1868
1901
  plan: task.plan,
1902
+ modelOverride: task.modelOverride,
1903
+ thinkingLevel: task.plan?.thinkingLevel,
1869
1904
  evidence: task.evidence,
1870
1905
  confidenceSignals: task.confidenceSignals,
1871
1906
  runtimeEvidence: task.runtimeEvidence,
@@ -2932,6 +2967,9 @@ var FileSessionStore = class {
2932
2967
  throw new Error(`Session directory is a symbolic link; ${operation} refused: ${dir}`);
2933
2968
  }
2934
2969
  headStatus(sessionId) {
2970
+ if (sessionDirIsSymlink(this.pathsFor(sessionId).dir)) {
2971
+ return "missing";
2972
+ }
2935
2973
  const head = this.tryReadHeadFile(sessionId);
2936
2974
  if (head === "corrupt") {
2937
2975
  return "corrupt";
@@ -2987,6 +3025,9 @@ var FileSessionStore = class {
2987
3025
  * never reinitialize a damaged session to sequence 0.
2988
3026
  */
2989
3027
  tryReadHeadFile(sessionId) {
3028
+ if (sessionDirIsSymlink(this.pathsFor(sessionId).dir)) {
3029
+ return null;
3030
+ }
2990
3031
  const headPath = this.pathsFor(sessionId).headPath;
2991
3032
  const durable = readDurableFileSync(this.gateway, headPath, (content) => this.parseHeadContent(content));
2992
3033
  if (durable !== null) {
@@ -8579,6 +8620,7 @@ function createFileObservationState(options = {}) {
8579
8620
  const files = /* @__PURE__ */ new Map();
8580
8621
  const maxFiles = Math.max(1, Math.floor(options.maxFiles ?? 100));
8581
8622
  const maxRangesPerFile = Math.max(0, Math.floor(options.maxRangesPerFile ?? 8));
8623
+ let generation = 0;
8582
8624
  function touchFile(absolutePath, observed) {
8583
8625
  files.delete(absolutePath);
8584
8626
  files.set(absolutePath, observed);
@@ -8695,8 +8737,12 @@ function createFileObservationState(options = {}) {
8695
8737
  invalidate(absolutePath) {
8696
8738
  files.delete(absolutePath);
8697
8739
  },
8740
+ getGeneration() {
8741
+ return generation;
8742
+ },
8698
8743
  clear() {
8699
8744
  files.clear();
8745
+ generation++;
8700
8746
  }
8701
8747
  };
8702
8748
  }
@@ -8716,6 +8762,7 @@ function createReadErrorResult(message, details) {
8716
8762
  function createReadTool(cwd, options) {
8717
8763
  const fs2 = getFileSystem();
8718
8764
  const fileObservationState = options?.fileObservationState ?? createFileObservationState();
8765
+ const callerObservations = /* @__PURE__ */ new WeakMap();
8719
8766
  const rootSchema = buildRootParameterSchema(cwd, options);
8720
8767
  const readSchema = Type.Object({
8721
8768
  path: Type.String({ description: "Path to the file to read. Example: 'Scripts/PlayerController.cs' or 'Assets/Gen/config.json'." }),
@@ -8950,7 +8997,18 @@ function createReadTool(cwd, options) {
8950
8997
  const readStartsAtBeginning = offset === void 0 || offset === 1;
8951
8998
  const readReachedEndOfFile = startLine + range2.selectedLines >= range2.totalLines;
8952
8999
  const isCompleteTextKnown = readStartsAtBeginning && readReachedEndOfFile && !truncation.truncated && !truncation.firstLineExceedsLimit;
8953
- if (fileObservationState.isUnchangedReadRange(absolutePath, rangeKey, snapshot, range2.selectedContentHash)) {
9000
+ let callerObservation = fileObservationState;
9001
+ if (signal) {
9002
+ const generation = fileObservationState.getGeneration();
9003
+ const existing = callerObservations.get(signal);
9004
+ if (existing?.generation === generation) {
9005
+ callerObservation = existing.state;
9006
+ } else {
9007
+ callerObservation = createFileObservationState();
9008
+ callerObservations.set(signal, { generation, state: callerObservation });
9009
+ }
9010
+ }
9011
+ if (fileObservationState.isUnchangedReadRange(absolutePath, rangeKey, snapshot, range2.selectedContentHash) && callerObservation.isUnchangedReadRange(absolutePath, rangeKey, snapshot, range2.selectedContentHash)) {
8954
9012
  if (signal) {
8955
9013
  signal.removeEventListener("abort", onAbort);
8956
9014
  }
@@ -9017,6 +9075,9 @@ Base directory: ${nodePath.dirname(absolutePath)}
9017
9075
  totalLines: range2.totalLines
9018
9076
  }
9019
9077
  );
9078
+ if (callerObservation !== fileObservationState) {
9079
+ callerObservation.recordTextRead(absolutePath, rangeKey, snapshot, range2.selectedContentHash, isCompleteTextKnown);
9080
+ }
9020
9081
  outputText = sourceHeader + outputText;
9021
9082
  const textContent = [{ type: "text", text: outputText }];
9022
9083
  if (aborted) return;
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  createCliWebResearchHealthStore,
8
8
  formatSize,
9
9
  truncateHeadTail
10
- } from "./chunks/chunk-XVUV3IM2.js";
10
+ } from "./chunks/chunk-N2MK46AE.js";
11
11
  import {
12
12
  AGENTS_CONTEXT_FILE_NAME,
13
13
  AgentSessionController,
@@ -60,7 +60,7 @@ import {
60
60
  setExtensionEnabledInSettings,
61
61
  shouldPreserveExecutionStateForUserText,
62
62
  supersedeExecutionState
63
- } from "./chunks/chunk-FKUEIYFQ.js";
63
+ } from "./chunks/chunk-REP6QANY.js";
64
64
  import "./chunks/chunk-ZKHMNEXL.js";
65
65
  import {
66
66
  Deref,
@@ -53356,6 +53356,46 @@ var ModelRegistry = class {
53356
53356
  }
53357
53357
  return { model, apiKey };
53358
53358
  }
53359
+ /** Resolve an explicit model reference for user-requested overrides.
53360
+ * Accepts "provider/model-id" (exact lookup) or a bare model id (only
53361
+ * when it matches exactly one configured model). Never guesses across
53362
+ * providers; ambiguity and missing keys are reported as fallback reasons. */
53363
+ resolveModelRef(ref) {
53364
+ const trimmed = ref.trim();
53365
+ if (!trimmed) {
53366
+ return { fallbackReason: "empty model reference" };
53367
+ }
53368
+ const separator = trimmed.indexOf("/");
53369
+ if (separator >= 0) {
53370
+ if (separator === 0 || separator === trimmed.length - 1) {
53371
+ return { fallbackReason: `invalid model reference "${trimmed}"; expected provider/model-id` };
53372
+ }
53373
+ const provider = trimmed.slice(0, separator);
53374
+ const modelId = trimmed.slice(separator + 1);
53375
+ const model2 = this.find(provider, modelId);
53376
+ if (!model2) {
53377
+ return { fallbackReason: `model "${trimmed}" is not configured` };
53378
+ }
53379
+ const apiKey2 = this.getApiKey(model2);
53380
+ if (!apiKey2) {
53381
+ return { model: model2, fallbackReason: `no API key available for model "${trimmed}"` };
53382
+ }
53383
+ return { model: model2, apiKey: apiKey2 };
53384
+ }
53385
+ const matches = this.getAll().filter((model2) => model2.id === trimmed);
53386
+ if (matches.length === 0) {
53387
+ return { fallbackReason: `model "${trimmed}" is not configured; use provider/model-id` };
53388
+ }
53389
+ if (matches.length > 1) {
53390
+ return { fallbackReason: `model "${trimmed}" is ambiguous across providers (${matches.map((model2) => `${model2.provider}/${model2.id}`).join(", ")}); use provider/model-id` };
53391
+ }
53392
+ const model = matches[0];
53393
+ const apiKey = this.getApiKey(model);
53394
+ if (!apiKey) {
53395
+ return { model, fallbackReason: `no API key available for model "${model.provider}/${model.id}"` };
53396
+ }
53397
+ return { model, apiKey };
53398
+ }
53359
53399
  hasExternalProviderConfig() {
53360
53400
  return this.usingExternalProviders;
53361
53401
  }
@@ -55169,11 +55209,44 @@ function canonicalSessionDir(sessionsDir, sessionId) {
55169
55209
  function publishJournalPath(sessionsDir, safeTargetId) {
55170
55210
  return path7.join(sessionsDir, PUBLISH_JOURNAL_DIR, `${safeTargetId}.json`);
55171
55211
  }
55212
+ var FSYNC_UNSUPPORTED_CODES = /* @__PURE__ */ new Set(["EPERM", "EINVAL", "ENOTSUP", "EOPNOTSUPP", "EACCES", "EBADF"]);
55213
+ function fsyncDirectory(dirPath) {
55214
+ try {
55215
+ const fd = fs7.openSync(dirPath, "r");
55216
+ try {
55217
+ fs7.fsyncSync(fd);
55218
+ } finally {
55219
+ fs7.closeSync(fd);
55220
+ }
55221
+ } catch (error) {
55222
+ const code = error?.code;
55223
+ if (code !== void 0 && FSYNC_UNSUPPORTED_CODES.has(code)) return;
55224
+ throw error;
55225
+ }
55226
+ }
55172
55227
  function writePublishJournal(journalPath, record) {
55173
- fs7.mkdirSync(path7.dirname(journalPath), { recursive: true });
55228
+ const journalDir = path7.dirname(journalPath);
55229
+ fs7.mkdirSync(journalDir, { recursive: true });
55174
55230
  const tempPath = `${journalPath}.tmp`;
55175
55231
  fs7.writeFileSync(tempPath, JSON.stringify(record, void 0, " "));
55232
+ const tempFd = fs7.openSync(tempPath, "r+");
55233
+ try {
55234
+ fs7.fsyncSync(tempFd);
55235
+ } finally {
55236
+ fs7.closeSync(tempFd);
55237
+ }
55176
55238
  fs7.renameSync(tempPath, journalPath);
55239
+ fsyncDirectory(journalDir);
55240
+ fsyncDirectory(path7.dirname(journalDir));
55241
+ }
55242
+ function markPublishJournalFailed(journalPath) {
55243
+ if (!journalPath) return;
55244
+ try {
55245
+ const record = JSON.parse(fs7.readFileSync(journalPath, "utf8"));
55246
+ if (record?.v !== 1 || typeof record.failedAt === "number") return;
55247
+ writePublishJournal(journalPath, { ...record, failedAt: Date.now() });
55248
+ } catch {
55249
+ }
55177
55250
  }
55178
55251
  function clearPublishJournal(journalPath) {
55179
55252
  if (!journalPath) return;
@@ -55226,6 +55299,7 @@ async function rewindStoredSession(params) {
55226
55299
  }
55227
55300
  async function forkStoredSession(params) {
55228
55301
  let stagingId;
55302
+ let preserveStagingForRecovery = false;
55229
55303
  try {
55230
55304
  const sanitizedTargetId = params.targetSessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
55231
55305
  if (sanitizedTargetId.startsWith(STAGING_SESSION_ID_PREFIX)) {
@@ -55356,6 +55430,7 @@ async function forkStoredSession(params) {
55356
55430
  if (hadPreviousTarget) {
55357
55431
  try {
55358
55432
  params.store.moveSession(params.targetSessionId, backupId);
55433
+ if (params.sessionsDir) fsyncDirectory(params.sessionsDir);
55359
55434
  } catch (error) {
55360
55435
  clearPublishJournal(journalPath);
55361
55436
  throw error;
@@ -55363,6 +55438,7 @@ async function forkStoredSession(params) {
55363
55438
  }
55364
55439
  try {
55365
55440
  params.store.moveSession(stagingId, params.targetSessionId);
55441
+ if (params.sessionsDir) fsyncDirectory(params.sessionsDir);
55366
55442
  } catch (error) {
55367
55443
  if (hadPreviousTarget) {
55368
55444
  try {
@@ -55370,8 +55446,11 @@ async function forkStoredSession(params) {
55370
55446
  throw new Error("target path is occupied");
55371
55447
  }
55372
55448
  params.store.moveSession(backupId, params.targetSessionId);
55449
+ if (params.sessionsDir) fsyncDirectory(params.sessionsDir);
55373
55450
  clearPublishJournal(journalPath);
55374
55451
  } catch (restoreError) {
55452
+ markPublishJournalFailed(journalPath);
55453
+ preserveStagingForRecovery = true;
55375
55454
  throw new SessionControlError(
55376
55455
  "session_io_error",
55377
55456
  `Fork publication failed; previous session is preserved as ${backupId}. Restore failed: ${String(restoreError)}`,
@@ -55406,7 +55485,7 @@ async function forkStoredSession(params) {
55406
55485
  } catch (error) {
55407
55486
  throw toIoError(error);
55408
55487
  } finally {
55409
- if (stagingId) {
55488
+ if (stagingId && !preserveStagingForRecovery) {
55410
55489
  try {
55411
55490
  params.store.delete(stagingId);
55412
55491
  } catch {
@@ -55479,7 +55558,7 @@ function recoverOnePublishJournal(params) {
55479
55558
  try {
55480
55559
  const parsed = JSON.parse(fs7.readFileSync(params.journalPath, "utf8"));
55481
55560
  const safeId = /^[a-zA-Z0-9_-]+$/;
55482
- if (parsed?.v !== 1 || !safeId.test(parsed.targetId ?? "") || !safeId.test(parsed.stagingId ?? "") || !((parsed.backupDir ?? null) === null || safeId.test(parsed.backupDir))) {
55561
+ if (parsed?.v !== 1 || !safeId.test(parsed.targetId ?? "") || !safeId.test(parsed.stagingId ?? "") || !((parsed.backupDir ?? null) === null || safeId.test(parsed.backupDir)) || !((parsed.failedAt ?? void 0) === void 0 || typeof parsed.failedAt === "number")) {
55483
55562
  throw new Error("journal record has unexpected shape");
55484
55563
  }
55485
55564
  record = parsed;
@@ -55505,7 +55584,7 @@ function recoverOnePublishJournal(params) {
55505
55584
  const backupExists = record.backupDir ? dirExists(record.backupDir) : false;
55506
55585
  const stagingExists = dirExists(record.stagingId);
55507
55586
  try {
55508
- if (targetExists && !stagingExists) {
55587
+ if (targetExists && !stagingExists && record.failedAt === void 0) {
55509
55588
  if (backupExists && record.backupDir) removeSessionDir(record.backupDir);
55510
55589
  removeJournal();
55511
55590
  return { action: "publish-completed", targetId: record.targetId };
@@ -55515,22 +55594,32 @@ function recoverOnePublishJournal(params) {
55515
55594
  path7.join(params.sessionsDir, record.backupDir),
55516
55595
  path7.join(params.sessionsDir, record.targetId)
55517
55596
  );
55518
- removeJournal();
55597
+ fsyncDirectory(params.sessionsDir);
55519
55598
  if (stagingExists) {
55520
55599
  try {
55521
55600
  removeSessionDir(record.stagingId);
55522
55601
  } catch (error) {
55523
55602
  warn(`[session-control] Restored ${record.targetId} but could not remove its abandoned staging copy ${record.stagingId}: ${String(error)}`);
55603
+ return { action: "ambiguous-preserved", targetId: record.targetId, message: `Staging cleanup failed after restore; journal preserved: ${String(error)}` };
55524
55604
  }
55525
55605
  }
55606
+ removeJournal();
55526
55607
  return { action: "restored-previous-target", targetId: record.targetId };
55527
55608
  }
55528
55609
  if (!targetExists && !backupExists) {
55529
- if (stagingExists) removeSessionDir(record.stagingId);
55610
+ if (stagingExists) {
55611
+ try {
55612
+ removeSessionDir(record.stagingId);
55613
+ } catch (error) {
55614
+ warn(`[session-control] Could not remove abandoned staging copy ${record.stagingId}: ${String(error)}`);
55615
+ return { action: "ambiguous-preserved", targetId: record.targetId, message: `Staging cleanup failed; journal preserved: ${String(error)}` };
55616
+ }
55617
+ }
55530
55618
  removeJournal();
55531
55619
  return stagingExists ? { action: "discarded-incomplete-fork", targetId: record.targetId } : { action: "nothing-to-recover", targetId: record.targetId };
55532
55620
  }
55533
- const message = `[session-control] Ambiguous interrupted publish for target ${record.targetId} (target=${targetExists}, backup=${backupExists}, staging=${stagingExists}); nothing was deleted \u2014 inspect ${params.sessionsDir} and ${journalName} manually`;
55621
+ const reason = record.failedAt !== void 0 ? "the publish failed in-process (restore failed) and the backup was preserved" : `target=${targetExists}, backup=${backupExists}, staging=${stagingExists}`;
55622
+ const message = `[session-control] Ambiguous interrupted publish for target ${record.targetId} (${reason}); nothing was deleted \u2014 inspect ${params.sessionsDir} and ${journalName} manually`;
55534
55623
  warn(message);
55535
55624
  return { action: "ambiguous-preserved", targetId: record.targetId, message };
55536
55625
  } catch (error) {
@@ -56206,6 +56295,9 @@ function createExtensionContext(extension, cwd, uiContext, abortFn, isIdleFn, ha
56206
56295
  resolveModelClass(modelClass) {
56207
56296
  return actions?.resolveModelClass?.(modelClass) ?? {};
56208
56297
  },
56298
+ resolveModelRef(modelRef) {
56299
+ return actions?.resolveModelRef?.(modelRef) ?? {};
56300
+ },
56209
56301
  getMessages() {
56210
56302
  return actions?.getMessages?.() ?? [];
56211
56303
  },
@@ -63885,6 +63977,7 @@ var ExtensionRunner = class {
63885
63977
  getAllTools: () => runner.actions.getAllTools(),
63886
63978
  getRuntimeTools: () => runner.actions.getRuntimeTools(),
63887
63979
  resolveModelClass: (modelClass) => runner.actions.resolveModelClass?.(modelClass) ?? {},
63980
+ resolveModelRef: (modelRef) => runner.actions.resolveModelRef?.(modelRef) ?? {},
63888
63981
  getMessages: () => runner.actions.getMessages(),
63889
63982
  getSessionMetadata: () => runner.actions.getSessionMetadata(),
63890
63983
  setSessionMetadata: (key, value) => runner.actions.setSessionMetadata(key, value),
@@ -74159,6 +74252,7 @@ function createExtensionContextForCommands(host) {
74159
74252
  },
74160
74253
  getRuntimeTools: () => host.agent.state.tools,
74161
74254
  resolveModelClass: (modelClass) => host.options.modelRegistry.resolveModelClass(modelClass),
74255
+ resolveModelRef: (modelRef) => host.options.modelRegistry.resolveModelRef(modelRef),
74162
74256
  getMessages: () => host.agent.state.messages,
74163
74257
  getSessionMetadata: () => ({ ...host.sessionManager.getActiveSession()?.metadata ?? {} }),
74164
74258
  setSessionMetadata: (key, value) => {
@@ -79434,6 +79528,7 @@ async function loadInteractiveExtensions(host) {
79434
79528
  fallbackReason: resolved.fallbackReason
79435
79529
  };
79436
79530
  },
79531
+ resolveModelRef: (modelRef) => host.options.modelRegistry.resolveModelRef(modelRef),
79437
79532
  getMessages: () => host.agent.state.messages,
79438
79533
  getSessionMetadata: () => ({ ...host.sessionManager.getActiveSession()?.metadata ?? {} }),
79439
79534
  setSessionMetadata: (key, value) => {
@@ -80657,6 +80752,7 @@ async function loadPrintModeExtensions(params) {
80657
80752
  })),
80658
80753
  getRuntimeTools: () => params.getAgent()?.state.tools ?? [],
80659
80754
  resolveModelClass: (modelClass) => params.modelRegistry.resolveModelClass(modelClass),
80755
+ resolveModelRef: (modelRef) => params.modelRegistry.resolveModelRef(modelRef),
80660
80756
  getMessages: () => params.getAgent()?.state.messages ?? [],
80661
80757
  getSessionMetadata: () => ({ ...params.sessionManager.getActiveSession()?.metadata ?? {} }),
80662
80758
  setSessionMetadata: (key, value) => {
@@ -81145,6 +81241,7 @@ async function loadJsonModeExtensions(params) {
81145
81241
  })),
81146
81242
  getRuntimeTools: () => params.getAgent()?.state.tools ?? [],
81147
81243
  resolveModelClass: (modelClass) => params.runtime.modelRegistry.resolveModelClass(modelClass),
81244
+ resolveModelRef: (modelRef) => params.runtime.modelRegistry.resolveModelRef(modelRef),
81148
81245
  getMessages: () => params.getAgent()?.state.messages ?? [],
81149
81246
  getSessionMetadata: () => ({ ...params.runtime.sessionManager.getActiveSession()?.metadata ?? {} }),
81150
81247
  setSessionMetadata: (key, value) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cydm/pie",
3
- "version": "2.4.0",
3
+ "version": "2.5.1",
4
4
  "description": "Pie AI Agent CLI",
5
5
  "type": "module",
6
6
  "bin": {