Skip to content

Commit 1d5ab9b

Browse files
adase11markpollack
authored andcommitted
feat: Implement cache management for Anthropic API with eligibility tracking
gh-4325: Enhance cache management for Anthropic API by introudicing per-message TTL and configurable content block usage optimization. Signed-off-by: Austin Dase <[email protected]>
1 parent 3c57027 commit 1d5ab9b

File tree

14 files changed

+1120
-242
lines changed

14 files changed

+1120
-242
lines changed

models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java

Lines changed: 92 additions & 115 deletions
Large diffs are not rendered by default.

models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatOptions.java

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
import org.springframework.ai.anthropic.api.AnthropicApi;
3434
import org.springframework.ai.anthropic.api.AnthropicApi.ChatCompletionRequest;
35-
import org.springframework.ai.anthropic.api.AnthropicCacheStrategy;
35+
import org.springframework.ai.anthropic.api.AnthropicCacheOptions;
3636
import org.springframework.ai.model.tool.ToolCallingChatOptions;
3737
import org.springframework.ai.tool.ToolCallback;
3838
import org.springframework.lang.Nullable;
@@ -46,6 +46,7 @@
4646
* @author Alexandros Pappas
4747
* @author Ilayaperumal Gopinathan
4848
* @author Soby Chacko
49+
* @author Austin Dase
4950
* @since 1.0.0
5051
*/
5152
@JsonInclude(Include.NON_NULL)
@@ -61,35 +62,16 @@ public class AnthropicChatOptions implements ToolCallingChatOptions {
6162
private @JsonProperty("top_k") Integer topK;
6263
private @JsonProperty("thinking") ChatCompletionRequest.ThinkingConfig thinking;
6364

64-
/**
65-
* The caching strategy to use. Defines which parts of the prompt should be cached.
66-
*/
6765
@JsonIgnore
68-
private AnthropicCacheStrategy cacheStrategy = AnthropicCacheStrategy.NONE;
69-
70-
/**
71-
* Cache time-to-live. Either "5m" (5 minutes, default) or "1h" (1 hour).
72-
* The 1-hour cache requires a beta header.
73-
*/
74-
@JsonIgnore
75-
private String cacheTtl = "5m";
76-
77-
public AnthropicCacheStrategy getCacheStrategy() {
78-
return this.cacheStrategy;
79-
}
80-
81-
public void setCacheStrategy(AnthropicCacheStrategy cacheStrategy) {
82-
this.cacheStrategy = cacheStrategy;
83-
}
66+
private AnthropicCacheOptions cacheOptions = AnthropicCacheOptions.DISABLED;
8467

85-
public String getCacheTtl() {
86-
return this.cacheTtl;
68+
public AnthropicCacheOptions getCacheOptions() {
69+
return this.cacheOptions;
8770
}
8871

89-
public void setCacheTtl(String cacheTtl) {
90-
this.cacheTtl = cacheTtl;
72+
public void setCacheOptions(AnthropicCacheOptions cacheOptions) {
73+
this.cacheOptions = cacheOptions;
9174
}
92-
9375
/**
9476
* Collection of {@link ToolCallback}s to be used for tool calling in the chat
9577
* completion requests.
@@ -142,8 +124,7 @@ public static AnthropicChatOptions fromOptions(AnthropicChatOptions fromOptions)
142124
.internalToolExecutionEnabled(fromOptions.getInternalToolExecutionEnabled())
143125
.toolContext(fromOptions.getToolContext() != null ? new HashMap<>(fromOptions.getToolContext()) : null)
144126
.httpHeaders(fromOptions.getHttpHeaders() != null ? new HashMap<>(fromOptions.getHttpHeaders()) : null)
145-
.cacheStrategy(fromOptions.getCacheStrategy())
146-
.cacheTtl(fromOptions.getCacheTtl())
127+
.cacheOptions(fromOptions.getCacheOptions())
147128
.build();
148129
}
149130

@@ -316,15 +297,14 @@ public boolean equals(Object o) {
316297
&& Objects.equals(this.internalToolExecutionEnabled, that.internalToolExecutionEnabled)
317298
&& Objects.equals(this.toolContext, that.toolContext)
318299
&& Objects.equals(this.httpHeaders, that.httpHeaders)
319-
&& Objects.equals(this.cacheStrategy, that.cacheStrategy)
320-
&& Objects.equals(this.cacheTtl, that.cacheTtl);
300+
&& Objects.equals(this.cacheOptions, that.cacheOptions);
321301
}
322302

323303
@Override
324304
public int hashCode() {
325305
return Objects.hash(this.model, this.maxTokens, this.metadata, this.stopSequences, this.temperature, this.topP,
326306
this.topK, this.thinking, this.toolCallbacks, this.toolNames, this.internalToolExecutionEnabled,
327-
this.toolContext, this.httpHeaders, this.cacheStrategy, this.cacheTtl);
307+
this.toolContext, this.httpHeaders, this.cacheOptions);
328308
}
329309

330310
public static class Builder {
@@ -424,19 +404,8 @@ public Builder httpHeaders(Map<String, String> httpHeaders) {
424404
return this;
425405
}
426406

427-
/**
428-
* Set the caching strategy to use.
429-
*/
430-
public Builder cacheStrategy(AnthropicCacheStrategy cacheStrategy) {
431-
this.options.cacheStrategy = cacheStrategy;
432-
return this;
433-
}
434-
435-
/**
436-
* Set the cache time-to-live. Either "5m" (5 minutes, default) or "1h" (1 hour).
437-
*/
438-
public Builder cacheTtl(String cacheTtl) {
439-
this.options.cacheTtl = cacheTtl;
407+
public Builder cacheOptions(AnthropicCacheOptions cacheOptions) {
408+
this.options.setCacheOptions(cacheOptions);
440409
return this;
441410
}
442411

models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/AnthropicApi.java

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
* @author Claudio Silva Junior
6868
* @author Filip Hrisafov
6969
* @author Soby Chacko
70+
* @author Austin Dase
7071
* @since 1.0.0
7172
*/
7273
public final class AnthropicApi {
@@ -860,6 +861,10 @@ public ContentBlock(Type type, String id, String name, Map<String, Object> input
860861
this(type, null, null, null, id, name, input, null, null, null, null, null, null);
861862
}
862863

864+
public static ContentBlockBuilder from(ContentBlock contentBlock) {
865+
return new ContentBlockBuilder(contentBlock);
866+
}
867+
863868
/**
864869
* The ContentBlock type.
865870
*/
@@ -984,6 +989,121 @@ public Source(String url) {
984989

985990
}
986991

992+
public static class ContentBlockBuilder {
993+
994+
private Type type;
995+
996+
private Source source;
997+
998+
private String text;
999+
1000+
private Integer index;
1001+
1002+
private String id;
1003+
1004+
private String name;
1005+
1006+
private Map<String, Object> input;
1007+
1008+
private String toolUseId;
1009+
1010+
private String content;
1011+
1012+
private String signature;
1013+
1014+
private String thinking;
1015+
1016+
private String data;
1017+
1018+
private CacheControl cacheControl;
1019+
1020+
public ContentBlockBuilder(ContentBlock contentBlock) {
1021+
this.type = contentBlock.type;
1022+
this.source = contentBlock.source;
1023+
this.text = contentBlock.text;
1024+
this.index = contentBlock.index;
1025+
this.id = contentBlock.id;
1026+
this.name = contentBlock.name;
1027+
this.input = contentBlock.input;
1028+
this.toolUseId = contentBlock.toolUseId;
1029+
this.content = contentBlock.content;
1030+
this.signature = contentBlock.signature;
1031+
this.thinking = contentBlock.thinking;
1032+
this.data = contentBlock.data;
1033+
this.cacheControl = contentBlock.cacheControl;
1034+
}
1035+
1036+
public ContentBlockBuilder type(Type type) {
1037+
this.type = type;
1038+
return this;
1039+
}
1040+
1041+
public ContentBlockBuilder source(Source source) {
1042+
this.source = source;
1043+
return this;
1044+
}
1045+
1046+
public ContentBlockBuilder text(String text) {
1047+
this.text = text;
1048+
return this;
1049+
}
1050+
1051+
public ContentBlockBuilder index(Integer index) {
1052+
this.index = index;
1053+
return this;
1054+
}
1055+
1056+
public ContentBlockBuilder id(String id) {
1057+
this.id = id;
1058+
return this;
1059+
}
1060+
1061+
public ContentBlockBuilder name(String name) {
1062+
this.name = name;
1063+
return this;
1064+
}
1065+
1066+
public ContentBlockBuilder input(Map<String, Object> input) {
1067+
this.input = input;
1068+
return this;
1069+
}
1070+
1071+
public ContentBlockBuilder toolUseId(String toolUseId) {
1072+
this.toolUseId = toolUseId;
1073+
return this;
1074+
}
1075+
1076+
public ContentBlockBuilder content(String content) {
1077+
this.content = content;
1078+
return this;
1079+
}
1080+
1081+
public ContentBlockBuilder signature(String signature) {
1082+
this.signature = signature;
1083+
return this;
1084+
}
1085+
1086+
public ContentBlockBuilder thinking(String thinking) {
1087+
this.thinking = thinking;
1088+
return this;
1089+
}
1090+
1091+
public ContentBlockBuilder data(String data) {
1092+
this.data = data;
1093+
return this;
1094+
}
1095+
1096+
public ContentBlockBuilder cacheControl(CacheControl cacheControl) {
1097+
this.cacheControl = cacheControl;
1098+
return this;
1099+
}
1100+
1101+
public ContentBlock build() {
1102+
return new ContentBlock(this.type, this.source, this.text, this.index, this.id, this.name, this.input,
1103+
this.toolUseId, this.content, this.signature, this.thinking, this.data, this.cacheControl);
1104+
}
1105+
1106+
}
9871107
}
9881108

9891109
///////////////////////////////////////

0 commit comments

Comments
 (0)