@oh-my-pi/pi-ai 15.11.1 → 15.11.2

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
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [15.11.2] - 2026-06-11
6
+
7
+ ### Fixed
8
+
9
+ - Fixed Anthropic encoding of error tool results with whitespace-only content so requests no longer 400 with `tool_result: content cannot be empty if is_error is true`
10
+
5
11
  ## [15.11.1] - 2026-06-11
6
12
 
7
13
  ### Changed
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-ai",
4
- "version": "15.11.1",
4
+ "version": "15.11.2",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -38,8 +38,8 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@bufbuild/protobuf": "^2.12.0",
41
- "@oh-my-pi/pi-catalog": "15.11.1",
42
- "@oh-my-pi/pi-utils": "15.11.1",
41
+ "@oh-my-pi/pi-catalog": "15.11.2",
42
+ "@oh-my-pi/pi-utils": "15.11.2",
43
43
  "openai": "^6.39.0",
44
44
  "partial-json": "^0.1.7",
45
45
  "zod": "4.4.3"
@@ -873,13 +873,7 @@ async function prepareAnthropicManyImageContext(context: Context, supportsImages
873
873
  return { ...context, messages };
874
874
  }
875
875
 
876
- /**
877
- * Convert content blocks to Anthropic API format
878
- */
879
- function convertContentBlocks(
880
- content: (TextContent | ImageContent)[],
881
- supportsImages = true,
882
- ):
876
+ type AnthropicToolResultContent =
883
877
  | string
884
878
  | Array<
885
879
  | { type: "text"; text: string }
@@ -891,7 +885,15 @@ function convertContentBlocks(
891
885
  data: string;
892
886
  };
893
887
  }
894
- > {
888
+ >;
889
+
890
+ /**
891
+ * Convert content blocks to Anthropic API format
892
+ */
893
+ function convertContentBlocks(
894
+ content: (TextContent | ImageContent)[],
895
+ supportsImages = true,
896
+ ): AnthropicToolResultContent {
895
897
  const blocks: Array<
896
898
  | { type: "text"; text: string }
897
899
  | {
@@ -2883,11 +2885,36 @@ function buildParams(
2883
2885
  return params;
2884
2886
  }
2885
2887
 
2888
+ const EMPTY_ERROR_TOOL_RESULT_TEXT = "Tool failed with no output.";
2889
+
2890
+ function isEmptyToolResultWireContent(content: AnthropicToolResultContent): boolean {
2891
+ if (typeof content === "string") {
2892
+ return content.trim().length === 0;
2893
+ }
2894
+ return content.length === 0;
2895
+ }
2896
+
2897
+ function ensureErrorToolResultWireContent(
2898
+ content: AnthropicToolResultContent,
2899
+ isError: boolean | undefined,
2900
+ ): AnthropicToolResultContent {
2901
+ if (!isError || !isEmptyToolResultWireContent(content)) {
2902
+ return content;
2903
+ }
2904
+ return typeof content === "string"
2905
+ ? EMPTY_ERROR_TOOL_RESULT_TEXT
2906
+ : [{ type: "text", text: EMPTY_ERROR_TOOL_RESULT_TEXT }];
2907
+ }
2908
+
2886
2909
  function buildToolResultBlock(model: Model<"anthropic-messages">, msg: ToolResultMessage): ContentBlockParam {
2910
+ const content = ensureErrorToolResultWireContent(
2911
+ convertContentBlocks(msg.content, model.input.includes("image")),
2912
+ msg.isError,
2913
+ );
2887
2914
  const block: ContentBlockParam = {
2888
2915
  type: "tool_result",
2889
2916
  tool_use_id: msg.toolCallId,
2890
- content: convertContentBlocks(msg.content, model.input.includes("image")),
2917
+ content,
2891
2918
  is_error: msg.isError,
2892
2919
  };
2893
2920
  if (model.compat.requiresToolResultId) {