@falai/agent 3.1.0 → 3.2.0

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.
Files changed (70) hide show
  1. package/dist/cjs/index.d.ts +2 -1
  2. package/dist/cjs/index.d.ts.map +1 -1
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/providers/DeepSeekProvider.d.ts +7 -1
  5. package/dist/cjs/providers/DeepSeekProvider.d.ts.map +1 -1
  6. package/dist/cjs/providers/DeepSeekProvider.js +1 -0
  7. package/dist/cjs/providers/DeepSeekProvider.js.map +1 -1
  8. package/dist/cjs/providers/GeminiProvider.d.ts +8 -0
  9. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  10. package/dist/cjs/providers/GeminiProvider.js +1 -0
  11. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  12. package/dist/cjs/providers/GenericOpenAICompatibleProvider.d.ts +6 -1
  13. package/dist/cjs/providers/GenericOpenAICompatibleProvider.d.ts.map +1 -1
  14. package/dist/cjs/providers/GenericOpenAICompatibleProvider.js +1 -0
  15. package/dist/cjs/providers/GenericOpenAICompatibleProvider.js.map +1 -1
  16. package/dist/cjs/providers/OpenAICompatibleProvider.d.ts +23 -0
  17. package/dist/cjs/providers/OpenAICompatibleProvider.d.ts.map +1 -1
  18. package/dist/cjs/providers/OpenAICompatibleProvider.js +1 -0
  19. package/dist/cjs/providers/OpenAICompatibleProvider.js.map +1 -1
  20. package/dist/cjs/providers/OpenRouterProvider.d.ts +9 -1
  21. package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
  22. package/dist/cjs/providers/OpenRouterProvider.js +1 -0
  23. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
  24. package/dist/cjs/providers/ProviderAdapter.d.ts +18 -1
  25. package/dist/cjs/providers/ProviderAdapter.d.ts.map +1 -1
  26. package/dist/cjs/providers/ProviderAdapter.js +22 -0
  27. package/dist/cjs/providers/ProviderAdapter.js.map +1 -1
  28. package/dist/cjs/providers/index.d.ts +1 -1
  29. package/dist/cjs/providers/index.d.ts.map +1 -1
  30. package/dist/cjs/providers/index.js.map +1 -1
  31. package/dist/index.d.ts +2 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/providers/DeepSeekProvider.d.ts +7 -1
  35. package/dist/providers/DeepSeekProvider.d.ts.map +1 -1
  36. package/dist/providers/DeepSeekProvider.js +1 -0
  37. package/dist/providers/DeepSeekProvider.js.map +1 -1
  38. package/dist/providers/GeminiProvider.d.ts +8 -0
  39. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  40. package/dist/providers/GeminiProvider.js +1 -0
  41. package/dist/providers/GeminiProvider.js.map +1 -1
  42. package/dist/providers/GenericOpenAICompatibleProvider.d.ts +6 -1
  43. package/dist/providers/GenericOpenAICompatibleProvider.d.ts.map +1 -1
  44. package/dist/providers/GenericOpenAICompatibleProvider.js +1 -0
  45. package/dist/providers/GenericOpenAICompatibleProvider.js.map +1 -1
  46. package/dist/providers/OpenAICompatibleProvider.d.ts +23 -0
  47. package/dist/providers/OpenAICompatibleProvider.d.ts.map +1 -1
  48. package/dist/providers/OpenAICompatibleProvider.js +1 -0
  49. package/dist/providers/OpenAICompatibleProvider.js.map +1 -1
  50. package/dist/providers/OpenRouterProvider.d.ts +9 -1
  51. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  52. package/dist/providers/OpenRouterProvider.js +1 -0
  53. package/dist/providers/OpenRouterProvider.js.map +1 -1
  54. package/dist/providers/ProviderAdapter.d.ts +18 -1
  55. package/dist/providers/ProviderAdapter.d.ts.map +1 -1
  56. package/dist/providers/ProviderAdapter.js +23 -1
  57. package/dist/providers/ProviderAdapter.js.map +1 -1
  58. package/dist/providers/index.d.ts +1 -1
  59. package/dist/providers/index.d.ts.map +1 -1
  60. package/dist/providers/index.js.map +1 -1
  61. package/docs/reference/providers.md +39 -0
  62. package/package.json +3 -4
  63. package/src/index.ts +4 -0
  64. package/src/providers/DeepSeekProvider.ts +8 -1
  65. package/src/providers/GeminiProvider.ts +9 -0
  66. package/src/providers/GenericOpenAICompatibleProvider.ts +7 -0
  67. package/src/providers/OpenAICompatibleProvider.ts +25 -0
  68. package/src/providers/OpenRouterProvider.ts +10 -1
  69. package/src/providers/ProviderAdapter.ts +26 -0
  70. package/src/providers/index.ts +1 -0
