@salesforce/sfdx-agent-harness-mastra 0.99.0 → 0.101.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,16 @@
3
3
  All notable changes to `@salesforce/sfdx-agent-harness-mastra` are documented in this file.
4
4
  Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
+ ## [0.101.0] - 2026-10-13
7
+
8
+ ### Features
9
+ - **harness-mastra**: migrate pass-throughs to LanguageModelV4 and remove chat-generations @W-24224624@ ([#876](https://github.com/forcedotcom/agentic-dx/pull/876))
10
+
11
+ ## [0.100.0] - 2026-10-09
12
+
13
+ ### Chores
14
+ - **agent-sdk,harness-claude,harness-mastra,harness-openai**: remove the openai harness @W-24458323@ ([#871](https://github.com/forcedotcom/agentic-dx/pull/871))
15
+
6
16
  ## [0.99.0] - 2026-10-06
7
17
 
8
18
  ### Features
package/README.md CHANGED
@@ -59,8 +59,8 @@ Linux and macOS release the handle eagerly; the retry options are no-ops on thos
59
59
  | ----------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
60
60
  | `MastraHarnessFactory` | class | `HarnessFactory` that produces a Mastra-backed `AgentHarness` bound to a storage root. |
61
61
  | `MastraHarnessFactoryConfig` | interface | Configuration for `MastraHarnessFactory` (`toolApprovalTimeoutMs?`, `languageModelBuilders?`). |
62
- | `MastraLanguageModelBuilderContext` | type | Context bag the harness threads into each `LanguageModelV3` builder (`getInfo`, `logBus`, `emitWireCommunication`, `innerFetch`). |
63
- | `MastraLanguageModelBuilder` | type | Factory function shape for a consumer-injected builder: `(ctx: MastraLanguageModelBuilderContext) => LanguageModelV3`. |
62
+ | `MastraLanguageModelBuilderContext` | type | Context bag the harness threads into each `LanguageModelV4` builder (`getInfo`, `logBus`, `emitWireCommunication`, `innerFetch`). |
63
+ | `MastraLanguageModelBuilder` | type | Factory function shape for a consumer-injected builder: `(ctx: MastraLanguageModelBuilderContext) => LanguageModelV4`. |
64
64
  | `MASTRA_BUILT_IN_TOOL_POLICIES` | const | Frozen `ReadonlyArray<ToolPolicyRule>` the harness feeds the SDK's `resolveToolApprovalPolicy` as the `tiers.harness` slice — `allow` rules for Mastra's built-in `updateWorkingMemory` / `skill` / `skill_search` / `skill_read` tools. |
65
65
  | `MASTRA_BUILT_IN_TOOL_NAMES` | const | The four built-in tool leaf names `MASTRA_BUILT_IN_TOOL_POLICIES` covers. |
66
66
 
@@ -81,20 +81,14 @@ no `globalThis` mutation. When no proxy env is set, `fetch` runs unwrapped (zero
81
81
 
82
82
  #### Injecting custom wire shapes
83
83
 
84
- A consumer can register a `LanguageModelV3` builder for a custom `providerHint` via
84
+ A consumer can register a `LanguageModelV4` builder for a custom `providerHint` via
85
85
  `MastraHarnessFactoryConfig.languageModelBuilders` without editing the harness's internal switch. Each injected key
86
- becomes a supported provider hint and a dispatch arm. Used to inject wire shapes the harness does not ship natively
87
- (e.g., a temporary GovCloud `chat/generations` fallback).
86
+ becomes a supported provider hint and a dispatch arm. Used to inject wire shapes the harness does not ship natively.
88
87
 
89
88
  ```ts
90
- import {
91
- CHAT_GENERATIONS_PROVIDER_HINT,
92
- buildChatGenerationsLanguageModel,
93
- } from '@salesforce/sfdx-agent-chat-generations';
94
-
95
89
  const factory = new MastraHarnessFactory({
96
90
  languageModelBuilders: {
97
- [CHAT_GENERATIONS_PROVIDER_HINT]: buildChatGenerationsLanguageModel,
91
+ 'my-custom-wire-shape': (ctx) => buildMyLanguageModel(ctx),
98
92
  },
99
93
  });
100
94
  ```
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import type { LogBus } from '@salesforce/agentic-common';
2
2
  import type { ModelConnectivityInfo, WireCommunicationEvent } from '@salesforce/sfdx-agent-sdk';
3
- import type { LanguageModelV3 } from '@ai-sdk/provider';
3
+ import type { LanguageModelV4 } from '@ai-sdk/provider';
4
4
  export { MastraHarnessFactory, type MastraHarnessFactoryConfig } from './mastra-harness-factory.js';
5
5
  export type { MastraAgentHarness } from './mastra-harness.js';
6
6
  export { MASTRA_BUILT_IN_TOOL_NAMES, MASTRA_BUILT_IN_TOOL_POLICIES } from './mastra-built-in-policies.js';
7
7
  export { type MastraAgentConfig, type MastraSkillSearchConfig, type MastraToolSearchConfig, type SkillSearchHandle, type ToolSearchHandle, } from './tool-search.js';
8
8
  /**
9
- * Context the harness threads into each `LanguageModelV3` builder — both the
9
+ * Context the harness threads into each `LanguageModelV4` builder — both the
10
10
  * built-in builders and any consumer-injected builders registered via
11
11
  * `MastraHarnessFactoryConfig.languageModelBuilders`. The shape mirrors what
12
12
  * `MastraHarness.buildLanguageModel` currently hands its internal builders, so an
@@ -33,10 +33,10 @@ export type MastraLanguageModelBuilderContext = {
33
33
  innerFetch: typeof fetch;
34
34
  };
35
35
  /**
36
- * Factory function shape for a consumer-injected `LanguageModelV3` builder.
36
+ * Factory function shape for a consumer-injected `LanguageModelV4` builder.
37
37
  * Registered via `MastraHarnessFactoryConfig.languageModelBuilders` keyed by a custom
38
38
  * `providerHint`, used to inject wire shapes the harness does not ship natively
39
- * (e.g. a temporary GovCloud `chat/generations` fallback). The builder receives the
39
+ * (e.g. a bespoke gateway wire format). The builder receives the
40
40
  * same context bag the harness's built-in pass-through builders get, so an injected
41
41
  * builder can emit `WireCommunicationEvent`s and honor `HTTPS_PROXY` routing without
42
42
  * duplicating the harness's own fetch wrapper / wire-monitoring plumbing. The
@@ -55,4 +55,4 @@ export type MastraLanguageModelBuilderContext = {
55
55
  * });
56
56
  * ```
57
57
  */
58
- export type MastraLanguageModelBuilder = (ctx: MastraLanguageModelBuilderContext) => LanguageModelV3;
58
+ export type MastraLanguageModelBuilder = (ctx: MastraLanguageModelBuilderContext) => LanguageModelV4;
@@ -12,10 +12,10 @@ export interface MastraHarnessFactoryConfig {
12
12
  */
13
13
  toolApprovalTimeoutMs?: number;
14
14
  /**
15
- * Consumer-registered `LanguageModelV3` builders keyed by `providerHint`. Each key
15
+ * Consumer-registered `LanguageModelV4` builders keyed by `providerHint`. Each key
16
16
  * becomes a supported provider hint and a dispatch arm in `buildLanguageModel`. Used
17
- * to inject wire shapes the harness does not ship natively (e.g. a temporary
18
- * GovCloud `chat/generations` fallback path). Keys MUST NOT collide with the
17
+ * to inject wire shapes the harness does not ship natively (e.g. a bespoke
18
+ * gateway wire format). Keys MUST NOT collide with the
19
19
  * harness's built-in hints (`anthropic`, `bedrock-anthropic`, `openai`,
20
20
  * `openai-responses`, `openai-compatible`) — constructing with a colliding key
21
21
  * throws at factory construction time rather than silently shadowing the built-in.
@@ -8,7 +8,7 @@ import { MastraApprovalCoordinator } from './mastra-approval-coordinator.js';
8
8
  import { type HttpErrorCapture } from './mcp-config-mapper.js';
9
9
  import { type MastraAgentConfig, type SkillSearchHandle, type ToolSearchHandle } from './tool-search.js';
10
10
  import { type MultimodalFile } from '@salesforce/sfdx-agent-sdk';
11
- import type { LanguageModelV3 } from '@ai-sdk/provider';
11
+ import type { LanguageModelV4 } from '@ai-sdk/provider';
12
12
  import { Clock, type LogRecord, type BackoffRetryerDeps, type UniqueIDGenerator, type Unsubscribe } from '@salesforce/agentic-common';
13
13
  import { type ToolsInput } from './utils.js';
14
14
  import { Workspace } from '@mastra/core/workspace';
@@ -247,13 +247,13 @@ export interface MastraHarnessOptions {
247
247
  */
248
248
  innerFetch?: typeof fetch;
249
249
  /**
250
- * Consumer-registered `LanguageModelV3` builders keyed by `providerHint`.
250
+ * Consumer-registered `LanguageModelV4` builders keyed by `providerHint`.
251
251
  * Forwarded from `MastraHarnessFactoryConfig.languageModelBuilders`. The
252
252
  * harness consults this map in `buildLanguageModel`'s `default` arm before
253
253
  * throwing `MODEL_NOT_SUPPORTED_BY_HARNESS`, so an injected builder can
254
254
  * handle a custom hint without editing the harness's internal switch.
255
255
  */
256
- languageModelBuilders?: Readonly<Record<string, (ctx: MastraLanguageModelBuilderContext) => LanguageModelV3>>;
256
+ languageModelBuilders?: Readonly<Record<string, (ctx: MastraLanguageModelBuilderContext) => LanguageModelV4>>;
257
257
  /**
258
258
  * Clock / sleep / RNG for the pre-first-token LLM retry loop (W-24236393), whose policy is
259
259
  * `PRE_FIRST_TOKEN_RETRY_OPTIONS`. Tests inject a no-sleep `sleep`.
@@ -327,9 +327,8 @@ export declare class MastraHarness implements MastraAgentHarness {
327
327
  * counter owned by the language model would bleed across turns AND across
328
328
  * concurrent threads; owning it here — the innermost map reset at each
329
329
  * `stream()` (per-turn) and keyed by thread (per-thread) — matches Claude's
330
- * per-`stream()` `toolArgFailureCounts` and OpenAI's per-turn
331
- * `consumerToolArgsAttempts`, so the exhaustion-clause wording is identical
332
- * across all three harnesses. Nested (rather than a `${agentId}::${threadId}`
330
+ * per-`stream()` `toolArgFailureCounts`, so the exhaustion-clause wording is
331
+ * identical across both harnesses. Nested (rather than a `${agentId}::${threadId}`
333
332
  * string key) so a consumer id containing the delimiter can't alias two
334
333
  * distinct scopes, and cleanup is O(1): `destroyThread` deletes the thread
335
334
  * entry, `destroyAgent` deletes the agent entry, `shutdown` clears all.
@@ -515,7 +514,7 @@ export declare class MastraHarness implements MastraAgentHarness {
515
514
  * non-empty paths.
516
515
  */
517
516
  /**
518
- * Dispatches on the bag's `providerHint` and returns a `LanguageModelV3` that
517
+ * Dispatches on the bag's `providerHint` and returns a `LanguageModelV4` that
519
518
  * speaks the provider-native pass-through endpoint. The builder closes over
520
519
  * `getInfo` so within-shape `modelId` swaps, JWT rotations, and
521
520
  * premium-rate-limit gate flips land on the next outbound call without
@@ -589,8 +588,8 @@ export declare class MastraHarness implements MastraAgentHarness {
589
588
  * `agent.stream()` accepts.
590
589
  *
591
590
  * `text` parts collapse into text content blocks; `image` / `file` parts become v5 `file`
592
- * content blocks (`mediaType` + base64 `data` + optional `filename`) that Mastra forwards to the
593
- * gateway bridge, which collects them into `ChatMessageIn.files[]`. Pre-stream validation and the
591
+ * content blocks (`mediaType` + base64 `data` + optional `filename`) that Mastra normalizes to V4
592
+ * `file` parts for the provider pass-through translators. Pre-stream validation and the
594
593
  * input-part guard live in the SDK's {@link lowerStreamInput}, so file caps and the
595
594
  * `MULTIMODAL_NOT_SUPPORTED` / `INVALID_MESSAGE_CONTENT` semantics are identical to the Claude
596
595
  * harness; this method only supplies the Mastra-specific lowering of each part.
@@ -27,7 +27,7 @@ import { validateMultimodalFiles } from '@salesforce/sfdx-agent-sdk';
27
27
  import { buildAnthropicDirectLanguageModel, buildAnthropicLanguageModel } from './pass-through-anthropic.js';
28
28
  import { buildOpenAIChatCompletionsLanguageModel } from './pass-through-openai-chat-completions.js';
29
29
  import { buildOpenAILanguageModel } from './pass-through-openai.js';
30
- import { readToolArgsRetryScope, TOOL_ARGS_RETRY_SCOPE_AGENT_ID, TOOL_ARGS_RETRY_SCOPE_PROVIDER, TOOL_ARGS_RETRY_SCOPE_THREAD_ID, } from './v3-stream-mapping.js';
30
+ import { readToolArgsRetryScope, TOOL_ARGS_RETRY_SCOPE_AGENT_ID, TOOL_ARGS_RETRY_SCOPE_PROVIDER, TOOL_ARGS_RETRY_SCOPE_THREAD_ID, } from './stream-mapping.js';
31
31
  import { ToolResultRedactionProcessor } from './mastra-tool-result-redaction-processor.js';
32
32
  import { backfillCreatedAt, buildSummaryPrompt, Clock, getErrorMessage, RealClock, splitFrontmatterAndBody, UUIDGenerator, } from '@salesforce/agentic-common';
33
33
  import { withPreFirstTokenRetry } from './retry-pre-first-token.js';
@@ -495,9 +495,8 @@ export class MastraHarness {
495
495
  * counter owned by the language model would bleed across turns AND across
496
496
  * concurrent threads; owning it here — the innermost map reset at each
497
497
  * `stream()` (per-turn) and keyed by thread (per-thread) — matches Claude's
498
- * per-`stream()` `toolArgFailureCounts` and OpenAI's per-turn
499
- * `consumerToolArgsAttempts`, so the exhaustion-clause wording is identical
500
- * across all three harnesses. Nested (rather than a `${agentId}::${threadId}`
498
+ * per-`stream()` `toolArgFailureCounts`, so the exhaustion-clause wording is
499
+ * identical across both harnesses. Nested (rather than a `${agentId}::${threadId}`
501
500
  * string key) so a consumer id containing the delimiter can't alias two
502
501
  * distinct scopes, and cleanup is O(1): `destroyThread` deletes the thread
503
502
  * entry, `destroyAgent` deletes the agent entry, `shutdown` clears all.
@@ -1551,7 +1550,7 @@ export class MastraHarness {
1551
1550
  * non-empty paths.
1552
1551
  */
1553
1552
  /**
1554
- * Dispatches on the bag's `providerHint` and returns a `LanguageModelV3` that
1553
+ * Dispatches on the bag's `providerHint` and returns a `LanguageModelV4` that
1555
1554
  * speaks the provider-native pass-through endpoint. The builder closes over
1556
1555
  * `getInfo` so within-shape `modelId` swaps, JWT rotations, and
1557
1556
  * premium-rate-limit gate flips land on the next outbound call without
@@ -1672,9 +1671,9 @@ export class MastraHarness {
1672
1671
  }));
1673
1672
  default: {
1674
1673
  // Consult the injected builders map before throwing. This is the
1675
- // extension point for consumer-registered wire shapes (e.g. a temporary
1676
- // GovCloud chat/generations fallback, W-23560954). The builder receives
1677
- // the same context bag the built-in builders get.
1674
+ // extension point for consumer-registered wire shapes (e.g. a bespoke
1675
+ // gateway wire format). The builder receives the same context bag the
1676
+ // built-in builders get.
1678
1677
  const custom = this.languageModelBuilders?.[initial.providerHint];
1679
1678
  if (custom) {
1680
1679
  return this.wrapLanguageModel(custom({ getInfo, logBus, emitWireCommunication, innerFetch }));
@@ -1774,8 +1773,8 @@ export class MastraHarness {
1774
1773
  * `agent.stream()` accepts.
1775
1774
  *
1776
1775
  * `text` parts collapse into text content blocks; `image` / `file` parts become v5 `file`
1777
- * content blocks (`mediaType` + base64 `data` + optional `filename`) that Mastra forwards to the
1778
- * gateway bridge, which collects them into `ChatMessageIn.files[]`. Pre-stream validation and the
1776
+ * content blocks (`mediaType` + base64 `data` + optional `filename`) that Mastra normalizes to V4
1777
+ * `file` parts for the provider pass-through translators. Pre-stream validation and the
1779
1778
  * input-part guard live in the SDK's {@link lowerStreamInput}, so file caps and the
1780
1779
  * `MULTIMODAL_NOT_SUPPORTED` / `INVALID_MESSAGE_CONTENT` semantics are identical to the Claude
1781
1780
  * harness; this method only supplies the Mastra-specific lowering of each part.
@@ -54,9 +54,8 @@ export function mapToolDefinitionsToMastraTools(tools, parkerLookup) {
54
54
  inputSchema: toStandardSchema(ensureJsonSchemaMarker(tool.inputSchema)),
55
55
  // `strict: false` keeps a provider compat-layer (OpenAI/Anthropic
56
56
  // strict-mode) from RE-degrading the preserved schema on the way to the
57
- // wire — arbitrary consumer schemas aren't structured-output schemas
58
- // (the OpenAI harness sets `strict: false` on consumer tools for the
59
- // same reason). Without it, `CoreToolBuilder.build` applies a matching
57
+ // wire — arbitrary consumer schemas aren't structured-output schemas.
58
+ // Without it, `CoreToolBuilder.build` applies a matching
60
59
  // compat layer that reintroduces `additionalProperties:false`.
61
60
  strict: false,
62
61
  // Issue #529 step 2c (Path A) — consumer tools bypass the
@@ -1,10 +1,10 @@
1
1
  import Anthropic from '@anthropic-ai/sdk';
2
- import type { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3Prompt } from '@ai-sdk/provider';
2
+ import type { LanguageModelV4, LanguageModelV4CallOptions, LanguageModelV4Prompt } from '@ai-sdk/provider';
3
3
  import type { LogBus } from '@salesforce/agentic-common';
4
4
  import type { ModelConnectivityInfo, WireCommunicationEvent } from '@salesforce/sfdx-agent-sdk';
5
- import { type GatewayFetchWireHooks } from './v3-stream-mapping.js';
5
+ import { type GatewayFetchWireHooks } from './stream-mapping.js';
6
6
  /**
7
- * Builds the in-process `LanguageModelV3` impl for the Salesforce LLM Gateway's
7
+ * Builds the in-process `LanguageModelV4` impl for the Salesforce LLM Gateway's
8
8
  * `/invoke-with-response-stream` (Bedrock-Anthropic pass-through) endpoint.
9
9
  * Drives `@anthropic-ai/bedrock-sdk` with `skipAuth: true` so the connectivity
10
10
  * resolver's headers (Salesforce JWT, tenant key, etc.) are the single source
@@ -50,9 +50,9 @@ export declare function buildAnthropicLanguageModel(opts: {
50
50
  * `standardSchemaToJSONSchema`), which injects `additionalProperties: false`
51
51
  * onto any object node that declared none (JSON Schema's default is open).
52
52
  * Gating against that closed schema would reject extra keys on an
53
- * implicitly-open nested object and diverge from Claude/OpenAI (which gate
53
+ * implicitly-open nested object and diverge from Claude (which gates
54
54
  * the pristine declared schema); validating the declared schema keeps the
55
- * gate verdict identical across all three harnesses (W-24023028). Same
55
+ * gate verdict identical across both harnesses (W-24023028). Same
56
56
  * per-config-snapshot freshness caveat as `getConsumerToolNames`. Defaults to
57
57
  * an empty map (no schema → the gate treats every consumer tool as
58
58
  * unvalidatable-`ok`) for callers that don't thread it.
@@ -66,12 +66,12 @@ export declare function buildAnthropicLanguageModel(opts: {
66
66
  * `LanguageModel`. Defaults to a single per-instance map for callers that
67
67
  * don't thread it (tests / consumer-injected builders).
68
68
  */
69
- getToolArgsRetryCounts?: (options: LanguageModelV3CallOptions) => Map<string, number>;
69
+ getToolArgsRetryCounts?: (options: LanguageModelV4CallOptions) => Map<string, number>;
70
70
  /** Per-read idle timeout (ms) for the gateway response body; see `createGatewayFetch`. */
71
71
  idleReadTimeoutMs?: number;
72
- }): LanguageModelV3;
72
+ }): LanguageModelV4;
73
73
  /**
74
- * Builds the in-process `LanguageModelV3` impl for direct-Anthropic API access
74
+ * Builds the in-process `LanguageModelV4` impl for direct-Anthropic API access
75
75
  * (`api.anthropic.com/v1/messages` or any Anthropic-shaped endpoint). Drives
76
76
  * `@anthropic-ai/sdk` with the api-key peeled from the resolver's headers.
77
77
  *
@@ -101,10 +101,10 @@ export declare function buildAnthropicDirectLanguageModel(opts: {
101
101
  /** See {@link buildAnthropicLanguageModel} `getConsumerToolSchemas`. */
102
102
  getConsumerToolSchemas?: () => ReadonlyMap<string, Record<string, unknown>>;
103
103
  /** See {@link buildAnthropicLanguageModel} `getToolArgsRetryCounts`. */
104
- getToolArgsRetryCounts?: (options: LanguageModelV3CallOptions) => Map<string, number>;
104
+ getToolArgsRetryCounts?: (options: LanguageModelV4CallOptions) => Map<string, number>;
105
105
  /** Per-read idle timeout (ms) for the gateway response body; see `createGatewayFetch`. */
106
106
  idleReadTimeoutMs?: number;
107
- }): LanguageModelV3;
107
+ }): LanguageModelV4;
108
108
  /**
109
109
  * Stamps `cache_control: {type:'ephemeral'}` on up to three of Anthropic's four
110
110
  * allowed breakpoints: the last tool (caches the constant tools block), the
@@ -115,25 +115,25 @@ export declare function buildAnthropicDirectLanguageModel(opts: {
115
115
  * only the turn-constant tools/system cached and forfeit most of the win.
116
116
  * Mutates only `commonParams`'s own arrays — which
117
117
  * `translate*ToAnthropic` builds fresh per request — never the caller's
118
- * original `LanguageModelV3` prompt/tool objects.
118
+ * original `LanguageModelV4` prompt/tool objects.
119
119
  */
