sam-coder-cli 1.0.63 → 1.0.65
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 +105 -3
- package/package.json +1 -1
package/bin/agi-cli.js
CHANGED
|
@@ -429,6 +429,9 @@ const agentUtils = {
|
|
|
429
429
|
|
|
430
430
|
async writeFile(filePath, content) {
|
|
431
431
|
try {
|
|
432
|
+
// Ensure directory exists
|
|
433
|
+
const dir = path.dirname(filePath);
|
|
434
|
+
await fs.mkdir(dir, { recursive: true });
|
|
432
435
|
await fs.writeFile(filePath, content, 'utf-8');
|
|
433
436
|
return `Successfully wrote to ${filePath}`;
|
|
434
437
|
} catch (error) {
|
|
@@ -755,7 +758,7 @@ function normalizeToolCallsFromMessage(message) {
|
|
|
755
758
|
// Parse segmented format like <|start|>channel<|message|>...<|end|>
|
|
756
759
|
function parseSegmentedTranscript(text) {
|
|
757
760
|
if (!text || typeof text !== 'string') {
|
|
758
|
-
return { content: text || '', thought: '', recoveredToolCalls: null };
|
|
761
|
+
return { content: text || '', thought: '', recoveredToolCalls: null, segmented: false };
|
|
759
762
|
}
|
|
760
763
|
|
|
761
764
|
const blockRegex = /\<\|start\|>([^<|]+)\<\|message\|>([\s\S]*?)\<\|end\|>/gi;
|
|
@@ -763,11 +766,13 @@ function parseSegmentedTranscript(text) {
|
|
|
763
766
|
let visibleParts = [];
|
|
764
767
|
let thoughts = [];
|
|
765
768
|
let commentaryParts = [];
|
|
769
|
+
let segmentedFound = false;
|
|
766
770
|
|
|
767
771
|
while ((match = blockRegex.exec(text)) !== null) {
|
|
768
772
|
const rawRole = (match[1] || '').trim().toLowerCase();
|
|
769
773
|
const body = (match[2] || '').trim();
|
|
770
774
|
if (!rawRole) continue;
|
|
775
|
+
segmentedFound = true;
|
|
771
776
|
|
|
772
777
|
if (rawRole === 'analysis') {
|
|
773
778
|
thoughts.push(body);
|
|
@@ -784,7 +789,72 @@ function parseSegmentedTranscript(text) {
|
|
|
784
789
|
|
|
785
790
|
// If no blocks matched, return original
|
|
786
791
|
if (visibleParts.length === 0 && thoughts.length === 0 && commentaryParts.length === 0) {
|
|
787
|
-
|
|
792
|
+
// Try channel-only segments: <|channel|>X [to=Y] [<|constrain|>Z] <|message|>... (<|end|>|<|call|>|<|return|>)
|
|
793
|
+
const chanRegex = /\<\|channel\|>\s*([a-zA-Z]+)\s*(?:to=([^\s<]+))?\s*(?:\<\|constrain\|>(\w+))?\s*\<\|message\|>([\s\S]*?)(?:\<\|end\|>|\<\|call\|>|\<\|return\|>)/gi;
|
|
794
|
+
let anyChannel = false;
|
|
795
|
+
let commsWithRecipients = [];
|
|
796
|
+
while ((match = chanRegex.exec(text)) !== null) {
|
|
797
|
+
anyChannel = true;
|
|
798
|
+
segmentedFound = true;
|
|
799
|
+
const channel = (match[1] || '').trim().toLowerCase();
|
|
800
|
+
const recipient = (match[2] || '').trim();
|
|
801
|
+
const constraint = (match[3] || '').trim().toLowerCase();
|
|
802
|
+
const body = (match[4] || '').trim();
|
|
803
|
+
if (channel === 'analysis') {
|
|
804
|
+
thoughts.push(body);
|
|
805
|
+
} else if (channel === 'commentary') {
|
|
806
|
+
if (recipient) {
|
|
807
|
+
commsWithRecipients.push({ recipient, constraint, body });
|
|
808
|
+
} else {
|
|
809
|
+
// preamble visible to user per spec
|
|
810
|
+
visibleParts.push(body);
|
|
811
|
+
}
|
|
812
|
+
} else if (channel === 'final') {
|
|
813
|
+
visibleParts.push(body);
|
|
814
|
+
} else {
|
|
815
|
+
visibleParts.push(body);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
// Build recovered tool calls from commentary with recipients
|
|
819
|
+
let recoveredToolCalls = null;
|
|
820
|
+
if (commsWithRecipients.length) {
|
|
821
|
+
recoveredToolCalls = [];
|
|
822
|
+
for (const item of commsWithRecipients) {
|
|
823
|
+
// recipient format like functions.get_weather
|
|
824
|
+
let funcName = item.recipient;
|
|
825
|
+
if (funcName.startsWith('functions.')) {
|
|
826
|
+
funcName = funcName.slice('functions.'.length);
|
|
827
|
+
}
|
|
828
|
+
// parse args
|
|
829
|
+
let args = {};
|
|
830
|
+
if (item.constraint === 'json' || item.body.startsWith('{') || item.body.startsWith('[')) {
|
|
831
|
+
try {
|
|
832
|
+
const parsed = JSON.parse(item.body);
|
|
833
|
+
args = parsed;
|
|
834
|
+
} catch (_) {
|
|
835
|
+
// ignore parse error; leave empty
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
recoveredToolCalls.push({
|
|
839
|
+
id: `inline-${recoveredToolCalls.length + 1}`,
|
|
840
|
+
type: 'function',
|
|
841
|
+
function: {
|
|
842
|
+
name: funcName,
|
|
843
|
+
arguments: typeof args === 'string' ? args : JSON.stringify(args)
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
if (!anyChannel) {
|
|
850
|
+
return { content: text, thought: '', recoveredToolCalls: null, segmented: false };
|
|
851
|
+
}
|
|
852
|
+
return {
|
|
853
|
+
content: visibleParts.join('\n\n').trim(),
|
|
854
|
+
thought: thoughts.join('\n\n').trim(),
|
|
855
|
+
recoveredToolCalls: recoveredToolCalls && recoveredToolCalls.length ? recoveredToolCalls : null,
|
|
856
|
+
segmented: segmentedFound
|
|
857
|
+
};
|
|
788
858
|
}
|
|
789
859
|
|
|
790
860
|
// Look for a Reasoning: level outside blocks as a hint
|
|
@@ -807,7 +877,8 @@ function parseSegmentedTranscript(text) {
|
|
|
807
877
|
return {
|
|
808
878
|
content: visibleParts.join('\n\n').trim(),
|
|
809
879
|
thought: thoughts.join('\n\n').trim(),
|
|
810
|
-
recoveredToolCalls: recoveredToolCalls && recoveredToolCalls.length ? recoveredToolCalls : null
|
|
880
|
+
recoveredToolCalls: recoveredToolCalls && recoveredToolCalls.length ? recoveredToolCalls : null,
|
|
881
|
+
segmented: segmentedFound
|
|
811
882
|
};
|
|
812
883
|
}
|
|
813
884
|
|
|
@@ -1251,6 +1322,37 @@ async function chat(rl, useToolCalling, initialModel) {
|
|
|
1251
1322
|
return;
|
|
1252
1323
|
}
|
|
1253
1324
|
|
|
1325
|
+
// Direct Harmony tool-call execution from user input (bypass model)
|
|
1326
|
+
try {
|
|
1327
|
+
const seg = parseSegmentedTranscript(input);
|
|
1328
|
+
if (seg && seg.segmented && seg.recoveredToolCalls && seg.recoveredToolCalls.length) {
|
|
1329
|
+
const messages = [];
|
|
1330
|
+
if (useToolCalling) {
|
|
1331
|
+
messages.push({ role: 'system', content: TOOL_CALLING_PROMPT });
|
|
1332
|
+
} else {
|
|
1333
|
+
messages.push({ role: 'system', content: FUNCTION_CALLING_PROMPT });
|
|
1334
|
+
}
|
|
1335
|
+
messages.push({ role: 'user', content: input });
|
|
1336
|
+
ui.startThinking();
|
|
1337
|
+
const results = await handleToolCalls(seg.recoveredToolCalls, messages);
|
|
1338
|
+
ui.stopThinking();
|
|
1339
|
+
if (results.length === 1) {
|
|
1340
|
+
ui.showSuccess(`Tool '${results[0].name}' executed.`);
|
|
1341
|
+
} else {
|
|
1342
|
+
ui.showSuccess(`Executed ${results.length} tool calls.`);
|
|
1343
|
+
}
|
|
1344
|
+
// Show concise outputs
|
|
1345
|
+
results.forEach(r => {
|
|
1346
|
+
const preview = typeof r.content === 'string' ? r.content : JSON.stringify(r.content);
|
|
1347
|
+
ui.showInfo(`${r.name}: ${preview.length > 300 ? preview.slice(0, 300) + '...' : preview}`);
|
|
1348
|
+
});
|
|
1349
|
+
rl.prompt();
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
} catch (e) {
|
|
1353
|
+
// Fall through to normal processing if parsing/execution fails
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1254
1356
|
const result = useToolCalling
|
|
1255
1357
|
? await processQueryWithTools(input, conversation, currentModel)
|
|
1256
1358
|
: await processQuery(input, conversation, currentModel);
|