@yeaft/webchat-agent 0.1.680 → 0.1.682
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/package.json +1 -1
- package/unify/tool-folding/index.js +38 -8
package/package.json
CHANGED
|
@@ -23,12 +23,27 @@ export { buildFallbackStub } from './fallback-stub.js';
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Collapse messages[startIdx..endIdx] (inclusive) into a single
|
|
26
|
-
* `{ role: '
|
|
27
|
-
* mutate the input.
|
|
26
|
+
* `{ role: 'user', content }` reflection message. Returns a NEW array; does
|
|
27
|
+
* not mutate the input.
|
|
28
28
|
*
|
|
29
|
-
* The original assistant+tool sequence (the action arc) is replaced by
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
* The original assistant+tool sequence (the action arc) is replaced by ONE
|
|
30
|
+
* synthetic user message carrying the reflection summary. User messages
|
|
31
|
+
* that happened to appear inside the range stay put (defensive — the caller
|
|
32
|
+
* normally passes a range that contains only assistant+tool).
|
|
33
|
+
*
|
|
34
|
+
* Why role='user' (not 'assistant'):
|
|
35
|
+
* The Anthropic Messages API requires the messages array to end with a
|
|
36
|
+
* user message before the next assistant turn. If we collapsed into an
|
|
37
|
+
* assistant message and the reflection happened to land at the tail
|
|
38
|
+
* (e.g. immediately before #applyPendingT2Reflections fires its next
|
|
39
|
+
* query), the API rejects the request with "model does not support
|
|
40
|
+
* assistant message prefill".
|
|
41
|
+
*
|
|
42
|
+
* Following Claude Code's compact pattern, we wrap the reflection as a
|
|
43
|
+
* synthetic user message — the model treats it as a context-recovery
|
|
44
|
+
* directive and continues from there. The opening line ("The previous N
|
|
45
|
+
* tool calls have been folded ...") plus the closing "Continue from
|
|
46
|
+
* here." make it unambiguous that this is not a fresh user prompt.
|
|
32
47
|
*
|
|
33
48
|
* @param {Array} messages
|
|
34
49
|
* @param {number} startIdx
|
|
@@ -43,13 +58,28 @@ export function collapseRangeToReflection(messages, startIdx, endIdx, reflection
|
|
|
43
58
|
const collapsed = messages.slice(startIdx, endIdx + 1);
|
|
44
59
|
const after = messages.slice(endIdx + 1);
|
|
45
60
|
|
|
61
|
+
// Count tool_use occurrences inside the collapsed range so the wrapper
|
|
62
|
+
// text can name how many calls were folded. Falls back to "previous"
|
|
63
|
+
// wording when no tool calls are detected.
|
|
64
|
+
let toolCount = 0;
|
|
65
|
+
for (const m of collapsed) {
|
|
66
|
+
if (m && m.role === 'assistant' && Array.isArray(m.toolCalls)) {
|
|
67
|
+
toolCount += m.toolCalls.length;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
46
71
|
// Preserve any user messages that happened to appear inside the range
|
|
47
72
|
// (not expected per V7 spec, but defensive). Everything else (assistant +
|
|
48
|
-
// tool) is replaced by ONE
|
|
73
|
+
// tool) is replaced by ONE synthetic user reflection message.
|
|
49
74
|
const preservedUsers = collapsed.filter(m => m && m.role === 'user');
|
|
75
|
+
const header = toolCount > 0
|
|
76
|
+
? `The previous ${toolCount} tool call${toolCount === 1 ? '' : 's'} have been folded for context efficiency.`
|
|
77
|
+
: 'The previous tool calls have been folded for context efficiency.';
|
|
78
|
+
const wrappedContent =
|
|
79
|
+
`${header}\n\nSummary:\n${reflectionContent}\n\nContinue from here.`;
|
|
50
80
|
const reflectionMsg = {
|
|
51
|
-
role: '
|
|
52
|
-
content:
|
|
81
|
+
role: 'user',
|
|
82
|
+
content: wrappedContent,
|
|
53
83
|
_reflection: true,
|
|
54
84
|
};
|
|
55
85
|
return [...before, ...preservedUsers, reflectionMsg, ...after];
|