ns-kiro-core 0.1.2 → 0.2.0
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/cost.d.ts +6 -1
- package/dist/cost.js +9 -2
- package/dist/cost.js.map +1 -1
- package/dist/effort.js +10 -2
- package/dist/effort.js.map +1 -1
- package/dist/event-parser.d.ts +28 -4
- package/dist/event-parser.js +40 -1
- package/dist/event-parser.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kiro-cli.d.ts +17 -0
- package/dist/kiro-cli.js +47 -1
- package/dist/kiro-cli.js.map +1 -1
- package/dist/models.d.ts +10 -2
- package/dist/models.js +70 -4
- package/dist/models.js.map +1 -1
- package/dist/request-builder.d.ts +49 -0
- package/dist/request-builder.js +229 -0
- package/dist/request-builder.js.map +1 -0
- package/dist/response-assembler.d.ts +89 -0
- package/dist/response-assembler.js +330 -0
- package/dist/response-assembler.js.map +1 -0
- package/dist/response-stream.d.ts +39 -0
- package/dist/response-stream.js +123 -0
- package/dist/response-stream.js.map +1 -0
- package/dist/stream.js +72 -621
- package/dist/stream.js.map +1 -1
- package/dist/transport.d.ts +24 -0
- package/dist/transport.js +80 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +30 -0
- package/package.json +6 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { KiroAdditionalModelRequestFields } from "./effort.js";
|
|
2
|
+
import type { KiroModel } from "./models.js";
|
|
3
|
+
import { type KiroHistoryEntry, type KiroUserInputMessage } from "./transform.js";
|
|
4
|
+
import type { KiroMessage, KiroTool } from "./types.js";
|
|
5
|
+
export interface KiroRequest {
|
|
6
|
+
conversationState: {
|
|
7
|
+
chatTriggerType: "MANUAL";
|
|
8
|
+
agentTaskType: "vibe";
|
|
9
|
+
conversationId: string;
|
|
10
|
+
currentMessage: {
|
|
11
|
+
userInputMessage: KiroUserInputMessage;
|
|
12
|
+
};
|
|
13
|
+
history?: KiroHistoryEntry[];
|
|
14
|
+
};
|
|
15
|
+
additionalModelRequestFields?: KiroAdditionalModelRequestFields;
|
|
16
|
+
profileArn: string;
|
|
17
|
+
agentMode?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface BuildKiroRequestParams {
|
|
20
|
+
messages: KiroMessage[];
|
|
21
|
+
model: KiroModel;
|
|
22
|
+
kiroModelId: string;
|
|
23
|
+
/** Already carries any thinking markers the caller decided to prepend. */
|
|
24
|
+
systemPrompt: string;
|
|
25
|
+
tools?: KiroTool[];
|
|
26
|
+
conversationId: string;
|
|
27
|
+
profileArn: string;
|
|
28
|
+
additionalModelRequestFields?: KiroAdditionalModelRequestFields;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The request plus what was actually put on the wire.
|
|
32
|
+
*
|
|
33
|
+
* The counts describe the post-repair body, not the caller's input: they exist
|
|
34
|
+
* to be correlated against a rejection, so they must describe the bytes sent.
|
|
35
|
+
*/
|
|
36
|
+
export interface BuiltKiroRequest {
|
|
37
|
+
request: KiroRequest;
|
|
38
|
+
wireHistoryLength: number;
|
|
39
|
+
wireContentLength: number;
|
|
40
|
+
hasImages: boolean;
|
|
41
|
+
toolResultCount: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Assemble the body for one Kiro runtime call.
|
|
45
|
+
*
|
|
46
|
+
* Throws when the local history exceeds its budget, rather than silently
|
|
47
|
+
* dropping context the caller believes it sent.
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildKiroRequest(params: BuildKiroRequestParams): BuiltKiroRequest;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// ABOUTME: Builds the Kiro runtime request body from a neutral conversation.
|
|
2
|
+
// ABOUTME: Pure and side-effect free, so request shaping is testable without a transport.
|
|
3
|
+
import { debugLog } from "./debug.js";
|
|
4
|
+
import { addPlaceholderTools, assertHistoryWithinLimit, HISTORY_LIMIT, HISTORY_LIMIT_CONTEXT_WINDOW, prepareHistory, } from "./history.js";
|
|
5
|
+
import { isKiroToolStructureRule, kiroConversationEntries, repairKiroConversation } from "./history-validator.js";
|
|
6
|
+
import { buildHistory, convertImagesToKiro, convertToolsToKiro, EMPTY_CONTENT_PLACEHOLDER, extractImages, getContentText, normalizeMessages, relocateDisplacedToolResults, sanitizeSurrogates, TOOL_RESULT_LIMIT, toKiroToolUseId, truncate, } from "./transform.js";
|
|
7
|
+
import { TRUNCATION_NOTICE, wasPreviousResponseTruncated } from "./truncation.js";
|
|
8
|
+
function toolResultOf(message) {
|
|
9
|
+
return {
|
|
10
|
+
content: [{ text: truncate(getContentText(message), TOOL_RESULT_LIMIT) }],
|
|
11
|
+
status: message.isError ? "error" : "success",
|
|
12
|
+
toolUseId: toKiroToolUseId(message.toolCallId),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Assemble the body for one Kiro runtime call.
|
|
17
|
+
*
|
|
18
|
+
* Throws when the local history exceeds its budget, rather than silently
|
|
19
|
+
* dropping context the caller believes it sent.
|
|
20
|
+
*/
|
|
21
|
+
export function buildKiroRequest(params) {
|
|
22
|
+
const { messages, model, kiroModelId, systemPrompt, tools, conversationId, profileArn } = params;
|
|
23
|
+
// Relocate a tool result that arrived behind a later assistant turn than the
|
|
24
|
+
// one that called it, before anything positional runs. Interleaved concurrent
|
|
25
|
+
// tool executions produce that shape, and `sanitizeHistory` pairs
|
|
26
|
+
// POSITIONALLY, so without this pass the displaced result's issuing assistant
|
|
27
|
+
// is dropped and the real tool output is discarded.
|
|
28
|
+
const normalized = relocateDisplacedToolResults(normalizeMessages(messages));
|
|
29
|
+
const { history: rawHistory, systemPrepended, currentMsgStartIdx, } = buildHistory(normalized, kiroModelId, systemPrompt);
|
|
30
|
+
// Preserve semantic context locally; the host owns lossy compaction.
|
|
31
|
+
const history = prepareHistory(rawHistory, model.input.includes("image"));
|
|
32
|
+
const dynamicHistoryLimit = Math.floor((model.contextWindow / HISTORY_LIMIT_CONTEXT_WINDOW) * HISTORY_LIMIT);
|
|
33
|
+
const currentMessages = normalized.slice(currentMsgStartIdx);
|
|
34
|
+
const firstMsg = currentMessages[0];
|
|
35
|
+
let currentContent = "";
|
|
36
|
+
const currentToolResults = [];
|
|
37
|
+
let currentImages;
|
|
38
|
+
if (firstMsg?.role === "assistant") {
|
|
39
|
+
let armContent = "";
|
|
40
|
+
const armToolUses = [];
|
|
41
|
+
for (const block of firstMsg.content) {
|
|
42
|
+
if (block.type === "text")
|
|
43
|
+
armContent += block.text;
|
|
44
|
+
// Reasoning is deliberately NOT serialized into the assistant text
|
|
45
|
+
// channel, matching `buildHistory`. Flattening it to
|
|
46
|
+
// `<thinking>...</thinking>` writes literal markup into the string the
|
|
47
|
+
// model reads back as its own prior speech.
|
|
48
|
+
else if (block.type === "toolCall") {
|
|
49
|
+
armToolUses.push({ name: block.name, toolUseId: toKiroToolUseId(block.id), input: block.arguments });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (armContent || armToolUses.length > 0) {
|
|
53
|
+
const prevArm = history[history.length - 1]?.assistantResponseMessage;
|
|
54
|
+
if (history.length > 0 && !history[history.length - 1]?.userInputMessage && prevArm) {
|
|
55
|
+
// Merge into previous assistant message to maintain alternation
|
|
56
|
+
// without synthetic padding. Join only non-empty sides: a turn that
|
|
57
|
+
// carried only reasoning or only a tool call leaves `armContent`
|
|
58
|
+
// empty, and an unconditional separator would append a bare `\n\n`
|
|
59
|
+
// onto text the model actually produced.
|
|
60
|
+
prevArm.content =
|
|
61
|
+
prevArm.content && armContent ? `${prevArm.content}\n\n${armContent}` : prevArm.content || armContent;
|
|
62
|
+
if (armToolUses.length > 0)
|
|
63
|
+
prevArm.toolUses = [...(prevArm.toolUses || []), ...armToolUses];
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
history.push({
|
|
67
|
+
assistantResponseMessage: {
|
|
68
|
+
content: armContent,
|
|
69
|
+
...(armToolUses.length > 0 ? { toolUses: armToolUses } : {}),
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const toolResultImages = [];
|
|
75
|
+
for (let i = 1; i < currentMessages.length; i++) {
|
|
76
|
+
const m = currentMessages[i];
|
|
77
|
+
if (m?.role !== "toolResult")
|
|
78
|
+
continue;
|
|
79
|
+
currentToolResults.push(toolResultOf(m));
|
|
80
|
+
toolResultImages.push(...extractImages(m));
|
|
81
|
+
}
|
|
82
|
+
if (toolResultImages.length > 0)
|
|
83
|
+
currentImages = convertImagesToKiro(toolResultImages);
|
|
84
|
+
// A tool turn carries its payload in `userInputMessageContext.toolResults`,
|
|
85
|
+
// so it needs no text. Leaving this empty also leaves the fallback below
|
|
86
|
+
// free to fill in only genuinely payload-less turns.
|
|
87
|
+
currentContent = "";
|
|
88
|
+
}
|
|
89
|
+
else if (firstMsg?.role === "toolResult") {
|
|
90
|
+
const toolResultImages = [];
|
|
91
|
+
for (const m of currentMessages) {
|
|
92
|
+
if (m.role !== "toolResult")
|
|
93
|
+
continue;
|
|
94
|
+
currentToolResults.push(toolResultOf(m));
|
|
95
|
+
toolResultImages.push(...extractImages(m));
|
|
96
|
+
}
|
|
97
|
+
if (toolResultImages.length > 0)
|
|
98
|
+
currentImages = convertImagesToKiro(toolResultImages);
|
|
99
|
+
// Empty by design — `toolResults` is this turn's payload.
|
|
100
|
+
currentContent = "";
|
|
101
|
+
}
|
|
102
|
+
else if (firstMsg?.role === "user") {
|
|
103
|
+
currentContent = getContentText(firstMsg);
|
|
104
|
+
if (systemPrompt && !systemPrepended)
|
|
105
|
+
currentContent = `${systemPrompt}\n\n${currentContent}`;
|
|
106
|
+
}
|
|
107
|
+
// Current assistant tool calls are outbound history too, so enforce the
|
|
108
|
+
// budget only after they have been appended.
|
|
109
|
+
assertHistoryWithinLimit(history, dynamicHistoryLimit);
|
|
110
|
+
if (wasPreviousResponseTruncated(messages)) {
|
|
111
|
+
currentContent = currentContent === "" ? TRUNCATION_NOTICE : `${TRUNCATION_NOTICE}\n\n${currentContent}`;
|
|
112
|
+
}
|
|
113
|
+
// Always synthesize placeholder specs for tool names referenced in history,
|
|
114
|
+
// even when the caller declares none. Without this, a call that inherits a
|
|
115
|
+
// tool-rich conversation but declares no current tools is rejected by Kiro
|
|
116
|
+
// as "Improperly formed request", because history references toolUses with
|
|
117
|
+
// no tool catalog.
|
|
118
|
+
let uimc;
|
|
119
|
+
const baseTools = tools?.length ? convertToolsToKiro(tools) : [];
|
|
120
|
+
const finalTools = history.length > 0 ? addPlaceholderTools(baseTools, history) : baseTools;
|
|
121
|
+
if (currentToolResults.length > 0 || finalTools.length > 0) {
|
|
122
|
+
uimc = {};
|
|
123
|
+
if (currentToolResults.length > 0)
|
|
124
|
+
uimc.toolResults = currentToolResults;
|
|
125
|
+
if (finalTools.length > 0)
|
|
126
|
+
uimc.tools = finalTools;
|
|
127
|
+
}
|
|
128
|
+
if (firstMsg?.role === "user") {
|
|
129
|
+
const imgs = extractImages(firstMsg);
|
|
130
|
+
if (imgs.length > 0)
|
|
131
|
+
currentImages = convertImagesToKiro(imgs);
|
|
132
|
+
}
|
|
133
|
+
// A turn with neither text nor tool results has no payload at all: an
|
|
134
|
+
// image-only user message, or an empty-text one. Send a neutral prompt so
|
|
135
|
+
// its attachments still reach the model.
|
|
136
|
+
//
|
|
137
|
+
// The `currentToolResults` guard is load-bearing. Without it this line
|
|
138
|
+
// refills every tool turn that deliberately left `currentContent` empty.
|
|
139
|
+
// Kiro's rule is content **or** tool results — see EMPTY_CONTENT_PLACEHOLDER.
|
|
140
|
+
if (currentContent === "" && currentToolResults.length === 0)
|
|
141
|
+
currentContent = EMPTY_CONTENT_PLACEHOLDER;
|
|
142
|
+
// Pre-send REPAIR against the rules first-party Kiro Agent enforces.
|
|
143
|
+
// `prepareHistory` covers the shapes this provider itself produces, but not
|
|
144
|
+
// every shape a caller can hand us: `sanitizeHistory` tests tool pairing by
|
|
145
|
+
// POSITION, so an assistant entry with `toolUses` survives whenever the next
|
|
146
|
+
// entry carries any `toolResults` at all, matching ids or not, and
|
|
147
|
+
// `injectSyntheticToolCalls` only rescues orphaned RESULTS. A mismatched
|
|
148
|
+
// pair — both partners present, paired with each other's counterpart —
|
|
149
|
+
// passes both passes untouched and is rejected on the wire with
|
|
150
|
+
// `400 TOOL_USE_RESULT_MISMATCH`.
|
|
151
|
+
//
|
|
152
|
+
// Repair runs on the WHOLE conversation and is split back afterwards.
|
|
153
|
+
// Repairing `history` alone would be wrong in the ordinary case: its last
|
|
154
|
+
// entry is normally the assistant whose `toolUses` this very request
|
|
155
|
+
// answers, so rule 4 would synthesize a FAILED result for a call whose real
|
|
156
|
+
// output is sitting in the current message.
|
|
157
|
+
const conversationEntries = kiroConversationEntries(history, {
|
|
158
|
+
content: currentContent,
|
|
159
|
+
modelId: kiroModelId,
|
|
160
|
+
origin: "KIRO_CLI",
|
|
161
|
+
...(uimc ? { userInputMessageContext: uimc } : {}),
|
|
162
|
+
});
|
|
163
|
+
const repair = repairKiroConversation(conversationEntries);
|
|
164
|
+
if (repair.diagnostics.length > 0) {
|
|
165
|
+
debugLog("request.invariants", { errors: repair.diagnostics, remaining: repair.remaining });
|
|
166
|
+
}
|
|
167
|
+
// Split back. Repair keeps the current message last in every case but total
|
|
168
|
+
// collapse, where a conversation that is *only* a bare tool-result carrier
|
|
169
|
+
// has no valid opening entry and step 1 consumes it.
|
|
170
|
+
const repairedCurrent = repair.entries[repair.entries.length - 1]?.userInputMessage;
|
|
171
|
+
// Read the repaired context EXACTLY, including when repair removed it. A
|
|
172
|
+
// `?? uimc` fallback would undo the repair in the one case that matters
|
|
173
|
+
// most: stripping every orphaned tool result leaves a turn with no context
|
|
174
|
+
// at all, and falling back would put the orphans — the shape the backend
|
|
175
|
+
// rejects — straight back onto the wire.
|
|
176
|
+
let wireHistory;
|
|
177
|
+
let wireContent;
|
|
178
|
+
let wireUimc;
|
|
179
|
+
if (repairedCurrent) {
|
|
180
|
+
wireHistory = repair.entries.slice(0, -1);
|
|
181
|
+
wireContent = repairedCurrent.content;
|
|
182
|
+
wireUimc = repairedCurrent.userInputMessageContext;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// Collapsed. Apply what repair would have applied to a lone carrier: drop
|
|
186
|
+
// the results that answer nothing, keep any tool catalog, and give the
|
|
187
|
+
// empty turn the neutral prompt.
|
|
188
|
+
wireHistory = [];
|
|
189
|
+
wireContent = currentContent || EMPTY_CONTENT_PLACEHOLDER;
|
|
190
|
+
wireUimc = uimc?.tools?.length ? { tools: uimc.tools } : undefined;
|
|
191
|
+
}
|
|
192
|
+
if (repair.remaining.length > 0) {
|
|
193
|
+
const structural = repair.remaining.filter((e) => isKiroToolStructureRule(e.rule));
|
|
194
|
+
if (structural.length > 0) {
|
|
195
|
+
console.warn(`[kiro-core] outbound history still violates ${structural
|
|
196
|
+
.map((e) => `${e.rule}@${e.index}`)
|
|
197
|
+
.join(", ")} after repair — Kiro may reject this request`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
request: {
|
|
202
|
+
conversationState: {
|
|
203
|
+
chatTriggerType: "MANUAL",
|
|
204
|
+
agentTaskType: "vibe",
|
|
205
|
+
conversationId,
|
|
206
|
+
currentMessage: {
|
|
207
|
+
userInputMessage: {
|
|
208
|
+
content: sanitizeSurrogates(wireContent),
|
|
209
|
+
modelId: kiroModelId,
|
|
210
|
+
origin: "KIRO_CLI",
|
|
211
|
+
...(currentImages ? { images: currentImages } : {}),
|
|
212
|
+
...(wireUimc ? { userInputMessageContext: wireUimc } : {}),
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
...(wireHistory.length > 0 ? { history: wireHistory } : {}),
|
|
216
|
+
},
|
|
217
|
+
...(params.additionalModelRequestFields
|
|
218
|
+
? { additionalModelRequestFields: params.additionalModelRequestFields }
|
|
219
|
+
: {}),
|
|
220
|
+
profileArn,
|
|
221
|
+
agentMode: "vibe",
|
|
222
|
+
},
|
|
223
|
+
wireHistoryLength: wireHistory.length,
|
|
224
|
+
wireContentLength: wireContent.length,
|
|
225
|
+
hasImages: !!currentImages,
|
|
226
|
+
toolResultCount: wireUimc?.toolResults?.length ?? 0,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=request-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-builder.js","sourceRoot":"","sources":["../src/request-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { KiroModel } from "./models.js";
|
|
2
|
+
import type { KiroWireEventFrame } from "./response-stream.js";
|
|
3
|
+
import type { KiroStreamEvent, KiroUsage } from "./types.js";
|
|
4
|
+
/** What the finished attempt produced, before the caller decides to keep it. */
|
|
5
|
+
export interface KiroAttemptSummary {
|
|
6
|
+
responseText: string;
|
|
7
|
+
hasText: boolean;
|
|
8
|
+
sawAnyToolCalls: boolean;
|
|
9
|
+
emittedToolCalls: number;
|
|
10
|
+
/** The whole turn is a "Continue" echo taught by synthetic padding. */
|
|
11
|
+
isEchoLoop: boolean;
|
|
12
|
+
/** No text and no tool calls: a 200 that said nothing. */
|
|
13
|
+
isEmpty: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface KiroCompletedResponse {
|
|
16
|
+
stopReason: "stop" | "toolUse" | "length";
|
|
17
|
+
usage: KiroUsage;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Accumulates one response.
|
|
21
|
+
*
|
|
22
|
+
* Block indexes are monotonic across the whole call, including across an
|
|
23
|
+
* internal retry, so the buffer and the usage totals outlive a single attempt
|
|
24
|
+
* while everything else is reset by {@link beginAttempt}.
|
|
25
|
+
*/
|
|
26
|
+
export declare class KiroResponseAssembler {
|
|
27
|
+
private readonly model;
|
|
28
|
+
private readonly thinkingEnabled;
|
|
29
|
+
private readonly pending;
|
|
30
|
+
private readonly blocks;
|
|
31
|
+
private readonly usage;
|
|
32
|
+
private totalContent;
|
|
33
|
+
private lastContentData;
|
|
34
|
+
private usageEvent;
|
|
35
|
+
private receivedContextUsage;
|
|
36
|
+
private thinkingParser;
|
|
37
|
+
private nativeThinkingBlockIndex;
|
|
38
|
+
private nativeThinkingEnded;
|
|
39
|
+
private textBlockIndex;
|
|
40
|
+
private emittedToolCalls;
|
|
41
|
+
private sawAnyToolCalls;
|
|
42
|
+
private currentToolCall;
|
|
43
|
+
constructor(model: KiroModel, thinkingEnabled: boolean);
|
|
44
|
+
/** Clear per-attempt state. Block indexes and accumulated usage are kept. */
|
|
45
|
+
beginAttempt(): void;
|
|
46
|
+
/** Hand over the events buffered so far. */
|
|
47
|
+
takeEvents(): KiroStreamEvent[];
|
|
48
|
+
/** Announce that a retry discarded everything emitted so far. */
|
|
49
|
+
discard(): void;
|
|
50
|
+
handle(frame: KiroWireEventFrame): void;
|
|
51
|
+
/**
|
|
52
|
+
* Close the turn: flush a trailing tool call, close thinking, and run the
|
|
53
|
+
* text-dialect recovery and echo-stripping passes.
|
|
54
|
+
*/
|
|
55
|
+
endTurn(): KiroAttemptSummary;
|
|
56
|
+
/** Drop an echo the caller decided not to retry, so it is not read as a continuation signal. */
|
|
57
|
+
stripEcho(): void;
|
|
58
|
+
/** Close the text block and settle usage and the stop reason. */
|
|
59
|
+
complete(): KiroCompletedResponse;
|
|
60
|
+
private ensureNativeThinkingBlock;
|
|
61
|
+
private endNativeThinking;
|
|
62
|
+
private emitToolCall;
|
|
63
|
+
private flushToolCall;
|
|
64
|
+
/**
|
|
65
|
+
* Extract text-dialect tool calls from content when no native tool calls
|
|
66
|
+
* arrived. Two dialects are recovered at this seam:
|
|
67
|
+
* 1. Kiro's own `[Called name with args: {...}]` bracket form.
|
|
68
|
+
* 2. Anthropic's `<invoke name="..."><parameter .../></invoke>` XML form,
|
|
69
|
+
* which opus-class models emit as plain text at high context.
|
|
70
|
+
* Without this, the turn ends `stop` with zero tool calls — the agent loop
|
|
71
|
+
* sees a finished answer and an unattended session stalls with no error
|
|
72
|
+
* recorded anywhere.
|
|
73
|
+
*
|
|
74
|
+
* Models that emit native tool-use events opt out via
|
|
75
|
+
* `recoverTextToolCalls: false`. For them this pass has nothing to rescue
|
|
76
|
+
* and everything to break: prose that merely *quotes* the syntax — a model
|
|
77
|
+
* explaining how a tool is called — would be lifted into a real call the
|
|
78
|
+
* model never made. Absent means recover, so a model the catalog says
|
|
79
|
+
* nothing about keeps the fallback.
|
|
80
|
+
*/
|
|
81
|
+
private recoverTextToolCalls;
|
|
82
|
+
/**
|
|
83
|
+
* Strip echo noise: when tool calls are present and the text content is just
|
|
84
|
+
* "." or a similar short echo from history padding, remove it. This prevents
|
|
85
|
+
* the echo from accumulating in conversation history and reinforcing the
|
|
86
|
+
* pattern in future turns.
|
|
87
|
+
*/
|
|
88
|
+
private stripEchoNoise;
|
|
89
|
+
}
|