@probelabs/probe 0.6.0-rc128 → 0.6.0-rc129

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.
@@ -1152,11 +1152,28 @@ When troubleshooting:
1152
1152
  }
1153
1153
 
1154
1154
  // Initialize conversation with existing history + new user message
1155
- let currentMessages = [
1156
- { role: 'system', content: systemMessage },
1157
- ...this.history, // Include previous conversation history
1158
- userMessage
1159
- ];
1155
+ // If history already contains a system message (from session cloning), reuse it for cache efficiency
1156
+ // Otherwise add a fresh system message
1157
+ const hasSystemMessage = this.history.length > 0 && this.history[0].role === 'system';
1158
+ let currentMessages;
1159
+
1160
+ if (hasSystemMessage) {
1161
+ // Reuse existing system message from history for cache efficiency
1162
+ currentMessages = [
1163
+ ...this.history,
1164
+ userMessage
1165
+ ];
1166
+ if (this.debug) {
1167
+ console.log('[DEBUG] Reusing existing system message from history for cache efficiency');
1168
+ }
1169
+ } else {
1170
+ // Add fresh system message (first call or empty history)
1171
+ currentMessages = [
1172
+ { role: 'system', content: systemMessage },
1173
+ ...this.history, // Include previous conversation history
1174
+ userMessage
1175
+ ];
1176
+ }
1160
1177
 
1161
1178
  let currentIteration = 0;
1162
1179
  let completionAttempted = false;
@@ -2147,6 +2164,163 @@ Convert your previous response content into actual JSON data that follows this s
2147
2164
  }
2148
2165
  }
2149
2166
 
