@codehz/ai 0.8.1 → 0.9.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/README.md +8 -2
- package/dist/index.d.mts +66 -6
- package/dist/index.mjs +149 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,7 +97,11 @@ type AIRequest = {
|
|
|
97
97
|
temperature?: number; // provider/model-defined generation parameter
|
|
98
98
|
maxOutputTokens?: number; // 最大输出 token
|
|
99
99
|
reasoningLevel?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; // 可移植思考力度
|
|
100
|
-
include?: {
|
|
100
|
+
include?: {
|
|
101
|
+
usage?: "off" | "best_effort" | "required";
|
|
102
|
+
billing?: "off" | "best_effort" | "required";
|
|
103
|
+
providerMetadata?: "off" | "best_effort";
|
|
104
|
+
};
|
|
101
105
|
};
|
|
102
106
|
```
|
|
103
107
|
|
|
@@ -530,7 +534,9 @@ const r2 = await collectStream(client.stream({ input, tools }));
|
|
|
530
534
|
|
|
531
535
|
## 辅助信息采集
|
|
532
536
|
|
|
533
|
-
usage / billing / providerMetadata 由 adapter 在流结束时经 `response.auxiliary` 与 `AIResponse` 字段交付。`AuxiliaryCollector` 是 provider 内部实现细节,`0.5.0` 起不再从根入口导出。`lookup` / `postprocessBilling` 为 experimental 扩展点,库内 HTTP adapter 默认未接线。
|
|
537
|
+
`usage` / `billing` / `providerMetadata` 由 adapter 在流结束时经 `response.auxiliary` 与 `AIResponse` 字段交付。`AuxiliaryCollector` 是 provider 内部实现细节,`0.5.0` 起不再从根入口导出。`lookup` / `postprocessBilling` 为 experimental 扩展点,库内 HTTP adapter 默认未接线。
|
|
538
|
+
|
|
539
|
+
`usage` 与 `billing` 的 `include` 支持三种模式:`off` 表示不采集;`best_effort`(默认)表示尽可能采集,缺失时静默;`required` 表示缺失时发出 `USAGE_MISSING` 或 `BILLING_MISSING` warning。估算 billing 仍会发出 `BILLING_ESTIMATED` warning。
|
|
534
540
|
|
|
535
541
|
## 开发命令
|
|
536
542
|
|
package/dist/index.d.mts
CHANGED
|
@@ -127,6 +127,42 @@ type OutputItem = MessageItem | ReasoningItem | ToolCallItem | OpaqueItem | Serv
|
|
|
127
127
|
/** replay 材料的类型等价于 InputItem */
|
|
128
128
|
type ReplayItem = InputItem;
|
|
129
129
|
//#endregion
|
|
130
|
+
//#region src/types/cache.d.ts
|
|
131
|
+
/** Request-level portable prompt cache controls and provider extensions. */
|
|
132
|
+
type PromptCacheMode = "off" | "auto" | "explicit";
|
|
133
|
+
type PromptCacheSettings = {
|
|
134
|
+
/** Cache strategy; when omitted, the adapter/provider decides. */mode?: PromptCacheMode; /** Session or tenant routing hint; providers may ignore it. */
|
|
135
|
+
key?: string; /** Provider-specific retention hint. */
|
|
136
|
+
ttl?: "short" | "long" | string;
|
|
137
|
+
};
|
|
138
|
+
type ProviderCacheOptions = {
|
|
139
|
+
responses?: {
|
|
140
|
+
promptCacheKey?: string;
|
|
141
|
+
promptCacheRetention?: "in_memory" | "24h";
|
|
142
|
+
promptCacheMode?: "implicit" | "explicit" | "off";
|
|
143
|
+
};
|
|
144
|
+
chatCompletions?: {
|
|
145
|
+
promptCacheKey?: string;
|
|
146
|
+
promptCacheRetention?: "in_memory" | "24h";
|
|
147
|
+
};
|
|
148
|
+
messages?: {
|
|
149
|
+
cacheTtl?: "5m" | "1h";
|
|
150
|
+
betaHeader?: string;
|
|
151
|
+
};
|
|
152
|
+
gemini?: {
|
|
153
|
+
cachedContent?: string;
|
|
154
|
+
};
|
|
155
|
+
ollama?: {
|
|
156
|
+
keepAlive?: string | number;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
type PromptCacheMetadata = {
|
|
160
|
+
requestedMode: PromptCacheMode;
|
|
161
|
+
appliedMode: "off" | "implicit" | "explicit" | "unsupported";
|
|
162
|
+
keyApplied: boolean;
|
|
163
|
+
ttlApplied: boolean;
|
|
164
|
+
};
|
|
165
|
+
//#endregion
|
|
130
166
|
//#region src/types/request.d.ts
|
|
131
167
|
type ToolDefinition = {
|
|
132
168
|
name: string;
|
|
@@ -171,8 +207,8 @@ type McpServerTool = {
|
|
|
171
207
|
/** Provider 托管执行的工具声明(不进客户端 tool loop) */
|
|
172
208
|
type ServerToolDefinition = WebSearchServerTool | CodeExecutionServerTool | McpServerTool;
|
|
173
209
|
type IncludeSettings = {
|
|
174
|
-
usage?: "off" | "best_effort";
|
|
175
|
-
billing?: "off" | "best_effort";
|
|
210
|
+
usage?: "off" | "best_effort" | "required";
|
|
211
|
+
billing?: "off" | "best_effort" | "required";
|
|
176
212
|
providerMetadata?: "off" | "best_effort";
|
|
177
213
|
};
|
|
178
214
|
/** Portable reasoning / thinking effort. Mapped per-adapter to provider wire fields. */
|
|
@@ -197,7 +233,11 @@ type AIRequest = {
|
|
|
197
233
|
* Messages `thinking`, Ollama `think`, Gemini `thinkingConfig`).
|
|
198
234
|
* Unsupported levels throw.
|
|
199
235
|
*/
|
|
200
|
-
reasoningLevel?: ReasoningLevel; /**
|
|
236
|
+
reasoningLevel?: ReasoningLevel; /** Portable request-level prompt cache strategy and routing hint. */
|
|
237
|
+
cache?: PromptCacheSettings; /** Typed provider-native cache extensions; unsupported fields are ignored by other adapters. */
|
|
238
|
+
providerOptions?: {
|
|
239
|
+
cache?: ProviderCacheOptions;
|
|
240
|
+
}; /** AbortSignal 用于打断请求。abort 时 fetch 调用会被取消,流迭代器抛出 AbortError。 */
|
|
201
241
|
signal?: AbortSignal;
|
|
202
242
|
};
|
|
203
243
|
//#endregion
|
|
@@ -691,7 +731,7 @@ declare class AdapterAuxiliaryState {
|
|
|
691
731
|
constructor(request: NormalizedRequest);
|
|
692
732
|
recordUsage(usage: Partial<Usage>, source: UsageSource, raw?: unknown): void;
|
|
693
733
|
recordBilling(billing: Partial<BillingInfo>, source: BillingSource, raw?: unknown): void;
|
|
694
|
-
recordProviderMetadata(source: string, metadata: Record<string, unknown> | undefined): void;
|
|
734
|
+
recordProviderMetadata(source: string | undefined, metadata: Record<string, unknown> | undefined): void;
|
|
695
735
|
finalize(factory: EventFactory, options?: AuxiliaryFinalizeOptions): Promise<AuxiliaryFinalizeResult>;
|
|
696
736
|
private shouldAttemptLookup;
|
|
697
737
|
}
|
|
@@ -886,6 +926,11 @@ type ResponsesAPIRequest = {
|
|
|
886
926
|
effort: string;
|
|
887
927
|
}; /** 服务端多轮续写;opaque replay 的 response id 映射到此字段,而非 item_reference */
|
|
888
928
|
previous_response_id?: string;
|
|
929
|
+
prompt_cache_key?: string;
|
|
930
|
+
prompt_cache_options?: {
|
|
931
|
+
mode?: "implicit" | "explicit" | "off";
|
|
932
|
+
retention?: "in_memory" | "24h";
|
|
933
|
+
};
|
|
889
934
|
stream: true;
|
|
890
935
|
};
|
|
891
936
|
/** EasyInputMessage:content 可为 string,或 input_* content parts */
|
|
@@ -1025,7 +1070,7 @@ type MessagesAPIRequest = {
|
|
|
1025
1070
|
model: string;
|
|
1026
1071
|
max_tokens: number;
|
|
1027
1072
|
messages: MessagesAPIMessage[];
|
|
1028
|
-
system?: string;
|
|
1073
|
+
system?: string | MessagesAPIContentBlock[];
|
|
1029
1074
|
tools?: MessagesAPITool[];
|
|
1030
1075
|
tool_choice?: {
|
|
1031
1076
|
type: "auto" | "none";
|
|
@@ -1055,34 +1100,45 @@ type MessagesAPIImageSource = {
|
|
|
1055
1100
|
type: "url";
|
|
1056
1101
|
url: string;
|
|
1057
1102
|
};
|
|
1103
|
+
type MessagesCacheControl = {
|
|
1104
|
+
type: "ephemeral";
|
|
1105
|
+
ttl?: "5m" | "1h";
|
|
1106
|
+
};
|
|
1058
1107
|
type MessagesAPIContentBlock = {
|
|
1059
1108
|
type: "text";
|
|
1060
1109
|
text: string;
|
|
1110
|
+
cache_control?: MessagesCacheControl;
|
|
1061
1111
|
} | {
|
|
1062
1112
|
type: "image";
|
|
1063
1113
|
source: MessagesAPIImageSource;
|
|
1114
|
+
cache_control?: MessagesCacheControl;
|
|
1064
1115
|
} | {
|
|
1065
1116
|
type: "thinking";
|
|
1066
1117
|
thinking: string;
|
|
1067
1118
|
signature?: string;
|
|
1119
|
+
cache_control?: MessagesCacheControl;
|
|
1068
1120
|
} | {
|
|
1069
1121
|
type: "redacted_thinking";
|
|
1070
1122
|
data: string;
|
|
1123
|
+
cache_control?: MessagesCacheControl;
|
|
1071
1124
|
} | {
|
|
1072
1125
|
type: "tool_use";
|
|
1073
1126
|
id: string;
|
|
1074
1127
|
name: string;
|
|
1075
1128
|
input: Record<string, unknown>;
|
|
1129
|
+
cache_control?: MessagesCacheControl;
|
|
1076
1130
|
} | {
|
|
1077
1131
|
type: "tool_result";
|
|
1078
1132
|
tool_use_id: string;
|
|
1079
1133
|
content: string | MessagesAPIContentBlock[];
|
|
1080
1134
|
is_error?: boolean;
|
|
1135
|
+
cache_control?: MessagesCacheControl;
|
|
1081
1136
|
};
|
|
1082
1137
|
type MessagesAPITool = {
|
|
1083
1138
|
name: string;
|
|
1084
1139
|
description?: string;
|
|
1085
1140
|
input_schema: Record<string, unknown>;
|
|
1141
|
+
cache_control?: MessagesCacheControl;
|
|
1086
1142
|
};
|
|
1087
1143
|
//#endregion
|
|
1088
1144
|
//#region src/adapters/messages/adapter.d.ts
|
|
@@ -1114,6 +1170,8 @@ type ChatRequest = {
|
|
|
1114
1170
|
temperature?: number;
|
|
1115
1171
|
max_tokens?: number; /** Portable reasoningLevel → reasoning_effort */
|
|
1116
1172
|
reasoning_effort?: string;
|
|
1173
|
+
prompt_cache_key?: string;
|
|
1174
|
+
prompt_cache_retention?: "in_memory" | "24h";
|
|
1117
1175
|
stream: true;
|
|
1118
1176
|
n: 1;
|
|
1119
1177
|
};
|
|
@@ -1172,6 +1230,7 @@ type OllamaChatRequest = {
|
|
|
1172
1230
|
model: string;
|
|
1173
1231
|
messages: OllamaMessage[];
|
|
1174
1232
|
stream: true;
|
|
1233
|
+
keep_alive?: string | number;
|
|
1175
1234
|
tools?: OllamaTool[]; /** Portable reasoningLevel → think;minimal/xhigh/max 不支持 */
|
|
1176
1235
|
think?: boolean | "low" | "medium" | "high";
|
|
1177
1236
|
options?: {
|
|
@@ -1253,6 +1312,7 @@ type GeminiFunctionCallingConfig = {
|
|
|
1253
1312
|
};
|
|
1254
1313
|
type GeminiGenerateContentRequest = {
|
|
1255
1314
|
contents: GeminiContent[];
|
|
1315
|
+
cachedContent?: string;
|
|
1256
1316
|
systemInstruction?: {
|
|
1257
1317
|
parts: Array<{
|
|
1258
1318
|
text: string;
|
|
@@ -1477,5 +1537,5 @@ declare function assertMockRequest(request: NormalizedRequest, expectation: Mock
|
|
|
1477
1537
|
//#region src/adapters/mock/streaming.d.ts
|
|
1478
1538
|
declare function withMockStreaming(handler: MockStaticHandler, options: MockTextStreamOptions): MockHandler;
|
|
1479
1539
|
//#endregion
|
|
1480
|
-
export { type AIClient, AIError, AIMappingError, AIProviderError, AIRecoverableError, type AIRequest, AIRequestError, type AIResponse, AIStreamError, type AIStreamEvent, type AdapterKind, type AuxiliaryInfo, type BackendAdapter, type BackendTrace, type BillingInfo, ChatCompletionsAdapter, type ChatCompletionsAdapterOptions, type Citation, type CodeExecutionServerTool, type CompressRequest, type CompressResult, type ContainerFileCitation, type ContentBlock, type ContextCompressCapable, type CreateAIClientOptions, type ErrorCode, type FetchFn, GeminiAdapter, type GeminiAdapterOptions, type IncludeSettings, type InputItem, type InstructionBlock, type JsonContentBlock, KNOWN_ADAPTER_KINDS, type KnownAdapterKind, type KnownErrorCode, type KnownWarningCode, type McpServerTool, type MessageCompletedEvent, type MessageDeltaEvent, type MessageItem, type MessageStartedEvent, MessagesAdapter, type MessagesAdapterOptions, MockAdapter, type MockAdapterOptions, type MockAuxiliaryStep, type MockCompleteStep, type MockCompressHandler, type MockErrorStep, type MockHandler, type MockHandlerContext, type MockHistoryRecord, type MockInputExpectation, type MockInterruptStep, type MockMessageStep, type MockOutputStep, type MockReasoningStep, type MockRequestExpectation, type MockServerToolCallStep, type MockServerToolDiscoveryStep, type MockServerToolResultStep, type MockStaticHandler, type MockStep, type MockTextStreamOptions, type MockThrowStep, type MockToolCallStep, type MockWarningStep, type NormalizedRequest, OllamaAdapter, type OllamaAdapterOptions, type OpaqueItem, type OutputItem, REASONING_LEVELS, REASONING_LEVEL_SET, type ReasoningCompletedEvent, type ReasoningDeltaEvent, type ReasoningItem, type ReasoningLevel, type ReasoningStartedEvent, type ReplayItem, type ResponseAuxiliaryEvent, type ResponseCompletedEvent, type ResponseStartedEvent, type ResponseWarningEvent, ResponsesAdapter, type ResponsesAdapterOptions, type ServerToolCallItem, type ServerToolCompletedEvent, type ServerToolDefinition, type ServerToolDeltaEvent, type ServerToolDiscoveryCompletedEvent, type ServerToolDiscoveryItem, type ServerToolResultCompletedEvent, type ServerToolResultItem, type ServerToolStartedEvent, type StopReason, type StreamEventBase, type StreamWarning, type TextContentBlock, type ToolCallCompletedEvent, type ToolCallDeltaEvent, type ToolCallItem, type ToolCallStartedEvent, type ToolChoice, type ToolDefinition, type ToolResultItem, type UrlCitation, type Usage, WarningCode, type WarningCodeName, type WarningCodeValue, type WebSearchServerTool, type WebSearchUserLocation, assertMockRequest, blockToText, coalesceContentBlocks, collectStream, contentBlocksToText, createAIClient, extractText, imageBlock, jsonBlock, mapReasoningVisibility, mapStopReason, messageItem, opaqueBlock, opaqueItem, reasoningItem, replayFromOutput, serverToolCallItem, serverToolDiscoveryItem, serverToolResultItem, streamWarningKey, supportsContextCompress, textBlock, toolCallItem, toolResultItem, withMockStreaming };
|
|
1540
|
+
export { type AIClient, AIError, AIMappingError, AIProviderError, AIRecoverableError, type AIRequest, AIRequestError, type AIResponse, AIStreamError, type AIStreamEvent, type AdapterKind, type AuxiliaryInfo, type BackendAdapter, type BackendTrace, type BillingInfo, ChatCompletionsAdapter, type ChatCompletionsAdapterOptions, type Citation, type CodeExecutionServerTool, type CompressRequest, type CompressResult, type ContainerFileCitation, type ContentBlock, type ContextCompressCapable, type CreateAIClientOptions, type ErrorCode, type FetchFn, GeminiAdapter, type GeminiAdapterOptions, type IncludeSettings, type InputItem, type InstructionBlock, type JsonContentBlock, KNOWN_ADAPTER_KINDS, type KnownAdapterKind, type KnownErrorCode, type KnownWarningCode, type McpServerTool, type MessageCompletedEvent, type MessageDeltaEvent, type MessageItem, type MessageStartedEvent, MessagesAdapter, type MessagesAdapterOptions, MockAdapter, type MockAdapterOptions, type MockAuxiliaryStep, type MockCompleteStep, type MockCompressHandler, type MockErrorStep, type MockHandler, type MockHandlerContext, type MockHistoryRecord, type MockInputExpectation, type MockInterruptStep, type MockMessageStep, type MockOutputStep, type MockReasoningStep, type MockRequestExpectation, type MockServerToolCallStep, type MockServerToolDiscoveryStep, type MockServerToolResultStep, type MockStaticHandler, type MockStep, type MockTextStreamOptions, type MockThrowStep, type MockToolCallStep, type MockWarningStep, type NormalizedRequest, OllamaAdapter, type OllamaAdapterOptions, type OpaqueItem, type OutputItem, type PromptCacheMetadata, type PromptCacheMode, type PromptCacheSettings, type ProviderCacheOptions, REASONING_LEVELS, REASONING_LEVEL_SET, type ReasoningCompletedEvent, type ReasoningDeltaEvent, type ReasoningItem, type ReasoningLevel, type ReasoningStartedEvent, type ReplayItem, type ResponseAuxiliaryEvent, type ResponseCompletedEvent, type ResponseStartedEvent, type ResponseWarningEvent, ResponsesAdapter, type ResponsesAdapterOptions, type ServerToolCallItem, type ServerToolCompletedEvent, type ServerToolDefinition, type ServerToolDeltaEvent, type ServerToolDiscoveryCompletedEvent, type ServerToolDiscoveryItem, type ServerToolResultCompletedEvent, type ServerToolResultItem, type ServerToolStartedEvent, type StopReason, type StreamEventBase, type StreamWarning, type TextContentBlock, type ToolCallCompletedEvent, type ToolCallDeltaEvent, type ToolCallItem, type ToolCallStartedEvent, type ToolChoice, type ToolDefinition, type ToolResultItem, type UrlCitation, type Usage, WarningCode, type WarningCodeName, type WarningCodeValue, type WebSearchServerTool, type WebSearchUserLocation, assertMockRequest, blockToText, coalesceContentBlocks, collectStream, contentBlocksToText, createAIClient, extractText, imageBlock, jsonBlock, mapReasoningVisibility, mapStopReason, messageItem, opaqueBlock, opaqueItem, reasoningItem, replayFromOutput, serverToolCallItem, serverToolDiscoveryItem, serverToolResultItem, streamWarningKey, supportsContextCompress, textBlock, toolCallItem, toolResultItem, withMockStreaming };
|
|
1481
1541
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1064,7 +1064,7 @@ var AdapterAuxiliaryState = class {
|
|
|
1064
1064
|
recordProviderMetadata(source, metadata) {
|
|
1065
1065
|
if (this.request.include?.providerMetadata === "off" || !metadata || isEmptyRecord(metadata)) return;
|
|
1066
1066
|
this.collector.recordMetadata(metadata);
|
|
1067
|
-
this.metadataSources.add(source);
|
|
1067
|
+
if (source) this.metadataSources.add(source);
|
|
1068
1068
|
}
|
|
1069
1069
|
async finalize(factory, options = {}) {
|
|
1070
1070
|
if (options.lookup && this.shouldAttemptLookup()) await this.collector.tryLookup(options.lookup, options.lookupTimeoutMs);
|
|
@@ -1091,11 +1091,11 @@ var AdapterAuxiliaryState = class {
|
|
|
1091
1091
|
billing: built.billing,
|
|
1092
1092
|
auxiliary: built.auxiliary
|
|
1093
1093
|
}));
|
|
1094
|
-
if (this.request.include?.usage
|
|
1095
|
-
if (this.request.include?.billing
|
|
1094
|
+
if (this.request.include?.usage === "required" && !built.usage) events.push(factory.responseWarning("Usage information was not provided by the provider", WarningCode.USAGE_MISSING));
|
|
1095
|
+
if (this.request.include?.billing === "required") {
|
|
1096
1096
|
if (!built.billing) events.push(factory.responseWarning("Billing information was not provided by the provider", WarningCode.BILLING_MISSING));
|
|
1097
1097
|
else if (built.billing.isEstimated) events.push(factory.responseWarning("Billing amount is an estimate", WarningCode.BILLING_ESTIMATED));
|
|
1098
|
-
}
|
|
1098
|
+
} else if (built.billing?.isEstimated) events.push(factory.responseWarning("Billing amount is an estimate", WarningCode.BILLING_ESTIMATED));
|
|
1099
1099
|
return {
|
|
1100
1100
|
events,
|
|
1101
1101
|
usage: built.usage,
|
|
@@ -1119,6 +1119,102 @@ function isEmptyRecord(value) {
|
|
|
1119
1119
|
return Object.keys(value).length === 0;
|
|
1120
1120
|
}
|
|
1121
1121
|
//#endregion
|
|
1122
|
+
//#region src/provider/prompt-cache.ts
|
|
1123
|
+
function requestedPromptCacheMode(request) {
|
|
1124
|
+
return request.cache?.mode ?? "auto";
|
|
1125
|
+
}
|
|
1126
|
+
function promptCacheAdapterForKind(kind) {
|
|
1127
|
+
if (kind === "responses" || kind === "chat-completions" || kind === "messages" || kind === "gemini" || kind === "ollama") return kind;
|
|
1128
|
+
}
|
|
1129
|
+
function promptCacheMetadata(request, adapter, overrides = {}) {
|
|
1130
|
+
const requestedMode = requestedPromptCacheMode(request);
|
|
1131
|
+
if (requestedMode === "off") return {
|
|
1132
|
+
requestedMode,
|
|
1133
|
+
appliedMode: "off",
|
|
1134
|
+
keyApplied: false,
|
|
1135
|
+
ttlApplied: false
|
|
1136
|
+
};
|
|
1137
|
+
const native = request.providerOptions?.cache;
|
|
1138
|
+
const portable = request.cache;
|
|
1139
|
+
let appliedMode = "implicit";
|
|
1140
|
+
let keyApplied = false;
|
|
1141
|
+
let ttlApplied = false;
|
|
1142
|
+
if (adapter === "responses") {
|
|
1143
|
+
const nativeOptions = native?.responses;
|
|
1144
|
+
const mode = nativeOptions?.promptCacheMode ?? (requestedMode === "explicit" ? "explicit" : void 0);
|
|
1145
|
+
keyApplied = mode !== "off" && Boolean(nativeOptions?.promptCacheKey ?? portable?.key);
|
|
1146
|
+
ttlApplied = mode !== "off" && Boolean(nativeOptions?.promptCacheRetention ?? mapPromptCacheRetention(portable?.ttl));
|
|
1147
|
+
appliedMode = mode === "off" ? "off" : mode === "explicit" ? "explicit" : "implicit";
|
|
1148
|
+
} else if (adapter === "chat-completions") {
|
|
1149
|
+
const options = native?.chatCompletions;
|
|
1150
|
+
keyApplied = Boolean(options?.promptCacheKey ?? portable?.key);
|
|
1151
|
+
ttlApplied = Boolean(options?.promptCacheRetention ?? mapPromptCacheRetention(portable?.ttl));
|
|
1152
|
+
appliedMode = requestedMode === "explicit" || Boolean(options?.promptCacheKey || options?.promptCacheRetention) ? "explicit" : "implicit";
|
|
1153
|
+
} else if (adapter === "messages") {
|
|
1154
|
+
const hasStablePrefix = Boolean(request.instructions) || request.input.length > 0 || (request.tools?.length ?? 0) > 0;
|
|
1155
|
+
const explicitRequested = requestedMode === "explicit" || native?.messages?.cacheTtl !== void 0;
|
|
1156
|
+
const explicit = explicitRequested && hasStablePrefix;
|
|
1157
|
+
appliedMode = explicit ? "explicit" : explicitRequested ? "unsupported" : "implicit";
|
|
1158
|
+
ttlApplied = explicit && Boolean(native?.messages?.cacheTtl ?? mapAnthropicCacheTtl(portable?.ttl));
|
|
1159
|
+
} else if (adapter === "gemini") if (native?.gemini?.cachedContent) appliedMode = "explicit";
|
|
1160
|
+
else appliedMode = requestedMode === "explicit" ? "unsupported" : "implicit";
|
|
1161
|
+
else if (adapter === "ollama") {
|
|
1162
|
+
const keepAlive = native?.ollama?.keepAlive;
|
|
1163
|
+
appliedMode = requestedMode === "explicit" && keepAlive === void 0 ? "unsupported" : requestedMode === "explicit" ? "explicit" : "implicit";
|
|
1164
|
+
}
|
|
1165
|
+
return {
|
|
1166
|
+
requestedMode,
|
|
1167
|
+
appliedMode: overrides.explicitApplied === true ? "explicit" : appliedMode,
|
|
1168
|
+
keyApplied: overrides.keyApplied ?? keyApplied,
|
|
1169
|
+
ttlApplied: overrides.ttlApplied ?? ttlApplied
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
function applyPromptCacheFields(body, request, adapter) {
|
|
1173
|
+
const portable = request.cache;
|
|
1174
|
+
const native = request.providerOptions?.cache;
|
|
1175
|
+
const metadata = promptCacheMetadata(request, adapter);
|
|
1176
|
+
if (portable?.mode === "off") return metadata;
|
|
1177
|
+
if (adapter === "responses") {
|
|
1178
|
+
const options = native?.responses;
|
|
1179
|
+
const key = options?.promptCacheKey ?? portable?.key;
|
|
1180
|
+
const mode = options?.promptCacheMode ?? (portable?.mode === "explicit" ? "explicit" : void 0);
|
|
1181
|
+
const retention = options?.promptCacheRetention ?? mapPromptCacheRetention(portable?.ttl);
|
|
1182
|
+
if (mode !== "off" && key) body.prompt_cache_key = key;
|
|
1183
|
+
if (mode || retention) body.prompt_cache_options = {
|
|
1184
|
+
...mode ? { mode } : {},
|
|
1185
|
+
...mode !== "off" && retention ? { retention } : {}
|
|
1186
|
+
};
|
|
1187
|
+
return metadata;
|
|
1188
|
+
}
|
|
1189
|
+
if (adapter === "chat-completions") {
|
|
1190
|
+
const options = native?.chatCompletions;
|
|
1191
|
+
const key = options?.promptCacheKey ?? portable?.key;
|
|
1192
|
+
const retention = options?.promptCacheRetention ?? mapPromptCacheRetention(portable?.ttl);
|
|
1193
|
+
if (key) body.prompt_cache_key = key;
|
|
1194
|
+
if (retention) body.prompt_cache_retention = retention;
|
|
1195
|
+
return metadata;
|
|
1196
|
+
}
|
|
1197
|
+
if (adapter === "gemini") {
|
|
1198
|
+
const cachedContent = native?.gemini?.cachedContent;
|
|
1199
|
+
if (cachedContent) body.cachedContent = cachedContent;
|
|
1200
|
+
return metadata;
|
|
1201
|
+
}
|
|
1202
|
+
if (adapter === "ollama") {
|
|
1203
|
+
const keepAlive = native?.ollama?.keepAlive;
|
|
1204
|
+
if (keepAlive !== void 0) body.keep_alive = keepAlive;
|
|
1205
|
+
}
|
|
1206
|
+
return metadata;
|
|
1207
|
+
}
|
|
1208
|
+
function mapPromptCacheRetention(ttl) {
|
|
1209
|
+
if (ttl === "short") return "in_memory";
|
|
1210
|
+
if (ttl === "long") return "24h";
|
|
1211
|
+
if (ttl === "in_memory" || ttl === "24h") return ttl;
|
|
1212
|
+
}
|
|
1213
|
+
function mapAnthropicCacheTtl(ttl) {
|
|
1214
|
+
if (ttl === "short" || ttl === "5m") return "5m";
|
|
1215
|
+
if (ttl === "long" || ttl === "1h") return "1h";
|
|
1216
|
+
}
|
|
1217
|
+
//#endregion
|
|
1122
1218
|
//#region src/provider/base.ts
|
|
1123
1219
|
var AdapterBase = class {
|
|
1124
1220
|
/**
|
|
@@ -1201,7 +1297,10 @@ var AdapterBase = class {
|
|
|
1201
1297
|
yield factory.responseCompleted(payload);
|
|
1202
1298
|
}
|
|
1203
1299
|
createAuxiliaryState(request) {
|
|
1204
|
-
|
|
1300
|
+
const auxiliary = new AdapterAuxiliaryState(request);
|
|
1301
|
+
const adapter = promptCacheAdapterForKind(this.kind);
|
|
1302
|
+
if (adapter) auxiliary.recordProviderMetadata(void 0, { promptCache: promptCacheMetadata(request, adapter) });
|
|
1303
|
+
return auxiliary;
|
|
1205
1304
|
}
|
|
1206
1305
|
};
|
|
1207
1306
|
function mergeWarnings(...groups) {
|
|
@@ -1564,6 +1663,7 @@ function usageFromChatCompletions(raw) {
|
|
|
1564
1663
|
outputTokens: num(raw.completion_tokens),
|
|
1565
1664
|
totalTokens: num(raw.total_tokens),
|
|
1566
1665
|
cachedInputTokens: num(raw.prompt_tokens_details?.cached_tokens),
|
|
1666
|
+
cacheWriteInputTokens: num(raw.cache_write_tokens ?? raw.prompt_tokens_details?.cache_write_tokens),
|
|
1567
1667
|
reasoningTokens: num(raw.completion_tokens_details?.reasoning_tokens)
|
|
1568
1668
|
});
|
|
1569
1669
|
}
|
|
@@ -1574,6 +1674,7 @@ function usageFromOpenAIResponses(raw) {
|
|
|
1574
1674
|
outputTokens: num(raw.output_tokens),
|
|
1575
1675
|
totalTokens: num(raw.total_tokens),
|
|
1576
1676
|
cachedInputTokens: num(raw.input_tokens_details?.cached_tokens),
|
|
1677
|
+
cacheWriteInputTokens: num(raw.cache_write_tokens ?? raw.input_tokens_details?.cache_write_tokens),
|
|
1577
1678
|
reasoningTokens: num(raw.output_tokens_details?.reasoning_tokens)
|
|
1578
1679
|
});
|
|
1579
1680
|
}
|
|
@@ -2279,6 +2380,7 @@ function buildResponsesRequest(request, options) {
|
|
|
2279
2380
|
if (request.maxOutputTokens !== void 0) body.max_output_tokens = request.maxOutputTokens;
|
|
2280
2381
|
if (request.metadata) body.metadata = request.metadata;
|
|
2281
2382
|
if (request.reasoningLevel !== void 0) body.reasoning = mapResponsesReasoning(request.reasoningLevel);
|
|
2383
|
+
applyPromptCacheFields(body, request, "responses");
|
|
2282
2384
|
return body;
|
|
2283
2385
|
}
|
|
2284
2386
|
/**
|
|
@@ -3351,8 +3453,45 @@ function buildMessagesRequest(request, options) {
|
|
|
3351
3453
|
});
|
|
3352
3454
|
if (request.temperature !== void 0) body.temperature = request.temperature;
|
|
3353
3455
|
if (request.reasoningLevel !== void 0) body.thinking = mapMessagesThinking(request.reasoningLevel, body.max_tokens);
|
|
3456
|
+
applyMessagesPromptCache(body, request, systemPrompt);
|
|
3354
3457
|
return body;
|
|
3355
3458
|
}
|
|
3459
|
+
function applyMessagesPromptCache(body, request, systemPrompt) {
|
|
3460
|
+
const requestedMode = requestedPromptCacheMode(request);
|
|
3461
|
+
if (requestedMode === "off") return;
|
|
3462
|
+
if (requestedMode !== "explicit" && request.providerOptions?.cache?.messages?.cacheTtl === void 0) return;
|
|
3463
|
+
const ttl = request.providerOptions?.cache?.messages?.cacheTtl ?? mapAnthropicCacheTtl(request.cache?.ttl);
|
|
3464
|
+
const cacheControl = {
|
|
3465
|
+
type: "ephemeral",
|
|
3466
|
+
...ttl ? { ttl } : {}
|
|
3467
|
+
};
|
|
3468
|
+
if (systemPrompt) {
|
|
3469
|
+
body.system = [{
|
|
3470
|
+
type: "text",
|
|
3471
|
+
text: systemPrompt,
|
|
3472
|
+
cache_control: cacheControl
|
|
3473
|
+
}];
|
|
3474
|
+
return;
|
|
3475
|
+
}
|
|
3476
|
+
const lastMessage = body.messages[body.messages.length - 1];
|
|
3477
|
+
if (lastMessage) {
|
|
3478
|
+
if (typeof lastMessage.content === "string") {
|
|
3479
|
+
lastMessage.content = [{
|
|
3480
|
+
type: "text",
|
|
3481
|
+
text: lastMessage.content,
|
|
3482
|
+
cache_control: cacheControl
|
|
3483
|
+
}];
|
|
3484
|
+
return;
|
|
3485
|
+
}
|
|
3486
|
+
const lastBlock = lastMessage.content[lastMessage.content.length - 1];
|
|
3487
|
+
if (lastBlock) {
|
|
3488
|
+
lastBlock.cache_control = cacheControl;
|
|
3489
|
+
return;
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
const lastTool = body.tools?.[body.tools.length - 1];
|
|
3493
|
+
if (lastTool) lastTool.cache_control = cacheControl;
|
|
3494
|
+
}
|
|
3356
3495
|
new NormalizedRequestMapper("messages");
|
|
3357
3496
|
/** 用 response 级别的命名空间合成 content block 的 item ID,避免多轮工具循环 ID 碰撞 */
|
|
3358
3497
|
function synthesizeItemId(kind, blockIndex, responseId) {
|
|
@@ -3390,7 +3529,8 @@ async function* mapMessagesStream(host, providerRequest, factory, request) {
|
|
|
3390
3529
|
headers: host.mergeHeaders({
|
|
3391
3530
|
"Content-Type": "application/json",
|
|
3392
3531
|
"x-api-key": host.apiKey ?? "",
|
|
3393
|
-
"anthropic-version": host.apiVersion
|
|
3532
|
+
"anthropic-version": host.apiVersion,
|
|
3533
|
+
...request.providerOptions?.cache?.messages?.betaHeader ? { "anthropic-beta": request.providerOptions.cache.messages.betaHeader } : {}
|
|
3394
3534
|
}),
|
|
3395
3535
|
body: providerRequest
|
|
3396
3536
|
});
|
|
@@ -3825,6 +3965,7 @@ function buildChatCompletionsRequest(request, options) {
|
|
|
3825
3965
|
if (request.maxOutputTokens !== void 0) body.max_tokens = request.maxOutputTokens;
|
|
3826
3966
|
if (request.metadata) body.metadata = request.metadata;
|
|
3827
3967
|
if (request.reasoningLevel !== void 0) body.reasoning_effort = mapChatCompletionsReasoningEffort(request.reasoningLevel);
|
|
3968
|
+
applyPromptCacheFields(body, request, "chat-completions");
|
|
3828
3969
|
return body;
|
|
3829
3970
|
}
|
|
3830
3971
|
//#endregion
|
|
@@ -4224,6 +4365,7 @@ function buildOllamaRequest(request, options) {
|
|
|
4224
4365
|
if (request.maxOutputTokens !== void 0) body.options.num_predict = request.maxOutputTokens;
|
|
4225
4366
|
}
|
|
4226
4367
|
if (request.reasoningLevel !== void 0) body.think = mapOllamaThink(request.reasoningLevel);
|
|
4368
|
+
applyPromptCacheFields(body, request, "ollama");
|
|
4227
4369
|
return body;
|
|
4228
4370
|
}
|
|
4229
4371
|
new NormalizedRequestMapper("ollama");
|
|
@@ -4525,6 +4667,7 @@ function buildGeminiRequest(request, options) {
|
|
|
4525
4667
|
if (request.maxOutputTokens !== void 0) generationConfig.maxOutputTokens = request.maxOutputTokens;
|
|
4526
4668
|
if (request.reasoningLevel !== void 0) generationConfig.thinkingConfig = mapGeminiThinking(request.reasoningLevel);
|
|
4527
4669
|
if (Object.keys(generationConfig).length > 0) body.generationConfig = generationConfig;
|
|
4670
|
+
applyPromptCacheFields(body, request, "gemini");
|
|
4528
4671
|
return body;
|
|
4529
4672
|
}
|
|
4530
4673
|
new NormalizedRequestMapper("gemini");
|