120
120
  export declare function applyCacheBreakpoints(commonParams: Omit<Anthropic.Messages.MessageCreateParamsStreaming, 'stream'>): void;
121
121
  /**
122
- * Translates a V3 `LanguageModelV3Prompt` into Anthropic's Messages API shape
122
+ * Translates a V4 `LanguageModelV4Prompt` into Anthropic's Messages API shape
123
123
  * — top-level `system` string + `MessageParam[]` of role-tagged content blocks.
124
124
  *
125
- * V3 keeps system / user / assistant / tool messages flat. Anthropic combines
125
+ * V4 keeps system / user / assistant / tool messages flat. Anthropic combines
126
126
  * tool results onto a synthetic user-role turn carrying `tool_result` blocks,
127
- * so we collapse consecutive tool-only V3 messages into the surrounding user
127
+ * so we collapse consecutive tool-only V4 messages into the surrounding user
128
128
  * turn shape.
129
129
  */
130
- export declare function translatePromptToAnthropic(prompt: LanguageModelV3Prompt): {
130
+ export declare function translatePromptToAnthropic(prompt: LanguageModelV4Prompt): {
131
131
  system?: string;
132
132
  messages: Anthropic.Messages.MessageParam[];
133
133
  };
134
134
  /**
135
- * Translates V3 function-tool definitions into Anthropic's `Tool[]` shape.
135
+ * Translates V4 function-tool definitions into Anthropic's `Tool[]` shape.
136
136
  * Skips non-function variants (provider-defined / dynamic) — the pass-through
137
137
  * path supports only the function-tool subset that Mastra's tool mapper produces.
138
138
  */
139
- export declare function translateToolsToAnthropic(options: LanguageModelV3CallOptions): Anthropic.Messages.Tool[];
139
+ export declare function translateToolsToAnthropic(options: LanguageModelV4CallOptions): Anthropic.Messages.Tool[];
@@ -5,9 +5,9 @@
5
5
  import { AnthropicBedrock } from '@anthropic-ai/bedrock-sdk';
6
6
  import Anthropic from '@anthropic-ai/sdk';
7
7
  import { EmptyStreamError, NetworkStreamError, isStreamTransportError, recognizeBedrockValidationError, } from './stream-errors.js';
8
- import { SpanLifecycle, ToolInputSpanLifecycle, buildValidatedToolCallChunk, createGatewayFetch, isEmptyUsage, isParameterExcluded, mapAnthropicFinishReason, mapAnthropicUsage, toolResultOutputToString, } from './v3-stream-mapping.js';
8
+ import { SpanLifecycle, ToolInputSpanLifecycle, buildValidatedToolCallChunk, createGatewayFetch, isEmptyUsage, isParameterExcluded, mapAnthropicFinishReason, mapAnthropicUsage, toolResultOutputToString, v4FileDataToBase64, } from './stream-mapping.js';
9
9
  /**
10
- * Builds the in-process `LanguageModelV3` impl for the Salesforce LLM Gateway's
10
+ * Builds the in-process `LanguageModelV4` impl for the Salesforce LLM Gateway's
11
11
  * `/invoke-with-response-stream` (Bedrock-Anthropic pass-through) endpoint.
12
12
  * Drives `@anthropic-ai/bedrock-sdk` with `skipAuth: true` so the connectivity
13
13
  * resolver's headers (Salesforce JWT, tenant key, etc.) are the single source
@@ -44,7 +44,7 @@ export function buildAnthropicLanguageModel(opts) {
44
44
  }),
45
45
  };
46
46
  return {
47
- specificationVersion: 'v3',
47
+ specificationVersion: 'v4',
48
48
  provider: 'salesforce-llm-gateway-pass-through-anthropic',
49
49
  // Mastra captures `modelId` once at construction. The actual wire id
50
50
  // sent on every call is read from the live bag via `commonParams.model`
@@ -57,7 +57,7 @@ export function buildAnthropicLanguageModel(opts) {
57
57
  };
58
58
  }
59
59
  /**
60
- * Builds the in-process `LanguageModelV3` impl for direct-Anthropic API access
60
+ * Builds the in-process `LanguageModelV4` impl for direct-Anthropic API access
61
61
  * (`api.anthropic.com/v1/messages` or any Anthropic-shaped endpoint). Drives
62
62
  * `@anthropic-ai/sdk` with the api-key peeled from the resolver's headers.
63
63
  *
@@ -104,7 +104,7 @@ export function buildAnthropicDirectLanguageModel(opts) {
104
104
  }),
105
105
  };
106
106
  return {
107
- specificationVersion: 'v3',
107
+ specificationVersion: 'v4',
108
108
  provider: 'anthropic-direct-pass-through',
109
109
  modelId: initialInfo.nativeModelId,
110
110
  supportedUrls: {},
@@ -231,7 +231,7 @@ const CACHE_CONTROL_EPHEMERAL = Object.freeze({ type: 'ephemeral' });
231
231
  * only the turn-constant tools/system cached and forfeit most of the win.
232
232
  * Mutates only `commonParams`'s own arrays — which
233
233
  * `translate*ToAnthropic` builds fresh per request — never the caller's
234
- * original `LanguageModelV3` prompt/tool objects.
234
+ * original `LanguageModelV4` prompt/tool objects.
235
235
  */
236
236
  export function applyCacheBreakpoints(commonParams) {
237
237
  const tools = commonParams.tools;
@@ -348,7 +348,7 @@ async function doGenerate(ctx, options) {
348
348
  content.push(...buildValidatedToolCallChunk(block.id, block.name, argsBuffer, toolSchemas.get(block.name), ctx.getConsumerToolNames().has(block.name), { retryCounts: ctx.getToolArgsRetryCounts(options), logBus: ctx.logBus }));
349
349
  }
350
350
  // Other block types (redacted_thinking, server-tool-result, etc.) are
351
- // not in the V3 ChatEvent surface — same posture as doStream.
351
+ // not in the V4 ChatEvent surface — same posture as doStream.
352
352
  }
353
353
  const finishReason = mapAnthropicFinishReason(message.stop_reason, sawToolCalls);
354
354
  const usage = mapAnthropicUsage(message.usage);
@@ -398,7 +398,7 @@ async function doStream(ctx, options) {
398
398
  const stream = new ReadableStream({
399
399
  start: async (controller) => {
400
400
  const textSpan = new SpanLifecycle();
401
- // Extended-thinking narration streams on its own V3 reasoning span,
401
+ // Extended-thinking narration streams on its own V4 reasoning span,
402
402
  // so it surfaces as `reasoning-delta` (→ AG-UI REASONING_MESSAGE_CONTENT)
403
403
  // rather than bleeding into the answer's `text-delta`.
404
404
  const reasoningSpan = new SpanLifecycle('reasoning');
@@ -432,7 +432,7 @@ async function doStream(ctx, options) {
432
432
  case 'content_block_start': {
433
433
  const block = event.content_block;
434
434
  if (block.type === 'text') {
435
- // Open the V3 text span on the first text block of the message
435
+ // Open the V4 text span on the first text block of the message
436
436
  // (or after a tool_use rotated us forward).
437
437
  textSpan.openIfNeeded(controller);
438
438
  }
@@ -460,7 +460,7 @@ async function doStream(ctx, options) {
460
460
  });
461
461
  }
462
462
  // Other block types (redacted_thinking, server-tool result, etc.)
463
- // are intentionally ignored — they're not in the V3 ChatEvent surface.
463
+ // are intentionally ignored — they're not in the V4 ChatEvent surface.
464
464
  break;
465
465
  }
466
466
  case 'content_block_delta': {
@@ -481,7 +481,7 @@ async function doStream(ctx, options) {
481
481
  }
482
482
  }
483
483
  // signature_delta / citations_delta are not surfaced — the
484
- // encrypted thinking signature has no V3 stream-part and no
484
+ // encrypted thinking signature has no V4 stream-part and no
485
485
  // consumer surface (AG-UI ReasoningEncryptedValue is deferred).
486
486
  break;
487
487
  }
@@ -526,7 +526,7 @@ async function doStream(ctx, options) {
526
526
  }
527
527
  // Stream ended without an explicit `message_stop`. If we saw at least
528
528
  // one recognized content / usage event, close out the span and
529
- // synthesize a terminal `finish` so V3 consumers see exactly one. If
529
+ // synthesize a terminal `finish` so V4 consumers see exactly one. If
530
530
  // we saw NONE — a clean-but-empty body — surface a classified `error`
531
531
  // instead of a false-success empty `finish` (8a). A cancelled turn is
532
532
  // exempt: an aborted stream ends cleanly here too (the SDK `Stream`
@@ -556,7 +556,7 @@ async function doStream(ctx, options) {
556
556
  // Trailing-JSON #396: the gateway sometimes appends a JSON error envelope
557
557
  // after the terminal eventstream frame on otherwise-successful responses,
558
558
  // which the Anthropic SDK's parser surfaces as a late throw. Drop it
559
- // silently — V3 consumers must see exactly one terminal `finish`.
559
+ // silently — V4 consumers must see exactly one terminal `finish`.
560
560
  controller.close();
561
561
  return;
562
562
  }
@@ -574,7 +574,7 @@ async function doStream(ctx, options) {
574
574
  });
575
575
  return { stream };
576
576
  }
577
- /** Default Anthropic `max_tokens` when V3 doesn't supply one. The Bedrock invoke
577
+ /** Default Anthropic `max_tokens` when V4 doesn't supply one. The Bedrock invoke
578
578
  * API requires the field; Mastra leaves it unset for many turns. 4096 mirrors
579
579
  * the `@ai-sdk/anthropic` provider's default. */
580
580
  const DEFAULT_MAX_TOKENS = 4096;
@@ -590,12 +590,12 @@ const DEFAULT_MAX_TOKENS = 4096;
590
590
  */
591
591
  const SUMMARY_MAX_OUTPUT_TOKENS = 16384;
592
592
  /**
593
- * Translates a V3 `LanguageModelV3Prompt` into Anthropic's Messages API shape
593
+ * Translates a V4 `LanguageModelV4Prompt` into Anthropic's Messages API shape
594
594
  * — top-level `system` string + `MessageParam[]` of role-tagged content blocks.
595
595
  *
596
- * V3 keeps system / user / assistant / tool messages flat. Anthropic combines
596
+ * V4 keeps system / user / assistant / tool messages flat. Anthropic combines
597
597
  * tool results onto a synthetic user-role turn carrying `tool_result` blocks,
598
- * so we collapse consecutive tool-only V3 messages into the surrounding user
598
+ * so we collapse consecutive tool-only V4 messages into the surrounding user
599
599
  * turn shape.
600
600
  */
601
601
  export function translatePromptToAnthropic(prompt) {
@@ -669,7 +669,7 @@ export function translatePromptToAnthropic(prompt) {
669
669
  return system !== undefined ? { system, messages } : { messages };
670
670
  }
671
671
  /**
672
- * Translates V3 function-tool definitions into Anthropic's `Tool[]` shape.
672
+ * Translates V4 function-tool definitions into Anthropic's `Tool[]` shape.
673
673
  * Skips non-function variants (provider-defined / dynamic) — the pass-through
674
674
  * path supports only the function-tool subset that Mastra's tool mapper produces.
675
675
  */
@@ -685,13 +685,11 @@ export function translateToolsToAnthropic(options) {
685
685
  }));
