@deepstrike/sdk 0.2.52 → 0.2.60
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/README.md +28 -28
- package/dist/agent-ir.d.ts +103 -0
- package/dist/agent-ir.js +134 -0
- package/dist/agent.d.ts +67 -0
- package/dist/agent.js +36 -0
- package/dist/collaboration/harness.js +1 -1
- package/dist/collaboration/modes/creator-verifier.d.ts +2 -7
- package/dist/collaboration/modes/creator-verifier.js +4 -6
- package/dist/collaboration/pool.d.ts +8 -20
- package/dist/collaboration/pool.js +27 -97
- package/dist/compat/anthropic/mcp.d.ts +15 -0
- package/dist/compat/anthropic/mcp.js +10 -0
- package/dist/compat/openai/agent.d.ts +34 -0
- package/dist/compat/openai/agent.js +24 -0
- package/dist/governance.d.ts +1 -17
- package/dist/governance.js +1 -34
- package/dist/guardrail.d.ts +6 -0
- package/dist/guardrail.js +1 -0
- package/dist/handoff-target.d.ts +12 -0
- package/dist/handoff-target.js +1 -0
- package/dist/harness/manifest.js +0 -4
- package/dist/index.d.ts +19 -7
- package/dist/index.js +8 -5
- package/dist/kernel.d.ts +2 -20
- package/dist/knowledge/public.d.ts +29 -0
- package/dist/knowledge/public.js +1 -0
- package/dist/mcp-server.d.ts +28 -0
- package/dist/mcp-server.js +1 -0
- package/dist/memory/agent.d.ts +2 -2
- package/dist/memory/agent.js +2 -2
- package/dist/memory/durable.d.ts +16 -0
- package/dist/memory/durable.js +46 -0
- package/dist/memory/in-memory-store.d.ts +9 -7
- package/dist/memory/in-memory-store.js +8 -2
- package/dist/memory/protocols.d.ts +22 -4
- package/dist/memory/public.d.ts +4 -3
- package/dist/memory/public.js +3 -2
- package/dist/providers/anthropic-adapter.d.ts +47 -0
- package/dist/providers/anthropic-adapter.js +444 -0
- package/dist/providers/anthropic-compatible.d.ts +2 -3
- package/dist/providers/anthropic-compatible.js +8 -5
- package/dist/providers/anthropic.d.ts +19 -23
- package/dist/providers/anthropic.js +169 -395
- package/dist/providers/base.js +43 -3
- package/dist/providers/capability-router.d.ts +29 -0
- package/dist/providers/capability-router.js +43 -0
- package/dist/providers/catalog.d.ts +16 -4
- package/dist/providers/catalog.js +112 -21
- package/dist/providers/content-normalization.d.ts +57 -0
- package/dist/providers/content-normalization.js +238 -0
- package/dist/providers/content-policy.d.ts +16 -0
- package/dist/providers/content-policy.js +39 -0
- package/dist/providers/credentials.d.ts +83 -0
- package/dist/providers/credentials.js +190 -0
- package/dist/providers/endpoints.d.ts +137 -0
- package/dist/providers/endpoints.js +128 -0
- package/dist/providers/factories.js +9 -3
- package/dist/providers/gemini-adapter.d.ts +33 -0
- package/dist/providers/gemini-adapter.js +272 -0
- package/dist/providers/gemini.d.ts +16 -3
- package/dist/providers/gemini.js +97 -195
- package/dist/providers/model-catalog.d.ts +37 -0
- package/dist/providers/model-catalog.js +62 -0
- package/dist/providers/model-registry.d.ts +98 -0
- package/dist/providers/model-registry.js +315 -0
- package/dist/providers/ollama-adapter.d.ts +65 -0
- package/dist/providers/ollama-adapter.js +188 -0
- package/dist/providers/ollama.d.ts +9 -4
- package/dist/providers/ollama.js +96 -109
- package/dist/providers/openai-chat-dialects.d.ts +154 -0
- package/dist/providers/openai-chat-dialects.js +179 -0
- package/dist/providers/openai-chat.d.ts +46 -18
- package/dist/providers/openai-chat.js +418 -51
- package/dist/providers/openai-responses-adapter.d.ts +42 -0
- package/dist/providers/openai-responses-adapter.js +341 -0
- package/dist/providers/openai-responses.d.ts +14 -33
- package/dist/providers/openai-responses.js +131 -264
- package/dist/providers/openai.d.ts +29 -76
- package/dist/providers/openai.js +195 -292
- package/dist/providers/protocol-adapter.d.ts +34 -0
- package/dist/providers/protocol-adapter.js +9 -0
- package/dist/providers/protocol-capabilities.d.ts +34 -0
- package/dist/providers/protocol-capabilities.js +44 -0
- package/dist/providers/provider-error.d.ts +31 -0
- package/dist/providers/provider-error.js +149 -0
- package/dist/providers/public.d.ts +26 -3
- package/dist/providers/public.js +13 -1
- package/dist/providers/registry.d.ts +7 -6
- package/dist/providers/registry.js +47 -20
- package/dist/providers/request-plan.d.ts +86 -0
- package/dist/providers/request-plan.js +175 -0
- package/dist/providers/usage-normalizer.d.ts +48 -0
- package/dist/providers/usage-normalizer.js +96 -0
- package/dist/providers/vendor-profiles.d.ts +2 -15
- package/dist/providers/vendor-profiles.js +14 -60
- package/dist/runtime/canonical-kernel-step.d.ts +1 -2
- package/dist/runtime/canonical-kernel-step.js +47 -12
- package/dist/runtime/context-policy.d.ts +10 -12
- package/dist/runtime/context-policy.js +6 -8
- package/dist/runtime/durable-content.d.ts +50 -0
- package/dist/runtime/durable-content.js +159 -0
- package/dist/runtime/execution-plane.d.ts +2 -2
- package/dist/runtime/execution-plane.js +2 -2
- package/dist/runtime/kernel-event-log.js +0 -1
- package/dist/runtime/kernel-step.d.ts +0 -1
- package/dist/runtime/kernel-step.js +4 -2
- package/dist/runtime/mcp-proxy-plane.d.ts +25 -1
- package/dist/runtime/mcp-proxy-plane.js +44 -6
- package/dist/runtime/output-schema.d.ts +1 -2
- package/dist/runtime/provider-replay.d.ts +1 -1
- package/dist/runtime/provider-replay.js +12 -27
- package/dist/runtime/reactive-session.d.ts +1 -1
- package/dist/runtime/reactive-session.js +2 -3
- package/dist/runtime/run-group.d.ts +1 -1
- package/dist/runtime/runner.d.ts +26 -40
- package/dist/runtime/runner.js +145 -63
- package/dist/runtime/session-log.d.ts +8 -1
- package/dist/runtime/session-log.js +42 -2
- package/dist/runtime/session-repair.d.ts +1 -1
- package/dist/runtime/session-repair.js +1 -1
- package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
- package/dist/runtime/sub-agent-orchestrator.js +8 -11
- package/dist/runtime/workflow-control-flow.d.ts +0 -4
- package/dist/runtime/workflow-control-flow.js +0 -16
- package/dist/session.d.ts +11 -0
- package/dist/session.js +1 -0
- package/dist/skill.d.ts +17 -0
- package/dist/skill.js +16 -0
- package/dist/skills/loader.d.ts +3 -0
- package/dist/tools/errors.d.ts +1 -3
- package/dist/tools/errors.js +1 -3
- package/dist/tools/index.d.ts +3 -0
- package/dist/types/agent.d.ts +21 -9
- package/dist/types/agent.js +30 -4
- package/dist/types.d.ts +128 -13
- package/package.json +3 -3
- package/dist/providers/deepseek.d.ts +0 -46
- package/dist/providers/deepseek.js +0 -97
- package/dist/providers/glm.d.ts +0 -25
- package/dist/providers/glm.js +0 -48
- package/dist/providers/kimi.d.ts +0 -23
- package/dist/providers/kimi.js +0 -30
- package/dist/providers/minimax.d.ts +0 -49
- package/dist/providers/minimax.js +0 -98
- package/dist/providers/profiles.d.ts +0 -1992
- package/dist/providers/profiles.js +0 -796
- package/dist/providers/qwen.d.ts +0 -38
- package/dist/providers/qwen.js +0 -97
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const ANTHROPIC_PROTOCOL_CAPABILITIES = {
|
|
2
|
+
acceptedInputModalities: ["text", "image"],
|
|
3
|
+
emittedOutputModalities: ["text"],
|
|
4
|
+
tools: true,
|
|
5
|
+
parallelToolCalls: true,
|
|
6
|
+
structuredOutput: false,
|
|
7
|
+
reasoningReplay: "required",
|
|
8
|
+
promptCaching: true,
|
|
9
|
+
mediaForms: { imageUrl: true, imageBase64: true },
|
|
10
|
+
};
|
|
11
|
+
export const GEMINI_PROTOCOL_CAPABILITIES = {
|
|
12
|
+
acceptedInputModalities: ["text", "image", "audio"],
|
|
13
|
+
emittedOutputModalities: ["text"],
|
|
14
|
+
tools: true,
|
|
15
|
+
reasoningReplay: "none",
|
|
16
|
+
mediaForms: { imageUrl: true, imageBase64: true, audioBase64: true },
|
|
17
|
+
};
|
|
18
|
+
export const OLLAMA_PROTOCOL_CAPABILITIES = {
|
|
19
|
+
acceptedInputModalities: ["text", "image"],
|
|
20
|
+
emittedOutputModalities: ["text"],
|
|
21
|
+
tools: true,
|
|
22
|
+
reasoningReplay: "none",
|
|
23
|
+
mediaForms: { imageBase64: true },
|
|
24
|
+
};
|
|
25
|
+
export const OPENAI_RESPONSES_PROTOCOL_CAPABILITIES = {
|
|
26
|
+
acceptedInputModalities: ["text", "image", "file"],
|
|
27
|
+
emittedOutputModalities: ["text"],
|
|
28
|
+
tools: true,
|
|
29
|
+
parallelToolCalls: true,
|
|
30
|
+
structuredOutput: true,
|
|
31
|
+
reasoningReplay: "optional",
|
|
32
|
+
promptCaching: true,
|
|
33
|
+
mediaForms: { imageUrl: true, imageBase64: true, fileId: true },
|
|
34
|
+
};
|
|
35
|
+
export const OPENAI_CHAT_PROTOCOL_CAPABILITIES = {
|
|
36
|
+
acceptedInputModalities: ["text", "image", "audio"],
|
|
37
|
+
emittedOutputModalities: ["text"],
|
|
38
|
+
tools: true,
|
|
39
|
+
parallelToolCalls: true,
|
|
40
|
+
structuredOutput: true,
|
|
41
|
+
reasoningReplay: "optional",
|
|
42
|
+
promptCaching: true,
|
|
43
|
+
mediaForms: { imageUrl: true, imageBase64: true, audioBase64: true },
|
|
44
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type ProviderErrorKind = "transport" | "auth" | "rate_limit" | "context_overflow" | "invalid_request" | "modality" | "model_unavailable" | "protocol" | "unknown";
|
|
2
|
+
export interface ProviderErrorOptions {
|
|
3
|
+
provider: string;
|
|
4
|
+
kind: ProviderErrorKind;
|
|
5
|
+
retryable: boolean;
|
|
6
|
+
message: string;
|
|
7
|
+
httpStatus?: number;
|
|
8
|
+
providerCode?: string;
|
|
9
|
+
cause?: unknown;
|
|
10
|
+
}
|
|
11
|
+
/** Stable provider-failure contract. Only the named scalar fields cross the host ABI. */
|
|
12
|
+
export declare class ProviderError extends Error {
|
|
13
|
+
readonly provider: string;
|
|
14
|
+
readonly kind: ProviderErrorKind;
|
|
15
|
+
readonly retryable: boolean;
|
|
16
|
+
readonly httpStatus?: number;
|
|
17
|
+
readonly providerCode?: string;
|
|
18
|
+
readonly cause: unknown;
|
|
19
|
+
constructor(options: ProviderErrorOptions);
|
|
20
|
+
}
|
|
21
|
+
export declare function classifyProviderError(provider: string, error: unknown): ProviderError;
|
|
22
|
+
export declare function circuitOpenError(provider: string): ProviderError;
|
|
23
|
+
/** Safe scalar projection for runner → canonical-host events. */
|
|
24
|
+
export declare function providerErrorEventFields(error: unknown): {
|
|
25
|
+
error_kind?: ProviderErrorKind;
|
|
26
|
+
retryable?: boolean;
|
|
27
|
+
http_status?: number;
|
|
28
|
+
provider_code?: string;
|
|
29
|
+
};
|
|
30
|
+
/** Provider errors expose their stable message without serializing the retained SDK cause. */
|
|
31
|
+
export declare function providerErrorMessage(error: unknown, fallback: (value: unknown) => string): string;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/** Stable provider-failure contract. Only the named scalar fields cross the host ABI. */
|
|
2
|
+
export class ProviderError extends Error {
|
|
3
|
+
provider;
|
|
4
|
+
kind;
|
|
5
|
+
retryable;
|
|
6
|
+
httpStatus;
|
|
7
|
+
providerCode;
|
|
8
|
+
cause;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options.message, options.cause === undefined ? undefined : { cause: options.cause });
|
|
11
|
+
this.name = "ProviderError";
|
|
12
|
+
this.provider = options.provider;
|
|
13
|
+
this.kind = options.kind;
|
|
14
|
+
this.retryable = options.retryable;
|
|
15
|
+
this.httpStatus = options.httpStatus;
|
|
16
|
+
this.providerCode = options.providerCode;
|
|
17
|
+
this.cause = options.cause;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const CONTEXT_OVERFLOW_CODES = new Set([
|
|
21
|
+
"context_length_exceeded",
|
|
22
|
+
"prompt_too_long",
|
|
23
|
+
]);
|
|
24
|
+
const NETWORK_CODES = new Set([
|
|
25
|
+
"ECONNABORTED",
|
|
26
|
+
"ECONNREFUSED",
|
|
27
|
+
"ECONNRESET",
|
|
28
|
+
"EHOSTUNREACH",
|
|
29
|
+
"ENETUNREACH",
|
|
30
|
+
"ETIMEDOUT",
|
|
31
|
+
]);
|
|
32
|
+
function object(value) {
|
|
33
|
+
return value && typeof value === "object" ? value : undefined;
|
|
34
|
+
}
|
|
35
|
+
function scalarString(value) {
|
|
36
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
37
|
+
}
|
|
38
|
+
function scalarStatus(value) {
|
|
39
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599
|
|
40
|
+
? value
|
|
41
|
+
: undefined;
|
|
42
|
+
}
|
|
43
|
+
function errorStatus(error) {
|
|
44
|
+
const outer = object(error);
|
|
45
|
+
const response = object(outer?.response);
|
|
46
|
+
return scalarStatus(outer?.httpStatus)
|
|
47
|
+
?? scalarStatus(outer?.status)
|
|
48
|
+
?? scalarStatus(response?.status);
|
|
49
|
+
}
|
|
50
|
+
function errorCode(error) {
|
|
51
|
+
const outer = object(error);
|
|
52
|
+
const nested = object(outer?.error);
|
|
53
|
+
const nestedError = object(nested?.error);
|
|
54
|
+
const body = object(outer?.body);
|
|
55
|
+
const bodyError = object(body?.error);
|
|
56
|
+
return scalarString(outer?.providerCode)
|
|
57
|
+
?? scalarString(outer?.code)
|
|
58
|
+
?? scalarString(outer?.error_code)
|
|
59
|
+
?? scalarString(nested?.code)
|
|
60
|
+
?? scalarString(nested?.error_code)
|
|
61
|
+
?? scalarString(nestedError?.code)
|
|
62
|
+
?? scalarString(nestedError?.error_code)
|
|
63
|
+
?? scalarString(nestedError?.type)
|
|
64
|
+
?? scalarString(bodyError?.code)
|
|
65
|
+
?? scalarString(bodyError?.error_code);
|
|
66
|
+
}
|
|
67
|
+
function errorMessage(error) {
|
|
68
|
+
if (error instanceof Error && error.message)
|
|
69
|
+
return error.message;
|
|
70
|
+
return typeof error === "string" ? error : "Provider request failed";
|
|
71
|
+
}
|
|
72
|
+
function classifyKind(error, status, code) {
|
|
73
|
+
if (status === 413 || (code && CONTEXT_OVERFLOW_CODES.has(code.toLowerCase())))
|
|
74
|
+
return "context_overflow";
|
|
75
|
+
const name = error instanceof Error ? error.name : scalarString(object(error)?.name);
|
|
76
|
+
if (name === "UnsupportedModalityError")
|
|
77
|
+
return "modality";
|
|
78
|
+
if (name === "ProtocolResponseError")
|
|
79
|
+
return "protocol";
|
|
80
|
+
if (name === "ContentValidationError" || name === "ProviderReplayValidationError") {
|
|
81
|
+
return "invalid_request";
|
|
82
|
+
}
|
|
83
|
+
if (name === "APIConnectionError" || name === "APIConnectionTimeoutError")
|
|
84
|
+
return "transport";
|
|
85
|
+
if (status === 401 || status === 403)
|
|
86
|
+
return "auth";
|
|
87
|
+
if (status === 429)
|
|
88
|
+
return "rate_limit";
|
|
89
|
+
if (code === "model_not_found" || status === 404 || (status !== undefined && status >= 500)) {
|
|
90
|
+
return "model_unavailable";
|
|
91
|
+
}
|
|
92
|
+
if (status === 408 || status === 409)
|
|
93
|
+
return "transport";
|
|
94
|
+
if (status === 400 || status === 422)
|
|
95
|
+
return "invalid_request";
|
|
96
|
+
const normalizedCode = code?.toUpperCase();
|
|
97
|
+
if (normalizedCode && NETWORK_CODES.has(normalizedCode))
|
|
98
|
+
return "transport";
|
|
99
|
+
if (error instanceof TypeError && status === undefined)
|
|
100
|
+
return "transport";
|
|
101
|
+
return "unknown";
|
|
102
|
+
}
|
|
103
|
+
function retryable(kind, status) {
|
|
104
|
+
if (kind === "transport" || kind === "rate_limit" || kind === "model_unavailable")
|
|
105
|
+
return true;
|
|
106
|
+
if (kind === "unknown" && status !== undefined)
|
|
107
|
+
return status >= 500 && status !== 501;
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
export function classifyProviderError(provider, error) {
|
|
111
|
+
if (error instanceof ProviderError)
|
|
112
|
+
return error;
|
|
113
|
+
const httpStatus = errorStatus(error);
|
|
114
|
+
const providerCode = errorCode(error);
|
|
115
|
+
const kind = classifyKind(error, httpStatus, providerCode);
|
|
116
|
+
return new ProviderError({
|
|
117
|
+
provider,
|
|
118
|
+
kind,
|
|
119
|
+
retryable: retryable(kind, httpStatus),
|
|
120
|
+
message: errorMessage(error),
|
|
121
|
+
...(httpStatus !== undefined ? { httpStatus } : {}),
|
|
122
|
+
...(providerCode !== undefined ? { providerCode } : {}),
|
|
123
|
+
cause: error,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
export function circuitOpenError(provider) {
|
|
127
|
+
return new ProviderError({
|
|
128
|
+
provider,
|
|
129
|
+
kind: "model_unavailable",
|
|
130
|
+
retryable: true,
|
|
131
|
+
providerCode: "circuit_open",
|
|
132
|
+
message: "Circuit breaker open",
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/** Safe scalar projection for runner → canonical-host events. */
|
|
136
|
+
export function providerErrorEventFields(error) {
|
|
137
|
+
if (!(error instanceof ProviderError))
|
|
138
|
+
return {};
|
|
139
|
+
return {
|
|
140
|
+
error_kind: error.kind,
|
|
141
|
+
retryable: error.retryable,
|
|
142
|
+
...(error.httpStatus !== undefined ? { http_status: error.httpStatus } : {}),
|
|
143
|
+
...(error.providerCode !== undefined ? { provider_code: error.providerCode } : {}),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/** Provider errors expose their stable message without serializing the retained SDK cause. */
|
|
147
|
+
export function providerErrorMessage(error, fallback) {
|
|
148
|
+
return error instanceof ProviderError ? error.message : fallback(error);
|
|
149
|
+
}
|
|
@@ -3,8 +3,31 @@ export type { BackendProviderOptions } from "./factories.js";
|
|
|
3
3
|
export { OpenAIChatProvider } from "./openai.js";
|
|
4
4
|
export { CircuitBreaker } from "./base.js";
|
|
5
5
|
export { OpenAIResponsesAdapter } from "./openai-responses.js";
|
|
6
|
-
export type { OpenAIResponsesRunState } from "./openai-responses.js";
|
|
6
|
+
export type { OpenAIResponsesRequestPlan, OpenAIResponsesRunState, OpenAIResponsesStreamState, } from "./openai-responses.js";
|
|
7
7
|
export { OpenAIChatAdapter } from "./openai-chat.js";
|
|
8
|
-
export {
|
|
9
|
-
export type {
|
|
8
|
+
export { openAIChatDialects } from "./openai-chat-dialects.js";
|
|
9
|
+
export type { OpenAIChatDialectId, OpenAIChatWireDialect } from "./openai-chat-dialects.js";
|
|
10
|
+
export { GeminiAdapter } from "./gemini-adapter.js";
|
|
11
|
+
export { OllamaAdapter, OllamaNdjsonDecoder } from "./ollama-adapter.js";
|
|
12
|
+
export type { GeminiRequestPlan, GeminiStreamState, } from "./gemini-adapter.js";
|
|
13
|
+
export { ProtocolResponseError } from "./protocol-adapter.js";
|
|
14
|
+
export { ProviderError, classifyProviderError, } from "./provider-error.js";
|
|
15
|
+
export type { ProviderErrorKind, ProviderErrorOptions } from "./provider-error.js";
|
|
16
|
+
export type { AdapterDecodeInput, AdapterOutput, AdapterStreamInput, CanonicalStopReason, ProtocolAdapter, } from "./protocol-adapter.js";
|
|
17
|
+
export { endpointProfiles } from "./endpoints.js";
|
|
18
|
+
export type { EndpointProfile, EndpointProfileId, EndpointProtocol, ProviderId } from "./endpoints.js";
|
|
19
|
+
export { ContentPolicyError, contentDispositionFor } from "./content-policy.js";
|
|
20
|
+
export type { ContentDisposition, ContentPlacement } from "./content-policy.js";
|
|
21
|
+
export { CapabilityRouter } from "./capability-router.js";
|
|
22
|
+
export type { CapabilityRequirement, CapabilityRouteResult } from "./capability-router.js";
|
|
23
|
+
export { createProviderRequestPlan, createProviderRequestPlanForProvider, estimateProviderPromptTokens, measurementForPlan, normalizeProviderUsage, priceProviderUsage, recordPromptMeasurement } from "./request-plan.js";
|
|
24
|
+
export type { CostObservation, NormalizedProviderUsage, PricingSnapshot, ProviderRequestEndpoint, ProviderRequestPlan, RecordedPromptMeasurement } from "./request-plan.js";
|
|
25
|
+
export { CredentialResolutionError, OAuthCredentialResolver, redactCredential, resolveCredential } from "./credentials.js";
|
|
26
|
+
export type { CredentialOptions, CredentialRequest, CredentialResolver, OAuthAccessToken, OAuthCredentialResolverOptions, OAuthRefreshRequest, ProviderCredential, } from "./credentials.js";
|
|
27
|
+
export { DynamicModelCatalog, StaticModelCatalog } from "./model-catalog.js";
|
|
28
|
+
export type { ModelCatalog, ModelCatalogRefreshResult, ModelCatalogSource } from "./model-catalog.js";
|
|
29
|
+
export { modelRegistry, resolveEffectiveCapability } from "./model-registry.js";
|
|
30
|
+
export { ContentValidationError, ToolResultProjectionConflictError, normalizeCanonicalContext, normalizeCanonicalAdapterInput, normalizeToolResultPart, projectToolOutputToText, validateCanonicalAdapterInput, } from "./content-normalization.js";
|
|
31
|
+
export type { CanonicalAdapterInput, CanonicalMessage, CanonicalMessageBlock, CanonicalRenderedContext, CanonicalToolResult, } from "./content-normalization.js";
|
|
32
|
+
export type { CapabilityState, EffectiveCapability, EffectiveModelCapabilities, GenerationProtocol, ModelDescriptor, ModelKind, ModelRegistration, ResolvedProviderRuntime, } from "./model-registry.js";
|
|
10
33
|
export type { ProviderRunState, ProviderToolSpec, ProviderReplay, RenderedContext, CacheBreakpointStrategy } from "../types.js";
|
package/dist/providers/public.js
CHANGED
|
@@ -8,4 +8,16 @@ export { OpenAIChatProvider } from "./openai.js";
|
|
|
8
8
|
export { CircuitBreaker } from "./base.js";
|
|
9
9
|
export { OpenAIResponsesAdapter } from "./openai-responses.js";
|
|
10
10
|
export { OpenAIChatAdapter } from "./openai-chat.js";
|
|
11
|
-
export {
|
|
11
|
+
export { openAIChatDialects } from "./openai-chat-dialects.js";
|
|
12
|
+
export { GeminiAdapter } from "./gemini-adapter.js";
|
|
13
|
+
export { OllamaAdapter, OllamaNdjsonDecoder } from "./ollama-adapter.js";
|
|
14
|
+
export { ProtocolResponseError } from "./protocol-adapter.js";
|
|
15
|
+
export { ProviderError, classifyProviderError, } from "./provider-error.js";
|
|
16
|
+
export { endpointProfiles } from "./endpoints.js";
|
|
17
|
+
export { ContentPolicyError, contentDispositionFor } from "./content-policy.js";
|
|
18
|
+
export { CapabilityRouter } from "./capability-router.js";
|
|
19
|
+
export { createProviderRequestPlan, createProviderRequestPlanForProvider, estimateProviderPromptTokens, measurementForPlan, normalizeProviderUsage, priceProviderUsage, recordPromptMeasurement } from "./request-plan.js";
|
|
20
|
+
export { CredentialResolutionError, OAuthCredentialResolver, redactCredential, resolveCredential } from "./credentials.js";
|
|
21
|
+
export { DynamicModelCatalog, StaticModelCatalog } from "./model-catalog.js";
|
|
22
|
+
export { modelRegistry, resolveEffectiveCapability } from "./model-registry.js";
|
|
23
|
+
export { ContentValidationError, ToolResultProjectionConflictError, normalizeCanonicalContext, normalizeCanonicalAdapterInput, normalizeToolResultPart, projectToolOutputToText, validateCanonicalAdapterInput, } from "./content-normalization.js";
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import type { LLMProvider } from "../types.js";
|
|
1
|
+
import type { LLMProvider, RuntimePolicy } from "../types.js";
|
|
2
|
+
import type { EndpointProtocol, ProviderId } from "./endpoints.js";
|
|
2
3
|
export type ProviderRetry = {
|
|
3
4
|
maxRetries: number;
|
|
4
5
|
baseDelay: number;
|
|
5
6
|
};
|
|
6
|
-
/** Constructs a provider for one `(providerId, endpointProtocol)` pair.
|
|
7
|
-
|
|
8
|
-
* object, the rest take a positional `baseURL` string). */
|
|
9
|
-
export type ProviderMaker = (apiKey: string, model: string | undefined, retry: ProviderRetry | undefined, baseURL: string | undefined) => LLMProvider;
|
|
7
|
+
/** Constructs a provider for one `(providerId, endpointProtocol)` pair. */
|
|
8
|
+
export type ProviderMaker = (apiKey: string, model: string | undefined, retry: ProviderRetry | undefined, baseURL: string | undefined, runtimePolicy: RuntimePolicy | undefined, authMode?: "api_key" | "bearer") => LLMProvider;
|
|
10
9
|
/** Build the registry key for a `(providerId, endpointProtocol)` pair. */
|
|
11
10
|
export declare function providerRegistryKey(providerId: string, protocol: string): string;
|
|
11
|
+
/** OAuth bearer is opt-in per provider/protocol. Compatible endpoints do not inherit this policy. */
|
|
12
|
+
export declare function supportsBearerCredential(providerId: ProviderId, protocol: EndpointProtocol): boolean;
|
|
12
13
|
/**
|
|
13
14
|
* Single source of truth for which provider class backs each `(vendor, wire)` pair. Consumed by
|
|
14
15
|
* both `createProvider` (catalog) and the per-backend factory functions, so the two can no longer
|
|
15
16
|
* drift. Adding a vendor/wire = add a row here (+ its `vendor-profiles` / `endpointProfiles` data) —
|
|
16
|
-
* no dispatch branch to edit.
|
|
17
|
+
* no dispatch branch to edit. Compatible rows are generated from dialect/profile data.
|
|
17
18
|
*/
|
|
18
19
|
export declare const PROVIDER_REGISTRY: Record<string, ProviderMaker>;
|
|
@@ -1,35 +1,62 @@
|
|
|
1
1
|
import { AnthropicProvider } from "./anthropic.js";
|
|
2
2
|
import { OpenAIChatProvider } from "./openai.js";
|
|
3
3
|
import { OpenAIResponsesProvider } from "./openai-responses.js";
|
|
4
|
-
import {
|
|
5
|
-
import { KimiProvider, KimiAnthropicProvider } from "./kimi.js";
|
|
6
|
-
import { QwenProvider, QwenAnthropicProvider } from "./qwen.js";
|
|
7
|
-
import { GLMProvider, GLMAnthropicProvider } from "./glm.js";
|
|
8
|
-
import { MiniMaxOpenAIProvider, MiniMaxAnthropicProvider } from "./minimax.js";
|
|
4
|
+
import { AnthropicCompatibleProvider } from "./anthropic-compatible.js";
|
|
9
5
|
import { GeminiProvider } from "./gemini.js";
|
|
6
|
+
import { OllamaProvider } from "./ollama.js";
|
|
7
|
+
import { openAIChatDialects } from "./openai-chat-dialects.js";
|
|
8
|
+
import { endpointProfiles } from "./endpoints.js";
|
|
9
|
+
import { anthropicVendorProfiles } from "./vendor-profiles.js";
|
|
10
10
|
/** Build the registry key for a `(providerId, endpointProtocol)` pair. */
|
|
11
11
|
export function providerRegistryKey(providerId, protocol) {
|
|
12
12
|
return `${providerId}:${protocol}`;
|
|
13
13
|
}
|
|
14
|
+
/** OAuth bearer is opt-in per provider/protocol. Compatible endpoints do not inherit this policy. */
|
|
15
|
+
export function supportsBearerCredential(providerId, protocol) {
|
|
16
|
+
return (providerId === "openai" && (protocol === "openai-chat" || protocol === "openai-responses"))
|
|
17
|
+
|| (providerId === "anthropic" && protocol === "anthropic-messages");
|
|
18
|
+
}
|
|
19
|
+
function openAIChatMaker(dialectId) {
|
|
20
|
+
const dialect = openAIChatDialects[dialectId];
|
|
21
|
+
return (apiKey, model, retry, baseURL, runtimePolicy, authMode) => new OpenAIChatProvider({
|
|
22
|
+
apiKey,
|
|
23
|
+
model,
|
|
24
|
+
retry,
|
|
25
|
+
baseURL: baseURL ?? endpointProfiles[dialect.endpointId].baseURL,
|
|
26
|
+
runtimePolicy,
|
|
27
|
+
dialect,
|
|
28
|
+
authMode,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const openAIChatRegistry = Object.fromEntries(Object.values(openAIChatDialects).map(dialect => [
|
|
32
|
+
providerRegistryKey(dialect.providerId, "openai-chat"),
|
|
33
|
+
openAIChatMaker(dialect.id),
|
|
34
|
+
]));
|
|
35
|
+
function anthropicCompatibleMaker(vendorId) {
|
|
36
|
+
return (apiKey, model, retry, baseURL, runtimePolicy) => new AnthropicCompatibleProvider(anthropicVendorProfiles[vendorId], apiKey, model, retry, baseURL, runtimePolicy);
|
|
37
|
+
}
|
|
14
38
|
/**
|
|
15
39
|
* Single source of truth for which provider class backs each `(vendor, wire)` pair. Consumed by
|
|
16
40
|
* both `createProvider` (catalog) and the per-backend factory functions, so the two can no longer
|
|
17
41
|
* drift. Adding a vendor/wire = add a row here (+ its `vendor-profiles` / `endpointProfiles` data) —
|
|
18
|
-
* no dispatch branch to edit.
|
|
42
|
+
* no dispatch branch to edit. Compatible rows are generated from dialect/profile data.
|
|
19
43
|
*/
|
|
20
44
|
export const PROVIDER_REGISTRY = {
|
|
21
|
-
"anthropic:anthropic-messages": (k, m, r, b) => new AnthropicProvider(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
45
|
+
"anthropic:anthropic-messages": (k, m, r, b, p, authMode) => new AnthropicProvider({
|
|
46
|
+
apiKey: k,
|
|
47
|
+
model: m,
|
|
48
|
+
retry: r,
|
|
49
|
+
baseURL: b,
|
|
50
|
+
...(p ? { runtimePolicy: p } : {}),
|
|
51
|
+
...(authMode === "bearer" ? { authMode: "bearer" } : {}),
|
|
52
|
+
}),
|
|
53
|
+
"openai:openai-responses": (k, m, r, b, p, authMode) => new OpenAIResponsesProvider(k, m, r, b, p, authMode),
|
|
54
|
+
"deepseek:anthropic-messages": anthropicCompatibleMaker("deepseek"),
|
|
55
|
+
"kimi:anthropic-messages": anthropicCompatibleMaker("kimi"),
|
|
56
|
+
"qwen:anthropic-messages": anthropicCompatibleMaker("qwen"),
|
|
57
|
+
"glm:anthropic-messages": anthropicCompatibleMaker("glm"),
|
|
58
|
+
"minimax:anthropic-messages": anthropicCompatibleMaker("minimax"),
|
|
59
|
+
"gemini:gemini": (k, m, r, b, p) => new GeminiProvider(k, m, r, b, p),
|
|
60
|
+
"ollama:ollama-chat": (_k, m, _r, b, p) => new OllamaProvider(m, b, p),
|
|
61
|
+
...openAIChatRegistry,
|
|
35
62
|
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { RenderedContext, ToolSchema, ProviderUsage } from "../types.js";
|
|
2
|
+
export interface ProviderRequestEndpoint {
|
|
3
|
+
id: string;
|
|
4
|
+
protocol: string;
|
|
5
|
+
baseURL: string;
|
|
6
|
+
}
|
|
7
|
+
/** One provider-visible request, deliberately excluding credentials and transport-only retries. */
|
|
8
|
+
export interface ProviderRequestPlan {
|
|
9
|
+
providerId: string;
|
|
10
|
+
modelId: string;
|
|
11
|
+
endpoint: ProviderRequestEndpoint;
|
|
12
|
+
context: RenderedContext;
|
|
13
|
+
tools: ToolSchema[];
|
|
14
|
+
options: Record<string, unknown>;
|
|
15
|
+
fingerprint: string;
|
|
16
|
+
}
|
|
17
|
+
export interface NormalizedProviderUsage extends ProviderUsage {
|
|
18
|
+
/** Input not accounted as a cache read or write. `inputTokens` remains the full footprint. */
|
|
19
|
+
uncachedInputTokens: number;
|
|
20
|
+
}
|
|
21
|
+
/** Durable host fact: a specific logical request was counted before execution. */
|
|
22
|
+
export interface RecordedPromptMeasurement {
|
|
23
|
+
requestFingerprint: string;
|
|
24
|
+
inputTokens: number;
|
|
25
|
+
source: {
|
|
26
|
+
kind: "native";
|
|
27
|
+
provider: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "local_exact";
|
|
30
|
+
tokenizer: string;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "heuristic";
|
|
33
|
+
};
|
|
34
|
+
confidence: "exact" | "high_confidence" | "low_confidence";
|
|
35
|
+
}
|
|
36
|
+
export interface PricingSnapshot {
|
|
37
|
+
version: string;
|
|
38
|
+
currency: string;
|
|
39
|
+
region: string;
|
|
40
|
+
effectiveFrom: string;
|
|
41
|
+
expiresAt?: string;
|
|
42
|
+
ratesPerMillion: {
|
|
43
|
+
input: number;
|
|
44
|
+
output: number;
|
|
45
|
+
cacheRead?: number;
|
|
46
|
+
cacheCreation?: number;
|
|
47
|
+
reasoning?: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export type CostObservation = {
|
|
51
|
+
source: "snapshot";
|
|
52
|
+
currency: string;
|
|
53
|
+
amount: number;
|
|
54
|
+
pricingVersion: string;
|
|
55
|
+
} | {
|
|
56
|
+
source: "unpriced";
|
|
57
|
+
reason: "pricing_snapshot_not_effective" | "pricing_snapshot_expired" | "invalid_pricing_snapshot";
|
|
58
|
+
};
|
|
59
|
+
export declare function createProviderRequestPlan(input: Omit<ProviderRequestPlan, "fingerprint" | "options"> & {
|
|
60
|
+
options?: Record<string, unknown>;
|
|
61
|
+
}): ProviderRequestPlan;
|
|
62
|
+
/** Build the plan from a resolved provider when the runner only has the public provider object. */
|
|
63
|
+
export declare function createProviderRequestPlanForProvider(provider: {
|
|
64
|
+
descriptor?(): {
|
|
65
|
+
provider: string;
|
|
66
|
+
protocol: string;
|
|
67
|
+
model: string;
|
|
68
|
+
};
|
|
69
|
+
requestPlanIdentity?(): {
|
|
70
|
+
providerId?: string;
|
|
71
|
+
modelId?: string;
|
|
72
|
+
endpoint?: {
|
|
73
|
+
id?: string;
|
|
74
|
+
protocol?: string;
|
|
75
|
+
baseURL?: string;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
}, context: RenderedContext, tools: ToolSchema[], options?: Record<string, unknown>): ProviderRequestPlan;
|
|
79
|
+
export declare function estimateProviderPromptTokens(context: RenderedContext, tools: ToolSchema[]): number;
|
|
80
|
+
/** Bind a preflight count to its exact provider-visible request. Replay only reuses matching facts. */
|
|
81
|
+
export declare function recordPromptMeasurement(plan: Pick<ProviderRequestPlan, "fingerprint">, measurement: Omit<RecordedPromptMeasurement, "requestFingerprint">): RecordedPromptMeasurement;
|
|
82
|
+
export declare function measurementForPlan(plan: Pick<ProviderRequestPlan, "fingerprint">, recorded: RecordedPromptMeasurement | undefined): RecordedPromptMeasurement | undefined;
|
|
83
|
+
/** Normalize postflight provider facts without turning estimates into actual usage. */
|
|
84
|
+
export declare function normalizeProviderUsage(usage: ProviderUsage): NormalizedProviderUsage;
|
|
85
|
+
/** Cost is derived only from an explicit, time-valid host snapshot; otherwise it stays unknown. */
|
|
86
|
+
export declare function priceProviderUsage(usage: NormalizedProviderUsage, snapshot: PricingSnapshot, observedAt?: string | Date): CostObservation;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
const TRANSPORT_ONLY_KEYS = new Set([
|
|
3
|
+
"apiKey", "api_key", "bearerToken", "bearer_token", "authorization", "credential",
|
|
4
|
+
"credentials", "retry", "maxRetries", "baseDelay", "timeout", "signal", "access_token", "refresh_token", "token", "secret", "x-api-key",
|
|
5
|
+
]);
|
|
6
|
+
export function createProviderRequestPlan(input) {
|
|
7
|
+
const options = materialOptions(input.options ?? {});
|
|
8
|
+
const plan = {
|
|
9
|
+
providerId: input.providerId,
|
|
10
|
+
modelId: input.modelId,
|
|
11
|
+
endpoint: sanitizeEndpoint(input.endpoint),
|
|
12
|
+
context: clone(input.context),
|
|
13
|
+
tools: clone(input.tools),
|
|
14
|
+
options,
|
|
15
|
+
};
|
|
16
|
+
return { ...plan, fingerprint: sha256(stableJson(plan)) };
|
|
17
|
+
}
|
|
18
|
+
/** Build the plan from a resolved provider when the runner only has the public provider object. */
|
|
19
|
+
export function createProviderRequestPlanForProvider(provider, context, tools, options) {
|
|
20
|
+
const descriptor = provider.descriptor?.() ?? { provider: "unknown", protocol: "unknown", model: "unknown" };
|
|
21
|
+
const identity = provider.requestPlanIdentity?.();
|
|
22
|
+
return createProviderRequestPlan({
|
|
23
|
+
providerId: identity?.providerId ?? descriptor.provider,
|
|
24
|
+
modelId: identity?.modelId ?? descriptor.model,
|
|
25
|
+
endpoint: {
|
|
26
|
+
id: identity?.endpoint?.id ?? `${descriptor.provider}.${descriptor.protocol}`,
|
|
27
|
+
protocol: identity?.endpoint?.protocol ?? descriptor.protocol,
|
|
28
|
+
baseURL: identity?.endpoint?.baseURL ?? "",
|
|
29
|
+
},
|
|
30
|
+
context,
|
|
31
|
+
tools,
|
|
32
|
+
options,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export function estimateProviderPromptTokens(context, tools) {
|
|
36
|
+
const bytes = new TextEncoder().encode(stableJson({ context, tools })).byteLength;
|
|
37
|
+
return Math.max(1, Math.ceil(bytes / 4));
|
|
38
|
+
}
|
|
39
|
+
/** Bind a preflight count to its exact provider-visible request. Replay only reuses matching facts. */
|
|
40
|
+
export function recordPromptMeasurement(plan, measurement) {
|
|
41
|
+
return {
|
|
42
|
+
requestFingerprint: plan.fingerprint,
|
|
43
|
+
inputTokens: requireNonNegativeInteger(measurement.inputTokens, "inputTokens"),
|
|
44
|
+
source: clone(measurement.source),
|
|
45
|
+
confidence: measurement.confidence,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function measurementForPlan(plan, recorded) {
|
|
49
|
+
if (!recorded || recorded.requestFingerprint !== plan.fingerprint)
|
|
50
|
+
return undefined;
|
|
51
|
+
if (!Number.isSafeInteger(recorded.inputTokens) || recorded.inputTokens < 0)
|
|
52
|
+
return undefined;
|
|
53
|
+
if (recorded.confidence !== "exact" && recorded.confidence !== "high_confidence" && recorded.confidence !== "low_confidence")
|
|
54
|
+
return undefined;
|
|
55
|
+
const source = recorded.source;
|
|
56
|
+
if (!source || typeof source !== "object")
|
|
57
|
+
return undefined;
|
|
58
|
+
if (source.kind === "native" && typeof source["provider"] === "string" && source["provider"].length > 0)
|
|
59
|
+
return clone(recorded);
|
|
60
|
+
if (source.kind === "local_exact" && typeof source.tokenizer === "string" && source.tokenizer.length > 0)
|
|
61
|
+
return clone(recorded);
|
|
62
|
+
if (source.kind === "heuristic")
|
|
63
|
+
return clone(recorded);
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
/** Normalize postflight provider facts without turning estimates into actual usage. */
|
|
67
|
+
export function normalizeProviderUsage(usage) {
|
|
68
|
+
const inputTokens = requireNonNegativeInteger(usage.inputTokens, "inputTokens");
|
|
69
|
+
const outputTokens = requireNonNegativeInteger(usage.outputTokens, "outputTokens");
|
|
70
|
+
const cacheReadInputTokens = optionalNonNegativeInteger(usage.cacheReadInputTokens, "cacheReadInputTokens");
|
|
71
|
+
const cacheCreationInputTokens = optionalNonNegativeInteger(usage.cacheCreationInputTokens, "cacheCreationInputTokens");
|
|
72
|
+
const reasoningTokens = optionalNonNegativeInteger(usage.reasoningTokens, "reasoningTokens");
|
|
73
|
+
const cached = (cacheReadInputTokens ?? 0) + (cacheCreationInputTokens ?? 0);
|
|
74
|
+
if (cached > inputTokens)
|
|
75
|
+
throw new RangeError("cache token subsets cannot exceed inputTokens");
|
|
76
|
+
if (reasoningTokens !== undefined && reasoningTokens > outputTokens) {
|
|
77
|
+
throw new RangeError("reasoningTokens must be a subset of outputTokens");
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
inputTokens,
|
|
81
|
+
uncachedInputTokens: inputTokens - cached,
|
|
82
|
+
outputTokens,
|
|
83
|
+
...(cacheReadInputTokens !== undefined ? { cacheReadInputTokens } : {}),
|
|
84
|
+
...(cacheCreationInputTokens !== undefined ? { cacheCreationInputTokens } : {}),
|
|
85
|
+
...(reasoningTokens !== undefined ? { reasoningTokens } : {}),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Cost is derived only from an explicit, time-valid host snapshot; otherwise it stays unknown. */
|
|
89
|
+
export function priceProviderUsage(usage, snapshot, observedAt = new Date()) {
|
|
90
|
+
const at = typeof observedAt === "string" ? new Date(observedAt) : observedAt;
|
|
91
|
+
const from = new Date(snapshot.effectiveFrom);
|
|
92
|
+
const expires = snapshot.expiresAt ? new Date(snapshot.expiresAt) : undefined;
|
|
93
|
+
const rates = snapshot.ratesPerMillion;
|
|
94
|
+
const requiredRates = [rates.input, rates.output];
|
|
95
|
+
if (!snapshot.version || !snapshot.currency || Number.isNaN(at.valueOf()) || Number.isNaN(from.valueOf())
|
|
96
|
+
|| requiredRates.some(rate => typeof rate !== "number" || !Number.isFinite(rate) || rate < 0)
|
|
97
|
+
|| Object.values(rates).some(rate => typeof rate !== "number" || !Number.isFinite(rate) || rate < 0)) {
|
|
98
|
+
return { source: "unpriced", reason: "invalid_pricing_snapshot" };
|
|
99
|
+
}
|
|
100
|
+
if (at < from)
|
|
101
|
+
return { source: "unpriced", reason: "pricing_snapshot_not_effective" };
|
|
102
|
+
if (expires && (Number.isNaN(expires.valueOf()) || at >= expires)) {
|
|
103
|
+
return { source: "unpriced", reason: "pricing_snapshot_expired" };
|
|
104
|
+
}
|
|
105
|
+
const amount = (usage.uncachedInputTokens * rates.input
|
|
106
|
+
+ usage.outputTokens * rates.output
|
|
107
|
+
+ (usage.cacheReadInputTokens ?? 0) * (rates.cacheRead ?? rates.input)
|
|
108
|
+
+ (usage.cacheCreationInputTokens ?? 0) * (rates.cacheCreation ?? rates.input)
|
|
109
|
+
+ (usage.reasoningTokens ?? 0) * (rates.reasoning ?? 0)) / 1_000_000;
|
|
110
|
+
return { source: "snapshot", currency: snapshot.currency, amount, pricingVersion: snapshot.version };
|
|
111
|
+
}
|
|
112
|
+
function materialOptions(options) {
|
|
113
|
+
return sanitizeMaterialValue(options);
|
|
114
|
+
}
|
|
115
|
+
function sanitizeEndpoint(endpoint) {
|
|
116
|
+
try {
|
|
117
|
+
const url = new URL(endpoint.baseURL);
|
|
118
|
+
url.username = "";
|
|
119
|
+
url.password = "";
|
|
120
|
+
url.search = "";
|
|
121
|
+
url.hash = "";
|
|
122
|
+
return { ...clone(endpoint), baseURL: url.toString().replace(/\/$/, "") };
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return { ...clone(endpoint), baseURL: "" };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function sanitizeMaterialValue(value) {
|
|
129
|
+
if (value === undefined || typeof value === "function")
|
|
130
|
+
return undefined;
|
|
131
|
+
if (Array.isArray(value))
|
|
132
|
+
return value.map(sanitizeMaterialValue).filter(item => item !== undefined);
|
|
133
|
+
if (value !== null && typeof value === "object") {
|
|
134
|
+
return Object.fromEntries(Object.keys(value).sort().flatMap(key => {
|
|
135
|
+
if (TRANSPORT_ONLY_KEYS.has(key) || isTransportOnlyKey(key))
|
|
136
|
+
return [];
|
|
137
|
+
const sanitized = sanitizeMaterialValue(value[key]);
|
|
138
|
+
return sanitized === undefined ? [] : [[key, sanitized]];
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
function isTransportOnlyKey(key) {
|
|
144
|
+
const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
145
|
+
return normalized.includes("authorization") || normalized.includes("credential")
|
|
146
|
+
|| normalized.includes("accesstoken") || normalized.includes("refreshtoken")
|
|
147
|
+
|| normalized.includes("apikey") || normalized === "bearer" || normalized === "token"
|
|
148
|
+
|| normalized === "secret" || normalized === "xapikey";
|
|
149
|
+
}
|
|
150
|
+
function stableJson(value) {
|
|
151
|
+
if (value === null || typeof value !== "object")
|
|
152
|
+
return JSON.stringify(value);
|
|
153
|
+
if (Array.isArray(value))
|
|
154
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
155
|
+
const object = value;
|
|
156
|
+
return `{${Object.keys(object).sort().map(key => `${JSON.stringify(key)}:${stableJson(object[key])}`).join(",")}}`;
|
|
157
|
+
}
|
|
158
|
+
function sha256(value) {
|
|
159
|
+
return `sha256:${createHash("sha256").update(value).digest("hex")}`;
|
|
160
|
+
}
|
|
161
|
+
function clone(value) {
|
|
162
|
+
if (value === undefined || value === null || typeof value !== "object")
|
|
163
|
+
return value;
|
|
164
|
+
if (Array.isArray(value))
|
|
165
|
+
return value.map(clone);
|
|
166
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, clone(item)]));
|
|
167
|
+
}
|
|
168
|
+
function requireNonNegativeInteger(value, name) {
|
|
169
|
+
if (!Number.isSafeInteger(value) || value < 0)
|
|
170
|
+
throw new RangeError(`${name} must be a non-negative safe integer`);
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
function optionalNonNegativeInteger(value, name) {
|
|
174
|
+
return value === undefined ? undefined : requireNonNegativeInteger(value, name);
|
|
175
|
+
}
|