@corbat-tech/coco 2.8.0 → 2.8.1
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/cli/index.js +172 -100
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +114 -82
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1012,22 +1012,38 @@ var init_anthropic = __esm({
|
|
|
1012
1012
|
async *stream(messages, options) {
|
|
1013
1013
|
this.ensureInitialized();
|
|
1014
1014
|
try {
|
|
1015
|
-
const stream = await this.client.messages.stream(
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1015
|
+
const stream = await this.client.messages.stream(
|
|
1016
|
+
{
|
|
1017
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL,
|
|
1018
|
+
max_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
1019
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
1020
|
+
system: this.extractSystem(messages, options?.system),
|
|
1021
|
+
messages: this.convertMessages(messages)
|
|
1022
|
+
},
|
|
1023
|
+
{ signal: options?.signal }
|
|
1024
|
+
);
|
|
1025
|
+
const streamTimeout = this.config.timeout ?? 12e4;
|
|
1026
|
+
let lastActivityTime = Date.now();
|
|
1027
|
+
const checkTimeout = () => {
|
|
1028
|
+
if (Date.now() - lastActivityTime > streamTimeout) {
|
|
1029
|
+
throw new Error(`Stream timeout: No response from LLM for ${streamTimeout / 1e3}s`);
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
const timeoutInterval = setInterval(checkTimeout, 5e3);
|
|
1033
|
+
try {
|
|
1034
|
+
for await (const event of stream) {
|
|
1035
|
+
lastActivityTime = Date.now();
|
|
1036
|
+
if (event.type === "content_block_delta") {
|
|
1037
|
+
const delta = event.delta;
|
|
1038
|
+
if (delta.type === "text_delta" && delta.text) {
|
|
1039
|
+
yield { type: "text", text: delta.text };
|
|
1040
|
+
}
|
|
1027
1041
|
}
|
|
1028
1042
|
}
|
|
1043
|
+
yield { type: "done" };
|
|
1044
|
+
} finally {
|
|
1045
|
+
clearInterval(timeoutInterval);
|
|
1029
1046
|
}
|
|
1030
|
-
yield { type: "done" };
|
|
1031
1047
|
} catch (error) {
|
|
1032
1048
|
throw this.handleError(error);
|
|
1033
1049
|
}
|
|
@@ -1038,90 +1054,106 @@ var init_anthropic = __esm({
|
|
|
1038
1054
|
async *streamWithTools(messages, options) {
|
|
1039
1055
|
this.ensureInitialized();
|
|
1040
1056
|
try {
|
|
1041
|
-
const stream = await this.client.messages.stream(
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1057
|
+
const stream = await this.client.messages.stream(
|
|
1058
|
+
{
|
|
1059
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL,
|
|
1060
|
+
max_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
1061
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
1062
|
+
system: this.extractSystem(messages, options?.system),
|
|
1063
|
+
messages: this.convertMessages(messages),
|
|
1064
|
+
tools: this.convertTools(options.tools),
|
|
1065
|
+
tool_choice: options.toolChoice ? this.convertToolChoice(options.toolChoice) : void 0
|
|
1066
|
+
},
|
|
1067
|
+
{ signal: options?.signal }
|
|
1068
|
+
);
|
|
1050
1069
|
let currentToolCall = null;
|
|
1051
1070
|
let currentToolInputJson = "";
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1071
|
+
const streamTimeout = this.config.timeout ?? 12e4;
|
|
1072
|
+
let lastActivityTime = Date.now();
|
|
1073
|
+
const checkTimeout = () => {
|
|
1074
|
+
if (Date.now() - lastActivityTime > streamTimeout) {
|
|
1075
|
+
throw new Error(`Stream timeout: No response from LLM for ${streamTimeout / 1e3}s`);
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
const timeoutInterval = setInterval(checkTimeout, 5e3);
|
|
1079
|
+
try {
|
|
1080
|
+
for await (const event of stream) {
|
|
1081
|
+
lastActivityTime = Date.now();
|
|
1082
|
+
if (event.type === "content_block_start") {
|
|
1083
|
+
const contentBlock = event.content_block;
|
|
1084
|
+
if (contentBlock.type === "tool_use") {
|
|
1085
|
+
if (currentToolCall) {
|
|
1086
|
+
getLogger().warn(
|
|
1087
|
+
`[Anthropic] content_block_stop missing for tool '${currentToolCall.name}' \u2014 finalizing early to prevent data bleed.`
|
|
1088
|
+
);
|
|
1089
|
+
try {
|
|
1090
|
+
currentToolCall.input = currentToolInputJson ? JSON.parse(currentToolInputJson) : {};
|
|
1091
|
+
} catch {
|
|
1092
|
+
currentToolCall.input = {};
|
|
1093
|
+
}
|
|
1094
|
+
yield {
|
|
1095
|
+
type: "tool_use_end",
|
|
1096
|
+
toolCall: { ...currentToolCall }
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
currentToolCall = {
|
|
1100
|
+
id: contentBlock.id,
|
|
1101
|
+
name: contentBlock.name
|
|
1102
|
+
};
|
|
1103
|
+
currentToolInputJson = "";
|
|
1104
|
+
yield {
|
|
1105
|
+
type: "tool_use_start",
|
|
1106
|
+
toolCall: { ...currentToolCall }
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
} else if (event.type === "content_block_delta") {
|
|
1110
|
+
const delta = event.delta;
|
|
1111
|
+
if (delta.type === "text_delta" && delta.text) {
|
|
1112
|
+
yield { type: "text", text: delta.text };
|
|
1113
|
+
} else if (delta.type === "input_json_delta" && delta.partial_json) {
|
|
1114
|
+
currentToolInputJson += delta.partial_json;
|
|
1115
|
+
yield {
|
|
1116
|
+
type: "tool_use_delta",
|
|
1117
|
+
toolCall: {
|
|
1118
|
+
...currentToolCall
|
|
1119
|
+
},
|
|
1120
|
+
text: delta.partial_json
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
} else if (event.type === "content_block_stop") {
|
|
1056
1124
|
if (currentToolCall) {
|
|
1057
|
-
getLogger().warn(
|
|
1058
|
-
`[Anthropic] content_block_stop missing for tool '${currentToolCall.name}' \u2014 finalizing early to prevent data bleed.`
|
|
1059
|
-
);
|
|
1060
1125
|
try {
|
|
1061
1126
|
currentToolCall.input = currentToolInputJson ? JSON.parse(currentToolInputJson) : {};
|
|
1062
1127
|
} catch {
|
|
1063
|
-
|
|
1128
|
+
let repaired = false;
|
|
1129
|
+
if (currentToolInputJson) {
|
|
1130
|
+
try {
|
|
1131
|
+
currentToolCall.input = JSON.parse(jsonrepair(currentToolInputJson));
|
|
1132
|
+
repaired = true;
|
|
1133
|
+
getLogger().debug(`Repaired JSON for tool ${currentToolCall.name}`);
|
|
1134
|
+
} catch {
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
if (!repaired) {
|
|
1138
|
+
getLogger().warn(
|
|
1139
|
+
`Failed to parse tool call arguments for ${currentToolCall.name}: ${currentToolInputJson?.slice(0, 300)}`
|
|
1140
|
+
);
|
|
1141
|
+
currentToolCall.input = {};
|
|
1142
|
+
}
|
|
1064
1143
|
}
|
|
1065
1144
|
yield {
|
|
1066
1145
|
type: "tool_use_end",
|
|
1067
1146
|
toolCall: { ...currentToolCall }
|
|
1068
1147
|
};
|
|
1148
|
+
currentToolCall = null;
|
|
1149
|
+
currentToolInputJson = "";
|
|
1069
1150
|
}
|
|
1070
|
-
currentToolCall = {
|
|
1071
|
-
id: contentBlock.id,
|
|
1072
|
-
name: contentBlock.name
|
|
1073
|
-
};
|
|
1074
|
-
currentToolInputJson = "";
|
|
1075
|
-
yield {
|
|
1076
|
-
type: "tool_use_start",
|
|
1077
|
-
toolCall: { ...currentToolCall }
|
|
1078
|
-
};
|
|
1079
|
-
}
|
|
1080
|
-
} else if (event.type === "content_block_delta") {
|
|
1081
|
-
const delta = event.delta;
|
|
1082
|
-
if (delta.type === "text_delta" && delta.text) {
|
|
1083
|
-
yield { type: "text", text: delta.text };
|
|
1084
|
-
} else if (delta.type === "input_json_delta" && delta.partial_json) {
|
|
1085
|
-
currentToolInputJson += delta.partial_json;
|
|
1086
|
-
yield {
|
|
1087
|
-
type: "tool_use_delta",
|
|
1088
|
-
toolCall: {
|
|
1089
|
-
...currentToolCall
|
|
1090
|
-
},
|
|
1091
|
-
text: delta.partial_json
|
|
1092
|
-
};
|
|
1093
|
-
}
|
|
1094
|
-
} else if (event.type === "content_block_stop") {
|
|
1095
|
-
if (currentToolCall) {
|
|
1096
|
-
try {
|
|
1097
|
-
currentToolCall.input = currentToolInputJson ? JSON.parse(currentToolInputJson) : {};
|
|
1098
|
-
} catch {
|
|
1099
|
-
let repaired = false;
|
|
1100
|
-
if (currentToolInputJson) {
|
|
1101
|
-
try {
|
|
1102
|
-
currentToolCall.input = JSON.parse(jsonrepair(currentToolInputJson));
|
|
1103
|
-
repaired = true;
|
|
1104
|
-
getLogger().debug(`Repaired JSON for tool ${currentToolCall.name}`);
|
|
1105
|
-
} catch {
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
if (!repaired) {
|
|
1109
|
-
getLogger().warn(
|
|
1110
|
-
`Failed to parse tool call arguments for ${currentToolCall.name}: ${currentToolInputJson?.slice(0, 300)}`
|
|
1111
|
-
);
|
|
1112
|
-
currentToolCall.input = {};
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
yield {
|
|
1116
|
-
type: "tool_use_end",
|
|
1117
|
-
toolCall: { ...currentToolCall }
|
|
1118
|
-
};
|
|
1119
|
-
currentToolCall = null;
|
|
1120
|
-
currentToolInputJson = "";
|
|
1121
1151
|
}
|
|
1122
1152
|
}
|
|
1153
|
+
yield { type: "done" };
|
|
1154
|
+
} finally {
|
|
1155
|
+
clearInterval(timeoutInterval);
|
|
1123
1156
|
}
|
|
1124
|
-
yield { type: "done" };
|
|
1125
1157
|
} catch (error) {
|
|
1126
1158
|
throw this.handleError(error);
|
|
1127
1159
|
}
|
|
@@ -6564,7 +6596,7 @@ CONVERSATION:
|
|
|
6564
6596
|
* @param provider - The LLM provider to use for summarization
|
|
6565
6597
|
* @returns Compacted messages with summary replacing older messages
|
|
6566
6598
|
*/
|
|
6567
|
-
async compact(messages, provider) {
|
|
6599
|
+
async compact(messages, provider, signal) {
|
|
6568
6600
|
const conversationMessages = messages.filter((m) => m.role !== "system");
|
|
6569
6601
|
if (conversationMessages.length <= this.config.preserveLastN) {
|
|
6570
6602
|
return {
|
|
@@ -6596,7 +6628,7 @@ CONVERSATION:
|
|
|
6596
6628
|
}
|
|
6597
6629
|
const originalTokens = this.estimateTokens(messages, provider);
|
|
6598
6630
|
const conversationText = this.formatMessagesForSummary(messagesToSummarize);
|
|
6599
|
-
const summary = await this.generateSummary(conversationText, provider);
|
|
6631
|
+
const summary = await this.generateSummary(conversationText, provider, signal);
|
|
6600
6632
|
const systemMessages = messages.filter((m) => m.role === "system");
|
|
6601
6633
|
const summaryMessage = {
|
|
6602
6634
|
role: "user",
|
|
@@ -6650,16 +6682,30 @@ ${summary}
|
|
|
6650
6682
|
/**
|
|
6651
6683
|
* Generate a summary of the conversation using the LLM
|
|
6652
6684
|
*/
|
|
6653
|
-
async generateSummary(conversationText, provider) {
|
|
6685
|
+
async generateSummary(conversationText, provider, signal) {
|
|
6686
|
+
if (signal?.aborted) return "[Compaction cancelled]";
|
|
6654
6687
|
const prompt = COMPACTION_PROMPT + conversationText;
|
|
6655
6688
|
try {
|
|
6656
|
-
const
|
|
6689
|
+
const chatPromise = provider.chat([{ role: "user", content: prompt }], {
|
|
6657
6690
|
maxTokens: this.config.summaryMaxTokens,
|
|
6658
6691
|
temperature: 0.3
|
|
6659
6692
|
// Lower temperature for more consistent summaries
|
|
6660
6693
|
});
|
|
6694
|
+
if (signal) {
|
|
6695
|
+
const abortPromise = new Promise((_, reject) => {
|
|
6696
|
+
signal.addEventListener(
|
|
6697
|
+
"abort",
|
|
6698
|
+
() => reject(new DOMException("Aborted", "AbortError")),
|
|
6699
|
+
{ once: true }
|
|
6700
|
+
);
|
|
6701
|
+
});
|
|
6702
|
+
const response2 = await Promise.race([chatPromise, abortPromise]);
|
|
6703
|
+
return response2.content;
|
|
6704
|
+
}
|
|
6705
|
+
const response = await chatPromise;
|
|
6661
6706
|
return response.content;
|
|
6662
6707
|
} catch (error) {
|
|
6708
|
+
if (error instanceof DOMException && error.name === "AbortError") throw error;
|
|
6663
6709
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6664
6710
|
return `[Summary generation failed: ${errorMessage}. Previous conversation had ${conversationText.length} characters.]`;
|
|
6665
6711
|
}
|
|
@@ -6795,7 +6841,14 @@ function addMessage(session, message) {
|
|
|
6795
6841
|
session.messages.push(message);
|
|
6796
6842
|
const maxMessages = session.config.ui.maxHistorySize * 2;
|
|
6797
6843
|
if (session.messages.length > maxMessages) {
|
|
6798
|
-
|
|
6844
|
+
let sliceStart = session.messages.length - session.config.ui.maxHistorySize;
|
|
6845
|
+
while (sliceStart > 0 && sliceStart < session.messages.length) {
|
|
6846
|
+
const msg = session.messages[sliceStart];
|
|
6847
|
+
const isToolResult = Array.isArray(msg?.content) && msg.content.length > 0 && msg.content[0]?.type === "tool_result";
|
|
6848
|
+
if (!isToolResult) break;
|
|
6849
|
+
sliceStart--;
|
|
6850
|
+
}
|
|
6851
|
+
session.messages = session.messages.slice(sliceStart);
|
|
6799
6852
|
}
|
|
6800
6853
|
}
|
|
6801
6854
|
function substituteDynamicContext(body, cwd) {
|
|
@@ -7062,7 +7115,7 @@ function updateContextTokens(session, provider) {
|
|
|
7062
7115
|
}
|
|
7063
7116
|
session.contextManager.setUsedTokens(totalTokens);
|
|
7064
7117
|
}
|
|
7065
|
-
async function checkAndCompactContext(session, provider) {
|
|
7118
|
+
async function checkAndCompactContext(session, provider, signal) {
|
|
7066
7119
|
if (!session.contextManager) {
|
|
7067
7120
|
initializeContextManager(session, provider);
|
|
7068
7121
|
}
|
|
@@ -7074,7 +7127,7 @@ async function checkAndCompactContext(session, provider) {
|
|
|
7074
7127
|
preserveLastN: 4,
|
|
7075
7128
|
summaryMaxTokens: 1e3
|
|
7076
7129
|
});
|
|
7077
|
-
const result = await compactor.compact(session.messages, provider);
|
|
7130
|
+
const result = await compactor.compact(session.messages, provider, signal);
|
|
7078
7131
|
if (result.wasCompacted) {
|
|
7079
7132
|
const compactedNonSystem = result.messages.filter((m) => m.role !== "system");
|
|
7080
7133
|
session.messages = compactedNonSystem;
|
|
@@ -44590,7 +44643,8 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
44590
44643
|
const toolCallBuilders = /* @__PURE__ */ new Map();
|
|
44591
44644
|
for await (const chunk of provider.streamWithTools(messages, {
|
|
44592
44645
|
tools,
|
|
44593
|
-
maxTokens: session.config.provider.maxTokens
|
|
44646
|
+
maxTokens: session.config.provider.maxTokens,
|
|
44647
|
+
signal: options.signal
|
|
44594
44648
|
})) {
|
|
44595
44649
|
if (options.signal?.aborted) {
|
|
44596
44650
|
break;
|
|
@@ -44864,7 +44918,8 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
44864
44918
|
const finalMessages = getConversationContext(session, toolRegistry);
|
|
44865
44919
|
for await (const chunk of provider.streamWithTools(finalMessages, {
|
|
44866
44920
|
tools: [],
|
|
44867
|
-
maxTokens: session.config.provider.maxTokens
|
|
44921
|
+
maxTokens: session.config.provider.maxTokens,
|
|
44922
|
+
signal: options.signal
|
|
44868
44923
|
})) {
|
|
44869
44924
|
if (options.signal?.aborted) break;
|
|
44870
44925
|
if (chunk.type === "text" && chunk.text) {
|
|
@@ -46059,16 +46114,33 @@ async function startRepl(options = {}) {
|
|
|
46059
46114
|
const usageBefore = getContextUsagePercent(session);
|
|
46060
46115
|
let usageForDisplay = usageBefore;
|
|
46061
46116
|
try {
|
|
46062
|
-
const
|
|
46063
|
-
|
|
46064
|
-
|
|
46065
|
-
|
|
46066
|
-
|
|
46067
|
-
|
|
46068
|
-
|
|
46117
|
+
const compactAbort = new AbortController();
|
|
46118
|
+
const compactTimeout = setTimeout(() => compactAbort.abort(), 3e4);
|
|
46119
|
+
const compactSigint = () => compactAbort.abort();
|
|
46120
|
+
process.once("SIGINT", compactSigint);
|
|
46121
|
+
const compactSpinner = createSpinner("Compacting context");
|
|
46122
|
+
compactSpinner.start();
|
|
46123
|
+
try {
|
|
46124
|
+
const compactionResult = await checkAndCompactContext(
|
|
46125
|
+
session,
|
|
46126
|
+
provider,
|
|
46127
|
+
compactAbort.signal
|
|
46069
46128
|
);
|
|
46070
|
-
|
|
46071
|
-
|
|
46129
|
+
if (compactionResult?.wasCompacted) {
|
|
46130
|
+
usageForDisplay = getContextUsagePercent(session);
|
|
46131
|
+
compactSpinner.stop(
|
|
46132
|
+
`Context compacted (${usageBefore.toFixed(0)}% \u2192 ${usageForDisplay.toFixed(0)}%)`
|
|
46133
|
+
);
|
|
46134
|
+
warned75 = false;
|
|
46135
|
+
warned90 = false;
|
|
46136
|
+
} else {
|
|
46137
|
+
compactSpinner.clear();
|
|
46138
|
+
}
|
|
46139
|
+
} catch {
|
|
46140
|
+
compactSpinner.clear();
|
|
46141
|
+
} finally {
|
|
46142
|
+
clearTimeout(compactTimeout);
|
|
46143
|
+
process.off("SIGINT", compactSigint);
|
|
46072
46144
|
}
|
|
46073
46145
|
} catch {
|
|
46074
46146
|
}
|