@prestyj/agent 4.12.1 → 4.13.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.
package/dist/index.js CHANGED
@@ -264,23 +264,25 @@ async function* agentLoop(messages, options) {
264
264
  while (turn < maxTurns) {
265
265
  options.signal?.throwIfAborted();
266
266
  turn++;
267
- let msgChars = 0;
268
- for (const m of messages) {
269
- if (typeof m.content === "string") msgChars += m.content.length;
270
- else if (Array.isArray(m.content)) {
271
- for (const p of m.content) {
272
- if ("text" in p && typeof p.text === "string") msgChars += p.text.length;
273
- if ("content" in p && typeof p.content === "string") msgChars += p.content.length;
267
+ if (_diagFn) {
268
+ let msgChars = 0;
269
+ for (const m of messages) {
270
+ if (typeof m.content === "string") msgChars += m.content.length;
271
+ else if (Array.isArray(m.content)) {
272
+ for (const p of m.content) {
273
+ if ("text" in p && typeof p.text === "string") msgChars += p.text.length;
274
+ if ("content" in p && typeof p.content === "string") msgChars += p.content.length;
275
+ }
274
276
  }
275
277
  }
278
+ diag("turn_start", {
279
+ turn,
280
+ messages: messages.length,
281
+ chars: msgChars,
282
+ provider: options.provider,
283
+ model: options.model
284
+ });
276
285
  }
277
- diag("turn_start", {
278
- turn,
279
- messages: messages.length,
280
- chars: msgChars,
281
- provider: options.provider,
282
- model: options.model
283
- });
284
286
  if (firstTurn && options.getSteeringMessages) {
285
287
  const steering = await options.getSteeringMessages();
286
288
  if (steering && steering.length > 0) {
@@ -822,7 +824,7 @@ async function* agentLoop(messages, options) {
822
824
  const hasSequentialToolCall = toolCalls.some(
823
825
  (toolCall) => toolMap.get(toolCall.name)?.executionMode === "sequential"
824
826
  );
825
- const executionResult = hasSequentialToolCall ? yield* executeToolCallsSequential(toolCalls, toolResults, executionOptions) : yield* executeToolCallsParallel(toolCalls, toolResults, executionOptions);
827
+ const executionResult = hasSequentialToolCall ? yield* executeToolCallsMixed(toolCalls, toolResults, executionOptions) : yield* executeToolCallsParallel(toolCalls, toolResults, executionOptions);
826
828
  messages.push({ role: "tool", content: executionResult.toolResults });
827
829
  const toolsAborted = executionResult.aborted;
828
830
  if (fatalToolArgumentError) {
@@ -882,8 +884,10 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
882
884
  } else {
883
885
  try {
884
886
  const parsed = tool.parameters.parse(toolCall.args);
887
+ const callerSignal = options.signal;
888
+ const toolTimeout = AbortSignal.timeout(3e5);
885
889
  const ctx = {
886
- signal: options.signal ?? AbortSignal.timeout(3e5),
890
+ signal: callerSignal ? AbortSignal.any([callerSignal, toolTimeout]) : toolTimeout,
887
891
  toolCallId: toolCall.id,
888
892
  onUpdate: (update) => {
889
893
  pushEvent({
@@ -935,22 +939,59 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
935
939
  });
936
940
  return { toolCallId: toolCall.id, content: resultContent, isError };
937
941
  }
938
- async function* executeToolCallsSequential(toolCalls, initialToolResults, options) {
942
+ async function* executeToolCallsMixed(toolCalls, initialToolResults, options) {
939
943
  const eventStream = new EventStream();
940
944
  const state = { finalized: false };
941
945
  const resultsById = /* @__PURE__ */ new Map();
942
946
  const abortHandler = () => eventStream.abort(new Error("aborted"));
943
947
  options.signal?.addEventListener("abort", abortHandler, { once: true });
948
+ const phases = [];
949
+ let currentParallel = [];
950
+ for (const toolCall of toolCalls) {
951
+ const isSequential = options.toolMap.get(toolCall.name)?.executionMode === "sequential";
952
+ if (isSequential) {
953
+ if (currentParallel.length > 0) {
954
+ phases.push({ parallel: currentParallel, sequential: null });
955
+ currentParallel = [];
956
+ }
957
+ phases.push({ parallel: [], sequential: toolCall });
958
+ } else {
959
+ currentParallel.push(toolCall);
960
+ }
961
+ }
962
+ if (currentParallel.length > 0) {
963
+ phases.push({ parallel: currentParallel, sequential: null });
964
+ }
944
965
  void (async () => {
945
966
  try {
946
- for (const toolCall of toolCalls) {
967
+ for (const phase of phases) {
947
968
  if (options.signal?.aborted) break;
948
- const record = await executeSingleToolCall(
949
- toolCall,
950
- options,
951
- (event) => pushToolEvent(eventStream, state, event)
952
- );
953
- resultsById.set(record.toolCallId, record);
969
+ if (phase.sequential) {
970
+ const record = await executeSingleToolCall(
971
+ phase.sequential,
972
+ options,
973
+ (event) => pushToolEvent(eventStream, state, event)
974
+ );
975
+ resultsById.set(record.toolCallId, record);
976
+ } else if (phase.parallel.length === 1) {
977
+ const record = await executeSingleToolCall(
978
+ phase.parallel[0],
979
+ options,
980
+ (event) => pushToolEvent(eventStream, state, event)
981
+ );
982
+ resultsById.set(record.toolCallId, record);
983
+ } else {
984
+ await Promise.all(
985
+ phase.parallel.map(async (toolCall) => {
986
+ const record = await executeSingleToolCall(
987
+ toolCall,
988
+ options,
989
+ (event) => pushToolEvent(eventStream, state, event)
990
+ );
991
+ resultsById.set(record.toolCallId, record);
992
+ })
993
+ );
994
+ }
954
995
  }
955
996
  if (!state.finalized) eventStream.close();
956
997
  } catch (err) {