wave-agent-sdk 0.14.3 → 0.14.4
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/builtin/skills/settings/SKILLS.md +3 -0
- package/dist/managers/aiManager.d.ts +3 -0
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +107 -82
- package/dist/managers/forkedAgentManager.d.ts +1 -0
- package/dist/managers/forkedAgentManager.d.ts.map +1 -1
- package/dist/managers/forkedAgentManager.js +1 -0
- package/dist/managers/subagentManager.d.ts +1 -0
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +1 -0
- package/dist/services/autoMemoryService.d.ts.map +1 -1
- package/dist/services/autoMemoryService.js +1 -0
- package/dist/utils/constants.d.ts +2 -2
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +2 -2
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +16 -8
- package/dist/utils/stringUtils.d.ts +8 -0
- package/dist/utils/stringUtils.d.ts.map +1 -1
- package/dist/utils/stringUtils.js +45 -0
- package/package.json +1 -1
- package/src/managers/aiManager.ts +141 -110
- package/src/managers/forkedAgentManager.ts +3 -0
- package/src/managers/subagentManager.ts +2 -0
- package/src/services/autoMemoryService.ts +1 -0
- package/src/utils/constants.ts +2 -2
- package/src/utils/convertMessagesForAPI.ts +15 -8
- package/src/utils/stringUtils.ts +43 -0
|
@@ -42,6 +42,9 @@ When this skill is invoked, follow these steps:
|
|
|
42
42
|
- `allowed-tools`: (Optional) List of tools the skill can use.
|
|
43
43
|
- `context: fork`: (Optional) Run the skill in a separate subagent.
|
|
44
44
|
- `agent`: (Optional) Specify the subagent type (default: `general-purpose`).
|
|
45
|
+
- `disable-model-invocation`: (Optional, default: `false`) Set to `true` to hide the skill from the AI's available skills list. The skill can still be invoked by users via slash commands.
|
|
46
|
+
- `user-invocable`: (Optional, default: `true`) Set to `false` to hide the skill from the `/` slash command menu. The AI can still invoke it unless `disable-model-invocation` is also set.
|
|
47
|
+
- `model`: (Optional) Override the AI model used for skill execution (e.g., `"gpt-4o"`, `"o3-mini"`).
|
|
45
48
|
|
|
46
49
|
## Skill Locations
|
|
47
50
|
|
|
@@ -14,6 +14,8 @@ export interface AIManagerOptions {
|
|
|
14
14
|
stream?: boolean;
|
|
15
15
|
/**Optional model override (e.g. for subagents) */
|
|
16
16
|
modelOverride?: string;
|
|
17
|
+
/**Optional max turns limit to prevent runaway recursion (e.g. for auto-memory extraction) */
|
|
18
|
+
maxTurns?: number;
|
|
17
19
|
}
|
|
18
20
|
export declare class AIManager {
|
|
19
21
|
private container;
|
|
@@ -29,6 +31,7 @@ export declare class AIManager {
|
|
|
29
31
|
private modelOverride?;
|
|
30
32
|
private _onCwdChange?;
|
|
31
33
|
private consecutiveCompactionFailures;
|
|
34
|
+
private readonly maxTurns?;
|
|
32
35
|
constructor(container: Container, options: AIManagerOptions);
|
|
33
36
|
private get toolManager();
|
|
34
37
|
private get messageManager();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiManager.d.ts","sourceRoot":"","sources":["../../src/managers/aiManager.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,KAAK,EAGN,MAAM,mBAAmB,CAAC;AAY3B,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"aiManager.d.ts","sourceRoot":"","sources":["../../src/managers/aiManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { parseTaskNotificationXml } from "../utils/notificationXml.js";
|
|
|
5
5
|
import { calculateComprehensiveTotalTokens } from "../utils/tokenCalculation.js";
|
|
6
6
|
import * as fs from "node:fs/promises";
|
|
7
7
|
import { buildSystemPrompt } from "../prompts/index.js";
|
|
8
|
+
import { recoverTruncatedJson } from "../utils/stringUtils.js";
|
|
8
9
|
import { logger } from "../utils/globalLogger.js";
|
|
9
10
|
export class AIManager {
|
|
10
11
|
// Service overrides
|
|
@@ -23,6 +24,7 @@ export class AIManager {
|
|
|
23
24
|
this.callbacks = options.callbacks ?? {};
|
|
24
25
|
this.modelOverride = options.modelOverride;
|
|
25
26
|
this._onCwdChange = options.callbacks?.onCwdChange; // Initialize onCwdChange
|
|
27
|
+
this.maxTurns = options.maxTurns;
|
|
26
28
|
}
|
|
27
29
|
get toolManager() {
|
|
28
30
|
return this.container.get("ToolManager");
|
|
@@ -584,35 +586,45 @@ export class AIManager {
|
|
|
584
586
|
const toolName = functionToolCall.function?.name || "";
|
|
585
587
|
// Safely parse tool parameters, handle tools without parameters
|
|
586
588
|
let toolArgs = {};
|
|
589
|
+
let jsonRecovered = false;
|
|
587
590
|
const argsString = functionToolCall.function?.arguments?.trim();
|
|
588
591
|
if (!argsString || argsString === "") {
|
|
589
592
|
// Tool without parameters, use empty object
|
|
590
593
|
toolArgs = {};
|
|
591
594
|
}
|
|
592
595
|
else {
|
|
596
|
+
let recoveredArgs = argsString;
|
|
593
597
|
try {
|
|
594
598
|
toolArgs = JSON.parse(argsString);
|
|
595
599
|
}
|
|
596
|
-
catch
|
|
597
|
-
//
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
600
|
+
catch {
|
|
601
|
+
// Attempt to recover truncated JSON (e.g., missing closing braces)
|
|
602
|
+
recoveredArgs = recoverTruncatedJson(argsString);
|
|
603
|
+
try {
|
|
604
|
+
toolArgs = JSON.parse(recoveredArgs);
|
|
605
|
+
jsonRecovered = true;
|
|
606
|
+
logger.warn(`Recovered truncated JSON for tool "${toolName}"`);
|
|
607
|
+
}
|
|
608
|
+
catch (parseError) {
|
|
609
|
+
let errorMessage = `Failed to parse tool arguments`;
|
|
610
|
+
if (result.finish_reason === "length") {
|
|
611
|
+
errorMessage +=
|
|
612
|
+
" (output truncated, please reduce your output)";
|
|
613
|
+
}
|
|
614
|
+
logger?.error(errorMessage, parseError);
|
|
615
|
+
this.messageManager.updateToolBlock({
|
|
616
|
+
id: toolId,
|
|
617
|
+
parameters: argsString,
|
|
618
|
+
result: errorMessage,
|
|
619
|
+
success: false,
|
|
620
|
+
error: errorMessage,
|
|
621
|
+
stage: "end",
|
|
622
|
+
name: toolName,
|
|
623
|
+
compactParams: "",
|
|
624
|
+
timestamp: Date.now(),
|
|
625
|
+
});
|
|
626
|
+
return;
|
|
602
627
|
}
|
|
603
|
-
logger?.error(errorMessage, parseError);
|
|
604
|
-
this.messageManager.updateToolBlock({
|
|
605
|
-
id: toolId,
|
|
606
|
-
parameters: argsString,
|
|
607
|
-
result: errorMessage,
|
|
608
|
-
success: false,
|
|
609
|
-
error: errorMessage,
|
|
610
|
-
stage: "end",
|
|
611
|
-
name: toolName,
|
|
612
|
-
compactParams: "",
|
|
613
|
-
timestamp: Date.now(),
|
|
614
|
-
});
|
|
615
|
-
return;
|
|
616
628
|
}
|
|
617
629
|
}
|
|
618
630
|
const compactParams = this.generateCompactParams(toolName, toolArgs);
|
|
@@ -681,12 +693,18 @@ export class AIManager {
|
|
|
681
693
|
};
|
|
682
694
|
// Execute tool
|
|
683
695
|
const toolResult = await this.toolManager.execute(functionToolCall.function?.name || "", toolArgs, context);
|
|
696
|
+
// Build result content, adding truncation warning if JSON was recovered
|
|
697
|
+
let toolResultContent = toolResult.content ||
|
|
698
|
+
(toolResult.error ? `Error: ${toolResult.error}` : "");
|
|
699
|
+
if (jsonRecovered) {
|
|
700
|
+
toolResultContent +=
|
|
701
|
+
"\n\n⚠️ Tool arguments were truncated (likely exceeded max output tokens). Please reduce your output or split into multiple tool calls.";
|
|
702
|
+
}
|
|
684
703
|
// Update message state - tool execution completed
|
|
685
704
|
this.messageManager.updateToolBlock({
|
|
686
705
|
id: toolId,
|
|
687
706
|
parameters: argsString,
|
|
688
|
-
result:
|
|
689
|
-
(toolResult.error ? `Error: ${toolResult.error}` : ""),
|
|
707
|
+
result: toolResultContent,
|
|
690
708
|
success: toolResult.success,
|
|
691
709
|
error: toolResult.error,
|
|
692
710
|
stage: "end",
|
|
@@ -727,75 +745,82 @@ export class AIManager {
|
|
|
727
745
|
this.messageManager.finalizeStreamingBlocks();
|
|
728
746
|
// Check if there are tool operations or response was truncated, if so automatically initiate next AI service call
|
|
729
747
|
if (toolCalls.length > 0 || result.finish_reason === "length") {
|
|
730
|
-
//
|
|
731
|
-
if (this.
|
|
732
|
-
|
|
733
|
-
if (snapshots.length > 0) {
|
|
734
|
-
this.messageManager.addFileHistoryBlock(snapshots);
|
|
735
|
-
}
|
|
748
|
+
// Check maxTurns limit before recursing
|
|
749
|
+
if (this.maxTurns && recursionDepth + 1 >= this.maxTurns) {
|
|
750
|
+
logger?.debug(`Max turns (${this.maxTurns}) reached, stopping recursion.`);
|
|
736
751
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
if (hasBackgrounded) {
|
|
745
|
-
logger?.info("Some tools were manually backgrounded, stopping recursion.");
|
|
746
|
-
}
|
|
747
|
-
else if (!isCurrentlyAborted) {
|
|
748
|
-
// If response was truncated, add a hidden continuation message
|
|
749
|
-
if (result.finish_reason === "length") {
|
|
750
|
-
this.messageManager.addUserMessage({
|
|
751
|
-
content: "Output token limit hit. Resume directly — no apology, no recap of what you were doing. Pick up mid-thought if that is where the cut happened. Break remaining work into smaller pieces.",
|
|
752
|
-
isMeta: true,
|
|
753
|
-
});
|
|
752
|
+
else {
|
|
753
|
+
// Record committed snapshots to message history
|
|
754
|
+
if (this.reversionManager) {
|
|
755
|
+
const snapshots = this.reversionManager.getAndClearCommittedSnapshots();
|
|
756
|
+
if (snapshots.length > 0) {
|
|
757
|
+
this.messageManager.addFileHistoryBlock(snapshots);
|
|
758
|
+
}
|
|
754
759
|
}
|
|
755
|
-
//
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
760
|
+
// Check interruption status
|
|
761
|
+
const isCurrentlyAborted = abortController.signal.aborted ||
|
|
762
|
+
toolAbortController.signal.aborted;
|
|
763
|
+
// Check if all tools were manually backgrounded
|
|
764
|
+
const lastMessage = this.messageManager.getMessages()[this.messageManager.getMessages().length - 1];
|
|
765
|
+
const toolBlocks = lastMessage?.blocks.filter((block) => block.type === "tool") || [];
|
|
766
|
+
const hasBackgrounded = toolBlocks.length > 0 &&
|
|
767
|
+
toolBlocks.some((block) => block.isManuallyBackgrounded);
|
|
768
|
+
if (hasBackgrounded) {
|
|
769
|
+
logger?.info("Some tools were manually backgrounded, stopping recursion.");
|
|
770
|
+
}
|
|
771
|
+
else if (!isCurrentlyAborted) {
|
|
772
|
+
// If response was truncated, add a hidden continuation message
|
|
773
|
+
if (result.finish_reason === "length") {
|
|
774
|
+
this.messageManager.addUserMessage({
|
|
775
|
+
content: "Output token limit hit. Resume directly — no apology, no recap of what you were doing. Pick up mid-thought if that is where the cut happened. Break remaining work into smaller pieces.",
|
|
776
|
+
isMeta: true,
|
|
777
|
+
});
|
|
768
778
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
779
|
+
// Duplicate Tool Call Detection
|
|
780
|
+
if (toolCalls.length > 0) {
|
|
781
|
+
const messages = this.messageManager.getMessages();
|
|
782
|
+
// Find the most recent assistant message BEFORE the current one that has tool blocks
|
|
783
|
+
// The current assistant message is messages[messages.length - 1]
|
|
784
|
+
let previousAssistantWithTools;
|
|
785
|
+
for (let i = messages.length - 2; i >= 0; i--) {
|
|
786
|
+
const msg = messages[i];
|
|
787
|
+
if (msg.role === "assistant" &&
|
|
788
|
+
msg.blocks.some((b) => b.type === "tool")) {
|
|
789
|
+
previousAssistantWithTools = msg;
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
if (previousAssistantWithTools) {
|
|
794
|
+
const previousToolBlocks = previousAssistantWithTools.blocks.filter((b) => b.type === "tool");
|
|
795
|
+
for (const currentToolCall of toolCalls) {
|
|
796
|
+
const currentName = currentToolCall.function?.name;
|
|
797
|
+
const currentArgs = currentToolCall.function?.arguments;
|
|
798
|
+
const isDuplicate = previousToolBlocks.some((prevBlock) => prevBlock.name === currentName &&
|
|
799
|
+
prevBlock.parameters === currentArgs);
|
|
800
|
+
if (isDuplicate && currentName) {
|
|
801
|
+
const toolId = currentToolCall.id;
|
|
802
|
+
const lastMessage = messages[messages.length - 1];
|
|
803
|
+
const toolBlock = lastMessage.blocks.find((b) => b.type === "tool" && b.id === toolId);
|
|
804
|
+
if (toolBlock) {
|
|
805
|
+
const warning = `\n\nNote: You just called this tool with the same arguments in the previous turn. Please ensure you are not in a loop and consider if you need to change your approach.`;
|
|
806
|
+
this.messageManager.updateToolBlock({
|
|
807
|
+
id: toolId,
|
|
808
|
+
result: (toolBlock.result || "") + warning,
|
|
809
|
+
stage: "end",
|
|
810
|
+
});
|
|
811
|
+
}
|
|
787
812
|
}
|
|
788
813
|
}
|
|
789
814
|
}
|
|
790
815
|
}
|
|
816
|
+
// Recursively call AI service, increment recursion depth, and pass same configuration
|
|
817
|
+
await this.sendAIMessage({
|
|
818
|
+
recursionDepth: recursionDepth + 1,
|
|
819
|
+
model,
|
|
820
|
+
allowedRules,
|
|
821
|
+
maxTokens,
|
|
822
|
+
});
|
|
791
823
|
}
|
|
792
|
-
// Recursively call AI service, increment recursion depth, and pass same configuration
|
|
793
|
-
await this.sendAIMessage({
|
|
794
|
-
recursionDepth: recursionDepth + 1,
|
|
795
|
-
model,
|
|
796
|
-
allowedRules,
|
|
797
|
-
maxTokens,
|
|
798
|
-
});
|
|
799
824
|
}
|
|
800
825
|
}
|
|
801
826
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forkedAgentManager.d.ts","sourceRoot":"","sources":["../../src/managers/forkedAgentManager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC;IAC3B,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;CAC5C;AAED,MAAM,WAAW,2BAA2B;IAC1C,yBAAyB,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnE;AAED,qBAAa,kBAAkB;IAK3B,OAAO,CAAC,SAAS;IAJnB,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,SAAS,CAA8B;gBAGrC,SAAS,EAAE,SAAS,EAC5B,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,2BAA2B,CAAA;KAAO;IAK3D,OAAO,KAAK,eAAe,GAE1B;IAED;;;OAGG;IACG,cAAc,CAClB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,OAAO,EAAE,EACnB,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,sBAAsB,CAAC,EAAE,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"forkedAgentManager.d.ts","sourceRoot":"","sources":["../../src/managers/forkedAgentManager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC;IAC3B,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;CAC5C;AAED,MAAM,WAAW,2BAA2B;IAC1C,yBAAyB,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnE;AAED,qBAAa,kBAAkB;IAK3B,OAAO,CAAC,SAAS;IAJnB,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,SAAS,CAA8B;gBAGrC,SAAS,EAAE,SAAS,EAC5B,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,2BAA2B,CAAA;KAAO;IAK3D,OAAO,KAAK,eAAe,GAE1B;IAED;;;OAGG;IACG,cAAc,CAClB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,OAAO,EAAE,EACnB,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,sBAAsB,CAAC,EAAE,cAAc,CAAC;QACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,EACD,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC;YA0BJ,WAAW;IA6EzB;;OAEG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAazB;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,cAAc,IAAI,gBAAgB,EAAE;IAIpC,OAAO,CAAC,YAAY;CAKrB"}
|
|
@@ -48,6 +48,7 @@ export class ForkedAgentManager {
|
|
|
48
48
|
allowedTools: parameters.allowedTools,
|
|
49
49
|
model: parameters.model,
|
|
50
50
|
permissionModeOverride: parameters.permissionModeOverride,
|
|
51
|
+
maxTurns: parameters.maxTurns,
|
|
51
52
|
}, false);
|
|
52
53
|
// Pre-load the message manager with conversation history
|
|
53
54
|
instance.messageManager.setMessages(messages);
|
|
@@ -93,6 +93,7 @@ export declare class SubagentManager {
|
|
|
93
93
|
model?: string;
|
|
94
94
|
stream?: boolean;
|
|
95
95
|
permissionModeOverride?: PermissionMode;
|
|
96
|
+
maxTurns?: number;
|
|
96
97
|
}, runInBackground?: boolean, onUpdate?: () => void): Promise<SubagentInstance>;
|
|
97
98
|
/**
|
|
98
99
|
* Execute agent using subagent instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagentManager.d.ts","sourceRoot":"","sources":["../../src/managers/subagentManager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAS/C,OAAO,EACL,iBAAiB,EACjB,KAAK,0BAA0B,EAChC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAG9D,MAAM,WAAW,wBAAwB;IAEvC,gDAAgD;IAChD,0BAA0B,CAAC,EAAE,CAC3B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,iBAAiB,KACtB,IAAI,CAAC;IACV,wDAAwD;IACxD,+BAA+B,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/D,0DAA0D;IAC1D,iCAAiC,CAAC,EAAE,CAClC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,KAChB,IAAI,CAAC;IACV,4DAA4D;IAC5D,mCAAmC,CAAC,EAAE,CACpC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,KAChB,IAAI,CAAC;IACV,oDAAoD;IACpD,0BAA0B,CAAC,EAAE,CAC3B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,0BAA0B,KAC/B,IAAI,CAAC;IACV,8CAA8C;IAC9C,wBAAwB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAC7E,yDAAyD;IACzD,iCAAiC,CAAC,EAAE,CAClC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,KACX,IAAI,CAAC;CACX;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,qBAAqB,CAAC;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,cAAc,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,CAAC;IACtE,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACtC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,0BAA0B,CAAwC;IAC1E,OAAO,CAAC,oBAAoB,CAAwC;IAEpE,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAC,CAA2B;IAC7C,OAAO,CAAC,YAAY,CAAC,CAAyB;IAC9C,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,MAAM,CAAU;gBAEZ,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,sBAAsB;IAQjE,OAAO,KAAK,oBAAoB,GAE/B;IAED;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BjC;;OAEG;IACH,OAAO,CAAC,8BAA8B;IAWtC;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAY5D;;OAEG;IACH,iBAAiB,IAAI,qBAAqB,EAAE;IAS5C;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM;IAa/B;;;OAGG;IACH,oBAAoB,CAClB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,qBAAqB,EAAE,GAC9B,IAAI;IAgCP;;OAEG;IACG,cAAc,CAClB,aAAa,EAAE,qBAAqB,EACpC,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,sBAAsB,CAAC,EAAE,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"subagentManager.d.ts","sourceRoot":"","sources":["../../src/managers/subagentManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -203,6 +203,7 @@ export class SubagentManager {
|
|
|
203
203
|
subagentType: parameters.subagent_type, // Pass subagent type for hook context
|
|
204
204
|
modelOverride: parameters.model || configuration.model, // Pass model override
|
|
205
205
|
stream: parameters.stream ?? this.stream, // Pass streaming mode flag
|
|
206
|
+
maxTurns: parameters.maxTurns, // Pass maxTurns limit
|
|
206
207
|
callbacks: {
|
|
207
208
|
onUsageAdded: this.onUsageAdded,
|
|
208
209
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoMemoryService.d.ts","sourceRoot":"","sources":["../../src/services/autoMemoryService.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAUlD;;;GAGG;AACH,qBAAa,iBAAiB;IAIhB,OAAO,CAAC,SAAS;IAH7B,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,wBAAwB,CAAa;gBAEzB,SAAS,EAAE,SAAS;IAExC,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,kBAAkB,GAE7B;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,oBAAoB,GAE/B;IAED;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqE/C;;OAEG;YACW,aAAa;
|
|
1
|
+
{"version":3,"file":"autoMemoryService.d.ts","sourceRoot":"","sources":["../../src/services/autoMemoryService.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAUlD;;;GAGG;AACH,qBAAa,iBAAiB;IAIhB,OAAO,CAAC,SAAS;IAH7B,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,wBAAwB,CAAa;gBAEzB,SAAS,EAAE,SAAS;IAExC,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,kBAAkB,GAE7B;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,oBAAoB,GAE/B;IAED;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqE/C;;OAEG;YACW,aAAa;CA4D5B"}
|
|
@@ -128,6 +128,7 @@ export class AutoMemoryService {
|
|
|
128
128
|
],
|
|
129
129
|
model: "fastModel", // Use fast model for background tasks to reduce latency and cost
|
|
130
130
|
permissionModeOverride: "dontAsk", // Auto-deny out-of-scope writes without prompting user
|
|
131
|
+
maxTurns: 5, // Limit turns to prevent verification rabbit-holes
|
|
131
132
|
}, `${prompt}\n\nThe memory directory for this project is: ${memoryDir}`);
|
|
132
133
|
logger.debug("Auto-memory extraction started in background.");
|
|
133
134
|
}
|
|
@@ -21,6 +21,6 @@ export declare const USER_MEMORY_FILE: string;
|
|
|
21
21
|
/**
|
|
22
22
|
* AI related constants
|
|
23
23
|
*/
|
|
24
|
-
export declare const DEFAULT_WAVE_MAX_INPUT_TOKENS =
|
|
25
|
-
export declare const DEFAULT_WAVE_MAX_OUTPUT_TOKENS =
|
|
24
|
+
export declare const DEFAULT_WAVE_MAX_INPUT_TOKENS = 128000;
|
|
25
|
+
export declare const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 16384;
|
|
26
26
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAmC,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAA6C,CAAC;AAE9E;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAA0C,CAAC;AAE3E;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AAEvE;;GAEG;AACH,eAAO,MAAM,6BAA6B,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAmC,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAA6C,CAAC;AAE9E;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAA0C,CAAC;AAE3E;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AAEvE;;GAEG;AACH,eAAO,MAAM,6BAA6B,SAAS,CAAC;AACpD,eAAO,MAAM,8BAA8B,QAAQ,CAAC"}
|
package/dist/utils/constants.js
CHANGED
|
@@ -23,5 +23,5 @@ export const USER_MEMORY_FILE = path.join(DATA_DIRECTORY, "AGENTS.md");
|
|
|
23
23
|
/**
|
|
24
24
|
* AI related constants
|
|
25
25
|
*/
|
|
26
|
-
export const DEFAULT_WAVE_MAX_INPUT_TOKENS =
|
|
27
|
-
export const DEFAULT_WAVE_MAX_OUTPUT_TOKENS =
|
|
26
|
+
export const DEFAULT_WAVE_MAX_INPUT_TOKENS = 128000; // Default token limit
|
|
27
|
+
export const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 16384; // Default output token limit
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertMessagesForAPI.d.ts","sourceRoot":"","sources":["../../src/utils/convertMessagesForAPI.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAKjD,OAAO,EAEL,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"convertMessagesForAPI.d.ts","sourceRoot":"","sources":["../../src/utils/convertMessagesForAPI.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAKjD,OAAO,EAEL,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAiC7B;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,OAAO,EAAE,GAClB,0BAA0B,EAAE,CAsP9B"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { convertImageToBase64 } from "./messageOperations.js";
|
|
2
2
|
import { taskNotificationToXml } from "./notificationXml.js";
|
|
3
|
-
import { stripAnsiColors } from "./stringUtils.js";
|
|
3
|
+
import { recoverTruncatedJson, stripAnsiColors } from "./stringUtils.js";
|
|
4
4
|
import { logger } from "./globalLogger.js";
|
|
5
5
|
/**
|
|
6
|
-
* Safely handle tool call parameters, ensuring a legal JSON string is returned
|
|
6
|
+
* Safely handle tool call parameters, ensuring a legal JSON string is returned.
|
|
7
|
+
* Attempts to recover truncated JSON (e.g., missing closing braces).
|
|
7
8
|
* @param args Tool call parameters
|
|
8
9
|
* @returns Legal JSON string
|
|
9
10
|
*/
|
|
@@ -16,12 +17,19 @@ function safeToolArguments(args) {
|
|
|
16
17
|
JSON.parse(args);
|
|
17
18
|
return args;
|
|
18
19
|
}
|
|
19
|
-
catch
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
catch {
|
|
21
|
+
// Attempt to recover truncated JSON
|
|
22
|
+
const recovered = recoverTruncatedJson(args);
|
|
23
|
+
try {
|
|
24
|
+
JSON.parse(recovered);
|
|
25
|
+
return recovered;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Truly malformed JSON — return sanitized fallback
|
|
29
|
+
return JSON.stringify({
|
|
30
|
+
invalid_arguments: args,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
25
33
|
}
|
|
26
34
|
}
|
|
27
35
|
/**
|
|
@@ -23,6 +23,14 @@ export declare const stripAnsiColors: (text: string) => string;
|
|
|
23
23
|
* @returns Formatted line number prefix
|
|
24
24
|
*/
|
|
25
25
|
export declare function formatLineNumberPrefix(lineNumber: number): string;
|
|
26
|
+
/**
|
|
27
|
+
* Attempt to recover truncated JSON (e.g., missing closing braces due to max tokens).
|
|
28
|
+
* Tracks brace depth and only recovers if there are unclosed `{` braces.
|
|
29
|
+
* Will NOT recover if there are unclosed `[` brackets (can't guess the content).
|
|
30
|
+
* @param jsonStr Potentially truncated JSON string
|
|
31
|
+
* @returns Recovered JSON string, or the original if unrecoverable
|
|
32
|
+
*/
|
|
33
|
+
export declare function recoverTruncatedJson(jsonStr: string): string;
|
|
26
34
|
/**
|
|
27
35
|
* Efficiently get the last N lines of a string without splitting the whole string.
|
|
28
36
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stringUtils.d.ts","sourceRoot":"","sources":["../../src/utils/stringUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgC/D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,GACpB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwBxB;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAK9C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAehE"}
|
|
1
|
+
{"version":3,"file":"stringUtils.d.ts","sourceRoot":"","sources":["../../src/utils/stringUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgC/D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,GACpB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwBxB;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAK9C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkC5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAehE"}
|
|
@@ -77,6 +77,51 @@ export const stripAnsiColors = (text) => {
|
|
|
77
77
|
export function formatLineNumberPrefix(lineNumber) {
|
|
78
78
|
return `${lineNumber.toString().padStart(6)}\t`;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Attempt to recover truncated JSON (e.g., missing closing braces due to max tokens).
|
|
82
|
+
* Tracks brace depth and only recovers if there are unclosed `{` braces.
|
|
83
|
+
* Will NOT recover if there are unclosed `[` brackets (can't guess the content).
|
|
84
|
+
* @param jsonStr Potentially truncated JSON string
|
|
85
|
+
* @returns Recovered JSON string, or the original if unrecoverable
|
|
86
|
+
*/
|
|
87
|
+
export function recoverTruncatedJson(jsonStr) {
|
|
88
|
+
let braceDepth = 0;
|
|
89
|
+
let bracketDepth = 0;
|
|
90
|
+
let inString = false;
|
|
91
|
+
let escaped = false;
|
|
92
|
+
for (const ch of jsonStr) {
|
|
93
|
+
if (escaped) {
|
|
94
|
+
escaped = false;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (ch === "\\" && inString) {
|
|
98
|
+
escaped = true;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (ch === '"') {
|
|
102
|
+
inString = !inString;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!inString) {
|
|
106
|
+
if (ch === "{")
|
|
107
|
+
braceDepth++;
|
|
108
|
+
if (ch === "}")
|
|
109
|
+
braceDepth--;
|
|
110
|
+
if (ch === "[")
|
|
111
|
+
bracketDepth++;
|
|
112
|
+
if (ch === "]")
|
|
113
|
+
bracketDepth--;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Build recovery suffix
|
|
117
|
+
let suffix = "";
|
|
118
|
+
if (inString)
|
|
119
|
+
suffix += '"'; // Close unclosed string
|
|
120
|
+
if (braceDepth > 0 && bracketDepth === 0) {
|
|
121
|
+
suffix += "}".repeat(braceDepth);
|
|
122
|
+
}
|
|
123
|
+
return suffix ? jsonStr + suffix : jsonStr;
|
|
124
|
+
}
|
|
80
125
|
/**
|
|
81
126
|
* Efficiently get the last N lines of a string without splitting the whole string.
|
|
82
127
|
*/
|
package/package.json
CHANGED
|
@@ -24,6 +24,7 @@ import type { SubagentManager } from "./subagentManager.js";
|
|
|
24
24
|
import type { SkillManager } from "./skillManager.js";
|
|
25
25
|
import { buildSystemPrompt } from "../prompts/index.js";
|
|
26
26
|
import { Container } from "../utils/container.js";
|
|
27
|
+
import { recoverTruncatedJson } from "../utils/stringUtils.js";
|
|
27
28
|
import { ConfigurationService } from "../services/configurationService.js";
|
|
28
29
|
import type { NotificationQueue } from "./notificationQueue.js";
|
|
29
30
|
|
|
@@ -44,6 +45,8 @@ export interface AIManagerOptions {
|
|
|
44
45
|
stream?: boolean;
|
|
45
46
|
/**Optional model override (e.g. for subagents) */
|
|
46
47
|
modelOverride?: string;
|
|
48
|
+
/**Optional max turns limit to prevent runaway recursion (e.g. for auto-memory extraction) */
|
|
49
|
+
maxTurns?: number;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
export class AIManager {
|
|
@@ -59,6 +62,7 @@ export class AIManager {
|
|
|
59
62
|
private modelOverride?: string;
|
|
60
63
|
private _onCwdChange?: (newCwd: string) => void; // Store callback for CWD changes
|
|
61
64
|
private consecutiveCompactionFailures: number = 0;
|
|
65
|
+
private readonly maxTurns?: number;
|
|
62
66
|
|
|
63
67
|
// Service overrides
|
|
64
68
|
constructor(
|
|
@@ -73,6 +77,7 @@ export class AIManager {
|
|
|
73
77
|
this.callbacks = options.callbacks ?? {};
|
|
74
78
|
this.modelOverride = options.modelOverride;
|
|
75
79
|
this._onCwdChange = options.callbacks?.onCwdChange; // Initialize onCwdChange
|
|
80
|
+
this.maxTurns = options.maxTurns;
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
private get toolManager(): ToolManager {
|
|
@@ -814,34 +819,45 @@ export class AIManager {
|
|
|
814
819
|
const toolName = functionToolCall.function?.name || "";
|
|
815
820
|
// Safely parse tool parameters, handle tools without parameters
|
|
816
821
|
let toolArgs: Record<string, unknown> = {};
|
|
822
|
+
let jsonRecovered = false;
|
|
817
823
|
const argsString = functionToolCall.function?.arguments?.trim();
|
|
818
824
|
|
|
819
825
|
if (!argsString || argsString === "") {
|
|
820
826
|
// Tool without parameters, use empty object
|
|
821
827
|
toolArgs = {};
|
|
822
828
|
} else {
|
|
829
|
+
let recoveredArgs = argsString;
|
|
823
830
|
try {
|
|
824
831
|
toolArgs = JSON.parse(argsString);
|
|
825
|
-
} catch
|
|
826
|
-
//
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
832
|
+
} catch {
|
|
833
|
+
// Attempt to recover truncated JSON (e.g., missing closing braces)
|
|
834
|
+
recoveredArgs = recoverTruncatedJson(argsString);
|
|
835
|
+
try {
|
|
836
|
+
toolArgs = JSON.parse(recoveredArgs);
|
|
837
|
+
jsonRecovered = true;
|
|
838
|
+
logger.warn(
|
|
839
|
+
`Recovered truncated JSON for tool "${toolName}"`,
|
|
840
|
+
);
|
|
841
|
+
} catch (parseError) {
|
|
842
|
+
let errorMessage = `Failed to parse tool arguments`;
|
|
843
|
+
if (result.finish_reason === "length") {
|
|
844
|
+
errorMessage +=
|
|
845
|
+
" (output truncated, please reduce your output)";
|
|
846
|
+
}
|
|
847
|
+
logger?.error(errorMessage, parseError);
|
|
848
|
+
this.messageManager.updateToolBlock({
|
|
849
|
+
id: toolId,
|
|
850
|
+
parameters: argsString,
|
|
851
|
+
result: errorMessage,
|
|
852
|
+
success: false,
|
|
853
|
+
error: errorMessage,
|
|
854
|
+
stage: "end",
|
|
855
|
+
name: toolName,
|
|
856
|
+
compactParams: "",
|
|
857
|
+
timestamp: Date.now(),
|
|
858
|
+
});
|
|
859
|
+
return;
|
|
831
860
|
}
|
|
832
|
-
logger?.error(errorMessage, parseError);
|
|
833
|
-
this.messageManager.updateToolBlock({
|
|
834
|
-
id: toolId,
|
|
835
|
-
parameters: argsString,
|
|
836
|
-
result: errorMessage,
|
|
837
|
-
success: false,
|
|
838
|
-
error: errorMessage,
|
|
839
|
-
stage: "end",
|
|
840
|
-
name: toolName,
|
|
841
|
-
compactParams: "",
|
|
842
|
-
timestamp: Date.now(),
|
|
843
|
-
});
|
|
844
|
-
return;
|
|
845
861
|
}
|
|
846
862
|
}
|
|
847
863
|
|
|
@@ -942,13 +958,20 @@ export class AIManager {
|
|
|
942
958
|
context,
|
|
943
959
|
);
|
|
944
960
|
|
|
961
|
+
// Build result content, adding truncation warning if JSON was recovered
|
|
962
|
+
let toolResultContent =
|
|
963
|
+
toolResult.content ||
|
|
964
|
+
(toolResult.error ? `Error: ${toolResult.error}` : "");
|
|
965
|
+
if (jsonRecovered) {
|
|
966
|
+
toolResultContent +=
|
|
967
|
+
"\n\n⚠️ Tool arguments were truncated (likely exceeded max output tokens). Please reduce your output or split into multiple tool calls.";
|
|
968
|
+
}
|
|
969
|
+
|
|
945
970
|
// Update message state - tool execution completed
|
|
946
971
|
this.messageManager.updateToolBlock({
|
|
947
972
|
id: toolId,
|
|
948
973
|
parameters: argsString,
|
|
949
|
-
result:
|
|
950
|
-
toolResult.content ||
|
|
951
|
-
(toolResult.error ? `Error: ${toolResult.error}` : ""),
|
|
974
|
+
result: toolResultContent,
|
|
952
975
|
success: toolResult.success,
|
|
953
976
|
error: toolResult.error,
|
|
954
977
|
stage: "end",
|
|
@@ -1001,108 +1024,116 @@ export class AIManager {
|
|
|
1001
1024
|
|
|
1002
1025
|
// Check if there are tool operations or response was truncated, if so automatically initiate next AI service call
|
|
1003
1026
|
if (toolCalls.length > 0 || result.finish_reason === "length") {
|
|
1004
|
-
//
|
|
1005
|
-
if (this.
|
|
1006
|
-
|
|
1007
|
-
this.
|
|
1008
|
-
if (snapshots.length > 0) {
|
|
1009
|
-
this.messageManager.addFileHistoryBlock(snapshots);
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
// Check interruption status
|
|
1014
|
-
const isCurrentlyAborted =
|
|
1015
|
-
abortController.signal.aborted || toolAbortController.signal.aborted;
|
|
1016
|
-
|
|
1017
|
-
// Check if all tools were manually backgrounded
|
|
1018
|
-
const lastMessage =
|
|
1019
|
-
this.messageManager.getMessages()[
|
|
1020
|
-
this.messageManager.getMessages().length - 1
|
|
1021
|
-
];
|
|
1022
|
-
const toolBlocks =
|
|
1023
|
-
lastMessage?.blocks.filter(
|
|
1024
|
-
(block): block is import("../types/messaging.js").ToolBlock =>
|
|
1025
|
-
block.type === "tool",
|
|
1026
|
-
) || [];
|
|
1027
|
-
const hasBackgrounded =
|
|
1028
|
-
toolBlocks.length > 0 &&
|
|
1029
|
-
toolBlocks.some((block) => block.isManuallyBackgrounded);
|
|
1030
|
-
|
|
1031
|
-
if (hasBackgrounded) {
|
|
1032
|
-
logger?.info(
|
|
1033
|
-
"Some tools were manually backgrounded, stopping recursion.",
|
|
1027
|
+
// Check maxTurns limit before recursing
|
|
1028
|
+
if (this.maxTurns && recursionDepth + 1 >= this.maxTurns) {
|
|
1029
|
+
logger?.debug(
|
|
1030
|
+
`Max turns (${this.maxTurns}) reached, stopping recursion.`,
|
|
1034
1031
|
);
|
|
1035
|
-
} else
|
|
1036
|
-
//
|
|
1037
|
-
if (
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
}
|
|
1032
|
+
} else {
|
|
1033
|
+
// Record committed snapshots to message history
|
|
1034
|
+
if (this.reversionManager) {
|
|
1035
|
+
const snapshots =
|
|
1036
|
+
this.reversionManager.getAndClearCommittedSnapshots();
|
|
1037
|
+
if (snapshots.length > 0) {
|
|
1038
|
+
this.messageManager.addFileHistoryBlock(snapshots);
|
|
1039
|
+
}
|
|
1043
1040
|
}
|
|
1044
1041
|
|
|
1045
|
-
//
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1042
|
+
// Check interruption status
|
|
1043
|
+
const isCurrentlyAborted =
|
|
1044
|
+
abortController.signal.aborted ||
|
|
1045
|
+
toolAbortController.signal.aborted;
|
|
1046
|
+
|
|
1047
|
+
// Check if all tools were manually backgrounded
|
|
1048
|
+
const lastMessage =
|
|
1049
|
+
this.messageManager.getMessages()[
|
|
1050
|
+
this.messageManager.getMessages().length - 1
|
|
1051
|
+
];
|
|
1052
|
+
const toolBlocks =
|
|
1053
|
+
lastMessage?.blocks.filter(
|
|
1054
|
+
(block): block is import("../types/messaging.js").ToolBlock =>
|
|
1055
|
+
block.type === "tool",
|
|
1056
|
+
) || [];
|
|
1057
|
+
const hasBackgrounded =
|
|
1058
|
+
toolBlocks.length > 0 &&
|
|
1059
|
+
toolBlocks.some((block) => block.isManuallyBackgrounded);
|
|
1060
|
+
|
|
1061
|
+
if (hasBackgrounded) {
|
|
1062
|
+
logger?.info(
|
|
1063
|
+
"Some tools were manually backgrounded, stopping recursion.",
|
|
1064
|
+
);
|
|
1065
|
+
} else if (!isCurrentlyAborted) {
|
|
1066
|
+
// If response was truncated, add a hidden continuation message
|
|
1067
|
+
if (result.finish_reason === "length") {
|
|
1068
|
+
this.messageManager.addUserMessage({
|
|
1069
|
+
content:
|
|
1070
|
+
"Output token limit hit. Resume directly — no apology, no recap of what you were doing. Pick up mid-thought if that is where the cut happened. Break remaining work into smaller pieces.",
|
|
1071
|
+
isMeta: true,
|
|
1072
|
+
});
|
|
1060
1073
|
}
|
|
1061
1074
|
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1075
|
+
// Duplicate Tool Call Detection
|
|
1076
|
+
if (toolCalls.length > 0) {
|
|
1077
|
+
const messages = this.messageManager.getMessages();
|
|
1078
|
+
// Find the most recent assistant message BEFORE the current one that has tool blocks
|
|
1079
|
+
// The current assistant message is messages[messages.length - 1]
|
|
1080
|
+
let previousAssistantWithTools: Message | undefined;
|
|
1081
|
+
for (let i = messages.length - 2; i >= 0; i--) {
|
|
1082
|
+
const msg = messages[i];
|
|
1083
|
+
if (
|
|
1084
|
+
msg.role === "assistant" &&
|
|
1085
|
+
msg.blocks.some((b) => b.type === "tool")
|
|
1086
|
+
) {
|
|
1087
|
+
previousAssistantWithTools = msg;
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1068
1091
|
|
|
1069
|
-
|
|
1070
|
-
const
|
|
1071
|
-
|
|
1092
|
+
if (previousAssistantWithTools) {
|
|
1093
|
+
const previousToolBlocks =
|
|
1094
|
+
previousAssistantWithTools.blocks.filter(
|
|
1095
|
+
(b): b is import("../types/messaging.js").ToolBlock =>
|
|
1096
|
+
b.type === "tool",
|
|
1097
|
+
);
|
|
1072
1098
|
|
|
1073
|
-
const
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
prevBlock.parameters === currentArgs,
|
|
1077
|
-
);
|
|
1099
|
+
for (const currentToolCall of toolCalls) {
|
|
1100
|
+
const currentName = currentToolCall.function?.name;
|
|
1101
|
+
const currentArgs = currentToolCall.function?.arguments;
|
|
1078
1102
|
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
(b): b is import("../types/messaging.js").ToolBlock =>
|
|
1084
|
-
b.type === "tool" && b.id === toolId,
|
|
1103
|
+
const isDuplicate = previousToolBlocks.some(
|
|
1104
|
+
(prevBlock) =>
|
|
1105
|
+
prevBlock.name === currentName &&
|
|
1106
|
+
prevBlock.parameters === currentArgs,
|
|
1085
1107
|
);
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1108
|
+
|
|
1109
|
+
if (isDuplicate && currentName) {
|
|
1110
|
+
const toolId = currentToolCall.id;
|
|
1111
|
+
const lastMessage = messages[messages.length - 1];
|
|
1112
|
+
const toolBlock = lastMessage.blocks.find(
|
|
1113
|
+
(b): b is import("../types/messaging.js").ToolBlock =>
|
|
1114
|
+
b.type === "tool" && b.id === toolId,
|
|
1115
|
+
);
|
|
1116
|
+
if (toolBlock) {
|
|
1117
|
+
const warning = `\n\nNote: You just called this tool with the same arguments in the previous turn. Please ensure you are not in a loop and consider if you need to change your approach.`;
|
|
1118
|
+
this.messageManager.updateToolBlock({
|
|
1119
|
+
id: toolId,
|
|
1120
|
+
result: (toolBlock.result || "") + warning,
|
|
1121
|
+
stage: "end",
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1093
1124
|
}
|
|
1094
1125
|
}
|
|
1095
1126
|
}
|
|
1096
1127
|
}
|
|
1097
|
-
}
|
|
1098
1128
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1129
|
+
// Recursively call AI service, increment recursion depth, and pass same configuration
|
|
1130
|
+
await this.sendAIMessage({
|
|
1131
|
+
recursionDepth: recursionDepth + 1,
|
|
1132
|
+
model,
|
|
1133
|
+
allowedRules,
|
|
1134
|
+
maxTokens,
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1106
1137
|
}
|
|
1107
1138
|
}
|
|
1108
1139
|
} catch (error) {
|
|
@@ -47,6 +47,7 @@ export class ForkedAgentManager {
|
|
|
47
47
|
allowedTools?: string[];
|
|
48
48
|
model?: string;
|
|
49
49
|
permissionModeOverride?: PermissionMode;
|
|
50
|
+
maxTurns?: number;
|
|
50
51
|
},
|
|
51
52
|
prompt: string,
|
|
52
53
|
): Promise<string> {
|
|
@@ -84,6 +85,7 @@ export class ForkedAgentManager {
|
|
|
84
85
|
allowedTools?: string[];
|
|
85
86
|
model?: string;
|
|
86
87
|
permissionModeOverride?: PermissionMode;
|
|
88
|
+
maxTurns?: number;
|
|
87
89
|
},
|
|
88
90
|
prompt: string,
|
|
89
91
|
): Promise<void> {
|
|
@@ -103,6 +105,7 @@ export class ForkedAgentManager {
|
|
|
103
105
|
allowedTools: parameters.allowedTools,
|
|
104
106
|
model: parameters.model,
|
|
105
107
|
permissionModeOverride: parameters.permissionModeOverride,
|
|
108
|
+
maxTurns: parameters.maxTurns,
|
|
106
109
|
},
|
|
107
110
|
false,
|
|
108
111
|
);
|
|
@@ -251,6 +251,7 @@ export class SubagentManager {
|
|
|
251
251
|
model?: string;
|
|
252
252
|
stream?: boolean;
|
|
253
253
|
permissionModeOverride?: PermissionMode;
|
|
254
|
+
maxTurns?: number;
|
|
254
255
|
},
|
|
255
256
|
runInBackground?: boolean,
|
|
256
257
|
onUpdate?: () => void,
|
|
@@ -356,6 +357,7 @@ export class SubagentManager {
|
|
|
356
357
|
subagentType: parameters.subagent_type, // Pass subagent type for hook context
|
|
357
358
|
modelOverride: parameters.model || configuration.model, // Pass model override
|
|
358
359
|
stream: parameters.stream ?? this.stream, // Pass streaming mode flag
|
|
360
|
+
maxTurns: parameters.maxTurns, // Pass maxTurns limit
|
|
359
361
|
callbacks: {
|
|
360
362
|
onUsageAdded: this.onUsageAdded,
|
|
361
363
|
},
|
|
@@ -164,6 +164,7 @@ export class AutoMemoryService {
|
|
|
164
164
|
],
|
|
165
165
|
model: "fastModel", // Use fast model for background tasks to reduce latency and cost
|
|
166
166
|
permissionModeOverride: "dontAsk", // Auto-deny out-of-scope writes without prompting user
|
|
167
|
+
maxTurns: 5, // Limit turns to prevent verification rabbit-holes
|
|
167
168
|
},
|
|
168
169
|
`${prompt}\n\nThe memory directory for this project is: ${memoryDir}`,
|
|
169
170
|
);
|
package/src/utils/constants.ts
CHANGED
|
@@ -29,5 +29,5 @@ export const USER_MEMORY_FILE = path.join(DATA_DIRECTORY, "AGENTS.md");
|
|
|
29
29
|
/**
|
|
30
30
|
* AI related constants
|
|
31
31
|
*/
|
|
32
|
-
export const DEFAULT_WAVE_MAX_INPUT_TOKENS =
|
|
33
|
-
export const DEFAULT_WAVE_MAX_OUTPUT_TOKENS =
|
|
32
|
+
export const DEFAULT_WAVE_MAX_INPUT_TOKENS = 128000; // Default token limit
|
|
33
|
+
export const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 16384; // Default output token limit
|
|
@@ -2,7 +2,7 @@ import type { Message } from "../types/index.js";
|
|
|
2
2
|
import { convertImageToBase64 } from "./messageOperations.js";
|
|
3
3
|
import { taskNotificationToXml } from "./notificationXml.js";
|
|
4
4
|
import { ChatCompletionMessageToolCall } from "openai/resources";
|
|
5
|
-
import { stripAnsiColors } from "./stringUtils.js";
|
|
5
|
+
import { recoverTruncatedJson, stripAnsiColors } from "./stringUtils.js";
|
|
6
6
|
import {
|
|
7
7
|
ChatCompletionContentPart,
|
|
8
8
|
ChatCompletionMessageParam,
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
import { logger } from "./globalLogger.js";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Safely handle tool call parameters, ensuring a legal JSON string is returned
|
|
13
|
+
* Safely handle tool call parameters, ensuring a legal JSON string is returned.
|
|
14
|
+
* Attempts to recover truncated JSON (e.g., missing closing braces).
|
|
14
15
|
* @param args Tool call parameters
|
|
15
16
|
* @returns Legal JSON string
|
|
16
17
|
*/
|
|
@@ -23,12 +24,18 @@ function safeToolArguments(args: string): string {
|
|
|
23
24
|
// Try to parse as JSON to validate format
|
|
24
25
|
JSON.parse(args);
|
|
25
26
|
return args;
|
|
26
|
-
} catch
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
} catch {
|
|
28
|
+
// Attempt to recover truncated JSON
|
|
29
|
+
const recovered = recoverTruncatedJson(args);
|
|
30
|
+
try {
|
|
31
|
+
JSON.parse(recovered);
|
|
32
|
+
return recovered;
|
|
33
|
+
} catch {
|
|
34
|
+
// Truly malformed JSON — return sanitized fallback
|
|
35
|
+
return JSON.stringify({
|
|
36
|
+
invalid_arguments: args,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
32
39
|
}
|
|
33
40
|
}
|
|
34
41
|
|
package/src/utils/stringUtils.ts
CHANGED
|
@@ -92,6 +92,49 @@ export function formatLineNumberPrefix(lineNumber: number): string {
|
|
|
92
92
|
return `${lineNumber.toString().padStart(6)}\t`;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Attempt to recover truncated JSON (e.g., missing closing braces due to max tokens).
|
|
97
|
+
* Tracks brace depth and only recovers if there are unclosed `{` braces.
|
|
98
|
+
* Will NOT recover if there are unclosed `[` brackets (can't guess the content).
|
|
99
|
+
* @param jsonStr Potentially truncated JSON string
|
|
100
|
+
* @returns Recovered JSON string, or the original if unrecoverable
|
|
101
|
+
*/
|
|
102
|
+
export function recoverTruncatedJson(jsonStr: string): string {
|
|
103
|
+
let braceDepth = 0;
|
|
104
|
+
let bracketDepth = 0;
|
|
105
|
+
let inString = false;
|
|
106
|
+
let escaped = false;
|
|
107
|
+
|
|
108
|
+
for (const ch of jsonStr) {
|
|
109
|
+
if (escaped) {
|
|
110
|
+
escaped = false;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (ch === "\\" && inString) {
|
|
114
|
+
escaped = true;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (ch === '"') {
|
|
118
|
+
inString = !inString;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (!inString) {
|
|
122
|
+
if (ch === "{") braceDepth++;
|
|
123
|
+
if (ch === "}") braceDepth--;
|
|
124
|
+
if (ch === "[") bracketDepth++;
|
|
125
|
+
if (ch === "]") bracketDepth--;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Build recovery suffix
|
|
130
|
+
let suffix = "";
|
|
131
|
+
if (inString) suffix += '"'; // Close unclosed string
|
|
132
|
+
if (braceDepth > 0 && bracketDepth === 0) {
|
|
133
|
+
suffix += "}".repeat(braceDepth);
|
|
134
|
+
}
|
|
135
|
+
return suffix ? jsonStr + suffix : jsonStr;
|
|
136
|
+
}
|
|
137
|
+
|
|
95
138
|
/**
|
|
96
139
|
* Efficiently get the last N lines of a string without splitting the whole string.
|
|
97
140
|
*/
|