@amical/aiagent-sdk 0.1.11 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{WebMemoryManager-DXxLUDBB.d.ts → WebMemoryManager-BZNjinHF.d.ts} +10 -3
- package/dist/{WebMemoryManager-Bk19j8i6.d.mts → WebMemoryManager-DpaY-f0l.d.mts} +10 -3
- package/dist/index.d.mts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +100 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +100 -17
- package/dist/index.mjs.map +1 -1
- package/dist/runtime/nodeRuntime.d.mts +11 -2
- package/dist/runtime/nodeRuntime.d.ts +11 -2
- package/dist/runtime/nodeRuntime.js +230 -30
- package/dist/runtime/nodeRuntime.js.map +1 -1
- package/dist/runtime/nodeRuntime.mjs +230 -30
- package/dist/runtime/nodeRuntime.mjs.map +1 -1
- package/dist/runtime/webRuntime.d.mts +2 -1
- package/dist/runtime/webRuntime.d.ts +2 -1
- package/dist/runtime/webRuntime.js +230 -30
- package/dist/runtime/webRuntime.js.map +1 -1
- package/dist/runtime/webRuntime.mjs +230 -30
- package/dist/runtime/webRuntime.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -135,9 +135,11 @@ return (
|
|
|
135
135
|
},
|
|
136
136
|
{
|
|
137
137
|
name: "agent_read_file" /* FILE_READ */,
|
|
138
|
-
description: "Read the contents of a specific file.",
|
|
138
|
+
description: "Read the contents of a specific file. The returned content includes line numbers (e.g. '10|const x = 1;') so you can reference exact lines when editing.",
|
|
139
139
|
params: {
|
|
140
|
-
path: "(required) The absolute or relative file path to read."
|
|
140
|
+
path: "(required) The absolute or relative file path to read.",
|
|
141
|
+
start_line: "(optional) The 1-based line number to start reading from (inclusive). Defaults to 1.",
|
|
142
|
+
end_line: "(optional) The 1-based line number to stop reading at (inclusive). Defaults to the last line."
|
|
141
143
|
}
|
|
142
144
|
},
|
|
143
145
|
{
|
|
@@ -580,7 +582,17 @@ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
580
582
|
"dockerfile",
|
|
581
583
|
"makefile",
|
|
582
584
|
"properties",
|
|
583
|
-
"lock"
|
|
585
|
+
"lock",
|
|
586
|
+
"node-version",
|
|
587
|
+
"nvmrc",
|
|
588
|
+
"editorconfig",
|
|
589
|
+
"prettierrc",
|
|
590
|
+
"eslintrc",
|
|
591
|
+
"babelrc",
|
|
592
|
+
"stylelintrc",
|
|
593
|
+
"huskyrc",
|
|
594
|
+
"commitlintrc",
|
|
595
|
+
"lintstagedrc"
|
|
584
596
|
]);
|
|
585
597
|
var AgentState = /* @__PURE__ */ ((AgentState2) => {
|
|
586
598
|
AgentState2["IDLE"] = "idle";
|
|
@@ -671,6 +683,13 @@ var ClineAgent = class {
|
|
|
671
683
|
}
|
|
672
684
|
this.skillDir = this.runtime.path.join(this.runtime.env.cwd(), ".agents/skills");
|
|
673
685
|
this.rulesDir = this.runtime.path.join(this.runtime.env.cwd(), ".agents/rules");
|
|
686
|
+
const originalOnCondense = this.memory.onCondense;
|
|
687
|
+
this.memory.onCondense = async () => {
|
|
688
|
+
this.api.clearConversationId();
|
|
689
|
+
if (originalOnCondense) {
|
|
690
|
+
await originalOnCondense();
|
|
691
|
+
}
|
|
692
|
+
};
|
|
674
693
|
}
|
|
675
694
|
setState(newState) {
|
|
676
695
|
this.state = newState;
|
|
@@ -728,16 +747,6 @@ var ClineAgent = class {
|
|
|
728
747
|
async getAgentRules() {
|
|
729
748
|
const cwd = this.runtime.env.cwd();
|
|
730
749
|
const rules = [];
|
|
731
|
-
const agentsMdPath = this.runtime.path.join(cwd, "Agents.md");
|
|
732
|
-
try {
|
|
733
|
-
if (await this.runtime.fs.fileExists(agentsMdPath)) {
|
|
734
|
-
const content = await this.runtime.fs.readFile(agentsMdPath);
|
|
735
|
-
if (content && content.trim()) {
|
|
736
|
-
rules.push(content.trim());
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
} catch (e) {
|
|
740
|
-
}
|
|
741
750
|
try {
|
|
742
751
|
if (await this.runtime.fs.fileExists(this.rulesDir)) {
|
|
743
752
|
const files = await this.runtime.fs.readDir(this.rulesDir);
|
|
@@ -763,6 +772,28 @@ ${content.trim()}\`\`\``);
|
|
|
763
772
|
}
|
|
764
773
|
} catch (e) {
|
|
765
774
|
}
|
|
775
|
+
try {
|
|
776
|
+
const getAgentsMdPath = async () => {
|
|
777
|
+
const agentsMdPathList = [
|
|
778
|
+
this.runtime.path.join(cwd, "AGENTS.md"),
|
|
779
|
+
this.runtime.path.join(cwd, "Agents.md"),
|
|
780
|
+
this.runtime.path.join(cwd, "agents.md")
|
|
781
|
+
];
|
|
782
|
+
for (const item of agentsMdPathList) {
|
|
783
|
+
if (await this.runtime.fs.fileExists(item)) {
|
|
784
|
+
return item;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
const agentsMdPath = await getAgentsMdPath();
|
|
789
|
+
if (agentsMdPath) {
|
|
790
|
+
const content = await this.runtime.fs.readFile(agentsMdPath);
|
|
791
|
+
if (content && content.trim()) {
|
|
792
|
+
rules.push(content.trim());
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
} catch (e) {
|
|
796
|
+
}
|
|
766
797
|
return rules.join("\n---\n");
|
|
767
798
|
}
|
|
768
799
|
async getSkills() {
|
|
@@ -900,7 +931,8 @@ ${finalPrompt}` : finalPrompt;
|
|
|
900
931
|
if (path2) {
|
|
901
932
|
try {
|
|
902
933
|
const content = await this.runtime.fs.readFile(path2);
|
|
903
|
-
|
|
934
|
+
const result = this.formatFileContentWithLineNumbers(content, tool.params.start_line, tool.params.end_line);
|
|
935
|
+
toolResults.push({ tool, result });
|
|
904
936
|
} catch (error) {
|
|
905
937
|
toolResults.push({ tool, result: `Error: ${error.message}` });
|
|
906
938
|
}
|
|
@@ -913,6 +945,8 @@ ${finalPrompt}` : finalPrompt;
|
|
|
913
945
|
const result = await this.runtime.terminal.execCommand(cmd);
|
|
914
946
|
toolResults.push({ tool, result: `STDOUT: ${result.stdout}
|
|
915
947
|
STDERR: ${result.stderr}` });
|
|
948
|
+
} else {
|
|
949
|
+
toolResults.push({ tool, result: "Error: No command provided." });
|
|
916
950
|
}
|
|
917
951
|
} else if (tool.name === "agent_write_to_file" /* FILE_NEW */) {
|
|
918
952
|
const path2 = tool.params.path;
|
|
@@ -924,12 +958,18 @@ STDERR: ${result.stderr}` });
|
|
|
924
958
|
} catch (error) {
|
|
925
959
|
toolResults.push({ tool, result: `Error: ${error.message}` });
|
|
926
960
|
}
|
|
961
|
+
} else {
|
|
962
|
+
toolResults.push({ tool, result: "Error: Missing path or content." });
|
|
927
963
|
}
|
|
928
964
|
} else if (tool.name === "agent_list_files" /* LIST_FILES */) {
|
|
929
965
|
const path2 = tool.params.path || this.runtime.env.cwd();
|
|
966
|
+
const recursive = tool.params.recursive === "true";
|
|
930
967
|
try {
|
|
931
|
-
const files = await this.runtime.fs.readDir(path2);
|
|
932
|
-
toolResults.push({
|
|
968
|
+
const files = await this.runtime.fs.readDir(path2, { recursive });
|
|
969
|
+
toolResults.push({
|
|
970
|
+
tool,
|
|
971
|
+
result: files.map((f) => `${f.isDirectory() ? "[DIR] " : " "}${f.name}${f.isDirectory() ? "/" : ""}`).join("\n")
|
|
972
|
+
});
|
|
933
973
|
} catch (e) {
|
|
934
974
|
toolResults.push({ tool, result: `Error: ${e.message}` });
|
|
935
975
|
}
|
|
@@ -1069,10 +1109,15 @@ STDERR: ${result.stderr}` });
|
|
|
1069
1109
|
try {
|
|
1070
1110
|
const res = await fetch(url);
|
|
1071
1111
|
const text = await res.text();
|
|
1072
|
-
|
|
1112
|
+
const MAX_LEN = 8e3;
|
|
1113
|
+
const truncated = text.length > MAX_LEN ? `${text.substring(0, MAX_LEN)}
|
|
1114
|
+
...[truncated ${text.length - MAX_LEN} chars]` : text;
|
|
1115
|
+
toolResults.push({ tool, result: truncated });
|
|
1073
1116
|
} catch (e) {
|
|
1074
1117
|
toolResults.push({ tool, result: `Error: ${e.message}` });
|
|
1075
1118
|
}
|
|
1119
|
+
} else {
|
|
1120
|
+
toolResults.push({ tool, result: "Error: No url provided." });
|
|
1076
1121
|
}
|
|
1077
1122
|
} else if (tool.name === "agent_focus_chain" /* TODO */) {
|
|
1078
1123
|
toolResults.push({ tool, result: `Focus chain updated successfully.` });
|
|
@@ -1160,6 +1205,44 @@ ${this.promptManager.getUsedToolResultInstructions()}`;
|
|
|
1160
1205
|
}
|
|
1161
1206
|
return this.getPrompt();
|
|
1162
1207
|
}
|
|
1208
|
+
/**
|
|
1209
|
+
* 将文件内容格式化为带行号文本(模拟编辑器行号显示),
|
|
1210
|
+
* 支持通过 start_line / end_line 截取读取范围。
|
|
1211
|
+
*/
|
|
1212
|
+
formatFileContentWithLineNumbers(content, startLineParam, endLineParam) {
|
|
1213
|
+
const lines = content.split(/\r?\n/);
|
|
1214
|
+
const normalized = lines.length > 0 && lines[lines.length - 1] === "" ? lines.slice(0, -1) : lines;
|
|
1215
|
+
const total = normalized.length;
|
|
1216
|
+
if (total === 0) {
|
|
1217
|
+
return "1|(empty file)";
|
|
1218
|
+
}
|
|
1219
|
+
const parseLine = (val, fallback) => {
|
|
1220
|
+
if (val === void 0 || val === null || val.trim() === "") {
|
|
1221
|
+
return fallback;
|
|
1222
|
+
}
|
|
1223
|
+
const num = Number.parseInt(val, 10);
|
|
1224
|
+
if (!Number.isFinite(num) || num <= 0) {
|
|
1225
|
+
return fallback;
|
|
1226
|
+
}
|
|
1227
|
+
return num;
|
|
1228
|
+
};
|
|
1229
|
+
const start = parseLine(startLineParam, 1);
|
|
1230
|
+
const end = parseLine(endLineParam, total);
|
|
1231
|
+
if (start > end) {
|
|
1232
|
+
return `Error: start_line (${start}) cannot be greater than end_line (${end}).`;
|
|
1233
|
+
}
|
|
1234
|
+
if (start > total) {
|
|
1235
|
+
return `Error: start_line (${start}) is out of range. The file has ${total} lines.`;
|
|
1236
|
+
}
|
|
1237
|
+
const from = Math.max(1, start);
|
|
1238
|
+
const to = Math.min(total, end);
|
|
1239
|
+
const width = String(total).length;
|
|
1240
|
+
const selected = normalized.slice(from - 1, to);
|
|
1241
|
+
const numbered = selected.map((line, idx) => `${String(from + idx).padStart(width)}|${line}`).join("\n");
|
|
1242
|
+
const header = from === 1 && to === total ? `1-${total}/${total}` : `${from}-${to}/${total}`;
|
|
1243
|
+
return `${header}
|
|
1244
|
+
${numbered}`;
|
|
1245
|
+
}
|
|
1163
1246
|
/**
|
|
1164
1247
|
* 简单的 Diff 解析与替换辅助方法
|
|
1165
1248
|
*/
|
|
@@ -1409,6 +1492,9 @@ var WebApiHandler = class {
|
|
|
1409
1492
|
};
|
|
1410
1493
|
}
|
|
1411
1494
|
}
|
|
1495
|
+
clearConversationId() {
|
|
1496
|
+
this.conversationId = void 0;
|
|
1497
|
+
}
|
|
1412
1498
|
};
|
|
1413
1499
|
|
|
1414
1500
|
// src/prompt/WebPromptManager.ts
|
|
@@ -1714,16 +1800,127 @@ ${this?.getEnvironmentInfoPrompt?.(context)}`;
|
|
|
1714
1800
|
}
|
|
1715
1801
|
};
|
|
1716
1802
|
|
|
1803
|
+
// src/memory/condense.ts
|
|
1804
|
+
var TOOL_RESULT_CONTENT_REGEX = /<tool_call_result[^>]*>[\s\S]*?<\/tool_call_result>/;
|
|
1805
|
+
var EXPIRED_MARKER_TEXT = "[The result has expired and has been removed from the context]";
|
|
1806
|
+
var ATTEMPT_TOOL_NAME = "agent_attempt_completion" /* ATTEMPT */;
|
|
1807
|
+
function getContentString(content) {
|
|
1808
|
+
return typeof content === "string" ? content : "";
|
|
1809
|
+
}
|
|
1810
|
+
function isToolResultMessage(content) {
|
|
1811
|
+
if (typeof content !== "string") {
|
|
1812
|
+
return false;
|
|
1813
|
+
}
|
|
1814
|
+
return TOOL_RESULT_CONTENT_REGEX.test(content);
|
|
1815
|
+
}
|
|
1816
|
+
function isAttemptCallMessage(message) {
|
|
1817
|
+
if (message.role !== "assistant") {
|
|
1818
|
+
return false;
|
|
1819
|
+
}
|
|
1820
|
+
const content = getContentString(message.content);
|
|
1821
|
+
return new RegExp(`<${ATTEMPT_TOOL_NAME}[\\s>]`).test(content) || new RegExp(`<name>\\s*${ATTEMPT_TOOL_NAME}\\s*</name>`).test(content);
|
|
1822
|
+
}
|
|
1823
|
+
function markExpiredToolResult(content) {
|
|
1824
|
+
if (typeof content !== "string") {
|
|
1825
|
+
return content;
|
|
1826
|
+
}
|
|
1827
|
+
return content.replace(
|
|
1828
|
+
/(<tool_call_result[^>]*tool_name="([^"]*)"[^>]*>)[\s\S]*?(<\/tool_call_result>)/g,
|
|
1829
|
+
(_match, openTag, _toolName, closeTag) => {
|
|
1830
|
+
return `${openTag}
|
|
1831
|
+
${EXPIRED_MARKER_TEXT}
|
|
1832
|
+
${closeTag}`;
|
|
1833
|
+
}
|
|
1834
|
+
);
|
|
1835
|
+
}
|
|
1836
|
+
function splitConversations(messages) {
|
|
1837
|
+
const conversations = [];
|
|
1838
|
+
let current = [];
|
|
1839
|
+
for (const message of messages) {
|
|
1840
|
+
current.push(message);
|
|
1841
|
+
if (isAttemptCallMessage(message)) {
|
|
1842
|
+
conversations.push(current);
|
|
1843
|
+
current = [];
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
if (current.length > 0) {
|
|
1847
|
+
conversations.push(current);
|
|
1848
|
+
}
|
|
1849
|
+
return conversations;
|
|
1850
|
+
}
|
|
1851
|
+
function isCompleteConversation(conversation) {
|
|
1852
|
+
if (conversation.length === 0) {
|
|
1853
|
+
return false;
|
|
1854
|
+
}
|
|
1855
|
+
return isAttemptCallMessage(conversation[conversation.length - 1]);
|
|
1856
|
+
}
|
|
1857
|
+
function compressCompleteConversation(conversation) {
|
|
1858
|
+
if (conversation.length <= 2) {
|
|
1859
|
+
return conversation;
|
|
1860
|
+
}
|
|
1861
|
+
const head = conversation[0];
|
|
1862
|
+
const tail = conversation[conversation.length - 1];
|
|
1863
|
+
const mergedMarker = {
|
|
1864
|
+
role: "user",
|
|
1865
|
+
content: "[History Condensed] The intermediate tool calls and tool call results of this conversation have been merged. Please refer to the `agent_attempt_completion` summary below for the final conclusion."
|
|
1866
|
+
};
|
|
1867
|
+
return [head, mergedMarker, tail];
|
|
1868
|
+
}
|
|
1869
|
+
function markExpiredFirstHalf(messages) {
|
|
1870
|
+
const half = Math.floor(messages.length / 2);
|
|
1871
|
+
return messages.map((message, index) => {
|
|
1872
|
+
if (index < half && isToolResultMessage(message.content)) {
|
|
1873
|
+
return { ...message, content: markExpiredToolResult(message.content) };
|
|
1874
|
+
}
|
|
1875
|
+
return message;
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
function condenseMessages(messages, maxMessages) {
|
|
1879
|
+
if (messages.length <= maxMessages) {
|
|
1880
|
+
return messages;
|
|
1881
|
+
}
|
|
1882
|
+
const systemMessages = messages.filter((message) => message.role === "system");
|
|
1883
|
+
const restMessages = messages.filter((message) => message.role !== "system");
|
|
1884
|
+
const conversations = splitConversations(restMessages);
|
|
1885
|
+
const completeIndices = [];
|
|
1886
|
+
for (let i = 0; i < conversations.length; i++) {
|
|
1887
|
+
if (isCompleteConversation(conversations[i])) {
|
|
1888
|
+
completeIndices.push(i);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
const currentLength = () => systemMessages.length + conversations.reduce((acc, c) => acc + c.length, 0);
|
|
1892
|
+
if (completeIndices.length >= 2) {
|
|
1893
|
+
const lastCompleteIndex = completeIndices[completeIndices.length - 1];
|
|
1894
|
+
for (const idx of completeIndices) {
|
|
1895
|
+
if (idx === lastCompleteIndex) {
|
|
1896
|
+
break;
|
|
1897
|
+
}
|
|
1898
|
+
conversations[idx] = compressCompleteConversation(conversations[idx]);
|
|
1899
|
+
if (currentLength() <= maxMessages) {
|
|
1900
|
+
break;
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
let condensed = conversations.flat();
|
|
1905
|
+
condensed = markExpiredFirstHalf(condensed);
|
|
1906
|
+
if (systemMessages.length + condensed.length > maxMessages) {
|
|
1907
|
+
const nonSystemBudget = Math.max(0, maxMessages - systemMessages.length);
|
|
1908
|
+
condensed = condensed.slice(-nonSystemBudget);
|
|
1909
|
+
}
|
|
1910
|
+
return [...systemMessages, ...condensed];
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1717
1913
|
// src/memory/WebMemoryManager.ts
|
|
1718
1914
|
var WebMemoryManager = class {
|
|
1719
1915
|
storageKey;
|
|
1720
1916
|
maxMessages;
|
|
1721
1917
|
inMemoryFallback = [];
|
|
1918
|
+
onCondense;
|
|
1722
1919
|
/**
|
|
1723
1920
|
* @param storageKey SessionStorage 中的键名
|
|
1724
|
-
* @param maxMessages 保留的最大消息数量,用于简单的历史截断(默认
|
|
1921
|
+
* @param maxMessages 保留的最大消息数量,用于简单的历史截断(默认 200)
|
|
1725
1922
|
*/
|
|
1726
|
-
constructor(storageKey = "cline_agent_memory", maxMessages =
|
|
1923
|
+
constructor(storageKey = "cline_agent_memory", maxMessages = 200) {
|
|
1727
1924
|
this.storageKey = storageKey;
|
|
1728
1925
|
this.maxMessages = maxMessages;
|
|
1729
1926
|
}
|
|
@@ -1764,19 +1961,22 @@ var WebMemoryManager = class {
|
|
|
1764
1961
|
this.writeMessages(messages);
|
|
1765
1962
|
await this.condenseHistory();
|
|
1766
1963
|
}
|
|
1964
|
+
/**
|
|
1965
|
+
* 压缩历史:
|
|
1966
|
+
* - system 消息保持不变
|
|
1967
|
+
* - 以 agent_attempt_completion 为边界切分完整对话,仅合并“后面还有其他完整对话”的旧完整对话
|
|
1968
|
+
* - 其余需要压缩的场景下,对前半段工具调用结果标记为“结果已过期”
|
|
1969
|
+
* - 同时触发 onCondense 回调(宿主可据此清空 dify conversationId 新开窗口)
|
|
1970
|
+
*/
|
|
1767
1971
|
async condenseHistory() {
|
|
1768
1972
|
const messages = this.readMessages();
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
} else {
|
|
1777
|
-
condensed = messages.slice(sliceCount);
|
|
1778
|
-
}
|
|
1779
|
-
this.writeMessages(condensed);
|
|
1973
|
+
const condensed = condenseMessages(messages, this.maxMessages);
|
|
1974
|
+
if (condensed === messages) {
|
|
1975
|
+
return Promise.resolve();
|
|
1976
|
+
}
|
|
1977
|
+
this.writeMessages(condensed);
|
|
1978
|
+
if (this.onCondense) {
|
|
1979
|
+
await this.onCondense();
|
|
1780
1980
|
}
|
|
1781
1981
|
return Promise.resolve();
|
|
1782
1982
|
}
|