@@ -23,6 +23,28 @@ import { ProviderAdapter, type ProviderAdapterInit, type RequestConfig } from ".
23
23
  */
24
24
  export type StructuredOutputMode = "responses_parse" | "json_schema" | "json_object";
25
25
 
26
+ /**
27
+ * How the schema rides on a call that ALSO carries tools — the one turn shape
28
+ * an agent makes constantly and a provider seam cannot get right by itself.
29
+ *
30
+ * `"response_format"` sends both, which every shape documents and most models
31
+ * honour. `"prompt"` leaves the response format off those calls and sends the
32
+ * schema as prompt instead.
33
+ *
34
+ * Set it to `"prompt"` when the model answers a tool-worthy turn by NARRATING
35
+ * the tool — "let me look that up for you" — and then stopping. That is not a
36
+ * model without initiative: its decoder is pinned to the schema, so the tool
37
+ * call has nowhere to go, and no instruction can make it emit one. Nothing is
38
+ * logged, because from the wire's point of view nothing failed.
39
+ *
40
+ * Measured 2026-09-07, one request, sampled: `z-ai/glm-5.3-flash` called its
41
+ * tool 0/10 under a response format and 8/8 without one, `deepseek-v4-flash`
42
+ * 0/5, `gemini-3.8-flash` 3/10. It stays a setting rather than a default
43
+ * because the reverse is just as real — `qwen3.8-flash` went 10/10 → 1/6 the
44
+ * other way. Measure the model you ship; one call answers it.
45
+ */
46
+ export type JsonWithTools = "response_format" | "prompt";
47
+
26
48
  export interface OpenAICompatibleProviderInit
