@cydm/pie 2.6.1 → 2.6.3

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-IKLQHWY2.js";
4
+ } from "../../../chunks/chunk-WG6E54WK.js";
5
5
  import "../../../chunks/chunk-Y4CYXJR7.js";
6
6
  import "../../../chunks/chunk-O2DKMLNX.js";
7
7
  import "../../../chunks/chunk-XXGYUYXI.js";
@@ -7,7 +7,7 @@ import {
7
7
  isPlanModeSafeCommand,
8
8
  markCompletedPlanSteps,
9
9
  restoreExecutionState
10
- } from "../../../chunks/chunk-IKLQHWY2.js";
10
+ } from "../../../chunks/chunk-WG6E54WK.js";
11
11
  import "../../../chunks/chunk-Y4CYXJR7.js";
12
12
  import "../../../chunks/chunk-O2DKMLNX.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-3F5ZP2CV.js";
4
+ } from "../../../chunks/chunk-KTSUOXA7.js";
5
5
  import {
6
6
  createSharedFileSystemTools,
7
7
  createSubagentCapability
8
- } from "../../../chunks/chunk-IKLQHWY2.js";
8
+ } from "../../../chunks/chunk-WG6E54WK.js";
9
9
  import "../../../chunks/chunk-Y4CYXJR7.js";
10
10
  import "../../../chunks/chunk-O2DKMLNX.js";
11
11
  import "../../../chunks/chunk-5353DEEC.js";
@@ -8,7 +8,7 @@ import {
8
8
  executeManageTodoList,
9
9
  executionStateToTodos,
10
10
  restoreExecutionState
11
- } from "../../../chunks/chunk-IKLQHWY2.js";
11
+ } from "../../../chunks/chunk-WG6E54WK.js";
12
12
  import "../../../chunks/chunk-Y4CYXJR7.js";
13
13
  import "../../../chunks/chunk-O2DKMLNX.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-IKLQHWY2.js";
11
+ } from "./chunk-WG6E54WK.js";
12
12
  import {
13
13
  getBuiltinDir,
14
14
  getConfigDir
@@ -1390,6 +1390,17 @@ function formatSkillSummariesForPrompt(skills) {
1390
1390
  var DEFAULT_SUBAGENT_TIMEOUT_SECONDS = 1200;
1391
1391
  var DEFAULT_SUBAGENT_THINKING_LEVEL = "medium";
1392
1392
  var SUBAGENT_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
1393
+ var DEFAULT_HEARTBEAT_INTERVAL_MS = 3e4;
1394
+ function formatHeartbeatElapsed(ms) {
1395
+ const totalSeconds = Math.floor(ms / 1e3);
1396
+ if (totalSeconds < 60) return `${totalSeconds}s`;
1397
+ const minutes = Math.floor(totalSeconds / 60);
1398
+ if (minutes < 60) return `${minutes}m${String(totalSeconds % 60).padStart(2, "0")}s`;
1399
+ return `${Math.floor(minutes / 60)}h${String(minutes % 60).padStart(2, "0")}m`;
1400
+ }
1401
+ function clipHeartbeatLabel(text, maxLength = 60) {
1402
+ return text.length > maxLength ? `${text.slice(0, maxLength - 1)}\u2026` : text;
1403
+ }
1393
1404
  function formatSkillsForPrompt(skills) {
1394
1405
  return formatSkillSummariesForPrompt(skills);
1395
1406
  }
@@ -1596,9 +1607,30 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal) {
1596
1607
  const startTime = Date.now();
1597
1608
  task.status = "running";
1598
1609
  let timedOut = false;
1610
+ let lastProgressAt = Date.now();
1611
+ let lastActivity = "starting";
1612
+ const report = (update) => {
1613
+ lastProgressAt = Date.now();
1614
+ if (update.message) lastActivity = update.message;
1615
+ reportProgress(update);
1616
+ };
1617
+ const heartbeatIntervalMs = deps.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
1599
1618
  deps.debugLog?.("run", "runSubagentWithProgress START", { taskName: task.name, yoloMode: deps.yoloMode });
1619
+ let heartbeat;
1620
+ if (heartbeatIntervalMs > 0) {
1621
+ heartbeat = setInterval(() => {
1622
+ try {
1623
+ if (Date.now() - lastProgressAt < heartbeatIntervalMs) return;
1624
+ lastProgressAt = Date.now();
1625
+ reportProgress({
1626
+ message: `[${task.name}] Still working (${formatHeartbeatElapsed(Date.now() - startTime)} elapsed; last: ${clipHeartbeatLabel(lastActivity)})`
1627
+ });
1628
+ } catch {
1629
+ }
1630
+ }, Math.max(50, Math.min(1e3, heartbeatIntervalMs / 2)));
1631
+ }
1600
1632
  try {
1601
- reportProgress({ message: `[${task.name}] Starting...`, increment: 5 });
1633
+ report({ message: `[${task.name}] Starting...`, increment: 5 });
1602
1634
  const { plan, tools, apiKey, model } = buildSubagentPlan(deps, task.task, task.name, task.priority, task.timeoutSeconds, task.modelOverride, task.thinkingLevel, task.mode);
1603
1635
  task.plan = plan;
1604
1636
  task.needsParentWrite = task.mode === "read" && needsParentWrite(task.task);
@@ -1639,7 +1671,6 @@ ${formatSkillsForPrompt(deps.skills ?? [])}`;
1639
1671
  const subagent = createAgentInstance(deps, systemPrompt, tools, model, apiKey, plan.thinkingLevel);
1640
1672
  let assistantTurns = 0;
1641
1673
  let toolCalls = 0;
1642
- let outputTruncated = false;
1643
1674
  let rejectTimeout = () => void 0;
1644
1675
  let timeout;
1645
1676
  let unsubscribe;
@@ -1679,14 +1710,13 @@ ${formatSkillsForPrompt(deps.skills ?? [])}`;
1679
1710
  type: event.toolName === "bash" ? "command_run" : event.toolName === "read_file" ? "file_read" : "tool_success",
1680
1711
  message: `${event.toolName} started`
1681
1712
  });
1682
- reportProgress({ message: `[${task.name}] Using ${event.toolName}...` });
1713
+ report({ message: `[${task.name}] Using ${event.toolName}...` });
1683
1714
  }
