@blockrun/franklin 3.6.3 → 3.6.4
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/agent/loop.js +19 -8
- package/dist/tools/edit.js +11 -5
- package/dist/tools/task.js +19 -1
- package/package.json +1 -1
package/dist/agent/loop.js
CHANGED
|
@@ -642,18 +642,29 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
642
642
|
console.error(`[franklin] Max tokens hit — escalating to ${maxTokensOverride}`);
|
|
643
643
|
}
|
|
644
644
|
}
|
|
645
|
-
// Append what we got + a continuation prompt
|
|
645
|
+
// Append what we got + a continuation prompt with last-line anchor
|
|
646
646
|
const partialAssistant = { role: 'assistant', content: responseParts };
|
|
647
|
+
// Extract last line of output to give the model a concrete resume point
|
|
648
|
+
const textParts = responseParts.filter(p => p.type === 'text');
|
|
649
|
+
const lastTextBlock = textParts[textParts.length - 1];
|
|
650
|
+
let lastLineAnchor = '';
|
|
651
|
+
if (lastTextBlock && lastTextBlock.type === 'text') {
|
|
652
|
+
const lastLine = lastTextBlock.text.split('\n').filter(l => l.trim()).pop() ?? '';
|
|
653
|
+
if (lastLine.length > 10) {
|
|
654
|
+
lastLineAnchor = `\nYour output ended with: "${lastLine.slice(0, 120)}"\nResume immediately after that point.`;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
647
657
|
const continuationPrompt = {
|
|
648
658
|
role: 'user',
|
|
649
659
|
content: [
|
|
650
|
-
'Output token limit hit. Continue
|
|
651
|
-
'1. Resume
|
|
652
|
-
'2. Do NOT repeat
|
|
653
|
-
'3.
|
|
654
|
-
'4.
|
|
655
|
-
'5.
|
|
656
|
-
|
|
660
|
+
'Output token limit hit. Continue:',
|
|
661
|
+
'1. Resume exactly where you stopped — your prior output is visible above.',
|
|
662
|
+
'2. Do NOT repeat, summarize, or recap anything already output.',
|
|
663
|
+
'3. If mid-code-block, continue the same block without restarting.',
|
|
664
|
+
'4. Prefer tool calls (Write, Edit) over large text output — they are more token-efficient.',
|
|
665
|
+
'5. Be concise — skip explanations, focus on completing the work.',
|
|
666
|
+
lastLineAnchor,
|
|
667
|
+
].filter(l => l).join('\n'),
|
|
657
668
|
};
|
|
658
669
|
history.push(partialAssistant);
|
|
659
670
|
persistSessionMessage(partialAssistant);
|
package/dist/tools/edit.js
CHANGED
|
@@ -93,7 +93,7 @@ async function execute(input, ctx) {
|
|
|
93
93
|
const searchTerms = oldStr.split('\n').map(l => l.trim()).filter(l => l.length > 3);
|
|
94
94
|
const matchedLines = [];
|
|
95
95
|
if (searchTerms.length > 0) {
|
|
96
|
-
for (let i = 0; i < lines.length && matchedLines.length <
|
|
96
|
+
for (let i = 0; i < lines.length && matchedLines.length < 8; i++) {
|
|
97
97
|
if (searchTerms.some(term => lines[i].includes(term))) {
|
|
98
98
|
matchedLines.push({ num: i + 1, text: lines[i] });
|
|
99
99
|
}
|
|
@@ -101,12 +101,18 @@ async function execute(input, ctx) {
|
|
|
101
101
|
}
|
|
102
102
|
let hint;
|
|
103
103
|
if (matchedLines.length > 0) {
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
// Show matched lines with 1 line of context above for better orientation
|
|
105
|
+
const preview = matchedLines.map(m => {
|
|
106
|
+
const above = m.num > 1 ? ` ${m.num - 1}\t${lines[m.num - 2].slice(0, 80)}\n` : '';
|
|
107
|
+
return `${above}→ ${m.num}\t${m.text}`;
|
|
108
|
+
}).join('\n');
|
|
109
|
+
hint = `\n\nLines containing fragments of your old_string (${matchedLines.length} found):\n${preview}\n\nThe old_string must match EXACTLY — check indentation, quotes, and whitespace. Use Read to see the full region.`;
|
|
106
110
|
}
|
|
107
111
|
else {
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
// No matches — show the middle of the file (more useful than first 10 lines)
|
|
113
|
+
const mid = Math.max(0, Math.floor(lines.length / 2) - 5);
|
|
114
|
+
const preview = lines.slice(mid, mid + 12).map((l, i) => `${mid + i + 1}\t${l}`).join('\n');
|
|
115
|
+
hint = `\n\nNo matching fragments found in ${lines.length}-line file. Lines ${mid + 1}-${mid + 12}:\n${preview}\n\nUse Read to find the correct text.`;
|
|
110
116
|
}
|
|
111
117
|
return {
|
|
112
118
|
output: `Error: old_string not found in ${resolved}.${hint}`,
|
package/dist/tools/task.js
CHANGED
|
@@ -58,7 +58,25 @@ async function execute(input, _ctx) {
|
|
|
58
58
|
blocker.blocks.push(task.id);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
|
|
61
|
+
// Rich feedback: show status transition and dependency impact
|
|
62
|
+
let feedback = `Updated task #${task.id}`;
|
|
63
|
+
if (status) {
|
|
64
|
+
feedback += ` → ${status}`;
|
|
65
|
+
// If completed, show which tasks are now unblocked
|
|
66
|
+
if (status === 'completed' && task.blocks.length > 0) {
|
|
67
|
+
const nowUnblocked = task.blocks
|
|
68
|
+
.map(id => tasks.find(t => t.id === id))
|
|
69
|
+
.filter(t => t && t.blockedBy.every(bid => {
|
|
70
|
+
const blocker = tasks.find(bt => bt.id === bid);
|
|
71
|
+
return blocker?.status === 'completed';
|
|
72
|
+
}))
|
|
73
|
+
.map(t => `#${t.id} ${t.subject}`);
|
|
74
|
+
if (nowUnblocked.length > 0) {
|
|
75
|
+
feedback += ` — unblocked: ${nowUnblocked.join(', ')}`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { output: feedback };
|
|
62
80
|
}
|
|
63
81
|
case 'list': {
|
|
64
82
|
if (tasks.length === 0) {
|
package/package.json
CHANGED