smoltalk 0.13.0 → 0.13.1

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.
@@ -1,3 +1,4 @@
1
+ import Anthropic from "@anthropic-ai/sdk";
1
2
  import type { MessageParam, Tool } from "@anthropic-ai/sdk/resources/messages.js";
2
3
  import { PromptResult, Result, SmolClient, SmolConfig, StreamChunk, HostedToolResult } from "../types.js";
3
4
  import { BaseClient } from "./baseClient.js";
@@ -13,6 +14,16 @@ export declare function mergeConsecutiveMessages(messages: MessageParam[]): Mess
13
14
  * supported (forward-looking).
14
15
  */
15
16
  export declare function anthropicSupportsStructuredOutput(model: string): boolean;
17
+ /**
18
+ * A 400 whose message is only the generic "Invalid request data", with no
19
+ * field named, is not a malformed request. Anthropic returns it seconds into
20
+ * generation, intermittently, for a request that succeeds unchanged on the
21
+ * next try (seen with `output_config.format` plus tools on Opus 4.8). A real
22
+ * validation failure always names what it rejected, e.g.
23
+ * `messages.1.content: ...`. Treat the bare form as transient so it is retried
24
+ * like a 5xx.
25
+ */
26
+ export declare function isBareInvalidRequest(error: InstanceType<typeof Anthropic.APIError>): boolean;
16
27
  export declare function anthropicWebSearchEntries(hostedTools?: string[]): any[];
17
28
  export declare function parseAnthropicHostedTools(response: any, provider: string): HostedToolResult[];
18
29
  type EphemeralCacheControl = {
@@ -8,7 +8,7 @@ import { WEB_SEARCH, webSearchResult, applyHostedToolCost } from "../util/hosted
8
8
  import { zodToAnthropicTool } from "../util/tool.js";
9
9
  import { responseFormatToJsonSchema } from "../util/jsonSchema.js";
10
10
  import { normalizeAnthropicStopReason } from "../util/stopReason.js";
11
- import { SmolContentPolicyError, SmolContextWindowExceededError, smolErrorForStatus, } from "../smolError.js";
11
+ import { SmolContentPolicyError, SmolContextWindowExceededError, SmolOverloadedError, smolErrorForStatus, } from "../smolError.js";
12
12
  import { extractHttpErrorFields } from "../util/httpError.js";
13
13
  import { BaseClient } from "./baseClient.js";
14
14
  import { getModel, isTextModel } from "../models.js";
@@ -60,6 +60,27 @@ export function mergeConsecutiveMessages(messages) {
60
60
  export function anthropicSupportsStructuredOutput(model) {
61
61
  return !/^claude-(?:3(?:[-.]|$)|2(?:[-.]|$)|instant(?:[-.]|$))/i.test(model);
62
62
  }
63
+ /**
64
+ * A 400 whose message is only the generic "Invalid request data", with no
65
+ * field named, is not a malformed request. Anthropic returns it seconds into
66
+ * generation, intermittently, for a request that succeeds unchanged on the
67
+ * next try (seen with `output_config.format` plus tools on Opus 4.8). A real
68
+ * validation failure always names what it rejected, e.g.
69
+ * `messages.1.content: ...`. Treat the bare form as transient so it is retried
70
+ * like a 5xx.
71
+ */
72
+ export function isBareInvalidRequest(error) {
73
+ if (error.status !== 400) {
74
+ return false;
75
+ }
76
+ const body = error.error;
77
+ const bodyMessage = body?.error?.message;
78
+ if (typeof bodyMessage === "string") {
79
+ return bodyMessage.trim() === BARE_INVALID_REQUEST;
80
+ }
81
+ return error.message.trim() === BARE_INVALID_REQUEST;
82
+ }
83
+ const BARE_INVALID_REQUEST = "Invalid request data";
63
84
  export function anthropicWebSearchEntries(hostedTools) {
64
85
  if (hostedTools && hostedTools.includes(WEB_SEARCH)) {
65
86
  return [{ type: "web_search_20250305", name: "web_search" }];
@@ -333,6 +354,9 @@ export class SmolAnthropic extends BaseClient {
333
354
  msg.includes("violates our")) {
334
355
  throw new SmolContentPolicyError(error.message, http);
335
356
  }
357
+ if (isBareInvalidRequest(error)) {
358
+ throw new SmolOverloadedError(error.message, http);
359
+ }
336
360
  throw smolErrorForStatus(error.message, http);
337
361
  }
338
362
  throw error;
@@ -72,7 +72,9 @@ export declare class SmolContextWindowExceededError extends SmolError {
72
72
  export declare class SmolRateLimitError extends SmolError {
73
73
  constructor(message: string, options?: SmolErrorOptions);
74
74
  }
75
- /** Provider temporarily overloaded/unavailable (HTTP 503, or Anthropic's 529). */
75
+ /** Provider temporarily overloaded/unavailable (HTTP 503, or Anthropic's 529).
76
+ * Also raised for Anthropic's bare "Invalid request data" 400, which is a
77
+ * transient generation failure rather than a malformed request. */
76
78
  export declare class SmolOverloadedError extends SmolError {
77
79
  constructor(message: string, options?: SmolErrorOptions);
78
80
  }
package/dist/smolError.js CHANGED
@@ -121,7 +121,9 @@ export class SmolRateLimitError extends SmolError {
121
121
  this.name = "SmolRateLimitError";
122
122
  }
123
123
  }
124
- /** Provider temporarily overloaded/unavailable (HTTP 503, or Anthropic's 529). */
124
+ /** Provider temporarily overloaded/unavailable (HTTP 503, or Anthropic's 529).
125
+ * Also raised for Anthropic's bare "Invalid request data" 400, which is a
126
+ * transient generation failure rather than a malformed request. */
125
127
  export class SmolOverloadedError extends SmolError {
126
128
  constructor(message, options = {}) {
127
129
  super(message, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smoltalk",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "A common interface for LLM APIs",
5
5
  "homepage": "https://github.com/egonSchiele/smoltalk",
6
6
  "files": [