@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 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
- MIT License
2
-
3
- Copyright (c) 2026 ItsTrag1c
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
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.2-blue.svg" alt="Version" /></a>
13
- <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License" /></a>
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://clanksuite.dev">Website</a> ·
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/ClankSuite">Twitter</a> ·
24
- <a href="https://reddit.com/u/ClankSuite">Reddit</a>
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.2_macos](https://github.com/ItsTrag1c/Clank/releases/latest/download/Clank_1.7.2_macos) |
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** | [clanksuite.dev](https://clanksuite.dev) |
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** | [@ClankSuite](https://x.com/ClankSuite) |
202
- | **Reddit** | [u/ClankSuite](https://reddit.com/u/ClankSuite) |
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
- MIT — see [LICENSE](LICENSE)
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 workspaceContent = await loadWorkspaceFiles(opts.workspaceDir);
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
- 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.");
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 WORKSPACE_FILES) {
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.2 | ${resolved.modelId} | ${identity.toolTier} tier`));
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.2`;
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.2",
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.2",
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 ? 1500 : 4e3;
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.2" }
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.2";
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;