2167
+ /**
2168
+ * Clone this agent's session to create a new agent with shared conversation history
2169
+ * @param {Object} options - Clone options
2170
+ * @param {string} [options.sessionId] - Session ID for the cloned agent (defaults to new UUID)
2171
+ * @param {boolean} [options.stripInternalMessages=true] - Remove internal messages (schema reminders, mermaid fixes, etc.)
2172
+ * @param {boolean} [options.keepSystemMessage=true] - Keep the system message in cloned history
2173
+ * @param {boolean} [options.deepCopy=true] - Deep copy messages to prevent mutations
2174
+ * @param {Object} [options.overrides] - Override any ProbeAgent constructor options
2175
+ * @returns {ProbeAgent} New agent instance with cloned history
2176
+ */
2177
+ clone(options = {}) {
2178
+ const {
2179
+ sessionId = randomUUID(),
2180
+ stripInternalMessages = true,
2181
+ keepSystemMessage = true,
2182
+ deepCopy = true,
2183
+ overrides = {}
2184
+ } = options;
2185
+
2186
+ // Clone the history
2187
+ let clonedHistory = deepCopy
2188
+ ? JSON.parse(JSON.stringify(this.history))
2189
+ : [...this.history];
2190
+
2191
+ // Strip internal messages if requested
2192
+ if (stripInternalMessages) {
2193
+ clonedHistory = this._stripInternalMessages(clonedHistory, keepSystemMessage);
2194
+ }
2195
+
2196
+ // Create new agent with same configuration
2197
+ const clonedAgent = new ProbeAgent({
2198
+ // Copy current agent's config
2199
+ customPrompt: this.customPrompt,
2200
+ promptType: this.promptType,
2201
+ allowEdit: this.allowEdit,
2202
+ path: this.allowedFolders[0], // Use first allowed folder as primary path
2203
+ allowedFolders: [...this.allowedFolders],
2204
+ provider: this.clientApiProvider,
2205
+ model: this.modelName,
2206
+ debug: this.debug,
2207
+ outline: this.outline,
2208
+ maxResponseTokens: this.maxResponseTokens,
2209
+ maxIterations: this.maxIterations,
2210
+ disableMermaidValidation: this.disableMermaidValidation,
2211
+ enableMcp: !!this.mcpBridge,
2212
+ mcpConfig: this.mcpConfig,
2213
+ enableBash: this.enableBash,
2214
+ bashConfig: this.bashConfig,
2215
+ storageAdapter: this.storageAdapter,
2216
+ // Override with any provided options
2217
+ sessionId,
2218
+ ...overrides
2219
+ });
2220
+
2221
+ // Set the cloned history directly (before initialization to avoid overwriting)
2222
+ clonedAgent.history = clonedHistory;
2223
+
2224
+ if (this.debug) {
2225
+ console.log(`[DEBUG] Cloned session ${this.sessionId} -> ${sessionId}`);
2226
+ console.log(`[DEBUG] Cloned ${clonedHistory.length} messages (stripInternal: ${stripInternalMessages})`);
2227
+ }
2228
+
2229
+ return clonedAgent;
2230
+ }
2231
+
2232
+ /**
2233
+ * Internal method to strip internal/temporary messages from history
2234
+ * Removes: schema reminders, mermaid fix prompts, tool use reminders, etc.
2235
+ * Keeps: system message, user messages, assistant responses, tool results
2236
+ * @private
2237
+ */
2238
+ _stripInternalMessages(history, keepSystemMessage = true) {
2239
+ const filtered = [];
2240
+
2241
+ for (let i = 0; i < history.length; i++) {
2242
+ const message = history[i];
2243
+
2244
+ // Handle system message
2245
+ if (message.role === 'system') {
2246
+ if (keepSystemMessage) {
2247
+ filtered.push(message);
2248
+ } else if (this.debug) {
2249
+ console.log(`[DEBUG] Removing system message at index ${i}`);
2250
+ }
2251
+ continue;
2252
+ }
2253
+
2254
+ // Check if this is an internal message that should be stripped
2255
+ if (this._isInternalMessage(message, i, history)) {
2256
+ if (this.debug) {
2257
+ console.log(`[DEBUG] Stripping internal message at index ${i}: ${message.role}`);
2258
+ }
2259
+ continue;
2260
+ }
2261
+
2262
+ // Keep this message
2263
+ filtered.push(message);
2264
+ }
2265
+
2266
+ return filtered;
2267
+ }
2268
+
2269
+ /**
2270
+ * Determine if a message is an internal/temporary message
2271
+ * @private
2272
+ */
2273
+ _isInternalMessage(message, index, history) {
2274
+ if (message.role !== 'user') {
2275
+ return false; // Only user messages can be internal reminders
2276
+ }
2277
+
2278
+ // Handle null/undefined content
2279
+ if (!message.content) {
2280
+ return false;
2281
+ }
2282
+
2283
+ const content = typeof message.content === 'string'
2284
+ ? message.content
2285
+ : JSON.stringify(message.content);
2286
+
2287
+ // Schema reminder messages
2288
+ if (content.includes('IMPORTANT: A schema was provided') ||
2289
+ content.includes('You MUST respond with data that matches this schema') ||
2290
+ content.includes('Your response must conform to this schema:')) {
2291
+ return true;
2292
+ }
2293
+
2294
+ // Tool use reminder messages
2295
+ if (content.includes('Please use one of the available tools') &&
2296
+ content.includes('or use attempt_completion') &&
2297
+ content.includes('Remember: Use proper XML format')) {
2298
+ return true;
2299
+ }
2300
+
2301
+ // Mermaid fix prompts
2302
+ if (content.includes('The mermaid diagram in your response has syntax errors') ||
2303
+ content.includes('Please fix the mermaid syntax errors') ||
2304
+ content.includes('Here is the corrected version:')) {
2305
+ return true;
2306
+ }
2307
+
2308
+ // JSON correction prompts
2309
+ if (content.includes('Your response does not match the expected JSON schema') ||
2310
+ content.includes('Please provide a valid JSON response') ||
2311
+ content.includes('Schema validation error:')) {
2312
+ return true;
2313
+ }
2314
+
2315
+ // Empty attempt_complete reminders
2316
+ if (content.includes('When using <attempt_complete>') &&
2317
+ content.includes('this must be the ONLY content in your response')) {
2318
+ return true;
2319
+ }
2320
+
2321
+ return false;
2322
+ }
2323
+
2150
2324
  /**
2151
2325
  * Clean up resources (including MCP connections)
2152
2326
  */
