@kenkaiiii/gg-agent 4.3.199 → 4.3.201

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
@@ -711,136 +711,23 @@ async function* agentLoop(messages, options) {
711
711
  toolCalls.push(tc);
712
712
  }
713
713
  }
714
- const eventStream = new EventStream();
715
714
  let fatalToolArgumentError = null;
716
- const executions = toolCalls.map(async (toolCall) => {
717
- const startTime = Date.now();
718
- eventStream.push({
719
- type: "tool_call_start",
720
- toolCallId: toolCall.id,
721
- name: toolCall.name,
722
- args: toolCall.args
723
- });
724
- let resultContent;
725
- let details;
726
- let isError = false;
727
- const tool = toolMap.get(toolCall.name);
728
- if (!tool) {
729
- resultContent = `Unknown tool: ${toolCall.name}`;
730
- isError = true;
731
- } else {
732
- try {
733
- const parsed = tool.parameters.parse(toolCall.args);
734
- const ctx = {
735
- signal: options.signal ?? AbortSignal.timeout(3e5),
736
- toolCallId: toolCall.id,
737
- onUpdate: (update) => {
738
- eventStream.push({
739
- type: "tool_call_update",
740
- toolCallId: toolCall.id,
741
- update
742
- });
743
- }
744
- };
745
- const raw = await tool.execute(parsed, ctx);
746
- const normalized = normalizeToolResult(raw);
747
- resultContent = normalized.content;
748
- details = normalized.details;
749
- for (const key of invalidToolArgumentCounts.keys()) {
750
- if (key.startsWith(`${toolCall.name}:`)) invalidToolArgumentCounts.delete(key);
751
- }
752
- } catch (err) {
753
- isError = true;
754
- if (err instanceof ZodError) {
755
- const prettyError = prettifyError(err);
756
- const failureKey = `${toolCall.name}:${prettyError}`;
757
- const failureCount = (invalidToolArgumentCounts.get(failureKey) ?? 0) + 1;
758
- invalidToolArgumentCounts.set(failureKey, failureCount);
759
- resultContent = `Invalid arguments for tool \`${toolCall.name}\`:
760
- ` + prettyError + "\nRe-issue the call with each field as the correct type.";
761
- if (failureCount >= 3) {
762
- fatalToolArgumentError = new Error(
763
- `The model repeatedly issued invalid arguments for tool \`${toolCall.name}\`. This is usually an upstream model/tool-calling bug. Your conversation is preserved; send another message or switch models to continue.`
764
- );
765
- }
766
- } else {
767
- resultContent = err instanceof Error ? err.message : String(err);
768
- }
769
- }
770
- }
771
- const durationMs = Date.now() - startTime;
772
- eventStream.push({
773
- type: "tool_call_end",
774
- toolCallId: toolCall.id,
775
- result: toolResultPreview(resultContent),
776
- details,
777
- isError,
778
- durationMs
779
- });
780
- return { toolCallId: toolCall.id, content: resultContent, isError };
781
- });
782
- const abortHandler = () => eventStream.abort(new Error("aborted"));
783
- options.signal?.addEventListener("abort", abortHandler, { once: true });
784
- let toolResultsFinalized = false;
785
- Promise.all(executions).then((results) => {
786
- if (toolResultsFinalized) return;
787
- const resultsMap = new Map(results.map((r) => [r.toolCallId, r]));
788
- for (const tc of toolCalls) {
789
- const r = resultsMap.get(tc.id);
790
- toolResults.push({
791
- type: "tool_result",
792
- toolCallId: tc.id,
793
- content: r.content,
794
- isError: r.isError || void 0
795
- });
796
- }
797
- eventStream.close();
798
- }).catch((err) => eventStream.abort(err instanceof Error ? err : new Error(String(err))));
799
- let toolsAborted = false;
800
- try {
801
- for await (const event of eventStream) {
802
- yield event;
803
- }
804
- } catch (err) {
805
- if (isAbortError(err) || options.signal?.aborted) {
806
- toolsAborted = true;
807
- } else {
808
- throw err;
809
- }
810
- } finally {
811
- options.signal?.removeEventListener("abort", abortHandler);
812
- toolResultsFinalized = true;
813
- const resolvedIds = new Set(toolResults.map((r) => r.toolCallId));
814
- for (const tc of toolCalls) {
815
- if (!resolvedIds.has(tc.id)) {
816
- toolResults.push({
817
- type: "tool_result",
818
- toolCallId: tc.id,
819
- content: "Tool execution was aborted.",
820
- isError: true
821
- });
822
- }
823
- }
824
- if (options.maxToolResultChars) {
825
- const HARD_MAX = 4e5;
826
- const max = Math.min(options.maxToolResultChars, HARD_MAX);
827
- for (const tr of toolResults) {
828
- if (typeof tr.content === "string" && tr.content.length > max) {
829
- const headChars = Math.floor(max * 0.7);
830
- const tailChars = max - headChars;
831
- const head = tr.content.slice(0, headChars);
832
- const tail = tr.content.slice(-tailChars);
833
- const omitted = tr.content.length - headChars - tailChars;
834
- tr.content = head + `
835
-
836
- [... ${omitted} characters omitted ...]
837
-
838
- ` + tail;
839
- }
840
- }
841
- }
842
- messages.push({ role: "tool", content: toolResults });
843
- }
715
+ const markFatalToolArgumentError = (error) => {
716
+ fatalToolArgumentError = error;
717
+ };
718
+ const executionOptions = {
719
+ signal: options.signal,
720
+ maxToolResultChars: options.maxToolResultChars,
721
+ toolMap,
722
+ invalidToolArgumentCounts,
723
+ markFatalToolArgumentError
724
+ };
725
+ const hasSequentialToolCall = toolCalls.some(
726
+ (toolCall) => toolMap.get(toolCall.name)?.executionMode === "sequential"
727
+ );
728
+ const executionResult = hasSequentialToolCall ? yield* executeToolCallsSequential(toolCalls, toolResults, executionOptions) : yield* executeToolCallsParallel(toolCalls, toolResults, executionOptions);
729
+ messages.push({ role: "tool", content: executionResult.toolResults });
730
+ const toolsAborted = executionResult.aborted;
844
731
  if (fatalToolArgumentError) {
845
732
  yield { type: "error", error: fatalToolArgumentError };
846
733
  break;
@@ -877,6 +764,197 @@ async function* agentLoop(messages, options) {
877
764
  totalUsage: { ...totalUsage }
878
765
  };
879
766
  }
