@prestyj/agent 5.29.1 → 5.30.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.cts CHANGED
@@ -80,6 +80,11 @@ declare function buildStreamRuleReminder(rules: readonly StreamRule[]): Message;
80
80
  interface StructuredToolResult {
81
81
  content: ToolResultContent;
82
82
  details?: unknown;
83
+ /** End the run after persisting this result, without another model call or
84
+ * draining steering/follow-ups. Use a sequential tool to also prevent later
85
+ * calls in the same batch from running (e.g. a pending plan-review handoff).
86
+ * Host control metadata only: never serialized into provider tool results. */
87
+ endRun?: boolean;
83
88
  }
84
89
  type ToolExecuteResult = string | StructuredToolResult;
85
90
  interface ToolContext {
package/dist/index.d.ts CHANGED
@@ -80,6 +80,11 @@ declare function buildStreamRuleReminder(rules: readonly StreamRule[]): Message;
80
80
  interface StructuredToolResult {
81
81
  content: ToolResultContent;
82
82
  details?: unknown;
83
+ /** End the run after persisting this result, without another model call or
84
+ * draining steering/follow-ups. Use a sequential tool to also prevent later
85
+ * calls in the same batch from running (e.g. a pending plan-review handoff).
86
+ * Host control metadata only: never serialized into provider tool results. */
87
+ endRun?: boolean;
83
88
  }
84
89
  type ToolExecuteResult = string | StructuredToolResult;
85
90
  interface ToolContext {
package/dist/index.js CHANGED
@@ -1584,6 +1584,7 @@ async function* agentLoop(messages, options) {
1584
1584
  }
1585
1585
  messages.push({ role: "tool", content: executionResult.toolResults });
1586
1586
  yield { type: "checkpoint", turn };
1587
+ if (executionResult.endRun) break;
1587
1588
  const toolsAborted = executionResult.aborted;
1588
1589
  if (fatalToolArgumentError) {
1589
1590
  if (fatalToolArgumentRecoverable && !toolArgumentAutoContinueUsed) {
@@ -1720,6 +1721,7 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
1720
1721
  let resultContent;
1721
1722
  let details;
1722
1723
  let isError = false;
1724
+ let endRun = false;
1723
1725
  let invalidArgAttempt;
1724
1726
  const tool = options.toolMap.get(toolCall.name);
1725
1727
  if (tool) {
@@ -1778,6 +1780,7 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
1778
1780
  hardSignals.length === 1 ? toolTimeout : AbortSignal.any(hardSignals)
1779
1781
  );
1780
1782
  const normalized = normalizeToolResult(raw);
1783
+ endRun = normalized.endRun === true;
1781
1784
  resultContent = redactValue(normalized.content, toolRedactionOptions());
1782
1785
  details = redactValue(normalized.details, toolRedactionOptions());
1783
1786
  if (options.transformToolResult) {
@@ -1849,11 +1852,12 @@ ${hints}` : "") + "\nRe-issue the call with each field as the correct type.";
1849
1852
  durationMs,
1850
1853
  ...invalidArgAttempt === void 0 ? {} : { invalidArgAttempt }
1851
1854
  });
1852
- return { toolCallId: toolCall.id, content: resultContent, isError };
1855
+ return { toolCallId: toolCall.id, content: resultContent, isError, endRun: endRun && !isError };
1853
1856
  }
1854
1857
  function createPreemptTracker(options, eventStream, state, resultsById, dispatchedIds) {
1855
1858
  const running = /* @__PURE__ */ new Map();
1856
1859
  let graceTimer;
1860
+ let endRun = false;
1857
1861
  const preemptSignal = options.preemptSignal;
1858
1862
  const abandon = () => {
1859
1863
  graceTimer = void 0;
@@ -1877,7 +1881,7 @@ function createPreemptTracker(options, eventStream, state, resultsById, dispatch
1877
1881
  preemptSignal?.addEventListener("abort", onPreempt, { once: true });
1878
1882
  return {
1879
1883
  async run(toolCall) {
1880
- if (options.preemptSignal?.aborted) return;
1884
+ if (endRun || options.preemptSignal?.aborted) return;
1881
1885
  dispatchedIds.add(toolCall.id);
1882
1886
  const interruptible = isInterruptibleTool(options.toolMap.get(toolCall.name), toolCall.name);
1883
1887
  running.set(toolCall.id, { toolCall, interruptible, startedAt: Date.now() });
@@ -1889,15 +1893,15 @@ function createPreemptTracker(options, eventStream, state, resultsById, dispatch
1889
1893
  running.delete(toolCall.id);
1890
1894
  if (resultsById.has(toolCall.id)) return;
1891
1895
  const alreadyMarked = typeof record.content === "string" ? record.content.startsWith(STEER_INTERRUPTED_TEXT) : record.content[0]?.type === "text" && record.content[0].text.startsWith(STEER_INTERRUPTED_TEXT);
1892
- resultsById.set(
1893
- toolCall.id,
1894
- interruptible && preemptSignal?.aborted && !alreadyMarked ? markSteerInterrupted(record) : record
1895
- );
1896
+ const result = interruptible && preemptSignal?.aborted && !alreadyMarked ? markSteerInterrupted(record) : record;
1897
+ resultsById.set(toolCall.id, result);
1898
+ if (result.endRun && !result.isError) endRun = true;
1896
1899
  if (preemptSignal?.aborted && graceTimer === void 0 && running.size === 0) {
1897
1900
  eventStream.close();
1898
1901
  }
1899
1902
  },
1900
1903
  preempted: () => preemptSignal?.aborted === true,
1904
+ endRun: () => endRun,
1901
1905
  dispose: () => {
1902
1906
  if (graceTimer !== void 0) clearTimeout(graceTimer);
1903
1907
  preemptSignal?.removeEventListener("abort", onPreempt);
@@ -1932,7 +1936,7 @@ async function* executeToolCallsMixed(toolCalls, initialToolResults, options) {
1932
1936
  void (async () => {
1933
1937
  try {
1934
1938
  for (const phase of phases) {
1935
- if (options.signal?.aborted || options.preemptSignal?.aborted) break;
1939
+ if (options.signal?.aborted || options.preemptSignal?.aborted || tracker.endRun()) break;
1936
1940
  if (phase.sequential) {
1937
1941
  const signature = JSON.stringify([
1938
1942
  phase.sequential.name,
@@ -1970,7 +1974,12 @@ async function* executeToolCallsMixed(toolCalls, initialToolResults, options) {
1970
1974
  const toolResults = buildToolResults(initialToolResults, toolCalls, resultsById, dispatchedIds);
1971
1975
  capToolResults(toolResults, options.maxToolResultChars);
1972
1976
  capTurnToolResults(toolResults, options.maxTurnToolResultChars);
1973
- return { toolResults, aborted, preempted: !aborted && tracker.preempted() };
1977
+ return {
1978
+ toolResults,
1979
+ aborted,
1980
+ preempted: !aborted && tracker.preempted(),
1981
+ endRun: tracker.endRun()
1982
+ };
1974
1983
  }
1975
1984
  async function* executeToolCallsParallel(toolCalls, initialToolResults, options) {
1976
1985
  const eventStream = new EventStream();
@@ -2004,7 +2013,12 @@ async function* executeToolCallsParallel(toolCalls, initialToolResults, options)
2004
2013
  const toolResults = buildToolResults(initialToolResults, toolCalls, resultsById, dispatchedIds);
2005
2014
  capToolResults(toolResults, options.maxToolResultChars);
2006
2015
  capTurnToolResults(toolResults, options.maxTurnToolResultChars);
2007
- return { toolResults, aborted, preempted: !aborted && tracker.preempted() };
2016
+ return {
2017
+ toolResults,
2018
+ aborted,
2019
+ preempted: !aborted && tracker.preempted(),
2020
+ endRun: tracker.endRun()
2021
+ };
2008
2022
  }
2009
2023
  function cancelledBeforeStartText(name) {
2010
2024
  return `\`${name}\` was cancelled before it started, so it had no effect. Safe to retry.`;