@tractorscorch/clank 1.5.1 → 1.5.3
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 +16 -0
- package/README.md +2 -2
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [1.5.3] — 2026-03-23
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- **Local thinking models return empty responses** — Qwen3.5 puts all output in `reasoning_content` with empty `content`, and `enable_thinking:false` doesn't work (chat template overrides it). Now treats `reasoning_content` as text for local models so the user actually sees a response
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## [1.5.2] — 2026-03-23
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- **Thinking models (Qwen3.5) exhaust tokens on reasoning** — the model generates `<think>` reasoning tokens that eat the entire context window, leaving nothing for actual content. Added default `max_tokens: 4096` for local models and `reasoning_effort: "low"` to reduce thinking overhead
|
|
20
|
+
- **Telegram shows nothing during model thinking** — added periodic "typing" indicator every 4 seconds so the bot doesn't appear dead while the model processes internally
|
|
21
|
+
- **Root cause found via direct API testing** — Qwen3.5-35B returns empty `content` with all output in `reasoning_content`; without a max_tokens cap, the model spends all its budget on thinking
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
9
25
|
## [1.5.1] — 2026-03-23
|
|
10
26
|
|
|
11
27
|
### 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.5.
|
|
12
|
+
<a href="https://github.com/ItsTrag1c/Clank/releases/latest"><img src="https://img.shields.io/badge/version-1.5.3-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.5.
|
|
78
|
+
| **macOS** (Apple Silicon) | [Clank_1.5.3_macos](https://github.com/ItsTrag1c/Clank/releases/latest/download/Clank_1.5.3_macos) |
|
|
79
79
|
|
|
80
80
|
## Features
|
|
81
81
|
|
package/dist/index.js
CHANGED
|
@@ -2987,11 +2987,16 @@ var init_openai = __esm({
|
|
|
2987
2987
|
stream: true,
|
|
2988
2988
|
stream_options: { include_usage: true }
|
|
2989
2989
|
};
|
|
2990
|
+
if (this.isLocal) {
|
|
2991
|
+
body.reasoning_effort = "low";
|
|
2992
|
+
}
|
|
2990
2993
|
if (tools.length > 0) {
|
|
2991
2994
|
body.tools = this.formatTools(tools);
|
|
2992
2995
|
}
|
|
2993
2996
|
if (this.maxResponseTokens) {
|
|
2994
2997
|
body.max_tokens = this.maxResponseTokens;
|
|
2998
|
+
} else if (this.isLocal) {
|
|
2999
|
+
body.max_tokens = 4096;
|
|
2995
3000
|
}
|
|
2996
3001
|
const headers = {
|
|
2997
3002
|
"Content-Type": "application/json"
|
|
@@ -3045,7 +3050,11 @@ var init_openai = __esm({
|
|
|
3045
3050
|
const chunk = JSON.parse(data);
|
|
3046
3051
|
const choice = chunk.choices?.[0];
|
|
3047
3052
|
if (choice?.delta?.reasoning_content) {
|
|
3048
|
-
|
|
3053
|
+
if (this.isLocal) {
|
|
3054
|
+
yield { type: "text", content: choice.delta.reasoning_content };
|
|
3055
|
+
} else {
|
|
3056
|
+
yield { type: "thinking", content: choice.delta.reasoning_content };
|
|
3057
|
+
}
|
|
3049
3058
|
}
|
|
3050
3059
|
if (choice?.delta?.content) {
|
|
3051
3060
|
yield { type: "text", content: choice.delta.content };
|
|
@@ -5298,6 +5307,10 @@ var init_telegram = __esm({
|
|
|
5298
5307
|
try {
|
|
5299
5308
|
console.log(` Telegram: processing message from ${userId} in ${chatId}`);
|
|
5300
5309
|
await ctx.api.sendChatAction(chatId, "typing");
|
|
5310
|
+
const typingInterval2 = setInterval(() => {
|
|
5311
|
+
bot.api.sendChatAction(chatId, "typing").catch(() => {
|
|
5312
|
+
});
|
|
5313
|
+
}, 4e3);
|
|
5301
5314
|
let streamMsgId = null;
|
|
5302
5315
|
let sendingInitial = false;
|
|
5303
5316
|
let accumulated = "";
|
|
@@ -5366,8 +5379,10 @@ var init_telegram = __esm({
|
|
|
5366
5379
|
await ctx.api.sendMessage(chatId, chunk);
|
|
5367
5380
|
}
|
|
5368
5381
|
}
|
|
5382
|
+
clearInterval(typingInterval2);
|
|
5369
5383
|
console.log(` Telegram: response complete (${response?.length || 0} chars)`);
|
|
5370
5384
|
} catch (err) {
|
|
5385
|
+
clearInterval(typingInterval);
|
|
5371
5386
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
5372
5387
|
console.error(` Telegram: message handler error \u2014 ${errMsg}`);
|
|
5373
5388
|
await ctx.api.sendMessage(chatId, `Error: ${errMsg.slice(0, 200)}`).catch(() => {
|
|
@@ -6155,7 +6170,7 @@ var init_server = __esm({
|
|
|
6155
6170
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6156
6171
|
res.end(JSON.stringify({
|
|
6157
6172
|
status: "ok",
|
|
6158
|
-
version: "1.5.
|
|
6173
|
+
version: "1.5.3",
|
|
6159
6174
|
uptime: process.uptime(),
|
|
6160
6175
|
clients: this.clients.size,
|
|
6161
6176
|
agents: this.engines.size
|
|
@@ -6267,7 +6282,7 @@ var init_server = __esm({
|
|
|
6267
6282
|
const hello = {
|
|
6268
6283
|
type: "hello",
|
|
6269
6284
|
protocol: PROTOCOL_VERSION,
|
|
6270
|
-
version: "1.5.
|
|
6285
|
+
version: "1.5.3",
|
|
6271
6286
|
agents: this.config.agents.list.map((a) => ({
|
|
6272
6287
|
id: a.id,
|
|
6273
6288
|
name: a.name || a.id,
|
|
@@ -7662,7 +7677,7 @@ async function runTui(opts) {
|
|
|
7662
7677
|
ws.on("open", () => {
|
|
7663
7678
|
ws.send(JSON.stringify({
|
|
7664
7679
|
type: "connect",
|
|
7665
|
-
params: { auth: { token }, mode: "tui", version: "1.5.
|
|
7680
|
+
params: { auth: { token }, mode: "tui", version: "1.5.3" }
|
|
7666
7681
|
}));
|
|
7667
7682
|
});
|
|
7668
7683
|
ws.on("message", (data) => {
|
|
@@ -8091,7 +8106,7 @@ import { fileURLToPath as fileURLToPath5 } from "url";
|
|
|
8091
8106
|
import { dirname as dirname5, join as join19 } from "path";
|
|
8092
8107
|
var __filename3 = fileURLToPath5(import.meta.url);
|
|
8093
8108
|
var __dirname3 = dirname5(__filename3);
|
|
8094
|
-
var version = "1.5.
|
|
8109
|
+
var version = "1.5.3";
|
|
8095
8110
|
try {
|
|
8096
8111
|
const pkg = JSON.parse(readFileSync(join19(__dirname3, "..", "package.json"), "utf-8"));
|
|
8097
8112
|
version = pkg.version;
|