@rubytech/taskmaster 1.0.63 → 1.0.64

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.
@@ -30,7 +30,7 @@ import { acquireSessionWriteLock } from "../session-write-lock.js";
30
30
  import { applySkillEnvOverrides, applySkillEnvOverridesFromSnapshot, loadWorkspaceSkillEntries, resolveSkillsPromptForRun, } from "../skills.js";
31
31
  import { buildEmbeddedExtensionPaths } from "./extensions.js";
32
32
  import { logToolSchemasForGoogle, sanitizeSessionHistory, sanitizeToolsForGoogle, } from "./google.js";
33
- import { getEffectiveHistoryLimit, limitHistoryTurns, loadPreviousSessionMessages } from "./history.js";
33
+ import { getEffectiveHistoryLimit, limitHistoryTurns, loadPreviousSessionMessages, } from "./history.js";
34
34
  import { resolveGlobalLane, resolveSessionLane } from "./lanes.js";
35
35
  import { log } from "./logger.js";
36
36
  import { buildModelAliasLines, resolveModel } from "./model.js";
@@ -1,11 +1,12 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  /**
4
- * Default rolling window: keep the last 50 user turns.
4
+ * Default rolling window: keep the last 20 user turns.
5
5
  * Prevents context overflow without needing slow compaction.
6
- * ~50 turns × ~2k tokens/turn 100k tokens, well within 200k context windows.
6
+ * Turns can contain large tool results, so a conservative default is essential.
7
+ * ~20 turns × ~4k tokens/turn ≈ 80k tokens, leaving room for system prompt + tools.
7
8
  */
8
- const DEFAULT_HISTORY_TURNS = 50;
9
+ const DEFAULT_HISTORY_TURNS = 20;
9
10
  const THREAD_SUFFIX_REGEX = /^(.*)(?::(?:thread|topic):\d+)$/i;
10
11
  function stripThreadSuffix(value) {
11
12
  const match = value.match(THREAD_SUFFIX_REGEX);
@@ -86,10 +87,32 @@ export function getEffectiveHistoryLimit(sessionKey, config) {
86
87
  return DEFAULT_HISTORY_TURNS;
87
88
  }
88
89
  /**
89
- * Loads messages from all previous sessions for a given session key.
90
- * Returns them in chronological order (oldest first) as AgentMessage[].
91
- * Used to prepend historical context to the current session's messages,
92
- * creating one continuous conversation that the rolling window then trims.
90
+ * Conversation-only roles: user messages and assistant text responses.
91
+ * Tool calls and tool results are operational artifacts that bloat the context
92
+ * without adding conversational value they are excluded from historical context.
93
+ */
94
+ const CONVERSATION_ROLES = new Set(["user", "assistant"]);
95
+ /**
96
+ * Strips tool-call content blocks from assistant messages, keeping only text.
97
+ * An assistant message that contained only tool calls becomes a text-only message
98
+ * (or is skipped if it has no text content at all).
99
+ */
100
+ function stripToolCallBlocks(msg) {
101
+ if (msg.role !== "assistant")
102
+ return msg;
103
+ const content = msg.content;
104
+ if (!Array.isArray(content))
105
+ return msg;
106
+ const textBlocks = content.filter((b) => b && typeof b === "object" && b.type === "text");
107
+ if (textBlocks.length === 0)
108
+ return null; // assistant message was tool-calls only
109
+ return { ...msg, content: textBlocks };
110
+ }
111
+ /**
112
+ * Loads conversation messages from all previous sessions for a given session key.
113
+ * Returns user + assistant text messages in chronological order (oldest first).
114
+ * Tool calls, tool results, and other operational messages are excluded —
115
+ * this is purely conversational context for the rolling window.
93
116
  */
94
117
  export function loadPreviousSessionMessages(sessionFile, sessionKey) {
95
118
  if (!sessionKey)
@@ -112,10 +135,7 @@ export function loadPreviousSessionMessages(sessionFile, sessionKey) {
112
135
  for (const prev of entry.previousSessions) {
113
136
  if (!prev.sessionId)
114
137
  continue;
115
- const candidates = [
116
- prev.sessionFile,
117
- path.join(sessionsDir, `${prev.sessionId}.jsonl`),
118
- ].filter(Boolean);
138
+ const candidates = [prev.sessionFile, path.join(sessionsDir, `${prev.sessionId}.jsonl`)].filter(Boolean);
119
139
  const filePath = candidates.find((p) => fs.existsSync(p));
120
140
  if (!filePath)
121
141
  continue;
@@ -126,9 +146,13 @@ export function loadPreviousSessionMessages(sessionFile, sessionKey) {
126
146
  continue;
127
147
  try {
128
148
  const parsed = JSON.parse(line);
129
- if (parsed?.message?.role) {
130
- messages.push(parsed.message);
131
- }
149
+ const msg = parsed?.message;
150
+ if (!msg?.role || !CONVERSATION_ROLES.has(msg.role))
151
+ continue;
152
+ // Strip tool-call blocks from assistant messages
153
+ const cleaned = stripToolCallBlocks(msg);
154
+ if (cleaned)
155
+ messages.push(cleaned);
132
156
  }
133
157
  catch {
134
158
  // skip malformed lines
@@ -38,7 +38,7 @@ import { buildEmbeddedExtensionPaths } from "../extensions.js";
38
38
  import { applyExtraParamsToAgent } from "../extra-params.js";
39
39
  import { appendCacheTtlTimestamp, isCacheTtlEligibleProvider } from "../cache-ttl.js";
40
40
  import { logToolSchemasForGoogle, sanitizeSessionHistory, sanitizeToolsForGoogle, } from "../google.js";
41
- import { getEffectiveHistoryLimit, limitHistoryTurns, loadPreviousSessionMessages } from "../history.js";
41
+ import { getEffectiveHistoryLimit, limitHistoryTurns, loadPreviousSessionMessages, } from "../history.js";
42
42
  import { log } from "../logger.js";
43
43
  import { buildModelAliasLines } from "../model.js";
44
44
  import { clearActiveEmbeddedRun, setActiveEmbeddedRun, } from "../runs.js";
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.63",
3
- "commit": "15a1377031320e9d047b3aba1bcc9124e5b707d0",
4
- "builtAt": "2026-02-18T00:18:16.896Z"
2
+ "version": "1.0.64",
3
+ "commit": "894760f8c77c4a2e07270875031e811654b2b2c7",
4
+ "builtAt": "2026-02-18T00:26:04.061Z"
5
5
  }
@@ -171,9 +171,7 @@ export async function recoverOrphanedSessions(params) {
171
171
  // List JSONL files on disk
172
172
  let files;
173
173
  try {
174
- files = fs
175
- .readdirSync(sessionsDir)
176
- .filter((f) => f.endsWith(".jsonl"));
174
+ files = fs.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl"));
177
175
  }
178
176
  catch {
179
177
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.0.63",
3
+ "version": "1.0.64",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"