27
49
  extends Omit<ProviderAdapterInit, "provider"> {
28
50
  apiKey: string;
@@ -32,6 +54,8 @@ export interface OpenAICompatibleProviderInit
32
54
  headers?: Record<string, string>;
33
55
  config?: RequestConfig;
34
56
  structuredOutput?: StructuredOutputMode;
57
+ /** See {@link JsonWithTools}. Only affects calls that carry tools. */
58
+ jsonWithTools?: JsonWithTools;
35
59
  /** OpenRouter upstream-host pin, to keep a conversation's prompt cache warm. */
36
60
  providerOrder?: string[];
37
61
  /** Replacement `fetch`, for tests that script the wire. */
@@ -72,6 +96,7 @@ function buildProvider(init: OpenAICompatibleProviderInit, mode: StructuredOutpu
72
96
  model: init.model,
73
97
  id: init.id,
74
98
  jsonMode: mode === "json_schema" ? "schema" : "object",
99
+ ...(init.jsonWithTools ? { jsonWithTools: init.jsonWithTools } : {}),
75
100
  ...(init.baseUrl ? { baseUrl: init.baseUrl } : {}),
76
101
  ...(init.headers ? { headers: init.headers } : {}),
77
102
  ...(init.config?.maxTokens ? { maxTokens: init.config.maxTokens } : {}),
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ProviderCapabilities } from "../types/ai.js";
6
- import { OpenAICompatibleProvider } from "./OpenAICompatibleProvider.js";
6
+ import { OpenAICompatibleProvider, type JsonWithTools } from "./OpenAICompatibleProvider.js";
7
7
  import type { RequestConfig } from "./ProviderAdapter.js";
8
8
 
9
9
  export interface OpenRouterProviderOptions {
@@ -24,6 +24,14 @@ export interface OpenRouterProviderOptions {
24
24
  * conversation's rounds. Fallbacks stay on: this is a preference, not a lock.
25
25
  */
26
26
  providerOrder?: string[];
27
+ /**
28
+ * See {@link JsonWithTools} — and reach for it here first. One gateway serves
29
+ * hundreds of models and they do not agree: measured through this provider,
30
+ * `z-ai/glm-5.3-flash` called a tool 0/10 with the schema on the response
31
+ * format and 8/8 with it in the prompt, while `qwen3.8-flash` went the other
32
+ * way, 10/10 → 1/6. Changing `model` can change the right answer here.
33
+ */
34
+ jsonWithTools?: JsonWithTools;
27
35
  /** Request defaults sent with every call */
28
36
  config?: RequestConfig;
29
37
  /** Idle-stream deadline and retry budget */
@@ -54,6 +62,7 @@ export class OpenRouterProvider extends OpenAICompatibleProvider {
54
62
  // Chat completions rather than the Responses API: this gateway's
55
63
  // json_schema passthrough is what its models actually support.
56
64
  structuredOutput: "json_schema",
65
+ ...(options.jsonWithTools ? { jsonWithTools: options.jsonWithTools } : {}),
57
66
  headers: {
58
67
  ...(options.siteUrl ? { "HTTP-Referer": options.siteUrl } : {}),
59
68
  ...(options.siteName ? { "X-Title": options.siteName } : {}),
@@ -22,6 +22,7 @@ import {
22
22
  ProviderError,
23
23
  classify,
24
24
  isBackupEligible,
25
+ probeJsonWithTools,
25
26
  requireContent,
26
27
  streamWatch,
27
28
  streamWithBackupModels,
@@ -30,6 +31,8 @@ import {
30
31
  type ChatMessage,
31
32
  type Effort,
32
33
  type JsonObjectSchema,
34
+ type JsonWithToolsProbe,
35
+ type ProbeOptions,
33
36
  type Provider,
34
37
  type ProviderChunk,
35
38
  type StreamOptions,
@@ -260,6 +263,29 @@ export abstract class ProviderAdapter implements AiProvider {
260
263
  this.retryConfig = resolveRetryConfig(init.retryConfig);
261
264
  }
262
265
 
266
+ /**
267
+ * Ask this provider's MODEL whether it can still call a tool while its output
268
+ * is pinned to a schema — the shape every turn here sends, because that is how
269
+ * `message` and the step's `collect` fields come back.
270
+ *
271
+ * Some models cannot, and they do not report it: the call has nowhere to go,
272
+ * so the model narrates it ("let me look that up for you") and stops. On the
273
+ * wire the turn succeeded. Downstream it reads as an agent that will not use
274
+ * its tools, and no instruction fixes it — which is why this is a measurement
275
+ * rather than a setting to reason about.
276
+ *
277
+ * Run it once, at boot, and pass `use` back as `jsonWithTools` (or fail the
278
+ * boot when it is `null` — that model cannot serve this framework's turns).
279
+ * Log `calls`: `0/3 and 3/3` is what makes the next model swap's regression
280
+ * obvious. Costs `samples × 2` short calls, and errors propagate.
281
+ */
282
+ async probeJsonWithTools(opts?: ProbeOptions): Promise<JsonWithToolsProbe> {
283
+ return probeJsonWithTools(this.provider, {
284
+ model: this.primaryModel,
285
+ ...(opts ?? {}),
286
+ });
287
+ }
288
+
263
289
  async generateMessage<TContext = unknown, TStructured = AgentStructuredResponse>(
264
290
  input: GenerateMessageInput<TContext>,
265
291
  ): Promise<GenerateMessageOutput<TStructured>> {
@@ -23,6 +23,7 @@ export type { DeepSeekProviderOptions } from "./DeepSeekProvider.js";
23
23
 
24
24
  export { OpenAICompatibleProvider } from "./OpenAICompatibleProvider.js";
25
25
  export type {
26
+ JsonWithTools,
26
27
  OpenAICompatibleProviderInit,
27
28
  StructuredOutputMode,
28
29
  } from "./OpenAICompatibleProvider.js";