@salesforce/sfdx-agent-sdk 0.20.0 → 0.22.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 +15 -0
- package/README.md +12 -11
- package/dist/agent-connectivity-resolver.d.ts +47 -25
- package/dist/agent-connectivity-resolver.js +92 -15
- package/dist/agent-manager.d.ts +17 -1
- package/dist/agent-manager.js +40 -7
- package/dist/agent.d.ts +33 -10
- package/dist/agent.js +38 -50
- package/dist/api-key-connectivity-resolver.d.ts +110 -0
- package/dist/api-key-connectivity-resolver.js +114 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +2 -0
- package/dist/harness/agent-harness.d.ts +27 -5
- package/dist/harness/harness-bus-owner.d.ts +17 -0
- package/dist/harness/harness-bus-owner.js +27 -0
- package/dist/harness/harness-config.d.ts +3 -2
- package/dist/harness/harness-factory.d.ts +13 -0
- package/dist/harness/stream-input.d.ts +9 -5
- package/dist/harness/stream-input.js +12 -14
- package/dist/index.d.ts +8 -2
- package/dist/index.js +4 -1
- package/dist/internal/wire-communication-router.d.ts +43 -0
- package/dist/internal/wire-communication-router.js +119 -0
- package/dist/mcp-auth.d.ts +1 -1
- package/dist/models/claude-opus-4-5.d.ts +11 -0
- package/dist/models/claude-opus-4-5.js +21 -0
- package/dist/models/claude-opus-4-6.d.ts +11 -0
- package/dist/models/claude-opus-4-6.js +22 -0
- package/dist/models/claude-opus-4-7.d.ts +11 -0
- package/dist/models/claude-opus-4-7.js +22 -0
- package/dist/models/claude-sonnet-4-5.d.ts +11 -0
- package/dist/models/claude-sonnet-4-5.js +23 -0
- package/dist/models/claude-sonnet-4-6.d.ts +11 -0
- package/dist/models/claude-sonnet-4-6.js +22 -0
- package/dist/models/create-claude-model.d.ts +54 -0
- package/dist/models/create-claude-model.js +62 -0
- package/dist/models/gpt-5-4.d.ts +11 -0
- package/dist/models/gpt-5-4.js +21 -0
- package/dist/models/gpt-5-5.d.ts +15 -0
- package/dist/models/gpt-5-5.js +24 -0
- package/dist/models/gpt-5.d.ts +11 -0
- package/dist/models/gpt-5.js +23 -0
- package/dist/models/index.d.ts +19 -0
- package/dist/models/index.js +49 -0
- package/dist/models/model.d.ts +69 -0
- package/dist/models/model.js +63 -0
- package/dist/models/multimodal.d.ts +35 -0
- package/dist/models/multimodal.js +78 -0
- package/dist/models/types.d.ts +49 -0
- package/dist/models/types.js +18 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/model-connectivity-info.d.ts +87 -0
- package/dist/types/model-connectivity-info.js +6 -0
- package/dist/types/usage.d.ts +3 -3
- package/dist/types/wire-communication-event.d.ts +124 -0
- package/dist/types/wire-communication-event.js +6 -0
- package/dist/wire-communication-file-writer.d.ts +39 -0
- package/dist/wire-communication-file-writer.js +142 -0
- package/package.json +7 -8
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
import { Model, ModelName } from './model.js';
|
|
6
|
+
import { MimeType } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* GPT-5.5 is BETA on the gateway and gated behind the `AIModelBetaEnabled` org preference plus the
|
|
9
|
+
* `enableBetaModels` perm. Orgs without the gate active will receive a gateway error at request time.
|
|
10
|
+
*/
|
|
11
|
+
export class GPT55 extends Model {
|
|
12
|
+
name = ModelName.GPT_5_5;
|
|
13
|
+
displayId = 'GPT-5.5';
|
|
14
|
+
maxInputTokens = 1050000;
|
|
15
|
+
maxOutputTokens = 128000;
|
|
16
|
+
contextWindow = 1050000;
|
|
17
|
+
supportsPromptCache = false;
|
|
18
|
+
supportedFormats = [
|
|
19
|
+
{ name: 'png', mimeType: MimeType.Png },
|
|
20
|
+
{ name: 'jpeg', mimeType: MimeType.Jpeg },
|
|
21
|
+
{ name: 'pdf', mimeType: MimeType.Pdf },
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=gpt-5-5.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Model, ModelName } from './model.js';
|
|
2
|
+
import { type SupportedFileFormat } from './types.js';
|
|
3
|
+
export declare class GPT5 extends Model {
|
|
4
|
+
readonly name: ModelName;
|
|
5
|
+
readonly displayId: string;
|
|
6
|
+
readonly maxInputTokens: number;
|
|
7
|
+
readonly maxOutputTokens: number;
|
|
8
|
+
readonly contextWindow: number;
|
|
9
|
+
readonly supportsPromptCache: boolean;
|
|
10
|
+
readonly supportedFormats: readonly SupportedFileFormat[];
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
import { Model, ModelName } from './model.js';
|
|
6
|
+
import { MimeType } from './types.js';
|
|
7
|
+
export class GPT5 extends Model {
|
|
8
|
+
name = ModelName.GPT_5;
|
|
9
|
+
displayId = 'GPT-5';
|
|
10
|
+
// Reference: https://help.salesforce.com/s/articleView?id=ai.generative_ai_llm_limits.htm&type=5
|
|
11
|
+
maxInputTokens = 272000;
|
|
12
|
+
maxOutputTokens = 128000;
|
|
13
|
+
contextWindow = 272000;
|
|
14
|
+
supportsPromptCache = false;
|
|
15
|
+
// Multimodal limits: 15 MiB total, 10 files / request (the global SDK caps bind).
|
|
16
|
+
// No per-format caps are set for OpenAI models — only the global caps apply.
|
|
17
|
+
supportedFormats = [
|
|
18
|
+
{ name: 'png', mimeType: MimeType.Png },
|
|
19
|
+
{ name: 'jpeg', mimeType: MimeType.Jpeg },
|
|
20
|
+
{ name: 'pdf', mimeType: MimeType.Pdf },
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=gpt-5.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Model, ModelName } from './model.js';
|
|
2
|
+
export { Model, ModelName } from './model.js';
|
|
3
|
+
export { MimeType, type SupportedFileFormat, type MultimodalFile } from './types.js';
|
|
4
|
+
export { validateMultimodalFiles, MAX_FILES_PER_REQUEST, MAX_TOTAL_FILE_BYTES } from './multimodal.js';
|
|
5
|
+
export { GPT5 } from './gpt-5.js';
|
|
6
|
+
export { GPT54 } from './gpt-5-4.js';
|
|
7
|
+
export { GPT55 } from './gpt-5-5.js';
|
|
8
|
+
export { ClaudeSonnet45 } from './claude-sonnet-4-5.js';
|
|
9
|
+
export { ClaudeSonnet46 } from './claude-sonnet-4-6.js';
|
|
10
|
+
export { ClaudeOpus45 } from './claude-opus-4-5.js';
|
|
11
|
+
export { ClaudeOpus46 } from './claude-opus-4-6.js';
|
|
12
|
+
export { ClaudeOpus47 } from './claude-opus-4-7.js';
|
|
13
|
+
export { createClaudeModel, type ClaudeModelOverrides } from './create-claude-model.js';
|
|
14
|
+
export declare function getDefault(): Model;
|
|
15
|
+
export declare function getByName(modelName: ModelName): Model;
|
|
16
|
+
export declare const Models: {
|
|
17
|
+
readonly getDefault: typeof getDefault;
|
|
18
|
+
readonly getByName: typeof getByName;
|
|
19
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
import { Model, ModelName } from './model.js';
|
|
6
|
+
import { GPT5 } from './gpt-5.js';
|
|
7
|
+
import { GPT54 } from './gpt-5-4.js';
|
|
8
|
+
import { GPT55 } from './gpt-5-5.js';
|
|
9
|
+
import { ClaudeSonnet45 } from './claude-sonnet-4-5.js';
|
|
10
|
+
import { ClaudeSonnet46 } from './claude-sonnet-4-6.js';
|
|
11
|
+
import { ClaudeOpus45 } from './claude-opus-4-5.js';
|
|
12
|
+
import { ClaudeOpus46 } from './claude-opus-4-6.js';
|
|
13
|
+
import { ClaudeOpus47 } from './claude-opus-4-7.js';
|
|
14
|
+
export { Model, ModelName } from './model.js';
|
|
15
|
+
export { MimeType } from './types.js';
|
|
16
|
+
export { validateMultimodalFiles, MAX_FILES_PER_REQUEST, MAX_TOTAL_FILE_BYTES } from './multimodal.js';
|
|
17
|
+
export { GPT5 } from './gpt-5.js';
|
|
18
|
+
export { GPT54 } from './gpt-5-4.js';
|
|
19
|
+
export { GPT55 } from './gpt-5-5.js';
|
|
20
|
+
export { ClaudeSonnet45 } from './claude-sonnet-4-5.js';
|
|
21
|
+
export { ClaudeSonnet46 } from './claude-sonnet-4-6.js';
|
|
22
|
+
export { ClaudeOpus45 } from './claude-opus-4-5.js';
|
|
23
|
+
export { ClaudeOpus46 } from './claude-opus-4-6.js';
|
|
24
|
+
export { ClaudeOpus47 } from './claude-opus-4-7.js';
|
|
25
|
+
export { createClaudeModel } from './create-claude-model.js';
|
|
26
|
+
export function getDefault() {
|
|
27
|
+
return new ClaudeSonnet46();
|
|
28
|
+
}
|
|
29
|
+
export function getByName(modelName) {
|
|
30
|
+
if (modelName === ModelName.GPT_5)
|
|
31
|
+
return new GPT5();
|
|
32
|
+
if (modelName === ModelName.GPT_5_4)
|
|
33
|
+
return new GPT54();
|
|
34
|
+
if (modelName === ModelName.GPT_5_5)
|
|
35
|
+
return new GPT55();
|
|
36
|
+
if (modelName === ModelName.CLAUDE_SONNET_4_5)
|
|
37
|
+
return new ClaudeSonnet45();
|
|
38
|
+
if (modelName === ModelName.CLAUDE_SONNET_4_6)
|
|
39
|
+
return new ClaudeSonnet46();
|
|
40
|
+
if (modelName === ModelName.CLAUDE_OPUS_4_5)
|
|
41
|
+
return new ClaudeOpus45();
|
|
42
|
+
if (modelName === ModelName.CLAUDE_OPUS_4_6)
|
|
43
|
+
return new ClaudeOpus46();
|
|
44
|
+
if (modelName === ModelName.CLAUDE_OPUS_4_7)
|
|
45
|
+
return new ClaudeOpus47();
|
|
46
|
+
throw new Error(`No model mapping exists for "${modelName}".`);
|
|
47
|
+
}
|
|
48
|
+
export const Models = { getDefault, getByName };
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { SupportedFileFormat } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The canonical Salesforce LLM-Gateway model ids the SDK ships in-tree.
|
|
4
|
+
* Consumer-built variants via {@link createClaudeModel} carry an arbitrary
|
|
5
|
+
* gateway id string (the escape hatch for Bedrock-Anthropic Claude
|
|
6
|
+
* variants the SDK has not released yet); cross-harness code that
|
|
7
|
+
* branches on `model.name` MUST guard with
|
|
8
|
+
* `Object.values(ModelName).includes(model.name)` before treating it as
|
|
9
|
+
* an enum-typed value — an exhaustive `switch` over `ModelName` will
|
|
10
|
+
* silently miss escape-hatch ids.
|
|
11
|
+
*/
|
|
12
|
+
export declare enum ModelName {
|
|
13
|
+
GPT_5 = "llmgateway__OpenAIGPT5",
|
|
14
|
+
GPT_5_4 = "llmgateway__OpenAIGPT54",
|
|
15
|
+
GPT_5_5 = "llmgateway__OpenAIGPT55",
|
|
16
|
+
CLAUDE_SONNET_4_5 = "llmgateway__BedrockAnthropicClaude45Sonnet",
|
|
17
|
+
CLAUDE_SONNET_4_6 = "llmgateway__BedrockAnthropicClaude46Sonnet",
|
|
18
|
+
CLAUDE_OPUS_4_5 = "llmgateway__BedrockAnthropicClaude45Opus",
|
|
19
|
+
CLAUDE_OPUS_4_6 = "llmgateway__BedrockAnthropicClaude46Opus",
|
|
20
|
+
CLAUDE_OPUS_4_7 = "llmgateway__BedrockAnthropicClaude47Opus"
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Abstract description of a model the SDK / harness can talk to. Used for:
|
|
24
|
+
*
|
|
25
|
+
* - **Pre-flight multimodal validation.** `supportedFormats` is the
|
|
26
|
+
* single source of truth for which file types this model accepts and
|
|
27
|
+
* the per-format caps (`maxBytesPerFile`, `maxFilesPerRequest`).
|
|
28
|
+
* - **Context-window tracking.** `ChatSession.getContextUsage()` reads
|
|
29
|
+
* `contextWindow` to compute "% of context used".
|
|
30
|
+
* - **Prompt-cache routing.** Anthropic-Claude-family models declare
|
|
31
|
+
* `supportsPromptCache: true`; harnesses use the flag to enable cache
|
|
32
|
+
* write/read on the wire.
|
|
33
|
+
*
|
|
34
|
+
* In-tree subclasses pin `name` to a {@link ModelName} enum member;
|
|
35
|
+
* instances built via {@link createClaudeModel} (the consumer-facing
|
|
36
|
+
* escape hatch for forward-compat with unreleased Bedrock-Claude
|
|
37
|
+
* variants) carry an arbitrary gateway id string.
|
|
38
|
+
*
|
|
39
|
+
* Reference: https://docs.internal.salesforce.com/ai/einstein/gateway/models-and-providers/
|
|
40
|
+
*/
|
|
41
|
+
export declare abstract class Model {
|
|
42
|
+
abstract readonly name: ModelName | string;
|
|
43
|
+
abstract readonly displayId: string;
|
|
44
|
+
abstract readonly maxInputTokens: number;
|
|
45
|
+
abstract readonly maxOutputTokens: number;
|
|
46
|
+
abstract readonly contextWindow: number;
|
|
47
|
+
abstract readonly supportsPromptCache: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* The file formats this model accepts, with per-format limits. An
|
|
50
|
+
* empty array means the model is text-only.
|
|
51
|
+
*/
|
|
52
|
+
abstract readonly supportedFormats: readonly SupportedFileFormat[];
|
|
53
|
+
readonly permittedParameters?: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Vendor-specific HTTP headers to add to every outbound request for this model
|
|
56
|
+
* (e.g. `anthropic-version`, model-tag opt-in headers). Merged with the
|
|
57
|
+
* resolver-built header set before the request is sent.
|
|
58
|
+
*
|
|
59
|
+
* **Reserved headers cannot be overridden.** Both bundled connectivity
|
|
60
|
+
* resolvers (`DefaultAgentConnectivityResolver`, `ApiKeyConnectivityResolver`)
|
|
61
|
+
* spread `customHeaders` FIRST and resolver-set fields last, so any
|
|
62
|
+
* `Authorization`, `Content-Type`, `x-client-feature-id`, `x-sfdc-app-context`,
|
|
63
|
+
* or `x-sfdc-core-tenant-id` keys here are silently shadowed by the
|
|
64
|
+
* resolver's freshly-built values. Use `customHeaders` for vendor labels
|
|
65
|
+
* only — never for auth or tenancy. Custom resolvers should follow the
|
|
66
|
+
* same convention.
|
|
67
|
+
*/
|
|
68
|
+
readonly customHeaders?: Record<string, string>;
|
|
69
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The canonical Salesforce LLM-Gateway model ids the SDK ships in-tree.
|
|
7
|
+
* Consumer-built variants via {@link createClaudeModel} carry an arbitrary
|
|
8
|
+
* gateway id string (the escape hatch for Bedrock-Anthropic Claude
|
|
9
|
+
* variants the SDK has not released yet); cross-harness code that
|
|
10
|
+
* branches on `model.name` MUST guard with
|
|
11
|
+
* `Object.values(ModelName).includes(model.name)` before treating it as
|
|
12
|
+
* an enum-typed value — an exhaustive `switch` over `ModelName` will
|
|
13
|
+
* silently miss escape-hatch ids.
|
|
14
|
+
*/
|
|
15
|
+
export var ModelName;
|
|
16
|
+
(function (ModelName) {
|
|
17
|
+
ModelName["GPT_5"] = "llmgateway__OpenAIGPT5";
|
|
18
|
+
ModelName["GPT_5_4"] = "llmgateway__OpenAIGPT54";
|
|
19
|
+
ModelName["GPT_5_5"] = "llmgateway__OpenAIGPT55";
|
|
20
|
+
ModelName["CLAUDE_SONNET_4_5"] = "llmgateway__BedrockAnthropicClaude45Sonnet";
|
|
21
|
+
ModelName["CLAUDE_SONNET_4_6"] = "llmgateway__BedrockAnthropicClaude46Sonnet";
|
|
22
|
+
ModelName["CLAUDE_OPUS_4_5"] = "llmgateway__BedrockAnthropicClaude45Opus";
|
|
23
|
+
ModelName["CLAUDE_OPUS_4_6"] = "llmgateway__BedrockAnthropicClaude46Opus";
|
|
24
|
+
ModelName["CLAUDE_OPUS_4_7"] = "llmgateway__BedrockAnthropicClaude47Opus";
|
|
25
|
+
})(ModelName || (ModelName = {}));
|
|
26
|
+
/**
|
|
27
|
+
* Abstract description of a model the SDK / harness can talk to. Used for:
|
|
28
|
+
*
|
|
29
|
+
* - **Pre-flight multimodal validation.** `supportedFormats` is the
|
|
30
|
+
* single source of truth for which file types this model accepts and
|
|
31
|
+
* the per-format caps (`maxBytesPerFile`, `maxFilesPerRequest`).
|
|
32
|
+
* - **Context-window tracking.** `ChatSession.getContextUsage()` reads
|
|
33
|
+
* `contextWindow` to compute "% of context used".
|
|
34
|
+
* - **Prompt-cache routing.** Anthropic-Claude-family models declare
|
|
35
|
+
* `supportsPromptCache: true`; harnesses use the flag to enable cache
|
|
36
|
+
* write/read on the wire.
|
|
37
|
+
*
|
|
38
|
+
* In-tree subclasses pin `name` to a {@link ModelName} enum member;
|
|
39
|
+
* instances built via {@link createClaudeModel} (the consumer-facing
|
|
40
|
+
* escape hatch for forward-compat with unreleased Bedrock-Claude
|
|
41
|
+
* variants) carry an arbitrary gateway id string.
|
|
42
|
+
*
|
|
43
|
+
* Reference: https://docs.internal.salesforce.com/ai/einstein/gateway/models-and-providers/
|
|
44
|
+
*/
|
|
45
|
+
export class Model {
|
|
46
|
+
permittedParameters;
|
|
47
|
+
/**
|
|
48
|
+
* Vendor-specific HTTP headers to add to every outbound request for this model
|
|
49
|
+
* (e.g. `anthropic-version`, model-tag opt-in headers). Merged with the
|
|
50
|
+
* resolver-built header set before the request is sent.
|
|
51
|
+
*
|
|
52
|
+
* **Reserved headers cannot be overridden.** Both bundled connectivity
|
|
53
|
+
* resolvers (`DefaultAgentConnectivityResolver`, `ApiKeyConnectivityResolver`)
|
|
54
|
+
* spread `customHeaders` FIRST and resolver-set fields last, so any
|
|
55
|
+
* `Authorization`, `Content-Type`, `x-client-feature-id`, `x-sfdc-app-context`,
|
|
56
|
+
* or `x-sfdc-core-tenant-id` keys here are silently shadowed by the
|
|
57
|
+
* resolver's freshly-built values. Use `customHeaders` for vendor labels
|
|
58
|
+
* only — never for auth or tenancy. Custom resolvers should follow the
|
|
59
|
+
* same convention.
|
|
60
|
+
*/
|
|
61
|
+
customHeaders;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Model } from './model.js';
|
|
2
|
+
import type { MultimodalFile } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Maximum total decoded byte size of all `files[]` in one request, across
|
|
5
|
+
* every model. Conservative SDK-side cap: the gateway's own raw-payload
|
|
6
|
+
* cap is ~30 MB which leaves room for envelope (headers, tool defs,
|
|
7
|
+
* prompt text), so 15 MiB of decoded files keeps every request inside
|
|
8
|
+
* the gateway's E30066 ceiling.
|
|
9
|
+
*/
|
|
10
|
+
export declare const MAX_TOTAL_FILE_BYTES: number;
|
|
11
|
+
/**
|
|
12
|
+
* Maximum number of files in one request, across every model. Matches
|
|
13
|
+
* the gateway's E30065 cap.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MAX_FILES_PER_REQUEST = 10;
|
|
16
|
+
/**
|
|
17
|
+
* Pre-flight validation for multimodal `files[]` content. On failure
|
|
18
|
+
* throws {@link AgentSDKError} with type {@link AgentSDKErrorType.MULTIMODAL_NOT_SUPPORTED}
|
|
19
|
+
* and a message describing the specific cap or format violation. The
|
|
20
|
+
* single source of truth for multimodal caps and the MIME allowlist —
|
|
21
|
+
* both harnesses route their pre-stream `MessagePart[]` validation
|
|
22
|
+
* through this so the SDK guarantee "a file is accepted or rejected
|
|
23
|
+
* identically regardless of harness" holds.
|
|
24
|
+
*
|
|
25
|
+
* Fast return for text-only requests (no files).
|
|
26
|
+
*
|
|
27
|
+
* Validation order:
|
|
28
|
+
* 1. Global file count (≤ {@link MAX_FILES_PER_REQUEST}).
|
|
29
|
+
* 2. Per file: the model must declare the format, and the file must
|
|
30
|
+
* fit its per-format byte cap.
|
|
31
|
+
* 3. Global total decoded size (≤ {@link MAX_TOTAL_FILE_BYTES}).
|
|
32
|
+
* 4. Per format: the file count for that format must fit its
|
|
33
|
+
* per-format count cap.
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateMultimodalFiles(files: readonly MultimodalFile[], model: Model): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
import { AgentSDKError, AgentSDKErrorType } from '../errors.js';
|
|
6
|
+
/**
|
|
7
|
+
* Maximum total decoded byte size of all `files[]` in one request, across
|
|
8
|
+
* every model. Conservative SDK-side cap: the gateway's own raw-payload
|
|
9
|
+
* cap is ~30 MB which leaves room for envelope (headers, tool defs,
|
|
10
|
+
* prompt text), so 15 MiB of decoded files keeps every request inside
|
|
11
|
+
* the gateway's E30066 ceiling.
|
|
12
|
+
*/
|
|
13
|
+
export const MAX_TOTAL_FILE_BYTES = 15 * 1024 * 1024;
|
|
14
|
+
/**
|
|
15
|
+
* Maximum number of files in one request, across every model. Matches
|
|
16
|
+
* the gateway's E30065 cap.
|
|
17
|
+
*/
|
|
18
|
+
export const MAX_FILES_PER_REQUEST = 10;
|
|
19
|
+
/**
|
|
20
|
+
* Approximate the decoded byte length of a base64 string without actually
|
|
21
|
+
* decoding. O(1) and within ≤ 2 bytes of the exact length for any
|
|
22
|
+
* well-formed base64. The gateway is the authority on malformed base64.
|
|
23
|
+
*/
|
|
24
|
+
function approximateBase64Bytes(data) {
|
|
25
|
+
return Math.floor(data.length * 0.75);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Pre-flight validation for multimodal `files[]` content. On failure
|
|
29
|
+
* throws {@link AgentSDKError} with type {@link AgentSDKErrorType.MULTIMODAL_NOT_SUPPORTED}
|
|
30
|
+
* and a message describing the specific cap or format violation. The
|
|
31
|
+
* single source of truth for multimodal caps and the MIME allowlist —
|
|
32
|
+
* both harnesses route their pre-stream `MessagePart[]` validation
|
|
33
|
+
* through this so the SDK guarantee "a file is accepted or rejected
|
|
34
|
+
* identically regardless of harness" holds.
|
|
35
|
+
*
|
|
36
|
+
* Fast return for text-only requests (no files).
|
|
37
|
+
*
|
|
38
|
+
* Validation order:
|
|
39
|
+
* 1. Global file count (≤ {@link MAX_FILES_PER_REQUEST}).
|
|
40
|
+
* 2. Per file: the model must declare the format, and the file must
|
|
41
|
+
* fit its per-format byte cap.
|
|
42
|
+
* 3. Global total decoded size (≤ {@link MAX_TOTAL_FILE_BYTES}).
|
|
43
|
+
* 4. Per format: the file count for that format must fit its
|
|
44
|
+
* per-format count cap.
|
|
45
|
+
*/
|
|
46
|
+
export function validateMultimodalFiles(files, model) {
|
|
47
|
+
if (files.length === 0) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (files.length > MAX_FILES_PER_REQUEST) {
|
|
51
|
+
throw new AgentSDKError(`Too many files in request: ${files.length} exceeds the gateway cap of ${MAX_FILES_PER_REQUEST}.`, AgentSDKErrorType.MULTIMODAL_NOT_SUPPORTED);
|
|
52
|
+
}
|
|
53
|
+
let totalBytes = 0;
|
|
54
|
+
for (const file of files) {
|
|
55
|
+
const bytes = approximateBase64Bytes(file.data);
|
|
56
|
+
totalBytes += bytes;
|
|
57
|
+
const format = model.supportedFormats.find((f) => f.mimeType === file.mimeType);
|
|
58
|
+
if (!format) {
|
|
59
|
+
throw new AgentSDKError(`Model ${model.name} does not support files of type "${file.mimeType}".`, AgentSDKErrorType.MULTIMODAL_NOT_SUPPORTED);
|
|
60
|
+
}
|
|
61
|
+
if (format.maxBytesPerFile !== undefined && bytes > format.maxBytesPerFile) {
|
|
62
|
+
throw new AgentSDKError(`File of type "${file.mimeType}" exceeds the per-format cap for model ${model.name}: ${bytes} bytes > ${format.maxBytesPerFile} bytes.`, AgentSDKErrorType.MULTIMODAL_NOT_SUPPORTED);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (totalBytes > MAX_TOTAL_FILE_BYTES) {
|
|
66
|
+
throw new AgentSDKError(`Total file size ${totalBytes} bytes exceeds the gateway cap of ${MAX_TOTAL_FILE_BYTES} bytes.`, AgentSDKErrorType.MULTIMODAL_NOT_SUPPORTED);
|
|
67
|
+
}
|
|
68
|
+
for (const format of model.supportedFormats) {
|
|
69
|
+
if (format.maxFilesPerRequest === undefined) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const count = files.filter((f) => f.mimeType === format.mimeType).length;
|
|
73
|
+
if (count > format.maxFilesPerRequest) {
|
|
74
|
+
throw new AgentSDKError(`Too many files of type "${format.mimeType}" for model ${model.name}: ${count} exceeds the per-format cap of ${format.maxFilesPerRequest}.`, AgentSDKErrorType.MULTIMODAL_NOT_SUPPORTED);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=multimodal.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IANA MIME types accepted on the multimodal path.
|
|
3
|
+
*
|
|
4
|
+
* A file with any other `mimeType` is rejected pre-stream by
|
|
5
|
+
* {@link validateMultimodalFiles}. The set is intentionally narrow —
|
|
6
|
+
* Salesforce gateway-routed models accept these three; consumer-built
|
|
7
|
+
* models via {@link createClaudeModel} can declare any subset.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MimeType: {
|
|
10
|
+
readonly Png: "image/png";
|
|
11
|
+
readonly Jpeg: "image/jpeg";
|
|
12
|
+
readonly Pdf: "application/pdf";
|
|
13
|
+
};
|
|
14
|
+
export type MimeType = (typeof MimeType)[keyof typeof MimeType];
|
|
15
|
+
/**
|
|
16
|
+
* A file format a model accepts, with the per-format limits sourced from
|
|
17
|
+
* the model registry.
|
|
18
|
+
*
|
|
19
|
+
* A model's {@link Model.supportedFormats} array is the single source of
|
|
20
|
+
* truth for which file types it accepts and the per-format caps applied
|
|
21
|
+
* during pre-flight validation. An empty array means the model is
|
|
22
|
+
* text-only.
|
|
23
|
+
*/
|
|
24
|
+
export type SupportedFileFormat = {
|
|
25
|
+
/** Short registry name for the format. */
|
|
26
|
+
name: 'png' | 'jpeg' | 'pdf';
|
|
27
|
+
/** IANA media type sent on the wire as `mimeType`. */
|
|
28
|
+
mimeType: MimeType;
|
|
29
|
+
/**
|
|
30
|
+
* Optional per-format cap on the decoded size of any single file of
|
|
31
|
+
* this format (in bytes). When unset, only the global 15 MiB total
|
|
32
|
+
* cap applies.
|
|
33
|
+
*/
|
|
34
|
+
maxBytesPerFile?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Optional per-format cap on the number of files of this format in
|
|
37
|
+
* one request. When unset, only the global 10-file cap applies.
|
|
38
|
+
*/
|
|
39
|
+
maxFilesPerRequest?: number;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The minimal file shape multimodal validation needs: a MIME type and the
|
|
43
|
+
* base64-encoded bytes. Harness callers (which hold SDK message parts,
|
|
44
|
+
* not full provider request shapes) can satisfy this directly.
|
|
45
|
+
*/
|
|
46
|
+
export type MultimodalFile = {
|
|
47
|
+
mimeType: string;
|
|
48
|
+
data: string;
|
|
49
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* IANA MIME types accepted on the multimodal path.
|
|
7
|
+
*
|
|
8
|
+
* A file with any other `mimeType` is rejected pre-stream by
|
|
9
|
+
* {@link validateMultimodalFiles}. The set is intentionally narrow —
|
|
10
|
+
* Salesforce gateway-routed models accept these three; consumer-built
|
|
11
|
+
* models via {@link createClaudeModel} can declare any subset.
|
|
12
|
+
*/
|
|
13
|
+
export const MimeType = {
|
|
14
|
+
Png: 'image/png',
|
|
15
|
+
Jpeg: 'image/jpeg',
|
|
16
|
+
Pdf: 'application/pdf',
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=types.js.map
|
package/dist/types/index.d.ts
CHANGED
|
@@ -2,3 +2,4 @@ export type { Message, MessageRole, MessagePart, TextPart, ReasoningPart, ToolCa
|
|
|
2
2
|
export type { ChatEvent, StartEvent, TextDeltaEvent, ReasoningDeltaEvent, ToolCallEvent, ToolApprovalRequestEvent, ToolResultEvent, StepStartEvent, StepFinishEvent, ErrorEvent, FinishEvent, ChatStreamResult, } from './events.js';
|
|
3
3
|
export type { ToolDefinition, ToolCallInfo, ToolResultInfo } from './tools.js';
|
|
4
4
|
export type { UsageMetadata, FinishReason } from './usage.js';
|
|
5
|
+
export type { ModelConnectivityInfo, ProviderHint } from './model-connectivity-info.js';
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Model } from '../models/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Wire shape the harness should speak.
|
|
4
|
+
*
|
|
5
|
+
* The literal-union members are the wire shapes the SDK and its bundled
|
|
6
|
+
* harnesses recognize today; the trailing `string` allows forward-compat —
|
|
7
|
+
* a resolver can return a hint for a future provider without a same-day
|
|
8
|
+
* type bump in the SDK. Harnesses that don't recognize the value MUST
|
|
9
|
+
* throw `AgentSDKError(MODEL_NOT_SUPPORTED_BY_HARNESS)` rather than
|
|
10
|
+
* default to a wrong-shape builder.
|
|
11
|
+
*/
|
|
12
|
+
export type ProviderHint =
|
|
13
|
+
/** Anthropic Messages API direct (e.g. api.anthropic.com). */
|
|
14
|
+
'anthropic'
|
|
15
|
+
/** Anthropic Messages API via AWS Bedrock invoke. The Salesforce LLM
|
|
16
|
+
* Gateway's `/invoke-with-response-stream` is this shape. */
|
|
17
|
+
| 'bedrock-anthropic'
|
|
18
|
+
/** OpenAI Responses API direct (api.openai.com). */
|
|
19
|
+
| 'openai'
|
|
20
|
+
/** OpenAI Responses API via the Salesforce LLM Gateway's `/responses`
|
|
21
|
+
* pass-through endpoint. */
|
|
22
|
+
| 'openai-responses'
|
|
23
|
+
/** OpenAI-compatible `/v1/chat/completions` (LLMG-Express, third-party
|
|
24
|
+
* OpenAI-shape gateways). */
|
|
25
|
+
| 'openai-compatible'
|
|
26
|
+
/** Forward-compat tail. Harnesses must validate against
|
|
27
|
+
* `HarnessFactory.supportedProviderHints` and reject unknowns. */
|
|
28
|
+
| (string & {});
|
|
29
|
+
/**
|
|
30
|
+
* The connectivity facts a harness needs to make an LLM request.
|
|
31
|
+
*
|
|
32
|
+
* Returned from {@link AgentConnectivityResolver.resolve} as part of
|
|
33
|
+
* {@link ResolvedConnectivity}. Five fields. Auth-kind branching lives
|
|
34
|
+
* inside `getHeaders()` — the harness never inspects whether the auth is
|
|
35
|
+
* a JWT, an API key, or anything else.
|
|
36
|
+
*
|
|
37
|
+
* The harness reads this bag per stream (Mastra: per HTTP call via a
|
|
38
|
+
* fetch wrapper that closes over a getter; Claude: once per subprocess
|
|
39
|
+
* spawn). Resolvers MUST treat the bag as live: each call to
|
|
40
|
+
* `getHeaders()` produces a fresh header map suitable for the *next*
|
|
41
|
+
* outbound request.
|
|
42
|
+
*/
|
|
43
|
+
export interface ModelConnectivityInfo {
|
|
44
|
+
/**
|
|
45
|
+
* Capability descriptor for the requested model. Used by harnesses
|
|
46
|
+
* for pre-flight multimodal validation (file format, file size,
|
|
47
|
+
* caps) and by the SDK for context-usage reporting.
|
|
48
|
+
*/
|
|
49
|
+
readonly model: Model;
|
|
50
|
+
/**
|
|
51
|
+
* Provider-native or gateway base URL, with no trailing slash and
|
|
52
|
+
* no path beyond the gateway/provider's API root. Harnesses concat
|
|
53
|
+
* the path the wire shape requires.
|
|
54
|
+
*/
|
|
55
|
+
readonly baseUrl: string;
|
|
56
|
+
/**
|
|
57
|
+
* Wire id the provider SDK should set on the request body's
|
|
58
|
+
* `model` field. May differ from `model.name` when the resolver
|
|
59
|
+
* points at a non-gateway endpoint (e.g. Anthropic-direct expects
|
|
60
|
+
* `claude-sonnet-4-6`; Salesforce gateway expects
|
|
61
|
+
* `llmgateway__BedrockAnthropicClaude46Sonnet`).
|
|
62
|
+
*/
|
|
63
|
+
readonly nativeModelId: string;
|
|
64
|
+
/**
|
|
65
|
+
* Wire shape the harness should speak. The manager validates this
|
|
66
|
+
* against the harness's `supportedProviderHints` before any harness
|
|
67
|
+
* work begins; a harness only sees hints it recognizes.
|
|
68
|
+
*/
|
|
69
|
+
readonly providerHint: ProviderHint;
|
|
70
|
+
/**
|
|
71
|
+
* Returns the FULL set of headers (Authorization included) for the
|
|
72
|
+
* NEXT outbound request to `baseUrl`.
|
|
73
|
+
*
|
|
74
|
+
* **Per-call invocation contract.** Mastra harnesses MUST call this
|
|
75
|
+
* on every HTTP call (inside their fetch wrapper). Claude harnesses
|
|
76
|
+
* MUST call this once per subprocess spawn and serialize the result
|
|
77
|
+
* into the env. Caching the returned map across requests is a bug —
|
|
78
|
+
* the resolver re-evaluates rotating credentials (JWT freshness,
|
|
79
|
+
* api-key swap, premium-rate-limit feature-id flip) on every call,
|
|
80
|
+
* and a cached map will go stale silently.
|
|
81
|
+
*
|
|
82
|
+
* Harnesses MUST tolerate `getHeaders` throwing: a thrown error
|
|
83
|
+
* propagates to the caller as a stream-time failure, identical to
|
|
84
|
+
* any other transport error.
|
|
85
|
+
*/
|
|
86
|
+
getHeaders(): Promise<Record<string, string>>;
|
|
87
|
+
}
|
package/dist/types/usage.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ export type UsageMetadata = {
|
|
|
57
57
|
* are all `undefined` — making "no reading yet" indistinguishable from
|
|
58
58
|
* "harness reported every field as undefined."
|
|
59
59
|
* - `contextWindow` is always populated, contractually. Every `Model`
|
|
60
|
-
*
|
|
60
|
+
* bound to an `Agent` via `ModelConnectivityInfo.model` must publish a
|
|
61
61
|
* `contextWindow`; see the `sfdx-agent-sdk` ARCHITECTURE.md Critical
|
|
62
62
|
* Invariant on this and issue #507.
|
|
63
63
|
* - `usedFraction` is `undefined` iff every input-bearing field on the
|
|
@@ -77,8 +77,8 @@ export type ContextUsage = {
|
|
|
77
77
|
usage: UsageMetadata;
|
|
78
78
|
/**
|
|
79
79
|
* The model's total context-window size in tokens. Read live at call
|
|
80
|
-
* time from the agent's currently-bound `
|
|
81
|
-
* correct across `Agent.updateAgentConfig()` model swaps.
|
|
80
|
+
* time from the agent's currently-bound `ModelConnectivityInfo.model`,
|
|
81
|
+
* so it stays correct across `Agent.updateAgentConfig()` model swaps.
|
|
82
82
|
*/
|
|
83
83
|
contextWindow: number;
|
|
84
84
|
/**
|