@@ -29292,7 +29292,7 @@ var init_semantics = __esm({
29292
29292
  return;
29293
29293
  for (const cn of contentNodes) {
29294
29294
  const ch = cn.children || {};
29295
- const inspectTok = (tk) => {
29295
+ const inspectTok = (tk, inQuoted = false) => {
29296
29296
  if (!tk)
29297
29297
  return false;
29298
29298
  const img = String(tk.image || "");
@@ -29302,7 +29302,7 @@ var init_semantics = __esm({
29302
29302
  this.ctx.errors.push({
29303
29303
  line: tk.startLine ?? 1,
29304
29304
  column: col,
29305
- severity: "warning",
29305
+ severity: inQuoted ? "error" : "warning",
29306
29306
  code: "FL-LABEL-BACKTICK",
29307
29307
  message: "Backticks (`\u2026`) inside node labels are not supported by Mermaid.",
29308
29308
  hint: 'Remove the backticks or use quotes instead, e.g., "GITHUB_ACTIONS" and "--cli".',
@@ -29314,12 +29314,12 @@ var init_semantics = __esm({
29314
29314
  };
29315
29315
  const texts = ch.Text || [];
29316
29316
  for (const tk of texts) {
29317
- if (inspectTok(tk))
29317
+ if (inspectTok(tk, false))
29318
29318
  return;
29319
29319
  }
29320
29320
  const qs = ch.QuotedString || [];
29321
29321
  for (const tk of qs) {
29322
- if (inspectTok(tk))
29322
+ if (inspectTok(tk, true))
29323
29323
  return;
29324
29324
  }
29325
29325
  }
@@ -29720,6 +29720,36 @@ function mapFlowchartParserError(err, text) {
29720
29720
  length: len
29721
29721
  };
29722
29722
  }
29723
+ {
29724
+ const caret0 = Math.max(0, column - 1);
29725
+ const openIdx = lineStr.lastIndexOf("[", caret0);
29726
+ if (openIdx !== -1) {
29727
+ const closeIdx = lineStr.indexOf("]", openIdx + 1);
29728
+ const seg = closeIdx !== -1 ? lineStr.slice(openIdx + 1, closeIdx) : lineStr.slice(openIdx + 1);
29729
+ if (seg.includes('"')) {
29730
+ return {
29731
+ line,
29732
+ column,
29733
+ severity: "error",
29734
+ code: "FL-LABEL-QUOTE-IN-UNQUOTED",
29735
+ message: "Quotes are not allowed inside unquoted node labels. Use &quot; for quotes or wrap the entire label in quotes.",
29736
+ hint: 'Example: I[Log &quot;processing N items&quot;] or I["Log \\"processing N items\\""]',
29737
+ length: len
29738
+ };
29739
+ }
29740
+ if (seg.includes("(") || seg.includes(")")) {
29741
+ return {
29742
+ line,
29743
+ column,
29744
+ severity: "error",
29745
+ code: "FL-LABEL-PARENS-UNQUOTED",
29746
+ message: "Parentheses inside an unquoted label are not supported by Mermaid.",
29747
+ hint: 'Wrap the label in quotes, e.g., A["Mark (X)"] \u2014 or replace ( and ) with HTML entities: &#40; and &#41;.',
29748
+ length: len
29749
+ };
29750
+ }
29751
+ }
29752
+ }
29723
29753
  if (tokType === "QuotedString") {
29724
29754
  return {
29725
29755
  line,
@@ -29752,6 +29782,24 @@ function mapFlowchartParserError(err, text) {
29752
29782
  length: len
29753
29783
  };
29754
29784
  }
29785
+ {
29786
+ const caret0 = Math.max(0, column - 1);
29787
+ const openIdx = lineStr.lastIndexOf("(", caret0);
29788
+ if (openIdx !== -1) {
29789
+ const seg = lineStr.slice(openIdx + 1);
29790
+ if (seg.includes("(") || seg.includes(")")) {
29791
+ return {
29792
+ line,
29793
+ column,
29794
+ severity: "error",
29795
+ code: "FL-LABEL-PARENS-UNQUOTED",
29796
+ message: "Parentheses inside an unquoted label are not supported by Mermaid.",
29797
+ hint: 'Wrap the label in quotes, e.g., A["Mark (X)"] \u2014 or replace ( and ) with HTML entities: &#40; and &#41;.',
29798
+ length: len
29799
+ };
29800
+ }
29801
+ }
29802
+ }
29755
29803
  const q = findInnerQuoteIssue("(");
29756
29804
  if (q?.kind === "escaped") {
29757
29805
  return { line, column: q.column, severity: "error", code: "FL-LABEL-ESCAPED-QUOTE", message: 'Escaped quotes (\\") in node labels are not supported by Mermaid. Use &quot; instead.', hint: 'Prefer "He said &quot;Hi&quot;".', length: 2 };
@@ -29773,6 +29821,25 @@ function mapFlowchartParserError(err, text) {
29773
29821
  length: len
29774
29822
  };
29775
29823
  }
29824
+ {
29825
+ const caret0 = Math.max(0, column - 1);
29826
+ const openIdx = lineStr.lastIndexOf("{", caret0);
29827
+ if (openIdx !== -1) {
29828
+ const closeIdx = lineStr.indexOf("}", openIdx + 1);
29829
+ const seg = closeIdx !== -1 ? lineStr.slice(openIdx + 1, closeIdx) : lineStr.slice(openIdx + 1);
29830
+ if (seg.includes("(") || seg.includes(")")) {
29831
+ return {
29832
+ line,
29833
+ column,
29834
+ severity: "error",
29835
+ code: "FL-LABEL-PARENS-UNQUOTED",
29836
+ message: "Parentheses inside an unquoted label are not supported by Mermaid.",
29837
+ hint: 'Wrap the label in quotes, e.g., A["Mark (X)"] \u2014 or replace ( and ) with HTML entities: &#40; and &#41;.',
29838
+ length: len
29839
+ };
29840
+ }
29841
+ }
29842
+ }
29776
29843
  const q = findInnerQuoteIssue("{");
29777
29844
  if (q?.kind === "escaped") {
29778
29845
  return {
@@ -30111,6 +30178,17 @@ ${br.example}`,
30111
30178
  if (inRule("arrow") && err.name === "NoViableAltException") {
30112
30179
  return { line, column, severity: "error", code: "SE-ARROW-INVALID", message: `Invalid sequence arrow near '${found}'.`, hint: "Use ->, -->, ->>, -->>, -x, --x, -), --), <<->>, or <<-->>", length: len };
30113
30180
  }
30181
+ if ((err.name === "NoViableAltException" || err.name === "MismatchedTokenException") && tokType === "Minus") {
30182
+ return {
30183
+ line,
30184
+ column,
30185
+ severity: "error",
30186
+ code: "SE-BULLET-LINE-UNSUPPORTED",
30187
+ message: "Bullet list lines starting with '-' are not supported in sequence diagrams.",
30188
+ hint: "Wrap free\u2011form text in a note block instead, for example:\nNote over A : Item 1\nNote over A\n - Item 1\n - Item 2\nend note",
30189
+ length: len
30190
+ };
30191
+ }
30114
30192
  if (inRule("noteStmt")) {
30115
30193
  if (err.name === "MismatchedTokenException" && exp("Colon")) {
30116
30194
  return { line, column, severity: "error", code: "SE-NOTE-MALFORMED", message: "Malformed note: missing colon before the note text.", hint: "Example: Note right of Alice: Hello", length: len };
@@ -30268,6 +30346,17 @@ ${br.example}`,
30268
30346
  };
30269
30347
  }
30270
30348
  }
30349
+ if ((err.name === "NotAllInputParsedException" || err.name === "NoViableAltException") && found === "-") {
30350
+ return {
30351
+ line,
30352
+ column,
30353
+ severity: "error",
30354
+ code: "SE-BULLET-LINE-UNSUPPORTED",
30355
+ message: "Bullet list lines starting with '-' are not supported in sequence diagrams.",
30356
+ hint: "Wrap free\u2011form text in a note block, for example:\nNote over A : Item 1\nNote over A\n - Item 1\n - Item 2\nend note",
30357
+ length: len
30358
+ };
30359
+ }
30271
30360
  if ((err.name === "NoViableAltException" || err.name === "NotAllInputParsedException") && tokType === "ElseKeyword") {
30272
30361
  return { line, column, severity: "error", code: "SE-ELSE-OUTSIDE-ALT", message: "'else' is only allowed inside 'alt' blocks.", hint: "Use: alt Condition \u2026 else \u2026 end", length: len };
30273
30362
  }
@@ -30469,6 +30558,30 @@ function validateFlowchart(text, options = {}) {
30469
30558
  return errs;
30470
30559
  },
30471
30560
  postParse: (text2, tokens, _cst, prevErrors) => {
30561
+ {
30562
+ const tks = tokens;
30563
+ const firstByLine = /* @__PURE__ */ new Map();
30564
+ for (const tk of tks) {
30565
+ const ln = tk.startLine ?? 1;
30566
+ const col = tk.startColumn ?? 1;
30567
+ const prev = firstByLine.get(ln);
30568
+ if (!prev || (prev.startColumn ?? Infinity) > col)
30569
+ firstByLine.set(ln, tk);
30570
+ }
30571
+ for (const tk of tks) {
30572
+ if (tk.image === "title" && firstByLine.get(tk.startLine ?? 1) === tk) {
30573
+ prevErrors.push({
30574
+ line: tk.startLine ?? 1,
30575
+ column: tk.startColumn ?? 1,
30576
+ severity: "error",
30577
+ code: "FL-META-UNSUPPORTED",
30578
+ message: "'title' is not supported in flowcharts by the current Mermaid CLI.",
30579
+ hint: 'Use a Markdown heading above the code block, or draw a labeled node at the top (e.g., T["Dependency Relationship"]).',
30580
+ length: tk.image?.length ?? 5
30581
+ });
30582
+ }
30583
+ }
30584
+ }
30472
30585
  const escWarn = detectEscapedQuotes(tokens, {
30473
30586
  code: "FL-LABEL-ESCAPED-QUOTE",
30474
30587
  message: 'Escaped quotes (\\") in node labels are accepted by Mermaid, but using &quot; is preferred for portability.',
@@ -32887,6 +33000,13 @@ function computeFixes(text, errors, level = "safe") {
32887
33000
  const replaced = inner.split('\\"').join("&quot;");
32888
33001
  edits.push({ start: { line: e.line, column: q1 + 2 }, end: { line: e.line, column: q2 + 1 }, newText: replaced });
32889
33002
  continue;
33003
+ if (is("FL-META-UNSUPPORTED", e)) {
33004
+ if (level === "all") {
33005
+ const lineText2 = lineTextAt(text, e.line);
33006
+ edits.push({ start: { line: e.line, column: 1 }, end: { line: e.line + 1, column: 1 }, newText: "" });
33007
+ }
33008
+ continue;
33009
+ }
32890
33010
  }
32891
33011
  }
32892
33012
  }
@@ -32894,6 +33014,12 @@ function computeFixes(text, errors, level = "safe") {
32894
33014
  edits.push(replaceRange(text, at(e), e.length ?? 2, "&quot;"));
32895
33015
  continue;
32896
33016
  }
33017
+ if (is("FL-META-UNSUPPORTED", e)) {
33018
+ if (level === "all") {
33019
+ edits.push({ start: { line: e.line, column: 1 }, end: { line: e.line + 1, column: 1 }, newText: "" });
33020
+ }
33021
+ continue;
33022
+ }
32897
33023
  if (is("FL-LABEL-BACKTICK", e)) {
32898
33024
  edits.push(replaceRange(text, at(e), e.length ?? 1, ""));
32899
33025
  continue;
@@ -32943,6 +33069,12 @@ function computeFixes(text, errors, level = "safe") {
32943
33069
  edits.push(replaceRange(text, at(e), e.length ?? 1, rep));
32944
33070
  continue;
32945
33071
  }
33072
+ if (is("FL-END-WITHOUT-SUBGRAPH", e)) {
33073
+ if (level === "all") {
33074
+ edits.push({ start: { line: e.line, column: 1 }, end: { line: e.line + 1, column: 1 }, newText: "" });
33075
+ }
33076
+ continue;
33077
+ }
32946
33078
  if (is("FL-LABEL-DOUBLE-IN-DOUBLE", e)) {
32947
33079
  const lineText = lineTextAt(text, e.line);
32948
33080
  const caret0 = Math.max(0, e.column - 1);
@@ -33279,6 +33411,9 @@ function computeFixes(text, errors, level = "safe") {
33279
33411
  continue;
33280
33412
  }
33281
33413
  if (is("FL-QUOTE-UNCLOSED", e)) {
33414
+ if (patchedLines.has(e.line)) {
33415
+ continue;
33416
+ }
33282
33417
  if (level === "all") {
33283
33418
  const lineText = lineTextAt(text, e.line);
33284
33419
  const caret0 = Math.max(0, e.column - 1);
@@ -33353,7 +33488,7 @@ function computeFixes(text, errors, level = "safe") {
33353
33488
  newInner = ltrim + left + replacedMid + right + rtrim;
33354
33489
  } else {
33355
33490
  const replaced = inner.split("&quot;").join("\0").split('"').join("&quot;").split("\0").join("&quot;");
33356
- newInner = '"' + replaced + '"';
33491
+ newInner = replaced;
33357
33492
  }
33358
33493
  edits.push({ start: { line: e.line, column: contentStart + 1 }, end: { line: e.line, column: closeIdx + 1 }, newText: newInner });
33359
33494
  patchedLines.add(e.line);
@@ -47961,7 +48096,7 @@ var init_ProbeAgent = __esm({
47961
48096
  MAX_HISTORY_MESSAGES = 100;
47962
48097
  SUPPORTED_IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "webp", "gif", "bmp", "svg"];
47963
48098
  MAX_IMAGE_FILE_SIZE = 20 * 1024 * 1024;
47964
- ProbeAgent = class {
48099
+ ProbeAgent = class _ProbeAgent {
47965
48100
  /**
47966
48101
  * Create a new ProbeAgent instance
47967
48102
  * @param {Object} options - Configuration options
@@ -48843,12 +48978,24 @@ You are working with a repository located at: ${searchDirectory}
48843
48978
  }))
48844
48979
  ];
48845
48980
  }
48846
- let currentMessages = [
48847
- { role: "system", content: systemMessage },
48848
- ...this.history,
48849
- // Include previous conversation history
48850
- userMessage
48851
- ];
48981
+ const hasSystemMessage = this.history.length > 0 && this.history[0].role === "system";
48982
+ let currentMessages;
48983
+ if (hasSystemMessage) {
48984
+ currentMessages = [
48985
+ ...this.history,
48986
+ userMessage
48987
+ ];
48988
+ if (this.debug) {
48989
+ console.log("[DEBUG] Reusing existing system message from history for cache efficiency");
48990
+ }
48991
+ } else {
48992
+ currentMessages = [
48993
+ { role: "system", content: systemMessage },
48994
+ ...this.history,
48995
+ // Include previous conversation history
48996
+ userMessage
48997
+ ];
48998
+ }
48852
48999
  let currentIteration = 0;
48853
49000
  let completionAttempted = false;
48854
49001
  let finalResult = "I was unable to complete your request due to reaching the maximum number of tool iterations.";
@@ -49643,6 +49790,116 @@ Convert your previous response content into actual JSON data that follows this s
49643
49790
  console.log(`[DEBUG] Cleared conversation history and reset counters for session ${this.sessionId}`);
49644
49791
  }
49645
49792
  }
49793
+ /**
49794
+ * Clone this agent's session to create a new agent with shared conversation history
49795
+ * @param {Object} options - Clone options
49796
+ * @param {string} [options.sessionId] - Session ID for the cloned agent (defaults to new UUID)
49797
+ * @param {boolean} [options.stripInternalMessages=true] - Remove internal messages (schema reminders, mermaid fixes, etc.)
49798
+ * @param {boolean} [options.keepSystemMessage=true] - Keep the system message in cloned history
49799
+ * @param {boolean} [options.deepCopy=true] - Deep copy messages to prevent mutations
49800
+ * @param {Object} [options.overrides] - Override any ProbeAgent constructor options
49801
+ * @returns {ProbeAgent} New agent instance with cloned history
49802
+ */
49803
+ clone(options = {}) {
49804
+ const {
49805
+ sessionId = randomUUID4(),
49806
+ stripInternalMessages = true,
49807
+ keepSystemMessage = true,
49808
+ deepCopy = true,
49809
+ overrides = {}
49810
+ } = options;
49811
+ let clonedHistory = deepCopy ? JSON.parse(JSON.stringify(this.history)) : [...this.history];
49812
+ if (stripInternalMessages) {
49813
+ clonedHistory = this._stripInternalMessages(clonedHistory, keepSystemMessage);
49814
+ }
49815
+ const clonedAgent = new _ProbeAgent({
49816
+ // Copy current agent's config
49817
+ customPrompt: this.customPrompt,
49818
+ promptType: this.promptType,
49819
+ allowEdit: this.allowEdit,
49820
+ path: this.allowedFolders[0],
49821
+ // Use first allowed folder as primary path
49822
+ allowedFolders: [...this.allowedFolders],
49823
+ provider: this.clientApiProvider,
49824
+ model: this.modelName,
49825
+ debug: this.debug,
49826
+ outline: this.outline,
49827
+ maxResponseTokens: this.maxResponseTokens,
49828
+ maxIterations: this.maxIterations,
49829
+ disableMermaidValidation: this.disableMermaidValidation,
49830
+ enableMcp: !!this.mcpBridge,
49831
+ mcpConfig: this.mcpConfig,
49832
+ enableBash: this.enableBash,
49833
+ bashConfig: this.bashConfig,
49834
+ storageAdapter: this.storageAdapter,
49835
+ // Override with any provided options
49836
+ sessionId,
49837
+ ...overrides
49838
+ });
49839
+ clonedAgent.history = clonedHistory;
49840
+ if (this.debug) {
49841
+ console.log(`[DEBUG] Cloned session ${this.sessionId} -> ${sessionId}`);
49842
+ console.log(`[DEBUG] Cloned ${clonedHistory.length} messages (stripInternal: ${stripInternalMessages})`);
49843
+ }
49844
+ return clonedAgent;
49845
+ }
49846
+ /**
49847
+ * Internal method to strip internal/temporary messages from history
49848
+ * Removes: schema reminders, mermaid fix prompts, tool use reminders, etc.
49849
+ * Keeps: system message, user messages, assistant responses, tool results
49850
+ * @private
49851
+ */
49852
+ _stripInternalMessages(history, keepSystemMessage = true) {
49853
+ const filtered = [];
49854
+ for (let i = 0; i < history.length; i++) {
49855
+ const message = history[i];
49856
+ if (message.role === "system") {
49857
+ if (keepSystemMessage) {
49858
+ filtered.push(message);
49859
+ } else if (this.debug) {
49860
+ console.log(`[DEBUG] Removing system message at index ${i}`);
49861
+ }
49862
+ continue;
49863
+ }
49864
+ if (this._isInternalMessage(message, i, history)) {
49865
+ if (this.debug) {
49866
+ console.log(`[DEBUG] Stripping internal message at index ${i}: ${message.role}`);
49867
+ }
49868
+ continue;
49869
+ }
49870
+ filtered.push(message);
49871
+ }
49872
+ return filtered;
49873
+ }
49874
+ /**
49875
+ * Determine if a message is an internal/temporary message
49876
+ * @private
49877
+ */
49878
+ _isInternalMessage(message, index, history) {
49879
+ if (message.role !== "user") {
49880
+ return false;
49881
+ }
49882
+ if (!message.content) {
49883
+ return false;
49884
+ }
49885
+ const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
49886
+ if (content.includes("IMPORTANT: A schema was provided") || content.includes("You MUST respond with data that matches this schema") || content.includes("Your response must conform to this schema:")) {
49887
+ return true;
49888
+ }
49889
+ if (content.includes("Please use one of the available tools") && content.includes("or use attempt_completion") && content.includes("Remember: Use proper XML format")) {
49890
+ return true;
49891
+ }
49892
+ if (content.includes("The mermaid diagram in your response has syntax errors") || content.includes("Please fix the mermaid syntax errors") || content.includes("Here is the corrected version:")) {
49893
+ return true;
49894
+ }
49895
+ if (content.includes("Your response does not match the expected JSON schema") || content.includes("Please provide a valid JSON response") || content.includes("Schema validation error:")) {
49896
+ return true;
49897
+ }
49898
+ if (content.includes("When using <attempt_complete>") && content.includes("this must be the ONLY content in your response")) {
49899
+ return true;
49900
+ }
49901
+ return false;
49902
+ }
49646
49903
  /**
49647
49904
  * Clean up resources (including MCP connections)
49648
49905
  */