1684
1715
  if (event.type === "tool_execution_end" && event.isError) {
1685
1716
  task.confidenceSignals.push({ type: "tool_error", message: `${event.toolName} failed` });
1686
1717
  }
1687
1718
  if (event.type === "message_end" && event.message?.role === "assistant") {
1688
1719
  assistantTurns++;
1689
- if (event.message.stopReason === "length") outputTruncated = true;
1690
1720
  }
1691
1721
  });
1692
1722
  let prompt = task.task;
@@ -1694,7 +1724,7 @@ ${formatSkillsForPrompt(deps.skills ?? [])}`;
1694
1724
  prompt += "\n\nThis delegation is read mode. Do not write files. If changes are needed, describe them for the parent.";
1695
1725
  }
1696
1726
  prompt += "\n\nReturn evidence for your conclusion and state uncertainty as low, medium, or high.";
1697
- reportProgress({ message: `[${task.name}] Running plan ${plan.complexity}/${plan.modelClass}...`, increment: 20 });
1727
+ report({ message: `[${task.name}] Running plan ${plan.complexity}/${plan.modelClass}...`, increment: 20 });
1698
1728
  try {
1699
1729
  await Promise.race([
1700
1730
  (async () => {
@@ -1722,6 +1752,7 @@ ${formatSkillsForPrompt(deps.skills ?? [])}`;
1722
1752
  throw new Error(`Subagent stream interrupted (SSE stream aborted before the report was produced, stopReason=${terminalStopReason ?? "none"}${collectedResponse ? ", partial transcript discarded" : ", no text response"})${detail}`);
1723
1753
  }
1724
1754
  let response = collectedResponse;
1755
+ const outputTruncated = terminalStopReason === "length";
1725
1756
  if (outputTruncated) {
1726
1757
  task.confidenceSignals.push({ type: "output_truncated", message: "final response hit the provider's output token limit" });
1727
1758
  response += "\n\n[Incomplete report: the subagent's final response was cut off by the provider's output token limit (stopReason=length). The items above may be a partial list \u2014 rerun the task with a narrower scope, or ask for the remaining items.]";
@@ -1744,7 +1775,7 @@ ${formatSkillsForPrompt(deps.skills ?? [])}`;
1744
1775
  };
1745
1776
  task.parentHandoffRequired = isParentHandoffRequired(task) || outputTruncated;
1746
1777
  task.completedAt = Date.now();
1747
- reportProgress({ message: `[${task.name}] Completed (${durationMs}ms, ${toolCalls} tools)`, increment: 100 });
1778
+ report({ message: `[${task.name}] Completed (${durationMs}ms, ${toolCalls} tools)`, increment: 100 });
1748
1779
  } catch (error) {
1749
1780
  const errorMessage = error instanceof Error ? error.message : String(error);
1750
1781
  const stackTrace = error instanceof Error ? error.stack : void 0;
@@ -1759,7 +1790,11 @@ ${formatSkillsForPrompt(deps.skills ?? [])}`;
1759
1790
  task.uncertainty = "high";
1760
1791
  task.parentHandoffRequired = isParentHandoffRequired(task);
1761
1792
  task.completedAt = Date.now();
1762
- reportProgress({ message: `[${task.name}] Failed: ${errorMessage.slice(0, 100)}`, increment: 100 });
1793
+ report({ message: `[${task.name}] Failed: ${errorMessage.slice(0, 100)}`, increment: 100 });
1794
+ } finally {
1795
+ if (heartbeat) {
1796
+ clearInterval(heartbeat);
1797
+ }
1763
1798
  }