686
686
  }
687
687
  function toAnthropicFileBlock(part) {
688
- if (typeof part.data !== 'string') {
689
- throw new Error(`Unsupported file data for "${part.mediaType}": expected a base64 string, got ${part.data instanceof URL ? 'a URL' : 'binary data'}. Only base64-encoded file data is supported.`);
690
- }
688
+ const base64 = v4FileDataToBase64(part.data, part.mediaType);
691
689
  if (part.mediaType === 'application/pdf') {
692
690
  return {
693
691
  type: 'document',
694
- source: { type: 'base64', media_type: 'application/pdf', data: part.data },
692
+ source: { type: 'base64', media_type: 'application/pdf', data: base64 },
695
693
  };
696
694
  }
697
695
  if (part.mediaType === 'image/png' ||
@@ -700,7 +698,7 @@ function toAnthropicFileBlock(part) {
700
698
  part.mediaType === 'image/webp') {
701
699
  return {
702
700
  type: 'image',
703
- source: { type: 'base64', media_type: part.mediaType, data: part.data },
701
+ source: { type: 'base64', media_type: part.mediaType, data: base64 },
704
702
  };
705
703
  }
706
704
  throw new Error(`Unsupported file media type "${part.mediaType}". Anthropic supports image/png, image/jpeg, image/gif, image/webp, application/pdf.`);
@@ -1,10 +1,10 @@
1
1
  import type { ChatCompletionMessageParam, ChatCompletionTool } from 'openai/resources/chat/completions';
2
- import type { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3FinishReason, LanguageModelV3Prompt } from '@ai-sdk/provider';
2
+ import type { LanguageModelV4, LanguageModelV4CallOptions, LanguageModelV4FinishReason, LanguageModelV4Prompt } from '@ai-sdk/provider';
3
3
  import type { LogBus } from '@salesforce/agentic-common';
4
4
  import type { ModelConnectivityInfo, WireCommunicationEvent } from '@salesforce/sfdx-agent-sdk';
5
- import { type GatewayFetchWireHooks } from './v3-stream-mapping.js';
5
+ import { type GatewayFetchWireHooks } from './stream-mapping.js';
6
6
  /**
7
- * Builds the in-process `LanguageModelV3` impl that drives the `openai` SDK's
7
+ * Builds the in-process `LanguageModelV4` impl that drives the `openai` SDK's
8
8
  * `chat.completions.create({ stream: true })` against an OpenAI-compatible
9
9
  * endpoint (LLM Gateway Express, LiteLLM, vLLM, etc. — anything that speaks
10
10
  * `/v1/chat/completions`).
@@ -15,7 +15,7 @@ import { type GatewayFetchWireHooks } from './v3-stream-mapping.js';
15
15
  * `input` split); (3) streaming events are `ChatCompletionChunk` objects with
16
16
  * `choices[0].delta` text/tool-call deltas and the terminal `finish_reason`
17
17
  * landing on the same chunk shape rather than a discrete `response.completed`
18
- * event. The V3 mapping output is identical — same `text-delta` / `tool-call` /
18
+ * event. The V4 mapping output is identical — same `text-delta` / `tool-call` /
19
19
  * `finish` parts the Responses builder produces.
20
20
  *
21
21
  * Per-call freshness contract is the same as the other builders: every HTTP
@@ -35,28 +35,28 @@ export declare function buildOpenAIChatCompletionsLanguageModel(opts: {
35
35
  /** See `buildAnthropicLanguageModel` `getConsumerToolSchemas`. */
36
36
  getConsumerToolSchemas?: () => ReadonlyMap<string, Record<string, unknown>>;
37
37
  /** See `buildAnthropicLanguageModel` `getToolArgsRetryCounts`. */
38
- getToolArgsRetryCounts?: (options: LanguageModelV3CallOptions) => Map<string, number>;
38
+ getToolArgsRetryCounts?: (options: LanguageModelV4CallOptions) => Map<string, number>;
39
39
  /** Per-read idle timeout (ms) for the gateway response body; see `createGatewayFetch`. */
40
40
  idleReadTimeoutMs?: number;
41
- }): LanguageModelV3;
41
+ }): LanguageModelV4;
42
42
  /**
43
- * Translates a V3 `LanguageModelV3Prompt` into the OpenAI Chat Completions
43
+ * Translates a V4 `LanguageModelV4Prompt` into the OpenAI Chat Completions
44
44
  * `messages` array shape. System messages stay as `system` role; user / tool
45
45
  * follow naturally. Assistant text + tool-calls collapse onto a single
46
46
  * assistant message carrying a `content` string (when text is present) plus
47
47
  * `tool_calls` (when calls are present). Tool results land on `tool` role
48
48
  * with `tool_call_id`.
49
49
  */
