@tractorscorch/clank 1.7.2 → 1.7.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/CHANGELOG.md +20 -0
- package/LICENSE +190 -21
- package/README.md +28 -10
- package/dist/index.js +88 -18
- package/dist/index.js.map +1 -1
- package/dist/workspace/templates/SOUL.md +1 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [1.7.4] — 2026-03-26
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- **Telegram/Discord typing indicator crash** — `sendChatAction` and `sendTyping` calls now fail silently instead of aborting message processing. Telegram rate-limits typing indicators (429 Too Many Requests), which would kill the entire message handler after sustained conversations. Discord's `sendTyping` gets the same treatment for consistency
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## [1.7.3] — 2026-03-25
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- **Smart memory for local models** — local models no longer load the full MEMORY.md into the system prompt (wastes context tokens). Instead, memories are injected via TF-IDF relevance matching with a tighter 800-char budget, keeping only what's relevant to the current conversation
|
|
20
|
+
- **System file protection rule** — agents are now instructed not to modify, delete, or overwrite files outside the workspace or current working directory unless the user explicitly names the file. Prevents local models from touching system files, OS directories, or config dotfiles unprompted
|
|
21
|
+
- **Proactive auto-compaction** — context is now checked after every tool result (not just at the start of each loop iteration). If a large tool result pushes context past the threshold, tier-1 compaction fires immediately with zero latency. A pre-send safety check at 90% utilization catches anything that slips through
|
|
22
|
+
- **Context overflow recovery** — if a provider returns a context-length error, the engine now auto-compacts aggressively and retries once instead of crashing. If context is still critically full (>95%), warns the user to use `/compact` or `/new`
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **TF-IDF memory relevance** — `buildMemoryBlock()` was called with an empty query string, making relevance scoring useless. Now passes session context for proper matching
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
9
29
|
## [1.7.2] — 2026-03-24
|
|
10
30
|
|
|
11
31
|
### Added
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,190 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to the Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by the Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding any notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
Copyright 2026 Clank Labs (ItsTrag1c)
|
|
179
|
+
|
|
180
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
181
|
+
you may not use this file except in compliance with the License.
|
|
182
|
+
You may obtain a copy of the License at
|
|
183
|
+
|
|
184
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
185
|
+
|
|
186
|
+
Unless required by applicable law or agreed to in writing, software
|
|
187
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
188
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
189
|
+
See the License for the specific language governing permissions and
|
|
190
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -9,19 +9,19 @@
|
|
|
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.7.
|
|
13
|
-
<a href="https://
|
|
12
|
+
<a href="https://github.com/ItsTrag1c/Clank/releases/latest"><img src="https://img.shields.io/badge/version-1.7.4-blue.svg" alt="Version" /></a>
|
|
13
|
+
<a href="https://www.apache.org/licenses/LICENSE-2.0"><img src="https://img.shields.io/badge/License-Apache%202.0-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>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
19
|
-
<a href="https://
|
|
19
|
+
<a href="https://clanklabs.dev">Website</a> ·
|
|
20
20
|
<a href="https://github.com/ItsTrag1c/Clank/blob/main/docs/INSTALL.md">Install Guide</a> ·
|
|
21
21
|
<a href="https://github.com/ItsTrag1c/Clank/blob/main/docs/USER_GUIDE.md">User Guide</a> ·
|
|
22
22
|
<a href="https://github.com/ItsTrag1c/Clank/blob/main/CHANGELOG.md">Changelog</a> ·
|
|
23
|
-
<a href="https://x.com/
|
|
24
|
-
<a href="https://reddit.com/u/
|
|
23
|
+
<a href="https://x.com/Clank_Labs">Twitter</a> ·
|
|
24
|
+
<a href="https://reddit.com/u/ClankLabs">Reddit</a>
|
|
25
25
|
</p>
|
|
26
26
|
|
|
27
27
|
---
|
|
@@ -92,7 +92,25 @@ That's it. Setup auto-detects your local models, configures the gateway, and get
|
|
|
92
92
|
| Platform | Download |
|
|
93
93
|
|----------|----------|
|
|
94
94
|
| **npm** (all platforms) | `npm install -g @tractorscorch/clank` |
|
|
95
|
-
| **macOS** (Apple Silicon) | [Clank_1.7.
|
|
95
|
+
| **macOS** (Apple Silicon) | [Clank_1.7.4_macos](https://github.com/ItsTrag1c/Clank/releases/latest/download/Clank_1.7.4_macos) |
|
|
96
|
+
|
|
97
|
+
## Wrench — Purpose-Built Agentic Model
|
|
98
|
+
|
|
99
|
+
[**Wrench**](https://clanklabs.dev/wrench) is our custom fine-tuned model, built specifically for Clank. It scores **72/75 (96%)** on agentic benchmarks — matching Claude Sonnet — while running locally on consumer hardware.
|
|
100
|
+
|
|
101
|
+
- **Base:** Qwen3.5-35B-A3B (3B active parameters, MoE)
|
|
102
|
+
- **Format:** Q4_K_M GGUF (~20GB)
|
|
103
|
+
- **Min GPU:** 16GB VRAM
|
|
104
|
+
- **Download:** [HuggingFace](https://huggingface.co/ClankLabs/Wrench-35B-A3B-Q4_K_M-GGUF)
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Ollama
|
|
108
|
+
ollama create wrench -f Modelfile
|
|
109
|
+
# Set as primary model in Clank config: "primary": "ollama/wrench"
|
|
110
|
+
|
|
111
|
+
# llama.cpp
|
|
112
|
+
./llama-server -m Wrench-35B-A3B-Q4_K_M-GGUF.gguf -c 8192 -ngl 99
|
|
113
|
+
```
|
|
96
114
|
|
|
97
115
|
## Security Notice
|
|
98
116
|
|
|
@@ -195,11 +213,11 @@ See [SECURITY.md](SECURITY.md) for the full security model.
|
|
|
195
213
|
|
|
196
214
|
| | |
|
|
197
215
|
|--|--|
|
|
198
|
-
| **Website** | [
|
|
216
|
+
| **Website** | [clanklabs.dev](https://clanklabs.dev) |
|
|
199
217
|
| **GitHub** | [ItsTrag1c/Clank](https://github.com/ItsTrag1c/Clank) |
|
|
200
218
|
| **npm** | [npmjs.com/package/@tractorscorch/clank](https://www.npmjs.com/package/@tractorscorch/clank) |
|
|
201
|
-
| **Twitter/X** | [@
|
|
202
|
-
| **Reddit** | [u/
|
|
219
|
+
| **Twitter/X** | [@Clank_Labs](https://x.com/Clank_Labs) |
|
|
220
|
+
| **Reddit** | [u/ClankLabs](https://reddit.com/u/ClankLabs) |
|
|
203
221
|
| **Legacy** | [Clank-Legacy](https://github.com/ItsTrag1c/Clank-Legacy) (archived CLI v2.7.0 + Desktop v2.6.1) |
|
|
204
222
|
|
|
205
223
|
## Requirements
|
|
@@ -209,4 +227,4 @@ See [SECURITY.md](SECURITY.md) for the full security model.
|
|
|
209
227
|
|
|
210
228
|
## License
|
|
211
229
|
|
|
212
|
-
|
|
230
|
+
Apache 2.0 — see [LICENSE](LICENSE)
|
package/dist/index.js
CHANGED
|
@@ -320,6 +320,30 @@ ${summary.trim()}`,
|
|
|
320
320
|
this.compactTier1Aggressive();
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
|
+
/** Check if context is critically full (>95% utilization) */
|
|
324
|
+
isOverflowing() {
|
|
325
|
+
return this.utilizationPercent() >= 95;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Tier-1 only compaction — synchronous, no LLM call.
|
|
329
|
+
* Safe to call mid-turn without adding latency.
|
|
330
|
+
*/
|
|
331
|
+
compactTier1Only() {
|
|
332
|
+
const before = this.messages.length;
|
|
333
|
+
const tokensBefore = this.estimateTokens();
|
|
334
|
+
this.compactTier1();
|
|
335
|
+
if (this.utilizationPercent() >= 70) {
|
|
336
|
+
this.compactTier1Aggressive();
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
ok: true,
|
|
340
|
+
tier: 1,
|
|
341
|
+
messagesBefore: before,
|
|
342
|
+
messagesAfter: this.messages.length,
|
|
343
|
+
estimatedTokensBefore: tokensBefore,
|
|
344
|
+
estimatedTokensAfter: this.estimateTokens()
|
|
345
|
+
};
|
|
346
|
+
}
|
|
323
347
|
/** Clear all messages */
|
|
324
348
|
clear() {
|
|
325
349
|
this.messages = [];
|
|
@@ -988,6 +1012,9 @@ ${results}`
|
|
|
988
1012
|
outputTokens = 0;
|
|
989
1013
|
}
|
|
990
1014
|
try {
|
|
1015
|
+
if (this.contextEngine.utilizationPercent() > 90) {
|
|
1016
|
+
this.contextEngine.compactTier1Only();
|
|
1017
|
+
}
|
|
991
1018
|
const streamIterator = activeProvider.stream(
|
|
992
1019
|
this.contextEngine.getMessages(),
|
|
993
1020
|
this.systemPrompt,
|
|
@@ -1024,6 +1051,21 @@ ${results}`
|
|
|
1024
1051
|
} catch (streamErr) {
|
|
1025
1052
|
const errMsg = streamErr instanceof Error ? streamErr.message : "unknown";
|
|
1026
1053
|
const isTimeout = streamErr instanceof Error && (streamErr.name === "TimeoutError" || streamErr.name === "AbortError" || errMsg.includes("timed out"));
|
|
1054
|
+
const isContextError = /context.*(length|limit|exceeded)|too many tokens|maximum.*tokens|token limit/i.test(errMsg);
|
|
1055
|
+
if (attempt === 0 && isContextError && !signal.aborted) {
|
|
1056
|
+
this.emit("error", {
|
|
1057
|
+
message: "Context limit hit \u2014 compacting and retrying...",
|
|
1058
|
+
recoverable: true
|
|
1059
|
+
});
|
|
1060
|
+
this.contextEngine.compactTier1Only();
|
|
1061
|
+
if (this.contextEngine.isOverflowing()) {
|
|
1062
|
+
this.emit("error", {
|
|
1063
|
+
message: "Context is nearly full \u2014 use /compact or /new to free space",
|
|
1064
|
+
recoverable: true
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
continue;
|
|
1068
|
+
}
|
|
1027
1069
|
const isRetryable = !isTimeout && !signal.aborted && (errMsg.includes("connection dropped") || errMsg.includes("stopped responding") || errMsg.includes("empty response") || errMsg.includes("fetch failed") || errMsg.includes("ECONNREFUSED") || errMsg.includes("ECONNRESET"));
|
|
1028
1070
|
if (attempt === 0 && (isRetryable || !signal.aborted && !isTimeout)) {
|
|
1029
1071
|
this.emit("error", {
|
|
@@ -1129,6 +1171,15 @@ ${results}`
|
|
|
1129
1171
|
this.contextEngine.ingest(result);
|
|
1130
1172
|
this.emit("tool-result", { id: tc.id, name: tc.name, success: false, summary: errMsg });
|
|
1131
1173
|
}
|
|
1174
|
+
if (this.contextEngine.needsCompaction()) {
|
|
1175
|
+
this.contextEngine.compactTier1Only();
|
|
1176
|
+
if (this.contextEngine.isOverflowing()) {
|
|
1177
|
+
this.emit("error", {
|
|
1178
|
+
message: "Context is nearly full \u2014 use /compact or /new to free space",
|
|
1179
|
+
recoverable: true
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1132
1183
|
}
|
|
1133
1184
|
}
|
|
1134
1185
|
if (iterationCount >= MAX_ITERATIONS) {
|
|
@@ -1265,9 +1316,11 @@ import { platform, hostname } from "os";
|
|
|
1265
1316
|
async function buildSystemPrompt(opts) {
|
|
1266
1317
|
const parts = [];
|
|
1267
1318
|
const compact = opts.compact ?? false;
|
|
1319
|
+
const isLocal = opts.isLocal ?? false;
|
|
1268
1320
|
const isSubAgent = (opts.spawnDepth ?? 0) > 0;
|
|
1269
1321
|
if (!compact) {
|
|
1270
|
-
const
|
|
1322
|
+
const files = isLocal ? WORKSPACE_FILES_LOCAL : WORKSPACE_FILES;
|
|
1323
|
+
const workspaceContent = await loadWorkspaceFiles(opts.workspaceDir, files);
|
|
1271
1324
|
if (workspaceContent) {
|
|
1272
1325
|
parts.push(workspaceContent);
|
|
1273
1326
|
parts.push("---");
|
|
@@ -1297,7 +1350,8 @@ async function buildSystemPrompt(opts) {
|
|
|
1297
1350
|
"You are an AI agent running LOCALLY on the user's machine.",
|
|
1298
1351
|
"You have tools: read_file, write_file, edit_file, list_directory, bash, search_files, glob_files, git, web_search, web_fetch, and self-config tools.",
|
|
1299
1352
|
"ALWAYS use your tools. NEVER say you cannot access files, run commands, or perform actions. You CAN \u2014 use your tools.",
|
|
1300
|
-
"NEVER apologize and refuse. If asked to do something, DO IT with your tools or explain what tool you need."
|
|
1353
|
+
"NEVER apologize and refuse. If asked to do something, DO IT with your tools or explain what tool you need.",
|
|
1354
|
+
"Do NOT modify files outside your workspace or the user's current directory unless the user explicitly names the file."
|
|
1301
1355
|
].join(" "));
|
|
1302
1356
|
} else {
|
|
1303
1357
|
parts.push("## CRITICAL: You Are a Local Agent With Tools");
|
|
@@ -1313,13 +1367,18 @@ async function buildSystemPrompt(opts) {
|
|
|
1313
1367
|
parts.push("3. NEVER apologize and refuse to act. If a task requires a tool, use it. If you lack a specific tool, say which tool you need \u2014 do not give a generic refusal.");
|
|
1314
1368
|
parts.push("4. Read files before editing them. Use tools proactively without being asked twice.");
|
|
1315
1369
|
parts.push("5. You can configure yourself \u2014 use the config, channel, agent, and model management tools to modify your own setup.");
|
|
1370
|
+
parts.push("6. Do NOT modify, delete, or overwrite files outside your workspace directory or the user's current working directory unless the user explicitly names the file. System files, OS directories, and config dotfiles are off-limits by default.");
|
|
1316
1371
|
}
|
|
1317
1372
|
if (opts.thinking === "off") {
|
|
1318
1373
|
parts.push("");
|
|
1319
1374
|
parts.push("Do NOT use extended thinking or reasoning blocks. Respond directly and concisely.");
|
|
1320
1375
|
}
|
|
1321
1376
|
parts.push("");
|
|
1322
|
-
|
|
1377
|
+
if (isLocal) {
|
|
1378
|
+
parts.push("Your memories are managed automatically. Use memory tools to save or recall important information. Do not rely on conversation history for long-term facts.");
|
|
1379
|
+
} else {
|
|
1380
|
+
parts.push("When you learn something important about the user or project, save it using the config or memory tools so you remember it next time.");
|
|
1381
|
+
}
|
|
1323
1382
|
parts.push("");
|
|
1324
1383
|
const projectMemory = await loadProjectMemory(opts.identity.workspace);
|
|
1325
1384
|
if (projectMemory) {
|
|
@@ -1329,9 +1388,9 @@ async function buildSystemPrompt(opts) {
|
|
|
1329
1388
|
}
|
|
1330
1389
|
return parts.join("\n");
|
|
1331
1390
|
}
|
|
1332
|
-
async function loadWorkspaceFiles(workspaceDir) {
|
|
1391
|
+
async function loadWorkspaceFiles(workspaceDir, files = WORKSPACE_FILES) {
|
|
1333
1392
|
const sections = [];
|
|
1334
|
-
for (const filename of
|
|
1393
|
+
for (const filename of files) {
|
|
1335
1394
|
const filePath = join2(workspaceDir, filename);
|
|
1336
1395
|
if (existsSync2(filePath)) {
|
|
1337
1396
|
try {
|
|
@@ -1383,7 +1442,7 @@ async function ensureWorkspaceFiles(workspaceDir, templateDir) {
|
|
|
1383
1442
|
}
|
|
1384
1443
|
}
|
|
1385
1444
|
}
|
|
1386
|
-
var WORKSPACE_FILES, SUB_AGENT_FILE;
|
|
1445
|
+
var WORKSPACE_FILES, WORKSPACE_FILES_LOCAL, SUB_AGENT_FILE;
|
|
1387
1446
|
var init_system_prompt = __esm({
|
|
1388
1447
|
"src/engine/system-prompt.ts"() {
|
|
1389
1448
|
"use strict";
|
|
@@ -1396,6 +1455,13 @@ var init_system_prompt = __esm({
|
|
|
1396
1455
|
"TOOLS.md",
|
|
1397
1456
|
"MEMORY.md"
|
|
1398
1457
|
];
|
|
1458
|
+
WORKSPACE_FILES_LOCAL = [
|
|
1459
|
+
"SOUL.md",
|
|
1460
|
+
"USER.md",
|
|
1461
|
+
"IDENTITY.md",
|
|
1462
|
+
"AGENTS.md",
|
|
1463
|
+
"TOOLS.md"
|
|
1464
|
+
];
|
|
1399
1465
|
SUB_AGENT_FILE = "RUNNER.md";
|
|
1400
1466
|
}
|
|
1401
1467
|
});
|
|
@@ -5150,7 +5216,7 @@ async function runChat(opts) {
|
|
|
5150
5216
|
console.log(cyan(" / __|| | __ _ _ _ | |__"));
|
|
5151
5217
|
console.log(cyan(" | (__ | |/ _` || ' \\| / /"));
|
|
5152
5218
|
console.log(cyan(" \\___||_|\\__,_||_||_|_\\_\\"));
|
|
5153
|
-
console.log(dim(` v1.7.
|
|
5219
|
+
console.log(dim(` v1.7.4 | ${resolved.modelId} | ${identity.toolTier} tier`));
|
|
5154
5220
|
console.log(dim(" Type your message. Press Ctrl+C to exit.\n"));
|
|
5155
5221
|
const rl = createInterface({
|
|
5156
5222
|
input: process.stdin,
|
|
@@ -6337,7 +6403,8 @@ var init_telegram = __esm({
|
|
|
6337
6403
|
if (!this.gateway) return;
|
|
6338
6404
|
try {
|
|
6339
6405
|
console.log(` Telegram: processing message from ${userId} in ${chatId}`);
|
|
6340
|
-
await ctx.api.sendChatAction(chatId, "typing")
|
|
6406
|
+
await ctx.api.sendChatAction(chatId, "typing").catch(() => {
|
|
6407
|
+
});
|
|
6341
6408
|
const typingInterval2 = setInterval(() => {
|
|
6342
6409
|
bot.api.sendChatAction(chatId, "typing").catch(() => {
|
|
6343
6410
|
});
|
|
@@ -6462,7 +6529,8 @@ var init_telegram = __esm({
|
|
|
6462
6529
|
const processVoice = async () => {
|
|
6463
6530
|
if (!this.gateway || !this.config) return;
|
|
6464
6531
|
try {
|
|
6465
|
-
await ctx.api.sendChatAction(chatId, "typing")
|
|
6532
|
+
await ctx.api.sendChatAction(chatId, "typing").catch(() => {
|
|
6533
|
+
});
|
|
6466
6534
|
const file = await ctx.api.getFile(msg.voice.file_id);
|
|
6467
6535
|
const fileUrl = `https://api.telegram.org/file/bot${telegramConfig.botToken}/${file.file_path}`;
|
|
6468
6536
|
const res = await fetch(fileUrl);
|
|
@@ -6817,7 +6885,7 @@ _Kill with /kill <id> or /killall_`;
|
|
|
6817
6885
|
return !current ? "\u{1F4AD} Thinking display *on* \u2014 you'll see the model's reasoning above responses." : "\u{1F4AD} Thinking display *off* \u2014 only the final response will be shown.";
|
|
6818
6886
|
}
|
|
6819
6887
|
case "version": {
|
|
6820
|
-
return `\u{1F527} *Clank* v1.7.
|
|
6888
|
+
return `\u{1F527} *Clank* v1.7.4`;
|
|
6821
6889
|
}
|
|
6822
6890
|
default:
|
|
6823
6891
|
return null;
|
|
@@ -6899,7 +6967,8 @@ var init_discord = __esm({
|
|
|
6899
6967
|
const isDM = !message.guild;
|
|
6900
6968
|
if (!this.gateway) return;
|
|
6901
6969
|
try {
|
|
6902
|
-
await message.channel.sendTyping()
|
|
6970
|
+
await message.channel.sendTyping().catch(() => {
|
|
6971
|
+
});
|
|
6903
6972
|
const response = await this.gateway.handleInboundMessage(
|
|
6904
6973
|
{
|
|
6905
6974
|
channel: "discord",
|
|
@@ -7407,7 +7476,7 @@ var init_server = __esm({
|
|
|
7407
7476
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
7408
7477
|
res.end(JSON.stringify({
|
|
7409
7478
|
status: "ok",
|
|
7410
|
-
version: "1.7.
|
|
7479
|
+
version: "1.7.4",
|
|
7411
7480
|
uptime: process.uptime(),
|
|
7412
7481
|
clients: this.clients.size,
|
|
7413
7482
|
agents: this.engines.size
|
|
@@ -7519,7 +7588,7 @@ var init_server = __esm({
|
|
|
7519
7588
|
const hello = {
|
|
7520
7589
|
type: "hello",
|
|
7521
7590
|
protocol: PROTOCOL_VERSION,
|
|
7522
|
-
version: "1.7.
|
|
7591
|
+
version: "1.7.4",
|
|
7523
7592
|
agents: this.config.agents.list.map((a) => ({
|
|
7524
7593
|
id: a.id,
|
|
7525
7594
|
name: a.name || a.id,
|
|
@@ -7829,10 +7898,11 @@ var init_server = __esm({
|
|
|
7829
7898
|
channel,
|
|
7830
7899
|
compact,
|
|
7831
7900
|
thinking,
|
|
7832
|
-
spawnDepth: currentDepth
|
|
7901
|
+
spawnDepth: currentDepth,
|
|
7902
|
+
isLocal: resolved.isLocal
|
|
7833
7903
|
});
|
|
7834
|
-
const memoryBudget = resolved.isLocal ?
|
|
7835
|
-
const memoryBlock = await this.memoryManager.buildMemoryBlock("", identity.workspace, memoryBudget);
|
|
7904
|
+
const memoryBudget = resolved.isLocal ? 800 : 4e3;
|
|
7905
|
+
const memoryBlock = await this.memoryManager.buildMemoryBlock("session", identity.workspace, memoryBudget);
|
|
7836
7906
|
const fullPrompt = memoryBlock ? systemPrompt + "\n\n---\n\n" + memoryBlock : systemPrompt;
|
|
7837
7907
|
const maxSpawnDepth = this.config.agents.defaults.subagents?.maxSpawnDepth ?? 1;
|
|
7838
7908
|
const maxConcurrent = this.config.agents.defaults.subagents?.maxConcurrent ?? 8;
|
|
@@ -9149,7 +9219,7 @@ async function runTui(opts) {
|
|
|
9149
9219
|
ws.on("open", () => {
|
|
9150
9220
|
ws.send(JSON.stringify({
|
|
9151
9221
|
type: "connect",
|
|
9152
|
-
params: { auth: { token }, mode: "tui", version: "1.7.
|
|
9222
|
+
params: { auth: { token }, mode: "tui", version: "1.7.4" }
|
|
9153
9223
|
}));
|
|
9154
9224
|
});
|
|
9155
9225
|
ws.on("message", (data) => {
|
|
@@ -9592,7 +9662,7 @@ import { fileURLToPath as fileURLToPath5 } from "url";
|
|
|
9592
9662
|
import { dirname as dirname5, join as join20 } from "path";
|
|
9593
9663
|
var __filename3 = fileURLToPath5(import.meta.url);
|
|
9594
9664
|
var __dirname3 = dirname5(__filename3);
|
|
9595
|
-
var version = "1.7.
|
|
9665
|
+
var version = "1.7.4";
|
|
9596
9666
|
try {
|
|
9597
9667
|
const pkg = JSON.parse(readFileSync(join20(__dirname3, "..", "package.json"), "utf-8"));
|
|
9598
9668
|
version = pkg.version;
|