1764
1799
  }
1765
1800
  function buildParallelResult(tasks, totalDuration) {
@@ -7866,7 +7901,7 @@ var AskUserMultiParamsSchema = Type.Object({
7866
7901
  }))
7867
7902
  });
7868
7903
  function buildUnsupportedResult(error) {
7869
- const message = error instanceof InteractionUnavailableError ? error.message : error instanceof Error ? error.message : String(error);
7904
+ const message = error instanceof InteractionUnavailableError ? `${error.message}. This host has no interactive UI registered (headless or print run) \u2014 do not retry ask_user tools here; proceed without asking, or state the question as plain text.` : error instanceof Error ? error.message : String(error);
7870
7905
  return {
7871
7906
  content: [{ type: "text", text: `Interaction unavailable: ${message}` }],
7872
7907
  details: { unsupported: true, error: message },
@@ -8082,6 +8117,13 @@ function createAskUserCapability() {
8082
8117
  parameters: AskUserMultiParamsSchema,
8083
8118
  async execute(toolCallIdOrArgs, maybeArgs) {
8084
8119
  try {
8120
+ if (!hasInteractionHandler()) {
8121
+ return {
8122
+ content: [{ type: "text", text: "Interaction unavailable: this host has no interactive UI registered (headless or print run). Do not retry ask_user_multi here \u2014 proceed without asking, or state the question as plain text." }],
8123
+ details: { unsupported: true, error: "no interaction handler" },
8124
+ isError: true
8125
+ };
8126
+ }
8085
8127
  const args = typeof toolCallIdOrArgs === "string" && maybeArgs !== void 0 ? maybeArgs : toolCallIdOrArgs;
8086
8128
  const normalized = normalizeAskUserArgs(args);
8087
8129
  if ("error" in normalized) {
@@ -15367,9 +15409,18 @@ var webResearchSchema = Type.Object({
15367
15409
  description: "Maximum credible sources to fetch and cite. Defaults to 3."
15368
15410
  }))
15369
15411
  });
15412
+ function httpStatusFromFailureText(text) {
15413
+ const match2 = /\bHTTP\s?(\d{3})\b/i.exec(text);
15414
+ return match2 ? Number(match2[1]) : void 0;
15415
+ }
15370
15416
  var DEFAULT_WEB_RESEARCH_SEARCH_ATTEMPT_TIMEOUT_MS = 45e3;
15371
- var DEFAULT_WEB_RESEARCH_FETCH_ATTEMPT_TIMEOUT_MS = 3e4;
15417
+ var DEFAULT_WEB_RESEARCH_FETCH_ATTEMPT_TIMEOUT_MS = 45e3;
15372
15418
  var DEFAULT_WEB_RESEARCH_BROWSER_ATTEMPT_TIMEOUT_MS = 45e3;
15419
+ function isTransientFetchFailure(category, text) {
15420
+ if (category === "timeout" || category === "provider_error") return true;
15421
+ if (category === "http_error") return /\bHTTP\s?(5\d\d|429)\b/i.test(text);
15422
+ return false;
15423
+ }
15373
15424
  function isRecord5(value) {
15374
15425
  return !!value && typeof value === "object" && !Array.isArray(value);
15375
15426
  }
@@ -16107,36 +16158,48 @@ function createSharedWebResearchTool(deps) {
16107
16158
  return true;
16108
16159
  });
16109
16160
  const fetchScoredSource = async (scored) => {
16110
- const startedAt = Date.now();
16111
16161
  onUpdate?.({
16112
16162
  content: [{ type: "text", text: `Fetching source: ${scored.source.url}` }],
16113
16163
  details: { query, actualQueries: [...new Set(actualQueries)], sources: dedupedSources, fetchedSources, providerAttempts, attempts, qualityScore: qualityScore(fetchedSources, scoredSources), warnings, browserRequiredSources }
16114
16164
  });
16115
- const fetchResult = await runWithDeadline(
16116
- (childSignal) => webFetchTool.execute("web_research_fetch", { url: scored.source.url }, childSignal),
16117
- fetchAttemptTimeoutMs,
16118
- `web_research fetch attempt timed out after ${Math.ceil(fetchAttemptTimeoutMs / 1e3)} seconds`,
16119
- signal
16120
- ).catch((error) => ({
16121
- content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
16122
- details: {
16123
- url: scored.source.url,
16124
- sourceUrl: scored.source.url,
16125
- durationMs: Date.now() - startedAt,
16126
- failureCategory: "timeout"
16127
- },
16128
- isError: true
16129
- }));
16165
+ const fetchOnce = async () => {
16166
+ const startedAt = Date.now();
16167
+ const result = await runWithDeadline(
16168
+ (childSignal) => webFetchTool.execute("web_research_fetch", { url: scored.source.url }, childSignal),
16169
+ fetchAttemptTimeoutMs,
16170
+ `web_research fetch attempt timed out after ${Math.ceil(fetchAttemptTimeoutMs / 1e3)} seconds`,
16171
+ signal
16172
+ ).catch((error) => ({
16173
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
16174
+ details: {
16175
+ url: scored.source.url,
16176
+ sourceUrl: scored.source.url,
16177
+ durationMs: Date.now() - startedAt,
16178
+ failureCategory: "timeout"
16179
+ },
16180
+ isError: true
16181
+ }));
16182
+ return { result, startedAt, endedAt: Date.now() };
16183
+ };
16184
+ let attempt = await fetchOnce();
16185
+ let attemptTotalMs = attempt.endedAt - attempt.startedAt;
16186
+ if (attempt.result.isError && isTransientFetchFailure(contentDetails(attempt.result).failureCategory, textFromResult(attempt.result))) {
16187
+ attempts.push({ phase: "fetch", url: scored.source.url, status: "failed", failureCategory: contentDetails(attempt.result).failureCategory, failureStatus: httpStatusFromFailureText(textFromResult(attempt.result)), durationMs: attemptTotalMs });
16188
+ attempt = await fetchOnce();
16189
+ attemptTotalMs += attempt.endedAt - attempt.startedAt;
16190
+ }
16191
+ const fetchResult = attempt.result;
16130
16192
  const details2 = contentDetails(fetchResult);
16131
16193
  const text = textFromResult(fetchResult);
16132
- fetchDurationMs += Date.now() - startedAt;
16133
- sourceReadDurations.push(Date.now() - startedAt);
16194
+ fetchDurationMs += attemptTotalMs;
16195
+ sourceReadDurations.push(attemptTotalMs);
16134
16196
  attempts.push({
16135
16197
  phase: "fetch",
16136
16198
  url: scored.source.url,
16137
16199
  status: fetchResult.isError ? "failed" : "completed",
16138
16200
  failureCategory: details2.failureCategory,
16139
- durationMs: Date.now() - startedAt
16201
+ ...fetchResult.isError ? { failureStatus: httpStatusFromFailureText(text) } : {},
16202
+ durationMs: attemptTotalMs
16140
16203
  });
16141
16204
  if (details2.requiresBrowser) {
16142
16205
  const browserEntry = {
@@ -16243,9 +16306,12 @@ function createSharedWebResearchTool(deps) {
16243
16306
  }
16244
16307
  };
16245
16308
  if (fetchedSources.length === 0) {
16309
+ const fetchFailures = details.attempts.filter((attempt) => attempt.phase === "fetch" && attempt.status === "failed").slice(0, 6);
16310
+ const failureSummary = fetchFailures.length ? `
16311
+ Fetch failures: ${fetchFailures.map((attempt) => `${attempt.url} (${attempt.failureCategory || "fetch_failed"}${attempt.failureStatus !== void 0 ? ` ${attempt.failureStatus}` : ""})`).join("; ")}` : "";
16246
16312
  const reason = browserRequiredSources.length ? "web_research found candidate sources, but they require browser-rendered reading and no host browser reader completed." : "web_research could not fetch any credible source for this query.";
16247
16313
  return {
16248
- content: [{ type: "text", text: `${reason}
16314
+ content: [{ type: "text", text: `${reason}${failureSummary}
16249
16315
 
16250
16316
  Queries tried: ${details.actualQueries.join("; ") || query}` }],
16251
16317
  details,