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.
Files changed (2) hide show
  1. package/bin/agi-cli.js +72 -0
  2. 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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sam-coder-cli",
3
- "version": "1.0.60",
3
+ "version": "1.0.61",
4
4
  "description": "SAM-CODER: An animated command-line AI assistant with agency capabilities.",
5
5
  "main": "bin/agi-cli.js",
6
6
  "bin": {