bashkit 0.3.1 → 0.4.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/AGENTS.md +7 -5
- package/README.md +26 -0
- package/dist/cloudflare/index.d.ts +20 -0
- package/dist/cloudflare/index.js +1251 -0
- package/dist/durable/durable-session.d.ts +220 -0
- package/dist/durable/index.d.ts +41 -0
- package/dist/durable/index.js +159 -0
- package/dist/durable/schema.d.ts +51 -0
- package/dist/durable/types.d.ts +208 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +656 -140
- package/dist/react/index.d.ts +42 -0
- package/dist/react/index.js +10 -0
- package/dist/react/types.d.ts +333 -0
- package/dist/react/use-agent.d.ts +33 -0
- package/dist/react/use-durable-chat.d.ts +39 -0
- package/dist/tools/ask-user.d.ts +12 -12
- package/dist/tools/bash.d.ts +3 -3
- package/dist/tools/edit.d.ts +1 -1
- package/dist/tools/glob.d.ts +1 -1
- package/dist/tools/grep.d.ts +12 -12
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/read.d.ts +2 -2
- package/dist/tools/task.d.ts +8 -6
- package/dist/tools/web-search.d.ts +2 -2
- package/dist/utils/debug.d.ts +83 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/workflow.js +827 -234
- package/package.json +7 -2
package/dist/index.js
CHANGED
|
@@ -615,19 +615,197 @@ var DEFAULT_CONFIG = {
|
|
|
615
615
|
// src/tools/ask-user.ts
|
|
616
616
|
import { tool, zodSchema } from "ai";
|
|
617
617
|
import { z } from "zod";
|
|
618
|
+
|
|
619
|
+
// src/utils/debug.ts
|
|
620
|
+
import { appendFileSync } from "node:fs";
|
|
621
|
+
var state = {
|
|
622
|
+
mode: "off",
|
|
623
|
+
logs: [],
|
|
624
|
+
counters: new Map,
|
|
625
|
+
parentStack: []
|
|
626
|
+
};
|
|
627
|
+
var MAX_STRING_LENGTH = 1000;
|
|
628
|
+
var MAX_ARRAY_ITEMS = 10;
|
|
629
|
+
function initDebugMode() {
|
|
630
|
+
const envValue = process.env.BASHKIT_DEBUG;
|
|
631
|
+
if (!envValue) {
|
|
632
|
+
state.mode = "off";
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
if (envValue === "1" || envValue === "stderr") {
|
|
636
|
+
state.mode = "stderr";
|
|
637
|
+
} else if (envValue === "json") {
|
|
638
|
+
state.mode = "json";
|
|
639
|
+
} else if (envValue === "memory") {
|
|
640
|
+
state.mode = "memory";
|
|
641
|
+
} else if (envValue.startsWith("file:")) {
|
|
642
|
+
state.mode = "file";
|
|
643
|
+
state.filePath = envValue.slice(5);
|
|
644
|
+
} else {
|
|
645
|
+
state.mode = "stderr";
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
initDebugMode();
|
|
649
|
+
function isDebugEnabled() {
|
|
650
|
+
return state.mode !== "off";
|
|
651
|
+
}
|
|
652
|
+
function generateId(tool) {
|
|
653
|
+
const count = (state.counters.get(tool) || 0) + 1;
|
|
654
|
+
state.counters.set(tool, count);
|
|
655
|
+
return `${tool}-${count}`;
|
|
656
|
+
}
|
|
657
|
+
function truncateString(str) {
|
|
658
|
+
if (str.length <= MAX_STRING_LENGTH)
|
|
659
|
+
return str;
|
|
660
|
+
return `${str.slice(0, MAX_STRING_LENGTH)}... [truncated, ${str.length - MAX_STRING_LENGTH} more chars]`;
|
|
661
|
+
}
|
|
662
|
+
function summarize(data, depth = 0) {
|
|
663
|
+
if (depth > 5)
|
|
664
|
+
return "[nested object]";
|
|
665
|
+
if (data === null || data === undefined)
|
|
666
|
+
return data;
|
|
667
|
+
if (typeof data === "string") {
|
|
668
|
+
return truncateString(data);
|
|
669
|
+
}
|
|
670
|
+
if (typeof data === "number" || typeof data === "boolean") {
|
|
671
|
+
return data;
|
|
672
|
+
}
|
|
673
|
+
if (Array.isArray(data)) {
|
|
674
|
+
const truncated = data.length > MAX_ARRAY_ITEMS;
|
|
675
|
+
const items = data.slice(0, MAX_ARRAY_ITEMS).map((item) => summarize(item, depth + 1));
|
|
676
|
+
if (truncated) {
|
|
677
|
+
return [...items, `[${data.length - MAX_ARRAY_ITEMS} more items]`];
|
|
678
|
+
}
|
|
679
|
+
return items;
|
|
680
|
+
}
|
|
681
|
+
if (typeof data === "object") {
|
|
682
|
+
const result = {};
|
|
683
|
+
for (const [key, value] of Object.entries(data)) {
|
|
684
|
+
result[key] = summarize(value, depth + 1);
|
|
685
|
+
}
|
|
686
|
+
return result;
|
|
687
|
+
}
|
|
688
|
+
return String(data);
|
|
689
|
+
}
|
|
690
|
+
function emitEvent(event) {
|
|
691
|
+
if (state.mode === "off")
|
|
692
|
+
return;
|
|
693
|
+
switch (state.mode) {
|
|
694
|
+
case "memory":
|
|
695
|
+
state.logs.push(event);
|
|
696
|
+
break;
|
|
697
|
+
case "json":
|
|
698
|
+
process.stderr.write(`${JSON.stringify(event)}
|
|
699
|
+
`);
|
|
700
|
+
break;
|
|
701
|
+
case "file":
|
|
702
|
+
if (state.filePath) {
|
|
703
|
+
appendFileSync(state.filePath, `${JSON.stringify(event)}
|
|
704
|
+
`);
|
|
705
|
+
}
|
|
706
|
+
break;
|
|
707
|
+
case "stderr":
|
|
708
|
+
default:
|
|
709
|
+
formatHumanReadable(event);
|
|
710
|
+
break;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
function formatHumanReadable(event) {
|
|
714
|
+
const indent = " ".repeat(state.parentStack.length);
|
|
715
|
+
if (event.event === "start") {
|
|
716
|
+
const inputSummary = event.input ? Object.entries(event.input).map(([k, v]) => `${k}=${JSON.stringify(v)}`).slice(0, 3).join(" ") : "";
|
|
717
|
+
process.stderr.write(`${indent}[bashkit:${event.tool}] → ${inputSummary}
|
|
718
|
+
`);
|
|
719
|
+
} else if (event.event === "end") {
|
|
720
|
+
const summaryStr = event.summary ? Object.entries(event.summary).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(" ") : "";
|
|
721
|
+
process.stderr.write(`${indent}[bashkit:${event.tool}] ← ${event.duration_ms}ms ${summaryStr}
|
|
722
|
+
`);
|
|
723
|
+
} else if (event.event === "error") {
|
|
724
|
+
process.stderr.write(`${indent}[bashkit:${event.tool}] ✗ ${event.error}
|
|
725
|
+
`);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
function debugStart(tool, input) {
|
|
729
|
+
if (state.mode === "off")
|
|
730
|
+
return "";
|
|
731
|
+
const id = generateId(tool);
|
|
732
|
+
const parent = state.parentStack.length > 0 ? state.parentStack[state.parentStack.length - 1] : undefined;
|
|
733
|
+
const event = {
|
|
734
|
+
id,
|
|
735
|
+
ts: Date.now(),
|
|
736
|
+
tool,
|
|
737
|
+
event: "start",
|
|
738
|
+
input: input ? summarize(input) : undefined,
|
|
739
|
+
parent
|
|
740
|
+
};
|
|
741
|
+
emitEvent(event);
|
|
742
|
+
return id;
|
|
743
|
+
}
|
|
744
|
+
function debugEnd(id, tool, options) {
|
|
745
|
+
if (state.mode === "off" || !id)
|
|
746
|
+
return;
|
|
747
|
+
const event = {
|
|
748
|
+
id,
|
|
749
|
+
ts: Date.now(),
|
|
750
|
+
tool,
|
|
751
|
+
event: "end",
|
|
752
|
+
output: options.output ? summarize(options.output) : undefined,
|
|
753
|
+
summary: options.summary,
|
|
754
|
+
duration_ms: options.duration_ms
|
|
755
|
+
};
|
|
756
|
+
emitEvent(event);
|
|
757
|
+
}
|
|
758
|
+
function debugError(id, tool, error) {
|
|
759
|
+
if (state.mode === "off" || !id)
|
|
760
|
+
return;
|
|
761
|
+
const event = {
|
|
762
|
+
id,
|
|
763
|
+
ts: Date.now(),
|
|
764
|
+
tool,
|
|
765
|
+
event: "error",
|
|
766
|
+
error: error instanceof Error ? error.message : error
|
|
767
|
+
};
|
|
768
|
+
emitEvent(event);
|
|
769
|
+
}
|
|
770
|
+
function pushParent(id) {
|
|
771
|
+
if (state.mode === "off" || !id)
|
|
772
|
+
return;
|
|
773
|
+
state.parentStack.push(id);
|
|
774
|
+
}
|
|
775
|
+
function popParent() {
|
|
776
|
+
if (state.mode === "off")
|
|
777
|
+
return;
|
|
778
|
+
state.parentStack.pop();
|
|
779
|
+
}
|
|
780
|
+
function getDebugLogs() {
|
|
781
|
+
return [...state.logs];
|
|
782
|
+
}
|
|
783
|
+
function clearDebugLogs() {
|
|
784
|
+
state.logs = [];
|
|
785
|
+
state.counters.clear();
|
|
786
|
+
state.parentStack = [];
|
|
787
|
+
}
|
|
788
|
+
function reinitDebugMode() {
|
|
789
|
+
state.logs = [];
|
|
790
|
+
state.counters.clear();
|
|
791
|
+
state.parentStack = [];
|
|
792
|
+
initDebugMode();
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/tools/ask-user.ts
|
|
618
796
|
var questionOptionSchema = z.object({
|
|
619
797
|
label: z.string().describe("The display text for this option. Should be concise (1-5 words). Add '(Recommended)' suffix for suggested options."),
|
|
620
|
-
description: z.string().
|
|
798
|
+
description: z.string().nullable().default(null).describe("Explanation of what this option means or its implications.")
|
|
621
799
|
});
|
|
622
800
|
var structuredQuestionSchema = z.object({
|
|
623
|
-
header: z.string().
|
|
801
|
+
header: z.string().nullable().default(null).describe("Very short label displayed as a chip/tag (max 12 chars). Examples: 'Auth method', 'Library', 'Approach'."),
|
|
624
802
|
question: z.string().describe("The complete question to ask the user. Should be clear and specific."),
|
|
625
|
-
options: z.array(questionOptionSchema).min(2).max(4).
|
|
626
|
-
multiSelect: z.boolean().
|
|
803
|
+
options: z.array(questionOptionSchema).min(2).max(4).nullable().default(null).describe("Available choices for this question. 2-4 options. An 'Other' option is automatically available to users."),
|
|
804
|
+
multiSelect: z.boolean().nullable().default(null).describe("Set to true to allow the user to select multiple options instead of just one.")
|
|
627
805
|
});
|
|
628
806
|
var askUserInputSchema = z.object({
|
|
629
|
-
question: z.string().
|
|
630
|
-
questions: z.array(structuredQuestionSchema).min(1).max(4).
|
|
807
|
+
question: z.string().nullable().default(null).describe("Simple question string (for backward compatibility). Use 'questions' for structured multi-choice."),
|
|
808
|
+
questions: z.array(structuredQuestionSchema).min(1).max(4).nullable().default(null).describe("Structured questions with options (1-4 questions).")
|
|
631
809
|
});
|
|
632
810
|
var ASK_USER_DESCRIPTION = `Use this tool when you need to ask the user questions during execution.
|
|
633
811
|
|
|
@@ -664,22 +842,46 @@ function createAskUserTool(config) {
|
|
|
664
842
|
description: ASK_USER_DESCRIPTION,
|
|
665
843
|
inputSchema: zodSchema(askUserInputSchema),
|
|
666
844
|
execute: async (input) => {
|
|
845
|
+
const startTime = performance.now();
|
|
846
|
+
const debugId = isDebugEnabled() ? debugStart("ask-user", {
|
|
847
|
+
hasQuestion: !!input.question,
|
|
848
|
+
questionCount: input.questions?.length ?? 0,
|
|
849
|
+
question: input.question ? input.question.length > 100 ? `${input.question.slice(0, 100)}...` : input.question : undefined
|
|
850
|
+
}) : "";
|
|
667
851
|
try {
|
|
668
852
|
if (!input.question && !input.questions) {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
853
|
+
const error2 = "Either 'question' or 'questions' must be provided";
|
|
854
|
+
if (debugId)
|
|
855
|
+
debugError(debugId, "ask-user", error2);
|
|
856
|
+
return { error: error2 };
|
|
672
857
|
}
|
|
673
858
|
if (input.questions && input.questions.length > 0) {
|
|
674
859
|
if (normalizedConfig.onStructuredQuestions) {
|
|
675
860
|
const answers = await normalizedConfig.onStructuredQuestions(input.questions);
|
|
676
861
|
const firstKey = Object.keys(answers)[0];
|
|
677
862
|
const firstAnswer = answers[firstKey];
|
|
863
|
+
const durationMs2 = Math.round(performance.now() - startTime);
|
|
864
|
+
if (debugId) {
|
|
865
|
+
debugEnd(debugId, "ask-user", {
|
|
866
|
+
summary: {
|
|
867
|
+
type: "structured",
|
|
868
|
+
answerCount: Object.keys(answers).length
|
|
869
|
+
},
|
|
870
|
+
duration_ms: durationMs2
|
|
871
|
+
});
|
|
872
|
+
}
|
|
678
873
|
return {
|
|
679
874
|
answer: Array.isArray(firstAnswer) ? firstAnswer.join(", ") : firstAnswer,
|
|
680
875
|
answers
|
|
681
876
|
};
|
|
682
877
|
}
|
|
878
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
879
|
+
if (debugId) {
|
|
880
|
+
debugEnd(debugId, "ask-user", {
|
|
881
|
+
summary: { type: "structured", awaiting: true },
|
|
882
|
+
duration_ms: durationMs
|
|
883
|
+
});
|
|
884
|
+
}
|
|
683
885
|
return {
|
|
684
886
|
questions: input.questions,
|
|
685
887
|
awaiting_response: true
|
|
@@ -688,18 +890,36 @@ function createAskUserTool(config) {
|
|
|
688
890
|
if (input.question) {
|
|
689
891
|
if (normalizedConfig.onQuestion) {
|
|
690
892
|
const answer = await normalizedConfig.onQuestion(input.question);
|
|
893
|
+
const durationMs2 = Math.round(performance.now() - startTime);
|
|
894
|
+
if (debugId) {
|
|
895
|
+
debugEnd(debugId, "ask-user", {
|
|
896
|
+
summary: { type: "simple", hasAnswer: true },
|
|
897
|
+
duration_ms: durationMs2
|
|
898
|
+
});
|
|
899
|
+
}
|
|
691
900
|
return { answer };
|
|
692
901
|
}
|
|
902
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
903
|
+
if (debugId) {
|
|
904
|
+
debugEnd(debugId, "ask-user", {
|
|
905
|
+
summary: { type: "simple", awaiting: true },
|
|
906
|
+
duration_ms: durationMs
|
|
907
|
+
});
|
|
908
|
+
}
|
|
693
909
|
return {
|
|
694
910
|
question: input.question,
|
|
695
911
|
awaiting_response: true
|
|
696
912
|
};
|
|
697
913
|
}
|
|
698
|
-
|
|
914
|
+
const error = "No question provided";
|
|
915
|
+
if (debugId)
|
|
916
|
+
debugError(debugId, "ask-user", error);
|
|
917
|
+
return { error };
|
|
699
918
|
} catch (error) {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
919
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
920
|
+
if (debugId)
|
|
921
|
+
debugError(debugId, "ask-user", errorMessage);
|
|
922
|
+
return { error: errorMessage };
|
|
703
923
|
}
|
|
704
924
|
}
|
|
705
925
|
});
|
|
@@ -710,9 +930,9 @@ import { tool as tool2, zodSchema as zodSchema2 } from "ai";
|
|
|
710
930
|
import { z as z2 } from "zod";
|
|
711
931
|
var bashInputSchema = z2.object({
|
|
712
932
|
command: z2.string().describe("The command to execute"),
|
|
713
|
-
timeout: z2.number().
|
|
714
|
-
description: z2.string().
|
|
715
|
-
run_in_background: z2.boolean().
|
|
933
|
+
timeout: z2.number().nullable().default(null).describe("Optional timeout in milliseconds (max 600000)"),
|
|
934
|
+
description: z2.string().nullable().default(null).describe("Clear, concise description of what this command does in 5-10 words"),
|
|
935
|
+
run_in_background: z2.boolean().nullable().default(null).describe("Set to true to run this command in the background")
|
|
716
936
|
});
|
|
717
937
|
var BASH_DESCRIPTION = `Executes a bash command in a persistent shell session with optional timeout.
|
|
718
938
|
|
|
@@ -763,12 +983,18 @@ function createBashTool(sandbox, config) {
|
|
|
763
983
|
description: _description,
|
|
764
984
|
run_in_background: _run_in_background
|
|
765
985
|
}) => {
|
|
986
|
+
const startTime = performance.now();
|
|
987
|
+
const debugId = isDebugEnabled() ? debugStart("bash", {
|
|
988
|
+
command: command.length > 200 ? `${command.slice(0, 200)}...` : command,
|
|
989
|
+
timeout
|
|
990
|
+
}) : "";
|
|
766
991
|
if (config?.blockedCommands) {
|
|
767
992
|
for (const blocked of config.blockedCommands) {
|
|
768
993
|
if (command.includes(blocked)) {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
994
|
+
const error = `Command blocked: contains '${blocked}'`;
|
|
995
|
+
if (debugId)
|
|
996
|
+
debugError(debugId, "bash", error);
|
|
997
|
+
return { error };
|
|
772
998
|
}
|
|
773
999
|
}
|
|
774
1000
|
}
|
|
@@ -787,6 +1013,18 @@ function createBashTool(sandbox, config) {
|
|
|
787
1013
|
stderr = stderr.slice(0, maxOutputLength) + `
|
|
788
1014
|
[output truncated, ${stderr.length - maxOutputLength} chars omitted]`;
|
|
789
1015
|
}
|
|
1016
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
1017
|
+
if (debugId) {
|
|
1018
|
+
debugEnd(debugId, "bash", {
|
|
1019
|
+
summary: {
|
|
1020
|
+
exitCode: result.exitCode,
|
|
1021
|
+
stdoutLen: result.stdout.length,
|
|
1022
|
+
stderrLen: result.stderr.length,
|
|
1023
|
+
interrupted: result.interrupted
|
|
1024
|
+
},
|
|
1025
|
+
duration_ms: durationMs
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
790
1028
|
return {
|
|
791
1029
|
stdout,
|
|
792
1030
|
stderr,
|
|
@@ -795,9 +1033,10 @@ function createBashTool(sandbox, config) {
|
|
|
795
1033
|
duration_ms: result.durationMs
|
|
796
1034
|
};
|
|
797
1035
|
} catch (error) {
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
1036
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1037
|
+
if (debugId)
|
|
1038
|
+
debugError(debugId, "bash", errorMessage);
|
|
1039
|
+
return { error: errorMessage };
|
|
801
1040
|
}
|
|
802
1041
|
}
|
|
803
1042
|
});
|
|
@@ -810,7 +1049,7 @@ var editInputSchema = z3.object({
|
|
|
810
1049
|
file_path: z3.string().describe("The absolute path to the file to modify"),
|
|
811
1050
|
old_string: z3.string().describe("The text to replace"),
|
|
812
1051
|
new_string: z3.string().describe("The text to replace it with (must be different from old_string)"),
|
|
813
|
-
replace_all: z3.boolean().
|
|
1052
|
+
replace_all: z3.boolean().nullable().default(null).describe("Replace all occurrences of old_string (default false)")
|
|
814
1053
|
});
|
|
815
1054
|
var EDIT_DESCRIPTION = `Performs exact string replacements in files.
|
|
816
1055
|
|
|
@@ -840,31 +1079,51 @@ function createEditTool(sandbox, config) {
|
|
|
840
1079
|
file_path,
|
|
841
1080
|
old_string,
|
|
842
1081
|
new_string,
|
|
843
|
-
replace_all
|
|
1082
|
+
replace_all: rawReplaceAll
|
|
844
1083
|
}) => {
|
|
1084
|
+
const replace_all = rawReplaceAll ?? false;
|
|
1085
|
+
const startTime = performance.now();
|
|
1086
|
+
const debugId = isDebugEnabled() ? debugStart("edit", {
|
|
1087
|
+
file_path,
|
|
1088
|
+
old_string: old_string.length > 100 ? `${old_string.slice(0, 100)}...` : old_string,
|
|
1089
|
+
replace_all
|
|
1090
|
+
}) : "";
|
|
845
1091
|
if (old_string === new_string) {
|
|
846
|
-
|
|
1092
|
+
const error = "old_string and new_string must be different";
|
|
1093
|
+
if (debugId)
|
|
1094
|
+
debugError(debugId, "edit", error);
|
|
1095
|
+
return { error };
|
|
847
1096
|
}
|
|
848
1097
|
if (config?.allowedPaths) {
|
|
849
1098
|
const isAllowed = config.allowedPaths.some((allowed) => file_path.startsWith(allowed));
|
|
850
1099
|
if (!isAllowed) {
|
|
851
|
-
|
|
1100
|
+
const error = `Path not allowed: ${file_path}`;
|
|
1101
|
+
if (debugId)
|
|
1102
|
+
debugError(debugId, "edit", error);
|
|
1103
|
+
return { error };
|
|
852
1104
|
}
|
|
853
1105
|
}
|
|
854
1106
|
try {
|
|
855
1107
|
const exists = await sandbox.fileExists(file_path);
|
|
856
1108
|
if (!exists) {
|
|
857
|
-
|
|
1109
|
+
const error = `File not found: ${file_path}`;
|
|
1110
|
+
if (debugId)
|
|
1111
|
+
debugError(debugId, "edit", error);
|
|
1112
|
+
return { error };
|
|
858
1113
|
}
|
|
859
1114
|
const content = await sandbox.readFile(file_path);
|
|
860
1115
|
const occurrences = content.split(old_string).length - 1;
|
|
861
1116
|
if (occurrences === 0) {
|
|
862
|
-
|
|
1117
|
+
const error = `String not found in file: "${old_string}"`;
|
|
1118
|
+
if (debugId)
|
|
1119
|
+
debugError(debugId, "edit", error);
|
|
1120
|
+
return { error };
|
|
863
1121
|
}
|
|
864
1122
|
if (!replace_all && occurrences > 1) {
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
1123
|
+
const error = `String appears ${occurrences} times in file. Use replace_all=true to replace all, or provide a more unique string.`;
|
|
1124
|
+
if (debugId)
|
|
1125
|
+
debugError(debugId, "edit", error);
|
|
1126
|
+
return { error };
|
|
868
1127
|
}
|
|
869
1128
|
let newContent;
|
|
870
1129
|
let replacements;
|
|
@@ -876,15 +1135,23 @@ function createEditTool(sandbox, config) {
|
|
|
876
1135
|
replacements = 1;
|
|
877
1136
|
}
|
|
878
1137
|
await sandbox.writeFile(file_path, newContent);
|
|
1138
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
1139
|
+
if (debugId) {
|
|
1140
|
+
debugEnd(debugId, "edit", {
|
|
1141
|
+
summary: { replacements },
|
|
1142
|
+
duration_ms: durationMs
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
879
1145
|
return {
|
|
880
1146
|
message: `Successfully edited ${file_path}`,
|
|
881
1147
|
file_path,
|
|
882
1148
|
replacements
|
|
883
1149
|
};
|
|
884
1150
|
} catch (error) {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
1151
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1152
|
+
if (debugId)
|
|
1153
|
+
debugError(debugId, "edit", errorMessage);
|
|
1154
|
+
return { error: errorMessage };
|
|
888
1155
|
}
|
|
889
1156
|
}
|
|
890
1157
|
});
|
|
@@ -951,33 +1218,44 @@ In plan mode, you'll:
|
|
|
951
1218
|
- This tool REQUIRES user approval - they must consent to entering plan mode
|
|
952
1219
|
- If unsure whether to use it, err on the side of planning - it's better to get alignment upfront than to redo work
|
|
953
1220
|
- Users appreciate being consulted before significant changes`;
|
|
954
|
-
function createEnterPlanModeTool(
|
|
1221
|
+
function createEnterPlanModeTool(state2, onEnter) {
|
|
955
1222
|
return tool4({
|
|
956
1223
|
description: ENTER_PLAN_MODE_DESCRIPTION,
|
|
957
1224
|
inputSchema: zodSchema4(enterPlanModeInputSchema),
|
|
958
1225
|
execute: async ({
|
|
959
1226
|
reason
|
|
960
1227
|
}) => {
|
|
1228
|
+
const startTime = performance.now();
|
|
1229
|
+
const debugId = isDebugEnabled() ? debugStart("enter-plan-mode", { reason }) : "";
|
|
961
1230
|
try {
|
|
962
|
-
if (
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1231
|
+
if (state2.isActive) {
|
|
1232
|
+
const error = "Already in planning mode. Use ExitPlanMode to exit.";
|
|
1233
|
+
if (debugId)
|
|
1234
|
+
debugError(debugId, "enter-plan-mode", error);
|
|
1235
|
+
return { error };
|
|
966
1236
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1237
|
+
state2.isActive = true;
|
|
1238
|
+
state2.enteredAt = new Date;
|
|
1239
|
+
state2.reason = reason;
|
|
970
1240
|
if (onEnter) {
|
|
971
1241
|
await onEnter(reason);
|
|
972
1242
|
}
|
|
1243
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
1244
|
+
if (debugId) {
|
|
1245
|
+
debugEnd(debugId, "enter-plan-mode", {
|
|
1246
|
+
summary: { mode: "planning" },
|
|
1247
|
+
duration_ms: durationMs
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
973
1250
|
return {
|
|
974
1251
|
message: `Entered planning mode: ${reason}. Use Read, Grep, and Glob to explore. Call ExitPlanMode when ready with a plan.`,
|
|
975
1252
|
mode: "planning"
|
|
976
1253
|
};
|
|
977
1254
|
} catch (error) {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1255
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1256
|
+
if (debugId)
|
|
1257
|
+
debugError(debugId, "enter-plan-mode", errorMessage);
|
|
1258
|
+
return { error: errorMessage };
|
|
981
1259
|
}
|
|
982
1260
|
}
|
|
983
1261
|
});
|
|
@@ -1017,19 +1295,32 @@ function createExitPlanModeTool(onPlanSubmit) {
|
|
|
1017
1295
|
execute: async ({
|
|
1018
1296
|
plan
|
|
1019
1297
|
}) => {
|
|
1298
|
+
const startTime = performance.now();
|
|
1299
|
+
const debugId = isDebugEnabled() ? debugStart("exit-plan-mode", {
|
|
1300
|
+
planLength: plan.length,
|
|
1301
|
+
planPreview: plan.length > 200 ? `${plan.slice(0, 200)}...` : plan
|
|
1302
|
+
}) : "";
|
|
1020
1303
|
try {
|
|
1021
1304
|
let approved;
|
|
1022
1305
|
if (onPlanSubmit) {
|
|
1023
1306
|
approved = await onPlanSubmit(plan);
|
|
1024
1307
|
}
|
|
1308
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
1309
|
+
if (debugId) {
|
|
1310
|
+
debugEnd(debugId, "exit-plan-mode", {
|
|
1311
|
+
summary: { approved },
|
|
1312
|
+
duration_ms: durationMs
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1025
1315
|
return {
|
|
1026
1316
|
message: approved ? "Plan approved, proceeding with execution" : "Plan submitted for review",
|
|
1027
1317
|
approved
|
|
1028
1318
|
};
|
|
1029
1319
|
} catch (error) {
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1320
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1321
|
+
if (debugId)
|
|
1322
|
+
debugError(debugId, "exit-plan-mode", errorMessage);
|
|
1323
|
+
return { error: errorMessage };
|
|
1033
1324
|
}
|
|
1034
1325
|
}
|
|
1035
1326
|
});
|
|
@@ -1040,7 +1331,7 @@ import { tool as tool6, zodSchema as zodSchema6 } from "ai";
|
|
|
1040
1331
|
import { z as z6 } from "zod";
|
|
1041
1332
|
var globInputSchema = z6.object({
|
|
1042
1333
|
pattern: z6.string().describe('Glob pattern to match files (e.g., "**/*.ts", "src/**/*.js", "*.md")'),
|
|
1043
|
-
path: z6.string().
|
|
1334
|
+
path: z6.string().nullable().default(null).describe("Directory to search in (defaults to working directory)")
|
|
1044
1335
|
});
|
|
1045
1336
|
var GLOB_DESCRIPTION = `
|
|
1046
1337
|
- Fast file pattern matching tool that works with any codebase size
|
|
@@ -1061,29 +1352,48 @@ function createGlobTool(sandbox, config) {
|
|
|
1061
1352
|
pattern,
|
|
1062
1353
|
path
|
|
1063
1354
|
}) => {
|
|
1064
|
-
const searchPath = path
|
|
1355
|
+
const searchPath = path ?? ".";
|
|
1356
|
+
const startTime = performance.now();
|
|
1357
|
+
const debugId = isDebugEnabled() ? debugStart("glob", { pattern, path: searchPath }) : "";
|
|
1065
1358
|
if (config?.allowedPaths) {
|
|
1066
1359
|
const isAllowed = config.allowedPaths.some((allowed) => searchPath.startsWith(allowed));
|
|
1067
1360
|
if (!isAllowed) {
|
|
1068
|
-
|
|
1361
|
+
const error = `Path not allowed: ${searchPath}`;
|
|
1362
|
+
if (debugId)
|
|
1363
|
+
debugError(debugId, "glob", error);
|
|
1364
|
+
return { error };
|
|
1069
1365
|
}
|
|
1070
1366
|
}
|
|
1071
1367
|
try {
|
|
1072
|
-
const
|
|
1368
|
+
const findFlag = pattern.includes("/") ? "-path" : "-name";
|
|
1369
|
+
const findPattern = pattern.includes("/") && !pattern.startsWith("*") ? `*/${pattern}` : pattern;
|
|
1370
|
+
const result = await sandbox.exec(`find ${searchPath} -type f ${findFlag} "${findPattern}" 2>/dev/null | head -1000`, { timeout: config?.timeout });
|
|
1073
1371
|
if (result.exitCode !== 0 && result.stderr) {
|
|
1074
|
-
|
|
1372
|
+
const error = result.stderr;
|
|
1373
|
+
if (debugId)
|
|
1374
|
+
debugError(debugId, "glob", error);
|
|
1375
|
+
return { error };
|
|
1075
1376
|
}
|
|
1076
1377
|
const matches = result.stdout.split(`
|
|
1077
1378
|
`).filter(Boolean).map((p) => p.trim());
|
|
1379
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
1380
|
+
if (debugId) {
|
|
1381
|
+
debugEnd(debugId, "glob", {
|
|
1382
|
+
summary: { count: matches.length },
|
|
1383
|
+
output: matches.slice(0, 10),
|
|
1384
|
+
duration_ms: durationMs
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1078
1387
|
return {
|
|
1079
1388
|
matches,
|
|
1080
1389
|
count: matches.length,
|
|
1081
1390
|
search_path: searchPath
|
|
1082
1391
|
};
|
|
1083
1392
|
} catch (error) {
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1393
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1394
|
+
if (debugId)
|
|
1395
|
+
debugError(debugId, "glob", errorMessage);
|
|
1396
|
+
return { error: errorMessage };
|
|
1087
1397
|
}
|
|
1088
1398
|
}
|
|
1089
1399
|
});
|
|
@@ -1094,18 +1404,18 @@ import { tool as tool7, zodSchema as zodSchema7 } from "ai";
|
|
|
1094
1404
|
import { z as z7 } from "zod";
|
|
1095
1405
|
var grepInputSchema = z7.object({
|
|
1096
1406
|
pattern: z7.string().describe("The regular expression pattern to search for in file contents"),
|
|
1097
|
-
path: z7.string().
|
|
1098
|
-
glob: z7.string().
|
|
1099
|
-
type: z7.string().
|
|
1100
|
-
output_mode: z7.enum(["content", "files_with_matches", "count"]).
|
|
1101
|
-
"-i": z7.boolean().
|
|
1102
|
-
"-n": z7.boolean().
|
|
1103
|
-
"-B": z7.number().
|
|
1104
|
-
"-A": z7.number().
|
|
1105
|
-
"-C": z7.number().
|
|
1106
|
-
head_limit: z7.number().
|
|
1107
|
-
offset: z7.number().
|
|
1108
|
-
multiline: z7.boolean().
|
|
1407
|
+
path: z7.string().nullable().default(null).describe("File or directory to search in (defaults to cwd)"),
|
|
1408
|
+
glob: z7.string().nullable().default(null).describe('Glob pattern to filter files (e.g. "*.js", "*.{ts,tsx}")'),
|
|
1409
|
+
type: z7.string().nullable().default(null).describe('File type to search (e.g. "js", "py", "rust")'),
|
|
1410
|
+
output_mode: z7.enum(["content", "files_with_matches", "count"]).nullable().default(null).describe('Output mode: "content" shows matching lines, "files_with_matches" shows file paths (default), "count" shows match counts'),
|
|
1411
|
+
"-i": z7.boolean().nullable().default(null).describe("Case insensitive search"),
|
|
1412
|
+
"-n": z7.boolean().nullable().default(null).describe("Show line numbers in output. Requires output_mode: 'content'. Defaults to true."),
|
|
1413
|
+
"-B": z7.number().nullable().default(null).describe("Number of lines to show before each match. Requires output_mode: 'content'."),
|
|
1414
|
+
"-A": z7.number().nullable().default(null).describe("Number of lines to show after each match. Requires output_mode: 'content'."),
|
|
1415
|
+
"-C": z7.number().nullable().default(null).describe("Number of lines to show before and after each match. Requires output_mode: 'content'."),
|
|
1416
|
+
head_limit: z7.number().nullable().default(null).describe("Limit output to first N lines/entries. Works across all output modes. Defaults to 0 (unlimited)."),
|
|
1417
|
+
offset: z7.number().nullable().default(null).describe("Skip first N lines/entries before applying head_limit. Works across all output modes. Defaults to 0."),
|
|
1418
|
+
multiline: z7.boolean().nullable().default(null).describe("Enable multiline mode where patterns can span lines. Default: false.")
|
|
1109
1419
|
});
|
|
1110
1420
|
var GREP_DESCRIPTION = `A powerful content search tool built on ripgrep with regex support.
|
|
1111
1421
|
|
|
@@ -1140,27 +1450,43 @@ function createGrepTool(sandbox, config) {
|
|
|
1140
1450
|
path,
|
|
1141
1451
|
glob,
|
|
1142
1452
|
type,
|
|
1143
|
-
output_mode
|
|
1453
|
+
output_mode: rawOutputMode,
|
|
1144
1454
|
"-i": caseInsensitive,
|
|
1145
1455
|
"-B": beforeContext,
|
|
1146
1456
|
"-A": afterContext,
|
|
1147
1457
|
"-C": context,
|
|
1148
1458
|
head_limit,
|
|
1149
|
-
offset
|
|
1459
|
+
offset: rawOffset,
|
|
1150
1460
|
multiline
|
|
1151
1461
|
} = input;
|
|
1462
|
+
const output_mode = rawOutputMode ?? "files_with_matches";
|
|
1463
|
+
const offset = rawOffset ?? 0;
|
|
1152
1464
|
const searchPath = path || ".";
|
|
1465
|
+
const startTime = performance.now();
|
|
1466
|
+
const debugId = isDebugEnabled() ? debugStart("grep", {
|
|
1467
|
+
pattern,
|
|
1468
|
+
path: searchPath,
|
|
1469
|
+
output_mode,
|
|
1470
|
+
glob,
|
|
1471
|
+
type,
|
|
1472
|
+
caseInsensitive,
|
|
1473
|
+
multiline
|
|
1474
|
+
}) : "";
|
|
1153
1475
|
if (config?.allowedPaths) {
|
|
1154
1476
|
const isAllowed = config.allowedPaths.some((allowed) => searchPath.startsWith(allowed));
|
|
1155
1477
|
if (!isAllowed) {
|
|
1156
|
-
|
|
1478
|
+
const error = `Path not allowed: ${searchPath}`;
|
|
1479
|
+
if (debugId)
|
|
1480
|
+
debugError(debugId, "grep", error);
|
|
1481
|
+
return { error };
|
|
1157
1482
|
}
|
|
1158
1483
|
}
|
|
1159
1484
|
try {
|
|
1160
1485
|
if (!sandbox.rgPath) {
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1486
|
+
const error = "Ripgrep not available. Call ensureSandboxTools(sandbox) before using Grep with remote sandboxes.";
|
|
1487
|
+
if (debugId)
|
|
1488
|
+
debugError(debugId, "grep", error);
|
|
1489
|
+
return { error };
|
|
1164
1490
|
}
|
|
1165
1491
|
const cmd = buildRipgrepCommand({
|
|
1166
1492
|
rgPath: sandbox.rgPath,
|
|
@@ -1176,17 +1502,48 @@ function createGrepTool(sandbox, config) {
|
|
|
1176
1502
|
multiline
|
|
1177
1503
|
});
|
|
1178
1504
|
const result = await sandbox.exec(cmd, { timeout: config?.timeout });
|
|
1505
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
1506
|
+
let output;
|
|
1179
1507
|
if (output_mode === "files_with_matches") {
|
|
1180
|
-
|
|
1508
|
+
output = parseFilesOutput(result.stdout);
|
|
1509
|
+
if (debugId) {
|
|
1510
|
+
debugEnd(debugId, "grep", {
|
|
1511
|
+
summary: {
|
|
1512
|
+
fileCount: output.count,
|
|
1513
|
+
exitCode: result.exitCode
|
|
1514
|
+
},
|
|
1515
|
+
duration_ms: durationMs
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1181
1518
|
} else if (output_mode === "count") {
|
|
1182
|
-
|
|
1519
|
+
output = parseCountOutput(result.stdout);
|
|
1520
|
+
if (debugId) {
|
|
1521
|
+
debugEnd(debugId, "grep", {
|
|
1522
|
+
summary: {
|
|
1523
|
+
total: output.total,
|
|
1524
|
+
exitCode: result.exitCode
|
|
1525
|
+
},
|
|
1526
|
+
duration_ms: durationMs
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1183
1529
|
} else {
|
|
1184
|
-
|
|
1530
|
+
output = parseContentOutput(result.stdout, head_limit, offset);
|
|
1531
|
+
if (debugId) {
|
|
1532
|
+
debugEnd(debugId, "grep", {
|
|
1533
|
+
summary: {
|
|
1534
|
+
matchCount: output.total_matches,
|
|
1535
|
+
exitCode: result.exitCode
|
|
1536
|
+
},
|
|
1537
|
+
duration_ms: durationMs
|
|
1538
|
+
});
|
|
1539
|
+
}
|
|
1185
1540
|
}
|
|
1541
|
+
return output;
|
|
1186
1542
|
} catch (error) {
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1543
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1544
|
+
if (debugId)
|
|
1545
|
+
debugError(debugId, "grep", errorMessage);
|
|
1546
|
+
return { error: errorMessage };
|
|
1190
1547
|
}
|
|
1191
1548
|
}
|
|
1192
1549
|
});
|
|
@@ -1253,7 +1610,7 @@ function parseCountOutput(stdout) {
|
|
|
1253
1610
|
total
|
|
1254
1611
|
};
|
|
1255
1612
|
}
|
|
1256
|
-
function parseContentOutput(stdout, head_limit, offset
|
|
1613
|
+
function parseContentOutput(stdout, head_limit, offset) {
|
|
1257
1614
|
const fileData = new Map;
|
|
1258
1615
|
for (const line of stdout.split(`
|
|
1259
1616
|
`).filter(Boolean)) {
|
|
@@ -1350,8 +1707,8 @@ import { tool as tool8, zodSchema as zodSchema8 } from "ai";
|
|
|
1350
1707
|
import { z as z8 } from "zod";
|
|
1351
1708
|
var readInputSchema = z8.object({
|
|
1352
1709
|
file_path: z8.string().describe("Absolute path to file or directory"),
|
|
1353
|
-
offset: z8.number().
|
|
1354
|
-
limit: z8.number().
|
|
1710
|
+
offset: z8.number().nullable().default(null).describe("Line number to start reading from (1-indexed)"),
|
|
1711
|
+
limit: z8.number().nullable().default(null).describe("Maximum number of lines to read")
|
|
1355
1712
|
});
|
|
1356
1713
|
var READ_DESCRIPTION = `Reads a file from the local filesystem. You can access any file directly by using this tool.
|
|
1357
1714
|
Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.
|
|
@@ -1377,20 +1734,35 @@ function createReadTool(sandbox, config) {
|
|
|
1377
1734
|
offset,
|
|
1378
1735
|
limit
|
|
1379
1736
|
}) => {
|
|
1737
|
+
const startTime = performance.now();
|
|
1738
|
+
const debugId = isDebugEnabled() ? debugStart("read", { file_path, offset, limit }) : "";
|
|
1380
1739
|
if (config?.allowedPaths) {
|
|
1381
1740
|
const isAllowed = config.allowedPaths.some((allowed) => file_path.startsWith(allowed));
|
|
1382
1741
|
if (!isAllowed) {
|
|
1383
|
-
|
|
1742
|
+
const error = `Path not allowed: ${file_path}`;
|
|
1743
|
+
if (debugId)
|
|
1744
|
+
debugError(debugId, "read", error);
|
|
1745
|
+
return { error };
|
|
1384
1746
|
}
|
|
1385
1747
|
}
|
|
1386
1748
|
try {
|
|
1387
1749
|
const exists = await sandbox.fileExists(file_path);
|
|
1388
1750
|
if (!exists) {
|
|
1389
|
-
|
|
1751
|
+
const error = `Path not found: ${file_path}`;
|
|
1752
|
+
if (debugId)
|
|
1753
|
+
debugError(debugId, "read", error);
|
|
1754
|
+
return { error };
|
|
1390
1755
|
}
|
|
1391
1756
|
const isDir = await sandbox.isDirectory(file_path);
|
|
1392
1757
|
if (isDir) {
|
|
1393
1758
|
const entries = await sandbox.readDir(file_path);
|
|
1759
|
+
const durationMs2 = Math.round(performance.now() - startTime);
|
|
1760
|
+
if (debugId) {
|
|
1761
|
+
debugEnd(debugId, "read", {
|
|
1762
|
+
summary: { type: "directory", count: entries.length },
|
|
1763
|
+
duration_ms: durationMs2
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1394
1766
|
return {
|
|
1395
1767
|
type: "directory",
|
|
1396
1768
|
entries,
|
|
@@ -1416,9 +1788,10 @@ function createReadTool(sandbox, config) {
|
|
|
1416
1788
|
"dylib"
|
|
1417
1789
|
];
|
|
1418
1790
|
if (binaryExtensions.includes(ext || "")) {
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1791
|
+
const error = `Cannot read binary file: ${file_path} (file exists, ${content.length} bytes). Use appropriate tools to process ${ext?.toUpperCase()} files (e.g., Python scripts for PDFs).`;
|
|
1792
|
+
if (debugId)
|
|
1793
|
+
debugError(debugId, "read", error);
|
|
1794
|
+
return { error };
|
|
1422
1795
|
}
|
|
1423
1796
|
}
|
|
1424
1797
|
const allLines = content.split(`
|
|
@@ -1426,9 +1799,10 @@ function createReadTool(sandbox, config) {
|
|
|
1426
1799
|
const totalLines = allLines.length;
|
|
1427
1800
|
const maxLinesWithoutLimit = config?.maxFileSize || 500;
|
|
1428
1801
|
if (!limit && totalLines > maxLinesWithoutLimit) {
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1802
|
+
const error = `File is large (${totalLines} lines). Use 'offset' and 'limit' to read in chunks. Example: offset=1, limit=100 for first 100 lines.`;
|
|
1803
|
+
if (debugId)
|
|
1804
|
+
debugError(debugId, "read", error);
|
|
1805
|
+
return { error };
|
|
1432
1806
|
}
|
|
1433
1807
|
const startLine = offset ? offset - 1 : 0;
|
|
1434
1808
|
const endLine = limit ? startLine + limit : allLines.length;
|
|
@@ -1437,6 +1811,18 @@ function createReadTool(sandbox, config) {
|
|
|
1437
1811
|
line_number: startLine + i + 1,
|
|
1438
1812
|
content: line
|
|
1439
1813
|
}));
|
|
1814
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
1815
|
+
if (debugId) {
|
|
1816
|
+
debugEnd(debugId, "read", {
|
|
1817
|
+
summary: {
|
|
1818
|
+
type: "text",
|
|
1819
|
+
totalLines,
|
|
1820
|
+
returnedLines: lines.length,
|
|
1821
|
+
bytes: content.length
|
|
1822
|
+
},
|
|
1823
|
+
duration_ms: durationMs
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1440
1826
|
return {
|
|
1441
1827
|
type: "text",
|
|
1442
1828
|
content: selectedLines.join(`
|
|
@@ -1445,9 +1831,10 @@ function createReadTool(sandbox, config) {
|
|
|
1445
1831
|
total_lines: totalLines
|
|
1446
1832
|
};
|
|
1447
1833
|
} catch (error) {
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1834
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1835
|
+
if (debugId)
|
|
1836
|
+
debugError(debugId, "read", errorMessage);
|
|
1837
|
+
return { error: errorMessage };
|
|
1451
1838
|
}
|
|
1452
1839
|
}
|
|
1453
1840
|
});
|
|
@@ -1481,22 +1868,29 @@ function createSkillTool(config) {
|
|
|
1481
1868
|
execute: async ({
|
|
1482
1869
|
name
|
|
1483
1870
|
}) => {
|
|
1871
|
+
const startTime = performance.now();
|
|
1872
|
+
const debugId = isDebugEnabled() ? debugStart("skill", { name, availableSkills: Object.keys(skills) }) : "";
|
|
1484
1873
|
try {
|
|
1485
1874
|
const skill = skills[name];
|
|
1486
1875
|
if (!skill) {
|
|
1487
1876
|
const available = Object.keys(skills);
|
|
1488
1877
|
if (available.length === 0) {
|
|
1489
|
-
|
|
1878
|
+
const error2 = "No skills are available.";
|
|
1879
|
+
if (debugId)
|
|
1880
|
+
debugError(debugId, "skill", error2);
|
|
1881
|
+
return { error: error2 };
|
|
1490
1882
|
}
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1883
|
+
const error = `Skill '${name}' not found. Available skills: ${available.join(", ")}`;
|
|
1884
|
+
if (debugId)
|
|
1885
|
+
debugError(debugId, "skill", error);
|
|
1886
|
+
return { error };
|
|
1494
1887
|
}
|
|
1495
1888
|
let instructions;
|
|
1496
1889
|
if (!sandbox) {
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1890
|
+
const error = `Cannot load skill '${name}': no sandbox provided to read ${skill.path}`;
|
|
1891
|
+
if (debugId)
|
|
1892
|
+
debugError(debugId, "skill", error);
|
|
1893
|
+
return { error };
|
|
1500
1894
|
}
|
|
1501
1895
|
const content = await sandbox.readFile(skill.path);
|
|
1502
1896
|
const frontmatterEnd = content.indexOf(`
|
|
@@ -1509,6 +1903,17 @@ function createSkillTool(config) {
|
|
|
1509
1903
|
if (onActivate) {
|
|
1510
1904
|
await onActivate(skill, instructions);
|
|
1511
1905
|
}
|
|
1906
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
1907
|
+
if (debugId) {
|
|
1908
|
+
debugEnd(debugId, "skill", {
|
|
1909
|
+
summary: {
|
|
1910
|
+
skillName: skill.name,
|
|
1911
|
+
instructionLength: instructions.length,
|
|
1912
|
+
hasAllowedTools: !!skill.allowedTools
|
|
1913
|
+
},
|
|
1914
|
+
duration_ms: durationMs
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1512
1917
|
return {
|
|
1513
1918
|
name: skill.name,
|
|
1514
1919
|
instructions,
|
|
@@ -1516,9 +1921,10 @@ function createSkillTool(config) {
|
|
|
1516
1921
|
message: skill.allowedTools ? `Skill '${name}' activated. Restricted to tools: ${skill.allowedTools.join(", ")}` : `Skill '${name}' activated. Follow the instructions below.`
|
|
1517
1922
|
};
|
|
1518
1923
|
} catch (error) {
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1924
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1925
|
+
if (debugId)
|
|
1926
|
+
debugError(debugId, "skill", errorMessage);
|
|
1927
|
+
return { error: errorMessage };
|
|
1522
1928
|
}
|
|
1523
1929
|
}
|
|
1524
1930
|
});
|
|
@@ -1613,6 +2019,11 @@ function createWebFetchTool(config) {
|
|
|
1613
2019
|
providerOptions,
|
|
1614
2020
|
execute: async (input) => {
|
|
1615
2021
|
const { url, prompt } = input;
|
|
2022
|
+
const startTime = performance.now();
|
|
2023
|
+
const debugId = isDebugEnabled() ? debugStart("web-fetch", {
|
|
2024
|
+
url,
|
|
2025
|
+
prompt: prompt.length > 200 ? `${prompt.slice(0, 200)}...` : prompt
|
|
2026
|
+
}) : "";
|
|
1616
2027
|
try {
|
|
1617
2028
|
const { content, finalUrl } = await fetchContent(url, apiKey, provider);
|
|
1618
2029
|
const result = await generateText({
|
|
@@ -1623,6 +2034,16 @@ Content from ${url}:
|
|
|
1623
2034
|
|
|
1624
2035
|
${content}`
|
|
1625
2036
|
});
|
|
2037
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
2038
|
+
if (debugId) {
|
|
2039
|
+
debugEnd(debugId, "web-fetch", {
|
|
2040
|
+
summary: {
|
|
2041
|
+
contentLength: content.length,
|
|
2042
|
+
responseLength: result.text.length
|
|
2043
|
+
},
|
|
2044
|
+
duration_ms: durationMs
|
|
2045
|
+
});
|
|
2046
|
+
}
|
|
1626
2047
|
return {
|
|
1627
2048
|
response: result.text,
|
|
1628
2049
|
url,
|
|
@@ -1632,15 +2053,18 @@ ${content}`
|
|
|
1632
2053
|
if (error && typeof error === "object" && "status" in error) {
|
|
1633
2054
|
const statusCode = error.status;
|
|
1634
2055
|
const message = error.message || "API request failed";
|
|
2056
|
+
if (debugId)
|
|
2057
|
+
debugError(debugId, "web-fetch", `${message} (status: ${statusCode})`);
|
|
1635
2058
|
return {
|
|
1636
2059
|
error: message,
|
|
1637
2060
|
status_code: statusCode,
|
|
1638
2061
|
retryable: RETRYABLE_STATUS_CODES.includes(statusCode)
|
|
1639
2062
|
};
|
|
1640
2063
|
}
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
2064
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
2065
|
+
if (debugId)
|
|
2066
|
+
debugError(debugId, "web-fetch", errorMessage);
|
|
2067
|
+
return { error: errorMessage };
|
|
1644
2068
|
}
|
|
1645
2069
|
}
|
|
1646
2070
|
});
|
|
@@ -1697,8 +2121,8 @@ async function searchContent(apiKey, provider, options) {
|
|
|
1697
2121
|
}
|
|
1698
2122
|
var webSearchInputSchema = z11.object({
|
|
1699
2123
|
query: z11.string().describe("The search query to use"),
|
|
1700
|
-
allowed_domains: z11.array(z11.string()).
|
|
1701
|
-
blocked_domains: z11.array(z11.string()).
|
|
2124
|
+
allowed_domains: z11.array(z11.string()).nullable().default(null).describe("Only include results from these domains"),
|
|
2125
|
+
blocked_domains: z11.array(z11.string()).nullable().default(null).describe("Never include results from these domains")
|
|
1702
2126
|
});
|
|
1703
2127
|
var WEB_SEARCH_DESCRIPTION = `Searches the web and returns results with links. Use this for accessing up-to-date information beyond your knowledge cutoff.
|
|
1704
2128
|
|
|
@@ -1736,12 +2160,22 @@ function createWebSearchTool(config) {
|
|
|
1736
2160
|
providerOptions,
|
|
1737
2161
|
execute: async (input) => {
|
|
1738
2162
|
const { query, allowed_domains, blocked_domains } = input;
|
|
2163
|
+
const startTime = performance.now();
|
|
2164
|
+
const debugId = isDebugEnabled() ? debugStart("web-search", { query, allowed_domains, blocked_domains }) : "";
|
|
1739
2165
|
try {
|
|
1740
2166
|
const results = await searchContent(apiKey, provider, {
|
|
1741
2167
|
query,
|
|
1742
2168
|
allowedDomains: allowed_domains,
|
|
1743
2169
|
blockedDomains: blocked_domains
|
|
1744
2170
|
});
|
|
2171
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
2172
|
+
if (debugId) {
|
|
2173
|
+
debugEnd(debugId, "web-search", {
|
|
2174
|
+
summary: { resultCount: results.length },
|
|
2175
|
+
output: results.slice(0, 5).map((r) => ({ title: r.title, url: r.url })),
|
|
2176
|
+
duration_ms: durationMs
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
1745
2179
|
return {
|
|
1746
2180
|
results,
|
|
1747
2181
|
total_results: results.length,
|
|
@@ -1751,15 +2185,18 @@ function createWebSearchTool(config) {
|
|
|
1751
2185
|
if (error && typeof error === "object" && "status" in error) {
|
|
1752
2186
|
const statusCode = error.status;
|
|
1753
2187
|
const message = error.message || "API request failed";
|
|
2188
|
+
if (debugId)
|
|
2189
|
+
debugError(debugId, "web-search", `${message} (status: ${statusCode})`);
|
|
1754
2190
|
return {
|
|
1755
2191
|
error: message,
|
|
1756
2192
|
status_code: statusCode,
|
|
1757
2193
|
retryable: RETRYABLE_STATUS_CODES.includes(statusCode)
|
|
1758
2194
|
};
|
|
1759
2195
|
}
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
2196
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
2197
|
+
if (debugId)
|
|
2198
|
+
debugError(debugId, "web-search", errorMessage);
|
|
2199
|
+
return { error: errorMessage };
|
|
1763
2200
|
}
|
|
1764
2201
|
}
|
|
1765
2202
|
});
|
|
@@ -1795,29 +2232,43 @@ function createWriteTool(sandbox, config) {
|
|
|
1795
2232
|
file_path,
|
|
1796
2233
|
content
|
|
1797
2234
|
}) => {
|
|
2235
|
+
const startTime = performance.now();
|
|
1798
2236
|
const byteLength = Buffer.byteLength(content, "utf-8");
|
|
2237
|
+
const debugId = isDebugEnabled() ? debugStart("write", { file_path, contentLength: byteLength }) : "";
|
|
1799
2238
|
if (config?.maxFileSize && byteLength > config.maxFileSize) {
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
2239
|
+
const error = `File content exceeds maximum size of ${config.maxFileSize} bytes (got ${byteLength})`;
|
|
2240
|
+
if (debugId)
|
|
2241
|
+
debugError(debugId, "write", error);
|
|
2242
|
+
return { error };
|
|
1803
2243
|
}
|
|
1804
2244
|
if (config?.allowedPaths) {
|
|
1805
2245
|
const isAllowed = config.allowedPaths.some((allowed) => file_path.startsWith(allowed));
|
|
1806
2246
|
if (!isAllowed) {
|
|
1807
|
-
|
|
2247
|
+
const error = `Path not allowed: ${file_path}`;
|
|
2248
|
+
if (debugId)
|
|
2249
|
+
debugError(debugId, "write", error);
|
|
2250
|
+
return { error };
|
|
1808
2251
|
}
|
|
1809
2252
|
}
|
|
1810
2253
|
try {
|
|
1811
2254
|
await sandbox.writeFile(file_path, content);
|
|
2255
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
2256
|
+
if (debugId) {
|
|
2257
|
+
debugEnd(debugId, "write", {
|
|
2258
|
+
summary: { bytes_written: byteLength },
|
|
2259
|
+
duration_ms: durationMs
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
1812
2262
|
return {
|
|
1813
2263
|
message: `Successfully wrote to ${file_path}`,
|
|
1814
2264
|
bytes_written: byteLength,
|
|
1815
2265
|
file_path
|
|
1816
2266
|
};
|
|
1817
2267
|
} catch (error) {
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
2268
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
2269
|
+
if (debugId)
|
|
2270
|
+
debugError(debugId, "write", errorMessage);
|
|
2271
|
+
return { error: errorMessage };
|
|
1821
2272
|
}
|
|
1822
2273
|
}
|
|
1823
2274
|
});
|
|
@@ -1835,8 +2286,8 @@ var taskInputSchema = z13.object({
|
|
|
1835
2286
|
description: z13.string().describe("A short (3-5 word) description of the task"),
|
|
1836
2287
|
prompt: z13.string().describe("The task for the agent to perform"),
|
|
1837
2288
|
subagent_type: z13.string().describe("The type of specialized agent to use for this task"),
|
|
1838
|
-
system_prompt: z13.string().
|
|
1839
|
-
tools: z13.array(z13.string()).
|
|
2289
|
+
system_prompt: z13.string().nullable().default(null).describe("Optional custom system prompt for this agent. If provided, overrides the default system prompt for the subagent type. Use this to create dynamic, specialized agents on the fly."),
|
|
2290
|
+
tools: z13.array(z13.string()).nullable().default(null).describe("Optional list of tool names this agent can use (e.g., ['Read', 'Grep', 'WebSearch']). If provided, overrides the default tools for the subagent type. Use this to restrict or expand the agent's capabilities.")
|
|
1840
2291
|
});
|
|
1841
2292
|
var TASK_DESCRIPTION = `Launch a new agent to handle complex, multi-step tasks autonomously.
|
|
1842
2293
|
|
|
@@ -1864,16 +2315,22 @@ var eventCounter = 0;
|
|
|
1864
2315
|
function generateEventId() {
|
|
1865
2316
|
return `subagent-${Date.now()}-${++eventCounter}`;
|
|
1866
2317
|
}
|
|
1867
|
-
function filterTools(allTools, allowedTools) {
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
2318
|
+
function filterTools(allTools, allowedTools, additionalTools) {
|
|
2319
|
+
let result;
|
|
2320
|
+
if (allowedTools) {
|
|
2321
|
+
result = {};
|
|
2322
|
+
for (const name of allowedTools) {
|
|
2323
|
+
if (allTools[name]) {
|
|
2324
|
+
result[name] = allTools[name];
|
|
2325
|
+
}
|
|
1874
2326
|
}
|
|
2327
|
+
} else {
|
|
2328
|
+
result = allTools;
|
|
2329
|
+
}
|
|
2330
|
+
if (additionalTools) {
|
|
2331
|
+
result = { ...result, ...additionalTools };
|
|
1875
2332
|
}
|
|
1876
|
-
return
|
|
2333
|
+
return result;
|
|
1877
2334
|
}
|
|
1878
2335
|
function createTaskTool(config) {
|
|
1879
2336
|
const {
|
|
@@ -1895,10 +2352,20 @@ function createTaskTool(config) {
|
|
|
1895
2352
|
tools: customTools
|
|
1896
2353
|
}) => {
|
|
1897
2354
|
const startTime = performance.now();
|
|
2355
|
+
const typeConfig = subagentTypes[subagent_type] || {};
|
|
2356
|
+
const debugId = isDebugEnabled() ? debugStart("task", {
|
|
2357
|
+
subagent_type,
|
|
2358
|
+
description,
|
|
2359
|
+
tools: [
|
|
2360
|
+
...customTools ?? typeConfig.tools ?? Object.keys(allTools),
|
|
2361
|
+
...Object.keys(typeConfig.additionalTools ?? {})
|
|
2362
|
+
]
|
|
2363
|
+
}) : "";
|
|
2364
|
+
if (debugId)
|
|
2365
|
+
pushParent(debugId);
|
|
1898
2366
|
try {
|
|
1899
|
-
const typeConfig = subagentTypes[subagent_type] || {};
|
|
1900
2367
|
const model = typeConfig.model || defaultModel;
|
|
1901
|
-
const tools = filterTools(allTools, customTools ?? typeConfig.tools);
|
|
2368
|
+
const tools = filterTools(allTools, customTools ?? typeConfig.tools, typeConfig.additionalTools);
|
|
1902
2369
|
const systemPrompt = system_prompt ?? typeConfig.systemPrompt;
|
|
1903
2370
|
const commonOptions = {
|
|
1904
2371
|
model,
|
|
@@ -1969,6 +2436,19 @@ function createTaskTool(config) {
|
|
|
1969
2436
|
}
|
|
1970
2437
|
});
|
|
1971
2438
|
const durationMs2 = Math.round(performance.now() - startTime);
|
|
2439
|
+
if (debugId) {
|
|
2440
|
+
popParent();
|
|
2441
|
+
debugEnd(debugId, "task", {
|
|
2442
|
+
summary: {
|
|
2443
|
+
tokens: {
|
|
2444
|
+
input: usage2.inputTokens,
|
|
2445
|
+
output: usage2.outputTokens
|
|
2446
|
+
},
|
|
2447
|
+
steps: response.messages?.length
|
|
2448
|
+
},
|
|
2449
|
+
duration_ms: durationMs2
|
|
2450
|
+
});
|
|
2451
|
+
}
|
|
1972
2452
|
return {
|
|
1973
2453
|
result: text,
|
|
1974
2454
|
usage: usage2.inputTokens !== undefined && usage2.outputTokens !== undefined ? {
|
|
@@ -1996,6 +2476,19 @@ function createTaskTool(config) {
|
|
|
1996
2476
|
input_tokens: result.usage.inputTokens,
|
|
1997
2477
|
output_tokens: result.usage.outputTokens
|
|
1998
2478
|
} : undefined;
|
|
2479
|
+
if (debugId) {
|
|
2480
|
+
popParent();
|
|
2481
|
+
debugEnd(debugId, "task", {
|
|
2482
|
+
summary: {
|
|
2483
|
+
tokens: {
|
|
2484
|
+
input: result.usage.inputTokens,
|
|
2485
|
+
output: result.usage.outputTokens
|
|
2486
|
+
},
|
|
2487
|
+
steps: result.steps?.length
|
|
2488
|
+
},
|
|
2489
|
+
duration_ms: durationMs
|
|
2490
|
+
});
|
|
2491
|
+
}
|
|
1999
2492
|
return {
|
|
2000
2493
|
result: result.text,
|
|
2001
2494
|
usage,
|
|
@@ -2005,6 +2498,10 @@ function createTaskTool(config) {
|
|
|
2005
2498
|
};
|
|
2006
2499
|
} catch (error) {
|
|
2007
2500
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
2501
|
+
if (debugId) {
|
|
2502
|
+
popParent();
|
|
2503
|
+
debugError(debugId, "task", errorMessage);
|
|
2504
|
+
}
|
|
2008
2505
|
return { error: errorMessage };
|
|
2009
2506
|
}
|
|
2010
2507
|
}
|
|
@@ -2052,15 +2549,22 @@ var TODO_WRITE_DESCRIPTION = `Use this tool to create and manage a structured ta
|
|
|
2052
2549
|
- Keep exactly ONE task in_progress at any time
|
|
2053
2550
|
- ONLY mark completed when FULLY accomplished
|
|
2054
2551
|
- If blocked/errors, keep in_progress and create new task for the blocker`;
|
|
2055
|
-
function createTodoWriteTool(
|
|
2552
|
+
function createTodoWriteTool(state2, onUpdate) {
|
|
2056
2553
|
return tool14({
|
|
2057
2554
|
description: TODO_WRITE_DESCRIPTION,
|
|
2058
2555
|
inputSchema: zodSchema14(todoWriteInputSchema),
|
|
2059
2556
|
execute: async ({
|
|
2060
2557
|
todos
|
|
2061
2558
|
}) => {
|
|
2559
|
+
const startTime = performance.now();
|
|
2560
|
+
const debugId = isDebugEnabled() ? debugStart("todo-write", {
|
|
2561
|
+
todoCount: todos.length,
|
|
2562
|
+
pending: todos.filter((t) => t.status === "pending").length,
|
|
2563
|
+
in_progress: todos.filter((t) => t.status === "in_progress").length,
|
|
2564
|
+
completed: todos.filter((t) => t.status === "completed").length
|
|
2565
|
+
}) : "";
|
|
2062
2566
|
try {
|
|
2063
|
-
|
|
2567
|
+
state2.todos = todos;
|
|
2064
2568
|
if (onUpdate) {
|
|
2065
2569
|
onUpdate(todos);
|
|
2066
2570
|
}
|
|
@@ -2070,14 +2574,22 @@ function createTodoWriteTool(state, onUpdate) {
|
|
|
2070
2574
|
in_progress: todos.filter((t) => t.status === "in_progress").length,
|
|
2071
2575
|
completed: todos.filter((t) => t.status === "completed").length
|
|
2072
2576
|
};
|
|
2577
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
2578
|
+
if (debugId) {
|
|
2579
|
+
debugEnd(debugId, "todo-write", {
|
|
2580
|
+
summary: stats,
|
|
2581
|
+
duration_ms: durationMs
|
|
2582
|
+
});
|
|
2583
|
+
}
|
|
2073
2584
|
return {
|
|
2074
2585
|
message: "Todo list updated successfully",
|
|
2075
2586
|
stats
|
|
2076
2587
|
};
|
|
2077
2588
|
} catch (error) {
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2589
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
2590
|
+
if (debugId)
|
|
2591
|
+
debugError(debugId, "todo-write", errorMessage);
|
|
2592
|
+
return { error: errorMessage };
|
|
2081
2593
|
}
|
|
2082
2594
|
}
|
|
2083
2595
|
});
|
|
@@ -2326,20 +2838,20 @@ function pruneMessagesByTokens(messages, config) {
|
|
|
2326
2838
|
}
|
|
2327
2839
|
|
|
2328
2840
|
// src/utils/compact-conversation.ts
|
|
2329
|
-
async function compactConversation(messages, config,
|
|
2841
|
+
async function compactConversation(messages, config, state2 = { conversationSummary: "" }) {
|
|
2330
2842
|
const currentTokens = estimateMessagesTokens(messages);
|
|
2331
2843
|
const threshold = config.compactionThreshold ?? 0.85;
|
|
2332
2844
|
const limit = config.maxTokens * threshold;
|
|
2333
2845
|
if (currentTokens < limit) {
|
|
2334
|
-
return { messages, state, didCompact: false };
|
|
2846
|
+
return { messages, state: state2, didCompact: false };
|
|
2335
2847
|
}
|
|
2336
2848
|
const protectCount = config.protectRecentMessages ?? 10;
|
|
2337
2849
|
const recentMessages = messages.slice(-protectCount);
|
|
2338
2850
|
const oldMessages = messages.slice(0, -protectCount);
|
|
2339
2851
|
if (oldMessages.length === 0) {
|
|
2340
|
-
return { messages, state, didCompact: false };
|
|
2852
|
+
return { messages, state: state2, didCompact: false };
|
|
2341
2853
|
}
|
|
2342
|
-
const newSummary = await summarizeMessages(oldMessages, config.summarizerModel, config.taskContext,
|
|
2854
|
+
const newSummary = await summarizeMessages(oldMessages, config.summarizerModel, config.taskContext, state2.conversationSummary);
|
|
2343
2855
|
const compactedMessages = [
|
|
2344
2856
|
{
|
|
2345
2857
|
role: "user",
|
|
@@ -2874,10 +3386,13 @@ async function createDirectory(sandbox, path) {
|
|
|
2874
3386
|
export {
|
|
2875
3387
|
skillsToXml,
|
|
2876
3388
|
setupAgentEnvironment,
|
|
3389
|
+
reinitDebugMode,
|
|
2877
3390
|
pruneMessagesByTokens,
|
|
2878
3391
|
parseSkillMetadata,
|
|
2879
3392
|
loadSkillBundles,
|
|
2880
3393
|
loadSkillBundle,
|
|
3394
|
+
isDebugEnabled,
|
|
3395
|
+
getDebugLogs,
|
|
2881
3396
|
getContextStatus,
|
|
2882
3397
|
fetchSkills,
|
|
2883
3398
|
fetchSkill,
|
|
@@ -2909,6 +3424,7 @@ export {
|
|
|
2909
3424
|
contextNeedsCompaction,
|
|
2910
3425
|
contextNeedsAttention,
|
|
2911
3426
|
compactConversation,
|
|
3427
|
+
clearDebugLogs,
|
|
2912
3428
|
cached,
|
|
2913
3429
|
anthropicPromptCacheMiddlewareV2,
|
|
2914
3430
|
anthropicPromptCacheMiddleware,
|