agent-sh 0.12.18 → 0.12.19

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.
@@ -59,6 +59,9 @@ export declare class ConversationState {
59
59
  private hasOpenToolCalls;
60
60
  private flushPendingNotes;
61
61
  getMessages(): ChatCompletionMessageParam[];
62
+ /** Drop tool messages with no matching preceding tool_call — strict
63
+ * providers (DeepSeek) 400, and compaction can leave such orphans. */
64
+ private dropOrphanToolMessages;
62
65
  /**
63
66
  * If a stream was interrupted mid-tool-execution, an assistant message
64
67
  * with tool_calls can land in history without matching tool results.
@@ -163,7 +163,24 @@ export class ConversationState {
163
163
  this.invalidateMessagesCache();
164
164
  }
165
165
  getMessages() {
166
- return this.normalizeReasoningConsistency(this.stubDanglingToolCalls(this.messages));
166
+ return this.normalizeReasoningConsistency(this.stubDanglingToolCalls(this.dropOrphanToolMessages(this.messages)));
167
+ }
168
+ /** Drop tool messages with no matching preceding tool_call — strict
169
+ * providers (DeepSeek) 400, and compaction can leave such orphans. */
170
+ dropOrphanToolMessages(messages) {
171
+ const knownIds = new Set();
172
+ const result = [];
173
+ for (const msg of messages) {
174
+ if (msg.role === "assistant" && "tool_calls" in msg && msg.tool_calls) {
175
+ for (const tc of msg.tool_calls)
176
+ knownIds.add(tc.id);
177
+ }
178
+ if (msg.role === "tool" && !knownIds.has(msg.tool_call_id)) {
179
+ continue;
180
+ }
181
+ result.push(msg);
182
+ }
183
+ return result;
167
184
  }
168
185
  /**
169
186
  * If a stream was interrupted mid-tool-execution, an assistant message
@@ -582,19 +599,23 @@ export class ConversationState {
582
599
  slimTurn(messages) {
583
600
  const MAX_RESULT_LEN = 1500;
584
601
  const result = [];
585
- const readOnlyToolIds = new Set();
602
+ const droppedToolIds = new Set();
586
603
  for (const msg of messages) {
587
604
  if (msg.role === "assistant" && "tool_calls" in msg && msg.tool_calls) {
588
605
  const kept = msg.tool_calls.filter((tc) => {
589
606
  if (!("function" in tc))
590
607
  return true;
591
608
  if (READ_ONLY_TOOLS.has(tc.function.name)) {
592
- readOnlyToolIds.add(tc.id);
609
+ droppedToolIds.add(tc.id);
593
610
  return false;
594
611
  }
595
612
  return true;
596
613
  });
597
614
  if (kept.length === 0) {
615
+ // No content + no tool_calls is malformed (DeepSeek 400); drop the husk.
616
+ const text = typeof msg.content === "string" ? msg.content.trim() : "";
617
+ if (!text)
618
+ continue;
598
619
  const { tool_calls: _, ...rest } = msg;
599
620
  result.push(rest);
600
621
  }
@@ -604,7 +625,7 @@ export class ConversationState {
604
625
  continue;
605
626
  }
606
627
  if (msg.role === "tool") {
607
- if (readOnlyToolIds.has(msg.tool_call_id))
628
+ if (droppedToolIds.has(msg.tool_call_id))
608
629
  continue;
609
630
  const content = typeof msg.content === "string" ? msg.content : "";
610
631
  if (content.length > MAX_RESULT_LEN) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-sh",
3
- "version": "0.12.18",
3
+ "version": "0.12.19",
4
4
  "description": "A shell-first terminal where AI is one keystroke away",
5
5
  "type": "module",
6
6
  "main": "dist/core.js",