sam-coder-cli 1.0.60 → 1.0.61
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/bin/agi-cli.js +72 -0
- package/package.json +1 -1
package/bin/agi-cli.js
CHANGED
|
@@ -757,6 +757,27 @@ function normalizeToolCallsFromMessage(message) {
|
|
|
757
757
|
return message;
|
|
758
758
|
}
|
|
759
759
|
|
|
760
|
+
// Ask the model to produce a structured follow-up with thinking and either tool_calls or JSON action
|
|
761
|
+
async function requestStructuredFollowup(messages, currentModel, preferTools = true) {
|
|
762
|
+
const instruction = preferTools
|
|
763
|
+
? 'Think step-by-step inside <think></think>. Then, if any tools are needed, call them via tool_calls. If no tools are required, output a single markdown ```json code block with an action object (type, data, reasoning) per the schema. Do not include any other text.'
|
|
764
|
+
: 'Think step-by-step inside <think></think>, then output a single markdown ```json code block with an action object (type, data, reasoning) per the schema. Do not include any other text.';
|
|
765
|
+
|
|
766
|
+
const followupUser = { role: 'user', content: instruction };
|
|
767
|
+
const followupMessages = [...messages, followupUser];
|
|
768
|
+
const responseObj = await callOpenRouter(followupMessages, currentModel, !preferTools);
|
|
769
|
+
const assistantMessage = responseObj.choices[0].message;
|
|
770
|
+
if (assistantMessage && typeof assistantMessage.content === 'string') {
|
|
771
|
+
const { thought, content } = splitThinking(assistantMessage.content);
|
|
772
|
+
if (thought && SHOW_THOUGHTS) {
|
|
773
|
+
ui.showInfo(`Thinking:\n${thought}`);
|
|
774
|
+
}
|
|
775
|
+
assistantMessage.content = content;
|
|
776
|
+
}
|
|
777
|
+
normalizeToolCallsFromMessage(assistantMessage);
|
|
778
|
+
return { assistantMessage, updatedMessages: [...followupMessages, assistantMessage] };
|
|
779
|
+
}
|
|
780
|
+
|
|
760
781
|
// Call OpenRouter API with tool calling
|
|
761
782
|
async function callOpenRouter(messages, currentModel, useJson = false) {
|
|
762
783
|
const apiKey = OPENROUTER_API_KEY;
|
|
@@ -879,6 +900,57 @@ async function processQueryWithTools(query, conversation = [], currentModel) {
|
|
|
879
900
|
// If fallback execution fails, just return original assistant content
|
|
880
901
|
}
|
|
881
902
|
}
|
|
903
|
+
// Final attempt: request a structured follow-up that includes thinking and tool calls
|
|
904
|
+
try {
|
|
905
|
+
ui.startThinking();
|
|
906
|
+
const { assistantMessage: structuredMsg, updatedMessages } = await requestStructuredFollowup(messages, currentModel, true);
|
|
907
|
+
messages.length = 0; updatedMessages.forEach(m => messages.push(m));
|
|
908
|
+
|
|
909
|
+
// If tool calls present now, execute them
|
|
910
|
+
if (structuredMsg.tool_calls && structuredMsg.tool_calls.length) {
|
|
911
|
+
const toolResults2 = await handleToolCalls(structuredMsg.tool_calls, messages);
|
|
912
|
+
messages.push(...toolResults2);
|
|
913
|
+
const finalResponseObj2 = await callOpenRouter(messages, currentModel);
|
|
914
|
+
const finalAssistantMessage2 = finalResponseObj2.choices[0].message;
|
|
915
|
+
if (finalAssistantMessage2 && typeof finalAssistantMessage2.content === 'string') {
|
|
916
|
+
const { thought, content } = splitThinking(finalAssistantMessage2.content);
|
|
917
|
+
if (thought && SHOW_THOUGHTS) ui.showInfo(`Thinking:\n${thought}`);
|
|
918
|
+
finalAssistantMessage2.content = content;
|
|
919
|
+
}
|
|
920
|
+
messages.push(finalAssistantMessage2);
|
|
921
|
+
ui.stopThinking();
|
|
922
|
+
return { response: finalAssistantMessage2.content, conversation: messages };
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// Else try JSON action again from the structured response
|
|
926
|
+
const structuredAction = extractJsonFromMarkdown(structuredMsg.content);
|
|
927
|
+
if (structuredAction && structuredAction.type) {
|
|
928
|
+
try {
|
|
929
|
+
const result2 = await executeAction(structuredAction);
|
|
930
|
+
messages.push({ role: 'user', content: `Action result (${structuredAction.type}): ${result2}` });
|
|
931
|
+
const finalResponseObj3 = await callOpenRouter(messages, currentModel);
|
|
932
|
+
const finalAssistantMessage3 = finalResponseObj3.choices[0].message;
|
|
933
|
+
if (finalAssistantMessage3 && typeof finalAssistantMessage3.content === 'string') {
|
|
934
|
+
const { thought, content } = splitThinking(finalAssistantMessage3.content);
|
|
935
|
+
if (thought && SHOW_THOUGHTS) ui.showInfo(`Thinking:\n${thought}`);
|
|
936
|
+
finalAssistantMessage3.content = content;
|
|
937
|
+
}
|
|
938
|
+
messages.push(finalAssistantMessage3);
|
|
939
|
+
ui.stopThinking();
|
|
940
|
+
return { response: finalAssistantMessage3.content, conversation: messages };
|
|
941
|
+
} catch (_) {
|
|
942
|
+
ui.stopThinking();
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
ui.stopThinking();
|
|
947
|
+
return {
|
|
948
|
+
response: structuredMsg.content,
|
|
949
|
+
conversation: messages
|
|
950
|
+
};
|
|
951
|
+
} catch (_) {
|
|
952
|
+
// ignore and fall back to original assistant message
|
|
953
|
+
}
|
|
882
954
|
ui.stopThinking();
|
|
883
955
|
return {
|
|
884
956
|
response: assistantMessage.content,
|