@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.
Files changed (59) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +12 -11
  3. package/dist/agent-connectivity-resolver.d.ts +47 -25
  4. package/dist/agent-connectivity-resolver.js +92 -15
  5. package/dist/agent-manager.d.ts +17 -1
  6. package/dist/agent-manager.js +40 -7
  7. package/dist/agent.d.ts +33 -10
  8. package/dist/agent.js +38 -50
  9. package/dist/api-key-connectivity-resolver.d.ts +110 -0
  10. package/dist/api-key-connectivity-resolver.js +114 -0
  11. package/dist/errors.d.ts +2 -0
  12. package/dist/errors.js +2 -0
  13. package/dist/harness/agent-harness.d.ts +27 -5
  14. package/dist/harness/harness-bus-owner.d.ts +17 -0
  15. package/dist/harness/harness-bus-owner.js +27 -0
  16. package/dist/harness/harness-config.d.ts +3 -2
  17. package/dist/harness/harness-factory.d.ts +13 -0
  18. package/dist/harness/stream-input.d.ts +9 -5
  19. package/dist/harness/stream-input.js +12 -14
  20. package/dist/index.d.ts +8 -2
  21. package/dist/index.js +4 -1
  22. package/dist/internal/wire-communication-router.d.ts +43 -0
  23. package/dist/internal/wire-communication-router.js +119 -0
  24. package/dist/mcp-auth.d.ts +1 -1
  25. package/dist/models/claude-opus-4-5.d.ts +11 -0
  26. package/dist/models/claude-opus-4-5.js +21 -0
  27. package/dist/models/claude-opus-4-6.d.ts +11 -0
  28. package/dist/models/claude-opus-4-6.js +22 -0
  29. package/dist/models/claude-opus-4-7.d.ts +11 -0
  30. package/dist/models/claude-opus-4-7.js +22 -0
  31. package/dist/models/claude-sonnet-4-5.d.ts +11 -0
  32. package/dist/models/claude-sonnet-4-5.js +23 -0
  33. package/dist/models/claude-sonnet-4-6.d.ts +11 -0
  34. package/dist/models/claude-sonnet-4-6.js +22 -0
  35. package/dist/models/create-claude-model.d.ts +54 -0
  36. package/dist/models/create-claude-model.js +62 -0
  37. package/dist/models/gpt-5-4.d.ts +11 -0
  38. package/dist/models/gpt-5-4.js +21 -0
  39. package/dist/models/gpt-5-5.d.ts +15 -0
  40. package/dist/models/gpt-5-5.js +24 -0
  41. package/dist/models/gpt-5.d.ts +11 -0
  42. package/dist/models/gpt-5.js +23 -0
  43. package/dist/models/index.d.ts +19 -0
  44. package/dist/models/index.js +49 -0
  45. package/dist/models/model.d.ts +69 -0
  46. package/dist/models/model.js +63 -0
  47. package/dist/models/multimodal.d.ts +35 -0
  48. package/dist/models/multimodal.js +78 -0
  49. package/dist/models/types.d.ts +49 -0
  50. package/dist/models/types.js +18 -0
  51. package/dist/types/index.d.ts +1 -0
  52. package/dist/types/model-connectivity-info.d.ts +87 -0
  53. package/dist/types/model-connectivity-info.js +6 -0
  54. package/dist/types/usage.d.ts +3 -3
  55. package/dist/types/wire-communication-event.d.ts +124 -0
  56. package/dist/types/wire-communication-event.js +6 -0
  57. package/dist/wire-communication-file-writer.d.ts +39 -0
  58. package/dist/wire-communication-file-writer.js +142 -0
  59. 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
@@ -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
+ }
@@ -0,0 +1,6 @@
1
+ /*
2
+ * Copyright 2026, Salesforce, Inc. All rights reserved.
3
+ * See LICENSE.txt for license terms.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=model-connectivity-info.js.map
@@ -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
- * reachable via `Agent.llmGatewayClient.getModel()` must publish a
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 `LLMGatewayClient`, so it stays
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
  /**