@prestyj/agent 4.12.1 → 4.14.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.js CHANGED
@@ -258,29 +258,34 @@ async function* agentLoop(messages, options) {
258
258
  const STREAM_THINKING_IDLE_TIMEOUT_MS = 3e5;
259
259
  const STREAM_THINKING_HARD_TIMEOUT_MS = 6e5;
260
260
  const NON_STREAMING_HARD_TIMEOUT_MS = 3e5;
261
+ const isSakana = options.provider === "sakana";
262
+ const firstEventTimeoutMs = isSakana ? STREAM_THINKING_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
263
+ const initialHardTimeoutMs = isSakana ? STREAM_THINKING_HARD_TIMEOUT_MS : STREAM_HARD_TIMEOUT_MS;
261
264
  const MAX_TOOLCALL_DELTA_CHARS = 1e6;
262
265
  const MAX_TOOLCALL_DELTA_EVENTS = 2e4;
263
266
  try {
264
267
  while (turn < maxTurns) {
265
268
  options.signal?.throwIfAborted();
266
269
  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;
270
+ if (_diagFn) {
271
+ let msgChars = 0;
272
+ for (const m of messages) {
273
+ if (typeof m.content === "string") msgChars += m.content.length;
274
+ else if (Array.isArray(m.content)) {
275
+ for (const p of m.content) {
276
+ if ("text" in p && typeof p.text === "string") msgChars += p.text.length;
277
+ if ("content" in p && typeof p.content === "string") msgChars += p.content.length;
278
+ }
274
279
  }
275
280
  }
281
+ diag("turn_start", {
282
+ turn,
283
+ messages: messages.length,
284
+ chars: msgChars,
285
+ provider: options.provider,
286
+ model: options.model
287
+ });
276
288
  }
277
- diag("turn_start", {
278
- turn,
279
- messages: messages.length,
280
- chars: msgChars,
281
- provider: options.provider,
282
- model: options.model
283
- });
284
289
  if (firstTurn && options.getSteeringMessages) {
285
290
  const steering = await options.getSteeringMessages();
286
291
  if (steering && steering.length > 0) {
@@ -327,7 +332,7 @@ async function* agentLoop(messages, options) {
327
332
  const resetIdleTimer = () => {
328
333
  if (useNonStreamingFallback) return;
329
334
  if (idleTimer) clearTimeout(idleTimer);
330
- const timeoutMs = hasReceivedEvent ? STREAM_IDLE_TIMEOUT_MS : hasReceivedThinking ? STREAM_THINKING_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
335
+ const timeoutMs = hasReceivedEvent ? STREAM_IDLE_TIMEOUT_MS : hasReceivedThinking ? STREAM_THINKING_IDLE_TIMEOUT_MS : firstEventTimeoutMs;
331
336
  idleTimer = setTimeout(() => {
332
337
  diag("idle_timeout_fired", {
333
338
  events: streamEventCount,
@@ -341,7 +346,7 @@ async function* agentLoop(messages, options) {
341
346
  streamController.abort();
342
347
  }, timeoutMs);
343
348
  };
344
- let hardTimeoutMs = useNonStreamingFallback ? NON_STREAMING_HARD_TIMEOUT_MS : STREAM_HARD_TIMEOUT_MS;
349
+ let hardTimeoutMs = useNonStreamingFallback ? NON_STREAMING_HARD_TIMEOUT_MS : initialHardTimeoutMs;
345
350
  hardTimer = setTimeout(() => {
346
351
  diag("hard_timeout_fired", {
347
352
  events: typeof streamEventCount !== "undefined" ? streamEventCount : 0,
@@ -822,7 +827,7 @@ async function* agentLoop(messages, options) {
822
827
  const hasSequentialToolCall = toolCalls.some(
823
828
  (toolCall) => toolMap.get(toolCall.name)?.executionMode === "sequential"
824
829
  );
825
- const executionResult = hasSequentialToolCall ? yield* executeToolCallsSequential(toolCalls, toolResults, executionOptions) : yield* executeToolCallsParallel(toolCalls, toolResults, executionOptions);
830
+ const executionResult = hasSequentialToolCall ? yield* executeToolCallsMixed(toolCalls, toolResults, executionOptions) : yield* executeToolCallsParallel(toolCalls, toolResults, executionOptions);
826
831
  messages.push({ role: "tool", content: executionResult.toolResults });
827
832
  const toolsAborted = executionResult.aborted;
828
833
  if (fatalToolArgumentError) {
@@ -882,8 +887,10 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
882
887
  } else {
883
888
  try {
884
889
  const parsed = tool.parameters.parse(toolCall.args);
890
+ const callerSignal = options.signal;
891
+ const toolTimeout = AbortSignal.timeout(3e5);
885
892
  const ctx = {
886
- signal: options.signal ?? AbortSignal.timeout(3e5),
893
+ signal: callerSignal ? AbortSignal.any([callerSignal, toolTimeout]) : toolTimeout,
887
894
  toolCallId: toolCall.id,
888
895
  onUpdate: (update) => {
889
896
  pushEvent({
@@ -935,22 +942,59 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
935
942
  });
936
943
  return { toolCallId: toolCall.id, content: resultContent, isError };
937
944
  }
938
- async function* executeToolCallsSequential(toolCalls, initialToolResults, options) {
945
+ async function* executeToolCallsMixed(toolCalls, initialToolResults, options) {
939
946
  const eventStream = new EventStream();
940
947
  const state = { finalized: false };
941
948
  const resultsById = /* @__PURE__ */ new Map();
942
949
  const abortHandler = () => eventStream.abort(new Error("aborted"));
943
950
  options.signal?.addEventListener("abort", abortHandler, { once: true });
951
+ const phases = [];
952
+ let currentParallel = [];
953
+ for (const toolCall of toolCalls) {
954
+ const isSequential = options.toolMap.get(toolCall.name)?.executionMode === "sequential";
955
+ if (isSequential) {
956
+ if (currentParallel.length > 0) {
957
+ phases.push({ parallel: currentParallel, sequential: null });
958
+ currentParallel = [];
959
+ }
960
+ phases.push({ parallel: [], sequential: toolCall });
961
+ } else {
962
+ currentParallel.push(toolCall);
963
+ }
964
+ }
965
+ if (currentParallel.length > 0) {
966
+ phases.push({ parallel: currentParallel, sequential: null });
967
+ }
944
968
  void (async () => {
945
969
  try {
946
- for (const toolCall of toolCalls) {
970
+ for (const phase of phases) {
947
971
  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);
972
+ if (phase.sequential) {
973
+ const record = await executeSingleToolCall(
974
+ phase.sequential,
975
+ options,
976
+ (event) => pushToolEvent(eventStream, state, event)
977
+ );
978
+ resultsById.set(record.toolCallId, record);
979
+ } else if (phase.parallel.length === 1) {
980
+ const record = await executeSingleToolCall(
981
+ phase.parallel[0],
982
+ options,
983
+ (event) => pushToolEvent(eventStream, state, event)
984
+ );
985
+ resultsById.set(record.toolCallId, record);
986
+ } else {
987
+ await Promise.all(
988
+ phase.parallel.map(async (toolCall) => {
989
+ const record = await executeSingleToolCall(
990
+ toolCall,
991
+ options,
992
+ (event) => pushToolEvent(eventStream, state, event)
993
+ );
994
+ resultsById.set(record.toolCallId, record);
995
+ })
996
+ );
997
+ }
954
998
  }
955
999
  if (!state.finalized) eventStream.close();
956
1000
  } catch (err) {