767
+ function pushToolEvent(eventStream, state, event) {
768
+ if (!state.finalized) eventStream.push(event);
769
+ }
770
+ async function executeSingleToolCall(toolCall, options, pushEvent) {
771
+ const startTime = Date.now();
772
+ pushEvent({
773
+ type: "tool_call_start",
774
+ toolCallId: toolCall.id,
775
+ name: toolCall.name,
776
+ args: toolCall.args
777
+ });
778
+ let resultContent;
779
+ let details;
780
+ let isError = false;
781
+ const tool = options.toolMap.get(toolCall.name);
782
+ if (!tool) {
783
+ resultContent = `Unknown tool: ${toolCall.name}`;
784
+ isError = true;
785
+ } else {
786
+ try {
787
+ const parsed = tool.parameters.parse(toolCall.args);
788
+ const ctx = {
789
+ signal: options.signal ?? AbortSignal.timeout(3e5),
790
+ toolCallId: toolCall.id,
791
+ onUpdate: (update) => {
792
+ pushEvent({
793
+ type: "tool_call_update",
794
+ toolCallId: toolCall.id,
795
+ update
796
+ });
797
+ }
798
+ };
799
+ const raw = await tool.execute(parsed, ctx);
800
+ const normalized = normalizeToolResult(raw);
801
+ resultContent = normalized.content;
802
+ details = normalized.details;
803
+ for (const key of options.invalidToolArgumentCounts.keys()) {
804
+ if (key.startsWith(`${toolCall.name}:`)) options.invalidToolArgumentCounts.delete(key);
805
+ }
806
+ } catch (err) {
807
+ isError = true;
808
+ if (err instanceof ZodError) {
809
+ const prettyError = prettifyError(err);
810
+ const failureKey = `${toolCall.name}:${prettyError}`;
811
+ const failureCount = (options.invalidToolArgumentCounts.get(failureKey) ?? 0) + 1;
812
+ options.invalidToolArgumentCounts.set(failureKey, failureCount);
813
+ resultContent = `Invalid arguments for tool \`${toolCall.name}\`:
814
+ ` + prettyError + "\nRe-issue the call with each field as the correct type.";
815
+ if (failureCount >= 3) {
816
+ options.markFatalToolArgumentError(
817
+ new Error(
818
+ `The model repeatedly issued invalid arguments for tool \`${toolCall.name}\`. This is usually an upstream model/tool-calling bug. Your conversation is preserved; send another message or switch models to continue.`
819
+ )
820
+ );
821
+ }
822
+ } else {
823
+ resultContent = err instanceof Error ? err.message : String(err);
824
+ }
825
+ }
826
+ }
827
+ const durationMs = Date.now() - startTime;
828
+ pushEvent({
829
+ type: "tool_call_end",
830
+ toolCallId: toolCall.id,
831
+ result: toolResultPreview(resultContent),
832
+ details,
833
+ isError,
834
+ durationMs
835
+ });
836
+ return { toolCallId: toolCall.id, content: resultContent, isError };
837
+ }
838
+ async function* executeToolCallsSequential(toolCalls, initialToolResults, options) {
839
+ const eventStream = new EventStream();
840
+ const state = { finalized: false };
841
+ const resultsById = /* @__PURE__ */ new Map();
842
+ const abortHandler = () => eventStream.abort(new Error("aborted"));
843
+ options.signal?.addEventListener("abort", abortHandler, { once: true });
844
+ void (async () => {
845
+ try {
846
+ for (const toolCall of toolCalls) {
847
+ if (options.signal?.aborted) break;
848
+ const record = await executeSingleToolCall(
849
+ toolCall,
850
+ options,
851
+ (event) => pushToolEvent(eventStream, state, event)
852
+ );
853
+ resultsById.set(record.toolCallId, record);
854
+ }
855
+ if (!state.finalized) eventStream.close();
856
+ } catch (err) {
857
+ if (!state.finalized) eventStream.abort(err instanceof Error ? err : new Error(String(err)));
858
+ }
859
+ })();
860
+ let aborted = false;
861
+ try {
862
+ for await (const event of eventStream) {
863
+ yield event;
864
+ }
865
+ } catch (err) {
866
+ if (isAbortError(err) || options.signal?.aborted) {
867
+ aborted = true;
868
+ } else {
869
+ throw err;
870
+ }
871
+ } finally {
872
+ options.signal?.removeEventListener("abort", abortHandler);
873
+ state.finalized = true;
874
+ }
875
+ const toolResults = buildToolResults(initialToolResults, toolCalls, resultsById);
876
+ capToolResults(toolResults, options.maxToolResultChars);
877
+ return { toolResults, aborted };
878
+ }
879
+ async function* executeToolCallsParallel(toolCalls, initialToolResults, options) {
880
+ const eventStream = new EventStream();
881
+ const state = { finalized: false };
882
+ const resultsById = /* @__PURE__ */ new Map();
883
+ const abortHandler = () => eventStream.abort(new Error("aborted"));
884
+ options.signal?.addEventListener("abort", abortHandler, { once: true });
885
+ Promise.all(
886
+ toolCalls.map(async (toolCall) => {
887
+ const record = await executeSingleToolCall(
888
+ toolCall,
889
+ options,
890
+ (event) => pushToolEvent(eventStream, state, event)
891
+ );
892
+ resultsById.set(record.toolCallId, record);
893
+ })
894
+ ).then(() => {
895
+ if (!state.finalized) eventStream.close();
896
+ }).catch((err) => {
897
+ if (!state.finalized) eventStream.abort(err instanceof Error ? err : new Error(String(err)));
898
+ });
899
+ let aborted = false;
900
+ try {
901
+ for await (const event of eventStream) {
902
+ yield event;
903
+ }
904
+ } catch (err) {
905
+ if (isAbortError(err) || options.signal?.aborted) {
906
+ aborted = true;
907
+ } else {
908
+ throw err;
909
+ }
910
+ } finally {
911
+ options.signal?.removeEventListener("abort", abortHandler);
912
+ state.finalized = true;
913
+ }
914
+ const toolResults = buildToolResults(initialToolResults, toolCalls, resultsById);
915
+ capToolResults(toolResults, options.maxToolResultChars);
916
+ return { toolResults, aborted };
917
+ }
918
+ function buildToolResults(initialToolResults, toolCalls, resultsById) {
919
+ const toolResults = [...initialToolResults];
920
+ for (const toolCall of toolCalls) {
921
+ const result = resultsById.get(toolCall.id);
922
+ if (result) {
923
+ toolResults.push({
924
+ type: "tool_result",
925
+ toolCallId: toolCall.id,
926
+ content: result.content,
927
+ isError: result.isError || void 0
928
+ });
929
+ } else {
930
+ toolResults.push({
931
+ type: "tool_result",
932
+ toolCallId: toolCall.id,
933
+ content: "Tool execution was aborted.",
934
+ isError: true
935
+ });
936
+ }
937
+ }
938
+ return toolResults;
939
+ }
940
+ function capToolResults(toolResults, maxToolResultChars) {
941
+ if (!maxToolResultChars) return;
942
+ const hardMax = 4e5;
943
+ const max = Math.min(maxToolResultChars, hardMax);
944
+ for (const toolResult of toolResults) {
945
+ if (typeof toolResult.content !== "string" || toolResult.content.length <= max) continue;
946
+ const headChars = Math.floor(max * 0.7);
947
+ const tailChars = max - headChars;
948
+ const head = toolResult.content.slice(0, headChars);
949
+ const tail = toolResult.content.slice(-tailChars);
950
+ const omitted = toolResult.content.length - headChars - tailChars;
951
+ toolResult.content = head + `
952
+
953
+ [... ${omitted} characters omitted ...]
954
+
955
+ ` + tail;
956
+ }
957
+ }
880
958
  function normalizeToolResult(raw) {
881
959
  return typeof raw === "string" ? { content: raw } : raw;
882
960
  }