@tractorscorch/clank 1.4.5 → 1.4.7
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/CHANGELOG.md +15 -0
- package/README.md +2 -2
- package/dist/index.js +71 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [1.4.7] — 2026-03-22
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- **Tool calling crashes gateway** — context compaction could split tool call / tool result message pairs, sending orphaned messages to Ollama which returns 400 errors and corrupts the session permanently; compaction now drops complete pairs together
|
|
13
|
+
- **Orphaned tool result safety net** — Ollama provider now filters out orphaned tool results before sending to the API, preventing 400 errors even if compaction misses a pair
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## [1.4.6] — 2026-03-22
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **Telegram stutter (for real)** — when the model responds fast, the initial `sendMessage` promise hasn't resolved by the time the full response is ready, causing a duplicate message via the fallback path; now waits for the in-flight message ID before falling back
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
9
24
|
## [1.4.5] — 2026-03-22
|
|
10
25
|
|
|
11
26
|
### Fixed
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="https://github.com/ItsTrag1c/Clank/releases/latest"><img src="https://img.shields.io/badge/version-1.4.
|
|
12
|
+
<a href="https://github.com/ItsTrag1c/Clank/releases/latest"><img src="https://img.shields.io/badge/version-1.4.7-blue.svg" alt="Version" /></a>
|
|
13
13
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License" /></a>
|
|
14
14
|
<a href="https://www.npmjs.com/package/@tractorscorch/clank"><img src="https://img.shields.io/npm/v/@tractorscorch/clank.svg" alt="npm" /></a>
|
|
15
15
|
<a href="https://github.com/ItsTrag1c/Clank/stargazers"><img src="https://img.shields.io/github/stars/ItsTrag1c/Clank.svg" alt="Stars" /></a>
|
|
@@ -75,7 +75,7 @@ That's it. Setup auto-detects your local models, configures the gateway, and get
|
|
|
75
75
|
| Platform | Download |
|
|
76
76
|
|----------|----------|
|
|
77
77
|
| **npm** (all platforms) | `npm install -g @tractorscorch/clank` |
|
|
78
|
-
| **macOS** (Apple Silicon) | [Clank_1.4.
|
|
78
|
+
| **macOS** (Apple Silicon) | [Clank_1.4.7_macos](https://github.com/ItsTrag1c/Clank/releases/latest/download/Clank_1.4.7_macos) |
|
|
79
79
|
|
|
80
80
|
## Features
|
|
81
81
|
|
package/dist/index.js
CHANGED
|
@@ -216,6 +216,8 @@ var init_context_engine = __esm({
|
|
|
216
216
|
}
|
|
217
217
|
/**
|
|
218
218
|
* Tier 1 aggressive: drop oldest messages when regular compaction isn't enough.
|
|
219
|
+
* Drops tool call + tool result pairs together to avoid orphaned messages
|
|
220
|
+
* that cause API errors (Ollama/OpenAI require matching pairs).
|
|
219
221
|
*/
|
|
220
222
|
compactTier1Aggressive() {
|
|
221
223
|
const protectedCount = 6;
|
|
@@ -223,7 +225,38 @@ var init_context_engine = __esm({
|
|
|
223
225
|
while (this.estimateTokens() > budget.conversation * 0.7 && this.messages.length > protectedCount + 2) {
|
|
224
226
|
const dropIdx = this.messages.findIndex((m) => m.role !== "system");
|
|
225
227
|
if (dropIdx === -1 || dropIdx >= this.messages.length - protectedCount) break;
|
|
226
|
-
this.messages
|
|
228
|
+
const msg = this.messages[dropIdx];
|
|
229
|
+
if (msg.role === "assistant" && msg.tool_calls && msg.tool_calls.length > 0) {
|
|
230
|
+
const toolCallIds = new Set(msg.tool_calls.map((tc) => tc.id));
|
|
231
|
+
this.messages.splice(dropIdx, 1);
|
|
232
|
+
for (let i = dropIdx; i < this.messages.length; ) {
|
|
233
|
+
if (this.messages[i].role === "tool" && toolCallIds.has(this.messages[i].tool_call_id || "")) {
|
|
234
|
+
this.messages.splice(i, 1);
|
|
235
|
+
} else {
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
240
|
+
const parentIdx = this.messages.findLastIndex(
|
|
241
|
+
(m, idx) => idx < dropIdx && m.role === "assistant" && m.tool_calls?.some((tc) => tc.id === msg.tool_call_id)
|
|
242
|
+
);
|
|
243
|
+
if (parentIdx >= 0) {
|
|
244
|
+
const parent = this.messages[parentIdx];
|
|
245
|
+
const parentToolIds = new Set(parent.tool_calls.map((tc) => tc.id));
|
|
246
|
+
this.messages.splice(parentIdx, 1);
|
|
247
|
+
for (let i = parentIdx; i < this.messages.length; ) {
|
|
248
|
+
if (this.messages[i].role === "tool" && parentToolIds.has(this.messages[i].tool_call_id || "")) {
|
|
249
|
+
this.messages.splice(i, 1);
|
|
250
|
+
} else {
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
} else {
|
|
255
|
+
this.messages.splice(dropIdx, 1);
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
this.messages.splice(dropIdx, 1);
|
|
259
|
+
}
|
|
227
260
|
}
|
|
228
261
|
}
|
|
229
262
|
/**
|
|
@@ -238,7 +271,10 @@ var init_context_engine = __esm({
|
|
|
238
271
|
if (!this.provider) return;
|
|
239
272
|
const protectedCount = 6;
|
|
240
273
|
if (this.messages.length <= protectedCount + 2) return;
|
|
241
|
-
|
|
274
|
+
let cutoff = Math.max(2, this.messages.length - protectedCount - 2);
|
|
275
|
+
while (cutoff < this.messages.length && this.messages[cutoff].role === "tool") {
|
|
276
|
+
cutoff++;
|
|
277
|
+
}
|
|
242
278
|
const toSummarize = this.messages.slice(0, cutoff);
|
|
243
279
|
const toKeep = this.messages.slice(cutoff);
|
|
244
280
|
const conversationText = toSummarize.map((m) => {
|
|
@@ -478,11 +514,23 @@ var init_ollama = __esm({
|
|
|
478
514
|
}));
|
|
479
515
|
}
|
|
480
516
|
async *stream(messages, systemPrompt, tools, signal) {
|
|
517
|
+
const toolCallIds = /* @__PURE__ */ new Set();
|
|
518
|
+
for (const msg of messages) {
|
|
519
|
+
if (msg.role === "assistant" && msg.tool_calls) {
|
|
520
|
+
for (const tc of msg.tool_calls) toolCallIds.add(tc.id);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
const sanitized = messages.filter((msg) => {
|
|
524
|
+
if (msg.role === "tool" && msg.tool_call_id && !toolCallIds.has(msg.tool_call_id)) {
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
return true;
|
|
528
|
+
});
|
|
481
529
|
const apiMessages = [];
|
|
482
530
|
if (systemPrompt) {
|
|
483
531
|
apiMessages.push({ role: "system", content: systemPrompt });
|
|
484
532
|
}
|
|
485
|
-
for (const msg of
|
|
533
|
+
for (const msg of sanitized) {
|
|
486
534
|
if (msg.role === "tool") {
|
|
487
535
|
apiMessages.push({
|
|
488
536
|
role: "tool",
|
|
@@ -5275,6 +5323,20 @@ var init_telegram = __esm({
|
|
|
5275
5323
|
}
|
|
5276
5324
|
}
|
|
5277
5325
|
);
|
|
5326
|
+
if (sendingInitial && !streamMsgId) {
|
|
5327
|
+
await new Promise((r) => {
|
|
5328
|
+
const check2 = setInterval(() => {
|
|
5329
|
+
if (streamMsgId) {
|
|
5330
|
+
clearInterval(check2);
|
|
5331
|
+
r();
|
|
5332
|
+
}
|
|
5333
|
+
}, 50);
|
|
5334
|
+
setTimeout(() => {
|
|
5335
|
+
clearInterval(check2);
|
|
5336
|
+
r();
|
|
5337
|
+
}, 3e3);
|
|
5338
|
+
});
|
|
5339
|
+
}
|
|
5278
5340
|
if (streamMsgId && response) {
|
|
5279
5341
|
const finalText = response.length > 4e3 ? response.slice(0, 3950) + "\n... (truncated)" : response;
|
|
5280
5342
|
await bot.api.editMessageText(chatId, streamMsgId, finalText).catch(() => {
|
|
@@ -6064,7 +6126,7 @@ var init_server = __esm({
|
|
|
6064
6126
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6065
6127
|
res.end(JSON.stringify({
|
|
6066
6128
|
status: "ok",
|
|
6067
|
-
version: "1.4.
|
|
6129
|
+
version: "1.4.7",
|
|
6068
6130
|
uptime: process.uptime(),
|
|
6069
6131
|
clients: this.clients.size,
|
|
6070
6132
|
agents: this.engines.size
|
|
@@ -6176,7 +6238,7 @@ var init_server = __esm({
|
|
|
6176
6238
|
const hello = {
|
|
6177
6239
|
type: "hello",
|
|
6178
6240
|
protocol: PROTOCOL_VERSION,
|
|
6179
|
-
version: "1.4.
|
|
6241
|
+
version: "1.4.7",
|
|
6180
6242
|
agents: this.config.agents.list.map((a) => ({
|
|
6181
6243
|
id: a.id,
|
|
6182
6244
|
name: a.name || a.id,
|
|
@@ -7570,7 +7632,7 @@ async function runTui(opts) {
|
|
|
7570
7632
|
ws.on("open", () => {
|
|
7571
7633
|
ws.send(JSON.stringify({
|
|
7572
7634
|
type: "connect",
|
|
7573
|
-
params: { auth: { token }, mode: "tui", version: "1.4.
|
|
7635
|
+
params: { auth: { token }, mode: "tui", version: "1.4.7" }
|
|
7574
7636
|
}));
|
|
7575
7637
|
});
|
|
7576
7638
|
ws.on("message", (data) => {
|
|
@@ -7872,14 +7934,14 @@ async function runUpdate() {
|
|
|
7872
7934
|
}
|
|
7873
7935
|
console.log(dim9(" Pulling latest version..."));
|
|
7874
7936
|
try {
|
|
7875
|
-
const output = execSync2("npm install -g @tractorscorch/clank@latest --force", {
|
|
7937
|
+
const output = execSync2("npm install -g @tractorscorch/clank@latest --force --prefer-online", {
|
|
7876
7938
|
encoding: "utf-8",
|
|
7877
7939
|
timeout: 12e4
|
|
7878
7940
|
});
|
|
7879
7941
|
console.log(dim9(` ${output.trim()}`));
|
|
7880
7942
|
} catch (err) {
|
|
7881
7943
|
console.error(red6(` Update failed: ${err instanceof Error ? err.message : err}`));
|
|
7882
|
-
console.error(dim9(" Try manually: npm install -g @tractorscorch/clank@latest --force"));
|
|
7944
|
+
console.error(dim9(" Try manually: npm install -g @tractorscorch/clank@latest --force --prefer-online"));
|
|
7883
7945
|
return;
|
|
7884
7946
|
}
|
|
7885
7947
|
try {
|
|
@@ -7999,7 +8061,7 @@ import { fileURLToPath as fileURLToPath5 } from "url";
|
|
|
7999
8061
|
import { dirname as dirname5, join as join19 } from "path";
|
|
8000
8062
|
var __filename3 = fileURLToPath5(import.meta.url);
|
|
8001
8063
|
var __dirname3 = dirname5(__filename3);
|
|
8002
|
-
var version = "1.4.
|
|
8064
|
+
var version = "1.4.7";
|
|
8003
8065
|
try {
|
|
8004
8066
|
const pkg = JSON.parse(readFileSync(join19(__dirname3, "..", "package.json"), "utf-8"));
|
|
8005
8067
|
version = pkg.version;
|