50
- export declare function translatePromptToChatCompletions(prompt: LanguageModelV3Prompt): ChatCompletionMessageParam[];
50
+ export declare function translatePromptToChatCompletions(prompt: LanguageModelV4Prompt): ChatCompletionMessageParam[];
51
51
  /**
52
- * Translates V3 function-tool definitions into the Chat Completions `tools[]`
52
+ * Translates V4 function-tool definitions into the Chat Completions `tools[]`
53
53
  * shape. Skips non-function variants — same posture as the Responses builder.
54
54
  */
55
- export declare function translateToolsToChatCompletions(options: LanguageModelV3CallOptions): ChatCompletionTool[];
55
+ export declare function translateToolsToChatCompletions(options: LanguageModelV4CallOptions): ChatCompletionTool[];
56
56
  /**
57
- * Maps Chat Completions `finish_reason` onto V3's unified shape. The Chat
57
+ * Maps Chat Completions `finish_reason` onto V4's unified shape. The Chat
58
58
  * Completions API uses `'stop' | 'length' | 'tool_calls' | 'content_filter' |
59
59
  * 'function_call' | null`. `function_call` is the legacy shape from before
60
60
  * `tool_calls` existed; modern endpoints emit `'tool_calls'`.
61
61
  */
62
- export declare function mapChatCompletionFinishReason(raw: string | null, sawToolCalls: boolean): LanguageModelV3FinishReason;
62
+ export declare function mapChatCompletionFinishReason(raw: string | null, sawToolCalls: boolean): LanguageModelV4FinishReason;